AI大模型实战系列(五):LangChain 链路打通——构建 HR 智能问答系统与混合检索架构揭秘

在前面的章节中,我们已经成功锻造了 RAG 系统的各个核心“齿轮”:从文档的精准解析与分块,到利用本地大模型生成高维 Embeddings,再到构建 Chroma 向量数据库实现毫秒级召回。

然而,齿轮散落一地并不能让机器运转。本章,我们将引入目前大模型应用开发领域的“绝对霸主”——LangChain 框架,将这些孤立的组件无缝串联起来。我们将从零到一编写代码,落地本课程的第一个综合实战项目:公司 HR 制度智能问答系统

同时,我们将直面真实业务场景中的残酷真相,揭开纯向量检索的致命缺陷,并为你全面解析当前企业级 AI 架构的进阶标配:混合检索(Hybrid Retrieval)技术


一、 链路拼图:LangChain 与 Naive RAG 的标准工作流

在没有 LangChain 之前,开发者需要自己编写大量的胶水代码:手动调 API 获取向量、手写数据库查询语句、手动将检索结果拼接到长长的字符串中传给 LLM。这不仅极其繁琐,而且难以维护。

LangChain 的核心价值在于**“组件化”“链式编排(LCEL - LangChain Expression Language)”**。它将 RAG 的标准工作流(Naive RAG)高度抽象为以下五个标准化步骤:

  1. 加载(Document Loaders):连接各种数据源(PDF、Notion、数据库)。
  2. 转换(Text Splitters):将长文本切割为适应 Context Window 的块。
  3. 嵌入与存储(Embeddings & VectorStores):向量化并存入 Chroma。
  4. 检索(Retrievers):定义如何从数据库中捞取数据。
  5. 生成(Generation):将检索结果动态注入 Prompt 模板,交由 LLM 推理作答。

二、 实战演练 1:公司 HR 制度智能问答系统

针对企业内部极其繁琐的请假、报销、晋升等 HR 制度,我们现在利用 LangChain 快速拉起一个智能问答服务。

1. 核心架构代码梳理(行业最佳实践)

在真实的工程代码中,我们通常会使用 LangChain 的 create_retrieval_chain 来构建这条流水线。以下是提炼后的核心代码逻辑与架构思想:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain

# 1. 挂载已有的 Chroma 向量数据库作为 Retriever
# search_kwargs={"k": 3} 表示每次提问只召回最相关的 3 个文档块
retriever = vector_db.as_retriever(search_kwargs={"k": 3})

# 2. 初始化大语言模型 (此处以 Qwen 为例)
llm = ChatOpenAI(model="qwen-plus", temperature=0.1) 

# 3. 构建 RAG 专用系统提示词模板 (极其关键的工业级 Prompt)
system_prompt = (
    "你是一个专业的企业 HR 助手。"
    "请严格使用以下检索到的【参考资料】片段来回答用户的问题。"
    "如果参考资料中没有提供相关信息,或者你不知道答案,"
    "请直接回答“抱歉,根据目前的 HR 制度库,我无法回答该问题”,"
    "绝对禁止基于你的预训练知识进行编造或猜测。"
    "\n\n"
    "【参考资料】:\n"
    "{context}" # LangChain 会自动将召回的 3 个文档块填入这个占位符
)

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{input}"),
])

# 4. 组装“文档链”与“检索链”
question_answer_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)

# 5. 执行端到端问答
response = rag_chain.invoke({"input": "试用期员工可以申请年假吗?"})
print(response["answer"])

2. 核心参数剖析

  • Temperature = 0.1:在 RAG 场景中,LLM 的核心任务是“严谨的信息提取与总结”,而不是“创意写作”。因此,必须将温度值(随机性)调到极低,强制模型输出确定性极高的事实。
  • Prompt 注入防御:在 system_prompt 中,我们使用了强烈的约束词(“严格使用”、“绝对禁止编造”)。这是为了防止幻觉,确保输出的每一句话都能在 context 中找到出处。

三、 真实世界的暴击:纯向量检索的“阿喀琉斯之踵”

上面的 HR 系统在应对诸如“怎么请假”、“报销流程是什么”这类**“语义泛化”问题时表现极其优异。然而,当我们将同样的架构直接平移到医疗知识库**、电商商品库法律卷宗时,系统却遭遇了灾难性的“召回失效”。

致命缺陷:缺乏“精确匹配”能力

向量检索(Dense Retrieval)的本质是“语义压缩与模糊匹配”。它能理解“感冒”和“上呼吸道感染”是同一个意思。但是,如果用户搜索极其精确的特定实体,它就会彻底抓瞎:

  • 专有名词与编号:“我需要查询 A-X-998 号药品的副作用。” 向量模型在训练时很可能没见过这个罕见的编号,导致其切分出来的向量特征完全丢失。
  • 极端微小的词汇差异:用户搜索“甲亢”,文档库里有一篇关于“甲亢”,另一篇关于“甲减”。从全局语义上看,这两篇文章高度相似(都是讲甲状腺疾病、症状、用药),纯向量检索极容易把“甲减”的文章也召回上来。差之毫厘,在医疗场景下就是致命的误诊。

这就引出了企业级搜索架构的终极形态:不能只懂语义,还要懂关键字。


