上一篇通过天气查询示例,跑通了一个能够调用工具的 Agent,对“用户提问、模型选择工具、程序执行函数、模型生成回答”的过程有了初步认识。接下来,我想进一步弄清这些功能背后的组件分工:模型怎样接收消息,提示词如何组织输入,工具和检索器又在什么情况下参与执行。
本篇继续阅读 LangChain 中文网的概念指南,结合简短代码和流程图,梳理构建模块、核心组件及其输入输出关系,并对比固定链与 Agent 的执行方式,为后续学习多轮对话和知识库问答打下基础。
版本说明:中文站首页标注为 v0.3;本文梳理通用概念,示例已在上一篇的 1.x 环境验证,旧代码的导入路径需按当前版本核对。[中文站] [版本迁移]
目录
一、构建模块:先分清包与组件
二、核心组件:沿着数据流理解
三、LCEL:把组件接成可运行的流程
四、链与 Agent:预设步骤与动态选择
五、学习总结:把名称对应到实际数据
参考来源
一、构建模块:先分清包与组件
包是代码的组织和安装单位,组件是应用中的功能单元;一个应用通常会同时使用多个包中的组件。
| 包 | 主要职责 |
|---|---|
langchain-core | 提供消息、提示词、Runnable 等基础接口与组合机制。 |
langchain | 当前 1.x 主要提供 Agent 等核心应用能力。 |
langchain-community | 提供社区维护的第三方集成,按实际功能安装使用。 |
langchain-deepseek等 | 提供特定服务商的集成,例如用 ChatDeepSeek 访问 DeepSeek。 |
例如,上一篇用ChatDeepSeek连接模型,再用create_agent组织工具调用;这些对象分别承担模型接入和流程执行的职责。
二、核心组件:沿着数据流理解
1. 模型与消息:谁在说话,模型返回什么
Chat Models 以消息为核心,LLMs 抽象以字符串输入、输出为核心。这里区分的是调用接口;聊天模型也能接受字符串,框架会将其转换成用户消息。上一篇的ChatDeepSeek属于聊天模型,返回的是包含内容、工具调用信息等字段的消息对象。[模型]
常见消息角色有system(行为要求)、user(用户输入)、assistant(模型回复)和tool(工具结果);同一句话放在不同角色里,语境并不相同。多轮对话还需由程序保存、组织并传回历史,创建模型对象本身不等于永久记忆。[消息]
2. 提示词与输出处理:组织输入,整理结果
提示词模板把固定要求与变量分开,例如“请解释{topic}。”可以反复用于不同主题;示例选择器则用于按任务挑选参考样例,帮助模型理解希望得到的回答形式。
输出解析器处理模型返回值:StrOutputParser可提取文本,其他解析器可处理更具体的结构;需要固定字段时,也可使用模型支持的结构化输出能力。格式符合要求与内容正确需要分别检查。
3. 文档与检索:让回答用上外部资料
文档加载器将 PDF、网页等资料读成Document,其中通常有正文和来源元数据;文本分割器把长文切成片段,便于检索并控制传给模型的上下文长度。
在典型向量检索中,嵌入模型负责把文本编码成向量,向量存储负责保存和搜索,检索器负责根据问题返回相关文档。查询与文档向量需要处于兼容的向量空间。把相关片段连同问题提供给模型生成回答,就是一种常见的 RAG(检索增强生成)流程。[检索]
检索器也可以对接关键词搜索或数据库,并非只能使用向量库;RAG 补充的是运行时上下文,资料的正确性和检索结果仍需检查。
4. 工具与 Agent:从生成内容走向执行任务
工具通常包含名称、用途描述、输入参数结构和可执行函数;模型据此提出调用请求,再由程序执行并返回结果。工具包可以组织一组相关工具,Agent 则根据任务与已有结果决定下一步。[工具]
上一篇的get_weather(city)就是工具:模型给出城市参数,Python 执行函数,模型再读结果作答。键值存储可以保存应用数据,回调可以记录模型、工具的运行事件,帮助观察每一步发生了什么。
三、LCEL:把组件接成可运行的流程
LCEL 是 LangChain 表达式语言,常用|将前一步输出交给下一步。典型形式是prompt | model | parser,但各步的输入类型和内容必须匹配。
下面用固定回复的函数模拟模型,只演示数据流,不调用 API;可在上一篇的环境中运行:
from langchain_core.messages import AIMessage from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnableLambda prompt = ChatPromptTemplate.from_template("请解释{topic}。") mock_model = RunnableLambda( lambda _: AIMessage(content="Agent 会选择工具,并利用工具结果作答。") ) chain = prompt | mock_model | StrOutputParser() print(chain.invoke({"topic": "Agent"}))输出为Agent 会选择工具,并利用工具结果作答。其中模板产生提示值,模拟函数返回AIMessage,解析器提取字符串;更换主题不会改变这里写死的模拟回复,接入真实模型后才会进行生成。
这些可运行组件采用Runnable接口:invoke()处理一次输入,batch()处理一组输入,stream()返回输出块;持续的增量输出还取决于各组件是否支持流式处理。
四、链与 Agent:预设步骤与动态选择
固定链适合流程已知的任务,工具调用 Agent 适合需要模型选择动作的任务。例如,文本摘要可以固定为“提示词—模型—输出处理”;需要先查天气再决定如何回复时,则可以让 Agent 选择天气工具并读取结果。[Agent]
链也可以预设分支和并行步骤;Agent 的工具选择则由模型在执行过程中提出。设计应用时,流程清楚就先用简单组合,需要动态决策时再增加 Agent 能力。
五、学习总结:把名称对应到实际数据
这次学习后,我开始用“输入是什么、做了什么、输出交给谁”理解组件:模板把变量变成消息,模型生成回复或工具调用,解析器整理返回值,检索器补充资料,工具执行具体操作;这些职责对应着不同的数据流转。
再看上一篇的天气示例,我能分清“模型决定调用”“程序执行函数”“工具结果返回”和“模型组织回答”几个环节,也理解了为什么最终回答不能完全代替运行记录:回答可能补充工具没有提供的信息,需要回到输入和工具结果核对依据。
接下来的练习准备分两步:先把模拟函数换成已配置的ChatDeepSeek,观察真实消息和解析结果;再读取一小份本地文档,尝试切分、检索与问答。每次只增加一种能力,记录中间结果,更容易定位问题。
参考来源
[1] LangChain 中文网:概念指南(构建模块与组件)
[2] LangChain 官方文档:v1 迁移指南
[3] LangChain 官方文档:1.x 概览及相关组件说明