跳转至

PrivateGPT 文档问答

为什么要学 PrivateGPT

PrivateGPT 是一个专注于隐私的文档问答系统,所有处理100%在本地完成,不需要联网。它特别适合处理敏感文档(法律合同、医疗记录、财务报告等),因为数据永远不会离开你的机器。PrivateGPT 提供了 API 和 UI,支持多种文档格式的摄入和基于 RAG 的问答。


核心概念

概念白话解释用途
Ingestion文档摄入将文档解析、切片、嵌入
RAG Pipeline检索增强生成先搜索相关文档片段,再生成回答
Completion Mode补全模式纯 LLM 对话,不使用文档
Chunk文本块文档被切分的最小单位
Source Attribution来源归属回答时标注引用的文档和位置
Profile配置档预设的后端和参数组合

安装配置

环境准备

# 需要 Python 3.11+
python --version

# 克隆项目
git clone https://github.com/zylon-ai/private-gpt.git
cd private-gpt

# 使用 poetry 安装
pip install poetry
poetry install --extras "ui llms-ollama embeddings-ollama vector-stores-qdrant"

配置文件

# settings.yaml
server:
  env_name: local
  port: 8001

llm:
  mode: ollama
  max_new_tokens: 512
  context_window: 3900
  temperature: 0.1

ollama:
  llm_model: llama3
  embedding_model: nomic-embed-text
  api_base: http://localhost:11434

embedding:
  mode: ollama
  embed_dim: 768

vectorstore:
  database: qdrant

qdrant:
  path: ./local_data/qdrant

data:
  local_data_folder: ./local_data

ui:
  enabled: true
  path: /

快速启动

# 确保 Ollama 在运行
ollama serve &
ollama pull llama3
ollama pull nomic-embed-text

# 启动 PrivateGPT
poetry run python -m private_gpt

# 访问 UI: http://localhost:8001
# API docs: http://localhost:8001/docs

Docker 部署

version: '3.8'
services:
  private-gpt:
    build: .
    ports:
      - "8001:8001"
    volumes:
      - ./local_data:/app/local_data
      - ./settings.yaml:/app/settings.yaml
    environment:
      - PGPT_PROFILES=ollama
    depends_on:
      - ollama

  ollama:
    image: ollama/ollama
    volumes:
      - ollama-data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

volumes:
  ollama-data:

快速上手

通过 UI 使用

  1. 打开 http://localhost:8001
  2. 在左侧面板上传文档
  3. 等待 ingestion 完成(状态变为绿色)
  4. 在右侧对话框中提问
  5. 回答会附带来源文档引用

API 文档摄入

# 上传文档
curl -X POST http://localhost:8001/v1/ingest/file \
  -F "file=@report.pdf"

# 上传文本
curl -X POST http://localhost:8001/v1/ingest/text \
  -H "Content-Type: application/json" \
  -d '{
    "file_name": "notes.txt",
    "text": "这里是文档内容..."
  }'

# 查看已摄入的文档
curl http://localhost:8001/v1/ingest/list

API 问答

import requests

BASE = "http://localhost:8001/v1"

# 带上下文的问答(使用文档)
response = requests.post(f"{BASE}/chat/completions", json={
    "messages": [
        {"role": "user", "content": "这份报告的主要结论是什么?"}
    ],
    "use_context": True,
    "context_filter": {
        "docs_ids": ["doc-id-1", "doc-id-2"]  # 可选:限定搜索范围
    },
    "include_sources": True
})

data = response.json()
print(data["choices"][0]["message"]["content"])
for source in data["choices"][0]["sources"]:
    print(f"  来源: {source['document']['doc_metadata']['file_name']}")

进阶用法

批量文档摄入

import os
import requests
from pathlib import Path

INGEST_URL = "http://localhost:8001/v1/ingest/file"

docs_dir = Path("./documents")
supported = {".pdf", ".docx", ".txt", ".md", ".csv", ".html"}

for file_path in docs_dir.rglob("*"):
    if file_path.suffix.lower() in supported:
        print(f"Ingesting: {file_path.name}")
        with open(file_path, "rb") as f:
            response = requests.post(
                INGEST_URL,
                files={"file": (file_path.name, f)}
            )
        if response.status_code == 200:
            print(f"  OK: {response.json()}")
        else:
            print(f"  Error: {response.status_code}")

自定义切片策略

# settings.yaml
ingestion:
  chunk_size: 500
  chunk_overlap: 100

  # 针对不同文件类型的处理
  parsers:
    pdf:
      parser: "pymupdf"  # 或 "unstructured"
    docx:
      parser: "docx2txt"

多租户隔离

# 使用 context_filter 实现文档隔离
# 每个租户上传时打标签

# 上传时(假设有元数据支持)
response = requests.post(f"{BASE}/v1/ingest/file", 
    files={"file": open("doc.pdf", "rb")},
    data={"metadata": '{"tenant": "team-a"}'}
)

# 查询时过滤
response = requests.post(f"{BASE}/v1/chat/completions", json={
    "messages": [{"role": "user", "content": "问题"}],
    "use_context": True,
    "context_filter": {"docs_ids": team_a_doc_ids}
})

性能调优

# settings.yaml
llm:
  context_window: 3900     # 根据模型实际支持调整
  max_new_tokens: 1024     # 回答长度上限
  temperature: 0.1         # 低温度提高准确性

embedding:
  embed_dim: 768           # 匹配所选模型的维度

rag:
  similarity_top_k: 5      # 检索的片段数量
  similarity_value: 0.7    # 最低相似度阈值
  rerank:
    enabled: true
    model: "cross-encoder/ms-marco-MiniLM-L-6-v2"
    top_n: 3

常见问题

Q: 摄入大量 PDF 很慢怎么办?

  • 使用 pymupdf 替代 unstructured 解析器(更快)
  • 减少 chunk_overlap
  • 对特别大的文档先提取关键章节

Q: 回答质量不高?

  1. 增加 similarity_top_k(从 3 增加到 5-8)
  2. 启用 rerank 功能
  3. 优化文档切片大小(技术文档 500-800,一般文档 300-500)
  4. 换更好的 Embedding 模型

Q: 如何删除已摄入的文档?

# 通过 API 删除
curl -X DELETE http://localhost:8001/v1/ingest/doc-id-xxx

Q: 支持哪些文档格式?

PDF、DOCX、TXT、Markdown、CSV、HTML、EPUB、JSON 等。通过 Unstructured 解析器还支持 PPTX、XLSX 等。

Q: 与 AnythingLLM 的区别?

  • PrivateGPT:更注重隐私和 API-first 设计,适合集成到现有系统
  • AnythingLLM:UI 更丰富,多用户管理更完善,适合直接给终端用户使用

参考资源

  • GitHub:https://github.com/zylon-ai/private-gpt
  • 文档:https://docs.privategpt.dev/
  • API Reference:http://localhost:8001/docs(启动后)
  • 配置参考:https://docs.privategpt.dev/manual/settings
  • Discord:https://discord.gg/bK6mRVpErU