林子豪的 PKM
← 返回 Blog

把任务交给 AI Agent 之前,先定位任务坐标

从第一性原理出发理解 agent:读完以后,你能把 AGENTS.md、skill、plan mode、goal mode、subagent、handoff、guardrail 等概念放回同一套任务坐标里。

30 min read系列 · agent
aiagentcontextworkflow

这篇文章想先给一个明确承诺:

读完以后,你不只是知道几个 agent 术语,而是能从第一性原理出发,自己推导出这些术语为什么会出现。

换句话说,这不是一篇 AGENTS.mdskillplan modegoal modesubagenthandoffguardrail 的功能清单。它想讲的是:从 agent 的基本约束出发,为了让 AI 稳定完成任务,我们必须补上哪些系统结构。

顺着这个问题往下推,你会发现很多看起来很新的名词,其实都在回答同几类老问题:上下文从哪里来,这次是哪类任务,人类怎么管过程,确定性动作交给谁做。

理解了这个框架以后,AGENTS.md 不再只是一个配置文件,skill 不再只是一个 prompt 包,plan mode 不再只是“先写计划”,goal mode 不再只是“放手让 AI 干”,subagent 不再只是“多开几个 AI”,handoff 不再只是普通总结,guardrail 也不再只是安全口号。它们都会变成某个任务坐标下自然长出来的组件。

这也意味着,不是所有任务都需要 skillhandoffsubagentgoal modeguardrail。很多任务直接聊天就够,硬上这些组件只会增加摩擦。真正重要的不是“会不会用更多 agent 功能”,而是能不能判断当前任务应该用哪些,不应该用哪些。

下面的三个维度就是为了做这个选择:C 看上下文从哪里来,T 看这次是哪类任务,A 看人怎么管过程。最后那张反查表也不是术语索引,而是一张选择表:先定位任务,再选合适的 agent 工作方式。

以后再出现新的 agent 名词,也可以先不急着记。把它放回这套框架里,问它解决的是哪一类问题,通常就能看出它是必要结构、局部优化,还是只是换了一个名字的包装。

很多人学 AI agent 时,会先被一堆词淹没。

tool useMCPmemoryRAGskillsubagenthandoffguardrailplan modegoal modecheckpointworkflowverifier。每个词看起来都重要,每个工具都像是在解决“让 AI 更强”的问题。

但真实使用时,最容易出问题的地方往往不是某个功能不会用,而是没有先判断:当前这个任务到底应该用哪种 agent 工作方式。

有些任务直接聊天就够。有些任务只需要把当前材料贴进去。有些任务需要稳定背景,比如 AGENTS.mdCLAUDE.md、profile、style guide、glossary。有些任务资料很多,AGENTS.md 不应该继续堆正文,而应该变成文档地图。有些任务的上下文和工作规程更复杂,需要 skill 懒加载。有些任务不能一口气让 AI 跑到底,必须拆成 stage gate。有些任务可以交给 goal mode,但前提是目标、权限和验收边界清楚。有些任务看起来像 AI 问题,其实应该交给程序、CLI 或校验器。

所以使用 AI agent 的第一步,不是写一个更长的 prompt,而是定位任务坐标。

先建立一个朴素模型

AI 是没有可靠记忆的强能力执行者

可以先用一个朴素的隐喻理解 AI:

AI 是一个能力很强、会使用工具、但没有可靠记忆的人。

它可以解释概念、总结材料、改写文字、生成方案、发现风险、写脚本、调用工具。但它不天然知道你是谁,不天然知道你的项目历史,也不天然知道你们公司的术语、偏好、禁区、上次任务做到哪里。

产品里看起来像“AI 记得你”的部分,通常不是模型自己记住了,而是外层系统把历史、摘要、偏好、文档、memory 或 skill 重新放进了这一轮 context。这个区别很重要,因为它决定了我们不能把所有失败都归因于“模型不够聪明”。

如果 AI 没有看到正确背景,它就会猜。如果任务边界没有定义清楚,它就会按最常见的模式补全。如果过程太长又没有中间产物,它就会越跑越偏。如果结果需要精确校验,而你只让模型凭感觉检查,它就会漏掉低级错误。

所以更可靠的使用方式是问三个问题:

1. 这次任务需要哪种外部记忆?

2. 这次是哪类任务?

3. 人类要管过程到什么程度?

这三个问题可以组成一个简单坐标系:C × T × A

对话窗口不是白纸

在继续讲 C 之前,先看一眼你打开 Codex、Claude Code 或其它 agent 程序时,真正摆在对话窗口里的东西。

用户看到的通常只是一个输入框,好像只有自己刚打的那句话。但在这句话前面,系统已经放进去了一些固定内容:system prompt、可用工具、MCP 连接、权限边界、输出规则。你说话之后,用户消息才接在这些固定内容后面。

也就是说,你每次和 agent 说话,并不是在一张白纸上开始。更像是打开了一个已经铺好底稿的工作台:上面先有系统说明和工具能力,然后才有你的输入、agent 的回复、工具调用结果、检索出来的文档片段。

