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框架构建一个完整的智能聊天服务,主要包括:

  1. Eino框架使用:通过deepseek.NewChatModel创建大模型实例,调用Generate方法生成对话

  2. Gin框架使用:创建路由、注册中间件、绑定请求参数、返回JSON响应

  3. 日志输出:使用flag解析命令行参数,通过os.OpenFile将日志输出到文件

  4. 异常处理:使用recover捕获panic,实现recoveryMiddleware中间件防止服务器崩溃

通过本文的学习,你应该能够掌握:

  • Go语言Web服务开发
  • AI大模型调用
  • 日志与异常处理
  • API文档生成

参考资料:

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