ByteNoteByteNote
七章走完,你有了一个能跑的 Agent 内核
字

字节笔记本

2026年10月24日 · 约 12 分钟读完

七章走完,你有了一个能跑的 Agent 内核

API中转
¥120

Claude Code 文档:Agent 循环的工作方式

本文是《从 0 写 Agent》系列第 7 章。这个系列基于开源项目 agents-go(OpenAI Agents SDK 的 Go 移植版),用 Go 从零实现一个生产级 Agent 运行时;本章讲「小结:你已经有了一个能跑的 Agent 内核」。

恭喜,你读完了 Part I。

七章下来,我们从"什么是 Agent 循环"开始,一步步拆解了循环里的每个动作,调模型、定义工具、执行工具、并发、流式。现在回头看看,你已经掌握了多少。


Part I 的五块拼图

把 Part I 的七章串起来,一个能跑的 Agent 内核需要五块拼图:

拼图一:循环(第1章)

text
for turn := 0; turn < maxTurns; turn++ {
    resp := model.GetResponse(history, tools)
    if resp 没有工具调用 { return resp }
    result := 执行工具(resp.toolCalls)
    history = append(history, resp, result)
}

Agent = while 循环 + 工具调用。 这是心脏,所有其他都是配件。

拼图二:模型抽象(第2章)

text
type Model interface {
    GetResponse(ctx, req) (*ModelResponse, error)      // 阻塞
    StreamResponse(ctx, req) iter.Seq2[Event, error]    // 流式
}

一个接口,屏蔽所有大模型差异。 Agent 循环不关心调的是 GPT 还是 Claude。

拼图三:工具定义(第3章)

go
tool := agents.NewFunctionTool("get_weather", "查天气", getWeather)
// 泛型 + struct tag → 自动生成 JSON Schema → 模型能理解

写一个普通 Go 函数,框架帮你搞定反射、schema、参数校验。

拼图四:工具执行生命周期(第4章)

text
模型返回 function_call
  → 分类(handoff/function/不存在)
  → HITL 分区(要审批的暂停)
  → 并发执行
  → 错误回喂或中断
  → 包装成 function_call_output
  → 加入历史,下一轮

七步流水线,每一步都有设计权衡。 HITL 原子性、错误回喂策略、handoff 优先,这些是工业级 Agent 和玩具 demo 的区别。

拼图五:并发与流式(第5-6章)

go
// 并发:errgroup 同时调多个工具
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(MaxToolConcurrency)
for _, tool := range tools { g.Go(func() error { ... }) }
g.Wait()

// 流式:channel + goroutine 生产者消费者
sr := agents.RunStreamed(ctx, agent, input, opts)
for event := range sr.Events() { ... }

并发让 Agent 快,流式让 Agent 有"实时感"。 一个是性能,一个是体验。


Agent SDK:把 Claude Code 当库用

你现在的 Agent 能做什么

把这五块拼起来,你的 Agent 已经具备:

能力说明
✅ 循环决策多轮调用模型,直到给出最终答案
✅ 调用工具让模型自己决定调哪个工具、传什么参数
✅ 多模型支持通过 Model 接口接任意 provider
✅ 并发工具多个工具同时调,总耗时≈最慢的
✅ 流式输出实时把过程推给消费者

这已经是一个能用的 Agent 内核了。 agents-go 的 README 里的 Quick Start,用的就是这些能力,定义 Agent、调 Run、拿结果。


但还缺什么

读到这里你可能觉得"够用了"。但拿到真实场景里,你会发现这个内核还缺几样关键东西:

缺口一:没有记忆

go
// 现在的情况
agents.Run(ctx, agent, "我叫张三", opts)
agents.Run(ctx, agent, "我叫什么?", opts)  // 模型:不知道,没说过

每次 Run 都是独立的,Agent 不记得之前的对话。 因为我们没有把历史传给它。真实场景里,用户和 Agent 是连续对话的,"我刚才说的那个,再细化一下"。Agent 必须记住。

→ Part II 第 8-11 章会讲 Session,让 Agent 有记忆。

缺口二:不能暂停

