Golang 编写简单的 AI Agent Demo
status
Published
type
Post
slug
simple-ai-agent-demo-in-golang
date
Jun 25, 2025
tags
AI
Go
Note
summary
文章介绍了一个使用 Go 语言实现的简单 AI Agent 示例,阐述了 AI Agent 的基本结构,即“循环 + AI(LLM) + 工具(Tools)”。文章详细说明了如何通过 Go 语言连接 OpenAI 的大型语言模型(LLM),以及如何定义和整合可供 AI 调用的工具函数(Function Calling),最终形成一个完整的 AI Agent 工作闭环。
AI Agent 并不复杂,粗略来说就是
循环 + AI(LLM) + 工具(Tools)
。这里整理记录下之前用 Golang 写的 AI Agent Demo,可以当作一个最简的 AI Agent 示例,快速学习理解 AI Agent 的基本结构。
创建 Go 项目
mkdir example-agent cd example-agent go mod init example-agent touch main.go
循环输入输出
// main.go package main import ( "bufio" "fmt" "os" "strings" ) func main() { // 创建一个读取器,用来读取用户的输入 reader := bufio.NewReader(os.Stdin) for { fmt.Print("You: ") // 读取用户输入,直到遇到换行符 input, _ := reader.ReadString('\n') // 如果用户输入 "exit" 或 "quit",就退出循环 if strings.TrimSpace(input) == "exit" || strings.TrimSpace(input) == "quit" { fmt.Println("再见!") break } fmt.Println("Agent: 你说的是:", input) } }
连接 AI (LLM)
这里使用 OpenAI 的 SDK 来连接 AI(LLM) 。
注意: 需要一个 OpenAI API Key。或者使用第三方的 API 代理服务,修改 API 的 BaseURL 。
# 这个 star 多,就不用 OpenAI 官方 SDK 了 go get github.com/sashabaranov/go-openai
// main.go package main import ( "bufio" "context" "fmt" "log" "os" "strings" "github.com/sashabaranov/go-openai" ) func main() { // --- 初始化 AI 客户端 --- // 实际使用时,请务必使用安全的方式管理你的 API Key config := openai.DefaultConfig(os.Getenv("API_KEY")) // 使用第三方 API 代理,需设置 BaseURL config.BaseURL = "http://localhost:8080/v1" client := openai.NewClientWithConfig(config) // 创建一个列表来存储整个对话的上下文(历史消息) messages := []openai.ChatCompletionMessage{} reader := bufio.NewReader(os.Stdin) for { fmt.Print("You: ") input, _ := reader.ReadString('\n') if strings.TrimSpace(input) == "exit" || strings.TrimSpace(input) == "quit" { fmt.Println("再见!") break } // 将用户的消息添加到对话历史中 messages = append(messages, openai.ChatCompletionMessage{ Role: openai.ChatMessageRoleUser, Content: input, }) // --- 调用 LLM API --- resp, err := client.CreateChatCompletion( context.Background(), openai.ChatCompletionRequest{ Model: openai.GPT4Turbo, Messages: messages, }, ) if err != nil { log.Printf("ChatCompletion error: %v\n", err) continue } aiResponse := resp.Choices[0].Message // 将 AI 的回复也添加到对话历史中 messages = append(messages, aiResponse) } }
Agent 工具(Tools)
如下这些函数就是 AI Agent 可调用的工具(Tools),也就是 Function Calling 。
// ... 其他代码 ... /* readFile 读取指定文件的内容 */ func readFile(filename string) (string, error) { data, err := os.ReadFile(filename) if err != nil { return "", err } return string(data), nil } /* listFiles 列出指定目录中的所有文件和子目录 */ func listFiles(path string) (string, error) { files, err := os.ReadDir(path) if err != nil { return "", err } var fileNames []string for _, file := range files { fileNames = append(fileNames, file.Name()) } return fmt.Sprintf("%v", fileNames), nil } /* editFile 编辑文件内容,通过字符串替换的方式 */ func editFile(filename, old, new string) error { data, err := os.ReadFile(filename) if err != nil { return err } newData := strings.Replace(string(data), old, new, -1) return os.WriteFile(filename, []byte(newData), 0644) } // ... main 函数 ...
整合调用
有了以上工具函数后,接下来在
client.CreateChatCompletion
的请求中,将这些可用工具信息发给 AI。// 在 for 循环中 resp, err := client.CreateChatCompletion( context.Background(), openai.ChatCompletionRequest{ Model: openai.GPT4Turbo, Messages: messages, // 定义可用工具(Function Calling)告诉 AI 它可以调用哪些函数 Tools: []openai.Tool{ { Type: openai.ToolTypeFunction, Function: &openai.FunctionDefinition{ Name: "read_file", Description: "Reads the content of a file.", // JSON Schema 定义参数格式 Parameters: json.RawMessage(`{ "type": "object", "properties": { "filename": { "type": "string", "description": "The path to the file to read" } }, "required": ["filename"] }`), }, }, { Type: openai.ToolTypeFunction, Function: &openai.FunctionDefinition{ Name: "list_files", Description: "Lists files in a directory.", Parameters: json.RawMessage(`{ "type": "object", "properties": { "path": { "type": "string", "description": "The directory path to list files from" } }, "required": ["path"] }`), }, }, { Type: openai.ToolTypeFunction, Function: &openai.FunctionDefinition{ Name: "edit_file", Description: "Edits a file by replacing a string.", Parameters: json.RawMessage(`{ "type": "object", "properties": { "filename": { "type": "string", "description": "The path to the file to edit" }, "old": { "type": "string", "description": "The string to be replaced" }, "new": { "type": "string", "description": "The new string to replace with" } }, "required": ["filename", "old", "new"] }`), }, }, }, }, )
这样 AI 就知道了有
read_file
、list_files
、edit_file
这些工具了,当 AI 处理用户输入后决定使用这些工具时,其回复中会包含一个 ToolCalls
字段,根据 ToolCalls
中的信息来执行相应的工具函数,再将结果一起发送给 AI ,由 AI 根据工具执行结果生成最终响应。// ... 其他代码 ... func main() { // ... for { // ... messages = append(messages, openai.ChatCompletionMessage{ Role: openai.ChatMessageRoleUser, Content: input, }) resp, err := client.CreateChatCompletion( // ... (请求信息,包含 list_files 等工具) ... ) // ... (错误处理) ... message := resp.Choices[0].Message messages = append(messages, message) // --- 检查 AI 是否要调用工具 --- if message.ToolCalls != nil { fmt.Println("Agent: 正在调用工具...") for _, toolCall := range message.ToolCalls { var result string // 存储工具执行结果 var err error // 根据工具名称执行相应的函数 switch toolCall.Function.Name { case "read_file": var args struct { Filename string `json:"filename"` } json.Unmarshal([]byte(toolCall.Function.Arguments), &args) result, err = readFile(args.Filename) case "list_files": var args struct { Path string `json:"path"` } json.Unmarshal([]byte(toolCall.Function.Arguments), &args) result, err = listFiles(args.Path) case "edit_file": var args struct { Filename string `json:"filename"` Old string `json:"old"` New string `json:"new"` } json.Unmarshal([]byte(toolCall.Function.Arguments), &args) err = editFile(args.Filename, args.Old, args.New) if err == nil { result = "File edited successfully." } } if err != nil { result = err.Error() } // 将工具执行结果添加到历史消息 messages = append(messages, openai.ChatCompletionMessage{ Role: openai.ChatMessageRoleTool, Content: result, Name: toolCall.Function.Name, ToolCallID: toolCall.ID, }) } // 发送给 AI ,根据工具执行结果生成最终回复 resp, err = client.CreateChatCompletion( context.Background(), openai.ChatCompletionRequest{ Model: openai.GPT4Turbo, Messages: messages, }, ) if err != nil { log.Printf("Tool Result ChatCompletion error: %v\n", err) continue } // 显示 AI 的最终回复 fmt.Println("Agent:", resp.Choices[0].Message.Content) // 将最终回复也添加到历史消息 messages = append(messages, resp.Choices[0].Message) } else { // 如果 AI 没有调用工具,直接显示回复 fmt.Println("Agent:", message.Content) } } }
以上整合后就形成了一个简单完整的 AI Agent 闭环:
用户提问 -> AI 响应 -> 工具调用 -> 执行函数 -> 将结果再发给 AI -> AI 生成最终回复