{:title "一个 Agent 对话窗口里装了什么"
 :description "每个块的高度按 token 数量近似缩放。横线下面不是硬性失效区,而是注意力风险开始变高的区域。"
 :capacity 128000
 :unit "tokens"
 :messages [{:id :system
             :role :system
             :label "system prompt"
             :tokens 2800
             :note "身份、边界、输出规则"}
            {:id :tools
             :role :tool-schema
             :label "tools + MCP schemas"
             :tokens 17000
             :note "工具越多,占用越大"}
            {:id :user-1
             :role :user
             :label "user msg 1"
             :tokens 900
             :note "你输入的第一句话"}
            {:id :assistant-1
             :role :assistant
             :label "assistant response 1"
             :tokens 1600
             :note "agent 的第一轮回复"}
            {:id :user-2
             :role :user
             :label "user msg 2"
             :tokens 1200
             :note "你继续追问或补充"}]
 :steps [{:phase :initial
          :title "新对话刚开始"
          :body "你还没说话时,对话窗口里已经有 system prompt 和工具/MCP schema。工具说明本身也占 context。"
          :visible [:system :tools]}
         {:phase :user
          :title "用户说第一句话"
          :body "你输入的问题会接在这些固定内容后面。对 agent 来说,用户消息只是当前窗口里的一个块。"
          :visible [:system :tools :user-1]}
         {:phase :assistant
          :title "Agent 回复"
          :body "Agent 的回复也会进入同一个对话历史。下一轮继续聊时,这条回复会变成窗口里的一部分。"
          :visible [:system :tools :user-1 :assistant-1]}
         {:phase :user
          :title "用户继续追问"
          :body "普通多轮聊天就是这样不断往后追加 user msg 和 assistant response。聊得越久,历史占用的空间越多。"
          :visible [:system :tools :user-1 :assistant-1 :user-2]}]}

这个图后面还会反复出现。这里先只看最普通的聊天:固定底稿、用户消息、agent 回复、用户继续追问。

如果你开一个新 session,之前那串 user msg、assistant msg、tool result 就不会自动跟过去。新的对话基本上会回到图里的第 1 步:固定的 system prompt 和工具能力还在,但前一轮对话里的历史材料没了。你要么重新说明背景,要么让 agent 读取文档、进度记录或 handoff,把必要上下文重新放回工作台。

三个维度:C / T / A

C:上下文从哪里来

第一个维度是 C,也就是 context 形态。它回答的是:AI 这次需要哪种外部记忆?

这条线最容易被讲虚。很多人会说“要管理上下文”,但没有说清楚上下文到底放在哪里、什么时候放、放多少、从哪个阶段开始需要地图。

我更愿意把它看成一个逐层升级的过程:

C0 直接聊天 -> C1 输入当前材料 -> C2 固定背景进入默认上下文 -> C3 默认上下文变成文档地图 -> C4 skill 懒加载局部上下文

每一层解决的问题都不一样。

C0:直接聊天

C0 是零外部上下文。比如:

- 什么是 OKR?

- 怎么理解 agent?

- 现金流是什么意思?

- 给我 10 个团建活动 idea。

这类问题主要依赖模型内化知识。直接问就可以。

这里的反面做法是过度工程化。为了问“什么是 OKR”,先准备公司资料、个人背景、skill、工具、文档地图,这没有必要。

如果一个任务只需要 C0 上下文,本身又只是普通问答,过程也由人类每步都看,最好的工作方式通常就是普通聊天。

C1:这次输入就是上下文

C1 是当前材料。它和 C0 的区别不是 AI 变高级了,而是这次任务的上下文来自用户当前贴进来的材料。

例如:

- 把这段会议记录整理成行动项。

- 把这份客户访谈摘出需求、顾虑和下一步。

- 把这份课程大纲整理成模块、目标、练习和产出。

- 把这段文章改写成小红书版本,但不要添加原文没有的信息。

这时的关键纪律是:AI 只能基于当前输入材料处理,不要猜材料里没有的东西。

如果会议记录里没有负责人,就应该输出 owner: unknown待确认,而不是编一个负责人。如果客户材料里没有预算,就应该标记缺失,而不是根据行业经验猜一个数字。

C1 很适合结构化输出。比如会议纪要可以让 AI 输出:

decisions:
action_items:
  - task:
    owner:
    due_date:
    status:
risks:
open_questions:

结构化不是为了看起来专业,而是为了让后续处理变得可能。字段稳定以后,程序可以检查 action item 是否缺负责人,检查 deadline 是否为空,检查风险项是否没有 owner。

所以 C1 的工作方式不是“让 AI 自由发挥”,而是:

当前输入材料 + 明确任务 + 结构化输出 + 不允许编造缺失信息

这也是很多人第一次真正用好 AI 的地方。不是让它有“长期记忆”,只是把这次要处理的材料放清楚。

C2:固定背景进入默认上下文

C2 是固定背景。它解决的是另一类问题:有些信息不是当前材料的一部分,但会在很多任务里反复使用。

比如你经常让 AI 帮你写客户邮件,它需要知道:

- 你是谁。

- 你的默认语气。

- 你和客户的关系。

- 你们公司的术语。

- 常用输出格式。

- 哪些表达你不喜欢。

- 哪些信息不能说死。

这些信息如果每次重新讲,会很烦,也容易漏。它们应该进入默认上下文。

在不同系统里,这个默认上下文可能叫:

- custom instructions

- AGENTS.md

- CLAUDE.md

- profile.md

- style.md

- glossary.md

- team-context.md

这些文件的共同点是:它们保存少量、稳定、高频使用的背景。

