news 2026/6/10 7:08:14

LangChain 处理链设计:知识库链与通用对话链的编排

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangChain 处理链设计:知识库链与通用对话链的编排

前言

意图识别判断了"走哪条路",处理链决定了"怎么走"。本文介绍项目中两条 LangChain 处理链的设计——知识库检索链(RAG Chain)和通用对话链(General Chat Chain),以及如何用AsyncGenerator实现全链路流式输出。

为什么需要两条链?

企业知识库问答系统面临两类完全不同的问题:

类型示例处理方式
知识库查询"公司的请假流程是什么?"检索 + 生成
日常闲聊"你好"、"今天星期几"直接回答

如果不区分,闲聊也会走检索管线——浪费一次 RAGFlow API 调用,还可能检索出无关内容干扰回答。因此项目设计了双链架构,由意图识别决定走哪条。

架构总览

意图识别结果 / \ knowledge_base general_chat / \ 查询增强 + RAG检索 纯 LLM 对话 \ / 流式输出 (AsyncGenerator) | 最终回答

第一条链:知识库检索链

这是项目的核心链,实现了完整的 RAG 流程:

# Langchain_utils/chains.py ​ def create_knowledge_chain(system_prompt: str = "你是一个有用的助手"): async def process_with_knowledge(question: str, history: str): # 步骤 1:查询增强 enhanced_question = enhance_query(question, history) ​ # 步骤 2:RAGFlow 检索 rag_answer = RAGFlow_chat(enhanced_question) ​ # 步骤 3:构建增强 Prompt prompt = system_prompt + "\n\n" ​ if history: prompt += f"对话历史:\n{history}\n\n" ​ prompt += f"用户问题: {question}\n\n" prompt += f"知识库检索结果:\n{rag_answer}\n\n" prompt += "请基于上述知识库信息回答用户问题,如果知识库中没有相关信息,请说明。\n\n" prompt += f"用户问题: {question}" ​ # 步骤 4:LLM 流式生成 async for chunk in call_llm(question, prompt): yield chunk ​ return process_with_knowledge

点睛之笔:用户问题在 Prompt 中出现了两次——一次在开头提供上下文,一次在结尾驱动生成。这是经典的 Prompt 工程技巧。

第二条链:通用对话链

相比知识库链简洁得多,纯 LLM 对话:

def create_general_chain(system_prompt: str = "你是一个有用的助手"): async def process_general_chat(question: str, history: str): prompt = system_prompt + "\n\n" ​ if history: prompt += f"对话历史:\n{history}\n\n" ​ prompt += f"用户问题: {question}" ​ async for chunk in call_llm(question, prompt): yield chunk ​ return process_general_chat

没有检索步骤,上下文只有对话历史。适用于日常问候、常识问答、数学计算等。

共性:call_llm 流式调用

两条链最终都调用同一个流式 LLM 函数:

async def call_llm(question: str, prompt: str) -> AsyncGenerator[str, None]: # 从环境变量加载配置 api_key = os.getenv("") model = os.getenv("") base_url = os.getenv("") ​ # 创建流式 LLM llm = ChatOpenAI( model=model, base_url=base_url, api_key=api_key, streaming=True ) ​ chat_prompt = ChatPromptTemplate.from_messages([ ('system', prompt), ('human', question) ]) ​ chain = chat_prompt | llm ​ # astream 返回异步生成器,逐 token yield async for chunk in chain.astream({}): if hasattr(chunk, 'content') and chunk.content: yield chunk.content

chain.astream({})是 LCEL 的异步流式调用,返回AsyncGenerator,每个 chunk 是一个 token。外层逐层透传,直到 API 层的 SSE。

统一处理器:串起一切

有了两条链后,需要一个"总控"来串联:记忆加载 → 意图识别 → 链选择 → 流式输出 → 记忆保存:

