AI Agent = 大模型 + 工具 + 控制循环(Agent Loop)
简单来说,就是让大语言模型不仅能回答问题,还能“动手”帮你做事,例如调用代码执行工具、读取/写入文件、运行测试或执行联网搜索。本文将带你使用 Golang 手把手实现这套底层逻辑,构建一个可本地离线运行、并能连接 DeepSeek-R1 与 Ollama 的 AI 编程助手。
1. 核心项目结构(MVP)
以下是本项目的简约目录结构:
easy-agent/
├── main.go
├── agent/
│ ├── agent.go
│ ├── agency.go
│ ├── memory.go
│ ├── ollama_client.go
│ └── tools.go
└── client/
└── index.html
agent/:AI Agent 的核心逻辑层。
client/:一个基于 WebSocket 的简单前端,用于测试交互。
ollama_client.go:负责与本地模型服务通信。
agent.go:实现 Agent 主循环(处理 Function Calling)。
tools.go:定义并执行各类工具。
memory.go:实现简单的记忆与上下文管理系统。
2. 基础通信:消息格式与 Function Calling
大模型与 Agent 之间通过消息(messages)进行沟通,基本格式如下:
{ "role": "user", "content": "帮我解释下面代码" }
{ "role": "assistant", "content": "…" }
{ "role": "tool", "name": "run_code", "content": "执行结果…" }
当模型决定要执行某个工具时,会返回包含 function_call 的响应:
{
"message": {
"role": "assistant",
"function_call": {
"name": "run_code",
"arguments": "{\"language\":\"go\",\"code\":\"...\"}"
}
}
}
Agent 的核心工作流程即为:
- 解析模型的
function_call。
- 执行对应的工具(例如运行一段代码)。
- 将工具执行结果以
role: tool 的消息追加回对话历史。
- 再次调用模型,提供包含工具结果的上下文。
- 循环此过程,直到模型给出最终的自然语言回答。
这个流程就是 Agent Loop 的灵魂。
3. 实现 Ollama 客户端
文件:agent/ollama_client.go
首先,我们定义一个客户端结构体,用于管理与 Ollama 服务的连接。
type OllamaClient struct {
Endpoint string
Client *http.Client
Model string
}
func NewOllamaClient(endpoint string, timeout time.Duration, model string) *OllamaClient {
return &OllamaClient{
Endpoint: endpoint,
Client: &http.Client{Timeout: timeout},
Model: model,
}
}
接下来实现核心的调用方法,该方法发送请求并处理响应,支持传入工具定义。
func (c *OllamaClient) Call(ctx context.Context, messages []ChatMessage, tools any) (*ChatResponse, error) {
reqBody := ChatRequest{
Model: c.Model,
Messages: messages,
Tools: tools,
ToolChoice: "auto",
}
b, _ := json.Marshal(reqBody)
req, _ := http.NewRequestWithContext(ctx, "POST", c.Endpoint, bytes.NewReader(b))
req.Header.Set("Content-Type", "application/json")
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var cr ChatResponse
json.NewDecoder(resp.Body).Decode(&cr)
return &cr, nil
}
至此,我们已拥有一个可调用 DeepSeek、Qwen 或 LLaMA 等模型的 Golang 客户端。
4. 实现 Agent 主循环
文件:agent/agency.go (示意代码,详情见完整源码)
Agent Loop 是协调模型思考与工具执行的核心控制器。
func (a *Agent) Run(prompt string) (string, error) {
messages := []ChatMessage{
{Role: "system", Content: "你是 AI 编程伙伴,遇到需要执行的任务请调用工具"},
{Role: "user", Content: prompt},
}
for i := 0; i < 6; i++ { // 限制循环次数,防止无限循环
cr, _ := a.client.Call(context.Background(), messages, toolsMetadata())
msg := cr.Choices[0].Message
// 判断模型是否调用了工具
if msg.FunctionCall != nil {
messages = append(messages, ChatMessage{
Role: msg.Role, Name: msg.FunctionCall.Name,
})
result := a.execTool(msg.FunctionCall) // 执行工具
messages = append(messages, ChatMessage{
Role: "tool", Name: msg.FunctionCall.Name, Content: result,
})
continue // 继续循环,将工具结果反馈给模型
}
return msg.Content, nil // 模型返回最终答案,循环结束
}
return "", fmt.Errorf("loop limit")
}
循环步骤解析:
- 初始化消息,包含系统指令和用户问题。
- 调用模型,让其进行思考。
- 若模型返回工具调用请求,则执行对应工具,并将结果作为新消息追加。
- 再次调用模型,此时模型已获得工具执行结果,可进行下一步推理或给出答案。
- 重复步骤3-4,直至模型输出最终结论。
5. 构建可扩展的工具系统
文件:tools.go
工具系统是 Agent 能力的体现。每个工具都是一个独立的函数。
func (a *Agent) execTool(fc *FunctionCall) string {
switch fc.Name {
case "run_code":
return RunCodeSandbox(args)
case "read_file":
return ReadFile(args)
case "web_search":
return WebSearch(args)
default:
return "unknown tool"
}
}
为了让模型知道有哪些工具可用,必须向其提供工具的定义(Schema):
func toolsMetadata() any {
return []map[string]any{
{
"type": "function",
"function": map[string]any{
"name": "web_search",
"description": "联网搜索相关信息",
"parameters": map[string]any{
"type": "object",
"properties": map[string]any{
"query": {"type": "string"},
"num_results": {"type": "integer"},
},
"required": []string{"query"},
},
},
},
// ... 可以在此处添加更多工具定义
}
}
模型之所以能自动调用工具,正是因为你通过 Schema 告诉了它工具的名称、描述和参数格式。 这涉及到如何高效地管理和交互数据,是构建健壮后端系统的重要一环。
6. 为 Agent 添加联网搜索能力
例如,我们可以为 Agent 增加一个 web_search 工具,使其具备从互联网获取信息并进行分析的能力。
工具函数伪代码如下:
func WebSearch(args WebSearchArgs) ([]SearchResult, error) {
// 此处可集成 SerpAPI、DuckDuckGo 或 Bing Search API
// 实现网络请求、页面抓取与结果解析
return results, nil
}
定义后,模型在需要时便会自动生成如下调用:
{
"function_call": {
"name": "web_search",
"arguments": "{\"query\":\"Go map race condition\", \"num_results\":3}"
}
}
Agent 执行搜索后,将结果返回给模型,模型便能总结信息并输出智能结论,这正是 AI Agent 多步推理能力的体现。
7. 运行与调试:WebSocket 前端界面
项目已包含一个简单的 client/index.html 前端页面。
运行服务端:
go run main.go
然后在浏览器中打开页面,即可通过 WebSocket 与 Agent 进行实时、流式的对话交互。前端界面能直观展示 Agent 的思考过程、工具调用及最终回复,极大方便了开发和调试。

8. 总结与展望
本文完成了从零搭建一个最小可用(MVP)的本地 AI Agent,它基于 Golang,整合了 Ollama 与 DeepSeek 模型,并实现了基础的 Function Calling 与工具执行循环。这只是构建强大个人助手的起点。在 人工智能 应用蓬勃发展的今天,一个可扩展的 Agent 框架未来可以集成代码自动生成、性能分析与优化、复杂任务规划等高级能力,成为开发者真正的智能协作伙伴。
项目源码