这里的“少量”很重要。AGENTS.md 不应该从一开始就变成资料仓库。它更像一份默认工作说明:我是谁、这个项目是什么、常用命令是什么、重要边界是什么、写作或沟通风格是什么、什么事情绝对不要做。

{:title "C2:固定背景进入默认上下文"
 :description "和普通聊天相比,这里多了一块 AGENTS.md。它不是用户这次输入的材料,而是每次进入这个项目时默认会带上的稳定背景。"
 :capacity 128000
 :unit "tokens"
 :messages [{:id :system
             :role :system
             :label "system prompt"
             :tokens 2800
             :note "产品和模型的通用规则"}
            {:id :agents
             :role :system
             :label "AGENTS.md"
             :tokens 5200
             :note "项目背景、命令、边界、偏好"}
            {:id :tools
             :role :tool-schema
             :label "tools + MCP schemas"
             :tokens 17000
             :note "工具越多,占用越大"}
            {:id :user-1
             :role :user
             :label "user msg"
             :tokens 900
             :note "这次具体请求"}
            {:id :assistant-1
             :role :assistant
             :label "assistant response"
             :tokens 1600}]
 :steps [{:phase :default-context
          :title "进入项目后的默认底稿"
          :body "在 C2 里,AGENTS.md 这类稳定背景会跟 system prompt、工具说明一起出现在窗口前面。"
          :visible [:system :agents :tools]}
         {:phase :user
          :title "用户提出这次请求"
          :body "用户不需要每次重新解释项目背景,只要说这一次要做什么。"
          :visible [:system :agents :tools :user-1]}
         {:phase :assistant
          :title "Agent 基于固定背景回复"
          :body "Agent 回复时,既能看到用户当前请求,也能看到 AGENTS.md 里的稳定约束。"
          :visible [:system :agents :tools :user-1 :assistant-1]}]}

比如在一个代码仓库里,AGENTS.md 可以告诉 coding agent:

- 用哪个命令跑测试。

- 哪些测试是 agent 可以跑的,哪些是人类手动跑的。

- 本地服务怎么启动。

- 哪些文件不能动。

- worktree 经常是脏的,不要随便 revert 别人的改动。

在一个个人写作系统里,style.md 可以告诉写作 agent:

- 默认写中文。

- 不要写空泛鸡汤。

- 先给判断,再给例子。

- 不要把 blog 写成产品发布稿。

- 保留作者的概念和语气。

C2 的核心是:

少量、稳定、高频使用的背景,进入默认上下文。

反面做法有两个。第一个是每次都从头解释自己是谁。第二个是把所有资料都塞进默认上下文。前者浪费注意力,后者污染注意力。

C3:AGENTS.md 从正文变成地图

C3 时,资料已经多到不能再直接塞进默认上下文。

这时很多人会犯一个错误:继续往 AGENTS.md 或 custom instructions 里堆内容。项目历史、客户案例、写作模板、术语解释、过往决策、失败经验、操作规程,全都放进去。

短期看,这样很方便。长期看,AGENTS.md 会变成一堵墙。模型每次都要读一大堆和当前任务无关的信息,真正重要的约束反而被噪音淹没。

所以 C2 -> C3 的关键变化是:

AGENTS.md 不再承载全部知识,而是变成文档地图。

地图文档的作用不是把所有知识放进去,而是告诉 agent 该去哪里找。

用流行术语说,这就是 RAG 的核心动作:先 retrieval,按当前问题找到相关材料;再 generation,把材料放进当前 context 之后基于材料回答。

所以 RAG 不是“模型突然有了记忆”,而是一套外部记忆进入当前窗口的流程。区别只在于,检索入口可以是向量数据库、搜索引擎、知识库,也可以是最朴素的 AGENTS.md 文档地图加文件读取工具。

{:title "C3:AGENTS.md 变成文档地图"
 :description "AGENTS.md 不再装所有背景,而是告诉 agent:这类任务应该读哪些文件。先读相关文档,再基于文档回答,这就是最朴素的 RAG。"
 :capacity 128000
 :unit "tokens"
 :messages [{:id :system
             :role :system
             :label "system prompt"
             :tokens 2800
             :note "产品和模型的通用规则"}
            {:id :agents-map
             :role :system
             :label "AGENTS.md as map"
             :tokens 3600
             :note "告诉 agent 什么任务读什么文件"}
            {:id :tools
             :role :tool-schema
             :label "tools + MCP schemas"
             :tokens 17000}
            {:id :user-1
             :role :user
             :label "user msg"
             :tokens 900
             :note "这次要写方案"}
            {:id :assistant-plan
             :role :assistant
             :label "assistant decides what to read"
             :tokens 700
             :note "根据地图选择文件"}
            {:id :read-call
             :role :tool-call
             :label "tool call: read referenced files"
             :tokens 500
             :note "读取地图指向的文件"}
            {:id :read-result
             :role :tool-result
             :label "tool result: docs loaded"
             :tokens 12400
             :note "文件内容进入窗口"}
            {:id :assistant-answer
             :role :assistant
             :label "assistant response"
             :tokens 1800
             :note "基于用户请求和已读文件回答"}]
 :steps [{:phase :default-context
          :title "默认窗口里只有地图"
          :body "C3 里,AGENTS.md 的作用是导航。它不把所有销售方法、写作模板、案例和决策都塞进来。"
          :visible [:system :agents-map :tools]}
         {:phase :user
          :title "用户提出具体任务"
          :body "用户说完这次要做什么以后,agent 先用 AGENTS.md 判断应该读哪些文件。"
          :visible [:system :agents-map :tools :user-1 :assistant-plan]}
         {:phase :tool-call
          :title "Agent 先读地图指向的文件"
          :body "回答之前,agent 通过 tool call 去读取相关文件。文件还没读回来时,它不应该假装已经知道里面的内容。"
          :visible [:system :agents-map :tools :user-1 :assistant-plan :read-call]}
         {:phase :tool-result
          :title "文件内容进入当前窗口"
          :body "tool result 回来以后,相关文件内容才进入当前窗口。此时 agent 可以基于这些材料回答。"
          :visible [:system :agents-map :tools :user-1 :read-call :read-result :assistant-answer]}]}

