Go项目实战:使用Ollama本地部署大模型实现AI智能笔记生成
前言
在当今AI技术快速发展的背景下,越来越多的应用开始集成大语言模型(LLM)能力。然而,依赖云端API不仅成本高昂,还存在数据隐私和网络延迟等问题。本文将分享一个实际项目经验------如何在Go后端项目中集成Ollama,实现本地大模型部署,用于课程音视频的智能笔记生成。
项目背景
本项目是一个"通用音视频智能学习辅助平台",核心功能是:
- 教师上传课程视频
- 系统自动提取音频
- 学生点击"解析"后,AI自动生成结构化笔记
技术栈:
- 后端:Go + Gin + GORM
- 存储:MySQL + MinIO
- AI:Ollama(本地大模型)+ Whisper(语音识别)
为什么选择本地部署?
1. 成本控制
云端API(如OpenAI)按token计费,对于教育场景的大量视频解析,成本会迅速累积。本地部署后,只需要承担硬件成本。
2. 离线可用
不依赖网络连接,在内网环境也能正常使用。
3. 可定制性
可以根据需求选择不同规模的模型,平衡性能和资源消耗。
Ollama简介
Ollama是一个轻量级的本地大模型运行工具,支持:
- 一键安装和运行主流开源模型(Llama、Qwen、Mistral等)
- 兼容OpenAI API格式
- 自动管理模型下载和版本
- 支持GPU/CPU推理
实现方案
1. 架构设计
┌─────────────────────────────────────────────────────────┐
│ Go Backend (Gin) │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ AI Service │───▶│ LLM Client │───▶│ Ollama │ │
│ └──────────────┘ └──────────────┘ │ localhost │ │
│ │ │ :11434 │ │
│ │ └────────────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │Prompt Manager│ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
2. 核心代码实现
LLM客户端封装
go
package ai
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)
type LLMClient struct {
client *http.Client
model string
provider string // "ollama" 或 "openai"
baseURL string
}
func NewLLMClient(apiKey, baseURL, model string) *LLMClient {
provider := "openai"
// 自动检测是否为Ollama
if strings.Contains(baseURL, "localhost:11434") ||
strings.Contains(baseURL, "127.0.0.1:11434") {
provider = "ollama"
}
return &LLMClient{
client: &http.Client{Timeout: 5 * time.Minute},
model: model,
provider: provider,
baseURL: baseURL,
}
}
Ollama调用实现
go
func (c *LLMClient) generateWithOllama(
ctx context.Context,
systemRole, prompt string,
mutateOptions func(map[string]any),
) (string, error) {
base := c.baseURL
if base == "" {
base = "http://localhost:11434"
}
url := strings.TrimRight(base, "/") + "/api/chat"
// 构建请求体
body := map[string]any{
"model": c.model,
"messages": []map[string]string{
{"role": "system", "content": systemRole},
{"role": "user", "content": prompt},
},
"stream": false,
}
// 支持动态调整参数
options := map[string]any{}
if v := os.Getenv("OLLAMA_NUM_CTX"); v != "" {
options["num_ctx"], _ = strconv.Atoi(v)
}
if mutateOptions != nil {
mutateOptions(options)
}
if len(options) > 0 {
body["options"] = options
}
// 发送请求
b, _ := json.Marshal(body)
req, _ := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(b))
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var result struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
}
json.NewDecoder(resp.Body).Decode(&result)
return result.Message.Content, nil
}
智能降级策略
本地部署的一大挑战是资源限制。我们实现了多级降级策略:
go
func (c *LLMClient) GenerateContent(ctx context.Context, systemRole, prompt string) (string, error) {
if c.provider == "ollama" {
// 第一次尝试:完整配置
content, err := c.generateWithOllama(ctx, systemRole, prompt, nil)
if !isOllamaRunnerCrash(err) {
return content, err
}
// 第二次尝试:缩小上下文窗口
time.Sleep(2 * time.Second)
content, err = c.generateWithOllama(ctx, systemRole, prompt, func(opts map[string]any) {
opts["num_ctx"] = 2048
opts["num_predict"] = 512
})
if !isOllamaRunnerCrash(err) {
return content, err
}
// 第三次尝试:禁用GPU,使用CPU推理
time.Sleep(3 * time.Second)
return c.generateWithOllama(ctx, systemRole, prompt, func(opts map[string]any) {
opts["num_ctx"] = 1024
opts["num_predict"] = 256
opts["num_gpu"] = 0 // 禁用GPU层
})
}
// ... OpenAI API调用
}
3. 环境变量配置
bash
# AI配置
AI_LLM_PROVIDER=ollama
AI_LLM_BASE_URL=http://localhost:11434
AI_MODEL=qwen2.5:7b
# Ollama参数调优
OLLAMA_NUM_CTX=4096 # 上下文窗口大小
OLLAMA_NUM_PREDICT=2048 # 最大生成token数
OLLAMA_TEMPERATURE=0.7 # 温度参数
OLLAMA_NUM_GPU=1 # GPU层数(0禁用GPU)
4. Prompt管理
针对不同学科,我们设计了差异化的Prompt模板:
go
type PromptManager struct {
defaults map[string]string
}
func NewPromptManager() *PromptManager {
return &PromptManager{
defaults: map[string]string{
"system": `你是一个专业的课程学习助手。请根据以下音频转录内容,
生成结构化的学习笔记。要求:
1. 提取核心知识点
2. 标注重点和难点
3. 使用Markdown格式
4. 包含章节标题`,
},
}
}
部署步骤
1. 安装Ollama
bash
# Windows/Mac/Linux
curl -fsSL https://ollama.ai/install.sh | sh
# 或下载安装包:https://ollama.ai/download
2. 下载模型
bash
# 推荐模型(根据显存选择)
ollama pull qwen2.5:7b # 7B参数,需要约8GB显存
ollama pull qwen2.5:14b # 14B参数,需要约16GB显存
ollama pull llama3.1:8b # 8B参数,需要约10GB显存
# 查看已下载模型
ollama list
3. 启动服务
bash
# Ollama默认会自动启动,也可以手动启动
ollama serve
# 测试API
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5:7b",
"messages": [{"role": "user", "content": "你好"}]
}'
4. 启动Go服务
bash
# 设置环境变量
export AI_LLM_PROVIDER=ollama
export AI_LLM_BASE_URL=http://localhost:11434
export AI_MODEL=qwen2.5:7b
# 启动服务
go run cmd/server/main.go
性能优化建议
1. 模型选择
- 7B模型:适合一般性任务,生成速度快
- 14B模型:适合复杂推理,但需要更多资源
- 量化版本:使用GGUF量化格式,减少内存占用
2. 参数调优
bash
# 高质量但慢
OLLAMA_NUM_CTX=8192
OLLAMA_NUM_PREDICT=4096
# 快速但质量一般
OLLAMA_NUM_CTX=2048
OLLAMA_NUM_PREDICT=512
3. 硬件配置
- 最低配置:8GB RAM + 4核CPU
- 推荐配置:16GB RAM + 8核CPU + 8GB显存GPU
- 高性能配置:32GB RAM + 16核CPU + 24GB显存GPU
4. 并发控制
go
// 使用信号量限制并发数
var sem = make(chan struct{}, 3) // 最多3个并发请求
func (s *AIService) GenerateNote(ctx context.Context, mediaID uint) error {
sem <- struct{}{} // 获取令牌
defer func() { <-sem }() // 释放令牌
// ... 生成逻辑
}
常见问题与解决方案
1. Ollama Runner崩溃
现象 :model runner has unexpectedly stopped
解决方案:
bash
# 减小上下文窗口
export OLLAMA_NUM_CTX=2048
# 禁用GPU(如果有CUDA错误)
export OLLAMA_NUM_GPU=0
# 增加系统交换空间
2. 生成速度慢
优化方案:
- 使用更小的模型(7B → 3B)
- 启用GPU加速
- 减小
num_ctx和num_predict参数
3. 内存不足
解决方案:
- 使用量化模型:
ollama pull qwen2.5:7b-q4_0 - 增加系统内存或交换空间
- 减少并发请求数
4. API调用失败
检查项:
bash
# 确认Ollama服务运行
curl http://localhost:11434/api/tags
# 查看日志
journalctl -u ollama # Linux
# 或查看Ollama日志文件
总结
通过Ollama在本地部署大模型,我实现了:
- 成本可控:一次性硬件投入,长期零API费用
- 数据安全:敏感教学内容不出内网
- 灵活扩展:可根据需求选择不同规模模型
- 稳定可靠:不依赖外部API,避免限流和故障