跳到主内容
RAGLlamaIndex向量数据库文档问答

RAG 管道从零搭建:文档问答系统实战

用 LlamaIndex + ChromaDB + GPT-4o 搭一个生产级 RAG 系统——文档切分策略、Embedding 选型、检索优化、重排序、回答生成、评估指标,含完整代码和踩坑记录。

发布 2026-06-21更新 2026-09-30

适用场景

  • 公司内部知识库问答(HR 政策、技术文档、FAQ)
  • 法律/医疗文档检索 + 问答
  • 产品手册智能客服
  • 个人笔记/文献智能检索

RAG 架构总览

文档 → 切分 → Embedding → 存入向量数据库
                                    ↓
用户提问 → Embedding → 检索 Top-K → 重排序 → LLM 生成回答

技术选型

组件选型理由
框架LlamaIndex比 LangChain 更专注 RAG
EmbeddingBGE-large-zh-v1.5中文效果最佳,开源免费
向量数据库ChromaDB轻量,原型够用
重排序bge-reranker-large显著提升准确率
LLMGPT-4o性价比好,支持国内中转
文档解析Unstructured支持 PDF/Word/HTML

第一步:环境准备

pip install llama-index chromadb sentence-transformers unstructured

第二步:文档加载与切分

切分是 RAG 效果的决定性因素。

from llama_index.core import SimpleDirectoryReader
from llama_index.core.node_parser import SentenceSplitter

# 1. 加载文档
documents = SimpleDirectoryReader("./docs").load_data()

# 2. 切分
splitter = SentenceSplitter(
    chunk_size=512,      # 每块 512 token
    chunk_overlap=50,    # 重叠 50 token,保证上下文连贯
)
nodes = splitter.get_nodes_from_documents(documents)

切分策略选择

策略chunk_size适用场景
小块256FAQ、短问答
中块512通用文档(推荐起步值)
大块1024长文档、技术手册
按段落不固定保持语义完整

关键:chunk_overlap 设 chunk_size 的 10%,避免切断语义。

第三步:Embedding 与入库

from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.vector_stores.chroma import ChromaVectorStore
import chromadb

# 1. 用 BGE 中文模型
embed_model = HuggingFaceEmbedding(
    model_name="BAAI/bge-large-zh-v1.5",
    max_length=512,
)

# 2. 创建向量数据库
db = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = db.get_or_create_collection("docs")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)

# 3. 构建索引
from llama_index.core import StorageContext, VectorStoreIndex
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, embed_model=embed_model, storage_context=storage_context)

第四步:检索 + 重排序

from llama_index.core.postprocessor import SentenceTransformerRerank

# 重排序模型——显著提升检索质量
reranker = SentenceTransformerRerank(
    model="BAAI/bge-reranker-large",
    top_n=3,  # 重排序后取前 3
)

# 检索器
retriever = index.as_retriever(similarity_top_k=10)  # 先粗检索 10 条

# 检索 + 重排序
nodes = retriever.retrieve("年假怎么请?")
reranked = reranker.postprocess_nodes(nodes, query_str="年假怎么请?")

为什么要重排序

Embedding 检索快但不够精准。先粗检索 10 条,再用重排序模型精选 3 条,准确率提升 20-30%。

第五步:生成回答

from llama_index.llms.openai import OpenAI

llm = OpenAI(model="gpt-4o", temperature=0)

# 构建 query engine
query_engine = index.as_query_engine(
    llm=llm,
    similarity_top_k=10,
    node_postprocessors=[reranker],
    response_mode="compact",  # 紧凑模式,省 token
)

# 提问
response = query_engine.query("年假怎么请?需要提前多久申请?")
print(response.response)

Prompt 优化

默认 prompt 是英文的,中文场景建议自定义:

from llama_index.core import PromptTemplate

qa_prompt = PromptTemplate("""
你是一个文档问答助手。请根据以下检索到的文档片段回答问题。
如果文档中没有相关信息,明确说"文档中未找到相关信息",不要编造。

文档片段:
{context_str}

问题:{query_str}

回答:
""")

