RAG 知识库集成(架构与权衡)
RAG 知识助理 tutorial 给了完整 代码;本页讲架构权衡 — 把”能跑”做到”生产质量”的 6 个关键决策。
决策 1:Embedding model
| Model | Dim | $ / 1M token | 适合 |
|---|---|---|---|
OpenAI text-embedding-3-small | 1536 | $0.02 | 通用 / 中英混合(默认推荐) |
OpenAI text-embedding-3-large | 3072 | $0.13 | 高精度 / 复杂语义 |
| Anthropic Voyage AI | 1024 | $0.05 | 长文档优秀 |
| Cohere multilingual | 1024 | $0.10 | 多语言场景 |
| BGE-large(开源 / 本地) | 1024 | $0 | 隐私 / 离线 / 自托管 |
关键权衡:
- 切换 model 必须双写并行 30 天 → 灰度迁移 → 删旧 — 不能直接切(向量空间不兼容)
- 1536 dim PG 索引(ivfflat)建索引时间 ~10 min / 1M chunks;3072 dim 约 30 min
决策 2:切块策略
| 策略 | 块大小 | 重叠 | 适合 |
|---|---|---|---|
| 固定字符切(朴素) | 500 字符 | 100 字符 | 实现简单;适合 MVP |
| 句子边界切 | 3-5 句 | 1 句 | 中等;段落语义保留 |
| Section / Heading 切 | 按 H2/H3 边界 | — | 结构化文档(Markdown / docx) |
| Semantic chunking | 嵌套 LLM 判定边界 | — | 高质量;成本高 |
生产推荐:Heading 切 + 强 metadata(source / page / heading_path)。
function chunkByHeadings(markdown: string): { text: string; metadata: any }[] { const sections = markdown.split(/\n(?=#{1,3} )/); return sections.flatMap((section) => { const headingMatch = section.match(/^(#{1,3}) (.+)$/m); const heading = headingMatch?.[2]; const body = section.replace(/^#{1,3} .+\n/, "").trim(); if (body.length < 100) return [{ text: section, metadata: { heading } }]; // 长 section 再按段落切 return body.split(/\n\n+/).map((para) => ({ text: `## ${heading}\n\n${para}`, metadata: { heading }, })); });}决策 3:Hybrid Search(vector + BM25)
纯向量检索对专有名词 / 缩写 / 错别字 容易漏。叠加 BM25 全文搜回率显著高。
SELECT id, text, (embedding <=> $1) AS vector_distance, ts_rank(to_tsvector('simple', text), plainto_tsquery('simple', $2)) AS bm25_scoreFROM doc_chunksWHERE user_id = $3ORDER BY (embedding <=> $1) + (1.0 - ts_rank(...)) ASCLIMIT 20;或者用 Reciprocal Rank Fusion (RRF):vector 和 BM25 分别取 top 50,按 1/rank 加权融合。
决策 4:Re-ranking
top-k 检索后用 cross-encoder 二次精排,提升准确率 10-20%。
import { CohereClient } from "cohere-ai";const cohere = new CohereClient({ token: process.env.COHERE_API_KEY });
const reranked = await cohere.rerank({ model: "rerank-multilingual-v3.0", query: question, documents: topK.map((d) => d.text), topN: 5,});const finalContext = reranked.results.map((r) => topK[r.index].text);成本:~$2 / 1000 query。值不值看准确率提升。
决策 5:引用透明
LLM 回复后明确标 [1] [2] 标号,artifact 卡列源:
const c = await openai.chat.completions.create({ messages: [ { role: "system", content: `回答末尾用 [1] [2] 标注引用源。如果不足 → 直说"信息不足"。
来源:[1] ${chunks[0].source} ${chunks[0].text.slice(0, 100)}...[2] ${chunks[1].source} ${chunks[1].text.slice(0, 100)}...` }, { role: "user", content: question }, ],});
await agent.send(convId, { type: "text", text: c.choices[0]?.message?.content });await agent.sendArtifact(convId, { artifact: { subtype: "info", title: "参考来源", payload: { body: chunks.map((c, i) => `**[${i+1}]** ${c.source}`).join("\n") }, },});为什么这是必须的:用户对”AI 幻觉”敏感;明确引用提升信任感 + 让用户能验证。
决策 6:数据主权边界
Hashee 平台:永远看不到文档内容(盲管道)。
你的 Agent 后端:保存文档明文 + embedding(业务需要)。
用户撤销:触发 relation.revoked → 必须立即 DELETE FROM doc_chunks WHERE user_id = ?。
明文存哪:
| 位置 | 隐私 | 实用 |
|---|---|---|
| Agent 后端 PG | 高(用户授权后访问) | 高 |
| 用户自己设备(V2 路线) | 极高 | 低(agent 离线时不可达) |
| 第三方向量 DB(Pinecone / Weaviate) | 中(看 vendor TOS) | 高 |
V1 推荐:Agent 自己后端 PG + pgvector。
性能基准
| 操作 | P50 | P95 |
|---|---|---|
| Embedding(OpenAI small) | 80 ms | 200 ms |
| pgvector top-5 检索 (100k chunks) | 30 ms | 80 ms |
| LLM 总结(gpt-4o-mini) | 800 ms | 2 s |
| 端到端 RAG 回答 | 1-2 s | 3 s |
监控
| 指标 | 报警 |
|---|---|
| Embedding 调用 / day | 异常飙升 → 看是否被滥用 |
| 检索 vector_distance p50 | > 0.5 → 知识库覆盖差 |
| LLM “信息不足” 回复率 | > 30% → 库需扩充 |
| 用户点 thumbs down 比例 | > 10% → 检查 prompt / 切块策略 |
相关页面
- RAG 知识助理教程 — 完整代码
- Agent 记忆设计 — RAG 之外的 memory
- 信任中心 — 数据主权承诺
- GDPR 合规清单