Skip to content

In Practice — 用这个教程本身验证前面 15 章

用一个具体项目的真实构建过程,映射回每个概念。

这个教程是用一个 agent 工具写的。

起点是一个文件——draft-ideas.md,68 行。里面列了几个概念:上下文、工具、MCP、Commands、Sub Agent。每个概念下面两三句话,剩下的部分写着"暂不在范围内"。

用户带着这个文件走进一个空仓库,对 agent 说了第一句话:

"用这个 repo 建一个 GitHub Pages 教程站。"

紧接着第二句:

"先搭架子,内容回头再说。"

VitePress 站点结构、GitHub Pages 部署配置、中英双语路由——几分钟内到位。

然后用户指了一下 draft-ideas.md:"phase 1。"但在 agent 动手之前,补了一句:"先加载 brainstorming skill。" 不是直接让 agent 展开,而是先指定用什么方式展开。

展开之后,用户觉得 68 行不够撑起一个教程站。需要行业视角。于是给了一条指令,里面列了一串名字:Steve Yegge、Gene Kim、Karpathy、Martin Fowler,还有 Cline、Roo、Claude Code、OpenCode 的作者们——"从这些人那汲取关键洞见,看看怎么增强我们的骨架。"

六个 librarian agent 同时出发,分头去查不同方向的行业洞见。用户在旁边说了一句后来反复出现的话:"sub-agent 尽量后台跑"——理由很直接:"这样我还能继续和你说话。"

调研素材回来后,用户不满意中国市场的覆盖度。提了一个人名作为线索,让 agent 去找更多中国本土的 AI coding 实践者。又是一组 agent 同时出发。

素材堆积到一定量后,agent 把它们组织成了一个大文件。用户看了一眼组织方式,直接否了:"a 到 f、g 到 l,这文件名起得太烂了。我说了要逻辑清晰有条理,这不是。" 重来。

最终素材按逻辑拆分到了 materials/ 目录下。但这些素材不是照搬的——用户说了一句成语:"它山之石可以攻玉。"从"造 agent"的行业知识中,筛选对"用 agent tool 的人"有价值的东西。

然后开始一个个过。用户和 agent 坐在一起,对着素材逐个讨论每个概念值不值得进骨架:

  • "值得单独给一个位置?" —— "不值得,但挺好的,作为子项。"
  • "需要专门讲吗?" —— "简单提一嘴就够了。"
  • "这个要进骨架吗?" —— "要,但不是讲 LangChain 那些框架。"
  • "Human-in-the-loop?" —— "很好,值得单独占一个位置。"
  • "Cost?" —— "暂不在范围内。"

过程中确定了几条关键原则:"我们要做到 agent agnostic"——不绑任何特定产品。"就讲通用概念,不区分谁在读。"

68 行变成了 16 个概念节点。骨架锁定。

写内容。第一篇是 context.md——但用户不只是说"写吧",他给了一个方向:"把 HTTP 请求和响应的概念带进去,还有 SSE 事件——agent 就是这么和 LLM API 通信的,上下文就是这么累积的。" 这条指令确立了贯穿全站的技术解释模式:用 HTTP 请求/响应来展示 agent 和 LLM 之间的通信。

第一篇稿子落地后,开始第二篇 actors.md。写完第一版,用户说"不太好,改。"然后做了一件事:"我已经把两个文件 stage 好了,你只管编辑内容,这样我能看 diff。" 用户提前把文件暂存好,agent 只管编辑内容,改完不要 stage 也不要 commit——用户要自己看 diff,自己决定接不接受。

这个模式后来反复出现。

两篇打好基础后,所有剩余节点同时派出去。十几个 sub-agent 一次性收到任务,每个负责一个概念节点的中英双语初稿。完成通知开始一个接一个回来。有几个写到了错误的目录,用户说"别删,移过去就行。"同时,Oracle 被叫来审查关键节点的质量。

当天结束时,所有节点的初稿都到位了。

之后进入新阶段。用户要求加载 humanizer skill 开始审校。另一个方向也同时启动:SVG 插图。第一张图不好看,用户直说了。然后有个转折——用户说:"给它相关的 skill 和 prompt,但不要限制它的想象力。"结果回来,SVG 里有会动的箭头。用户说了一句:"我之前都不知道 SVG 还能这么玩。"从那以后,SVG 生成的策略变了——给方向,不给限制。