例如:

如果你要写销售方案,先看 docs/sales-method.md 和 cases/customer-cases.md。
如果你要写公众号,先看 writing/style.md 和 writing/bad-examples.md。
如果你要做候选人分析,先看 hr/scorecard.md 和 hr/interview-rules.md。
如果你要做 PPT,先看 ppt/structure-guide.md 和 ppt/page-checklist.md。
如果你遇到术语冲突,先看 glossary.md。
如果你要理解长期产品语义,先看 docs/decisions/。

这时 context 管理的目标不是“读得更多”,而是“路由得更准”。

一个好的文档地图至少要说明:

- 有哪些文档。

- 什么任务看什么文档。

- 哪些是长期决策。

- 哪些是模板。

- 哪些是案例。

- 哪些是当前任务资料。

- 哪些文档只在特定阶段需要。

比如写一份行业报告,不应该让 agent 一上来“读完全部 30 个文档,然后写最终报告”。更好的做法是先看地图,再按阶段读材料:

1. 先读任务 brief 和报告结构要求。

2. 再读行业资料索引。

3. 抽取证据,形成 evidence-map.md

4. 基于证据形成 outline。

5. 写初稿。

6. 用 checklist 校验。

这就是 C3 的价值:把大量资料从“上下文堆叠”变成“可路由的资料库”。

这也是为什么 context 管理 的目标不是“更多”,而是“更合适”。模型这一轮看到什么,比系统总共知道什么更重要。

C4:Skill 是懒加载的局部上下文包

C4C3 的机制几乎一样。区别不在于 agent 突然多了一种神秘能力,而在于这套做法被标准化了。

C3 里,我们自己在 AGENTS.md 里写地图:

如果你要做 PPT,先看 ppt/structure-guide.md 和 ppt/page-checklist.md。
如果你要做候选人分析,先看 hr/scorecard.md 和 hr/interview-rules.md。

到了 C4,agent 程序直接规定一套目录和格式:把相关文档、操作规程、输出格式、工具说明放进 .agents/skills/<skill-name>/ 下面。外层只保留 skill 的名字和描述;真正的正文放在 SKILL.md 里,需要时再读。

也就是说,skill 可以理解成:

C3 文档地图的标准化版本。

默认上下文里通常只需要看到 skill 描述,例如:

writing: 用于写作、改稿、文章结构和作者风格。
ppt-structure: 用于 PPT 页结构、论证链和页面 checklist。
interview-scorecard: 用于候选人评价、证据绑定和风险判断。

当用户任务命中某个场景时,agent 再通过 tool call 读取对应 skill 的正文。

{:title "C4:Skill 是标准化的文档地图"
 :description "和 C3 一样,默认窗口里只放地图;区别是地图入口变成 skill 描述,正文放在 .agents/skills 目录里,需要时再懒加载。"
 :capacity 128000
 :unit "tokens"
 :messages [{:id :system
             :role :system
             :label "system prompt"
             :tokens 2800}
            {:id :skill-index
             :role :system
             :label "skill descriptions"
             :tokens 2400
             :note "只放名字、描述、触发场景"}
            {:id :tools
             :role :tool-schema
             :label "tools + MCP schemas"
             :tokens 17000}
            {:id :user-1
             :role :user
             :label "user msg"
             :tokens 900
             :note "这次要做 PPT 结构"}
            {:id :assistant-plan
             :role :assistant
             :label "assistant selects ppt skill"
             :tokens 650
             :note "根据 skill 描述选择"}
            {:id :read-skill
             :role :tool-call
             :label "tool call: read .agents/skills/ppt/SKILL.md"
             :tokens 520}
            {:id :skill-body
             :role :tool-result
             :label "tool result: SKILL.md"
             :tokens 7600
             :note "局部规程进入窗口"}
            {:id :assistant-answer
             :role :assistant
             :label "assistant response"
             :tokens 1800
             :note "按 skill 的规程输出"}]
 :steps [{:phase :default-context
          :title "默认窗口里只有 skill 描述"
          :body "和 C3 的 AGENTS.md 地图类似,默认上下文只放 skill 的名字、描述和适用场景。"
          :visible [:system :skill-index :tools]}
         {:phase :user
          :title "用户任务命中某个 skill"
          :body "用户提出具体任务后,agent 根据 skill 描述判断是否需要加载某个 skill。"
          :visible [:system :skill-index :tools :user-1 :assistant-plan]}
         {:phase :tool-call
          :title "Agent 读取 skill 正文"
          :body "真正的操作规程在 .agents/skills 目录里。需要时,agent 通过 tool call 读取对应 SKILL.md。"
          :visible [:system :skill-index :tools :user-1 :assistant-plan :read-skill]}
         {:phase :tool-result
          :title "Skill 正文进入当前窗口"
          :body "SKILL.md 回来以后,局部规则、输出格式和工具偏好才进入当前窗口。agent 再按这些规则继续工作。"
          :visible [:system :skill-index :tools :user-1 :read-skill :skill-body :assistant-answer]}]}

