1. 为什么 todowrite 的提示词值得单独写一篇
如果你正在用 OpenCode 搭 Agent,大概率遇到过这种场面:你让它「加个暗色模式」,它二话不说直接改 CSS,改完发现状态没接上、组件没联动、测试也没跑。问题不在模型能力,而在你给 todowrite 这个工具的提示词没写清楚——它不知道该在什么时候把任务拆成待办清单,也不知道拆完之后每一步要覆盖哪些维度。
todowrite 是 OpenCode Agent 里负责「把自然语言需求翻译成结构化任务清单」的工具。它本质上是一个状态机写入器:Agent 判断当前任务足够复杂、步骤足够多、有明确的交付边界时,就调用 todowrite 把计划落成一条条可追踪的待办项。写得好,Agent 会像资深工程师一样先规划再动手;写得糊,它要么过度设计,把「改个按钮颜色」拆成八步,要么该拆不拆,一口气写完一堆耦合代码。
这篇面向需要为 Agent 定义任务清单写入能力的开发者,给你可直接复制的提示词模板、字段说明,以及在 OpenCode 里验证 todowrite 是否按预期生成待办项的完整流程。TaoToken 在这里的角色是提供统一的 Key 和 API 通道,让你在调试 Agent 工具调用时不用来回切换多个供应商配置,官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end ,API 地址是 https://taotoken.net/api 。
先说清楚 todowrite 适合谁:如果你只是让 Agent 做单轮问答、查个文档、改一行配置,那不需要它,强行调用只会浪费 token 和时间。但只要你面对的是「跨 UI、状态、样式、集成、测试」这类多领域任务,todowrite 就是让 Agent 保持工程纪律的关键工具。下面从提示词结构开始拆。
2. todowrite 提示词模板与字段说明(OpenCode Agent 任务清单写入)
写 todowrite 的提示词,核心是回答三个问题:什么时候触发、拆成什么样、每个字段填什么。我把它整理成一个可复用的模板,你可以直接贴进 OpenCode 的 tool description 或 system prompt 里。
2.1 触发条件:三个以上独立步骤才值得写清单
提示词里必须明确「不触发」和「触发」的边界,否则 Agent 会滥用。参考写法:
当且仅当满足以下任一条件时,调用 todowrite: 1. 任务需要跨越三个以上独立技术领域(如 UI、状态管理、样式、集成、测试); 2. 用户显式要求「运行测试」「构建」「验证」等收尾动作; 3. 任务存在隐式依赖,前一步的输出是后一步的输入。 以下情况禁止调用 todowrite: - 单一且直接的任务(如改一个常量、修一个拼写); - 少于三步的简单任务; - 纯对话、检索、问答类任务; - 琐碎且无组织收益的任务。这段的作用是给 Agent 一个「认知负荷」判断标准。少于三步的简单任务强行写清单,就是形式主义,调用工具本身消耗 token 和时间,得不偿失。
2.2 字段结构:每条待办必须可验证
todowrite 的每条待办项建议包含四个字段,缺一不可:
| 字段 | 含义 | 示例 |
|---|---|---|
| id | 唯一标识,便于后续更新状态 | todo-1 |
| content | 祈使句描述的具体动作 | 创建主题切换按钮组件 |
| status | 当前状态,初始为 pending | pending |
| priority | 优先级,high/medium/low | high |
提示词里要强调:content 必须是祈使句,且包含可验证的完成标准。比如「编写暗色模式样式」不如「在 styles/theme.css 中定义 dark 主题变量并导出」来得可验证。
2.3 拆解维度:UI、State、Style、Integration、Test
这是从实际案例里提炼出来的五维拆解法。提示词里可以这样写:
拆解任务时,按以下维度检查是否覆盖完整: - UI 层:用户可见的交互元素; - State 层:全局状态管理与数据流; - Style 层:样式变量与主题定义; - Integration 层:现有组件接入新状态; - Test 层:测试、构建、错误处理。 若用户只提到部分维度,主动推断缺失的收尾步骤, 例如用户说「跑测试」,应补充「处理测试中出现的失败或错误」。最后一句是关键。用户说「跑测试和构建」,但没说报错了怎么办。作为开发者,跑测试报错不管等于没做。提示词要引导 Agent 主动补全这个闭环。
2.4 完整可复制模板
把上面几段拼起来,就是一个可直接用的 todowrite 提示词模板:
你是 OpenCode Agent 的任务规划器。当任务满足触发条件时, 调用 todowrite 生成结构化待办清单。 触发条件: - 跨越三个以上独立技术领域; - 用户显式要求测试/构建/验证; - 存在隐式依赖链。 禁止触发: - 单一直接任务、少于三步、纯对话检索、无组织收益的琐碎任务。 拆解维度:UI、State、Style、Integration、Test。 每条待办包含 id、content、status、priority。 content 用祈使句,包含可验证的完成标准。 主动推断用户未明说的收尾步骤,补全闭环。这个模板不依赖具体模型,OpenCode 里配置好工具描述后即可生效。接下来讲怎么在 OpenCode 里把它接上并验证。
3. 在 OpenCode 中接入 todowrite 的可复制配置
提示词写好了,得让 OpenCode 真正加载它。OpenCode 的工具配置通常放在项目根目录的配置文件里,不同版本路径略有差异,常见的是opencode.json或.opencode/config.json。下面给一份可复制的 JSON 片段,路径按你实际项目调整。
3.1 工具定义配置
{ "tools": { "todowrite": { "enabled": true, "description": "当任务跨越三个以上独立技术领域、或用户显式要求测试构建、或存在隐式依赖链时,调用此工具生成结构化待办清单。禁止用于单一直接任务、少于三步的简单任务、纯对话检索类任务。", "parameters": { "todos": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "status": { "type": "string", "enum": ["pending", "in_progress", "completed"] }, "priority": { "type": "string", "enum": ["high", "medium", "low"] } }, "required": ["id", "content", "status", "priority"] } } } } } }3.2 模型通道配置
OpenCode 需要连到一个模型服务。如果你用 TaoToken 作为统一通道,配置里填 Base URL 和 Key 即可。Base URL 用 https://taotoken.net/api ,Key 在控制台生成。三件套要写全:Base URL、Key、Model ID。
{ "provider": { "taotoken": { "baseURL": "https://taotoken.net/api", "apiKey": "sk-你的Key", "model": "claude-sonnet-4-20250514" } } }Model ID 按你实际使用的模型填,不要照抄。Key 建议放环境变量,别硬编码进仓库:
export TAOTOKEN_API_KEY="sk-你的Key"配置里改成"apiKey": "${TAOTOKEN_API_KEY}"。
3.3 提示词挂载位置
todowrite 的触发规则和拆解维度,建议放在 system prompt 或工具 description 里。OpenCode 支持在配置中指定 system prompt 文件:
{ "agent": { "systemPromptFile": "./prompts/todowrite-planner.md" } }把第 2 节的模板写进prompts/todowrite-planner.md,OpenCode 启动时会自动加载。这样提示词和配置分离,改提示词不用动 JSON。
配置完成后,用opencode --debug启动,观察日志里 todowrite 是否被注册。如果日志里出现tool registered: todowrite,说明接入成功。接下来验证调用行为。
4. 验证 todowrite 是否按预期生成待办项
配置好了不代表行为正确,得用真实请求验证。我试过用一个「添加暗色模式」的需求来测,这个需求天然跨越 UI、State、Style、Integration、Test 五个维度,是检验 todowrite 触发逻辑的好案例。
4.1 发起验证请求
在 OpenCode 交互界面输入:
给当前项目添加暗色模式,运行测试和构建。预期行为:Agent 不直接改 CSS,而是先调用 todowrite 生成待办清单。如果它直接开始写样式,说明触发条件没生效,回去检查提示词里的触发规则是否被正确加载。
4.2 检查生成的待办结构
正常情况下,todowrite 应该生成类似这样的清单:
{ "todos": [ { "id": "todo-1", "content": "创建主题切换按钮组件并接入设置面板", "status": "pending", "priority": "high" }, { "id": "todo-2", "content": "建立全局主题状态管理,支持读取和切换当前主题", "status": "pending", "priority": "high" }, { "id": "todo-3", "content": "在样式文件中定义 dark 主题变量并导出", "status": "pending", "priority": "high" }, { "id": "todo-4", "content": "将现有组件接入主题状态系统,完成联动", "status": "pending", "priority": "medium" }, { "id": "todo-5", "content": "运行测试和构建,定位并处理出现的失败或错误", "status": "pending", "priority": "high" } ] }重点看第 5 条:用户只说了「运行测试和构建」,但清单里补上了「定位并处理出现的失败或错误」。这说明提示词里的隐式意图推断生效了。如果第 5 条只写「运行测试」,说明推断规则没起作用,需要检查提示词里那段「主动推断用户未明说的收尾步骤」。
4.3 观察状态流转
todowrite 生成清单后,Agent 执行每一步时应该更新对应待办的 status。从 pending 到 in_progress 再到 completed。你可以在 OpenCode 的调试面板里观察这个流转。如果所有待办一直是 pending,说明状态更新逻辑没接上,检查工具定义里 status 字段的 enum 是否完整。
4.4 验证不触发场景
反向验证同样重要。输入一个简单任务:
把首页标题的字体大小改成 18px。预期行为:Agent 直接改,不调用 todowrite。如果它生成了清单,说明禁止触发规则没生效,Agent 在过度设计。这时候回去检查提示词里「禁止触发」那段的措辞是否足够强硬。
两个方向都验证通过,说明 todowrite 的提示词和配置都到位了。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
接入和验证过程中,报错基本集中在通道配置和工具注册两块。下面按真实报错逐个排查。
5.1 401 Unauthorized
最常见。日志里出现401或invalid api key,先检查三件事:Key 是否填对、Base URL 是否是 https://taotoken.net/api 、环境变量是否被正确读取。如果你用了${TAOTOKEN_API_KEY}但没 export,OpenCode 读到的是空字符串,自然 401。用echo $TAOTOKEN_API_KEY确认变量有值。
5.2 local proxy failed
日志里出现local proxy failed或connection refused,通常是 Base URL 写错或网络不通。确认 URL 没有多余斜杠,https://taotoken.net/api后面不要加/v1之类的路径,除非文档明确要求。另外检查本地是否有其他进程占用了 OpenCode 的代理端口。
5.3 reading choices 报错
error reading choices或cannot read property choices of undefined,说明返回体结构不符合预期。这通常是 Model ID 填错,或者请求发到了不兼容的端点。确认 Model ID 和你实际使用的模型一致,不要照抄示例里的claude-sonnet-4-20250514。如果换了模型,Model ID 要同步改。
5.4 OAuth 相关报错
如果你用的是需要 OAuth 的模型服务,日志里可能出现OAuth token expired或refresh failed。OpenCode 的 OAuth 流程和 API Key 流程是两套。用 TaoToken 的 Key 通道时,不需要走 OAuth,确认配置里没有残留的 OAuth 字段。如果之前配过 OAuth,清掉相关配置再试。
5.5 todowrite 不触发
配置都对,但 Agent 就是不调用 todowrite。检查三点:工具 description 是否被正确加载(看启动日志)、system prompt 文件路径是否正确、触发条件里的「三个以上独立技术领域」是否被模型理解。可以把触发条件写得更具体,比如直接列出「UI、State、Style、Integration、Test」五个维度名。
5.6 待办项生成但状态不更新
清单生成了,但执行过程中 status 一直是 pending。检查工具定义里是否包含 status 字段的更新接口。todowrite 通常配套一个 todoupdate 工具,如果只注册了 todowrite 没注册 todoupdate,状态就无法流转。在配置里补上 todoupdate 的定义。
排查完这些,基本能覆盖 90% 的接入问题。剩下的多半是提示词措辞问题,回去调触发规则即可。
6. 把 todowrite 用顺手的几个实操建议
提示词模板和配置都给了,最后说几个实际用下来的经验。todowrite 的价值不在于「生成了清单」,而在于「清单的粒度刚好」。太粗,等于没拆;太细,Agent 光维护清单就耗掉大量 token。
一个判断标准:每条待办应该是一个「可独立验证的交付单元」。比如「创建主题切换按钮组件」可以独立验证——按钮渲染出来了、点击有反应。「编写暗色模式样式」就不太好验证,改成「在 styles/theme.css 中定义 dark 主题变量并导出」就清晰了。
另一个经验是优先级别滥用。如果所有待办都是 high,等于没有优先级。UI 和 State 通常是 high,因为它们是其他步骤的依赖;Style 和 Integration 可以 medium;Test 看情况,如果用户显式要求就是 high。
还有一点:todowrite 生成的清单不是一成不变的。执行过程中如果发现新依赖,Agent 应该能追加或调整待办。提示词里可以加一句「执行中发现新的必要步骤时,更新清单而非忽略」。这样 Agent 不会为了「保持原计划」而跳过必要工作。
如果你在 OpenCode 里调试 todowrite 时想快速验证模型返回,可以用 TaoToken 的模型对话入口直接发请求看返回结构,省去在 OpenCode 里反复重启的时间。接入文档里有完整的请求示例。长期跑编码 Agent 的话,Coding Plan 的通道更稳定,适合把 todowrite 这类工具调用纳入日常流程。