AI 实战 / 已完成
AI 应用里的 RAG 知识库实战
理解文档上传、切分、向量化、检索、Prompt、引用来源和 RAG 效果调试。
返回文章积累一句话:RAG 知识库就是先从你的资料里找出相关片段,再把片段交给大模型回答,减少模型胡说。
本篇学完你会什么:理解上传文档、切分、向量化、入库、检索、拼提示词、生成回答、引用来源和效果调试这一整条 RAG 实战链路。
1. 为什么 AI 应用需要 RAG
直接问大模型:
我们公司报销制度是什么?模型可能不知道你的公司制度,也可能编一个听起来很像真的答案。
RAG 的做法是:
先查你的资料
再带着资料问模型
最后让模型根据资料回答它解决的是:
| 问题 | RAG 怎么帮忙 |
|---|---|
| 模型不知道私有资料 | 先从知识库检索 |
| 模型容易胡说 | 要求根据资料回答 |
| 回答没有依据 | 返回引用来源 |
| 文档太长塞不进 prompt | 只取最相关片段 |
2. RAG 完整流程
完整链路:
上传文档
↓
解析文本
↓
切分 chunk
↓
生成 embedding
↓
存入向量库
↓
用户提问
↓
问题生成 embedding
↓
检索相似 chunk
↓
把 chunk 放进 prompt
↓
大模型生成回答
↓
返回答案和引用来源大白话:先把资料整理成一张可搜索的卡片库。用户问问题时,先从卡片库找相关卡片,再拿卡片去问模型。
3. 文档上传后先做什么
用户上传的可能是:
PDF
Word
Markdown
网页
纯文本
代码文件第一步不是马上丢给模型,而是解析出干净文本。
你需要保存:
| 字段 | 作用 |
|---|---|
document_id | 文档 id |
filename | 原文件名 |
content | 解析后的全文 |
created_at | 上传时间 |
owner_id | 谁上传的 |
还要记录失败原因,比如:
文件太大
格式不支持
PDF 扫描件没有文字
解析超时4. 切分 chunk 怎么理解
模型不能每次都读完整文档,所以要切成小段。
比如一篇制度文档:
第一段:报销适用范围
第二段:交通费标准
第三段:住宿费标准
第四段:审批流程为了先理解,可以把“每一段就是一个 chunk”当成入门版说法。
真实项目里,chunk 不一定刚好等于自然段。切分方式要看文档长什么样:
| 切分方式 | 适合 | 注意 |
|---|---|---|
| 按自然段 | 制度、文章这类段落清楚的文档 | 段落太长要再拆 |
| 固定长度 + 重叠 | 文档格式混乱、段落不稳定 | 不要切断关键上下文 |
| 按标题层级 | Markdown、技术文档、说明书 | 把标题保存到 metadata |
| 表格/代码特殊处理 | 参数表、API 文档、代码片段 | 不要把一行表或一段代码拆散 |
chunk 要保存:
| 字段 | 作用 |
|---|---|
chunk_id | 片段 id |
document_id | 属于哪份文档 |
content | 片段正文 |
page | 来自第几页 |
title | 来自哪个标题 |
embedding | 向量 |
切太大,检索不准;切太小,上下文不完整。初学可以先用:
每段 500-800 个中文字符
相邻段落重叠 80-120 个字符5. Embedding 和向量库是什么
Embedding 可以理解成:把一段文字变成一串数字,方便计算“意思像不像”。
比如:
“报销交通费需要什么材料?”和:
“交通费报销需提供发票和审批单”字面不完全一样,但意思很接近。Embedding 就是帮系统判断这种接近程度。
向量库就是专门存这些数字和文本片段的仓库。
常见选择:
| 选择 | 适合 |
|---|---|
| pgvector | 已经用 PostgreSQL,想少引入新组件 |
| Chroma | 本地学习和小项目 |
| Milvus | 数据量更大、向量检索更专业 |
| Elasticsearch/OpenSearch | 需要关键词检索和向量混合 |
6. 检索怎么做
用户提问:
出差住宿费最多报多少?系统做:
问题 -> embedding -> 向量库查 top_k 个相似 chunk伪代码:
query_vector = embedding_model.embed_query(question)
chunks = vector_store.similarity_search_by_vector(query_vector, k=5)top_k=5 的意思是:先找最相关的 5 个片段。
不要一开始取太多。取太多会让 prompt 变长、成本变高,还可能把不相关内容塞给模型。
7. Prompt 怎么拼
拿到片段后,把它们放进提示词:
你是知识库问答助手。
请只根据【资料】回答问题。
如果资料里没有答案,就说“资料中没有找到明确答案”。
【资料】
1. 交通费报销需要发票和审批单。
2. 住宿费标准为每晚不超过 500 元。
【问题】
出差住宿费最多报多少?关键规则:
- 明确要求“只根据资料回答”。
- 明确资料不足时怎么说。
- 保留来源信息,方便引用。
8. 回答里为什么要带引用
没有引用,用户只能相信模型。
带引用后,用户能回到原文确认。
返回可以这样:
{
"answer": "根据资料,出差住宿费标准为每晚不超过 500 元。",
"sources": [
{
"document": "报销制度.pdf",
"page": 3,
"chunk_id": "chunk_102"
}
]
}引用不是装饰,它是 RAG 的信任基础。
9. 后端接口怎么设计
最小接口:
| 接口 | 作用 |
|---|---|
POST /knowledge/documents | 上传文档 |
GET /knowledge/documents | 文档列表 |
POST /knowledge/documents/{id}/index | 解析、切分、向量化 |
POST /knowledge/chat | 基于知识库问答 |
问答请求:
{
"question": "出差住宿费最多报多少?",
"document_ids": [1, 2],
"top_k": 5
}问答响应:
{
"answer": "出差住宿费标准为每晚不超过 500 元。",
"sources": [
{
"document_id": 1,
"filename": "报销制度.pdf",
"page": 3
}
]
}10. RAG 效果差怎么调
效果差时,不要只怪模型。按这条链路查:
文档是否解析干净
chunk 是否切得太碎或太大
embedding 模型是否合适
top_k 是否太少或太多
检索结果是否真的相关
prompt 是否要求只根据资料回答
是否返回引用来源常见调法:
| 问题 | 调整 |
|---|---|
| 找不到答案 | 增大 top_k,检查文档是否入库 |
| 答案不准 | 优化 chunk,加入标题和页码 metadata |
| 回答胡说 | prompt 要求资料不足就说明 |
| 成本太高 | 减少 top_k,缩短 chunk,缓存结果 |
| 引用不对 | 检查 chunk 的 document/page metadata |
11. 常见错误
| 错误 | 后果 | 修正 |
|---|---|---|
| 把整份文档直接塞给模型 | 超长、贵、不稳定 | 先切分和检索 |
| chunk 没保存来源 | 无法引用 | 保存 document/page/title |
| 只做向量检索,不看结果 | 不知道错在哪 | 调试时打印 top_k chunk |
| prompt 没限制依据 | 模型容易自由发挥 | 要求只根据资料回答 |
| 文档更新后不重建索引 | 答案用旧资料 | 文档变更后重新向量化 |
| 用户权限没控制 | 可能查到不该看的资料 | 检索时按 owner/tenant 过滤 |
12. 检查清单
[ ] 文档能上传并记录 owner
[ ] 文档能解析成干净文本
[ ] chunk 保存了 document_id、page、title
[ ] embedding 已写入向量库
[ ] 问题能检索 top_k 片段
[ ] prompt 明确只根据资料回答
[ ] 资料不足时不会编答案
[ ] 回答返回 sources
[ ] 文档更新后能重建索引
[ ] 检索时有用户或租户权限过滤13. 总结表
| 名词 | 大白话 |
|---|---|
| RAG | 先查资料,再让模型回答 |
| chunk | 从文档切出来的小片段 |
| embedding | 把文字变成可比较的数字 |
| 向量库 | 保存 embedding 和片段的仓库 |
| top_k | 找最相关的前几段 |
| metadata | 片段来源信息,比如文档、页码、标题 |
| sources | 回答引用的资料来源 |
| hallucination | 模型胡说 |
上一篇建议:大白话讲解——FastAPI 项目配置、多环境和部署上线.md
下一篇建议:把 RAG 接到你的 AI 实验室 小接口里,先做“上传一份 Markdown 文档并问答”的最小版本。