你可能不只有一个工作场景,而是很多场景:

- 写文章。

- 做销售方案。

- 做候选人评价。

- 做课程开发。

- 做 PPT 结构。

- 做代码 review。

- 做生产环境排障。

- 做学习复盘。

每个场景都有自己的背景、术语、输入格式、输出格式、工具用法、检查规则和常见失败模式。如果全部写进一个 AGENTS.md,地图本身也会变成噪音。Skill 的作用,就是把这些局部规程拆出去,按场景放在固定目录里。

Skill 不是“别人写得好的 prompt”。更准确地说:

Skill 是一组按场景打包的局部地图 + 操作规程 + 输出契约 + 工具说明 + 检查规则。

它的价值有两个。

第一,复用反复出现的工作方法。比如做 PPT 时,每次都要检查每页回答什么问题、证据是什么、听众为什么要信。这个方法不应该每次重新讲,可以打包成 PPT structure skill。

第二,懒加载上下文。写文章时加载 writing skill,做客户分析时加载 sales skill,做候选人评价时加载 interview scorecard skill。当前任务不需要的 skill 就不进入 context。

Skill 可以自然触发,也可以人工触发,还可以由规则触发。

自然触发最方便,但不保证每次准确。人工触发适合重要阶段,比如你明确说“用写作 skill 帮我改这篇文章”。规则触发最稳定,比如结构化输出里 output_type = ppt_outline,系统就自动加载 PPT 结构校验 skill。

C4 的核心不是让 agent 看更多东西,而是把上下文拆成可以按需加载的包。

T:任务类型决定工作方式

第二个维度是 T。我不建议把它只理解成“任务有几步”,因为很多任务不是沿着一条复杂度曲线升级的。所以这里用任务名字,不用序号。

更实用的问法是:

这次到底是哪一类任务?

有些任务是普通问答,有些是处理一份材料,有些要先对齐 spec,有些需要阶段性交付,有些是长任务接力,有些可以并行拆给多个 agent,还有一些其实不是让 AI 想,而是要让程序、tool 或 MCP 去做确定性动作。

普通问答和解释

这类任务就是问答解释。用户问一个问题,AI 给一个回答。这里通常不需要工作流。

例子:

- 解释一个概念。

- 改一句话。

- 给几个 idea。

- 帮我理解一个术语。

这类任务直接聊天就够。不要为了一个普通解释任务引入文档地图、plan mode 或 skill。

处理一份当前材料

这类任务是单材料处理。比如把一份会议纪要整理成行动项,把一段录音转写整理成摘要,把一份文档提取成字段。这里的核心是结构化输出。

这里的重点不是“让 AI 多思考”,而是把用户当前输入的材料处理干净。

典型任务包括:

- 会议纪要转行动项。

- 客户访谈摘需求、顾虑和下一步。

- 课程大纲整理成模块、目标和练习。

- 把一段文章改写成另一种风格。

它和 C1 经常一起出现:用户贴进来的材料就是上下文,AI 不应该编材料里没有的信息。

小目标任务先对齐 spec

这类任务是小目标任务。比如“帮我写一封客户邮件”“帮我写一个活动通知”“基于这些材料写一页方案”。

从这里开始,问题不再只是处理材料,而是达成目标。于是第一件事不是执行,而是对齐 spec:我们到底要做什么,什么算做对,哪些东西不能牺牲。

这也是很多任务失败的地方。用户说“帮我写一封客户邮件”,AI 立刻开始写。但它可能不知道写给谁、关系如何、邮件目的是什么、语气要正式还是轻松、有哪些话不能说、希望对方下一步做什么。

所以遇到这种任务时,一个好 agent 应该先把问题问清楚,或者至少显式写出它对任务的理解。这里可以用 grill 类工作方式:不要一上来执行,先挑战模糊词,追问边界,用具体场景压测需求。

更稳的做法,是把这段对齐过程落成一个中间文档。它可以叫 plan.mdbrief.mdprd.md,名字不重要,重要的是它把聊天里达成的共识从对话历史里拿出来,变成之后可以重新加载的文件。