# Langchain_utils/processor.py ​ def create_unified_processor(session_id: str): memory = create_memory(session_id=session_id) knowledge_chain = create_knowledge_chain(system_prompt) general_chain = create_general_chain(system_prompt) ​ async def processor(question: str): # 1. 加载对话历史 memory_vars = memory.load_memory_variables({}) chat_history = memory_vars.get("chat_history", []) formatted_history = format_chat_history(chat_history) ​ # 2. 意图识别 intent = detect_intent(question, formatted_history) ​ # 3. 发送元数据 metadata = {"intent": intent, "original_query": question} yield {"type": "metadata", "data": metadata} ​ # 4. 根据意图选择链 if intent == "knowledge_base": chain = knowledge_chain else: chain = general_chain ​ # 5. 流式输出 full_answer = "" async for chunk in chain(question, formatted_history): full_answer += chunk yield {"type": "content", "data": chunk} ​ # 6. 保存到记忆 memory.chat_memory.add_messages([ HumanMessage(content=question), AIMessage(content=full_answer) ]) ​ # 7. 结束标记 yield {"type": "end", "data": {"full_answer": full_answer, "metadata": metadata}} ​ # 附加实用方法 processor.get_stats = lambda: stats.copy() processor.clear_memory = lambda: memory.clear() ​ return processor

流式输出的统一格式是一个字典,包含三种类型:

type含义data
metadata流开始时的元信息意图、原始问题
content逐 token 内容文本片段
end流结束标记完整回答 + 最终元数据

为什么要 clear_memory?

clear_memory被挂载到 processor 函数上,供 API 层调用:

# output/main_service.py ​ def clear_session_memory(session_id: str): if session_id in _processors: processor = _processors[session_id] processor.clear_memory() # 调用附加函数

用户点击"新会话"时,前端会请求/api/memory/clear,清除 MongoDB 中的对话历史。新对话从干净的上下文开始。

小结

本文介绍了双链架构的设计思路:

  1. 知识库链:查询增强 → RAG 检索 → LLM 总结,完整的 RAG 管道

  2. 通用对话链:纯 LLM 对话,无检索开销

  3. 统一处理器:记忆 → 意图 → 链选择 → 流式输出 → 记忆保存

  4. AsyncGenerator 全链路:从 LLM token 到 SSE 事件,零缓冲流式传输

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 7:05:15

Agentic AI 解读:从认知跃升到企业落地实战指南

文章目录一、前言二、AI Agent vs Agentic AI:不是同一件事三、书籍结构:五大部分构建完整落地路径五部分个人分析第一部分第二部分第三部分第四部分第五部分四、实战价值:代码案例助力理解4.1 简单LangChain单Agent示例(AI Agent…

作者头像 李华
网站建设 2026/6/10 7:02:05

C++虚表

多态的基本概念 1.多态是指允许一个接口被多种类型的对象使用,通常通过继承和重写实现 2.在C中,多态的实现依赖于虚函数 多态的实现 1.父类提供数据成员和成员函数,子类继承并重写父类的函数 2.函数参数为父类指针,可以传递父类对…

作者头像 李华
网站建设 2026/6/10 6:59:02

Java异常处理总结

Java异常处理总结作者:没有四次元口袋的蓝胖 日期:2026-06-09 标签:Java, 异常处理一、异常体系架构 1.1 整体继承树 Throwable ├── Error(严重错误,程序不该捕获) │ ├── StackOverflowError │ …

作者头像 李华
网站建设 2026/6/10 6:57:29

调查研究-165 vLLM 深入浅出:从 PagedAttention 到生产级大模型推理服务

vLLM 深入浅出:从 PagedAttention 到生产级大模型推理服务TL;DR 如果你正在本地或服务器上部署大语言模型,迟早会遇到三个问题:显存不够、并发上不去、接口不好接。模型本身只是第一步,真正让模型稳定对外提供服务的是推理引擎。 …

作者头像 李华
网站建设 2026/6/10 6:49:59

最新 macOS 27 页面新变化,先睹为快!

一、状态栏变化状态栏可以手动/自动折叠隐藏,状态栏可以跨过刘海显示,不用再第三方软件去折叠显示了。二、新图标变化状态栏电池出现了新图标。Siri 变成单独应用,出现新图标。应用展现新图标,本人感觉对比度和磨砂质感更高了&…

作者头像 李华