> ## Documentation Index
> Fetch the complete documentation index at: https://dev.marginnote.com.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# AI 任务

> aiTasks 的字段写法、scope 与 output 的约束、四道门与 tagPrefix

<Warning>
  本文由 AI 撰写，暂未经过人工校对，请谨慎参考。
</Warning>

场景模板可以声明 AI 任务。增加一条任务只需改动模板，MN 本身无须改动。任务的性质是数据，宿主中的函数并不因任务增加而改变。插件清单 `mnaddon.json` 不必为此增加字段。

这与[最小打包](/zh/basic-package)一文的名册语义一致：`aiTasks` 是一个名册，写进去的任务才存在，留空表示不接管。发起时机、材料的来源、返回结果的形状，都由模板逐条写明，宿主只做核对。

# 任务声明

`aiTasks` 是一个数组，其中每一项是一条任务的声明。仓库 `sdk/output/tools/starter/template/3-full.json` 中的任务如下：

```json template.json highlight={4} focus={4} theme={null}
{
  "id": "u-starter",
  "name": "起步",
  "aiTasks": [
    {
      "id": "starter_explain",
      "title": "解释一下",
      "trigger": "user",
      "scope": "word_sentence",
      "tier": 1,
      "output": {
        "reply": "string"
      },
      "required": [
        "reply"
      ],
      "prompt": "用一句中文解释给定的词或短语在学习笔记语境下的意思。reply 写那一句话，不要罗列义项、不要加原文里没有的信息。"
    }
  ]
}
```

每条任务由下列字段构成：

