37e RAG 知识库搭建
上一篇: 37d Agent 管理与 Skill 体系 | 下一篇: 37f 产品研发工作流 Agent
本篇搭建团队 RAG(Retrieval-Augmented Generation)知识库:从飞书知识库和文档中提取内容,经过分块和 Embedding 存入向量数据库,通过 RAG 检索 Skill 实现智能问答。目标是将团队的隐性知识(技术方案、历史决策、排错经验)转化为可检索的知识资产。
1. 知识源梳理
1.1 HackQuest 团队知识分布
| 知识源 | 内容类型 | 数据量估算 | 更新频率 |
|---|---|---|---|
| 飞书知识库 | 技术方案、架构文档、API 文档 | ~200 篇 | 每周 2-3 篇 |
| 飞书文档 | 会议纪要、评审记录、复盘报告 | ~500 篇 | 每天 1-2 篇 |
| GitHub README/Wiki | 项目说明、部署文档、开发规范 | ~50 篇 | 每月更新 |
| 飞书群聊精华 | 问题解答、排错经验 | ~1000 条 | 持续积累 |
| OpenClaw 记忆 | Agent 执行历史、决策记录 | 持续增长 | 实时 |
1.2 知识分类
| 分类 | 示例 | 检索场景 |
|---|---|---|
| 技术架构 | 系统架构图、技术选型文档 | ”我们的支付系统用的什么方案?“ |
| 开发规范 | 代码规范、Git 工作流、CR 标准 | ”提交 PR 的流程是什么?“ |
| 业务知识 | 课程体系、用户画像、产品路线图 | ”Solana 课程的目标用户是谁?“ |
| 排错经验 | 故障复盘、常见问题解决方案 | ”上次数据库连接池满了怎么解决的?“ |
| 流程制度 | 入职流程、请假制度、报销规范 | ”新员工入职需要准备什么?“ |
2. 向量数据库选型与配置
2.1 选型对比
| 维度 | Chroma | Weaviate | pgvector |
|---|---|---|---|
| 定位 | 轻量级,适合开发和小团队 | 生产级,功能丰富 | PostgreSQL 扩展 |
| 安装复杂度 | pip install | Docker 部署 | PostgreSQL 扩展安装 |
| 数据持久化 | 本地文件 | 内置持久化 | PostgreSQL 存储 |
| 最大数据量 | ~100 万向量 | 数十亿向量 | 取决于 PostgreSQL |
| 混合搜索 | 向量 + 元数据过滤 | 向量 + BM25 + 过滤 | 向量 + SQL |
| 多租户 | 通过 Collection 隔离 | 原生多租户 | 通过 Schema 隔离 |
| 月成本 | ¥0(自托管) | ¥0(自托管)/ Cloud 按量 | ¥0(复用现有 PG) |
| 推荐场景 | 30 人团队,知识库 < 10 万文档 | 大规模生产环境 | 已有 PostgreSQL 的团队 |
HackQuest 推荐:起步用 Chroma(简单快速),知识库超过 10 万文档后迁移到 Weaviate 或 pgvector。
2.2 Chroma 安装与配置
# 安装 Chroma
pip install chromadb
# 启动 Chroma Server(生产模式)
chroma run --host 0.0.0.0 --port 8000 --path /data/chromaPython 客户端连接:
import chromadb
client = chromadb.HttpClient(host="localhost", port=8000)
# 创建 Collection(按知识分类)
tech_collection = client.get_or_create_collection(
name="tech_docs",
metadata={"description": "技术架构和开发规范文档"}
)
business_collection = client.get_or_create_collection(
name="business_docs",
metadata={"description": "业务知识和产品文档"}
)
experience_collection = client.get_or_create_collection(
name="experience_docs",
metadata={"description": "排错经验和复盘报告"}
)2.3 pgvector 方案(备选)
如果团队已有 PostgreSQL,可以直接使用 pgvector 扩展,省去额外部署向量数据库:
-- 安装 pgvector 扩展
CREATE EXTENSION IF NOT EXISTS vector;
-- 创建知识库表
CREATE TABLE knowledge_chunks (
id SERIAL PRIMARY KEY,
source_type VARCHAR(50) NOT NULL, -- feishu_wiki, feishu_doc, github_readme
source_id VARCHAR(200) NOT NULL, -- 飞书文档 token 或 GitHub 路径
source_title VARCHAR(500),
chunk_index INTEGER NOT NULL,
content TEXT NOT NULL,
embedding vector(1536), -- OpenAI text-embedding-3-small 维度
metadata JSONB, -- 额外元数据
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 创建向量索引(IVFFlat,适合中等数据量)
CREATE INDEX idx_knowledge_embedding ON knowledge_chunks
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- 创建元数据索引
CREATE INDEX idx_knowledge_source ON knowledge_chunks(source_type, source_id);3. Embedding 管道
3.1 整体流程
飞书知识库/文档
│
▼
内容提取(lark-mcp)
│
▼
文本清洗(去除格式标记、空白)
│
▼
文本分块(按标题/段落/滑动窗口)
│
▼
生成 Embedding(OpenAI API)
│
▼
存入向量数据库(Chroma/pgvector)3.2 Embedding 模型选择
| 模型 | 维度 | 价格 | 性能 | 推荐场景 |
|---|---|---|---|---|
| OpenAI text-embedding-3-small | 1536 | $0.02/1M tokens | 良好 | 性价比首选 |
| OpenAI text-embedding-3-large | 3072 | $0.13/1M tokens | 优秀 | 高精度需求 |
| Cohere embed-v4.0 | 1024 | $0.10/1M tokens | 优秀 | 多语言场景 |
| BGE-M3(本地部署) | 1024 | 免费 | 良好 | 数据敏感场景 |
HackQuest 推荐:text-embedding-3-small,中文效果好,成本低。200 篇文档约 50 万 tokens,Embedding 成本约 ¥0.07。
3.3 文本分块策略
| 策略 | 适用场景 | 块大小 | 重叠 |
|---|---|---|---|
| 按标题分块 | 结构化文档(技术方案) | 按 H2/H3 标题切分 | 无 |
| 按段落分块 | 叙述性文档(会议纪要) | 每段一块 | 无 |
| 固定大小 + 滑动窗口 | 长文档 | 500 tokens | 50 tokens |
| 语义分块 | 混合内容 | 按语义边界切分 | 自适应 |
推荐组合策略:
- 优先按标题分块(保留文档结构)
- 如果单块超过 800 tokens,使用滑动窗口二次切分
- 每个块附加元数据:文档标题、章节标题、来源链接
3.4 Embedding 管道脚本
"""
飞书知识库 → Chroma 向量数据库 Embedding 管道
"""
import os
import re
import chromadb
from openai import OpenAI
# 初始化客户端
openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
chroma_client = chromadb.HttpClient(host="localhost", port=8000)
collection = chroma_client.get_or_create_collection("tech_docs")
def extract_feishu_doc(doc_token: str) -> dict:
"""
通过 lark-mcp 提取飞书文档内容。
实际使用时通过 OpenClaw Skill 调用 lark-mcp 工具。
这里展示数据结构。
"""
return {
"token": doc_token,
"title": "文档标题",
"content": "文档正文内容...",
"url": f"https://xxx.feishu.cn/docx/{doc_token}"
}
def chunk_by_heading(content: str, max_tokens: int = 800) -> list[dict]:
"""按标题分块,超长块二次切分"""
sections = re.split(r'\n(#{1,3}\s+)', content)
chunks = []
current_heading = ""
current_text = ""
for i, section in enumerate(sections):
if re.match(r'^#{1,3}\s+', section):
current_heading = section.strip()
else:
text = f"{current_heading}\n{section.strip()}" if current_heading else section.strip()
if not text:
continue
# 粗略估算 token 数(中文约 1.5 字/token)
estimated_tokens = len(text) / 1.5
if estimated_tokens > max_tokens:
# 滑动窗口二次切分
words = text.split('\n')
sub_chunk = ""
for line in words:
if len(sub_chunk + line) / 1.5 > max_tokens:
if sub_chunk:
chunks.append({"heading": current_heading, "content": sub_chunk.strip()})
sub_chunk = line + "\n"
else:
sub_chunk += line + "\n"
if sub_chunk.strip():
chunks.append({"heading": current_heading, "content": sub_chunk.strip()})
else:
chunks.append({"heading": current_heading, "content": text})
return chunks
def generate_embeddings(texts: list[str]) -> list[list[float]]:
"""批量生成 Embedding"""
response = openai_client.embeddings.create(
model="text-embedding-3-small",
input=texts
)
return [item.embedding for item in response.data]
def index_document(doc: dict):
"""索引单个文档"""
chunks = chunk_by_heading(doc["content"])
if not chunks:
return
# 批量生成 Embedding
texts = [chunk["content"] for chunk in chunks]
embeddings = generate_embeddings(texts)
# 批量写入 Chroma
collection.upsert(
ids=[f"{doc['token']}_chunk_{i}" for i in range(len(chunks))],
embeddings=embeddings,
documents=texts,
metadatas=[{
"source_type": "feishu_wiki",
"source_id": doc["token"],
"source_title": doc["title"],
"source_url": doc["url"],
"chunk_heading": chunk["heading"],
"chunk_index": i
} for i, chunk in enumerate(chunks)]
)
print(f"✅ Indexed {doc['title']}: {len(chunks)} chunks")
# 使用示例
if __name__ == "__main__":
# 实际使用时,文档列表从飞书知识库 API 获取
doc_tokens = ["doccnxxxxxxxxxx", "doccnyyyyyyyyyy"]
for token in doc_tokens:
doc = extract_feishu_doc(token)
index_document(doc)4. RAG 检索 Skill
4.1 检索 Skill 完整示例
创建 skills/knowledge/knowledge-rag-search.md:
# knowledge-rag-search
根据用户问题检索知识库,结合检索结果生成回答。
## 触发条件
- 用户消息包含"知识库"、"查一下"、"有没有文档"、"之前怎么做的"
- 其他 Skill 无法匹配时的兜底(知识库问答)
## 执行步骤
1. 提取用户问题的核心关键词
2. 将用户问题转换为 Embedding 向量
3. 在向量数据库中检索最相关的 5 个文档块(top_k=5,相似度阈值 > 0.7)
4. 将检索到的文档块作为上下文,结合用户问题生成回答
5. 在回答末尾附上参考文档链接
6. 将本次问答写入记忆,积累常见问题
## 检索参数
- top_k: 5
- 相似度阈值: 0.7(低于此阈值的结果不使用)
- 搜索范围: 所有 Collection(tech_docs, business_docs, experience_docs)
## Prompt 模板
你是 HackQuest 团队的知识助手。根据以下检索到的文档内容回答用户问题。
规则:
1. 只基于检索到的文档内容回答,不要编造信息
2. 如果检索结果不足以回答问题,明确告知用户"知识库中暂无相关信息"
3. 回答末尾列出参考文档链接
4. 使用简洁清晰的中文回答
检索到的文档:
{retrieved_chunks}
用户问题:{user_question}
## 输出格式
回答正文(2-5 段)
📚 参考文档:
- [文档标题1](链接1)
- [文档标题2](链接2)
## 示例输出
**用户问题**: 我们的支付系统用的什么方案?
**回答**:
HackQuest 的支付系统采用 Stripe 作为主要支付网关,支持信用卡和加密货币支付。
核心架构:
- 前端使用 Stripe Elements 组件
- 后端通过 Stripe Node.js SDK 处理支付意图
- Webhook 接收支付状态回调,更新订单状态
- 加密货币支付通过 Coinbase Commerce API 集成
详细的技术方案见架构文档。
📚 参考文档:
- [支付系统架构设计](https://xxx.feishu.cn/docx/xxx)
- [Stripe 集成指南](https://xxx.feishu.cn/wiki/xxx)
## 权限要求
- 向量数据库读取权限
- OpenAI Embedding API 调用权限
## 错误处理
- 向量数据库连接失败:回复"知识库服务暂时不可用,请稍后再试"
- 检索结果为空:回复"知识库中暂无相关信息,建议联系 [相关负责人]"
- Embedding API 调用失败:使用关键词匹配作为降级方案4.2 检索参数调优
| 参数 | 默认值 | 调优建议 |
|---|---|---|
| top_k | 5 | 简单问题用 3,复杂问题用 7-10 |
| 相似度阈值 | 0.7 | 精确匹配场景提高到 0.8,模糊搜索降低到 0.6 |
| 搜索范围 | 全部 Collection | 根据问题类型限定 Collection 提高精度 |
| 重排序 | 无 | 检索结果多时,用 LLM 对 top_k 结果重排序 |
4.3 上下文拼接策略
[系统 Prompt]
你是 HackQuest 团队的知识助手...
[检索结果 - 按相似度降序]
--- 文档 1 (相似度: 0.92) ---
来源: 支付系统架构设计
内容: ...
--- 文档 2 (相似度: 0.85) ---
来源: Stripe 集成指南
内容: ...
[用户问题]
我们的支付系统用的什么方案?5. 知识自动更新
5.1 增量更新方案
飞书文档变更 Webhook
│
▼
OpenClaw 接收事件
│
▼
knowledge-auto-update Skill
│
├─→ 提取变更文档内容
├─→ 删除旧的文档块
├─→ 重新分块和 Embedding
└─→ 写入向量数据库创建 skills/knowledge/knowledge-auto-update.md:
# knowledge-auto-update
监听飞书文档变更事件,自动更新向量数据库中的对应文档。
## 触发条件
飞书文档变更事件(文档编辑保存后触发)。
## 执行步骤
1. 从事件中提取文档 token
2. 通过 lark-mcp 读取文档最新内容
3. 删除向量数据库中该文档的所有旧块(通过 source_id 匹配)
4. 对新内容执行分块和 Embedding
5. 将新块写入向量数据库
6. 记录更新日志到记忆
## 过滤规则
- 只处理知识库和指定文件夹下的文档
- 忽略草稿状态的文档
- 忽略 5 分钟内的重复变更(防抖)
## 权限要求
- 飞书文档读取权限
- 向量数据库读写权限
- OpenAI Embedding API5.2 全量重建策略
定期全量重建,确保数据一致性:
# knowledge-full-rebuild
每周日凌晨 2:00 全量重建知识库索引。
## 触发条件
定时触发:每周日 02:00
## 执行步骤
1. 通过 lark-mcp 获取知识库所有文档列表
2. 清空向量数据库中所有 Collection
3. 逐个文档执行分块 → Embedding → 入库
4. 统计重建结果(文档数、块数、耗时)
5. 发送重建报告到运维群
## 预计耗时
- 200 篇文档约 30 分钟
- 主要耗时在 Embedding API 调用(受限于 API rate limit)5.3 更新监控
| 监控项 | 说明 | 告警条件 |
|---|---|---|
| 增量更新成功率 | 文档变更后是否成功更新索引 | 连续 3 次失败 |
| 全量重建耗时 | 每周重建的执行时间 | 超过 2 小时 |
| 索引文档数 | 向量数据库中的文档总数 | 与飞书文档数差异 > 10% |
| Embedding API 调用量 | 每日 API 调用 token 数 | 超过预算阈值 |
6. 效果评估与优化
6.1 评估指标
| 指标 | 定义 | 目标值 | 评估方法 |
|---|---|---|---|
| 检索准确率 | 返回的 top_k 结果中包含正确答案的比例 | > 80% | 人工标注测试集 |
| 回答准确率 | LLM 基于检索结果生成的回答是否正确 | > 85% | 人工评审 |
| 回答完整性 | 回答是否覆盖了问题的所有方面 | > 75% | 人工评审 |
| 幻觉率 | 回答中包含检索结果中不存在的信息的比例 | < 5% | 人工对比 |
| 响应时间 | 从提问到回答的端到端时间 | < 5s | 自动监控 |
6.2 构建评估测试集
为 HackQuest 场景构建 50 个标准问答对:
[
{
"question": "我们的支付系统用的什么方案?",
"expected_sources": ["支付系统架构设计"],
"expected_answer_contains": ["Stripe", "Coinbase Commerce"],
"category": "tech_architecture"
},
{
"question": "新员工入职第一天需要做什么?",
"expected_sources": ["入职流程指南"],
"expected_answer_contains": ["飞书账号", "GitHub 权限", "开发环境"],
"category": "process"
},
{
"question": "上次数据库连接池满了怎么解决的?",
"expected_sources": ["2026-06 数据库故障复盘"],
"expected_answer_contains": ["连接池", "max_connections", "pgbouncer"],
"category": "experience"
}
]6.3 常见问题与优化策略
| 问题 | 原因 | 优化策略 |
|---|---|---|
| 检索结果不相关 | 分块太大,语义稀释 | 减小块大小,按标题分块 |
| 回答不完整 | top_k 太小,遗漏关键信息 | 增大 top_k 到 7-10 |
| 回答包含幻觉 | Prompt 约束不够 | 强化”只基于检索结果回答”的指令 |
| 中文检索效果差 | Embedding 模型中文能力弱 | 换用 BGE-M3 或 Cohere embed-v4.0 |
| 响应时间长 | Embedding + 检索 + LLM 三次调用 | 缓存高频问题的 Embedding,使用更快的模型 |
| 知识过时 | 文档更新后索引未同步 | 确保增量更新 Skill 正常运行 |
7. 工具与资源推荐
| 工具 | 用途 | 价格 | 链接 |
|---|---|---|---|
| Chroma | 轻量级向量数据库 | 开源免费 | 官网 |
| Weaviate | 生产级向量数据库 | 开源免费 / Cloud 按量 | 官网 |
| pgvector | PostgreSQL 向量扩展 | 开源免费 | GitHub |
| OpenAI Embeddings | 文本向量化 | $0.02/1M tokens | 文档 |
| BGE-M3 | 开源多语言 Embedding | 免费(本地部署) | HuggingFace |
下一篇: 37f 产品研发工作流 Agent — 实现从需求到上线的完整研发流程自动化
Last updated on