开篇:一个让人抓狂的场景
想象这样一个周五下午,离下班还有2小时。
你接手了一个离职同事的Python项目——没有交接文档,没有README,只有一句"代码在Git上,你看看吧"。你打开项目,看到的是:
- 23个Python文件散落在4层文件夹里
- 一个叫
utils.py的文件有1800行,import了13个模块 - 路由定义藏在某个装饰器后面,
Ctrl+F都搜不到具体是哪个函数在处理/api/login - Git commit message 清一色是 "update" 和 "fix"
就在这时,产品经理发来消息:
"用户反馈登录接口偶尔返回500,看日志是KeyError,周一上线前必须修掉。"
你盯着屏幕,心想:"我连Bug在哪个文件都不知道,怎么修?"
你希望这时候有人能直接告诉你:
"Bug在
auth/manager.py第142行,变量名user_id写成了user_Id(大写I),改掉就行。我已经帮你跑过测试了,通过。"
这不是幻想中的救世主——这就是 Claude Code 在做的事。
但Claude Code不是魔法。它是一套可以理解、可以复现的工程方案。这个系列的目标不是教你"怎么用Claude Code",而是带你从零开始,用约300行Python代码,亲手造一个"能干活的AI助手"。
你不需要是AI专家,只需要会写Python函数,知道什么是API调用。
本节目标
读完这篇文章,你将:
- 理解Agent的本质:它不是"更聪明的聊天机器人",而是"能使用工具的推理循环"
- 建立心智模型:用一个生活化的类比,记住Claude Code的三层结构
- 明确学习路线:知道接下来7篇文章分别要解决什么问题
核心类比:带着工具箱的实习生(贯穿全系列)
在讲技术细节前,我们先建立一个直觉。
接下来8篇文章,我会一直用"带着工具箱的实习生"来比喻Agent。 每个新概念都会对应这个比喻中的一个元素:
- LLM = 实习生的大脑
- System Prompt = 实习生的岗位说明书
- Tools = 工具箱里的各种工具
- ReAct循环 = 实习生"想一步→做一步→看结果"的工作习惯
- 上下文管理 = 实习生的记事本(记不了太多,得挑重点记)
当你觉得某个概念抽象难懂时,就回想这个比喻。
把Claude Code想象成一个刚入职的实习生,他有三个特点:
- 有大脑(LLM):能理解你的指令,能思考"接下来该做什么"
- 有工具箱(Tools):里面装着螺丝刀(读文件)、扳手(写文件)、万用表(执行命令)
- 会循环工作(ReAct Loop):不是一次性干完,而是"想一步→做一步→看结果→再想下一步"
举个例子,你对他说:"帮我把main.py里的Bug修了。"
他的工作流程是这样的:
[第1轮]
🧠 思考:我得先看看main.py里写了什么
🔧 行动:打开工具箱,拿出"读文件"工具,读取main.py
👀 观察:看到了代码内容,发现第42行有个变量名拼错了
[第2轮]
🧠 思考:我需要把typo改成正确的拼写
🔧 行动:拿出"写文件"工具,修改第42行
👀 观察:文件已保存
[第3轮]
🧠 思考:我应该跑一下测试,确保没改坏
🔧 行动:拿出"执行命令"工具,运行pytest
👀 观察:测试通过了!
[完成]
💬 回复你:Bug已修复,测试通过
这就是Agent的核心工作模式:思考(Think)→ 行动(Act)→ 观察(Observe)→ 循环。
架构全景图:三层结构与反馈回路
现在我们把这个类比转化成技术架构。Claude Code的核心可以用三层来理解,关键是要看到层与层之间的反馈回路。
完整版(适合PC端阅读):
用户输入(自然语言:"帮我修Bug")
↓
┌─────────────────────────────────────────┐
│ Agent大脑层(LLM) │
│ 输入:用户指令 + 对话历史 │
│ 输出:Thought + Action(函数调用) │
│ ┌─────────────────────────────────┐ │
│ │ 1. 理解指令 │ │
│ │ 2. 规划步骤 │ │
│ │ 3. 决定用哪个工具 │ │
│ │ 4. 根据结果调整计划 │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
↓ ↑
工具调用(函数名+参数) │ 观察结果(文本)
read_file('main.py') │ "文件内容:..."
↓ │
┌─────────────────────────────────────────┐
│ 工具手脚层(Tools) │
│ 输入:函数名 + 参数 │
│ 输出:执行结果(文本) │
│ ┌──────────┐ ┌──────────┐ ┌─────────┐│
│ │read_file │ │write_file│ │run_cmd ││
│ └──────────┘ └──────────┘ └─────────┘│
└─────────────────────────────────────────┘
↓ ↑
系统调用(open/write/subprocess) │ 返回值
↓ │
┌─────────────────────────────────────────┐
│ 操作系统层(File System / Terminal) │
│ 你的代码库、终端、Git仓库... │
└─────────────────────────────────────────┘
⚠️ 注意右边的↑箭头:这是Agent能"看到结果并调整"的关键!
没有这个反馈回路,Agent就是盲人摸象。
简化版(适合手机端阅读):
用户输入(自然语言)
↓
┌──────────────────┐
│ Agent大脑(LLM) │
│ 输出:函数调用 │
└──────────────────┘
↓ ↑
↓ │ 反馈
↓ │
┌──────────────────┐
│ 工具箱 │
│ • 读文件 │
│ • 写文件 │
│ • 执行命令 │
└──────────────────┘
↓ ↑
↓ │
┌──────────────────┐
│ 你的电脑 │
└──────────────────┘
让我们逐层解释:
第1层:你的指令层
这是输入端,你用自然语言告诉Agent要做什么。可以是:
- 具体任务:"把这个函数改成异步的"
- 模糊需求:"帮我找找为什么登录失败"
- 探索性问题:"这个项目的架构是怎样的?"
第2层:Agent大脑层
这是核心,由大语言模型(LLM)驱动。它的职责是:
- 理解你的指令(自然语言处理)
- 规划完成任务需要哪些步骤
- 决策每一步该用哪个工具
- 调整根据工具返回的结果,修正计划
关键点:这一层不直接操作文件或执行命令,它只负责"思考"。就像实习生的大脑,只能想"我该拿哪个工具",但手还没动。
一个具体决策过程的推演
假设用户说:"帮我把main.py里的Bug修了。"
LLM内部发生的事(简化模拟):
1. 接收到消息:
System: 你是一个工程师Agent,能用工具...
User: 帮我把main.py里的Bug修了
2. LLM推理(在模型内部完成):
"用户让我修Bug,但我现在连main.py长什么样都不知道。
我的工具箱里有read_file,我应该先用它看看文件内容。
看完之后我才能判断Bug在哪。"
3. LLM输出(你会在代码里看到的):
Thought: 我需要先读取main.py的内容,才能找到Bug。
Action: read_file('main.py')
注意:第2步的推理是LLM在黑盒里完成的,我们只能通过第3步的格式化输出来"窥探"它的思考过程。这就是为什么System Prompt如此重要——它告诉LLM"你应该输出Thought和Action这种格式"。
第3层:工具手脚层
这是执行端,每个工具都是一个Python函数。典型的工具包括:
read_file(path)→ 读取文件内容write_file(path, content)→ 写入文件run_terminal_cmd(cmd)→ 执行Shell命令search_code(query)→ 搜索代码库
关键点:工具是"哑"的,它们不会思考,只会机械执行。就像螺丝刀不会自己决定拧哪个螺丝,必须由大脑指挥。
第4层:操作系统层
这是Agent最终作用的地方——你的文件系统、终端、Git仓库。Agent通过工具层间接操作这一层。
为什么要分层?一个对比实验
你可能会问:为什么不让LLM直接操作文件?为什么要多一个"工具层"?
让我们做个对比:
方案A:让LLM直接输出代码
你:帮我修Bug
LLM:好的,你需要把第42行改成这样:[输出一段代码]
你:[手动复制粘贴到文件里]
问题:LLM不知道改完后发生了什么,无法验证、无法调试。
方案B:让LLM调用工具
你:帮我修Bug
LLM:我先读文件 → 调用read_file('main.py')
系统:[返回文件内容]
LLM:我看到问题了,改第42行 → 调用write_file(...)
系统:[文件已保存]
LLM:我跑个测试验证 → 调用run_terminal_cmd('pytest')
系统:[测试通过]
LLM:修复完成!
优势:LLM能看到每一步的结果,形成闭环反馈。
这就是为什么Claude Code、AutoGPT、LangChain等所有Agent框架都采用"工具调用"架构。
ReAct循环的数学表达
在继续之前,让我们用一个简洁的公式来表达Agent的工作过程。这个公式贯穿整个系列,请记住它——你会发现每一篇文章都是在实现这个循环的某一块拼图。
初始状态 S_0 = (用户指令, 空对话历史)
循环 t = 0, 1, 2, ...:
Thought_t, Action_t = LLM(S_t)
如果 Action_t 为空:
跳出循环,返回最终回答
Observation_t = Execute(Action_t)
S_{t+1} = S_t + (Thought_t, Action_t, Observation_t)
返回最终回答
用人话翻译:
S_t= 当前Agent知道的所有信息(对话历史)LLM(S_t)= 大脑根据当前信息,输出思考和行动Execute(Action_t)= 执行工具,得到观察结果S_{t+1}= 把新的思考、行动、观察加入历史,形成新状态
这个循环会一直转,直到Agent认为任务完成(不再输出Action)。
我们要做什么?期望管理
在开始动手前,我们需要诚实地说明:我们要做的是一个教学版的Mini Claude Code,不是生产级的完整实现。
✅ 我们会实现的核心能力
| 能力 | 说明 | 对应篇章 |
|---|---|---|
| 基础对话 | 能调用LLM API,理解System Prompt | 第2篇 |
| ReAct循环 | 能"想→做→看→再想"地工作 | 第3篇 |
| 读写文件 | 能读取和修改代码文件 | 第4篇 |
| 执行命令 | 能运行Shell命令(只读操作) | 第5篇 |
| 完整Agent | 把上述能力组装成可用的系统 | 第6篇 |
| 代码搜索 | 能在整个项目中搜索关键词 | 第7篇 |
❌ 我们不会实现的高级特性
- 复杂的上下文管理:真实Claude Code用语义压缩+长上下文,我们只用简单的滑动窗口
- 代码语义理解:真实版用代码图谱(tree-sitter、LSIF),我们只用关键词搜索
- 自我纠错机制:真实版会重试失败的操作,我们的简化版可能一次失败就停止
- 20+种工具:我们只实现3个核心工具(读、写、执行)
为什么要简化?
因为我们的目标不是"做一个能用的产品",而是"理解Agent的工作原理"。就像学开车,你要先在空旷的停车场练习油门刹车,而不是直接上高速。
学完这个系列后,你会清楚地知道:
- Agent的每个齿轮是怎么转动的
- 为什么需要ReAct循环
- 工具调用的完整闭环是什么样的
- 真实工业级实现还需要补充哪些能力
环境准备:只需三样东西
我们的实现极简,只依赖:
- Python 3.8+(你应该已经有了)
- OpenAI Python SDK(
pip install openai) - API Key(OpenAI、Claude、或国内的兼容API)
为什么不用LangChain等框架?
你可能会问:市面上有LangChain、LangGraph、AutoGPT这些现成的Agent框架,为什么我们要从零开始写?
因为我们的目标是"看懂齿轮怎么转",而不是"快速搭建产品"。
- LangChain:帮你封装好了ReAct循环,你只需要调
agent.run(),但你就不知道里面发生了什么 - 我们的方式:用原生SDK,每一行代码都是你自己写的,没有黑盒
类比:学开车时,你要先在空旷的停车场练习油门刹车,而不是直接上高速。学完这个系列后,你再去用LangChain,会发现"哦,原来它只是帮我封装了这些步骤"。
⚠️ 关于API Key的安全提醒
- 用环境变量存储:
export OPENAI_API_KEY="sk-..." - 或者用
.env文件(记得加到.gitignore) - 千万别硬编码在代码里!
测试你的环境
运行这段代码,确保API能通:
import os
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
如果看到模型的回复,说明环境OK了。
⚠️ 新手容易踩的坑
-
误区:以为Agent就是"更聪明的ChatGPT"
- 真相:ChatGPT只能"说",Agent能"做"。区别在于工具调用能力。
-
误区:以为调用一次API就能完成任务
- 真相:复杂任务需要多轮循环。比如修Bug可能需要:读文件→分析→修改→测试→再修改,这是5轮循环。
-
误区:以为System Prompt随便写写就行
- 真相:System Prompt是Agent的"职业说明书",写得好坏直接决定Agent的表现。下一篇我们会深入讲解。
术语对照表(请务必过目)
在继续之前,我们需要对齐几个关键术语。这个系列会用统一的词汇,避免混用"智能体/Agent/代理"造成困惑。
请花30秒扫一遍,后面8篇文章都会用这套词汇。
| 中文 | 英文 | 说明 |
|---|---|---|
| 智能体/代理 | Agent | 能使用工具的AI系统 |
| 大语言模型 | LLM (Large Language Model) | 如GPT-4、Claude |
| 工具 | Tool | Agent能调用的函数 |
| 工具调用 | Tool Calling / Function Calling | LLM输出函数名和参数的能力 |
| 系统提示词 | System Prompt | 告诉LLM"你是谁、该怎么做" |
| 推理循环 | ReAct Loop | Think→Act→Observe的循环 |
| 上下文 | Context | 对话历史+当前状态 |
与真实代码的对照预告
你可能手边有一个Claude Code相关的代码文件夹(比如rust版本的实现)。在后续文章中,我会在关键节点标注**"真实代码里这里对应的是XX模块/XX函数",帮你建立教学简化版↔工业实现版**的映射。
比如:
- 我们的
LLMClient类 → 真实代码中的api/client.rs里的ProviderClient - 我们的
execute_tool函数 → 真实代码中的runtime/conversation.rs里的ToolExecutortrait - 我们的ReAct循环 → 真实代码中的
ConversationRuntime
这样你学完不仅会写Mini版,还能看懂真实的工业级代码。
下一步:从工具箱里拿出第一个工具
现在你已经理解了Agent的整体架构:大脑+工具箱+循环。但有一个关键问题我们还没解决:
怎么让LLM真正听懂"你是一个能干活的工程师,不是聊天机器人"?
答案藏在System Prompt里。它不是简单的"你是一个助手",而是一份详细的"职业说明书"。
下一篇,我们将从最基础的API调用讲起。但不要以为只是chat.completions.create那么简单。
我们会做一个小实验:
- 实验A:用System Prompt = "你是一个有用的助手"
- 实验B:用System Prompt = "你是一个Python专家,回答问题要包含代码示例,输出格式为Thought和Action"
然后问同一个问题:"怎么读取文件?"
看看两次回答的差异有多大——你会直观地理解:System Prompt不是装饰品,它是Agent的"职业基因"。
📝 自检清单(读完本篇请确认)
在进入下一篇之前,请确认你能回答以下问题:
- Agent和普通聊天机器人的本质区别是什么?
- ReAct循环的三个步骤分别是什么?
- 为什么需要"工具层"而不是让LLM直接操作文件?
- 你能默写出ReAct循环的数学公式吗?
如果都能回答,恭喜你,Agent的心智模型已经建立。 准备好了吗?下一篇见!
本系列提到的rust版本Claude Code基于开源项目github.com/soongenwong…
系列预告
- 第2篇:地基篇——让模型开口说话(System Prompt的艺术)
- 第3篇:灵魂篇——ReAct循环的骨架
- 第4篇:双手篇——赋予读写文件的能力
- 第5篇:终端篇——赋予执行命令的超能力
- 第6篇:整合篇——组装Mini Claude Code
- 第7篇:上下文篇——让Agent看懂整个文件夹
- 第8篇:反思与展望——我们得到了什么,还缺什么?