从零搭一套企业知识库:ChatGPT + RAG 部署实战命令整理
ChatGPT 企业知识库搭建|附完整命令
在企业数字化转型过程中,知识管理一直是一个高频但并不容易落地的问题。企业内部往往沉淀了大量文档,例如制度文件、产品手册、项目资料、会议纪要、售后案例、研发规范、销售话术、合同模板、培训材料等。这些资料分散在网盘、飞书、钉钉、企业微信、Confluence、SharePoint 或本地服务器中,员工真正需要时,往往很难快速找到准确答案。
随着大语言模型的发展,越来越多企业开始尝试基于 ChatGPT 搭建企业知识库,让员工可以像和专家对话一样查询内部资料。例如:
- “公司差旅报销标准是什么?”
- “某产品的技术参数有哪些?”
- “客户投诉某问题时,售后应该如何处理?”
- “研发接口规范在哪里?”
- “销售给医疗行业客户介绍产品时,有没有标准话术?”
不过,直接把企业文档丢给 ChatGPT 并不是一个可靠方案。企业知识库通常需要结合 RAG(Retrieval-Augmented Generation,检索增强生成) 技术,也就是先从企业文档中检索相关内容,再让大模型基于检索结果生成回答。
本文将从原理、架构、部署、命令、代码、数据导入、安全建议等方面,完整介绍如何搭建一个 ChatGPT 企业知识库系统。
一、企业知识库的核心思路
企业知识库不是简单地把文档上传给大模型,而是由以下几个关键步骤组成:
-
文档收集
收集企业内部的 PDF、Word、Excel、Markdown、TXT、网页、知识库页面等资料。 -
文档解析
将不同格式的文档转换成纯文本内容。 -
文本切分
将长文档切成多个较小片段,方便后续检索。 -
向量化 Embedding
使用 Embedding 模型将文本片段转换成向量。 -
存入向量数据库
将文本内容、元数据、向量一起存入数据库,例如 Qdrant、Milvus、Weaviate、FAISS 等。 -
用户提问
用户输入问题后,也将问题转换成向量。 -
相似度检索
在向量数据库中搜索与问题最相关的文档片段。 -
大模型生成答案
将检索到的内容和用户问题一起发给 ChatGPT,让模型基于企业资料回答。
这种方式的优势是:
- 不需要对大模型进行复杂微调;
- 可以持续更新企业资料;
- 回答更贴合企业内部知识;
- 可以追溯答案来源;
- 成本相对可控;
- 支持权限控制和私有化部署。
二、推荐技术架构
本文采用一个轻量但完整的技术架构,适合中小企业、技术团队或内部试点项目使用。
1. 技术组件
| 模块 | 推荐方案 |
|---|---|
| 大语言模型 | OpenAI GPT-4o / GPT-4.1 / GPT-4o-mini |
| Embedding 模型 | text-embedding-3-small 或 text-embedding-3-large |
| 后端框架 | Python + FastAPI |
| 向量数据库 | Qdrant |
| 文档解析 | LangChain Community / Unstructured / PyPDF |
| 前端界面 | 可先用 API 测试,后续接企业微信、飞书或 Web |
| 部署方式 | Docker / Docker Compose |
2. 系统架构图
用户提问
│
▼
企业知识库 API(FastAPI)
│
├── 调用 Embedding 模型,将问题向量化
│
▼
向量数据库 Qdrant
│
├── 检索相关企业文档片段
│
▼
ChatGPT / OpenAI API
│
├── 基于检索结果生成回答
▼
返回答案 + 引用来源
三、环境准备
下面以 Ubuntu 22.04 服务器为例。如果你使用 macOS、CentOS 或 Windows,也可以参考类似方式部署。
1. 更新系统
sudo apt update && sudo apt upgrade -y
2. 安装基础工具
sudo apt install -y curl wget git vim unzip htop net-tools build-essential
3. 安装 Docker
curl -fsSL https://get.docker.com | bash
启动 Docker:
sudo systemctl enable docker
sudo systemctl start docker
查看 Docker 版本:
docker --version
4. 安装 Docker Compose
如果你的 Docker 已经自带 Compose 插件,可以直接查看:
docker compose version
如果没有,可以安装:
sudo apt install -y docker-compose-plugin
再次检查:
docker compose version
5. 创建项目目录
mkdir -p ~/chatgpt-enterprise-kb
cd ~/chatgpt-enterprise-kb
四、创建项目结构
执行以下命令创建目录:
mkdir -p app data docs scripts
touch app/main.py app/ingest.py app/config.py app/requirements.txt
touch docker-compose.yml Dockerfile .env
最终目录结构如下:
chatgpt-enterprise-kb/
├── app/
│ ├── main.py
│ ├── ingest.py
│ ├── config.py
│ └── requirements.txt
├── data/
├── docs/
├── scripts/
├── Dockerfile
├── docker-compose.yml
└── .env
其中:
docs/:存放企业知识库文档;data/:存放临时数据;app/main.py:API 服务;app/ingest.py:文档导入脚本;app/config.py:配置文件;.env:环境变量;docker-compose.yml:编排 Qdrant 和 API 服务。
五、配置环境变量
编辑 .env 文件:
vim .env
写入以下内容:
OPENAI_API_KEY=你的OpenAI_API_Key
OPENAI_CHAT_MODEL=gpt-4o-mini
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
QDRANT_HOST=qdrant
QDRANT_PORT=6333
QDRANT_COLLECTION=enterprise_kb
CHUNK_SIZE=800
CHUNK_OVERLAP=120
TOP_K=5
说明:
OPENAI_API_KEY:你的 OpenAI API Key;OPENAI_CHAT_MODEL:用于回答问题的大模型;OPENAI_EMBEDDING_MODEL:用于文本向量化的模型;CHUNK_SIZE:文本切片大小;CHUNK_OVERLAP:片段之间的重叠字符数;TOP_K:每次检索返回的文档片段数量。
注意:企业环境中不要把
.env提交到 Git 仓库,避免 API Key 泄露。
六、编写 Python 依赖文件
编辑依赖文件:
vim app/requirements.txt
写入:
fastapi==0.115.6
uvicorn==0.34.0
python-dotenv==1.0.1
openai==1.59.6
qdrant-client==1.12.1
langchain==0.3.14
langchain-community==0.3.14
pypdf==5.1.0
python-multipart==0.0.20
tiktoken==0.8.0
这些依赖分别用于:
- FastAPI:提供 HTTP API;
- OpenAI:调用 ChatGPT 和 Embedding;
- Qdrant:连接向量数据库;
- LangChain:文档加载和文本切分;
- PyPDF:解析 PDF;
- python-dotenv:读取环境变量。
七、编写配置文件
编辑 app/config.py:
vim app/config.py
写入:
import os
from dotenv import load_dotenv
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_CHAT_MODEL = os.getenv("OPENAI_CHAT_MODEL", "gpt-4o-mini")
OPENAI_EMBEDDING_MODEL = os.getenv("OPENAI_EMBEDDING_MODEL", "text-embedding-3-small")
QDRANT_HOST = os.getenv("QDRANT_HOST", "localhost")
QDRANT_PORT = int(os.getenv("QDRANT_PORT", "6333"))
QDRANT_COLLECTION = os.getenv("QDRANT_COLLECTION", "enterprise_kb")
CHUNK_SIZE = int(os.getenv("CHUNK_SIZE", "800"))
CHUNK_OVERLAP = int(os.getenv("CHUNK_OVERLAP", "120"))
TOP_K = int(os.getenv("TOP_K", "5"))
八、编写文档导入脚本
文档导入脚本负责读取 docs/ 目录下的企业资料,将内容切片、向量化并写入 Qdrant。
编辑文件:
vim app/ingest.py
写入以下代码:
import os
import uuid
from pathlib import Path
from openai import OpenAI
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
from langchain_community.document_loaders import (
TextLoader,
PyPDFLoader,
UnstructuredWordDocumentLoader,
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from config import (
OPENAI_API_KEY,
OPENAI_EMBEDDING_MODEL,
QDRANT_HOST,
QDRANT_PORT,
QDRANT_COLLECTION,
CHUNK_SIZE,
CHUNK_OVERLAP,
)
client = OpenAI(api_key=OPENAI_API_KEY)
qdrant = QdrantClient(
host=QDRANT_HOST,
port=QDRANT_PORT,
)
def get_embedding(text: str):
response = client.embeddings.create(
model=OPENAI_EMBEDDING_MODEL,
input=text
)
return response.data[0].embedding
def load_document(file_path: str):
suffix = Path(file_path).suffix.lower()
if suffix == ".pdf":
loader = PyPDFLoader(file_path)
elif suffix in [".txt", ".md"]:
loader = TextLoader(file_path, encoding="utf-8")
elif suffix in [".doc", ".docx"]:
loader = UnstructuredWordDocumentLoader(file_path)
else:
print(f"跳过不支持的文件类型: {file_path}")
return []
return loader.load()
def ensure_collection(vector_size: int):
collections = qdrant.get_collections().collections
collection_names = [c.name for c in collections]
if QDRANT_COLLECTION not in collection_names:
qdrant.create_collection(
collection_name=QDRANT_COLLECTION,
vectors_config=VectorParams(
size=vector_size,
distance=Distance.COSINE
)
)
print(f"已创建集合: {QDRANT_COLLECTION}")
else:
print(f"集合已存在: {QDRANT_COLLECTION}")
def ingest_docs(docs_dir: str = "docs"):
all_docs = []
for root, _, files in os.walk(docs_dir):
for file in files:
file_path = os.path.join(root, file)
docs = load_document(file_path)
all_docs.extend(docs)
if not all_docs:
print("没有找到可导入的文档。")
return
splitter = RecursiveCharacterTextSplitter(
chunk_size=CHUNK_SIZE,
chunk_overlap=CHUNK_OVERLAP,
separators=["\n\n", "\n", "。", "!", "?", ".", " ", ""]
)
chunks = splitter.split_documents(all_docs)
print(f"原始文档数量: {len(all_docs)}")
print(f"切分后片段数量: {len(chunks)}")
first_embedding = get_embedding(chunks[0].page_content)
ensure_collection(vector_size=len(first_embedding))
points = []
for idx, chunk in enumerate(chunks):
text = chunk.page_content.strip()
if not text:
continue
embedding = get_embedding(text)
point = PointStruct(
id=str(uuid.uuid4()),
vector=embedding,
payload={
"text": text,
"source": chunk.metadata.get("source", ""),
"chunk_index": idx,
}
)
points.append(point)
if len(points) >= 50:
qdrant.upsert(
collection_name=QDRANT_COLLECTION,
points=points
)
print(f"已写入 {len(points)} 条")
points = []
if points:
qdrant.upsert(
collection_name=QDRANT_COLLECTION,
points=points
)
print(f"已写入剩余 {len(points)} 条")
print("知识库导入完成。")
if __name__ == "__main__":
ingest_docs()
九、编写问答 API 服务
编辑 app/main.py:
vim app/main.py
写入:
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
from openai import OpenAI
from qdrant_client import QdrantClient
from config import (
OPENAI_API_KEY,
OPENAI_CHAT_MODEL,
OPENAI_EMBEDDING_MODEL,
QDRANT_HOST,
QDRANT_PORT,
QDRANT_COLLECTION,
TOP_K,
)
app = FastAPI(title="ChatGPT Enterprise Knowledge Base")
client = OpenAI(api_key=OPENAI_API_KEY)
qdrant = QdrantClient(
host=QDRANT_HOST,
port=QDRANT_PORT,
)
class AskRequest(BaseModel):
question: str
class AskResponse(BaseModel):
answer: str
sources: List[str]
def get_embedding(text: str):
response = client.embeddings.create(
model=OPENAI_EMBEDDING_MODEL,
input=text
)
return response.data[0].embedding
def search_knowledge_base(question: str):
query_vector = get_embedding(question)
results = qdrant.search(
collection_name=QDRANT_COLLECTION,
query_vector=query_vector,
limit=TOP_K,
with_payload=True,
)
contexts = []
sources = []
for item in results:
payload = item.payload or {}
text = payload.get("text", "")
source = payload.get("source", "")
if text:
contexts.append(text)
if source:
sources.append(source)
return contexts, list(set(sources))
def generate_answer(question: str, contexts: List[str]):
context_text = "\n\n---\n\n".join(contexts)
system_prompt = """
你是企业内部知识库助手。
你必须严格基于提供的企业知识库内容回答问题。
如果知识库内容中没有相关信息,请明确说明“根据当前知识库资料,暂未找到相关信息”,不要编造。
回答要准确、清晰、结构化。
如涉及制度、流程、参数、规范,应尽量引用原文要点。
"""
user_prompt = f"""
以下是从企业知识库中检索到的相关内容:
{context_text}
用户问题:
{question}
请基于上述知识库内容回答。
"""
response = client.chat.completions.create(
model=OPENAI_CHAT_MODEL,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
temperature=0.2,
)
return response.choices[0].message.content
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/ask", response_model=AskResponse)
def ask(req: AskRequest):
contexts, sources = search_knowledge_base(req.question)
answer = generate_answer(req.question, contexts)
return AskResponse(
answer=answer,
sources=sources
)
这个接口提供了两个功能:
GET /health:健康检查;POST /ask:知识库问答。
十、编写 Dockerfile
编辑 Dockerfile:
vim Dockerfile
写入:
FROM python:3.11-slim
WORKDIR /app
COPY app/requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
COPY app /app
COPY docs /app/docs
COPY .env /app/.env
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
十一、编写 Docker Compose
编辑 docker-compose.yml:
vim docker-compose.yml
写入:
services:
qdrant:
image: qdrant/qdrant:v1.12.4
container_name: enterprise-qdrant
ports:
- "6333:6333"
- "6334:6334"
volumes:
- ./data/qdrant:/qdrant/storage
restart: unless-stopped
api:
build: .
container_name: enterprise-kb-api
ports:
- "8000:8000"
env_file:
- .env
volumes:
- ./docs:/app/docs
- ./app:/app
depends_on:
- qdrant
restart: unless-stopped
十二、启动服务
在项目根目录执行:
docker compose up -d --build
查看容器状态:
docker compose ps
查看日志:
docker compose logs -f
如果只想查看 API 日志:
docker compose logs -f api
如果只想查看 Qdrant 日志:
docker compose logs -f qdrant
测试 API 是否正常:
curl http://localhost:8000/health
正常返回:
{"status":"ok"}
十三、导入企业文档
将企业文档放入 docs/ 目录,例如:
cp /path/to/公司差旅制度.pdf ./docs/
cp /path/to/产品手册.md ./docs/
cp /path/to/售后服务流程.txt ./docs/
如果你想快速创建一个测试文档,可以执行:
cat > docs/company_policy.md << 'EOF'
# 公司差旅报销制度
员工因公出差需要提前提交出差申请,并经直属主管审批。
## 住宿标准
一线城市住宿标准不超过每晚 600 元。
二线城市住宿标准不超过每晚 450 元。
其他城市住宿标准不超过每晚 350 元。
## 餐饮补贴
员工出差期间,每人每天餐饮补贴为 100 元。
## 交通标准
高铁出行优先选择二等座。
飞机出行需要提前审批,经济舱可报销。
EOF
然后执行文档导入命令:
docker compose exec api python ingest.py
导入成功后,会看到类似输出:
原始文档数量: 1
切分后片段数量: 1
已创建集合: enterprise_kb
已写入剩余 1 条
知识库导入完成。
十四、测试知识库问答
执行以下命令:
curl -X POST http://localhost:8000/ask \
-H "Content-Type: application/json" \
-d '{"question":"一线城市出差住宿标准是多少?"}'
你可能会得到类似结果:
{
"answer": "根据企业知识库资料,一线城市住宿标准不超过每晚 600 元。",
"sources": [
"docs/company_policy.md"
]
}
继续测试:
curl -X POST http://localhost:8000/ask \
-H "Content-Type: application/json" \
-d '{"question":"员工出差餐饮补贴是多少?"}'
可能返回:
{
"answer": "根据企业知识库资料,员工出差期间,每人每天餐饮补贴为 100 元。",
"sources": [
"docs/company_policy.md"
]
}
如果提问超出知识库范围,例如:
curl -X POST http://localhost:8000/ask \
-H "Content-Type: application/json" \
-d '{"question":"公司今年的营收目标是多少?"}'
理想情况下系统会返回:
{
"answer": "根据当前知识库资料,暂未找到相关信息。",
"sources": []
}
这正是企业知识库系统需要具备的能力:知道就回答,不知道就拒绝编造。
十五、常用运维命令汇总
1. 启动服务
docker compose up -d
2. 停止服务
docker compose down
3. 重启服务
docker compose restart
4. 重新构建并启动
docker compose up -d --build
5. 查看容器
docker compose ps
6. 查看日志
docker compose logs -f
7. 进入 API 容器
docker compose exec api bash
8. 重新导入文档
docker compose exec api python ingest.py
9. 清空 Qdrant 数据
如果需要彻底重建知识库,可以先停止服务:
docker compose down
删除 Qdrant 数据目录:
rm -rf ./data/qdrant
重新启动:
docker compose up -d --build
再次导入:
docker compose exec api python ingest.py
10. 查看 Qdrant 集合
curl http://localhost:6333/collections
11. 查看指定集合信息
curl http://localhost:6333/collections/enterprise_kb
十六、如何提升回答质量
搭建完成后,企业知识库的效果并不只取决于大模型,还取决于文档质量、切片策略、检索策略和提示词设计。
1. 优化文档结构
建议将企业资料整理成清晰结构:
一级标题:制度名称
二级标题:适用范围
二级标题:具体标准
二级标题:审批流程
二级标题:注意事项
文档越规范,模型越容易理解。
2. 避免文档内容过旧
知识库系统一定要有更新机制。过期制度、旧版产品文档、历史流程说明会严重影响回答准确性。
建议:
- 给文档增加版本号;
- 给文档增加生效日期;
- 定期清理旧资料;
- 对关键制度设置专人维护。
3. 调整切片大小
如果切片太小,信息不完整;如果切片太大,检索不精准。
常见配置:
CHUNK_SIZE=800
CHUNK_OVERLAP=120
如果文档是制度类、流程类,可以适当增大:
CHUNK_SIZE=1200
CHUNK_OVERLAP=200
如果文档是 FAQ,可以适当减小:
CHUNK_SIZE=500
CHUNK_OVERLAP=80
修改后需要重新导入文档:
docker compose restart api
docker compose exec api python ingest.py
4. 增加引用来源
企业用户通常关心答案是否可信,因此建议每次回答都返回文档来源、章节、页码等信息。
当前示例已经返回 sources 字段。如果需要更细粒度,可以在文档解析时保留页码、标题、部门、版本号等元数据。
5. 使用更强模型
如果问题复杂、涉及多步推理,可以使用更强的大模型。
例如在 .env 中修改:
OPENAI_CHAT_MODEL=gpt-4o
然后重启服务:
docker compose restart api
如果主要追求低成本,可以使用:
OPENAI_CHAT_MODEL=gpt-4o-mini
十七、企业级安全建议
企业知识库涉及内部资料,安全设计非常重要。
1. API Key 安全
不要把 API Key 写死在代码里,也不要提交到 Git。
建议将 .env 加入 .gitignore:
cat > .gitignore << 'EOF'
.env
data/
__pycache__/
*.pyc
EOF
2. 增加访问鉴权
当前示例为了演示方便,没有增加鉴权。生产环境必须增加 Token、OAuth、企业微信登录或单点登录。
可以在 API 前加 Nginx,或者在 FastAPI 中增加 Header Token 校验。
3. 权限分级
不同部门的知识库资料不应全部开放给所有人。
例如:
- HR 制度:全员可见;
- 财务报表:管理层可见;
- 研发文档:研发团队可见;
- 销售合同:销售和法务可见。
实现方式可以是在 Qdrant payload 中加入:
{
"department": "finance",
"permission": ["finance", "management"]
}
检索时根据用户身份过滤。
4. 日志脱敏
用户提问可能包含客户信息、合同金额、手机号、邮箱等敏感内容。日志中应避免完整记录敏感数据。
5. 私有化与合规
如果企业资料不能发送到外部模型服务,可以考虑:
- 本地部署大语言模型;
- 本地部署 Embedding 模型;
- 使用私有云模型服务;
- 使用支持数据隔离和企业合规协议的云服务。
常见本地模型方案包括:
- Qwen;
- Llama;
- DeepSeek;
- Yi;
- Baichuan。
十八、可扩展方向
完成基础版后,还可以继续扩展以下能力。
1. 接入飞书机器人
员工可以直接在飞书群或私聊中提问,后端调用 /ask 接口返回答案。
2. 接入企业微信
通过企业微信应用,让内部员工直接查询制度、流程和产品资料。
3. 增加 Web 管理后台
后台功能可以包括:
- 上传文档;
- 删除文档;
- 查看导入状态;
- 重新构建索引;
- 管理用户权限;
- 查看问答日志;
- 统计高频问题。
4. 增加混合检索
单纯向量检索有时不适合精确关键词,例如合同编号、产品型号、错误码。
可以结合:
- 向量检索;
- BM25 关键词检索;
- Rerank 重排序。
这样可以明显提升检索准确率。
5. 增加人工反馈
用户可以对回答进行评价:
- 有帮助;
- 没帮助;
- 答错了;
- 资料过期。
这些反馈可以帮助知识库持续优化。
十九、常见问题排查
1. Qdrant 连接失败
检查容器是否运行:
docker compose ps
查看日志:
docker compose logs -f qdrant
确认 .env 中配置:
QDRANT_HOST=qdrant
QDRANT_PORT=6333
在 Docker Compose 网络中,API 容器访问 Qdrant 应使用服务名 qdrant,不是 localhost。
2. OpenAI API 调用失败
检查 API Key:
cat .env
确认环境变量是否加载:
docker compose exec api env | grep OPENAI
查看 API 日志:
docker compose logs -f api
3. 文档没有导入
检查 docs/ 目录:
ls -lh docs
确认文件类型是否支持。当前示例支持:
- PDF;
- TXT;
- Markdown;
- Word。
4. 回答不准确
可以从以下方向排查:
- 文档内容是否完整;
- 文档是否过期;
- 切片是否过大或过小;
- 检索返回数量是否太少;
- 提示词是否约束模型不要编造;
- 是否需要增加 Rerank。
可以尝试将 TOP_K 调大:
TOP_K=8
然后重启:
docker compose restart api
二十、总结
本文介绍了如何基于 ChatGPT、FastAPI 和 Qdrant 搭建一个企业知识库系统,并提供了完整命令和核心代码。
整体流程可以概括为:
企业文档 → 文本解析 → 文本切片 → 向量化 → 存入 Qdrant
用户问题 → 向量化 → 检索相关片段 → ChatGPT 生成答案 → 返回来源
这种基于 RAG 的企业知识库方案,不需要对大模型进行复杂训练,适合快速落地内部问答、制度查询、产品资料查询、客服知识库、售前支持、研发文档助手等场景。
如果是内部试点,可以先使用本文的轻量方案快速跑通;如果进入生产环境,则需要重点补充权限控制、日志审计、数据脱敏、文档版本管理、访问鉴权和监控告警。
对于企业而言,知识库的关键不只是“接入 ChatGPT”,而是建立一套持续更新、可信可控、可追溯、可运营的知识管理体系。只有当企业文档规范化、知识流程产品化、员工使用场景清晰化,AI 知识库才能真正发挥价值。