
字节笔记本
2026年10月24日 · 约 11 分钟读完
实战三:写一个代码助手 Agent

本文是《从 0 写 Agent》系列第 47 章。这个系列基于开源项目 agents-go(OpenAI Agents SDK 的 Go 移植版),用 Go 从零实现一个生产级 Agent 运行时;本章讲「实战三:代码助手 Agent」。
Claude Code、Codex 都是"代码助手 Agent",读代码、改代码、跑测试、提交。这一章用 agents-go 从 0 写一个迷你版代码助手,理解这类 Agent 的设计。
需求
一个代码助手 Agent 要能:
- 读文件,理解项目代码
- 改文件,修改代码
- 跑命令,执行测试、构建
- 多轮修改,改完跑测试,失败再改,循环到通过
- 安全,不在不该改的地方乱改

工具定义
// 读文件
type readFileArgs struct {
Path string `json:"path" jsonschema:"description=文件路径(相对于项目根)"`
}
readFile := agents.NewFunctionTool("read_file", "读取文件内容", func(ctx, tc, args readFileArgs) (string, error) {
// 用 os.Root 限制在项目目录内(第 31 章)
data, err := projectRoot.ReadFile(args.Path)
return string(data), err
})
// 改文件(str_replace 风格,像 Codex)
type editFileArgs struct {
Path string `json:"path"`
OldString string `json:"old_string" jsonschema:"description=要替换的原文"`
NewString string `json:"new_string" jsonschema:"description=替换成的新文"`
}
editFile := agents.NewFunctionTool("edit_file", "精确替换文件内容", func(ctx, tc, args editFileArgs) (string, error) {
content, _ := projectRoot.ReadFile(args.Path)
newContent := strings.Replace(content, args.OldString, args.NewString, 1)
if newContent == content {
return "未找到要替换的内容", nil // 没替换成功,回喂模型
}
projectRoot.WriteFile(args.Path, []byte(newContent), 0644)
return "修改成功", nil
})
// 跑命令(测试、构建)
type runCmdArgs struct {
Command string `json:"command" jsonschema:"description=要执行的命令"`
}
runCmd := agents.NewFunctionTool("run_command", "执行 shell 命令", func(ctx, tc, args runCmdArgs) (string, error) {
// 用 Sandbox 执行(第 32 章),安全隔离
result, err := sandbox.Exec(ctx, sandbox.ExecRequest{
Cmd: strings.Fields(args.Command),
Timeout: 60 * time.Second,
})
if err != nil { return "", err }
// 代码错误(exit≠0)回喂模型,让它看报错修代码
return fmt.Sprintf("exit=%d\nstdout:\n%s\nstderr:\n%s",
result.ExitCode, result.Stdout, result.Stderr), nil
})关键设计:edit_file 用 str_replace 不是全量重写
注意 edit_file 是"精确替换"(str_replace),不是"全量重写文件"。为什么?
- 全量重写,模型要输出整个文件内容。大文件(1000 行)token 爆炸,且容易丢内容。
- str_replace,模型只输出"改了哪几行"。token 省、改动精确、容易 review。
这是 Claude Code/Codex 的设计选择,agents-go 也用(README 里的 editor.NewTools)。 第 4 章讲的工具错误回喂在这里很有用,"未找到要替换的内容"回喂,模型知道 old_string 不对,下轮调整。
关键设计:run_command 用 Sandbox
执行命令用 Sandbox(第 32 章),不直接在本机跑。因为模型生成的命令可能危险(rm -rf、curl 恶意 URL)。Sandbox 隔离,即使命令恶意,不伤宿主。
代码错误(exit≠0)回喂模型(第 32 章的错误语义反转),模型看到测试失败的 stderr,知道哪里错了,下轮修代码。
Agent 定义
codeAgent := &agents.Agent{
Name: "代码助手",
Instructions: agents.StaticInstructions(`你是代码助手。
- 修改前先 read_file 理解现有代码
- 用 edit_file 做精确修改(不要全量重写)
- 改完用 run_command 跑测试
- 测试失败就看报错,继续修
- 不要改不相关的文件`),
Model: "openai/gpt-4o",
Tools: []agents.Tool{readFile, editFile, runCmd},
}典型的修改-测试循环
用户:"修复 src/auth.go 里的空指针 bug"
Agent: read_file("src/auth.go")
→ 看到代码,发现第 42 行 user.Profile 可能为 nil
Agent: edit_file("src/auth.go",
old: "return user.Profile.Name",
new: "if user.Profile != nil { return user.Profile.Name }\nreturn \"\"")
→ "修改成功"
Agent: run_command("go test ./src/auth/...")
→ exit=1, stderr: "undefined: Profile"
Agent Thought: 哦,应该是 user.Profile 改成 userProfile 变量名
Agent: edit_file(...) // 修正
Agent: run_command("go test ./src/auth/...")
→ exit=0, "PASS"
Agent: "已修复空指针 bug,测试通过。"这就是 ReAct(第 41 章),边查(读代码)边改(edit)边验证(跑测试)。 每轮都比上轮更接近"测试通过"。
安全设计
代码助手是最危险的 Agent 之一,它能改文件、跑命令。安全措施:
- os.Root 限制目录,read_file/edit_file 只能操作项目目录内(第 31 章)
- Sandbox 执行命令,run_command 在沙箱里跑(第 32 章)
- edit_file 的 str_replace,防止"全量重写覆盖整个文件"
- 指令约束,"不要改不相关的文件"
- 可选 HITL,关键修改前审批(
editFile.NeedsApproval = true)
纵深防御,多层保护,任何一层被突破还有其他层。 这是第 33 章安全哲学的应用。
和 Claude Code/Codex 的对比
这个迷你代码助手和真正的 Claude Code/Codex 的差距:
| 能力 | 迷你版 | Claude Code |
|---|---|---|
| 基本循环 | ✅ | ✅ |
| 文件操作 | ✅ | ✅ |
| 命令执行 | ✅ | ✅ |
| 项目理解(AGENTS.md) | ❌ | ✅ |
| 多 worktree 并行 | ❌ | ✅ |
| 流式输出 | ✅(SDK 有) | ✅ |
| MCP 集成 | ✅(SDK 有) | ✅ |
| Skills | ✅(SDK 有) | ✅ |
agents-go SDK 提供了基础设施,差距主要在"工程化打磨"和"产品体验"。 但核心原理,ReAct 循环 + 工具 + 安全,完全一致。
小结
代码助手 Agent 用到的核心组件:
- 工具(read/edit/run)→ 第 3-4 章
- os.Root 安全读改 → 第 31 章
- Sandbox 安全执行 → 第 32 章
- 错误回喂(测试失败→修代码)→ 第 32 章
它最能体现 ReAct 的价值,"边查边改边验证",循环逼近"测试通过"。
下一篇
第 48 章,实战四:多 Agent 客服中心。单个客服 Agent 不够,要做一个客服中心,分诊、退款专员、物流专员、技术支持,多 Agent 协作。用到 Handoff + Agent-as-Tool。
本文是《从 0 写 Agent》系列第 47 章,案例代码基于开源项目 agents-go(OpenAI Agents SDK 的 Go 移植版)。全系列目录见总览。

