news 2026/7/1 17:55:55

Go Eino 框架:从小白到上线,手把手搭建自己的ai模型,基础教学

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Go Eino 框架:从小白到上线,手把手搭建自己的ai模型,基础教学

本文面向Go 初学者 + AI 零基础,从安装环境到跑通一个能查天气、能搜索的智能助手,全程复制粘贴即可运行。


前置准备(5 分钟搞定)

你需要什么

工具要求怎么检查
Go1.21 以上终端输入go version
API KeyOpenAI 或兼容的 API去 platform.openai.com 申请,或使用国内中转
网络能访问 API 地址浏览器打开试试

没有 OpenAI Key 怎么办?

国内可以用以下替代(同样支持 Tool Calling):

  • 通义千问:阿里云 DashScope API,有免费额度
  • DeepSeek:platform.deepseek.com,便宜好用
  • 智谱 GLM:open.bigmodel.cn
  • 火山引擎 Ark:字节跳动云服务

本文以 OpenAI 为例,换成其他模型只需改 BaseURL + APIKey。


第 1 步:第一个程序——让 AI 说句话(10 分钟)

1.1 创建项目

打开终端,找个目录:

mkdir my-ai-assistant cd my-ai-assistant go mod init my-ai-assistant

1.2 安装 Eino

go get github.com/cloudwego/eino@latest go get github.com/cloudwego/eino-ext/components/model/openai@latest

1.3 写代码

创建main.go,复制粘贴以下全部内容:

package main import ( "context" "fmt" "os" "github.com/cloudwego/eino-ext/components/model/openai" "github.com/cloudwego/eino/schema" ) func main() { ctx := context.Background() // 创建模型客户端 chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{ BaseURL: getEnv("OPENAI_BASE_URL", "https://api.openai.com/v1"), APIKey: getEnv("OPENAI_API_KEY", ""), Model: "gpt-3.5-turbo", // 最便宜的,够用 }) if err != nil { panic(fmt.Sprintf("创建模型失败: %v", err)) } // 发送一条消息 result, err := chatModel.Generate(ctx, []*schema.Message{ schema.UserMessage("用一句话介绍你自己"), }) if err != nil { panic(fmt.Sprintf("调用失败: %v", err)) } fmt.Println("AI 回复:", result.Content) } // 辅助函数:读环境变量,没有则用默认值 func getEnv(key, defaultVal string) string { if v := os.Getenv(key); v != "" { return v } return defaultVal }

1.4 设置 Key 并运行

Windows PowerShell:

$env:OPENAI_API_KEY="sk-你的key" $env:OPENAI_BASE_URL="https://api.openai.com/v1" go run main.go

如果一切正常,你会看到:

AI 回复: 我是 ChatGPT,一个由 OpenAI 训练的大型语言模型...

❌ 报错了?跳到文末 常见问题排查 查看解决方案。


第 2 步:给 AI 装上"手脚"——写一个工具(15 分钟)

只会聊天没什么用,现在教 AI 调用一个真实的函数。

2.1 安装工具依赖

go get github.com/cloudwego/eino-ext/components/tool/duckduckgo@latest

2.2 理解"工具"是什么

// 工具就是一个函数,有明确的输入和输出 // AI 决定"什么时候调用、传什么参数" // 你的代码负责"真正执行"

2.3 改写 main.go

用下面完整代码替换之前的main.go

package main import ( "context" "fmt" "io" "os" "github.com/cloudwego/eino-ext/components/model/openai" duckduckgo "github.com/cloudwego/eino-ext/components/tool/duckduckgo" "github.com/cloudwego/eino/compose" "github.com/cloudwego/eino/flow/agent/react" "github.com/cloudwego/eino/schema" ) func main() { ctx := context.Background() // ========== 第1步:创建模型 ========== chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{ BaseURL: getEnv("OPENAI_BASE_URL", "https://api.openai.com/v1"), APIKey: getEnv("OPENAI_API_KEY", ""), Model: "gpt-4o-mini", // 支持 Tool Call 的模型 }) if err != nil { panic(fmt.Sprintf("创建模型失败: %v", err)) } // ========== 第2步:创建工具——联网搜索 ========== searchTool, err := duckduckgo.NewTool(ctx, &duckduckgo.Config{}) if err != nil { panic(fmt.Sprintf("创建搜索工具失败: %v", err)) } // ========== 第3步:组装 ReAct Agent ========== agent, err := react.NewAgent(ctx, &react.AgentConfig{ ToolCallingModel: chatModel, ToolsConfig: compose.ToolsNodeConfig{ Tools: []compose.BaseTool{searchTool}, }, MaxStep: 12, // 工具调用 + 回复最多 12 步 // 给 AI 一个"人设" MessageModifier: func(ctx context.Context, input []*schema.Message) []*schema.Message { return append([]*schema.Message{ schema.SystemMessage("你是一个乐于助人的助手。需要实时信息时必须先搜索再回答。"), }, input...) }, }) if err != nil { panic(fmt.Sprintf("创建 Agent 失败: %v", err)) } // ========== 第4步:提问,流式输出 ========== fmt.Println("👤 用户: 今天比特币价格多少?") fmt.Print("🤖 AI: ") stream, err := agent.Stream(ctx, []*schema.Message{ schema.UserMessage("今天比特币价格多少?"), }) if err != nil { panic(fmt.Sprintf("Agent 调用失败: %v", err)) } for { msg, err := stream.Recv() if err == io.EOF { break } if err != nil { panic(fmt.Sprintf("读取流失败: %v", err)) } fmt.Print(msg.Content) } fmt.Println() } func getEnv(key, defaultVal string) string { if v := os.Getenv(key); v != "" { return v } return defaultVal }

2.4 运行

$env:OPENAI_API_KEY="sk-你的key" go run main.go

你会看到 AI 先自动调用搜索工具获取比特币价格,然后基于搜索结果回答你——它自己在思考该用什么工具


第 3 步:做一个真正的项目——天气助手(20 分钟)

搜索工具依赖第三方,现在教你自己写一个工具,完全可控。

跟前两步不同,这次我们把代码拆分到多个文件,就像真实项目一样。

3.1 项目结构

my-ai-assistant/ ├── go.mod ├── go.sum ├── main.go # 入口,组装一切 ├── tools/ │ └── weather.go # 天气查询工具 └── config/ └── config.go # 配置管理

3.2 config/config.go —— 配置管理

package config import "os" type Config struct { BaseURL string APIKey string Model string } func Load() *Config { return &Config{ BaseURL: getEnv("OPENAI_BASE_URL", "https://api.openai.com/v1"), APIKey: getEnv("OPENAI_API_KEY", ""), Model: getEnv("OPENAI_MODEL", "gpt-4o-mini"), } } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback }

3.3 tools/weather.go —— 天气工具

package tools import ( "context" "fmt" "math/rand" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" ) // 定义工具的输入结构体(AI 会按照这个格式传参) type WeatherInput struct { City string `json:"city" jsonschema:"description=城市名称,例如北京"` } // 定义工具的输出结构体 type WeatherOutput struct { City string `json:"city"` Temperature float64 `json:"temperature"` Condition string `json:"condition"` Humidity int `json:"humidity"` } // NewWeatherTool 创建一个天气查询工具 // 这里用模拟数据,实际项目中替换为真实 API 调用 func NewWeatherTool() tool.InvokableTool { return tool.NewInvokableTool( &schema.ToolInfo{ Name: "get_weather", Desc: "查询指定城市的实时天气,返回温度、天气状况和湿度", ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{ "city": { Type: "string", Desc: "城市名称,例如 北京、上海、深圳", Required: true, }, }), }, func(ctx context.Context, input *WeatherInput) (*WeatherOutput, error) { // ---------- 这里是你要实现的真实逻辑 ---------- // 实际项目:调用和风天气、OpenWeatherMap 等 API // 现在用模拟数据演示 conditions := []string{"晴 ☀️", "多云 ⛅", "小雨 🌧", "阴天 ☁"} temp := 15.0 + rand.Float64()*20 // 15~35 度随机 result := &WeatherOutput{ City: input.City, Temperature: float64(int(temp*10)) / 10, Condition: conditions[rand.Intn(len(conditions))], Humidity: 40 + rand.Intn(50), } fmt.Printf(" 🔧 [工具调用] 查询天气: %s → %.1f°C %s\n", result.City, result.Temperature, result.Condition) return result, nil }, ) }

3.4 main.go —— 组装运行

package main import ( "context" "fmt" "io" "os" "strings" "my-ai-assistant/config" "my-ai-assistant/tools" "github.com/cloudwego/eino-ext/components/model/openai" "github.com/cloudwego/eino/compose" "github.com/cloudwego/eino/flow/agent/react" "github.com/cloudwego/eino/schema" ) func main() { ctx := context.Background() cfg := config.Load() if cfg.APIKey == "" { fmt.Println("❌ 请先设置环境变量 OPENAI_API_KEY") fmt.Println(" PowerShell: $env:OPENAI_API_KEY='sk-xxx'") os.Exit(1) } // ---------- 创建模型 ---------- chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{ BaseURL: cfg.BaseURL, APIKey: cfg.APIKey, Model: cfg.Model, }) if err != nil { panic(fmt.Sprintf("创建模型失败: %v", err)) } // ---------- 注册工具 ---------- weatherTool := tools.NewWeatherTool() // ---------- 创建 Agent ---------- agent, err := react.NewAgent(ctx, &react.AgentConfig{ ToolCallingModel: chatModel, ToolsConfig: compose.ToolsNodeConfig{ Tools: []compose.BaseTool{weatherTool}, }, MaxStep: 20, MessageModifier: func(ctx context.Context, input []*schema.Message) []*schema.Message { return append([]*schema.Message{ schema.SystemMessage(strings.Join([]string{ "你是一个天气预报助手。", "规则:", "1. 用户询问天气时,必须调用 get_weather 工具查询", "2. 用友好的语气回复,可以加一些生活建议", "3. 如果用户没有指定城市,主动询问", }, "\n")), }, input...) }, }) if err != nil { panic(fmt.Sprintf("创建 Agent 失败: %v", err)) } // ---------- 交互式对话 ---------- fmt.Println("═══════════════════════════════════") fmt.Println(" 🌤 天气助手已启动!") fmt.Println(" 输入 quit 退出") fmt.Println("═══════════════════════════════════") questions := []string{ "北京今天天气怎么样?", "上海呢?", } for i, q := range questions { fmt.Printf("\n👤 用户: %s\n", q) fmt.Print("🤖 AI: ") stream, err := agent.Stream(ctx, []*schema.Message{ schema.UserMessage(q), }) if err != nil { fmt.Printf("错误: %v\n", err) continue } for { msg, err := stream.Recv() if err == io.EOF { break } if err != nil { fmt.Printf("错误: %v\n", err) break } fmt.Print(msg.Content) } fmt.Println() // 演示多轮对话后重置 Agent(第二个问题用新 Agent) if i == 0 { fmt.Println("\n--- 继续下一轮对话 ---") } } }

3.5 运行

$env:OPENAI_API_KEY="sk-你的key" go run .

你看到的输出大概是:

═══════════════════════════════════ 🌤 天气助手已启动! 输入 quit 退出 ═══════════════════════════════════ 👤 用户: 北京今天天气怎么样? 🔧 [工具调用] 查询天气: 北京 → 28.3°C 晴 ☀️ 🤖 AI: 北京今天天气晴朗,温度28.3°C,湿度65%,非常适合户外活动哦!记得防晒~ --- 继续下一轮对话 --- 👤 用户: 上海呢? 🔧 [工具调用] 查询天气: 上海 → 22.7°C 小雨 🌧 🤖 AI: 上海今天有小雨,温度22.7°C,湿度78%,出门记得带伞~

第 4 步:ReAct Agent 到底在干什么?一张图看懂

很多教程直接给代码不说原理,这里用大白话解释:

┌─────────────┐ 用户提问 → │ 你的问题 │ └──────┬──────┘ ↓ ┌─────────────┐ │ ChatModel │ ← AI 看问题,决定怎么做 │ (GPT-4等) │ └──────┬──────┘ ↓ 需要查资料吗? ↙ ↘ 需要! 不需要 ↓ ↓ ┌───────────┐ ┌──────────┐ │ 调用工具 │ │ 直接回答 │ │ get_weather│ └──────────┘ └─────┬─────┘ ↓ 把工具结果 送回 ChatModel ↓ ┌──────────┐ │ 组织回答 │ → 输出给用户 └──────────┘

核心就是:AI 自己判断"我需不需要查资料?"需要就调用工具,把工具结果再喂给自己,最后组织回答。


第 5 步:加上第二个工具——计算器(10 分钟)

一个工具不够用?再加一个。

5.1 tools/calculator.go

package tools import ( "context" "fmt" "strconv" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" ) type CalcInput struct { Expression string `json:"expression" jsonschema:"description=数学表达式,例如 2+3*4"` } type CalcOutput struct { Expression string `json:"expression"` Result string `json:"result"` } func NewCalculatorTool() tool.InvokableTool { return tool.NewInvokableTool( &schema.ToolInfo{ Name: "calculate", Desc: "执行数学计算,支持加减乘除", ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{ "expression": { Type: "string", Desc: "要计算的数学表达式", Required: true, }, }), }, func(ctx context.Context, input *CalcInput) (*CalcOutput, error) { // 简单计算器(实际项目可用 goexpr 等库) result := input.Expression // 简化演示 fmt.Printf(" 🔢 [工具调用] 计算: %s\n", input.Expression) return &CalcOutput{ Expression: input.Expression, Result: result, }, nil }, ) }

5.2 修改 main.go 中注册工具的部分

把第 3.4 节的这一行:

weatherTool := tools.NewWeatherTool()

改为:

weatherTool := tools.NewWeatherTool() calcTool := tools.NewCalculatorTool()

再把ToolsConfig改为:

ToolsConfig: compose.ToolsNodeConfig{ Tools: []compose.BaseTool{weatherTool, calcTool}, },

就这么简单,AI 现在能自己决定"该查天气还是该计算"。


常见问题排查

Q1:go get下载失败 / 超时

# 设置 Go 代理(国内用户必做) $env:GOPROXY="https://goproxy.cn,direct" go env -w GOPROXY=https://goproxy.cn,direct

Q2: 编译报错package xxx is not in GOROOT

# 确保在项目目录下执行 cd my-ai-assistant go mod tidy # 自动补全依赖

Q3: 运行时报错model does not support tool calling

你用的模型不支持 Function Calling,换成以下任意一个:

  • gpt-4o-mini/gpt-4o/gpt-3.5-turbo-0125
  • deepseek-chat(DeepSeek)
  • qwen-max/qwen-plus(通义千问)

Q4: 流式输出乱码

Windows 终端编码问题,在代码开头加:

import "golang.org/x/text/encoding/unicode" // PowerShell 默认 UTF-8 一般没问题

Q5: 如何打印调试信息看 Agent 调用了什么工具?

tools/weather.go中已经有fmt.Printf打印,Agent 调用工具时能看到。如果想更详细:

// React 配置中加了日志,但最简单的方式是在你自己的工具函数里打日志 fmt.Printf(" 🔧 被调用: %s, 参数: %+v\n", toolName, input)

总结:你学会了什么

技能文中位置
安装 Eino + 调用大模型第 1 步
使用第三方工具(联网搜索)第 2 步
自己写一个工具第 3 步
理解 Agent 运行原理第 4 步
多工具组合第 5 步
排查常见问题常见问题

从这出发,你可以

  • 接入自己公司的 API 作为工具(查订单、查库存)
  • 接入数据库(通过工具让 AI 写 SQL 查询)
  • 做成 HTTP 服务(用net/http包装,提供 API 给前端)

推荐阅读:

  • Eino 官方示例:https://github.com/cloudwego/eino-examples
  • Eino 用户手册:https://www.cloudwego.io/zh/docs/eino/
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 17:54:02

竞争存在论:存在的递归语法

存在的递归语法:竞争存在论的元模式统一理论 ——从微观到宇宙的三阶段循环 摘要: 基于竞争存在论的三连续统框架及其向下、向上递归的实例,本文揭示一个贯穿所有层级的存在递归模式。通过分析空间连续统、运动连续统、属性连续统的递归展开&…

作者头像 李华
网站建设 2026/7/1 17:53:15

不过还好,自己还是坚持下来了

关于心态 回顾做这个项目,我觉得心态问题是最重要的,技术问题倒是其次。为什么这么说呢?因为对于10余年的老功能模块来说,其中最复杂的其实是业务逻辑,而并非技术实现。所以对于老系统的重构,你首先需要将…

作者头像 李华
网站建设 2026/7/1 17:52:33

安全触边是什么?主要具有哪些防撞功能与应用?

安全触边是一种专为防撞而设计的系统,广泛应用于工业设备的边缘,如AGV小车和自动门。这种装置依靠感应压力,在遇到人或障碍物时能够立即停止设备运行,进而有效降低碰撞风险。它的核心功能在于触压即停,确保在运行过程中…

作者头像 李华
网站建设 2026/7/1 17:48:11

头疼:要求不高,不去大厂,国央企开发岗就够了

很多985、211的同学,包括不少家长,现在都有一个超级致命的误区!不少人过来咨询说:大厂太卷、太拼了,我要求不高,我不想冲互联网大厂,我只求稳一点,能进个大国央企、银行的开发岗&…

作者头像 李华
网站建设 2026/7/1 17:47:40

工业级机器学习系统:总体架构设计

在以「工业大模型 数字孪生 具身智能」为核心驱动的智能制造系统(SoI)及高端装备全生命周期服务(AI-PSS)中,机器学习系统设计(Machine Learning System Design, MLSD)已跨越了传统“离线调包、…

作者头像 李华
网站建设 2026/7/1 17:47:13

【转帖】网络安全标识管理办法

网址:https://www.cac.gov.cn/2026-04/10/c_1777558393316312.htm 自愿原则,7月1日起施行 第一批产品目录及规则:https://blog.csdn.net/humors221/article/details/162442636 网络安全标识管理办法 第一章 总则 第一条 为提升产品的网络…

作者头像 李华