🦞 一只用 AI Agent 搭副业产线的程序员


模块一结束了。10 篇文章,从「AI 能帮程序员做什么」到「AI 的边界在哪」。

但你可能有个问题:每次写代码都要重新搭环境——注册 API Key、配置环境变量、装各种依赖。能不能一次性搭好?

这篇给你答案:一个 Docker Compose 文件,把 AI 开发需要的所有基础设施拉起来。


你需要什么

一个完整的 AI 开发环境包含这些组件:

组件作用你会用到的场景
DeepSeek 代理统一 API 入口,避免硬编码 Key所有调用
Ollama本地模型运行环境高频调用 / 隐私敏感
Open WebUI本地版 ChatGPT 界面Prompt 调试
Qdrant(向量数据库)存储和搜索 Embedding 向量模块三 RAG
Redis缓存 API 响应,省 TokenAgent 开发

一键部署

# docker-compose.yml
version: "3.8"

services:
  # 1. 本地模型引擎
  ollama:
    image: ollama/ollama:latest
    container_name: ai-ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    environment:
      - OLLAMA_KEEP_ALIVE=24h
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    restart: unless-stopped

  # 2. 本地 ChatGPT 界面(调试 Prompt 巨方便)
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: ai-webui
    ports:
      - "13000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - WEBUI_SECRET_KEY=change-me-to-random-string
    volumes:
      - webui_data:/app/backend/data
    depends_on:
      - ollama
    restart: unless-stopped

  # 3. 向量数据库(模块三用)
  qdrant:
    image: qdrant/qdrant:latest
    container_name: ai-qdrant
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage
    restart: unless-stopped

  # 4. Redis(Token 缓存、Agent 状态)
  redis:
    image: redis:7-alpine
    container_name: ai-redis
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    restart: unless-stopped

volumes:
  ollama_data:
  webui_data:
  qdrant_data:
  redis_data:
# 启动全家桶(首次启动会拉取镜像,耐心等几分钟)
docker compose up -d

# 拉一个本地模型(可选,不需要本地模型可以跳过)
docker exec -it ai-ollama ollama pull qwen2.5-coder:7b

# 确认各组件状态
docker compose ps

启动完成后:

服务地址用途
Ollama APIhttp://localhost:11434本地模型 API
Open WebUIhttp://localhost:13000聊天调试界面
Qdranthttp://localhost:6333向量数据库
Redislocalhost:6379缓存

配置你的 Go 项目模板

有了基础设施,还需要一个趁手的 Go 项目模板。我整理了一个:

ai-project/
├── main.go
├── go.mod
├── .env.example
├── internal/
│   ├── llm/
│   │   └── client.go        # LLM 调用客户端
│   ├── embed/
│   │   └── embeddings.go     # Embedding 工具
│   ├── cache/
│   │   └── redis.go          # Redis 缓存层
│   └── config/
│       └── config.go         # 配置管理
└── scripts/
    └── setup.sh              # 初始化脚本

核心配置:

// internal/config/config.go
package config

import "os"

type Config struct {
    // API 配置
    DeepSeekAPIKey  string
    DeepSeekBaseURL string

    // 本地服务
    OllamaURL  string
    QdrantURL  string
    RedisAddr  string

    // 默认参数
    DefaultModel    string
    DefaultTemp     float64
    DefaultMaxToken int
}

func Load() *Config {
    return &Config{
        DeepSeekAPIKey:  getEnv("DEEPSEEK_API_KEY", ""),
        DeepSeekBaseURL: getEnv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/anthropic"),
        OllamaURL:       getEnv("OLLAMA_URL", "http://localhost:11434"),
        QdrantURL:       getEnv("QDRANT_URL", "http://localhost:6334"),
        RedisAddr:       getEnv("REDIS_ADDR", "localhost:6379"),
        DefaultModel:    getEnv("DEFAULT_MODEL", "deepseek-v4-flash"),
        DefaultTemp:     getEnvFloat("DEFAULT_TEMP", 0.1),
        DefaultMaxToken: getEnvInt("DEFAULT_MAX_TOKENS", 500),
    }
}

