# 前言：为什么要自己造一个

2024 年底，Claude Code 发布。我第一次用它修了一个真实的 bug，没有写一行代码——只是描述了问题，然后看着它读文件、找函数、改代码、跑测试。整个过程大概两分钟。

我当时的第一反应不是"太好用了"，而是"这是怎么做到的"。

---

## 它不是魔法

Claude Code 的核心是一个循环：

1. 把用户的问题、可用工具的描述、对话历史一起发给语言模型
2. 模型决定调用哪个工具（读文件、运行命令、修改代码）
3. 把工具的执行结果返回给模型
4. 模型继续思考，直到它认为任务完成

这个循环本身并不复杂。复杂的是每一层的细节：流式输出怎么解析，工具调用的 JSON 怎么从流中组装，用户按 Esc 中断时如何保证历史不损坏，权限怎么管控，成本怎么追踪，终端 UI 如何在流式输出期间保持响应……

这些细节，你只有自己做一遍才会真正理解。

---

## 为什么是 Go

Go 的标准库够用，部署是单二进制，不需要 Python 环境，不需要 node_modules。对于一个命令行工具，这些特性比任何框架都重要。

而且 Go 的类型系统足够严格，能在设计阶段就逼着你把接口想清楚——比如"工具的 Execute 方法返回 error 还是把错误当 tool result？"这种问题，在 Go 里必须做决定，在动态语言里可以拖到上线之后。

---

## 为什么是 DeepSeek

写作本书时，DeepSeek V4 是性价比最高的模型选项，而且有几个对编程智能体特别有价值的能力：前缀缓存（长 system prompt 的 token 成本直接打折）、reasoner（内置的多步推理，不需要 chain-of-thought prompt engineering）、FIM 端点（填空补全，比 chat 便宜很多）。

但本书不是 DeepSeek 的使用手册。M6 会加入 Anthropic、OpenAI、Gemini 的支持，届时你会看到如何在不污染核心逻辑的前提下插入新的 Provider。

---

## 这本书的结构

全书分六部分，跟着真实的构建顺序走：

- **第一部分** 搞清楚我们要做什么，以及 LLM 工具调用的底层协议
- **第二部分** 从零实现 Agent 循环和工具系统
- **第三部分** 构建终端 UI，处理流式渲染和用户交互
- **第四部分** 加入会话持久化、Skill 系统、MCP
- **第五部分** 多 Provider 支持、性能优化、v1.0 发布
- **第六部分** v1.0 之后:跨会话记忆(v0.2.x)与 Skill 生命周期(v0.3.x)

每章以一个可运行的版本结束。每章里会有"坑"——那些在真实开发中遇到的、消耗了超过一分钟才搞清楚的问题。它们不是为了展示我犯了多少错，而是因为这些坑在你自己做的时候大概率也会遇到，提前知道原因要好过反复撞墙。

> **关于第六部分**:第 1-15 章是 v1.0 期间(2026 年 5 月)写完的, 当时书的预期就是停在 v1.0。但接下来半年 seek 走完了 v0.2.x(三层记忆)和 v0.3.x(Skill 生命周期)两个大版本——它们不是 v1.0 PRD 里写过的"未来工作", 是 seek 自举到一定规模后**作者自己用着觉得不够, 反推出来的需求**。第 16、17 章续写它们, 顺便也演示一本"声称完结"的技术书该怎么续:每个大版本一个 PRD(`docs/prd/v1.md`、`v2.md`), 每个 PRD 落地后一章, 不强行回头改前面。

---

## 一个约定

本书的代码不是为了演示而简化过的示例，而是真实运行的代码。如果某段代码看起来比"教科书写法"复杂一些，通常是因为有一个你迟早会踩的坑要绕开——我会在"坑"的标注里解释。

如果你有任何疑问，仓库的 Issues 和这本书同步维护。

---

## 关于写作过程

这本书在 2026 年 5 月用了大约两周时间完成。**写作过程本身分三段，AI 协作的比例和方式每段都不一样**——这里把它说清楚，给读者一个判断依据。

### 第一段：前言 + 第 1–7 章（手工）

提交于 `315290f`，2026-05-21。一次性把前言、第 1 章到第 7 章、目录全提上去。这部分是**作者手工写完**的——没有任何 LLM 草稿、没有补全、没有续写。

写法是先看自己 M0–M4 期间的 commit 历史、PR description、`docs/pitfalls.md`，然后按"我当时在想什么"复盘——把决定背后的取舍写成散文。代码片段从 `pkg/deepseek` / `pkg/agent` / `internal/tui` 真实摘取，不为讲故事简化。