写作风格也在这个阶段固化。用户说:"以后编辑这个 repo 的内容,都要加载 humanizer,还有十人混血儿风格。写进 CLAUDE.md。"一句话,从对话里的临时偏好变成了规则文件里的永久标准——每个会话、每个 sub-agent 自动继承。

审校不是一轮就完。先是 humanizer 清理 AI 痕迹——"此外"、"至关重要"、"不可或缺",逐个揪出来换掉。然后换了不同的模型交叉审校:Kimi K2.5 和 MiniMax 各看一遍,专门找 Opus 自己的盲区。最后 Opus 做穷尽扫描,连"本质上"在同一篇里出现几次都数。每一轮都发现前一轮漏掉的东西。

内容也不是写完就定了。用户启动了一轮研究——用教程自己教的方法(多代理并行编排)来验证教程自己的覆盖度。大量社区来源喂进去,跑出来骨架设计合理,问题不在广度在深度。三个盲区被标为高优先级:并行会话治理、长时循环控制、团队级配置管理。这三个发现推动了第二轮内容补深,近十个节点被扩展。

从 68 行到完整教程站,中间是审校、SVG 迭代、规则的生长、反复的人工纠偏。那些才是下面每节的故事。

用的工具是 OpenCode,但背后的模式放到任何 agent 工具上都成立。

规则书——从空白到纪律

对应概念:System Instructions知识喂养

一开始,CLAUDE.md 只有工程约束——技术栈是什么、用 bun 不用 npm、构建命令怎么写。跟内容无关。

然后事情开始发生。

Agent 在讲某个概念时编造了一个不存在的机制。用户的反应是一句"别瞎编"。这句话推动了一条规则:涉及具体实现细节的断言,必须标注来源或加限定词。

一轮审校下来,五个标题被标记为"太文艺"——"把你的大脑装进 Agent"、"给 Agent 请家教"这类。读者靠标题定位内容,文艺标题传递不了信息。于是规则文件多了一条:标题禁止文艺化。

这个过程一直在发生。每次口头纠偏,如果同类问题出现过两次以上,就不再停留在对话里——写进规则文件,下一轮全局生效。

审校时发现"心智模型"这个词太学术——读者根本不需要这个术语来理解概念。禁用,换成"理解方式"。"杠杆"听着像 MBA 课件,换成"最有效的方式"。"伤疤"和"结晶"像文学隐喻,换成"踩坑教训"和"验证过的好做法"。

整个规则文件就是这么长出来的——不是一次性设计,是每踩一个坑就多一条。

禁用词只是一半。另一半是把"感觉不对"变成可执行的检查。

有一轮审校,用户注意到文档里还残留着 emoji 标记——🔍、🎯、🧠。一句"这些还在",触发了一次全量扫描:遍历所有 .md 文件,找出残留符号,批量清理。不是一个个手动找——让 agent 跑脚本,把所有命中位置列出来,统一处理。

穷尽审校阶段,焦点从"哪些词不该用"升级到"哪些词用太多了"。中文的"本质上"和它的英文对应词——都是 AI 生成文本的高频指纹。数了一遍,同一篇文章里出现了八处。于是多了一条密度规则:同一篇文档中不超过两处,超出的换成"说白了"或直接删掉。

从禁止某个词,到控制同一个词的出现频率——这种精度要跑到第五轮审校才能提炼出来。

但不是每条规则都来自用户纠偏。审校到后半程,Agent 自己开始归纳模式——从多轮修改中提炼出"审美优先级"五条排序(中性优于判断性、精确优于生动、朴素优于华丽),主动提议写入 CLAUDE.md。规则文件变成了共建产物:用户踩坑时加一条,Agent 发现规律时也加一条。

规则还分层级。有些写在项目的 CLAUDE.md 里,只影响这个仓库。有些被升级到了用户级配置,影响该用户所有项目的所有会话。比如"sub-agent 优先后台运行",最初是这个项目里的口头偏好,后来被写进了用户全局的系统指令——因为它不只对这个项目有用,换个项目也一样需要。一条规则走到什么层级,取决于它是项目特有的,还是通用的。

