Skip to content

Commit 82ccaab

Browse files
Bill-Billionclaude
andcommitted
refine: rewrite s01 + add motto/harness headers to all 19 chapters
s01: Replace library metaphor with clean two-round dialogue showing the agent loop in action. Adopt docs/zh paper-writing structure: motto → problem → solution → numbered step walkthrough → quick ref. s02-s19: Add motto quote + Harness layer label to every chapter, matching the original docs/zh format. Reader immediately knows what this chapter is about and where it fits in the harness. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 39f5216 commit 82ccaab

18 files changed

Lines changed: 145 additions & 36 deletions

File tree

s01_agent_loop/README.md

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,104 @@
66

77
> 第 1/19 章
88
9+
> *"One loop & Bash is all you need"* — 一个工具 + 一个循环 = 一个 Agent。
10+
>
11+
> **Harness 层**: 循环 — 模型与真实世界的第一道连接。
12+
913
---
1014

11-
## 你想让 AI 帮你干活
15+
## 问题
1216

13-
大模型很聪明,但它"够不着"真实世界——不能读文件、不能跑命令、不能看报错。
17+
语言模型能推理代码,但碰不到真实世界——不能读文件、不能跑命令、不能看报错。
1418

1519
你可以给它一个工具(比如 bash),让它第一次调用拿到了结果。但然后呢?
1620

17-
**你自己把结果复制粘贴回对话框,再让它继续。**
21+
**你自己把结果复制粘贴回对话框,再让它继续。** 那你就是那个循环。我们要做的,就是把这个"复制粘贴"自动化。
22+
23+
---
24+
25+
## 解决方案
26+
27+
你问模型:"帮我创建 hello.py"。这个过程只有两轮:
28+
29+
```
30+
第 1 轮:
31+
模型回答: [tool_use: bash "echo 'print(42)' > hello.py"]
32+
↑ 模型调了工具 → 循环继续
33+
你帮它执行 bash,把结果 "(no output)" 告诉模型
34+
35+
第 2 轮:
36+
模型回答: [text: "已创建 hello.py"]
37+
↑ 模型没调工具 → 循环结束
38+
```
39+
40+
模型在第 1 轮觉得"我需要一个工具来干活",你执行了,把结果喂回去。第 2 轮它觉得"够了",停下来。
1841

19-
那你就是那个循环。我们要做的,就是把这个"复制粘贴"自动化。
42+
**整个 Agent 就是一个 while 循环。模型调了工具 → 你执行 → 结果喂回去 → 模型再判断。直到模型说"我不需要工具了",循环退出。**
2043

21-
## 一个比喻
44+
---
2245

23-
想象你派助手去图书馆查资料。
46+
## 工作原理
2447

25-
你问:"Python 怎么读文件?"助手查了一本书,告诉你需要用 `open()`。但他马上意识到光说函数不够,得给你一个例子。于是**他自己回去再查**,找到一段示例代码。查完之后觉得问题彻底回答清楚了,才回来汇报。
48+
将这个过程翻译成代码。分步来看:
2649

27-
关键在于:**助手不是查一次就回来**。他拿到中间结果后,自己判断"还需要继续查吗",需要就继续,不需要才停
50+
**第 1 步**:把用户的问题作为第一条消息
2851

29-
Agent Loop 就是把这个"自己判断要不要继续"自动化。
52+
```python
53+
messages = [{"role": "user", "content": query}]
54+
```
3055

31-
## 最小的 Agent:一个循环 + 一个工具
56+
**第 2 步**:将消息和工具定义一起发给 LLM。
3257

33-
![Agent Loop 流程图](images/agent-loop.svg)
58+
```python
59+
response = client.messages.create(
60+
model=MODEL, system=SYSTEM, messages=messages,
61+
tools=TOOLS, max_tokens=8000,
62+
)
63+
```
3464

35-
整个 Agent 就是一个 `while` 循环。模型每调用一次工具,循环就转一圈。模型说不调用了,循环就停
65+
**第 3 步**:追加模型回答,检查它是否调了工具。没调 → 结束
3666

37-
后面 18 个章节全都在这个循环上叠加新能力——但循环本身,始终不变。
67+
```python
68+
messages.append({"role": "assistant", "content": response.content})
69+
if response.stop_reason != "tool_use":
70+
return
71+
```
3872

39-
## 代码:不到 30 行
73+
**第 4 步**:执行模型要求的工具,收集结果。
74+
75+
```python
76+
results = []
77+
for block in response.content:
78+
if block.type == "tool_use":
79+
output = run_bash(block.input["command"])
80+
results.append({
81+
"type": "tool_result",
82+
"tool_use_id": block.id,
83+
"content": output,
84+
})
85+
```
86+
87+
**第 5 步**:把工具结果作为新消息追加,回到第 2 步。
88+
89+
```python
90+
messages.append({"role": "user", "content": results})
91+
```
92+
93+
组装为一个完整函数:
4094

4195
```python
4296
def agent_loop(messages):
4397
while True:
44-
# 1. 把消息发给大模型
4598
response = client.messages.create(
4699
model=MODEL, system=SYSTEM, messages=messages,
47100
tools=TOOLS, max_tokens=8000,
48101
)
49-
50-
# 2. 记住模型的回答
51102
messages.append({"role": "assistant", "content": response.content})
52103

53-
# 3. 模型没调用工具 → 任务完成,退出
54104
if response.stop_reason != "tool_use":
55105
return
56106

57-
# 4. 执行模型要求的所有工具调用
58107
results = []
59108
for block in response.content:
60109
if block.type == "tool_use":
@@ -64,29 +113,19 @@ def agent_loop(messages):
64113
"tool_use_id": block.id,
65114
"content": output,
66115
})
67-
68-
# 5. 把工具结果喂回去,循环继续
69116
messages.append({"role": "user", "content": results})
70117
```
71118