{:title "先对齐 spec,再写中间文档"
 :description "小目标任务不是一上来就执行。先和 AI 聊清楚要什么,写成 plan / PRD;新 session 再读取这个文档开始干活。"
 :capacity 128000
 :unit "tokens"
 :messages [{:id :system
             :role :system
             :label "system prompt"
             :tokens 2800}
            {:id :tools
             :role :tool-schema
             :label "tools + MCP schemas"
             :tokens 17000}
            {:id :user-brief
             :role :user
             :label "user msg: rough goal"
             :tokens 900
             :note "我想做一个 X"}
            {:id :assistant-questions
             :role :assistant
             :label "assistant asks clarifying questions"
             :tokens 1400
             :note "追问边界、目标、验收"}
            {:id :user-details
             :role :user
             :label "user msg: answers and constraints"
             :tokens 1800
             :note "补充对象、范围、禁区"}
            {:id :assistant-plan-draft
             :role :assistant
             :label "assistant drafts plan"
             :tokens 2200
             :note "整理成可执行计划"}
            {:id :write-plan-call
             :role :tool-call
             :label "tool call: write plan.md"
             :tokens 520}
            {:id :write-plan-result
             :role :tool-result
             :label "tool result: plan.md saved"
             :tokens 420
             :note "中间文档落盘"}
            {:id :new-user
             :role :user
             :label "new session user msg"
             :tokens 600
             :note "继续按 plan 做"}
            {:id :read-plan-call
             :role :tool-call
             :label "tool call: read plan.md"
             :tokens 460}
            {:id :plan-doc
             :role :tool-result
             :label "tool result: plan.md"
             :tokens 3600
             :note "重新加载对齐结果"}
            {:id :assistant-work
             :role :assistant
             :label "assistant starts implementation"
             :tokens 1600}]
 :steps [{:phase :align
          :title "第一轮:用户先说粗略目标"
          :body "小目标任务已经不是简单问答。用户先说想要什么,但这个目标通常还不够精确。"
          :visible [:system :tools :user-brief]}
         {:phase :align
          :title "继续聊两轮,把 spec 对齐"
          :body "AI 先追问目标、边界、对象、验收标准;用户补充约束。这里的重点是把任务定义清楚。"
          :visible [:system :tools :user-brief :assistant-questions :user-details :assistant-plan-draft]}
         {:phase :artifact
          :title "AI 写出中间文档"
          :body "对齐以后,不要只把共识留在聊天历史里。让 AI 通过 tool call 写成 plan.md / PRD。"
          :visible [:system :tools :user-brief :assistant-questions :user-details :assistant-plan-draft :write-plan-call :write-plan-result]}
         {:phase :new-session
          :title "新 session 重新加载 plan"
          :body "重新开一个 session 后,旧聊天不会自动跟过来。AI 先读取 plan.md,把之前对齐好的 spec 放回当前窗口。"
          :visible [:system :tools :new-user :read-plan-call :plan-doc]}
         {:phase :work
          :title "基于 plan 开始干活"
          :body "这时 AI 不需要猜之前聊过什么,也不依赖旧对话历史,而是基于中间文档继续执行。"
          :visible [:system :tools :new-user :plan-doc :assistant-work]}]}

这个套路很重要:聊天负责对齐判断,文件负责保存共识。对齐过程可以很自由,但一旦要进入执行,就应该把关键结论写进稳定 artifact。

这也就是很多 agent 产品里所谓的 plan mode:先不要执行,先把需求、边界、步骤和验收标准对齐,形成计划;等计划被确认后,再进入执行模式。

多阶段交付需要 stage gate

这类任务是多阶段交付。比如行业调研、PPT 方案、PRD、候选人分析、课程设计。这类任务包含研究、提取、分析、设计、写作、检查多个阶段,不适合 one-shot。更好的方式是 stage gate:每个阶段都有可检查产物,比如 research.mdevidence-map.mdoutline.mddraft.mdchecklist.md

这里的重点不是“让 AI 一次写完整”,而是把过程拆成可检查的中间产物。人类不一定要盯每一步,但要能在关键节点看方向是否对。

典型阶段可以是:

1. 明确研究问题和资料来源。

2. 抽取关键事实和证据。

3. 形成 evidence map。

4. 输出结构或 outline。

5. 写初稿。

6. 按 checklist 校验。

多阶段交付适合 stage gate,因为阶段之间会发生判断:证据够不够,方向要不要改,结构是否成立,哪些地方需要人类补材料。

长任务需要任务状态

这类任务是长任务或持续工作流。任务会跨多轮,可能隔天继续,可能换 agent 接手,也可能让 agent 自己跑很久。

很多产品里所谓的 goal mode,通常就是把一个长任务交给 agent:人给目标、边界和验收标准,agent 自己拆步骤、调用工具、推进进度,最后交付结果。

但长任务最危险的地方不是“不会开始”,而是任务状态只留在聊天历史里。对话太长以后,早期约束会被稀释,失败尝试会和有效结论混在一起,agent 可能重复走错路,也可能被最近几轮对话带偏。

解决方式不是相信一个 session 能从头正确到尾,而是把任务状态外置:让 agent 定期维护计划、进度、决策记录、证据地图和 handoff。这样即使清空 context、换 session、换 agent,也能从稳定 artifact 重新接上任务。