可迁移的模式:每个 agent 工具都有"系统指令"层。改这一层比反复口头提醒高效得多——口头纠偏只影响当前对话,写进规则文件影响之后所有对话。

Skills——按需装卸的能力

对应概念:SkillsSlash Commands

写教程正文时,加载 adopt-agentic-writer——它带着十人混血儿写作风格和 HTTP 请求/响应解释模板。做审校时,换成 humanizer-zh——专门清理 AI 生成痕迹。做 SVG 插图时,切到 baoyu-infographicbaoyu-image-gen 这组视觉 skill。

不同阶段,核心 skill 不同。adopt-agentic-writer 在整个内容写作阶段常驻;到审校阶段 humanizer-zh 接管,但 writer 仍然在场。视觉阶段切到 baoyu 系列后,写作类 skill 就不再给 sub-agent 了——它们的任务不需要。

这里有个容易踩的坑:sub-agent 是无状态的。主 agent 加载了某个 skill,不代表它派出去的子任务也知道这些规则。有一次用户发现 sub-agent 生成的 SVG 没遵循视觉设计规范,问了一句"你给 sub-agent 加载 baoyu skill 了吗?"——原因就是派发时忘了把 skill 传过去。

之后形成了一个习惯:每次给 sub-agent 派任务,明确列出它需要加载的 skill。能力不是默认继承的,得显式传递。

可迁移的模式:Skill 在不同工具里叫法不同——prompt 片段、规则文件、模板。核心机制相同:按需加载一段上下文,用完可以卸掉。和 Slash Command 的区别是,Command 是"这次做这件事",Skill 是"从现在起按这个方式做事"。

工具——Agent 怎么干活

对应概念:内置工具MCPCLI 工具

看 agent 的工具调用记录,有个特征很明显:读文件的次数远超改文件。不是因为 agent 爱阅读——改教程正文时,几乎每次 edit 之前都有对同一个文件的 read。先确认当前内容和上下文,再动手改。不读就改,大概率改错位置或丢掉上下文。

改文件时,局部修改和整文件覆写是两条路。改一段话、换一个词用局部编辑;新建文件或者整体重写的用覆写。有一次 SVG 迭代中,sub-agent 用整文件覆写的方式"注回动画",结果把已有的动画全盖掉了。之后策略变了——动画修改只用增量编辑,不整文件重写。

外部信息搜索有个有趣的分布:绝大部分搜索发生在 sub-agent 的会话里,不在主会话。用的是 firecrawl、exa、GitHub 搜索这些 MCP 工具。主 agent 负责调度和定稿,sub-agent 负责出去找证据——找到了把结论带回来,主 agent 再决定怎么用。

搜索的内容跟阶段有关。早期是行业调研——Reddit、Hacker News、技术博客,找有价值的社区信号。后期变成了事实核查——官方文档、GitHub 源码,验证教程里的技术断言是否准确。有一次,用户要求核查四种不同 agent 工具的上下文注入时机,sub-agent 分头去查各自的官方文档,把结论带回来交叉对比,改掉了教程里两处不准确的描述。搜索不是一次性的活——它贯穿整个项目,只是目标随阶段在变。

CLI 的使用模式也值得看。构建验证跑了很多次——每改完一轮就验证一次。Git 操作以本地审查为主(diff、status、log),push 到远端的次数很少。还有一个意外用法:bun 被拿来直接跑 SQLite 查询,分析工作会话数据——CLI 不只是辅助手段,它就是 agent 做数据分析的一等工具。

还有一个跟上下文直接相关的现象:会话够长之后,上下文会被自动压缩——对话历史被摘要,早期的细节被丢弃。主 session 触发了几十次压缩事件。

压缩之后会发生什么?Agent 做的第一件事不是继续改文件——而是回读 CLAUDE.md 和计划文件。先"记起来自己是谁、要做什么",再继续干活。这个行为在数据里看得很清楚:压缩后的几步操作里,大部分都是读取规则和计划。

这就是第一章讲的"压"和"选"在实战中的样子——窗口压缩了,agent 得主动选择先恢复哪些关键上下文。规则文件和计划文件之所以被优先回读,是因为它们是"决策基准"——丢了其他东西可以重查,丢了决策基准就会前后矛盾。

可迁移的模式:不管用什么 agent 工具,"读→改→验"这条链路是通用的。MCP 让外部搜索变成可标准化委派的能力。CLI 的输出是纯文本,天然适合注入上下文。

编排——一条消息派出去一群

对应概念:编排模式Sub Agent

这个项目的编排不是"派一个、等一个"。用户在早期就明确说过:"sub-agent 尽量后台跑"——理由很直接:你后台跑着,我还能继续和主 agent 对话。

于是形成了一个固定节奏:扇出→推进→回收

扇出:同类任务批量派给 sub-agent。写教程时,十几个节点的初稿同时派出去。做 SVG 时,多张图同时生成。单条消息里最多同时派了十五个 sub-agent。

推进:sub-agent 在后台跑的时候,主 agent 继续做其他事——审查之前的结果、更新规则文件、回应用户的新需求。

回收:到检查点再批量收结果。不是每派一个就立刻等回复,而是积攒一波,一起拉回来看。

什么时候不并行?需要当场判定的事——build 验证、commit 操作、最终审查结论。这些必须串行,结果出来才能决定下一步。

举个具体例子。In Practice 这章重写时,需要从工作会话里提取模式。一条消息同时派了十一个 sub-agent,分头挖不同维度——有的查编排模式,有的查 SVG 迭代,有的查用户纠偏记录。主 agent 在它们跑的时候继续做结构设计。等结果攒够了,一次性拉回来看哪些发现能用。

每个派出去的任务都有结构化的 prompt:目标是什么、必须做什么、禁止做什么、预期产出是什么。不是随手一句话。这套结构在失败恢复时尤其有用——sub-agent 没完成任务时,续接会话可以精确指出"哪里没做到"。

能力包也跟着阶段切换。写教程阶段,sub-agent 带着写作 skill 出发;审校阶段,换成 humanizer;到 SVG 阶段,整套视觉 skill 一次性打包给 sub-agent。不是固定模板——主 agent 根据当前任务域选能力包,不同阶段几乎没有交集。

失败恢复时,session 续接比重新开始高效得多——上下文已经在那里,不需要重新读文件、重新理解背景。续接的 prompt 只需要说清"哪里没做到"。早期尝试续接时经常失败——工具还不够稳定,session 找不到。到后期,续接变成了标准操作。

还有一种模式值得提:有些后台任务跑完了,结果从来没被显式回收。不是忘了——是任务的价值已经通过其他途径获得了,或者当时的决策已经不需要这个输出了。并行派发天然允许冗余:多派几个比少派一个的风险低,哪怕有些结果最终没用上。

角色分工也很清晰。Oracle(负责内容判断和叙事策略的 sub-agent)、Metis(负责计划完整性和验收标准的 sub-agent)、主 agent 做最终裁决。不是谁都能做一样的事——不同角色有不同的专长。

可迁移的模式:并行还是串行,不取决于工具,取决于任务之间有没有依赖。无依赖就并行,有依赖就串行。Sub-agent 的上下文是隔离的——主 agent 看到的东西,sub-agent 不一定看到,反过来也一样。

验证——技术通过不等于验收通过

对应概念:上下文Human-in-the-Loop

做 SVG 插图的时候,这个区别体现得最清楚。

一张 context.svg,经历了十一次迭代。中间有一段特别典型的链条:

风格多样化阶段,为了换视觉风格,原来的三十个动画掉到了五个。技术上没报错——XML 合法、构建通过。但内容损失了。

第一次尝试注回动画失败了。sub-agent 用整文件覆写的方式注入,结果把新风格也改坏了。

换了策略——改用增量编辑,逐个动画注入。恢复到二十六个。主 agent 手动补了剩下的四个,回到三十。

然后用户看了一眼:"看着不太清楚,四个东西排成一条线不太合适"。布局问题。于是又启动了一轮重设计——从线性布局改成 2×2 矩阵。

整个过程暴露出验证的三个层次:

  • 技术验证:XML 合法、构建通过、没有语法错误。可以自动化。
  • 任务验证:动画数量够不够、文字有没有截断、信息有没有丢失。可以脚本化检查。
  • 审美验证:好不好看、有没有"灵魂"、布局清不清楚。只有人能判断。

前两层通过了,第三层一样会被打回。用户说过"太呆板"、"没灵魂"、"像个鼻子"——这些反馈没法写进自动化脚本,但它们决定了"行不行"的最终结果。