query_engine.update_prompts({"response_synthesis_prompt": qa_prompt})

第六步:评估

检索质量评估

# 准备测试集:问题 + 正确答案所在文档
test_cases = [
    {"question": "年假怎么请?", "relevant_doc_id": "hr_policy_003"},
    {"question": "报销流程是什么?", "relevant_doc_id": "finance_007"},
]

# 计算 Recall@K
def eval_retrieval(query_engine, test_cases, k=5):
    hits = 0
    for tc in test_cases:
        nodes = query_engine.retrieve(tc["question"])
        retrieved_ids = [n.node.metadata["doc_id"] for n in nodes[:k]]
        if tc["relevant_doc_id"] in retrieved_ids:
            hits += 1
    return hits / len(test_cases)

recall = eval_retrieval(query_engine, test_cases, k=5)
print(f"Recall@5: {recall:.1%}")

回答质量评估

用 LLM 自动评估回答质量:

eval_prompt = f"""
请评估以下回答的质量,打分 1-5:
问题:{question}
检索到的文档:{retrieved_docs}
回答:{answer}

评分标准:
5 — 完全正确,基于文档
3 — 部分正确,有遗漏
1 — 错误或编造
"""

常见问题与优化

问题 1:检索不到相关文档

原因:切分太碎,语义丢失。

解决:

  • 增大 chunk_size(512 → 1024)
  • 加 chunk_overlap
  • 用 parent-child 切分(检索小块,返回大块)

问题 2:回答不基于文档(幻觉)

解决:

  • prompt 强制要求"只基于文档回答"
  • temperature 设 0
  • 检查检索结果是否相关(不相关就回答"未找到")

问题 3:中文检索效果差

解决:

  • 用 BGE 系列中文 Embedding 模型
  • 不要用 OpenAI 的 Embedding(中文效果一般)
  • 加重排序模型

问题 4:速度慢

解决:

  • Embedding 用 GPU
  • 向量数据库加 HNSW 索引
  • 减少 similarity_top_k(10 → 5)
  • LLM 用流式输出

2026-09-30 更新:模型选型这一段已经过时

本文写成于 2026 年年中,正文里的 GPT-4o 作为生成端模型已经不再是性价比选项。本站不改正文代码里的模型名(保留原始教程的可复现性),但选型这一段必须按当前口径读:

环节2026-09 的选型原则
生成端 LLM别再用 GPT-4o 这一代。按「每任务成本」选:高频问答走轻量档(如 GPT-6 Luna $0.10/$0.50 一类),需要多步推理的走中阶档。缓存命中率是成本第一变量——prompt 前缀必须稳定
Embedding优先选与你语料语言匹配的模型;中文语料用通用多语言 embedding 的效果通常优于英强中弱的旧款。别只看 MTEB 总分,看中文子集
重排序(rerank)成本敏感时先做「是否真的需要 rerank」的 A/B——很多场景里调好切分比加 rerank 收益更大
本地部署完全离线场景走 Ollama / LM Studio,但注意本地模型的长上下文与多步推理能力弱于前沿闭源模型,RAG 的「上下文已经喂足」特性恰好能补一部分短板

常见失效模式与排查顺序

RAG 线上出问题时,90% 的锅不在生成端。按下面顺序排查,能省掉大量无效调 prompt 的时间:

现象最可能的原因先做什么
答案「看起来对但细节错」检索没命中的上下文被模型用先验补全打印本次召回的 chunk,确认里面到底有没有答案
问什么都能答上来(包括不存在的)防幻觉 prompt 太弱,或 similarity_top_k 过大引入噪声收紧 prompt 的「只依据上下文」约束 + 降 top_k
明明文档里有,就是搜不到切分把答案切断了,或 embedding 与查询语义不匹配换切分策略(按标题层级 / 加 overlap)后重试
表格、公式类内容答不准解析器把结构丢了换支持表格结构的解析器,或表格单独走结构化检索
换一批文档效果骤降新文档格式 / 语言分布与调优时不同重新跑评估集,别沿用旧参数
延迟高瓶颈常在向量库 ANN 参数与 rerank,不在 LLM先量三段耗时再优化