四、 破局之道:混合检索(Hybrid Retrieval)架构解析

为了弥补纯向量检索的缺陷,现代 RAG 系统引入了**混合检索(Hybrid Search)**机制。它将信息检索领域最经典的技术与最前沿的 AI 技术进行了完美融合。

1. 传统检索的坚守:关键字与全文检索(BM25)

在没有 AI 的时代,ElasticSearch 等引擎统治着搜索领域,它们底层的核心算法是 TF-IDF 和它的进阶版 BM25 算法

  • 关键字检索:用户输入关键字,系统直接在倒排索引中查找精确匹配的记录。速度极快,定位极准。
  • BM25 全文检索(Sparse Retrieval 稀疏检索):BM25 会对用户的查询进行分词,然后计算这些词在文档中出现的频率(TF)以及在整个语料库中的稀有程度(IDF)。
    • 优势:对于专有名词、特定编号、产品型号的精确匹配(Exact Match)能力无敌。只要文档里有这个词,它就一定能被揪出来。
    • 劣势:不理解语义。搜“土豆”,绝对搜不到“马铃薯”。

2. 双剑合璧:混合检索的工业级架构

混合检索就是同时跑两路检索器:

  • 第一路:基于 Embedding 的向量检索库(捕捉高级语义意图)。
  • 第二路:基于 BM25 的全文检索库(死抠精确的字眼与编号)。

3. 核心难点:多路召回与 RRF 融合重排

当两路检索各自返回了 5 个文档块后,我们怎么决定哪几个最终喂给大模型?
因为向量计算出来的是“空间余弦距离”(如 0.85),而 BM25 计算出来的是“词频权重得分”(如 25.6)。两者的分数维度完全不同,无法直接相加比大小。

业界标配的解决方案是 RRF(Reciprocal Rank Fusion,倒数排名融合)算法
RRF 根本不看具体的分数,而是看排名(Rank)。它的数学逻辑极其简单却极其有效:
如果一个文档在向量检索中排第 1,在 BM25 中排第 2,它的综合得分就会飙升。RRF 巧妙地将不同维度、不同量纲的检索结果在排名层面进行了公平的融合排序(Rerank)。


五、 实战演练 2:医疗知识混合检索实战底座

理解了底层架构后,在医疗这种需要极度严谨的垂直领域中,我们如何使用 LangChain 落地混合检索?

LangChain 官方提供了一个极其优雅的组件:EnsembleRetriever(集成检索器),它内置了我们刚才提到的权重融合算法。

核心架构演示:

from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import Chroma

# 假设我们有一批高度专业的医疗文档块 (chunks)
medical_chunks = [
    "甲氨蝶呤 (MTX) 主要用于治疗重症类风湿关节炎...",
    "帕拉米韦注射液 0.3g/100ml 适用于成人及重症流感...",
    "风湿性关节炎的常规物理治疗方案包含..."
]

# ---------------------------------------------------------
# 引擎 1:构建传统的 BM25 稀疏检索器 (死守精确匹配)
# ---------------------------------------------------------
bm25_retriever = BM25Retriever.from_texts(medical_chunks)
bm25_retriever.k = 2 # 设定召回前 2 个

# ---------------------------------------------------------
# 引擎 2:构建基于 Chroma 的向量稠密检索器 (负责语义泛化)
# ---------------------------------------------------------
# (此处省略 embedding 模型的初始化步骤)
vectorstore = Chroma.from_texts(medical_chunks, embedding_model)
chroma_retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

# ---------------------------------------------------------
# 终极融合:构建集成检索器 (Hybrid Retriever)
# ---------------------------------------------------------
# weights=[0.4, 0.6] 表示我们赋予 BM25 40% 的排名权重,向量 60% 的权重
hybrid_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, chroma_retriever],
    weights=[0.4, 0.6] 
)

# 执行混合搜索:针对包含专业缩写和宽泛语义的复杂问题
# "MTX" 会触发 BM25 的高分精确匹配
# "关节疼痛" 会触发向量模型的语义泛化匹配
results = hybrid_retriever.invoke("患有严重关节疼痛,MTX的用药注意事项是什么?")

# 最终召回的结果将是两路引擎 RRF 融合后的最优解

在这个医疗混合架构中,无论是医生输入了极其生僻的药物化学式代码,还是患者输入了口语化的“我浑身骨头疼怎么治”,系统都能依靠双引擎的互补机制,把最核心的诊疗规范精准无误地捞出并喂给大模型。


本章总结

从简单的单一 HR 文档向量问答,到引入传统搜索技术的医疗混合检索架构,我们看到了 RAG 在面对真实商业复杂性时的架构演进。

单纯的向量模型虽然时髦,但在工业界,“经典技术兜底,AI 技术拔高” 才是最稳妥的架构哲学。

然而,我们目前的系统仍然存在一个隐患:无论检索出来的片段质量多么参差不齐,大模型都会照单全收去生成答案。有没有办法在检索结果喂给 LLM 之前,再进行一次“大浪淘沙”的精准提纯?

下一章,我们将深入探讨 Advanced RAG(进阶检索增强) 的核心武器:Reranker(重排模型)的接入与知识库的高阶评估策略!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