为什么手工？因为前 7 章定**全书的语气**——节奏、callout 密度、举例风格、"为什么这么做"的论证深度。这些一旦让 LLM 起草，作者就只能"修改"，很难再设定基线。先把基线立住，后面续写才有参照系。

### 第二段：M7 polish 的代码（seek 自举）

时间是 2026-05-22 凌晨到上午。作者用 seek 干自己的活时撞到几个 papercut——`/help` 滚屏冲掉对话、`/reset` 静默丢历史、light 终端看不清状态栏——立刻打开 seek，描述需求，让 seek 写代码、写测试、写 commit message。三个 commit：`b479187` / `393d6b7` / `56b9df8`。这三个都签了 `Co-Authored-By: DeepSeek`。

**这是真正的 seek 自举**——seek 改 seek 自己的代码。第 15 章 §15.2 那段"papercut 列表"讲的就是这一段。作者审阅 diff、改 commit message、把"AI 标记"洗掉，但绝大部分逻辑由 seek 提议。

### 第三段：第 8–15 章 + 附录 A（Claude 协作）

时间是 2026-05-22 下午到晚上。作者发现一个尴尬的事实：seek 适合写代码，但**写长篇技术叙事散文不是它的强项**——DeepSeek V4 在中文叙事的语气把控、跨章节伏笔回收、风格一致性上不够稳。

于是作者切换了 LLM 协作伙伴：**Claude（Anthropic）的 Opus 4.7（1M context）**——能一次性装下前 7 章 + PRD + pitfalls.md + 完整代码摘要作为参考，续写时风格不漂移。每一章的工作流大致：

1. 作者描述章节主题、要覆盖的代码范围、希望埋伏什么伏笔
2. Claude 用 grep / read 工具实际摸代码（不是凭印象写），写完一章
3. 作者过一遍——通常重写开头收尾、调整段落顺序、删冗余、把"AI 标记"洗掉
4. commit，签 `Co-Authored-By: Claude Opus 4.7`

附录 A 的对照表是 Claude 直接生成 + 作者校对的——表格类内容比叙事更适合机器。

为什么用 Claude 而不是 seek 续写本书？三个理由：

1. **写作语气**：Claude 4.7 在中文长篇叙事上的语气把控比 DeepSeek V4 稳得多——后者倾向于把每个段落写成"先 setup 再 conclude"的模板，长读容易让人腻
2. **跨章节状态**：Claude 的 1M context + 它在 Anthropic 自家环境的 prompt caching，让"参考前 7 章 + 30 个代码文件"这件事变成同一次会话能撑住的工作量
3. **诚实分工**：seek 是 DeepSeek 优化的工具，把 DeepSeek 跟 seek 绑在一起测试是有意义的；但"用 seek 写关于 seek 的书"这个 meta-test 价值有限——更有意义的是让 seek 改 seek 的代码（第二段做的那件事）

### 不变的部分

不管哪一段，**这些都是作者的**：

- 选题：每一章讲什么、不讲什么、伏笔埋哪、回收在哪
- 立论：每条"坑"的教训是什么、每条架构决定的取舍论据
- 语气：克制、不卖弄、不夸大 AI 协作的角色
- 取舍：写到一半发现某节其实没必要 → 删掉；某段读着像 LLM → 重写
- 签字：每个 commit 都是作者本人按下回车——`Co-Authored-By` 是协作记录，**主作者署名永远是 whyiyhw**

### 这是不是"作弊"

我想了一下这个问题：让 Claude 协助写一本"关于怎么从零造一个 LLM agent 工具"的书，本身有没有矛盾？

我的答案是没有。这本书的论点不是"AI 能不能写作"，是"**LLM agent 这种东西是怎么工作的、它的每一层做对要付什么代价**"。回答这个问题需要的是：

- 对协议层的精确理解（流式 SSE、tool_call delta、缓存命中条件）
- 对架构决定的论证（为什么 `pkg/deepseek` 不 import `pkg/llm`、为什么 JSONL 不是单文件 JSON）
- 对真实 bug 的诚实记录（孤儿 tool_calls、cumulative tokens、`finish_reason="length"`）

这些**事实**是作者写出来的代码 + 真实踩过的坑——LLM 协助梳理表达，但事实本身不能由它生成。如果你读到任何一段觉得"这不像作者会撞到的坑"，那是错的，请提 issue——所有 16 条编号坑都对应 `docs/pitfalls.md` 里的真实条目，每条都有 commit hash 摆在 git log 里。

**LLM 协作降低了写作的边际成本**——一本本来需要 6 个月业余时间的书，压缩到 2 周完成。但它不能创造原本不存在的洞察。这个区分对我重要——希望对你来说也清楚。

---

*whyiyhw，2026 年 5 月*