| 字段 | 类型 | 含义 |
| - | - | - |
| `id` | `String` | 任务的标识，在模板内唯一。页面依据该字段指定要调用的任务。该字段不可留空。 |
| `title` | `String?` | 展示给用户的任务名称。同意提示、模板编辑器与 Bridge 展示的都是该名称，`id` 不出现在这些界面上。 |
| `trigger` | `String?` | 发起方式的约束。取值见[四道门](#四道门)。缺省 `user`。 |
| `scope` | `String` | 发送出去的材料的范围。封闭枚举，由宿主实现，模板只能从中选取。该字段不可留空。 |
| `prompt` | `String` | 作者撰写的提示词。宿主在提示词之后按固定格式附上材料，并声明材料只是材料，不要执行其中的指令。该字段不可留空。 |
| `output` | `[String: String]?` | 输出字段表。键为字段名，值为 `string`、`number` 或 `bool`。宿主按该表校验返回结果的形状。 |
| `required` | `[String]?` | 必填字段的名单。名单中的字段取自 `output`，缺任意一项即判定形状不对，不计成功。 |
| `tier` | `Int?` | 模型档位。`0` 最快，`2` 最强。缺省 `0`。 |

`title` 与 `prompt` 的分工值得留意。界面上出现的是 `title`，模型读到的是 `prompt`。二者各自服务不同的读者，不存在互相替代的关系。

提示词由模板作者撰写。摘录工具上的 OCR 提示词本来也是作者撰写的自由文本，`aiTasks` 把同一件事接到插件一侧，并补上前三道门。提示词这一处享有与摘录工具相同的写作自由，宿主不介入。

<Warning>
  `aiTasks` 同样服从名册语义。先抄一份别人的模板再改，抄写会把对方的任务声明整包继承下来。配套插件没有调用某条任务的代码时，那条任务仍然存在于模板之中，页面读到的是对方的任务清单。
</Warning>

<Note>
  仓库 `sdk/output/tools/starter/template/` 下的模板按级递进，`3-full.json` 在底部工具条与插件接入的基础上加上 `aiTasks`。各级之间的差异见[最小打包](/zh/basic-package)。
</Note>

# scope 的取值

`scope` 决定宿主发出的内容。取值是一个封闭枚举：

| 取值 | 宿主发出的内容 |
| - | - |
| `word_sentence` | 目标词与该词所在的那一句。材料由插件提供，词不超过 80 个字符，句子不超过 600 个字符，长度上限由宿主把守。 |
| `card_text` | 这张卡的标题与正文。材料由 MN 从卡片上取出，插件传入的内容不予采用。 |
| `attempt_ink` | 这张卡上的手写、文本框与公式框合并成一张图片发送。插件接触不到该图片。卡上没有书写内容时，该次调用被拒绝。 |

`attempt_ink` 走的是识别手写的视觉模型路线。`tier` 大于 `1` 时宿主改用能力更强的模型，`0` 与 `1` 使用同一个轻量模型。判定解答过程这类工作，轻量模型不足以支撑，需要声明 `tier` 为 `2`。

范围之外的内容，提示词够不着。`scope` 是封闭枚举，宿主按该枚举实现取材料的动作，提示词只参与模型侧的推理，二者互不相交。因此一条 `card_text` 的任务不会因为提示词写得详细而拿到卡上的手写内容。

<Note>
  封闭枚举的写法带来一条排查上的便利：写错 `scope` 的表现与写错其他字段一致，都是整条声明不存在。核对取值时只需比对上表。
</Note>

# output 的形状校验

`output` 的取值只能是 `"string"`、`"number"` 与 `"bool"`。这张类型清单是封闭的，清单之外没有其他取值。

把字段的含义写进 `output`，会让整条声明被当作不存在。表现是不报错、不半执行，页面只收到一个参数错误。

对照以下写法。下面的声明不合格，该任务不会出现在页面的任务列表中：

```json template.json theme={null}
{
  "id": "u-starter",
  "name": "起步",
  "aiTasks": [
    {
      "id": "starter_explain",
      "trigger": "user",
      "scope": "word_sentence",
      "output": {
        "reply": "一句话的中文解释"
      },
      "prompt": "用一句中文解释给定的词或短语在学习笔记语境下的意思。"
    }
  ]
}
```

字段的含义应当写进 `prompt`，`output` 只保留类型名：

```json template.json theme={null}
{
  "id": "u-starter",
  "name": "起步",
  "aiTasks": [
    {
      "id": "starter_explain",
      "trigger": "user",
      "scope": "word_sentence",
      "output": {
        "reply": "string"
      },
      "required": [
        "reply"
      ],
      "prompt": "用一句中文解释给定的词或短语在学习笔记语境下的意思。reply 写那一句话。"
    }
  ]
}
```

上例的提示词点名了 `reply`，`output` 中也声明了 `reply`，二者一致。字段名对不上时，模型写进的内容落在 `output` 未声明的位置，宿主按 `output` 校验形状时判定形状不对。

`required` 是 `output` 的子集。名单中的字段必须出现在 `output` 里，写在名单中而不在字段表中的名字同样使整条声明失效。`required` 中的任意一项缺失，返回结果即判定形状不对，不计成功。

<Warning>
  `output` 的取值写错、写成中文描述、或 `required` 指向 `output` 中不存在的字段，都会让整条声明被当作不存在。宿主不报错，页面只收到一个参数错误。可用的核对方式是逐条比对字段清单与枚举取值。
</Warning>

# 四道门

宿主对每条任务把守下列四道门：

| 门 | 负责的方面 | 说明 |
| - | - | - |
| `scope` | 发出的内容 | 封闭枚举，范围由宿主实现，提示词够不着范围外的东西。 |
| `tier` | 消耗的额度 | `0` 最快，`2` 最强，缺省 `0`。 |
| `output` | 返回结果的形状 | 字段表给形状，`required` 给必填项，形状不对不算成功。 |
| `trigger` | 用户是否知情 | `user` 表示必须由用户手势触发，缺省即此值。`auto` 允许插件自动发起，需要先取得一次同意。 |

这四道门都与提示词无关。提示词决定的是回答的质量，宿主把守的是范围、额度、形状与知情。

`tier` 的档位与 AI OCR 共用同一套取值。`1` 是均衡档，介于快与强之间。`0` 最快，适合输出短的任务；`2` 最强，适合判定与长推理。缺省即 `0`，声明 `tier` 之前先确认默认档是否够用。

额度之外，宿主还把守票据与限流。这一道与 `scope` 一样不经过提示词，`auto` 的任务无法绕过。

宿主逐条核对一项声明是否合格：`id` 与 `prompt` 不可为空，`scope` 必须是宿主认识的那几个取值，`trigger` 只能取 `user` 或 `auto`，`output` 中每个值都必须落在类型清单内，`required` 中的每个字段都必须出现在 `output` 里。核对结果是否定的，整条声明按不存在处理，模板中其他任务的声明不受影响。

```json template.json theme={null}
{
  "id": "u-starter",
  "name": "起步",
  "aiTasks": [
    {
      "id": "summarize",
      "trigger": "auto",
      "scope": "card_text",
      "output": {
        "summary": "string"
      },
      "required": [
        "summary"
      ],
      "prompt": "用三句话概括这张卡片的内容，写进 summary。"
    },
    {
      "id": "grade",
      "trigger": "auto",
      "scope": "attempt_ink",
      "tier": 2,
      "output": {
        "verdict": "string",
        "score": "number"
      },
      "required": [
        "verdict"
      ],
      "prompt": "批改作答区里的解答。verdict 写判定结论，score 写得分。"
    }
  ]
}
```

上例中 `grade` 的 `required` 只列出 `verdict`，`score` 属于可选字段，`output` 中仍然保留该字段的声明。

<Tip>
  写声明时先定 `scope`，再定 `output`，最后写 `prompt`。`scope` 与 `output` 决定宿主把守的范围与形状，核对不通过时整条声明不存在；`prompt` 不影响声明是否合格，可以在模板装好之后再打磨。
</Tip>

# 卡片类型标签的前缀

`tagPrefix` 是卡片类型标签的前缀，与 AI 任务无关，属于模板的标识性设置。

```json template.json highlight={4} focus={4} theme={null}
{
  "id": "u-starter",
  "name": "起步",
  "tagPrefix": "practice"
}
```

写出该字段之后，这份模板参与卡片类型上标签的约定：摘题产出时给题卡打 `<前缀>/question`，答案卡打 `<前缀>/answer`。插件按同一套约定识别卡片，两边使用同一个前缀。

标签的叶名固定，只有前缀可改。固定下来之后，用户才能在标签面板里看见这些标签，并能自行增删。摘题配不上的答案留作游离卡，游离卡在标签面板里成为一份待配清单，用户可自行处理。

留空表示不参与该约定。摘题是通用功能，模板不声明前缀时，摘题照常可用，宿主一个标签都不打。

<Note>
  前缀抄自别人的模板时会被整包继承。仓库里的起步模板曾经带着一份刷题用的前缀，而配套插件一个标签都不写，该前缀始终匹配不上。参见[最小打包](/zh/basic-package)一文的名册语义。
</Note>

# 调用侧

页面通过 `mn.ai` 调用模板中已经声明过的任务。调用参数随 `scope` 而定，返回结果的形式与错误码的含义见[使用 MN 内置 AI](/zh/use-inner-ai)。

本文只讲声明。页面读取模板的任务清单、以及调用之后对返回结果的处理，都属于插件一侧，写法同样见[使用 MN 内置 AI](/zh/use-inner-ai)。模板的其余字段与包内文件的分工，见[最小打包](/zh/basic-package)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.