func getEnv(key, defaultVal string) string {
    if v := os.Getenv(key); v != "" {
        return v
    }
    return defaultVal
}

LLM 客户端(支持多后端切换):

// internal/llm/client.go
package llm

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type Client struct {
    BaseURL   string
    APIKey    string
    Model     string
    HTTP      *http.Client
}

type Message struct {
    Role    string `json:"role"`
    Content string `json:"content"`
}

func NewClient(baseURL, apiKey, model string) *Client {
    return &Client{
        BaseURL: baseURL,
        APIKey:  apiKey,
        Model:   model,
        HTTP:    &http.Client{},
    }
}

func (c *Client) Chat(messages []Message, temp float64, maxTokens int) (string, error) {
    body := map[string]interface{}{
        "model":       c.Model,
        "max_tokens":  maxTokens,
        "temperature": temp,
        "messages":    messages,
    }
    jsonBody, _ := json.Marshal(body)
    req, _ := http.NewRequest("POST", c.BaseURL+"/v1/messages", bytes.NewReader(jsonBody))
    req.Header.Set("x-api-key", c.APIKey)
    req.Header.Set("anthropic-version", "2023-06-01")
    req.Header.Set("Content-Type", "application/json")

    resp, err := c.HTTP.Do(req)
    if err != nil {
        return "", fmt.Errorf("请求失败: %w", err)
    }
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)

    if content, ok := result["content"].([]interface{}); ok && len(content) > 0 {
        if text, ok := content[0].(map[string]interface{})["text"].(string); ok {
            return text, nil
        }
    }
    return "", fmt.Errorf("无法解析响应")
}

// 快速切换后端
func NewDeepSeekClient(apiKey string) *Client {
    return NewClient("https://api.deepseek.com/anthropic", apiKey, "deepseek-v4-flash")
}

func NewOllamaClient(model string) *Client {
    return NewClient("http://localhost:11434/api", "", model)
}

验证环境:跑一个集成测试

package main

import (
    "fmt"
    "os"

    "ai-project/internal/config"
    "ai-project/internal/llm"
)

func main() {
    cfg := config.Load()
    client := llm.NewDeepSeekClient(cfg.DeepSeekAPIKey)

    messages := []llm.Message{
        {Role: "user", Content: "请验证环境是否正常,回复 'AI 开发环境已就绪'。"},
    }

    result, err := client.Chat(messages, 0.1, 100)
    if err != nil {
        fmt.Printf("环境验证失败: %v\n", err)
        os.Exit(1)
    }

    fmt.Println(result)
    fmt.Println("\n✅ 所有组件正常运行!")
}
go run main.go
# AI 开发环境已就绪。
# ✅ 所有组件正常运行!

模块一知识地图

核心知识你的武器
15 个真实可用场景样板代码生成、注释、审查、日志分析、自动化
2LLM 工作原理50 行 Go 对话程序
3Token/温度/上下文三参数对照实验
4主流模型横评4 任务 × 5 模型的完整数据
5第一个 LLM 程序5 分钟从零到运行
6API 价格真相100 次调用的真实账单
7本地 vs 云端Ollama 部署 + 混合策略
8Embedding50 行语义相似度计算
9AI 的边界6 个翻车案例 + 防御策略
10开发环境Docker Compose 全家桶 + Go 模板

接下来 —— 模块二:Prompt Engineering 实战

你已经知道 AI 怎么调了。接下来 10 篇文章,我们要把 Prompt 当代码写:

  • 不再把 Prompt 写在 .txt 里复制粘贴
  • 用 JSON 配置驱动 Prompt
  • 变量替换、条件分支、模板继承
  • 自动化测试——同一个 Prompt 跑 100 次,统计通过率
  • 安全防御——Prompt 注入攻防

下一篇:Prompt 的本质不是「聊天」,是「编程」。用同一个任务的好 Prompt vs 烂 Prompt,让你直观看到差距。

关注我,别错过。


🦞 一只用 AI Agent 搭副业产线的程序员

全平台同名:虾哥不加班
需要定制 AI 工具?来聊聊 → lob_ai

源码 & 模板:GitHub - lobster-bujiaban/ai-starter

更多推荐