最近学习了这个项目,很经典,对于agent以及harness又有了更近一步的了解。
项目地址:https://github.com/shareAI-lab/learn-claude-code/blob/main/README-zh.md
模型对于agent很重要,但是工程设计对于agent也同等重要,本质还是看对于系统设计的理解。
经典观点总结如下:
1.Agent 产品 = 模型 + Harness
Harness 是 agent 在特定领域工作所需要的一切:
Harness = Tools + Knowledge + Observation + Action Interfaces + Permissions
Tools: 文件读写、Shell、网络、数据库、浏览器
Knowledge: 产品文档、领域资料、API 规范、风格指南
Observation: git diff、错误日志、浏览器状态、传感器数据
Action: CLI 命令、API 调用、UI 交互
Permissions: 沙箱隔离、审批流程、信任边界
模型做决策。Harness 执行。模型做推理。Harness 提供上下文。模型是驾驶者。Harness 是载具。
2.Claude Code 本质:
Claude Code = 一个 agent loop
+ 工具 (bash, read, write, edit, glob, grep, browser...)
+ 按需 skill 加载
+ 上下文压缩
+ 子 agent 派生
+ 带依赖图的任务系统
+ 异步邮箱的团队协调
+ worktree 隔离的并行执行
+ 权限治理
3.agent模式
THE AGENT PATTERN
=================
User --> messages[] --> LLM --> response
|
stop_reason == "tool_use"?
/ \
yes no
| |
execute tools return text
append results
loop back -----------------> messages[]
这是最小循环。每个 AI Agent 都需要这个循环。
模型决定何时调用工具、何时停止。
代码只是执行模型的要求。
本仓库教你构建围绕这个循环的一切 --
让 agent 在特定领域高效工作的 harness。
1.s01: The Agent Loop (Agent 循环)
"One loop & Bash is all you need" -- 一个工具 + 一个循环 = 一个 Agent。
Harness 层: 循环 -- 模型与真实世界的第一道连接。
+--------+ +-------+ +---------+
| User | ---> | LLM | ---> | Tool |
| prompt | | | | execute |
+--------+ +---+---+ +----+----+
^ |
| tool_result |
+----------------+
(loop until stop_reason != "tool_use")
2.s02: Tool Use (工具使用)
"加一个工具, 只加一个 handler" -- 循环不用动, 新工具注册进 dispatch map 就行。
Harness 层: 工具分发 -- 扩展模型能触达的边界。
+--------+ +-------+ +------------------+
| User | ---> | LLM | ---> | Tool Dispatch |
| prompt | | | | { |
+--------+ +---+---+ | bash: run_bash |
^ | read: run_read |
| | write: run_wr |
+-----------+ edit: run_edit |
tool_result | } |
+------------------+
The dispatch map is a dict: {tool_name: handler_function}.
One lookup replaces any if/elif chain.
3.s03: TodoWrite (待办写入)
"没有计划的 agent 走哪算哪" -- 先列步骤再动手, 完成率翻倍。
Harness 层: 规划 -- 让模型不偏航, 但不替它画航线。
+--------+ +-------+ +---------+
| User | ---> | LLM | ---> | Tools |
| prompt | | | | + todo |
+--------+ +---+---+ +----+----+
^ |
| tool_result |
+----------------+
|
+-----------+-----------+
| TodoManager state |
| [ ] task A |
| [>] task B <- doing |
| [x] task C |
+-----------------------+
|
if rounds_since_todo >= 3:
4.s04: Subagents (Subagent)
"大任务拆小, 每个小任务干净的上下文" -- Subagent 用独立 messages[], 不污染主对话。
Harness 层: 上下文隔离 -- 守护模型的思维清晰度。
Parent agent Subagent
+------------------+ +------------------+
| messages=[...] | | messages=[] | <-- fresh
| | dispatch | |
| tool: task | ----------> | while tool_use: |
| prompt="..." | | call tools |
| | summary | append results |
| result = "..." | <---------- | return last text |
+------------------+ +------------------+
Parent context stays clean. Subagent context is discarded.
5.s05: Skills (Skill 加载)
"用到什么知识, 临时加载什么知识" -- 通过 tool_result 注入, 不塞 system prompt。
Harness 层: 按需知识 -- 模型开口要时才给的领域专长。
System prompt (Layer 1 -- always present):
+--------------------------------------+
| You are a coding agent. |
| Skills available: |
| - git: Git workflow helpers | ~100 tokens/skill
| - test: Testing best practices |
+--------------------------------------+
When model calls load_skill("git"):
+--------------------------------------+
| tool_result (Layer 2 -- on demand): |
| <skill name="git"> |
| Full git workflow instructions... | ~2000 tokens
| Step 1: ... |
| </skill> |
+--------------------------------------+
6.s06: Context Compact (上下文压缩)
"上下文总会满, 要有办法腾地方" -- 三层压缩策略, 换来无限会话。
Harness 层: 压缩 -- 干净的记忆, 无限的会话。
Every turn:
+------------------+
| Tool call result |
+------------------+
|
v
[Layer 1: micro_compact] (silent, every turn)
Replace tool_result > 3 turns old
with "[Previous: used {tool_name}]"
|
v
[Check: tokens > 50000?]
| |
no yes
| |
v v
continue [Layer 2: auto_compact]
Save transcript to .transcripts/
LLM summarizes conversation.
Replace all messages with [summary].
|
v
[Layer 3: compact tool]
Model calls compact explicitly.
Same summarization as auto_compact.
7.s07: Task System (任务系统)
"大目标要拆成小任务, 排好序, 记在磁盘上" -- 文件持久化的任务图, 为多 agent 协作打基础。
Harness 层: 持久化任务 -- 比任何一次对话都长命的目标。
把扁平清单升级为持久化到磁盘的任务图 。每个任务是一个 JSON 文件, 有状态、前置依赖 (blockedBy)。任务图随时回答三个问题:
-
什么可以做? -- 状态为
pending且blockedBy为空的任务。 -
什么被卡住? -- 等待前置任务完成的任务。
-
什么做完了? -- 状态为
completed的任务, 完成时自动解锁后续任务。.tasks/
task_1.json {"id":1, "status":"completed"}
task_2.json {"id":2, "blockedBy":[1], "status":"pending"}
task_3.json {"id":3, "blockedBy":[1], "status":"pending"}
task_4.json {"id":4, "blockedBy":[2,3], "status":"pending"}任务图 (DAG):
+----------+
+--> | task 2 | --+
| | pending | |
+----------+ +----------+ +--> +----------+
| task 1 | | task 4 |
| completed| --> +----------+ +--> | blocked |
+----------+ | task 3 | --+ +----------+
| pending |
+----------+顺序: task 1 必须先完成, 才能开始 2 和 3
并行: task 2 和 3 可以同时执行
依赖: task 4 要等 2 和 3 都完成
状态: pending -> in_progress -> completed
8.s08: Background Tasks (后台任务)
"慢操作丢后台, agent 继续想下一步" -- 后台线程跑命令, 完成后注入通知。
Harness 层: 后台执行 -- 模型继续思考, harness 负责等待。
Main thread Background thread
+-----------------+ +-----------------+
| agent loop | | subprocess runs |
| ... | | ... |
| [LLM call] <---+------- | enqueue(result) |
| ^drain queue | +-----------------+
+-----------------+
Timeline:
Agent --[spawn A]--[spawn B]--[other work]----
| |
v v
[A runs] [B runs] (parallel)
| |
+-- results injected before next LLM call --+
9.s09: Agent Teams (Agent 团队)
"任务太大一个人干不完, 要能分给队友" -- 持久化队友 + JSONL 邮箱。
Harness 层: 团队邮箱 -- 多个模型, 通过文件协调。
Teammate lifecycle:
spawn -> WORKING -> IDLE -> WORKING -> ... -> SHUTDOWN
Communication:
.team/
config.json <- team roster + statuses
inbox/
alice.jsonl <- append-only, drain-on-read
bob.jsonl
lead.jsonl
+--------+ send("alice","bob","...") +--------+
| alice | -----------------------------> | bob |
| loop | bob.jsonl << {json_line} | loop |
+--------+ +--------+
^ |
| BUS.read_inbox("alice") |
+---- alice.jsonl -> read + drain ---------+
10.s10: Team Protocols (团队协议)
"队友之间要有统一的沟通规矩" -- 一个 request-response 模式驱动所有协商。
Harness 层: 协议 -- 模型之间的结构化握手。
Shutdown Protocol Plan Approval Protocol
================== ======================
Lead Teammate Teammate Lead
| | | |
|--shutdown_req-->| |--plan_req------>|
| {req_id:"abc"} | | {req_id:"xyz"} |
| | | |
|<--shutdown_resp-| |<--plan_resp-----|
| {req_id:"abc", | | {req_id:"xyz", |
| approve:true} | | approve:true} |
Shared FSM:
[pending] --approve--> [approved]
[pending] --reject---> [rejected]
Trackers:
shutdown_requests = {req_id: {target, status}}
plan_requests = {req_id: {from, plan, status}}
11.s11: Autonomous Agents (Autonomous Agent)
"队友自己看看板, 有活就认领" -- 不需要领导逐个分配, 自组织。
Harness 层: 自治 -- 模型自己找活干, 无需指派。
Teammate lifecycle with idle cycle:
+-------+
| spawn |
+---+---+
|
v
+-------+ tool_use +-------+
| WORK | <------------- | LLM |
+---+---+ +-------+
|
| stop_reason != tool_use (or idle tool called)
v
+--------+
| IDLE | poll every 5s for up to 60s
+---+----+
|
+---> check inbox --> message? ----------> WORK
|
+---> scan .tasks/ --> unclaimed? -------> claim -> WORK
|
+---> 60s timeout ----------------------> SHUTDOWN
Identity re-injection after compression:
if len(messages) <= 3:
messages.insert(0, identity_block)
12.s12: Worktree + Task Isolation (Worktree 任务隔离)
"各干各的目录, 互不干扰" -- 任务管目标, worktree 管目录, 按 ID 绑定。
Harness 层: 目录隔离 -- 永不碰撞的并行执行通道。
Control plane (.tasks/) Execution plane (.worktrees/)
+------------------+ +------------------------+
| task_1.json | | auth-refactor/ |
| status: in_progress <------> branch: wt/auth-refactor
| worktree: "auth-refactor" | task_id: 1 |
+------------------+ +------------------------+
| task_2.json | | ui-login/ |
| status: pending <------> branch: wt/ui-login
| worktree: "ui-login" | task_id: 2 |
+------------------+ +------------------------+
|
index.json (worktree registry)
events.jsonl (lifecycle log)
State machines:
Task: pending -> in_progress -> completed
Worktree: absent -> active -> removed | kept
按照原工程中总结下来,彻彻底底的系统设计,分布式协同,协议,异步等,要想设计好agent系统还是主要看系统工程能力。