72-
**两个关键瞬间**
73-
- `stop_reason == "tool_use"` → 模型举手说"我还要用工具",循环继续
74-
- `stop_reason != "tool_use"` → 模型说"我做完了",循环退出
119+
不到 30 行,这就是整个 Agent。后面 18 个章节都在这个循环上叠加机制——循环本身始终不变。
75120

76-
## 消息是怎么流动的
121+
**循环只有两个信号**
77122

78-
```
79-
用户: "帮我创建一个 hello.py"
80-
81-
助手: [text: "好的,我来创建"] + [tool_use: bash "echo 'print(42)' > hello.py"]
82-
↓ ← stop_reason = "tool_use",循环继续
83-
用户: [tool_result: "(no output)"]
84-
85-
助手: [text: "已创建 hello.py"]
86-
← stop_reason = "end_turn",循环结束
87-
```
123+
| 信号 | 含义 | 循环动作 |
124+
|------|------|---------|
125+
| `stop_reason == "tool_use"` | 模型举手说"我要用工具" | 执行 → 结果喂回去 → 继续 |
126+
| `stop_reason != "tool_use"` | 模型说"我做完了" | 退出循环 |
88127

89-
每一步都是**追加**到同一个 `messages` 列表里。模型看到的是完整对话历史,所以它知道之前做了什么。
128+
---
90129

91130
## 速查
92131

@@ -97,6 +136,8 @@ def agent_loop(messages):
97136
| `messages` | 累积式消息列表,每一步追加,不删除 |
98137
| `tool_result` | 工具执行的结果,必须带 `tool_use_id` 告诉模型"这是你要的" |
99138

139+
---
140+
100141
## 试一下
101142

102143
```sh

s02_tool_use/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → `s02` → [s03](../s03_permission/) → s04 → ... → s19
66

77
> 第 2/19 章
88
9+
> *"加一个工具, 只加一个 handler"* — 循环不用动, 新工具注册进 dispatch map 就行。
10+
>
11+
> **Harness 层**: 工具分发 — 扩展模型能触达的边界。
12+
913
---
1014

1115
## 只有 bash 一把瑞士军刀

s03_permission/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → s02 → `s03` → [s04](../s04_hooks/) → s05 → ... → s19
66

77
> 第 3/19 章
88
9+
> *"先划边界, 再给自由"* — 权限管线决定哪些操作需要审批。
10+
>
11+
> **Harness 层**: 权限 — 在工具执行前加一道门。
12+
913
---
1014

1115
## Agent 能 `rm -rf /`

s04_hooks/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → s02 → s03 → `s04` → [s05](../s05_todo_write/) → s06 → ... →
66

77
> 第 4/19 章
88
9+
> *"挂在循环上, 不写进循环里"* — 钩子在工具执行前后注入扩展逻辑。
10+
>
11+
> **Harness 层**: 钩子 — 扩展点不侵入循环。
12+
913
---
1014

1115
## 循环快被改烂了

s05_todo_write/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → s02 → s03 → s04 → `s05` → [s06](../s06_subagent/) → s07 → ..
66

77
> 第 5/19 章
88
9+
> *"没有计划的 agent 走哪算哪"* — 先列步骤再动手, 完成率翻倍。
10+
>
11+
> **Harness 层**: 规划 — 让 Agent 在动手之前先想清楚。
12+
913
---
1014

1115
## 做着做着就偏了

s06_subagent/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → s02 → s03 → s04 → s05 → `s06` → [s07](../s07_skill_loading/)
66

77
> 第 6/19 章
88
9+
> *"大任务拆小, 每个小任务干净的上下文"* — Subagent 用独立 messages[], 不污染主对话。
10+
>
11+
> **Harness 层**: 子 Agent — 上下文隔离, 注意力不漂移。
12+
913
---
1014

1115
## 上下文被中间过程淹没了

s07_skill_loading/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → s02 → s03 → s04 → s05 → s06 → `s07` → [s08](../s08_context_c
66

77
> 第 7/19 章
88
9+
> *"用到时再加载, 别全塞 prompt 里"* — 通过 tool_result 注入, 不塞 system prompt。
10+
>
11+
> **Harness 层**: 知识 — 按需加载, 不堆满上下文。
12+
913
---
1014

1115
## system prompt 里堆了 6500 行文档

s08_context_compact/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → s02 → s03 → s04 → s05 → s06 → s07 → `s08` → [s09](../s09_m
66

77
> 第 8/19 章
88
9+
> *"上下文总会满, 要有办法腾地方"* — 四层压缩策略, 便宜的先跑贵的后跑。
10+
>
11+
> **Harness 层**: 压缩 — 干净的记忆, 无限的会话。
12+
913
---
1014

1115
## Agent 跑着跑着不动了

s09_memory/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → ... → s07 → s08 → `s09` → [s10](../s10_system_prompt/) → s11
66

77
> 第 9/19 章
88
9+
> *"记住该记的, 忘掉该忘的"* — 三个子系统: 筛选、提取、整理。
10+
>
11+
> **Harness 层**: 记忆 — 跨压缩、跨会话的知识积累。
12+
913
---
1014

1115
## 每次压缩后 Agent 都失忆了

s10_system_prompt/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ s01 → ... → s08 → s09 → `s10` → [s11](../s11_error_recovery/) → s12
66

77
> 第 10/19 章
88
9+
> *"prompt 是组装出来的, 不是写死的"* — 分段 + 按需拼接。
10+
>
11+
> **Harness 层**: 提示 — 运行时组装, 不硬编码。
12+
913
---
1014

1115
## system prompt 变成了一堵文字墙

0 commit comments

Comments
 (0)