AI 支持
接入 OpenAI、Anthropic、Gemini、Ollama、vLLM 或 HuggingFace,让标注者按需获得提示、关键词高亮和标签理由。
开启 AI 支持后,标注者工作时会有一个大语言模型写提示、高亮关键词、解释每个标签为什么可能适用。它不会替你填表单。决定权仍在标注者手里,每个助手都藏在一个需要他们按下的按钮后面。
安装
各家提供商的 SDK 都是可选依赖。基础安装不需要其中任何一个,只有当配置选中某个 endpoint_type 时才会导入对应的 SDK:
pip install "potato-annotation[ai]"这覆盖了常用的那几个。如果配置选了一个 SDK 缺失的端点,服务器会告诉你该装哪个包,而不是在导入时就失败。
支持的提供商
云端: openai、anthropic、gemini、huggingface
本地: ollama、vllm
视觉: ollama_vision、openai_vision、anthropic_vision、yolo
视觉端点以及图像和视频助手请见视觉 AI 支持。
配置
ai_support:
enabled: true
endpoint_type: "openai"
ai_config:
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
temperature: 0.7
max_tokens: 800
include:
all: true关于这个块有两点值得直说,因为运行时哪一点都不会被发现:
模型设置放在 ai_config 里面,比想当然的位置深一层。ai_support.model 和 ai_support.base_url 会被忽略,不过 potato validate --strict 会把它们指出来。
include.all 默认是关闭的。没有它,页面上任何地方都不会出现助手按钮,AI 面板渲染成空的,校验干净通过,也没有任何警告。
配置选项
| 选项 | 类型 | 描述 |
|---|---|---|
enabled | boolean | 开启 AI 支持 |
endpoint_type | string | 使用哪个提供商 |
ai_config_file | string | 存放端点细节的外部配置文件路径 |
ai_config.model | string | 模型名称,默认为该提供商自己的默认模型 |
ai_config.api_key | string | 云服务商必填 |
ai_config.base_url | string | 用某个兼容 OpenAI 的服务器替代厂商自家的,例如 vLLM、SGLang、LM Studio 或 LiteLLM。设置它之后 api_key 变为可选 |
ai_config.temperature | float | 回复的随机程度,0.0 到 2.0,默认 0.7 |
ai_config.max_tokens | integer | 回复的最大长度,默认 800 |
ai_config.include.all | boolean | 在所有方案上启用助手,默认 false |
ai_config.include.special_include | object | 按页面、按方案分别控制 |
cache_config.disk_cache.enabled | boolean | 把回复缓存到磁盘,默认 false |
cache_config.disk_cache.path | string | 缓存文件路径,开启缓存时必填 |
cache_config.prefetch.warm_up_page_count | integer | 启动时预先生成的实例数 |
cache_config.prefetch.on_next | integer | 向前翻页时预取的实例数 |
cache_config.prefetch.on_prev | integer | 向后翻页时预取的实例数 |
openai 和 openai_vision 接受三种提供 API 密钥的方式,校验三种都认:api_key 的值、环境中的 OPENAI_API_KEY,或指向一台不需要密钥的自托管服务器的 base_url。anthropic、huggingface 和 gemini 只读第一种,所以对这三个来说密钥确实是必需的。
没有理由就让 max_tokens 保持默认值。理由助手和关键词助手会在一次回复里为所有标签作答,所以几百个 token 会把回复从对象中间截断,助手渲染成空的,而且不报错。
几个助手
标注者在每个方案上会拿到三个按钮,外加第四种随提示一起出现的行为。
提示给出关于如何思考这条数据的指引,可以附带一个建议标签。
关键词标出与每个标签相关的词和短语,画成文本上的方框覆盖层,而不是背景高亮。
理由解释每个可选标签为什么可能适用,对所有标签给出平衡的推理。在培训标注者或判断确实困难时,这个最值得开启。
标签建议不是单独的按钮。当提示带有建议标签时,那个标签会带上琥珀色边框和一个闪光标记。
各端点能做什么
| 端点 | 文本 | 视觉 | 方框 | 关键词 | 理由 |
|---|---|---|---|---|---|
openai、anthropic、ollama | 是 | 否 | 否 | 是 | 是 |
openai_vision、anthropic_vision、ollama_vision | 是 | 是 | 否 | 仅文本条目 | 是 |
yolo | 否 | 是 | 是 | 否 | 否 |
「仅文本条目」是按条目判定的,而不是按端点判定。视觉模型仍然是语言模型,所以在文本条目上它提供全部三个助手,而在图像条目上关键词按钮会被过滤掉,因为没有词可标。
图文都有的条目
带截图的客服工单,或配着评论的产品照片,应该图文一起送到模型。Potato 从 item_properties.text_key 取文本,图片则取下面第一个能解析出结果的来源:
ai_support.image_keyitem_properties.image_keyinstance_display中type: image的字段,或第一个取值看起来像图片的展示字段
所以已经通过 instance_display 声明了照片的配置,不需要再写一遍:
instance_display:
fields:
- {key: body, type: text, label: Ticket}
- {key: screenshot, type: image, label: Screenshot}只把图片发过去,提示就会信心十足地描述这条数据里错误的那一半。给模型一张通用配图,再让它处理「导出按钮一直转圈」,它会回说自己没有拿到上下文。
这个字段接受 http(s) URL、data URI,或 media_directory 下的文件名。本地文件会从磁盘读出并以 base64 发送。既不是 URL、Potato 也找不到对应文件的值会被记进日志,然后不带图片去问模型,所以一条只针对文本推理的提示,就是去查那行日志的理由。
按方案启用助手
include.all 在所有地方开启所有助手。另一种做法是 special_include,它把页面索引映射到标注 id,再映射到该方案应带的助手列表:
ai_support:
enabled: true
endpoint_type: "openai"
ai_config:
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
include:
all: false
special_include:
"0":
"0": ["hint", "keyword"]
"1":
"1": ["hint"]
"2":
"0": ["hint", "keyword"]
"1": ["hint", "keyword"]内层的键是标注 id,也就是该方案在 annotation_schemes 中从零开始数的位置。
当表单按网格排布时,这一点比看上去更要紧。助手那一行是按方案渲染的,所以三个方案各三个助手就是九个按钮,每个单元格一行。单元格宽度低于约 260px 时,这一行会折叠成单行图标,标签保留为按钮的无障碍名称并放在它的 title 上。如果要把 layout.grid 和 AI 支持一起用,请按方案指定想要的助手,而不是在所有地方全部打开。
缓存与预取
一次大语言模型调用会给页面加载添上好几秒,而等待的标注者就不再按那个按钮了。缓存还能让你不必为别人重新访问过的条目付两次钱:
ai_support:
enabled: true
endpoint_type: "openai"
ai_config:
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
include:
all: true
cache_config:
disk_cache:
enabled: true
path: "annotation_output/ai_cache.json"
prefetch:
warm_up_page_count: 20
on_next: 10
on_prev: 3预热在启动时为前 N 条实例预先生成回复。预取则在标注者浏览时于光标前方生成,on_next 比 on_prev 大,反映的是大部分移动都是向前的。磁盘缓存在重启后依然保留。
外部 AI 配置文件
端点细节往往正是不能提交进仓库的那部分:API 密钥、内部服务器 URL、那台机器上装的是哪个模型。ai_config_file 把它们移进自己的文件:
# config.yaml, committed, no secrets
ai_support:
enabled: true
ai_config_file: ai-config.yaml
ai_config:
temperature: 0.7
max_tokens: 800
include:
all: true# ai-config.yaml, gitignored
endpoint_type: ollama
model: qwen3:0.6b
base_url: http://localhost:11434外部文件负责设置 endpoint_type,它的其他值会合并进 ai_config 并优先于内联的值。合并是扁平的:外部文件在自己的顶层直接放 model、base_url 和 api_key。把它们包在该文件里的 ai_config: 块中会产生 ai_config.ai_config,没有任何代码读它,启动随后会因缺少 API 密钥而失败,报错指向的还是错的键。
如果设置了 ai_config_file 但文件不存在,AI 支持会给出警告并自行关闭,服务器照常启动。potato validate --strict 把那条警告当成错误,所以一项以 AI 辅助为研究对象的研究,在 AI 关着的情况下过不了自己的检查。请在配置旁边附一份 ai-config.yaml.example 供人复制。ai-config.yaml 和 ai-config*.yaml 这两个模式已被 gitignore。
自定义提示词
提示词以 JSON 文件的形式放在 potato/ai/prompt/ 里,每种标注类型一个:
| 标注类型 | 提示词文件 |
|---|---|
| Radio | radio.json |
| Likert | likert.json |
| Multiselect | multiselect.json |
| Span | span.json |
| Slider | slider.json |
| Select | select.json |
| Number | number.json |
| Free text | textbox.json |
每个文件为每个助手保存一个模板,包含 name、prompt、output_format 和一个图标:
{
"hint": {
"name": "Hint",
"prompt": "TASK: Generate annotation guidance...\n- Text to annotate: \"${text}\"\n- Annotation task: ${description}\n- Available labels: ${labels}",
"output_format": "default_hint",
"img": "/static/ai_assistant_img/blub.svg"
}
}可用的变量是 ${text}、${description}、${labels}、${min_label}、${max_label}、${size}、${min_value} 和 ${max_value}。
output_format 指明渲染器期待的回复结构。default_hint 返回 {hint, suggestive_choice},default_keyword 返回 {label_keywords: [{label, keywords}]},default_rationale 返回 {rationales: [{label, reasoning}]}。
各提供商的配置
OpenAI
ai_support:
enabled: true
endpoint_type: "openai"
ai_config:
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
temperature: 0.7
max_tokens: 800
include:
all: trueAnthropic
ai_support:
enabled: true
endpoint_type: "anthropic"
ai_config:
model: "claude-sonnet-4-20250514"
api_key: "${ANTHROPIC_API_KEY}"
temperature: 0.7
max_tokens: 800
include:
all: trueGoogle Gemini
ai_support:
enabled: true
endpoint_type: "gemini"
ai_config:
model: "gemini-2.0-flash-exp"
api_key: "${GOOGLE_API_KEY}"
max_tokens: 800
include:
all: trueOllama
ai_support:
enabled: true
endpoint_type: "ollama"
ai_config:
model: "llama3.2"
base_url: "http://localhost:11434"
max_tokens: 800
include:
all: truevLLM
ai_support:
enabled: true
endpoint_type: "vllm"
ai_config:
model: "meta-llama/Llama-3.2-3B-Instruct"
base_url: "http://localhost:8000"
max_tokens: 800
include:
all: trueHuggingFace
ai_support:
enabled: true
endpoint_type: "huggingface"
ai_config:
model: "meta-llama/Llama-3.2-3B-Instruct"
api_key: "${HF_API_KEY}"
max_tokens: 800
include:
all: trueOpenRouter 不在 ai_support.endpoint_type 接受的十个取值之内,在这里写它,配置加载不起来。它能用在聊天侧栏:chat_support.endpoint_type: openrouter,注意这个拼写没有下划线。
给图像单独配一个端点
文本模型和视觉模型可以并排运行,让每种内容类型都用上更合适的那个:
ai_support:
enabled: true
endpoint_type: "ollama"
visual_endpoint_type: "ollama_vision"
ai_config:
model: "llama3.2"
include:
all: true
visual_ai_config:
model: "qwen2.5-vl:7b"完整示例
annotation_task_name: "Sentiment Analysis with AI Support"
task_dir: "."
data_files:
- "data/reviews.json"
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: radio
name: sentiment
description: "What is the sentiment of this text?"
labels: ["positive", "negative", "neutral"]
- annotation_type: multiselect
name: topics
description: "What topics are discussed?"
labels: ["product", "service", "price", "quality"]
ai_support:
enabled: true
endpoint_type: "openai"
ai_config:
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
temperature: 0.7
max_tokens: 800
include:
all: true
cache_config:
disk_cache:
enabled: true
path: "annotation_output/ai_cache.json"
prefetch:
warm_up_page_count: 20
on_next: 10
on_prev: 3
output_annotation_dir: "output/"
export_annotation_format: jsonl
user_config:
allow_all_users: true环境变量
把密钥留在配置之外:
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export GOOGLE_API_KEY="..."用 ${VARIABLE_NAME} 引用它们,主配置和外部 AI 配置文件里都能用。
故障排查
提示框是空的,但服务器确实回复了
模型回复了,请求返回 200,而提示框什么都不显示。有四件事会产生同样的症状,按这个顺序检查:
include.all缺失。 页面上根本没有助手按钮,而且没有任何警告。max_tokens太低。 理由助手和关键词助手会一次性为所有标签作答,所以回复从对象中间被截断。日志里会写模型触到了max_tokens。- 服务器忽略了 schema。 检查回复是 JSON 而不是散文。没有约束解码的服务器会按提示词暗示的任何结构作答。
- 键放错了地方。 所有跟模型有关的东西都属于
ai_config。validate --strict会指出它不认识的任何键。
一个按钮都没有,而启动日志看着正常
在日志里找 "AI endpoint ready"。如果它说端点启动失败,原因就在那一行上方的警告里。
Ollama 或 vLLM 连接失败
确认服务器正在运行、模型已经拉取,Ollama 用 ollama list 查看,并检查配置的 base_url 可以访问。
最佳实践
- 当成辅助来用 - 决定由标注者做出,一项默认接受建议的研究测的是模型
- 在生产环境启用缓存 - 它能降低延迟和重复开销
- 使用预热 - 预先生成开头那几条实例,第一位标注者就不用等
- 留意账单 - 云服务商按请求收费,每个方案都配一个助手会在整个语料上成倍放大
- 考虑本地端点 - 大批量工作,或语料不能离开本机时,用 Ollama 或 vLLM
- 把密钥放在环境变量里 - 绝不要提交它们
延伸阅读
- 视觉 AI 支持 - 面向图像和视频的视觉端点
- 选项高亮 - 弱化可能性较低的标签
- 多样性排序 - 基于嵌入的条目排序
- ICL 标注 - 在自有标注上做上下文学习
- 主动学习 - 模型驱动的实例优先级排序
有关实现细节,请参阅源文档。