AI大模型实战系列(五):LangChain 链路打通——构建 HR 智能问答系统与混合检索架构揭秘
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)高度抽象为以下五个标准化步骤:
- 加载(Document Loaders):连接各种数据源(PDF、Notion、数据库)。
- 转换(Text Splitters):将长文本切割为适应 Context Window 的块。
- 嵌入与存储(Embeddings & VectorStores):向量化并存入 Chroma。
- 检索(Retrievers):定义如何从数据库中捞取数据。
- 生成(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(重排模型)的接入与知识库的高阶评估策略!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)