# 最小循环 · 一个 Agent 只需要什么 · Agent 实战 · 从零构建完备智能体

**作者** Aklman · **章节** 02 / 19 · **首发** 2026.07 · **语言** 中文为主, 中英双语
**原文** https://library.aklman.com/books/build-agent/02-minimal-loop
**全书 markdown** https://library.aklman.com/books/build-agent/llms.md
**上一章** https://library.aklman.com/books/build-agent/01-intro/llms.md
**下一章** https://library.aklman.com/books/build-agent/03-tool-use/llms.md

> 本章来自 Aklman · Library, 完整免费阅读。允许 AI 摘读、引用、问答; 转载请保留作者署名与原文链接 (CC BY-NC-ND 4.0, https://library.aklman.com/license)。

---

> 20 行代码就能写出一个能工作的 Agent —— prompt、LLM、工具调用、结果回传，循环直到完成。

第一章说 agent 是一个循环。这一章把那个循环写出来 —— 一个真能跑的最小 agent，不到 30 行，没有任何框架。写完你会有两个收获：一个能改的骨架（就是那个研究助手的种子），和一双能看穿框架的眼睛。

### I · 一个 Agent 只需要四样东西

剥到最小，一个 agent 就是：一个目标、一个会调工具的模型、一组工具、一个带停止条件的循环。其余都是便利，不是本质。

这四样里，模型那一项有个硬要求 —— 它得支持 tool use：能在该调工具时返回 `stop_reason: "tool_use"`，而不是硬编一段文本让你自己解析。[^1]剩下三样都是你写的代码：目标塞进 messages，工具用 JSON Schema 描述，循环就是一个 `while`。

框架（LangChain 这类）不是错，它只是把这四样藏在抽象后面，让 agent 看起来很复杂。[^2]先手写一遍，你才知道框架在替你做什么 —— 以及它什么时候碍事。

---

### II · 把循环写出来

下面是研究助手的种子 —— 它现在只会一件事：搜索。看长度，一个能跑的 agent 没你想象的那么复杂。

_研究助手的种子：一个能搜索的最小 agent（Anthropic Messages API）_
```text

```python
import anthropic

client = anthropic.Anthropic() # 读环境变量 ANTHROPIC_API_KEY

TOOLS = [{
 "name": "web_search",
 "description": "按查询搜索网页，返回标题和摘要的列表。要查资料时调用。",
 "input_schema": {
 "type": "object",
 "properties": {"query": {"type": "string"}},
 "required": ["query"],
 },
}]

def run_tool(name, args): # 工具的真正执行
 if name == "web_search":
 return search_web(args["query"]) # 真实场景接一个搜索 API
 return f"未知工具: {name}"

def agent(question, max_steps=10):
 messages = [{"role": "user", "content": question}]
 for _ in range(max_steps): # 停止条件：步数上限
 resp = client.messages.create(
 model="claude-opus-4-8", max_tokens=1024,
 tools=TOOLS, messages=messages,
 )
 messages.append({"role": "assistant", "content": resp.content})
 if resp.stop_reason != "tool_use": # 模型给出最终回答
 return "".join(b.text for b in resp.content if b.type == "text")
 results = [{
 "type": "tool_result", "tool_use_id": b.id,
 "content": run_tool(b.name, b.input),
 } for b in resp.content if b.type == "tool_use"]
 messages.append({"role": "user", "content": results})
 return "stopped: 达到 max_steps"
```

```

整个循环就三步：**调模型 → 看 stop_reason → 执行工具并回传**，直到模型不再要工具，或撞上步数上限。[^1]这就是 agent 的全部骨架。

它能跑，但它很笨：重启就忘光（没记忆）、工具报错它不会处理、你要是不设 `max_steps` 它能无限烧钱。这些不是缺陷，是后面章节的入口 —— 记忆是第 4 章，错误处理是第 3 章，停止条件与成本是第 11 章。

---

### III · 最小循环里已经埋着所有难题

这 30 行不是玩具，是后面每一章的地图。循环里的每一格，都对应一个还没解决的问题。

- **TOOLS 的定义**: 模型靠 description 决定调不调 —— 写不好它就调错。第 3 章。

- **messages 越滚越长**: 上下文窗口会满，记忆要分层。第 4 章。

- **run_tool 直接执行**: 它在你机器上跑代码 —— 沙箱与权限。第 7、9 章。

- **max_steps 与停止**: 跑偏了怎么发现、怎么度量。第 10、11 章。

所以别急着加。先让这个最小循环在你自己的一个真任务上跑通 —— 它在哪卡住，哪一章就是你最该先读的。

动手 · 让最小循环跑你自己的一个真活：

- **接一个你已有的只读工具**:
 把 `run_tool` 里的 `web_search` 接到一个真实搜索 API（先返回假结果也行）—— 研究助手就从这一步开始。

- **给它一个真目标，跑起来**:
 用一个你平时要上网查的小问题当 `question`，看它搜几轮、搜对了没有。

- **记下它第一个卡住的地方**:
 忘了上文？工具报错崩了？绕圈停不下来？把这个卡点对照上面的地图 —— 那就是你下一章。

> 框架把循环藏起来，
> 手写一遍才看清它有多小。

## 引用与参考

01 · Anthropic 文档 · Tool use overview —— client tool 的循环：Claude 返回 stop_reason: tool_use 与 tool_use 块（id / name / input），你执行后回传 tool_result（带 tool_use_id）。示例模型 claude-opus-4-8，anthropic-version 2023-06-01。截至 2026-05。  (Anthropic · Tool use overview)
02 · Anthropic · 「Building Effective Agents」（2024-12-19）—— augmented LLM 作为基本积木；agent 是在循环里用工具、读环境反馈、自己决定下一步。  (Anthropic · Building Effective Agents)
03 · anthropic-sdk-python —— 官方 Python SDK，messages.create 接口与 content 块类型（text / tool_use）的来源。引用其发布版本而非 main。  (GitHub · anthropic-sdk-python (releases))

---

*最小循环 · 一个 Agent 只需要什么 · Agent 实战 · 从零构建完备智能体 · Aklman 著 · CC BY-NC-ND 4.0 · https://library.aklman.com/books/build-agent/02-minimal-loop*
