GO AGENT 开发指南

用 Go 构建 Agent:从 Loop 到多 Agent 协作

一个能上线的 Agent 不只是一次模型请求。它需要控制循环、验证工具参数、记录可恢复状态,并在多 Agent 场景中明确任务所有权。本文用 Modu 的真实模块边界说明这四层如何组合。

本文适合已经会写 Go、正在评估 Agent 框架或准备从单次 LLM 调用升级到可恢复工作流的开发者。 如果只想先跑起来,请直接看 Modu 快速开始

先把 Agent 拆成四层

“Agent 框架”容易被误解为一个模型 SDK。真正困难的部分是:模型决定调用工具之后,谁验证参数、谁 执行副作用、失败后从哪里继续、多个执行者如何交接。把这些职责混在一个函数里,短期代码少,长期却 很难测试和恢复。

模型接入 pkg/providers 处理协议、流式响应与 Provider 注册,不持有业务状态。
执行循环 pkg/agent 负责 ReAct 风格循环、工具执行、事件、中断与队列。
会话恢复 pkg/runtime 为已提交消息追加检查点,支持恢复与回退分支。
协作状态 pkg/mailbox 管理注册、收件箱、任务、项目、验收与会话记录。

应用仍然拥有 Prompt、工具目录、持久化策略和部署。这个边界很重要:框架提供执行机制,不应该替应用 决定业务权限或数据生命周期。

从最小 Agent Loop 开始

先只接一个模型和一个 Prompt,确认 Provider、模型 ID 与事件流都能工作。下面的结构与仓库中的 agent_demo 一致;Ollama 和 LM Studio 可以通过 OpenAI 兼容端点接入。

main.go
providers.Register(openai.New(
  "ollama",
  openai.WithBaseURL("http://localhost:11434/v1"),
))

model := &types.Model{
  ID: "llama3.2", Name: "Llama 3.2", ProviderID: "ollama",
}
a := agent.NewAgent(types.Config{
  InitialState: &types.State{
    SystemPrompt: "你是一个有帮助的助手。",
    Model: model,
  },
})

err := a.Prompt(context.Background(), "用三句话解释 Modu")

需要自己管理消息状态时,可以直接使用 agent.Loop;需要 Prompt 助手、订阅、队列与中断 状态时,使用 agent.Agent。不要在第一步就引入持久化或多 Agent。

把工具视为受控副作用

工具不是普通函数注册表。每个工具都要提供名称、说明、参数 Schema 和执行方法;循环会在执行前检查 参数。对文件写入、外部 API 或命令执行,还应通过 ApproveTool 明确审批边界。

描述让模型知道何时调用;名称要稳定,说明要包含明确适用条件。
参数用 JSON Schema 限制必填字段、类型与枚举,避免把校验留给业务代码。
执行接收 context.Context,让超时和取消能传递到外部请求。
审批高风险工具先询问宿主应用,不把授权决定交给模型。

如果工具已经修改外部系统,但结果还没写入会话就发生崩溃,恢复对话并不能撤销副作用。需要“恰好一次” 的操作必须在工具自己的 API 或数据库边界上使用幂等键或事务。

状态恢复要和业务事务分开

pkg/runtime 在每条已提交消息后写入检查点。进程重启后,Resume 会加载最新 状态并修复没有结果的中断工具调用;Rewind 则把旧检查点作为新的分支头,不删除后续历史。

runtime.go
store, err := runtime.NewFileStore("./checkpoints")
rt := runtime.New(agent.NewAgent(cfg), store, "session-123")

err = rt.Run(ctx, "完成这项任务")
resumed, err := rt.Resume(ctx)

内存 Store 适合测试;FileStore 使用每会话一个追加式 JSONL 文件并在追加后执行 fsync。对数据库或对象存储,实现同一个 Store 接口即可。

只有任务边界清晰时才增加 Agent

多 Agent 不等于让多个模型自由聊天。先定义谁分派、谁执行、谁验收以及失败后回到哪个状态。Mailbox 本身不调用 LLM,它只维护协调状态,因此可以独立测试任务流转。

Agent Teams 适合有明确角色和一个协调者的工作;协调者拆分任务并合并结果。
独立验收 适合输出必须由另一执行者接受的队列;Worker 提交,Validator 接受或要求重试。

mailbox.NewHub() 默认使用进程内状态。需要跨进程恢复任务、项目、角色与对话时,选择 SQLite Store;调用方还要处理收件箱已满、目标不存在和重试策略。

上线前检查这七件事

终止条件设置最大步骤数,并区分用户取消、模型错误与工具错误。
工具权限默认最小权限;对写操作、命令执行和外部发送设置审批。
参数校验Schema 只负责结构,业务层仍需验证资源归属和允许范围。
可观测性订阅 Agent、Turn、Message 与 Tool Execution 事件,记录耗时和失败点。
恢复语义明确哪些状态可重放,哪些外部副作用必须幂等。
上下文成本检查点保存完整消息历史;长会话要设计压缩和保留策略。
协作背压对满队列定义重试、丢弃或降级,不假设消息一定送达。

用可运行示例验证选型

不要先搭完整平台。按目标选择一个示例,用真实模型端点走通最短链路:

terminal
# 单 Agent 与工具调用
go run ./examples/agent_demo

# 检查点、恢复与回退
go run ./examples/runtime_demo

# 协调者驱动的多 Agent 工作
go run ./examples/agent_teams
Modu 完整快速开始安装、Provider、Runtime 与 Mailbox 用法 Agent Core 参考Loop、Agent 与宿主应用的职责边界 Runtime 恢复语义检查点、恢复、回退和外部副作用边界
已复制到剪贴板