{:title "长任务靠任务状态接力"
 :description "长任务不是一条对话从头跑到尾。先 plan mode 写计划;进入 goal mode 后按计划执行;关键节点更新进度;清空上下文后再读文档继续。"
 :capacity 128000
 :unit "tokens"
 :messages [{:id :system
             :role :system
             :label "system prompt"
             :tokens 2800}
            {:id :tools
             :role :tool-schema
             :label "tools + MCP schemas"
             :tokens 17000}
            {:id :user-brief
             :role :user
             :label "user msg: long goal"
             :tokens 1100
             :note "一个长任务目标"}
            {:id :plan-chat
             :role :assistant
             :label "planning conversation"
             :tokens 3800
             :note "追问、澄清、拆阶段"}
            {:id :write-plan
             :role :tool-call
             :label "tool call: write plan.md"
             :tokens 520}
            {:id :plan-saved
             :role :tool-result
             :label "tool result: plan.md saved"
             :tokens 420}
            {:id :start-user
             :role :user
             :label "new session: start work"
             :tokens 500}
            {:id :read-plan
             :role :tool-call
             :label "tool call: read plan.md"
             :tokens 460}
            {:id :plan-doc
             :role :tool-result
             :label "tool result: plan.md"
             :tokens 4200
             :note "阶段、约束、验收标准"}
            {:id :work-history
             :role :assistant
             :label "agent works for a while"
             :tokens 18000
             :note "执行、尝试、工具结果"}
            {:id :update-progress
             :role :tool-call
             :label "tool call: update plan.md + progress.md"
             :tokens 620}
            {:id :progress-saved
             :role :tool-result
             :label "tool result: progress saved"
             :tokens 500
             :note "关键节点落盘"}
            {:id :resume-user
             :role :user
             :label "new session: continue"
             :tokens 480}
            {:id :read-state
             :role :tool-call
             :label "tool call: read plan.md + progress.md"
             :tokens 560}
            {:id :state-docs
             :role :tool-result
             :label "tool result: current plan + progress"
             :tokens 5600
             :note "最新状态重新进入窗口"}
            {:id :continue-work
             :role :assistant
             :label "assistant continues work"
             :tokens 1800}]
 :steps [{:phase :plan
          :title "先对齐目标和 spec"
          :body "长任务开始时仍然要先对齐 spec。区别是计划要覆盖阶段、检查点和后续如何继续。"
          :visible [:system :tools :user-brief :plan-chat]}
         {:phase :artifact
          :title "把计划写成文档"
          :body "计划不能只留在聊天里。先通过 tool call 写成 plan.md,作为后续执行的入口。"
          :visible [:system :tools :user-brief :plan-chat :write-plan :plan-saved]}
         {:phase :work
          :title "清空上下文后读取 plan 开始跑"
          :body "进入执行时,可以开一个新 session。旧聊天历史不带过来,只读取 plan.md,然后开始干活。"
          :visible [:system :tools :start-user :read-plan :plan-doc :work-history]}
         {:phase :checkpoint
          :title "跑到关键节点,更新计划和进度"
          :body "执行一段以后,agent 发现到了关键节点,就把当前结论、已完成事项、失败路线和下一步写回 plan.md / progress.md。"
          :visible [:system :tools :plan-doc :work-history :update-progress :progress-saved]}
         {:phase :resume
          :title "再次清空上下文,读最新状态继续"
          :body "下一次继续时,不依赖旧聊天,而是读取刚更新的计划和进度文档。新的 agent 也能接手。"
          :visible [:system :tools :resume-user :read-state :state-docs :continue-work]}]}

这里的重点是:goal mode 不是“给 AI 一个大目标然后相信它自己记住一切”。真正可靠的做法是,长任务可以清空 context,但不能清空任务状态。任务状态应该被写进 plan.mdprogress.mddecision-log.mdhandoff.md 这类文件里。

可并行任务可以拆给 subagent

有些任务不是沿着一条主线顺序推进,而是天然可以拆成多个相对独立的分支。比如:

- 分别阅读三个模块,判断改动影响。

- 分别调研几个竞品,最后做对比。

- 分别检查几份资料,抽取证据。

- 分别验证几个可能原因,排除错误假设。

- 分别写方案的不同部分,再合并成一个版本。

这时就可以开 subagent

subagent 的价值不只是并行加速,更重要的是把局部任务放进局部上下文。主 agent 不必把所有材料都读进自己的窗口,也不必保留每个分支里的完整尝试过程。它只需要给每个 subagent 一个清楚的小任务:目标是什么,范围是什么,应该读什么材料,最后要交回什么格式。

subagent 做完以后,不应该把完整聊天历史倒回主窗口。它应该交回一个压缩过的中间结果:读了哪些材料,发现了什么,证据在哪里,哪些判断可靠,哪些地方还不确定,下一步建议是什么。

这个中间结果就是一种 handoff

handoff 可以理解成“一个 agent 写给另一个 agent 看的交接文档”。它不是给最终用户看的漂亮报告,而是为了让下一个 agent 或主 agent 不用重跑全部过程,也能接上工作。

一个好的 handoff 通常要包括:

- 当前任务范围。

- 已读材料和关键证据。

- 已完成结论。

- 失败尝试和不要再走的路。

- 剩余问题。

- 建议下一步。

- 如果涉及代码或文件,要说明改了哪里、还没验证什么。

所以 subagenthandoff 是一对概念:subagent 负责在隔离上下文里推进局部分支,handoff 负责把这个分支的有效结果交回主线。

反过来,如果任务不能清楚拆分,或者拆出去以后没有明确交回格式,就不要急着开 subagent。否则只是把一个混乱任务变成多个混乱任务。

确定性动作交给 program / tool / MCP

还有一类任务,不应该主要靠 AI “想”。

它们需要的是确定性动作:

- 批量处理文件。

- 查真实系统。

- 调用公司工具。

- 计算数字。

- 校验字段。

- 生成固定格式文件。

- 把结构化数据导成 PPT、CSV、JSON、邮件草稿或报告模板。

这些任务里,LLM 的职责是理解目标、组织步骤、选择工具、解释结果。真正执行确定性动作的,应该是 program、CLI、tool 或 MCP。

例如:

- 批量重命名文件,让程序做。

- 从 Excel 计算 KPI,让程序做。

- 查 CRM 客户状态,让 MCP / API 做。

- 查 GitHub issue,让工具做。

- 检查 action item 是否有 owner/date,让校验器做。

- 检查 PPT outline 是否超过页数,让程序做。

这里最重要的判断是:

这是适合 LLM 判断的问题,还是适合程序确定性执行的问题?

如果一个任务需要精确、重复、可校验,就不要逼 LLM 凭感觉完成。让 LLM 写结构、写规则、写校验器,然后让程序执行。

一个实用的 T 维度判断是:

小目标任务需要先对齐 spec,多阶段交付需要 stage gate,长任务需要任务状态,可并行任务需要 subagent 和 handoff,确定性动作需要 program / tool / MCP。

A:人要管过程到什么程度

第三个维度是 A,也就是自主性。它回答的是:控制权放在哪里。

同一个任务,既可以让人类每一步都看,也可以完全交给 agent 自由推进,还可以通过 skill、checklist、verifier、权限和阶段产物来管住过程。区别不在于 agent 能不能做,而在于这次任务适合哪种控制方式。

人类每一步都看

第一种方式是逐步指挥。agent 每做一步,先告诉人类;人类看完再决定下一步。它适合三类情况:

- 任务还没想清楚,过程本身就是探索。

- 风险高,错误动作不容易撤回。

- 中间判断比最终产物更重要。

比如第一次讨论架构、第一次改生产脚本、第一次写重要客户邮件,都不应该一上来就让 agent 跑到底。更好的方式是让 agent 先给判断、列风险、提下一步方案,人类确认以后再继续。

这种方式慢,但它买的是方向控制。你不是只要一个结果,而是要在过程中持续校正判断。

人类放手让 agent 自由推进

第二种方式是把过程控制权交给 agent。很多产品里的 goal mode 就属于这里:人给目标、边界和验收标准,agent 自己拆步骤、调用工具、处理错误,最后交付结果。

这种方式适合低风险、结果容易验证、失败可以重来的任务。比如整理一批文件、批量转换格式、安装一个能打开的软件、先做一个低风险原型。

但自由推进不是没有边界。比如你说“明天早上 9 点前让我准时到上海参加会议”,agent 可能确实把目标完成了,但如果它为了完成目标自动订了最贵的红眼航班、取消了你原来的安排、删掉了家庭日程、用你的账号付款,这个结果就不是你想要的。

所以 goal mode 的关键不是“更自动”,而是目标、权限、预算、验收标准和禁区是否足够清楚。否则 agent 可能完成了字面目标,却破坏了真正的约束。

人类用 guardrail 管过程

第三种方式是人不盯每一步,但也不完全放手。人类把关键判断做成 guardrail,让 agent 在边界内运行。

这里的 guardrail 不是一句空泛的“请谨慎”。它应该变成具体机制:

- skill:把某类任务的流程、规则、禁区和检查方式写进可加载的上下文包。

- checklist:把重要判断变成执行前后都要过一遍的清单。

- verifier:用程序、测试、lint、schema 或规则引擎检查结果。

- permission:限制 agent 能调用什么工具、能不能联网、能不能写文件、能不能付款或发布。

- stage gate:要求 agent 在关键节点交出 research.mdoutline.mddraft.mdchecklist.md 这类中间产物。

- handoff / progress docs:让长任务或多 agent 任务能在稳定文档里保存状态,而不是只靠聊天历史。

这种方式通常最适合长期工作流。人不用反复盯过程,但把判断标准提前放进环境里。agent 仍然有自主性,只是自主性被约束在可接受的轨道里。

所以更准确的说法是:

Goal mode 适合“帮我把事情办成”。每步都看适合“陪我一起判断”。Guardrail 适合“让 agent 自主推进,但不能越界”。

一旦你关心代码质量、架构、长期维护、中间判断、不可逆操作、钱、隐私或外部发布,就不要只在“每一步都看”和“完全放手”之间二选一。更好的做法通常是先设计 guardrail,再让 agent 在里面跑。

从任务坐标到工作方式

有了 C × T × A 以后,再看 agent 概念会清楚很多。它们不是一组并列的流行词,而是不同坐标下需要的能力组件。

上下文多时,需要文档地图或 skill。多阶段交付时,需要 stage gate。长期运行时,需要 progress docs 和 checkpoint。任务可以并行拆分、局部任务需要干净上下文时,才需要 subagent。一个 agent 要把中间结果交给另一个 agent 时,就需要 handoff。需要真实动作或确定性校验时,就让 program、tool、MCP、CLI 或 verifier 做。过程不能完全放手时,就用 skill、checklist、permission、stage gate、verifier 这些 guardrail 管住边界。

比如让 AI 生成一个 PPT outline,可以让模型提出页面结构、核心观点和证据需求。但检查页数是否超过 20 页、每页是否有核心观点、每个 claim 是否绑定证据,最好变成结构化字段和校验器。

凡是结构化字段,都可以让 AI 写校验器。凡是校验器能挡掉的问题,就不要浪费人的注意力。

最后可以把判断流程压缩成一张表:

这张表不是为了把任务机械分类,而是为了避免一上来就问“该用哪个工具”。更好的顺序是:

1. AI 需要哪种外部记忆?

2. 这次是哪类任务?

3. 我准备怎么管过程:每步都看、放手自由推进,还是用 guardrail 管边界?

4. 这个坐标下,应该用聊天、文档、stage gate、goal mode、skill、tool、program、subagent,还是 handoff?

会问 AI,只能得到一次回答。

会定位任务坐标,才能选择正确的 agent 工作方式。