5 分钟跑通你的第一个 AI Agent 系列「企业级 AI Agent 实现拆解」E31 篇Part 9 起步篇第一章。前面 30 篇拆解了 Eino 和 DeepFlux 的内部机制。从这里开始换个姿态从零动手把 Agent 真的跑起来。读完这篇你会得到一个能跑的 Go Agent 项目30 行核心代码ChatModel Tool ReAct 三者怎么串在一起用 DeepSeek国内可用、最便宜作为模型入口看懂终端输出Agent 在想什么准备工作你需要Go 1.21 及以上go version验证DeepSeek API Key去 platform.deepseek.com 注册新用户有免费额度一个能联网的终端为什么选 DeepSeek它的 API 兼容 OpenAI 格式只需换一个BaseURL价格比 GPT-4o 便宜 10 倍以上特别适合调试。第一步初始化项目mkdirmy-first-agentcdmy-first-agent go mod init my-first-agent安装依赖go get github.com/cloudwego/einolatest go get github.com/cloudwego/eino-ext/components/model/openailatesteino是核心框架eino-ext里装了各个模型的驱动这里用openai包驱动 DeepSeek两者 API 格式相同。第二步写一个 ToolTool 是 Agent 能调用的工具——类似函数但 Agent 会根据任务自己决定要不要调它、怎么调。新建main.gopackagemainimport(contextfmtioosgithub.com/cloudwego/eino-ext/components/model/openaigithub.com/cloudwego/eino/components/toolgithub.com/cloudwego/eino/components/tool/utilsgithub.com/cloudwego/eino/composegithub.com/cloudwego/eino/flow/agent/reactgithub.com/cloudwego/eino/schema)// 工具的输入参数用 struct 定义字段注释变成 JSON Schema 描述typeWeatherParamsstruct{Citystringjson:city jsonschema_description:城市名如 北京、上海}// 工具的执行逻辑返回 (结果字符串, error)funcgetWeather(_context.Context,p*WeatherParams)(string,error){// 这里可以调真实天气 API演示先硬编码returnfmt.Sprintf(%s 今天晴气温 25°C适合出行。,p.City),nil}工具定义只需要三样东西输入结构体、执行函数、一个名字和描述。第三步创建 ChatModelfuncnewChatModel(ctx context.Context)*openai.ChatModel{cm,err:openai.NewChatModel(ctx,openai.ChatModelConfig{BaseURL:https://api.deepseek.com,// DeepSeek 的 OpenAI 兼容地址Model:deepseek-chat,APIKey:os.Getenv(DEEPSEEK_API_KEY),// 从环境变量读别写死在代码里})iferr!nil{panic(err)}returncm}openai.NewChatModel本来是给 GPT 用的但因为 DeepSeek 的接口格式一样换个BaseURL就能用。这就是接口兼容带来的好处。第四步把 ChatModel Tool 组成 Agentfuncmain(){ctx:context.Background()// 1. 把函数包成 ToolweatherTool,err:utils.InferTool(get_weather,// 工具名Agent 会看到这个名字查询指定城市的天气,// 工具描述Agent 用它决定什么时候调getWeather,)iferr!nil{panic(err)}// 2. 创建 ChatModelchatModel:newChatModel(ctx)// 3. 用 react.NewAgent 把两者组装成一个 ReAct Agentagent,err:react.NewAgent(ctx,react.AgentConfig{ToolCallingModel:chatModel,ToolsConfig:compose.ToolsNodeConfig{Tools:[]tool.BaseTool{weatherTool},},})iferr!nil{panic(err)}// 4. 发一条消息用 Stream 得到流式回复sr,err:agent.Stream(ctx,[]*schema.Message{{Role:schema.User,Content:北京今天天气怎么样适合去颐和园吗},})iferr!nil{panic(err)}defersr.Close()// 5. 逐 token 打印打字机效果for{msg,err:sr.Recv()iferrio.EOF{break}iferr!nil{panic(err)}fmt.Print(msg.Content)// 不换行token 一个个蹦出来}fmt.Println()}运行exportDEEPSEEK_API_KEY你的 keygo run main.go你会看到类似这样的输出北京今天晴气温 25°C适合出行。颐和园户外游览非常适合 建议上午前往避开正午高温。记得带遮阳帽和防晒霜……发生了什么这 30 行代码背后Agent 完成了一次完整的 ReAct 循环用户消息 ↓ [思考] LLM 判断需要查天气才能回答 ↓ [行动] 调用 get_weather(city北京) ↓ [观察] 工具返回北京今天晴25°C ↓ [思考] LLM 结合观察生成最终回复 ↓ 流式输出给你react.NewAgent把这个循环封装好了。你给它 ChatModel 和 Tool它处理什么时候调工具、调什么、把结果填回上下文再想一轮这些细节。utils.InferTool 做了什么你写的是一个普通 Go 函数func(context.Context, *WeatherParams) (string, error)utils.InferTool把它变成 Agent 认识的tool.InvokableTool用反射读取WeatherParams的字段和jsonschema_descriptiontag生成 JSON Schema把这个 Schema 告诉 LLM“这个工具接受{city: string}参数”当 LLM 决定调工具时把 LLM 返回的 JSON 参数反序列化成*WeatherParams调你的函数你只需要关心业务逻辑不需要手写 JSON Schema。三行改动就能换模型想换成 GPT-4oBaseURL:,// 删掉 BaseURL用默认Model:gpt-4o,APIKey:os.Getenv(OPENAI_API_KEY),想换成 Claude后面会专门讲。想本地跑 LlamaE42 会讲 Ollama 接入。模型切换不影响工具和 Agent 逻辑。完整代码清单my-first-agent/ ├── go.mod └── main.go ← 全部 70 行含注释不需要 YAML不需要配置框架不需要数据库。这就是 Eino 的最小可运行形态。小结一个可用的 AI Agent ChatModel大脑Tool手ReAct 循环神经。Eino 把 ReAct 循环封在react.NewAgent里你只需要openai.NewChatModel接上模型utils.InferTool包一个函数成工具react.NewAgent组装起来agent.Stream发消息、收回复下一篇讲 Go 项目怎么组织——从脚本式的单文件到 DDD 4 层结构什么时候该分层、什么时候过度设计。代码来源eino-examples quickstart