1. Agent 循环
Harness层:循环是模型与真实世界的第一道连接。
在大模型刚问世的时候,我们绝大多数人用它来修改代码都是询问->复制粘贴->报错->接着询问,这就是为什么Agent出现的原因,大模型不能读文件、跑测试、看报错。没有循环,每次工具调用都要人来手动执行。
那第一层就是加入工具调用以及建立循环:工具调用一般使用openai的schema格式,传入system prompt,只要大模型返回tool调用,就一直循环,解析出调用的工具,然后执行工具,将工具运行结果作为消息返回给上下文。
2. 工具调用
Harness层:工具分发是扩展模型能触达的边界。
工具用字典存储起来,每个工具都有处理函数,循环不变。
3. 待办写入
Harness层:规划--让模型不偏航,但不替它画航线。
多步任务中,模型会丢失进度,通过TodoManager来规划任务,todo作为工具被注入,同一时间只能进行一个任务,当连续3轮以上为调用todo工具时,系统会将“请更新计划”注入上下文中。
4. 子Agent
Harness层:上下文隔离--守护模型的思维清晰度
Agent工作越久,messages数组越臃肿,每次读文件、跑命令的输出都永久留在上下文里。
父 Agent 有一个 task 工具。Subagent 拥有除 task 外的所有基础工具 (禁止递归生成)。Subagent 以 messages=[] 启动, 运行自己的循环。只有最终文本返回给父 Agent。
5. Skill加载
Harness层:按需知识--模型开口要时才给的领域专长。
每个 Skill 是一个目录, 包含 SKILL.md 文件和 YAML frontmatter。SkillLoader 递归扫描 SKILL.md 文件, 用目录名作为 Skill 标识。Skill加载作为一个工具,由大模型决定加载哪一个Skill,然后运行工具返回对应Skill.md中的具体内容作为上下文。
6. 上下文压缩
Harness层:压缩--干净的记忆,无限的会话。
第一层 -- micro_compact: 每次 LLM 调用前, 将旧的 tool result (比如只保留最近三个工具调用结果)替换为占位符。
第二层 -- auto_compact: token 超过阈值时, 保存完整对话到磁盘, 让 LLM 做摘要。
第三层 -- manual compact: compact 工具按需触发同样的摘要机制,由大模型显式调用。
完整历史通过 transcript 保存在磁盘上。信息没有真正丢失, 只是移出了活跃上下文。
7. 任务系统
Harness层:持久化任务--比任何一次对话都长命的目标。
TodoManager 只是内存中的扁平清单: 没有顺序、没有依赖、状态只有做完没做完。真实目标是有结构的 -- 任务 B 依赖任务 A, 任务 C 和 D 可以并行, 任务 E 要等 C 和 D 都完成。
没有显式的关系, Agent 分不清什么能做、什么被卡住、什么能同时跑。而且清单只活在内存里, 上下文压缩一跑就没了。
把扁平清单升级为持久化到磁盘的任务图。每个任务是一个 JSON 文件, 有状态、前置依赖 (blockedBy)。任务图随时回答三个问题:
- 什么可以做? -- 状态为 pending 且 blockedBy 为空的任务。
- 什么被卡住? -- 等待前置任务完成的任务。
- 什么做完了? -- 状态为 completed 的任务, 完成时自动解锁后续任务。
具体实现为:
- TaskManager: 每个任务一个 JSON 文件, CRUD + 依赖图。
- 依赖解除: 完成任务时, 自动将其 ID 从其他任务的 blockedBy 中移除, 解锁后续任务。
- 状态变更 + 依赖关联: update 处理状态转换和依赖边。
- 四个任务工具加入 dispatch map。
8. 后台任务
Harness层:后台执行--模型继续思考,harness负责等待。
有些命令要跑好几分钟: npm install、pytest、docker build。阻塞式循环下模型只能干等。用户说 "装依赖, 顺便建个配置文件", Agent 却只能一个一个来。
具体实现为:
- BackgroundManager 用线程安全的通知队列追踪任务。
- run() 启动守护线程, 立即返回。
- 子进程完成后, 结果进入通知队列。
- 每次 LLM 调用前排空通知队列。
9. Agent团队
Harness层:团队邮箱--多个模型,通过文件协调。
Subagent (s04) 是一次性的: 生成、干活、返回摘要、消亡。没有身份, 没有跨调用的记忆。Background Tasks (s08) 能跑 shell 命令, 但做不了 LLM 引导的决策。
真正的团队协作需要三样东西: (1) 能跨多轮对话存活的持久 Agent, (2) 身份和生命周期管理, (3) Agent 之间的通信通道。
具体实现为:
- TeammateManager 通过 config.json 维护团队名册。
- spawn() 创建队友并在线程中启动 agent loop。
- MessageBus: append-only 的 JSONL 收件箱。send() 追加一行; read_inbox() 读取全部并清空。
- 每个队友在每次 LLM 调用前检查收件箱, 将消息注入上下文。
10. 团队协议
Harness层:协议--模型之间的结构化握手。
9中队友能干活能通信, 但缺少结构化协调:
- 关机: 直接杀线程会留下写了一半的文件和过期的 config.json。需要握手 -- 领导请求, 队友批准 (收尾退出) 或拒绝 (继续干)。
- 计划审批: 领导说 "重构认证模块", 队友立刻开干。高风险变更应该先过审。 两者结构一样: 一方发带唯一 ID 的请求, 另一方引用同一 ID 响应。
具体实现为:
- 领导生成 request_id, 通过收件箱发起关机请求。
- 队友收到请求后, 用 approve/reject 响应。
- 计划审批遵循完全相同的模式。队友提交计划 (生成 request_id), 领导审查 (引用同一个 request_id)。 一个 FSM, 两种用途。同样的 pending -> approved | rejected 状态机可以套用到任何请求-响应协议上。
11. Autonomous Agent
Harness层:自治 -- 模型自己找活干, 无需指派。
前面提到的队友,只在被明确指派时才动。领导得给每个队友写 prompt, 任务看板上 10 个未认领的任务得手动分配。这扩展不了。
真正的自治: 队友自己扫描任务看板, 认领没人做的任务, 做完再找下一个。
一个细节: Context Compact 后 Agent 可能忘了自己是谁。身份重注入解决这个问题。
具体实现为:
- 队友循环分两个阶段: WORK 和 IDLE。LLM 停止调用工具 (或调用了 idle) 时, 进入 IDLE。
- 空闲阶段循环轮询收件箱和任务看板。
- 任务看板扫描: 找 pending 状态、无 owner、未被阻塞的任务。
- 身份重注入: 上下文过短 (说明发生了压缩) 时, 在开头插入身份块。
12. Worktree任务隔离
Harness层:目录隔离--永不碰撞的并行执行通道。
Agent 已经能自主认领和完成任务。但所有任务共享一个目录。两个 Agent 同时重构不同模块 -- A 改 config.py, B 也改 config.py, 未提交的改动互相污染, 谁也没法干净回滚。
任务板管 "做什么" 但不管 "在哪做"。解法: 给每个任务一个独立的 git worktree 目录, 用任务 ID 把两边关联起来。
具体实现为:
- 创建任务。 先把目标持久化。
- 创建 worktree 并绑定任务。 传入 task_id 自动将任务推进到 in_progress。
- 在 worktree 中执行命令。 cwd 指向隔离目录。
- 收尾。 两种选择:
- worktree_keep(name) -- 保留目录供后续使用
- worktree_remove(name, complete_task=True) -- 删除目录, 完成绑定任务, 发出事件。一个调用搞定拆除 + 完成。
- 事件流。 每个生命周期步骤写入 .worktrees/events.jsonl:
总结
首先我觉得12章存在一些问题,从某种意义上只是解决了不同agent修改代码的冲突问题,但并没有阐明最后合并的问题,具体claude是怎么修改代码的还要思考。
以及上面所有章节,并不是都要使用,应该是按需配合,以一个官方提供的全部例子来看: