0基础Go语言Eino框架智能体实战-chatModel
0基础Go语言Eino框架智能体实战-chatModel
摘要:本文详细介绍如何使用Go语言、Eino框架和Gin框架构建一个完整的智能聊天服务。涵盖环境搭建、大模型调用、API创建、日志输出、异常处理等核心知识点,适合零基础入门人工智能应用开发,源码在此。
一、项目概述
1.1 技术栈
| 技术 | 说明 | 版本 |
|---|---|---|
| Go | 服务端开发语言 | 1.21+ |
| Eino | 字节跳动开源的AI应用框架 | 最新 |
| Gin | 高性能HTTP Web框架 | 最新 |
| DeepSeek | 大模型提供商 | - |
1.2 功能特性
- 基于DeepSeek大模型的智能对话
- RESTful API接口设计
- Swagger UI在线调试
- 日志输出到文件或标准输出
- 完整的异常捕获机制
1.3 最终效果
┌─────────────────────────────────────────────────────┐
│ 智能聊天服务 │
├─────────────────────────────────────────────────────┤
│ POST /chat 聊天接口 │
│ GET /health 健康检查 │
│ GET /swagger/*any API文档 │
└─────────────────────────────────────────────────────┘
二、环境准备
2.1 安装Go环境
首先确保已安装Go语言环境:
# 检查Go版本
go version
# 输出示例
go version go1.21.6 darwin/arm64
2.2 安装swag工具
swag用于生成Swagger API文档:
# 安装swag命令行工具
go install github.com/swaggo/swag/cmd/swag@latest
# 验证安装
~/go/bin/swag --version
# v1.16.3
2.3 创建项目结构
mkdir -p ~/projects/chat-service
cd ~/projects/chat-service
mkdir -p docs # Swagger文档目录
三、配置文件
3.1 创建config.yml
在项目根目录创建配置文件:
model:
base_url: "https://api.minimaxi.com/v1" # API基础地址
api_key: "your-api-key-here" # API密钥
model_name: "MiniMax-M2.7" # 模型名称
app:
host: "0.0.0.0" # 监听地址
port: 8080 # 监听端口
3.2 Go配置结构体定义
// Config 模型配置
type Config struct {
Model ModelConfig `yaml:"model"`
App AppConfig `yaml:"app"`
}
// ModelConfig 大模型配置
type ModelConfig struct {
BaseURL string `yaml:"base_url"`
APIKey string `yaml:"api_key"`
ModelName string `yaml:"model_name"`
}
// AppConfig 应用配置
type AppConfig struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
}
3.3 读取配置文件
import (
"fmt"
"os"
"gopkg.in/yaml.v2"
)
func loadConfig(configPath string) (*Config, error) {
// 读取配置文件内容
data, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
// 解析YAML格式的配置
var config Config
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
return &config, nil
}
关键点说明:
yaml.Unmarshal()自动将YAML字段映射到Go结构体yaml:"base_url"标签指定YAML中的字段名- Go字段名可以不同(驼峰),但标签必须匹配YAML
四、Eino框架创建大模型聊天服务
4.1 初始化聊天模型
Eino框架是字节跳动开源的AI应用框架,提供了统一的大模型调用接口:
import (
"context"
"github.com/cloudwego/eino-ext/components/model/deepseek"
"github.com/cloudwego/eino/schema"
)
var chatModel *deepseek.ChatModel // 全局聊天模型实例
func initChatModel(cfg *Config) error {
ctx := context.Background()
// 创建DeepSeek聊天模型实例
model, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
APIKey: cfg.Model.APIKey, // API密钥
Model: cfg.Model.ModelName, // 模型名称
BaseURL: cfg.Model.BaseURL, // API基础地址
})
if err != nil {
return fmt.Errorf("创建ChatModel实例失败: %w", err)
}
chatModel = model
return nil
}
4.2 聊天请求与响应结构体
// ChatRequest 聊天请求
type ChatRequest struct {
// SystemPrompt 系统提示词,用于设定AI角色和行为
SystemPrompt string `json:"system_prompt" example:"你是一个有帮助的助手" description:"系统提示词"`
// UserMessage 用户消息,即用户的输入
UserMessage string `json:"user_message" example:"你好" description:"用户消息"`
}
// ChatResponse 聊天响应
type ChatResponse struct {
// Content 模型回复内容
Content string `json:"content" example:"你好!有什么可以帮助你的吗?" description:"模型回复内容"`
// PromptTokens 输入token数量
PromptTokens int `json:"prompt_tokens" example:"100" description:"输入token数量"`
// OutputTokens 输出token数量
OutputTokens int `json:"output_tokens" example:"50" description:"输出token数量"`
// TotalTokens 总token数量
TotalTokens int `json:"total_tokens" example:"150" description:"总token数量"`
}
4.3 聊天处理函数
import (
"net/http"
"time"
)
func chatHandler(c *gin.Context) {
var req ChatRequest
// 绑定并验证JSON请求体
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求参数"})
return
}
// 构建消息列表:系统提示 + 用户消息
messages := []*schema.Message{
schema.SystemMessage(req.SystemPrompt),
schema.UserMessage(req.UserMessage),
}
// 创建带超时的context,防止模型调用耗时过长
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
// 调用聊天模型生成响应
response, err := chatModel.Generate(ctx, messages)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "生成响应失败,请稍后重试"})
return
}
// 构建响应结构
resp := ChatResponse{
Content: response.Content,
}
// 提取token使用统计信息
if response.ResponseMeta != nil && response.ResponseMeta.Usage != nil {
resp.PromptTokens = response.ResponseMeta.Usage.PromptTokens
resp.OutputTokens = response.ResponseMeta.Usage.CompletionTokens
resp.TotalTokens = response.ResponseMeta.Usage.TotalTokens
}
c.JSON(http.StatusOK, resp)
}
4.4 消息类型说明
| 函数 | 说明 | 使用场景 |
|---|---|---|
schema.SystemMessage(content) |
系统消息 | 设置AI角色和行为 |
schema.UserMessage(content) |
用户消息 | 用户输入 |
schema.AssistantMessage(content) |
助手消息 | 对话历史 |
schema.ToolMessage(content, toolCallID) |
工具消息 | 工具调用结果 |
五、Gin框架创建API服务
5.1 Gin基本使用
Gin是一个用Go语言编写的高性能HTTP Web框架:
import "github.com/gin-gonic/gin"
func main() {
// 创建Gin实例
r := gin.Default()
// 注册路由
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
// 启动服务
r.Run(":8080")
}
5.2 健康检查接口
func healthHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
5.3 注册完整路由
func main() {
// 使用ReleaseMode减少日志输出
gin.SetMode(gin.ReleaseMode)
r := gin.New()
// 注册HTTP处理函数
r.GET("/health", healthHandler) // 健康检查
r.POST("/chat", chatHandler) // 聊天接口
// 启动服务
addr := fmt.Sprintf("%s:%d", cfg.App.Host, cfg.App.Port)
log.Printf("服务启动中,监听地址: %s", addr)
r.Run(addr)
}
5.4 Swagger文档集成
第一步:添加Swagger注释
// chatHandler 处理聊天请求
//
// @Summary 聊天接口
// @Description 与DeepSeek大模型对话
// @Tags chat
// @Accept json
// @Produce json
// @Param request body ChatRequest true "聊天请求"
// @Success 200 {object} ChatResponse
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /chat [post]
func chatHandler(c *gin.Context) {
// ...
}
第二步:生成Swagger文档
swag init -g chat_quickstart.go
第三步:注册Swagger路由
import (
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "your_module/lab01/docs" // 导入自动生成的docs包
)
func main() {
r := gin.Default()
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
常用Swagger注释说明:
| 注释 | 说明 |
|---|---|
@Summary |
接口概要 |
@Description |
接口详细描述 |
@Tags |
接口分组标签 |
@Param |
请求参数 |
@Success |
成功响应 |
@Failure |
失败响应 |
@Router |
路由路径 |
六、Go语言日志输出
6.1 标准日志库使用
Go语言内置了log包,提供基本的日志功能:
import "log"
func main() {
// 设置日志输出格式
log.SetFlags(log.LstdFlags | log.Lshortfile)
// 输出日志
log.Println("这是一条普通日志")
log.Printf("用户%s的操作失败,错误码: %d", "张三", 500)
log.Fatalf("严重错误: %v", err) // 输出后程序退出
}
6.2 日志输出到文件
通过命令行参数指定日志文件:
import (
"flag"
"os"
)
func main() {
// 解析命令行参数
logFile := flag.String("log", "", "日志输出文件路径")
flag.Parse()
// 设置日志输出
if *logFile != "" {
f, err := os.OpenFile(*logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("打开日志文件失败: %v", err)
}
defer f.Close()
log.SetOutput(f)
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Printf("日志将输出到文件: %s", *logFile)
} else {
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Println("日志将输出到标准输出")
}
}
6.3 日志使用示例
# 输出到标准输出(默认)
go run chat_quickstart.go
# 输出到指定日志文件
go run chat_quickstart.go -log app.log
# 输出到指定日志文件(绝对路径)
go run chat_quickstart.go -log /var/log/chat_service.log
6.4 日志格式说明
2026/04/07 10:30:15 main.go:45: 配置加载成功
2026/04/07 10:30:15- 日期和时间main.go:45- 代码位置(文件名:行号)- 日志内容
6.5 日志Flag说明
| Flag | 说明 |
|---|---|
Ldate |
日期(2009/01/23) |
Ltime |
时间(01:23:23) |
Lshortfile |
完整路径和行号 |
Llongfile |
完整路径和行号 |
LstdFlags |
标准格式(日期+时间) |
七、Go语言异常捕获与抛出
7.1 Go异常机制概述
Go语言使用panic和recover机制处理异常,不同于传统语言的try-catch:
// panic: 触发异常,中断程序执行
panic("这是一个严重错误")
// recover: 捕获panic,防止程序崩溃
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到异常:", r)
}
}()
7.2 Panic Recovery中间件
为了防止服务器崩溃,我们需要一个中间件来捕获所有未处理的panic:
import "runtime"
func recoveryMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
// 记录panic到日志
log.Printf("[PANIC RECOVERED] 异常信息: %v\n堆栈跟踪:\n%s", r, getStackTrace())
// 返回内部错误响应
c.JSON(http.StatusInternalServerError, gin.H{
"error": "服务器内部错误,请稍后重试",
})
c.Abort()
}
}()
c.Next()
}
}
// getStackTrace 获取当前goroutine的堆栈跟踪信息
func getStackTrace() string {
var buf [4096]byte
n := runtime.Stack(buf[:], false)
return string(buf[:n])
}
7.3 异常抛出函数
提供一个辅助函数,方便在错误发生时主动抛出异常:
func panicIfErr(err error, msg string) {
if err != nil {
log.Printf("[PANIC THROW] %s: %v", msg, err)
panic(fmt.Sprintf("%s: %v", msg, err))
}
}
7.4 使用示例
示例一:在初始化阶段使用
func main() {
// 初始化聊天模型
if err := initChatModel(cfg); err != nil {
panicIfErr(err, "初始化聊天模型失败")
}
}
示例二:在业务逻辑中主动抛出
func chatHandler(c *gin.Context) {
response, err := chatModel.Generate(ctx, messages)
if err != nil {
log.Printf("[ERROR] 模型调用失败: %v", err)
panic("chat model generation failed")
}
// ...
}
7.5 中间件注册
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
// 注册panic恢复中间件
r.Use(recoveryMiddleware())
// 注册路由
r.GET("/health", healthHandler)
r.POST("/chat", chatHandler)
}
7.6 日志中的异常标记
| 标记 | 含义 |
|---|---|
[PANIC RECOVERED] |
panic被recoveryMiddleware捕获 |
[PANIC THROW] |
panic被panicIfErr函数主动抛出 |
[ERROR] |
普通错误日志 |
7.7 异常日志输出示例
[PANIC RECOVERED] 异常信息: chat model generation failed
堆栈跟踪:
goroutine 8 [running]:
main.chatHandler(0xc0000a2000)
/path/to/chat_quickstart.go:143
...
八、完整代码整合
8.1 main函数完整实现
func main() {
// -------------------- 0. 解析命令行参数 --------------------
logFile := flag.String("log", "", "日志输出文件路径")
flag.Parse()
if *logFile != "" {
f, err := os.OpenFile(*logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("打开日志文件失败: %v", err)
}
defer f.Close()
log.SetOutput(f)
log.SetFlags(log.LstdFlags | log.Lshortfile)
} else {
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
// -------------------- 1. 加载配置 --------------------
cfg, err := loadConfig("config.yml")
if err != nil {
log.Fatalf("加载配置失败: %v", err)
}
log.Printf("配置加载成功: base_url=%s, model=%s", cfg.Model.BaseURL, cfg.Model.ModelName)
// -------------------- 2. 初始化聊天模型 --------------------
if err := initChatModel(cfg); err != nil {
log.Fatalf("初始化聊天模型失败: %v", err)
}
log.Println("聊天模型初始化成功")
// -------------------- 3. 设置Gin路由 --------------------
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(recoveryMiddleware())
r.GET("/health", healthHandler)
r.POST("/chat", chatHandler)
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
// -------------------- 4. 启动服务 --------------------
addr := fmt.Sprintf("%s:%d", cfg.App.Host, cfg.App.Port)
log.Printf("服务启动中,监听地址: %s", addr)
if err := r.Run(addr); err != nil {
log.Fatalf("服务启动失败: %v", err)
}
}
8.2 项目目录结构
lab01/
├── chat_quickstart.go # 主程序
├── config.yml # 配置文件
├── go.mod # Go模块文件
├── go.sum # 依赖校验文件
└── docs/ # Swagger文档
├── docs.go
├── swagger.json
└── swagger.yaml
九、启动与测试
9.1 启动服务
# 生成Swagger文档
~/go/bin/swag init -g chat_quickstart.go
# 启动服务(输出到标准输出)
go run chat_quickstart.go
# 启动服务(输出到日志文件)
go run chat_quickstart.go -log app.log
9.2 测试接口
# 健康检查
curl http://localhost:8080/health
# 聊天接口
curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d '{"system_prompt": "你是一个有帮助的助手", "user_message": "你好"}'
9.3 访问Swagger UI
打开浏览器访问:http://localhost:8080/swagger/index.html
十、总结
本文详细介绍了如何使用Go语言、Eino框架和Gin框架构建一个完整的智能聊天服务,主要包括:
-
Eino框架使用:通过
deepseek.NewChatModel创建大模型实例,调用Generate方法生成对话 -
Gin框架使用:创建路由、注册中间件、绑定请求参数、返回JSON响应
-
日志输出:使用
flag解析命令行参数,通过os.OpenFile将日志输出到文件 -
异常处理:使用
recover捕获panic,实现recoveryMiddleware中间件防止服务器崩溃
通过本文的学习,你应该能够掌握:
- Go语言Web服务开发
- AI大模型调用
- 日志与异常处理
- API文档生成
参考资料:
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)