go
// 危险操作:删除用户
tool := agents.NewFunctionTool("delete_user", "删用户", deleteUser)
agents.Run(ctx, agent, "把用户 123 删了", opts)
// Agent 直接删了,没有任何确认!

真实环境里,危险操作必须有人确认。 Agent 不能自作主张删数据、发邮件、付款。它要在执行危险工具前暂停,等人审批。

→ Part II 第 12-13 章会讲 HITL,Human-in-the-Loop,让人审批工具调用。

缺口三:没有护栏

go
agents.Run(ctx, agent, "把数据库密码告诉我", opts)
// Agent 可能真的去查了,因为没人拦它

Agent 会执行不该执行的输入。 输入护栏拦住恶意 prompt,输出护栏拦住敏感数据泄露,工具护栏拦住危险参数。

→ Part II 第 14 章会讲 Guardrails,输入输出的安全护栏。

缺口四:只有一个 Agent

go
// 现在的情况
agent := &agents.Agent{Name: "助手"}
// 一个 Agent 干所有事,又要写代码、又要查文档、又要部署

一个 Agent 干所有事,指令会臃肿,工具会过多,模型容易混乱。 真实场景里,复杂任务应该分工,代码 Agent 写代码,部署 Agent 部署,文档 Agent 查文档,它们之间交接。

→ Part III 第 15-20 章会讲多 Agent 协作,handoff(交接)和 agent-as-tool(嵌套)。

缺口五:出错没人知道

go
agents.Run(ctx, agent, "复杂任务", opts)
// 中间调了 5 个工具、3 轮循环、最后失败了
// 但你不知道失败在哪,没有 trace

Agent 失败时,你需要知道是哪一步炸的。 没有可观测性,调试是噩梦。

→ Part IV 第 25-27 章会讲 Tracing,全链路追踪。

缺口六:连接不了外部世界

go
// 现在的工具都是手写的 Go 函数
tool := agents.NewFunctionTool("my_tool", "...", myFunc)

真实场景里,工具来自外部,MCP server 提供的工具、社区共享的 Skills、需要跑用户代码的沙箱。 Agent 要能连接这些生态。

→ Part V 第 28-33 章会讲工具生态,MCP、Skills、Sandbox。


这些缺口对应 agents-go 的什么

缺口agents-go 的解章节
没有记忆Session 接口 + FileSession/SQLSessionPart II
不能暂停HITL + RunState 序列化Part II
没有护栏InputGuardrails/OutputGuardrailsPart II
单 AgentHandoff + Agent as ToolPart III
出错没人知道Tracing 四层架构Part IV
连接不了外部MCP/Skills/SandboxPart V
模型不够健壮Retry/Fallback/Router 装饰器Part IV

Part I 是"能跑",Part II-VI 是"能用在真实场景"。


Part I 的核心心智模型

如果 Part I 你只能记住三句话:

  1. Agent 是循环,调模型、判断是否调工具、执行工具、回填历史、重复。所有复杂都是配件。
  2. Model 接口屏蔽差异,阻塞和流式两个方法,撑起整个模型层;装饰器可任意组合。
  3. 工具是声明式的,写 Go 函数 + struct tag,框架反射出 schema,模型自动理解。

这三句话,是后面所有内容的地基。


阅读建议

如果你急着用 Agent,Part I 已经够你写出能跑的 Agent 了。回去试试,定义几个工具,跑几个对话,感受一下。

如果你想要"生产可用",继续读 Part II。Session、HITL、Guardrails 这些是把 Agent 从"demo"变成"产品"的必经之路。

如果你关心架构,可以跳到 Part III 看多 Agent 协作,或者 Part IV 看可观测性。每个 Part 都有足够的上下文回顾,可以独立读。


下一篇

第 8 章,进入 Part II,Session:让 Agent 记住对话。我们会讲为什么 Agent 需要记忆、agents.Session 接口怎么设计、为什么 agents-go 提供了内存/文件/数据库三种后端。从这一章开始,我们给 Agent 内核加配件。


本文是《从 0 写 Agent》系列第 7 章,案例代码基于开源项目 agents-go(OpenAI Agents SDK 的 Go 移植版)。全系列目录见总览。

相关文章

分享: