← 回到知识图谱
文章持续完善

跟读 learn-claude-code:17 个 harness 机制怎么挂到一个循环上

本文总结一门开源课程从一个 while 循环出发,把权限、压缩、记忆、任务图、团队、MCP 一个个挂上去。这篇是跟读总览:每个机制挂在循环哪里,换个位置会坏在哪。

创建 2026-11-05更新 2026-11-05阅读约 9 分钟
AgentHarnesslearn-claude-code

为什么跟读这门课

主线第 8 站 说过,Harness 是包在模型外面的运行时,管循环、工具、权限和记录。那一站讲了需要哪些零件,没讲零件怎么装。

learn-claude-code 正好补这一块。它用 Python 和 Anthropic SDK,从一个 150 行左右的循环开始,每章加一个机制,第 15 章把前 14 个机制装进同一个 3330 行的运行时,第 16、17 章再加固定编排和目标闸门。每章都有可以跑的代码和锁定设计约束的测试。

我按章读了源码和测试,把 17 章归成 7 站写成笔记。本文是这 7 站的总览。

两点阅读提示:

  • 课程仓库里同时有新版 s01 到 s17 和旧版 12 章(agents/、docs/),编号不同。本系列只跟新版。
  • 这是教学代码,不是 Claude Code 的源码。笔记里"和真实 Claude Code 的差别"一节,凡是没有公开资料支撑的都标了"推断"。

只有一个循环

整门课的骨架就是这几行:

messages[] → 调模型 → 回复里有 tool_use 吗?
                         ├─ 没有 → 结束
                         └─ 有   → 逐个执行 → tool_result 回填 → 回到开头

后面 16 章没有再写第二个循环。每章做的事,要么是在这个循环的某个位置挂一个东西,要么是换掉循环里的一个零件。所以我读每一章时只问两个问题:

  1. 这个机制挂在循环的哪个位置?
  2. 换个位置挂,会坏在哪?

第二个问题的答案,就是这一章的设计理由。

机制挂在哪里

下面是第 15 章集成版的一次迭代,括号里是机制来自哪一章:

 用户输入 → [UserPromptSubmit 钩子 s04]
  ① 注入    cron 到点任务 s12,后台完成通知 s11,todo 提醒 s05
  ② 预算    大结果落盘 → 裁中间 → 旧结果换路径 → LLM 摘要 s08
  ③ 上下文  记忆召回 s09,skill 目录 s07
  ④ 工具池  内置工具 s02 + mcp__server__tool s14(每轮重建)
  ⑤ 调用    组装 system prompt,重试与降级 s15
  ⑥ 判定    有没有 tool_use 块 s01
            没有 → [Stop 钩子 s04] → 目标判断器 s17 → 记忆抽取 s09
  ⑦ 执行    [PreToolUse:权限 s03 → 日志 s04]
            → 后台分支 s11 / 普通 handler s02
              (子代理 s06,load_skill s07,任务图 s10,Workflow s16)
            → [PostToolUse s04]
  ⑧ 回填    所有 tool_result 放进一条 user 消息,附上已完成的后台通知
 迭代之间:队友信箱 s13,cron 唤醒 s12,后台唤醒 s11

有几个位置我想了比较久:

  • 所有注入都放在迭代开头。 这里上一轮的 tool_result 已经回填完,是唯一不会把 tool_use 和 tool_result 拆开的位置。cron 线程如果在两者中间插一条消息,API 直接返回 400。
  • 权限排在后台分支前面。 反过来排,run_in_background 就成了绕过审批的后门。
  • 压缩排在注入之后、记忆召回之前。 注入的内容也要算进预算;召回要基于真正发出去的那份上下文。
  • 工具池每轮重建。 会话中途连上的 MCP server,下一轮就能用,权限策略同轮更新。

课程编号连续,代码不是一章叠一章

这是我读的时候最容易搞错的地方。很多章是直接建在第 4 章上的,测试里还专门断言"本章没有第 10 章的 Task 类"之类:

s01 → s02 → s03 → s04 ─┬─ s05 TodoWrite
                       ├─ s06 子代理
                       ├─ s07 skill → s08 压缩 → s09 记忆
                       ├─ s10 任务图 → s13 团队
                       ├─ s11 后台
                       ├─ s12 cron
                       ├─ s14 MCP
                       └─ s17 目标循环(独立运行)
s01 到 s14 → s15 集成 → s16 workflow

读第 11 章时要拿它和第 4 章比,不要和第 10 章比。

贯穿全课的几条规矩

规矩 违反了会怎样 出现在
每个 tool_use 都有配对的 tool_result,紧跟在下一条 user 消息里 API 返回 400,会话卡死 s01、s03(被拒也要回填)、s08(压缩要成对保留)、s11(占位结果)、s15
是否继续,看回复里有没有 tool_use 块,不看 stop_reason 兼容接口不一致时漏执行,留下悬空调用 s01、s15
工具出错也作为 tool_result 交回模型 一次异常打断整轮 s02、s03、s15
摘要、记忆、外部工具描述都当数据,不当指令 注入的文字经过压缩,变得像是权威指令 s08、s09、s14、s15
权限检查覆盖所有执行路径 后台、子代理、队友成了后门 s03、s04、s11、s15
模型说做完了,不等于做完了 提前收工 s05、s10、s17
交付语义要想清楚,至少一次就要幂等 重复执行或丢任务 s12、s15、s16

我拿自己站上的导游 Agent 对照过这张表,循环的停止条件和工具配对这两处最容易出问题。这也是第 1 站写得最细的部分。

七站

站 章节 回答什么问题
1 跟读 learn-claude-code(1):循环内核 s01–s04 循环怎么停;工具怎么分发;权限放在哪;钩子怎么让循环不再变
2 计划、子代理与上下文预算 s05、s06、s08 模型怎么不跑偏;大任务怎么隔离上下文;上下文满了先丢什么
3 跟读 learn-claude-code(3):跨会话记忆 s09 什么值得记;记忆什么时候选、什么时候写
4 任务图、后台与定时:让工作撑过一轮对话 s10–s12 工作怎么跨轮、跨时间不丢
5 多 Agent 团队:持久队友、信箱与原子认领 s13 子代理不够用时,队友怎么认领任务、怎么通信
6 技能、MCP 与集成 s07、s14、s15 工具从外部来时谁说了算;14 个机制装在一起会互相卡在哪
7 固定编排与目标闸门:Workflow 运行时和 Goal Loop s16、s17 什么时候把编排写死;谁来判断"真的做完了"

每站的结构相同:要解决的问题,机制怎么工作,换个做法会坏在哪,教学版的坑,和真实 Claude Code 的差别,自测题。

怎么读

  • 只有半天:第 1 站,然后直接看第 6 站里第 15 章的部分。前者是内核,后者讲 14 个机制放在一起时的顺序和冲突,看懂这两站就有了整门课的骨架。
  • 按问题补:关心"模型不跑偏"读 2、4、7 站;关心"上下文"读 2、3 站;关心"并发和异步"读 4、5 站;关心"工具来源和治理"读 6、7 站。
  • 准备面试:每站最后的自测题,先遮住参考答案自己讲,按问题、机制、例子、边界的顺序讲。被问到为什么这么排时,最有说服力的回答是讲清换个排法会坏在哪。

动手前的环境提醒

  • 课程用 .env 里的 MODEL_ID 和 ANTHROPIC_BASE_URL 选模型,可以接兼容 Anthropic 接口的其他服务商。
  • 第 13 章依赖 fcntl 和对 stdin 的 select,原生 Windows 跑不起来,要用 WSL。第 15 章对 fcntl 做了导入保护。
  • 在 Windows 上跑测试,还会遇到创建符号链接要权限、换行符和反斜杠路径这三类失败。它们和课程逻辑无关。

连接

这是一篇可以继续生长的笔记。沿着关系继续阅读 ↗