可迁移的模式:任何 agent 工作流都有这三层验证。纯技术任务可能只需要前两层。但涉及创意和判断的任务,第三层不可省略。

人——改流程比改内容多

对应概念:Human-in-the-Loop三角关系

回看用户的纠偏记录,有个意外的发现:将近一半的纠偏不是在改内容——是在改流程。

"sub-agent 必须后台运行"——这是流程。

"文本编辑必须由主 agent 亲自做,不委托 sub-agent"——这也是流程。

"review 之前不许 commit"——还是流程。

纠偏的语气有一个明显的递进。一开始是温和的偏好声明:"sub-agent 尽量后台跑"。然后是直接否定:"这看着不行,我们不是在做营销。"到反复出现同类问题时,语气明显升级——直接指出 agent 在编造事实,要求必须有证据再下结论。

最激烈的一次是关于事实准确性。Agent 在解释某个概念时,对 skill 加载机制做了一连串断言——听起来很合理,但查了源码发现全是编的。用户的第一句是"别瞎编"。Agent 承认了,改了。但几轮之后,类似问题又冒出来,用户直接加压:"讲事实。"

两次纠偏加在一起,推动了一条永久规则:涉及具体技术机制的断言,必须区分"已验证"和"未验证"。写进 CLAUDE.md 之后,后续所有会话和 sub-agent 都受约束。问题不再出现。

还有一种纠偏方式不那么明显:打断。用户在 agent 还没说完的时候直接中断,切到新方向。主 session 里出现了二十次。打断不是否定——大多数时候不是因为 agent 做错了,而是用户的优先级变了。Agent 在做阶段性汇报、用户已经知道结论了——打断,切到下一个任务。

同一个问题被纠偏两次以上,说明 agent 没有"学到"。这时候正确的做法不是第三次口头提醒,而是写进规则文件。口头纠偏只影响当前对话;写进 System Instructions 影响之后每一次请求。

但不是所有口头纠偏都变成了规则。追踪这些转化会发现一个有趣的分布:"标题禁止文艺化"出现一次就被写入——因为同类问题一看就知道还会再出现。而"review 前不许 commit"在对话里反复提了好几次,却一直停留在运行时约束,没有变成规则条文。停留在对话里的约束有一个风险:换个 session 它就失效了。

什么时候口头纠偏就够了?只出现过一次、特定于当前任务的问题。什么时候必须写进规则文件?同类问题出现过两次以上,或者跨 session 也需要生效的约束。这个判断本身就是 HITL 的一部分——不是所有纠偏都值得制度化,但重复出现的纠偏如果不固化,就是在浪费人的时间。

用户还有一种操作模式——铺轨。"我已经 stage 好了这两个文件,你只管改内容"——用户先把文件暂存好,agent 只管编辑内容,不碰版本控制。用户搭好铁轨,agent 在轨道上跑。

这不是因为 agent 不会用 git。而是提交历史一旦弄乱,回溯成本高。用户选择自己掌控这个环节——先审查再提交,确保每个 commit 干净可追溯。高风险操作自己来,低风险操作放手——这就是 HITL 的核心判断。

可迁移的模式:人在 agent 工作流中做三件事——定义任务、过程纠偏、结果验收。纠偏如果重复发生,就该固化成规则。高风险操作保留人工审批,低风险操作放手自动化。

这篇文章本身

你刚读完的这些文字,本身就经历了前面描述的所有环节。

多个 sub-agent 并行搜索工作会话历史,提取模式,带回结论。Oracle(专长叙事策略的 sub-agent)审查整体结构,Metis(专长计划审查的 sub-agent)检查完整性。用户说"用人话写,不要堆数字"——叙述方式从统计报告变成了你看到的这些故事。写作过程遵循着 CLAUDE.md 里那些从踩坑中长出来的规则。

写这章的时候,用了 SQLite 查询来翻阅工作会话——同一个 bun -e + 数据库的组合,在前面"工具"一节里刚讲过。Git 的提交历史被逐条对齐到 session 消息上——每个 commit 背后的用户指令都被找出来,不是靠回忆,是靠数据。

教程用自己的构建过程验证了自己讲的理论。如果这还不够说明"上下文管理"是怎么回事,回去重读第一章