排查铁律:先确认召回,再动 prompt。看不到召回内容就调 prompt,等于闭眼修车。

评估:怎么做得不骗自己

  1. 先建一个小而真的评估集(30~100 条即可),题目来自真实用户提问,不是作者编的。
  2. 分别评估两段:检索段用 Recall@K(答案所在 chunk 是否被召回),生成段用人工抽检或 LLM-as-judge。只测端到端准确率,你会分不清是检索错还是生成错。
  3. 留一组「文档里没有答案」的题,专门测模型会不会瞎编。RAG 最容易翻车的不是答不出,而是答得太自信。
  4. 每次改切分 / embedding / top_k,都重跑一次评估集,把数字记进表格。凭感觉调参是 RAG 项目最常见的失败原因。
  5. 上线后记录「问题 + 召回 + 回答」三元组,它们既是排查依据,也是下一轮评估集的素材。

小结

RAG 的工程重心不在模型,在数据管道:切分策略决定召回上限,embedding 决定语义匹配质量,rerank 与 top_k 决定噪声水平,生成端只负责把已经找到的内容说清楚。把顺序搞反——先换更强的模型再抱怨效果差——是这类项目最典型的浪费。

生产部署清单

  • 文档解析支持 PDF/Word/HTML/Markdown
  • 切分策略测试过(chunk_size 调优)
  • Embedding 模型选定并部署
  • 向量数据库持久化
  • 重排序模型集成
  • LLM prompt 优化(中文 + 防幻觉)
  • 检索质量评估(Recall@K > 80%)
  • 回答质量评估(人工抽检)
  • 流式输出(用户体验)
  • 缓存层(常见问题缓存回答)
  • 日志记录(问题 + 检索结果 + 回答)
  • 限流 + 鉴权
相关对比

Coze vs Dify:AI Agent 平台怎么选?零代码 vs 开源全控对比

Coze vs Dify 2026 选型对比:字节零代码 Bot 平台 vs 开源 LLMOps 全控平台,从平台定位、开发体验、工作流编排、RAG 精度、私有部署、价格模型和适合人群 7 个维度判断,帮你选对 AI Agent 平台。

Coze vs FastGPT:AI 知识库平台怎么选?Bot 工厂 vs RAG 专精对比

Coze vs FastGPT 2026 选型对比:字节零代码 Bot 平台 vs labring 开源 RAG 专精平台,从平台定位、开发体验、RAG 精度、工作流编排、模型生态、私有部署、价格模型和适合人群 8 个维度判断,帮你选对 AI 知识库平台。

FastGPT vs Dify:国内企业级 RAG 与 Agent 平台怎么选

FastGPT vs Dify 2026 选型对比:从数据合规、私有部署、RAG 精度、工作流复杂度、插件生态、Bot 多平台发布和适合人群判断,帮企业和团队决定是走 FastGPT 的知识库路线,还是 Dify 的 LLMOps 路线。

Dify vs Flowise:LLM 应用开发平台怎么选(2026)

Dify 与 Flowise 都是可视化 LLM 应用开发平台。一句话结论 + 决策树 + 成本对比:要开箱即用的完整产品与中文生态选 Dify,要节点级自由编排与自部署选 Flowise。

Dify vs Langflow:开源 LLMOps 平台怎么选?业务全控 vs LangChain 工程对比

Dify vs Langflow 2026 选型对比:Apache 2.0 LLMOps 全平台 vs MIT 可视化 LangChain 画布,从平台定位、开发体验、工作流编排、RAG 能力、模型生态、私有部署、价格模型和适合人群 8 个维度判断,帮你选对开源 LLMOps 平台。

Dify vs Manus:Agent 平台 vs 通用 Agent 怎么选?2026 对比

Dify vs Manus 2026 选型对比:开源 LLMOps Agent 平台 vs Butterfly Effect 通用 AI Agent。从定位、核心能力、可定制性、开源、价格和适用场景 6 个维度帮你选对 Agent 工具。

相关评测