RAG 中级 20分钟

企业文档智能问答系统

基于 LangChain + Chroma 构建的企业级文档问答系统,支持PDF/Word/网页等多格式文档,实现精准的语义检索和智能问答。

LangChainChromaOpenAIFastAPIReact

项目概述

企业在日常运营中积累了大量的文档资源,包括产品手册、技术规范、FAQ、合同模板等。如何让员工快速、准确地从海量文档中找到所需信息,是一个普遍痛点。

本案例展示了一个基于 RAG(Retrieval-Augmented Generation)架构的企业文档智能问答系统。系统支持 PDF、Word、网页等多种文档格式的自动解析和索引,用户可以通过自然语言提问,系统从知识库中检索最相关的内容并生成精准回答,同时标注信息来源。

关键指标

92%
检索准确率
< 1.5s
平均响应时间
10万+ 文档块
知识库规模
98%
引用准确率

系统架构

系统采用经典的 RAG 四层架构:文档处理层 → 向量索引层 → 检索层 → 生成层。

┌─────────────┐    ┌──────────────┐    ┌────────────┐    ┌──────────────┐
│  文档处理层   │    │  向量索引层    │    │   检索层    │    │   生成层      │
│             │    │              │    │            │    │              │
│ PDF解析      │───▶│ 文本分块       │───▶│ 语义检索     │───▶│ LLM 回答生成  │
│ Word解析     │    │ Embedding     │    │ 混合检索     │    │ 上下文注入    │
│ 网页爬取     │    │ Chroma 存储    │    │ 重排序       │    │ 引用标注      │
│ 自动清洗      │    │ 增量更新       │    │ 过滤         │    │ 格式输出      │
└─────────────┘    └──────────────┘    └────────────┘    └──────────────┘

实现细节

1

文档处理管道

多格式解析

使用 Unstructured 库支持 PDF、Word、Excel、Markdown 等多种格式的文档解析,保留文档结构(标题、段落、表格、列表)。

智能分块

基于文档结构进行语义分块(Semantic Chunking),而非简单的固定长度截断。保持段落、章节的完整性,确保每个块有独立的语义。

数据清洗

自动去除页眉页脚、水印、无关元数据,识别并修复乱码、表格形变等常见文档问题。

2

向量索引

Embedding 策略

采用 OpenAI text-embedding-3-small 模型(1536维),兼顾准确率和成本。对中文文档使用专门优化,处理中日韩文本的一致性问题。

Chroma 部署

作为嵌入式向量数据库,Chroma 直接集成在 FastAPI 应用中运行,零外部依赖。支持 HNSW 索引实现毫秒级检索。

增量更新

支持文档的增量添加和更新,每次更新只重新索引变化的文档块,避免全量重建的代价。

3

检索与生成

混合检索

结合语义检索(向量相似度)和关键词检索(BM25),在召回率和精确率之间取得平衡。支持自定义权重配置。

重排序

对初步检索结果使用 Cross-Encoder 重排序模型,将最相关的结果排到前面,提升 Top-K 准确率约 15-20%。

回答生成

LangChain 将检索到的文档块作为上下文注入 prompt,LLM 基于此生成回答。自动标注引用来源,支持多轮对话。

核心 RAG 实现

from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import UnstructuredPDFLoader
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker

# 1. 文档加载与分块
loader = UnstructuredPDFLoader("manual.pdf")
documents = loader.load()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    separators=["\n\n", "\n", "。", "!", "?", " ", ""]
)
chunks = text_splitter.split_documents(documents)

# 2. 构建向量索引
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(chunks, embeddings)

# 3. 混合检索 + 重排序
retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
reranker = CrossEncoderReranker(
    model_name="BAAI/bge-reranker-v2-m3",
    top_n=5
)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker,
    base_retriever=retriever
)

# 4. 问答
llm = ChatOpenAI(model="gpt-4o", temperature=0.1)
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=compression_retriever,
    return_source_documents=True
)

result = qa_chain.invoke({"query": "产品的退货政策是什么?"})
print(f"回答: {result['result']}")
print(f"来源: {[d.metadata['source'] for d in result['source_documents']]}")
        

经验教训

  • 文档质量直接影响检索效果 — OCR识别不准确或格式混乱的文档会导致嵌入向量质量下降,建议在预处理阶段投入更多精力
  • 分块策略需要针对文档类型调整 — 技术文档适合按章节分块,FAQ适合按问答对分块,混合文档需要分层分块策略
  • 重排序是性价比最高的优化 — 从10个候选中重排序取Top-5,效果提升显著且计算成本低
  • 上下文注入需要平衡 — 注入太多文档块会稀释注意力,建议控制在3-5个,且根据问题类型动态调整
  • 生产环境需要兜底策略 — 当检索结果置信度低时,应该友好地告知用户"未找到相关信息"而非勉强作答

更多案例

查看其他 AI 工程化落地案例

返回案例库