零基础极速搭建智能问答系统:Docker Compose整合ChatGLM3与BGE-zh全攻略

最近在帮几个创业团队搭建内部知识管理系统时,发现很多技术人对大模型私有化部署既向往又畏惧。向往的是能拥有自主可控的AI能力,畏惧的是复杂的安装步骤和晦涩的报错信息。其实用对工具链,整个过程可以像搭积木一样简单——下面我就用最直白的语言,分享如何用Docker Compose在本地机器上快速部署智能问答系统。

1. 环境准备与工具选型

1.1 硬件需求实测建议

我的ThinkPad P52(配备NVIDIA Quadro P3200显卡)跑这套系统时,发现几个关键指标直接影响使用体验:

组件 最低配置 推荐配置 实测数据反馈
GPU NVIDIA GTX 1060 6GB RTX 3060 12GB P3200(6GB)运行7B模型显存占用85%
内存 16GB 32GB 16GB环境下频繁触发SWAP交换
存储 50GB可用空间 NVMe SSD 100GB 镜像下载后实际占用约37GB

提示:Mac用户建议使用M1/M2芯片机型,通过docker buildx构建arm64版本镜像。曾帮一位使用M1 Max的开发者部署,性能反而优于部分x86平台。

1.2 软件依赖一键安装

避免到处找安装包,用这个组合命令搞定基础环境:

# Ubuntu/Debian系
sudo apt update && sudo apt install -y git curl python3-pip docker.io docker-compose-plugin nvidia-driver-535
sudo systemctl enable --now docker

# 验证安装
docker --version && docker-compose version
nvidia-smi  # 应显示GPU信息

遇到显卡驱动问题时,可以尝试:

# 清理旧驱动
sudo apt purge nvidia*
# 自动安装推荐版本
ubuntu-drivers devices
sudo ubuntu-drivers autoinstall

2. 容器化部署实战

2.1 镜像加速技巧

国内用户建议先配置镜像加速,否则下载可能超时:

mkdir -p ~/.docker
cat > ~/.docker/config.json <<EOF
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}
EOF

2.2 编排文件深度解析

这是我优化后的docker-compose.yml,增加了健康检查和资源限制:

version: '3.8'

services:
  chatglm:
    image: registry.cn-hangzhou.aliyuncs.com/llm-mirror/chatglm3:6b
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
    ports:
      - "8000:8000"
    volumes:
      - ./models:/app/models
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  bge-zh:
    image: registry.cn-beijing.aliyuncs.com/vector-db/bge-zh:latest
    ports:
      - "8888:8888"
    depends_on:
      chatglm:
        condition: service_healthy
    environment:
      - EMBEDDING_DIM=1024
      - MAX_SEQ_LENGTH=512

  webui:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./web:/usr/share/nginx/html

关键参数说明:

  • deploy.resources 确保GPU独占分配
  • healthcheck 实现服务依赖顺序控制
  • EMBEDDING_DIM 需要与ChatGLM3的隐藏层维度匹配

3. 高频故障排查手册

3.1 数据库连接异常

典型报错ConnectionRefusedError: [Errno 111] Connection refused通常有三种成因:

  1. 端口冲突:运行netstat -tulnp | grep 5432检查端口占用
  2. 初始化超时:在compose文件添加:
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
    
  3. 权限问题:执行chmod -R 777 ./data重置卷权限

3.2 显存不足的智能降级方案

当出现CUDA out of memory时,可以:

# 在模型加载时添加参数
model = AutoModel.from_pretrained(
    "THUDM/chatglm3-6b",
    device_map="auto",
    torch_dtype=torch.float16,
    load_in_4bit=True  # 4位量化
)

或者在启动命令中加入:

docker run --gpus all -e QUANTIZE=4bit your_image

4. 知识库优化实战技巧

4.1 文档预处理流水线

优质知识库需要结构化处理原始文档,这是我的预处理脚本:

from langchain.text_splitter import RecursiveCharacterTextSplitter

def process_document(filepath):
    with open(filepath) as f:
        text = f.read()
    
    # 智能分段
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50,
        length_function=len
    )
    return splitter.create_documents([text])

4.2 混合检索策略

单纯向量搜索可能丢失关键词,建议结合传统方法:

from rank_bm25 import BM25Okapi

class HybridRetriever:
    def __init__(self, docs):
        self.vector_db = FAISS.from_documents(docs, embeddings)
        self.bm25 = BM25Okapi([doc.page_content.split() for doc in docs])
    
    def search(self, query, top_k=5):
        # 向量相似度
        vector_results = self.vector_db.similarity_search(query, k=top_k)
        # 关键词匹配
        bm25_scores = self.bm25.get_scores(query.split())
        # 混合排序
        return sorted(zip(vector_results, bm25_scores),
                     key=lambda x: x[1]*0.3 + x[0][1]*0.7)

5. 性能调优与扩展

5.1 并发处理配置

docker-compose.yml中调整这些参数可提升吞吐量:

environment:
  - MAX_CONCURRENT=8  # 并行请求数
  - MAX_BATCH_SIZE=32 # 批处理大小
  - CACHE_DIR=/tmp/transformers
volumes:
  - ./cache:/tmp/transformers

5.2 监控方案实现

用Prometheus+Granfa搭建监控看板:

# prometheus.yml 片段
scrape_configs:
  - job_name: 'chatglm'
    static_configs:
      - targets: ['chatglm:8000']
    metrics_path: '/metrics'

添加监控指标暴露端点:

from prometheus_client import start_http_server, Counter

REQUEST_COUNT = Counter('api_requests', 'Total API requests')
@route('/api')
def handle():
    REQUEST_COUNT.inc()
    return jsonify(result)

这套系统在客户服务器上稳定运行了三个月后,我总结出几个实用建议:定期清理向量数据库的过期文档、为不同部门建立独立命名空间、日志中重点关注/health端点的响应时间波动。最近还尝试加入了Rerank模块,让搜索结果更精准——这些经验下次再展开详聊。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