banner
约 9,600 字
32 分钟

LangChain 多任务应用开发:从 Chain 到 Agent 的工程实践

摘要

本文以 LangChain 1.0 为基准梳理多任务 LLM 应用的开发主线:先说明组件化架构与 LCEL 链式表达式的设计,再通过基础 Chain、Agent 加搜索工具、带记忆对话、本地知识智能客服四个基础案例,以及工具链组合、故障诊断 Agent、LCEL 任务链三个进阶 CASE,给出可复用的实现模式和选型边界,最后对比 LangChain、LangGraph、Qwen-Agent、Coze、Dify 等 AI Agent 工具的定位。

LangChain 多任务应用开发:从 Chain 到 Agent 的工程实践

写在前面

大模型应用开发已经从单次问答走向多任务编排:一个业务往往需要多次模型调用,穿插搜索、计算、数据转换和对话记忆。LangChain 的价值在于把这类开发拆成可组合的组件,用 Chain 编排固定流程,用 Agent 实现自主决策。本文以 LangChain 1.0.2 的代码为准,沿着组件化架构、LCEL 链式表达式、Agent 与 ReAct、Memory 记忆这条主线展开,再用四个基础案例和三个进阶 CASE 说明每一步怎么落地。

全文主线:先解释 LangChain 的组件体系与 1.0 版本的结构变化;再给出基础 Chain、Agent 加搜索工具、多工具组合、带记忆对话的实现;随后深入两个代表性案例,即工具链组合(Agent 版与 LCEL 版对比)和网络故障诊断 Agent;最后对比 LangChain、LangGraph、Qwen-Agent、Coze、Dify 的定位。核心结论是:固定、可预期的流程用 LCEL 手动编排,需要根据问题自主选择工具的复杂任务用 Agent,工具的描述文本直接决定 Agent 的调用质量。

项目概览

项目

内容

框架版本

langchain==1.0.2langchain-core==1.0.1langchain-community==0.4dashscope==1.22.1

模型

通义千问 qwen-turboTongyi / ChatTongyi),部分脚本使用 deepseek-v3

工具

serpapi 搜索、自定义 calculator、文本分析、数据转换、文本处理、网络诊断(模拟实现)

核心机制

LCEL、create_agent@tool、ReAct 循环、RunnableWithMessageHistory

基础案例

基础 Chain、Agent 加搜索工具、多工具组合、带记忆对话、本地知识智能客服

进阶 CASE

工具链组合(Agent 版与 LCEL 版)、网络故障诊断 Agent、LCEL 多任务链

关键结果

全部场景有可运行代码与输出示例;工具链完成情感分析、行数统计、CSV 转 JSON;故障诊断输出完整推理链路

结果边界

网络诊断工具为模拟输出,未执行真实命令;外部能力依赖 API Key 与网络

背景、目标与约束

组件化是 LangChain 的基本答案

LangChain 提供一套工具、组件和接口,目标是简化创建大语言模型应用的过程。官方把组件分为六类:Models 负责模型接入;Prompts 负责提示管理、优化与序列化;Memory 保存与模型交互的上下文;Indexes 负责文档加载、转换、切割、向量化和索引查询,是构建知识库的基础;Chains 把一系列组件调用串联起来;Agents 决定模型采取哪些行动、执行并观察流程,直到任务完成。

这套划分解决了一个实际问题:一个完整的业务应用通常同时涉及模型、提示、文档、记忆和工具,如果每个应用都从零拼接,代码会迅速失控。组件化让每个能力可以独立替换和测试。

LangChain 1.0 的结构变化

LangChain 从 0.3 到 1.0 发生了结构性变化,概念本身没有变。包结构完全重构:langchain-core 只放抽象基类与 LCEL(LangChain Expression Language,LangChain 表达式语言),所有第三方集成不再直接依赖完整 langchainlangchain-community 存放社区维护的 loader、retriever、tool 等实现;合作伙伴包独立成库,例如 langchain-openailangchain-anthropic,体积更小、升级更灵活。

同时新增三个官方子项目:LangGraph 用图编排多步、多角色、有状态的工作流;LangServe 把链或代理一键封装成 REST(Representational State Transfer,表现层状态转移)API,自带 /invoke/stream/batch 端点;LangSmith 提供可视化调试、回归测试和在线监控,与回调系统深度打通。

API 风格全面转向 LCEL:鼓励用 | 运算符把组件拼成 Runnable,而不是继承 Chain 基类。例如 chain = prompt | llm,数据依次流经各组件,invoke() 是执行链的标准方法。

整体架构

LangChain 多任务应用开发整体架构(图由AI辅助绘制)
LangChain 多任务应用开发整体架构(图由AI辅助绘制)

图 1 是本文的整体架构图:用户任务先经过 Prompt Template 与消息占位符格式化为模型输入,交给 LLM 或 ChatModel;之后进入两种编排方式,Chain 或 LCEL 处理固定流程,Agent 通过 ReAct 循环自主调用工具;Memory 为多轮对话提供历史上下文;最终输出回答、JSON 或诊断结论,并用 LangSmith 做调试与监控。这张图对应全文主线,即应用开发的核心是选择编排方式并管理工具与状态。

LangChain 组件架构
LangChain 组件架构

图 2 是组件层面的架构示意,展示 LLM、ChatModel、Prompt、Chain、Agent、Tools、Memory 之间的关系。它与图 1 的区别在于视角:图 2 回答系统由哪些组件构成,图 1 回答一个任务如何流经这些组件。

技术选型

模型封装:LLM 与 ChatModel

LangChain 把模型分成两类:LLM 用于文本补全,输入字符串、输出字符串;ChatModel 用于对话,支持消息列表输入,并且具备 tool calling(工具调用)能力。项目代码中 Tongyi 是前者,ChatTongyi 是后者。

这个区别直接决定 Agent 的写法:Agent 需要模型在生成内容的同时输出工具调用意图,因此必须使用 ChatModel。基础 Chain 只需要文本补全,用 Tongyi 即可。

工具体系:预置与自定义

LangChain 集成了大量预置工具,包括 SerpAPI、Wikipedia、Bing Search、Google Serper、Wolfram Alpha、Python REPL、Requests、ArXiv API、文件系统工具等。load_tools(["serpapi"]) 可以一次加载多个工具。SerpAPI 支持 Google、Baidu、Yahoo、Ebay、YouTube 等搜索查询,需要单独安装 google-search-results 并配置 API Key。

预置工具之外,@tool 装饰器可以把任意 Python 函数转成 LangChain 工具。函数定义下方的 docstring 非常重要,Agent 通过它判断何时使用该工具,相当于工具的使用说明书。项目代码中自定义的 calculator 就是一个典型例子:函数体用正则白名单校验表达式,只允许数字和运算符,避免任意代码注入。

记忆方式

Chain 和 Agent 默认是无状态的,要让模型记住之前的交互必须引入 Memory。LangChain 提供四种短期记忆方式:

记忆方式

机制

适用场景

BufferMemory

将之前对话完整存储并传给 LLM

上下文较短、需要完整信息

BufferWindowMemory

只存储最近 K 组对话

控制 token 长度、长会话

ConversionMemory

对历史对话做摘要后传入

需要压缩历史、保留要点

VectorStore-backed Memory

对话存入向量数据库,按相似度匹配最近 K 组

长历史、按相关性检索

LangChain 短期记忆方式示意
LangChain 短期记忆方式示意

图 3 是四种短期记忆方式的示意。选择记忆方式本质是在信息完整度与上下文长度之间取舍:全量存储信息最完整但 token 开销最大,窗口和摘要以丢失细节为代价控制长度,向量检索则把取舍交给相似度匹配。

核心实现

基础 Chain:Prompt + LLM

最基础的用法是把 Prompt 模板和 LLM 组合成可执行链,代码来自 1-LLMChain.py

Python
from langchain_core.prompts import PromptTemplate
from langchain_community.llms import Tongyi

llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key)

prompt = PromptTemplate(
    input_variables=["product"],
    template="What is a good name for a company that makes {product}?",
)

chain = prompt | llm
result = chain.invoke({"product": "colorful socks"})

三个要点:prompt | llm 是 LangChain 1.x 推荐的 LCEL 组合方式;invoke() 是执行链的标准方法;输入必须是字典,key 对应模板中的 input_variables。这里已经能看到多任务开发的雏形,即每个业务任务都可以拆成模板加模型的独立链,再按需组合。

Agent 加搜索工具

当任务需要实时信息时,Chain 无法完成,因为模型自身不掌握当天日期和事件。2-LLMChain.py 演示了 Agent 加搜索工具的完整流程:

Python
from langchain_community.chat_models import ChatTongyi
from langchain_community.agent_toolkits.load_tools import load_tools
from langchain.agents import create_agent

llm = ChatTongyi(model_name="qwen-turbo", dashscope_api_key=api_key)
tools = load_tools(["serpapi"])
agent = create_agent(llm, tools)

result = agent.invoke({
    "messages": [("user", "今天是几月几号?历史上的今天有哪些名人出生")]
})
print(result["messages"][-1].content)

运行结果示例:今天是 12 月 9 日,历史上的今天有法国浪漫乐派作曲家柏辽兹(Hector Louis Berlioz)等名人出生。这个案例说明 Agent 的输入格式是 messages 列表,输出也在 messages 中取最后一条;模型先判断需要搜索,再调用 SerpAPI,最后把搜索结果组织成回答。

多工具组合:搜索加计算

3-LLMChain.py 把预置工具和自定义工具组合,任务是从当前北京温度推导华氏度并计算四分之一。预置的 llm-math 在 1.x 中已被替代,代码用 @tool 自定义了 calculator

Python
from langchain_core.tools import tool

@tool
def calculator(expression: str) -> str:
    """计算数学表达式。只接受数字和运算符,例如: 2+2, 100/4, 32*1.8+32。"""
    import re
    if not re.match(r'^[\d\s\+\-\*\/\.\(\)]+

这里的工程要点有两个:工具列表可以直接相加组合;`@tool` 的 docstring 是 Agent 判断调用时机的依据,因此描述必须写清楚输入格式和示例。自定义计算器还用正则白名单限制输入字符,避免把任意表达式交给 `eval`

### 带记忆的对话链

`4-ConversationChain.py` 演示了多轮对话的实现,核心是三个组件配合:

```python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    MessagesPlaceholder(variable_name="history"),  # 历史消息占位符
    ("human", "{input}")
])

store = {}
def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

conversation = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="history"
)

config = {"configurable": {"session_id": "default"}}
output = conversation.invoke({"input": "Hi there!"}, config=config)

MessagesPlaceholder 在 Prompt 中插入历史消息占位符;RunnableWithMessageHistory 自动管理消息历史;session_id 用于区分不同用户或会话。第二轮对话时,模型已经能记住第一轮的上下文。注意会话历史存储在一个进程内字典中,服务重启后即丢失,生产环境需要替换为持久化存储。

ReAct 范式与本地知识智能客服

ReAct(Reasoning and Acting,推理与行动)来自论文《ReAct: Synergizing Reasoning and Acting in Language Models》(2022),核心思想是把推理和动作结合:模型在步骤之间先思考,再行动,再观察结果,从而克服大模型胡言乱语的问题,同时提高结果的可解释性和可信度。

ReAct 范式示意
ReAct 范式示意

图 4 是 ReAct 范式的示意。典型的 Agent 逻辑是:由 LLM 选择工具;执行工具后把输出返回给 LLM;不断重复,直到 LLM 认为自己找到答案。这个过程对应模板中的四个关键字段:Thought(思考)、Action(行动)、Action Input(行动输入)、Observation(观察),可以重复 N 次,最后以 Final Answer 结束。

5-product_llm.py 把 ReAct 落地为一个本地知识智能客服,工具不是外部搜索,而是自有数据:

Python
@tool
def find_product_description(product_name: str) -> str:
    """通过产品名称找到产品描述。输入产品名称如 Model 3, Model Y, Model X"""
    product_info = {
        "Model 3": "具有简洁、动感的外观设计,流线型车身和现代化前脸。定价23.19-33.19万",
        "Model Y": "在外观上与Model 3相似,但采用了更高的车身和更大的后备箱空间。定价26.39-36.39万",
        "Model X": "拥有独特的翅子门设计和更加大胆的外观风格。定价89.89-105.89万",
    }
    return product_info.get(product_name, "没有找到这个产品")

@tool
def find_company_info(query: str) -> str:
    """当用户询问公司相关的问题时使用。输入用户的问题"""
    context = "特斯拉最知名的产品是电动汽车,其中包括Model S、Model 3、Model X和Model Y等多款车型。..."
    prompt = CONTEXT_QA_PROMPT.format(query=query, context=context)
    response = llm.invoke(prompt)
    return response.content

tools = [find_product_description, find_company_info]
agent = create_agent(llm, tools)

程序主体是 while True 循环,用户输入问题后交给 Agent,回答逐字动态打印。这个案例的关键在于把知识封装进工具:产品信息是本地字典,公司信息先组装成问答模板再调用模型生成,Agent 根据问题描述决定用哪个工具,而不是把所有知识塞进系统提示词。

代表性案例

CASE 1:工具链组合(Agent 版)

工具链组合的目标是让 Agent 通过多个工具逐步处理复杂问题。1-simple_toolchain.py 定义了五个自定义工具:文本分析、数据转换、统计行数、查找文本、替换文本,并用 create_agent 组合。

以任务一为例:分析文本情感并统计行数。Agent 的执行轨迹展示了 ReAct 的完整推理过程:

纯文本
思考: 我需要先分析文本的情感倾向,然后统计其中的行数。
行动: 文本分析
行动输入: '这个产品非常好用,我很喜欢它的设计,使用体验非常棒!...'
观察: {'word_count': 34, 'char_count': 102, 'sentiment': 'positive'}
思考: 我已经得到了情感倾向,现在需要统计行数。
行动: 文本处理
行动输入: operation='count_lines', content='...'
观察: {'line_count': 3}
思考: 我现在已经有了最终答案
回答: 这段文本的情感倾向是积极的(positive),并且它共有3行。

任务二是数据格式转换,输入 CSV 数据,工具返回 JSON 数组,最终回答中直接呈现转换结果:

JSON
[
  {"name": "张三", "age": "25", "comment": "这个产品很好"},
  {"name": "李四", "age": "30", "comment": "服务态度差"},
  {"name": "王五", "age": "28", "comment": "性价比高"}
]

整体工作流程是:用户提交任务描述,Agent 分析任务并决定使用哪些工具,通过 ReAct 框架调用相应工具,系统整合各工具结果生成最终回答。

CASE 2:工具链组合(LCEL 版)

2-simple_toolchain.py 用 LCEL 重写同一套工具链。工具函数被包装成 RunnableLambda,放入工具字典,再提供单工具调用、链式组合、并行执行三种编排方式:

Python
from langchain_core.runnables import RunnableLambda, RunnableMap, RunnablePassthrough

text_analysis_chain = RunnableLambda(lambda x: text_analysis.run(x["text"]))

def lcel_task_chain(task_type, params):
    if task_type not in tools:
        return "不支持的工具类型"
    return tools[task_type].invoke(params)

# 链式组合:先文本分析,再统计行数
chain = (
    RunnablePassthrough.assign(
        analysis=lambda x: text_analysis_chain.invoke({"text": x["text"]})
    )
    | RunnableLambda(lambda x: {
        "analysis": x["analysis"],
        "line_count": count_lines_chain.invoke({"content": x["text"]})
    })
)

# 并行执行:同时运行多个工具
parallel_chain = RunnableMap({
    "analysis": text_analysis_chain,
    "line_count": count_lines_chain,
})

两版实现的区别是理解 LangChain 编排方式的关键:

对比维度

Agent 版(1-simple_toolchain)

LCEL 版(2-simple_toolchain)

决策主体

Agent 自动解析任务、选择工具

开发者显式指定每一步

推理能力

支持 ReAct 多轮推理与工具调用

无自主决策,流程完全可控

组合方式

工具列表交给 create_agent

RunnableLambdaRunnableMapRunnablePassthrough

适合场景

智能决策加多工具自动调度

自定义流程、明确步骤、可控组合

CASE 3:网络故障诊断 Agent

网络故障诊断的难点在于工具之间存在串联关系:第一个工具的输出往往是第二个工具的输入,例如先 DNS 解析得到 IP,再对 IP 做连通性检查。2-network_diagnosis_agent.py 用四个模拟工具覆盖一条诊断链路:

工具

输入

输出

使用场景

PingTool

目标主机名或 IP

连通性状态与延迟

验证网络连接是否通畅

DNSTool

主机名

解析后的 IP 或失败信息

诊断 DNS 解析问题

InterfaceCheckTool

可选接口名称

接口状态、IP、子网掩码

检查本地网络配置

LogAnalysisTool

关键词、可选时间范围

匹配的日志条目

查找历史网络错误

示例问题的诊断链路:无法访问 www.example.com,先 DNS 解析得到 IP 93.184.216.34,再检查连通性返回连接超时,随后检查本地接口状态正常,最后分析日志发现多条 timeout 记录,诊断结论指向网络路由问题或目标服务器不可用。

这类 Agent 依赖 Zero-Shot ReAct:大模型在没有额外示例的情况下,直接根据工具名称和描述推理如何调用。LangChain 会自动把工具列表拼接进系统提示词,每个工具的 name 和 description 决定模型能否正确选择工具,因此工具描述必须写清楚输入格式和适用条件。

实际运行轨迹示例:模型先调用连通性检查,得到 Ping 成功延迟 59ms;再调用 DNS 解析,得到 IP 正常;然后调用日志分析,发现三条超时记录;最终结论是网络连通性和 DNS 均正常,浏览器无法访问的原因可能来自防火墙规则、代理设置或浏览器配置。整个过程展示了 Agent 如何根据观察结果不断调整下一步行动。

CASE 4:LCEL 多任务链

3-lcel-demo.py 演示了 LCEL 最典型的串行多任务链:翻译到英文、分析文本、回译中文,并用 stream() 边生成边输出:

Python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key, stream=True)

translate_to_en = ChatPromptTemplate.from_template("Translate this to English: {input}") | llm | StrOutputParser()
process_text = ChatPromptTemplate.from_template("Analyze this text: {text}") | llm | StrOutputParser()
translate_to_cn = ChatPromptTemplate.from_template("Translate this to Chinese: {output}") | llm | StrOutputParser()

workflow = {"text": translate_to_en} | process_text | translate_to_cn

for chunk in workflow.stream({"input": "北京有哪些好吃的地方,简略回答不超过200字"}):
    print(chunk, end="", flush=True)

{"text": translate_to_en} 是字典形式的分支,表示把第一段输出以 text 键传入下一段;StrOutputParser 把模型输出转成字符串,方便后续组件消费。LCEL 支持串联、分支、并行和流式,适合多步骤任务的灵活组合。

结果与评估

各案例的输入输出汇总:

案例

输入

输出

基础 Chain

{"product": "colorful socks"}

公司命名建议

Agent 加搜索

今天日期与历史名人问题

结合 SerpAPI 结果的回答

多工具组合

北京温度华氏度与四分之一

搜索加计算后的数值结果

带记忆对话

多轮问候

能引用上一轮上下文的回复

本地知识客服

产品与公司问题

基于本地字典与上下文模板的回答

工具链组合任务一

情感分析加行数统计

情感 positive、共 3 行

工具链组合任务二

CSV 数据

合法 JSON 数组

故障诊断

无法访问网站

完整诊断链路与结论

LCEL 多任务链

中文美食问题

翻译、分析、回译的流式结果

评估边界需要明确三点。第一,网络诊断工具是模拟实现,Ping、DNS、接口和日志分析都返回预设结果,没有执行真实命令,用于验证 Agent 的推理与串联逻辑,真实场景需要替换为实际工具。第二,所有 Agent 场景依赖通义千问 API 与 SerpAPI,需要配置 DASHSCOPE_API_KEY 和网络环境,脚本中也明确提示生产环境不要硬编码密钥。第三,版本边界以 LangChain 1.0.2 为准,旧文档中的 ZERO_SHOT_REACT_DESCRIPTIONAgentExecutor 等属于 0.3 写法,1.x 统一用 create_agent

AI Agent 工具对比

多任务应用开发还需要在框架层面做选型。材料给出的工具定位对比:

工具

核心定位

架构特点

适用场景

LangChain

开源 LLM 应用开发框架

基于链的线性或分支工作流,支持 Agent 模式

快速构建 RAG、对话系统、工具调用等线性任务

LangGraph

LangChain 扩展,专注复杂工作流

基于图的循环和条件逻辑,支持多 Agent 协作

循环、动态分支、状态管理复杂任务

Qwen-Agent

通义千问的 AI Agent 框架

基于阿里云大模型,支持多模态与工具调用

开源、集成多种工具、MCP 调用

Coze

字节跳动的无代码 AI Bot 平台

可视化拖拽界面,内置知识库与多模态插件

社交平台机器人、轻量级工作流

Dify

开源 LLM 应用开发平台

API 优先,支持 Prompt 工程与灵活编排

深度集成或私有化部署

四个维度的对比结论:工作流编排上,LangChain 适合固定流程,LangGraph 支持循环和条件边,Coze 可视化但灵活性较低,Dify 基于自然语言定义工作流;工具调用与扩展性上,LangChain 与 LangGraph 把工具作为链或图的节点,支持自定义与重试,Coze 依赖预置插件生态,Dify 支持 OpenAPI 集成;RAG 能力上,LangChain 开箱即用,LangGraph 需手动设计节点但支持反馈循环,Dify 提供基础 RAG,Coze 依赖知识库管理;多模态与部署上,Coze 支持图像视频生成并可发布到社交平台,Qwen-Agent 开源且支持 MCP(Model Context Protocol,模型上下文协议)调用,Dify 专注私有化部署。

选择建议:无代码开发用 Coze;快速原型用 LangChain 或 Qwen-Agent;复杂 Agent 系统用 LangGraph 或 Dify;企业私有化用 Dify、Qwen-Agent 或 LangChain 加 LangGraph 组合。

Coze 工作流中的节点与数据流关系
Coze 工作流中的节点与数据流关系

图 5 以 Coze 工作流为例展示节点间的关系:数据流表示上游节点的输出变量作为下游输入参数;控制流表示条件分支决定后续执行路径;HTTP 请求节点可以与其他节点并行执行;全局变量跨节点共享状态。这套关系同样适用于理解 LangGraph 等基于图的工作流。Coze 适合标准化诊断流程、多工具串联、条件分支决策和团队知识沉淀,局限在于无法直接 SSH 登录设备、复杂协议分析依赖外部系统、超过 50 节点的大规模拓扑需要拆分子工作流。

问题、限制与改进

第一,模拟工具与真实工具存在差距。故障诊断案例中的 Ping、DNS、日志工具都是返回预设结果的模拟实现,Agent 的推理链路可以被验证,但输出不能代表真实网络状态,生产落地需要把工具替换为真实命令或系统接口。

第二,外部依赖是运行前提。搜索和模型能力依赖 SerpAPI 与通义千问 API,网络不通或 Key 缺失时案例无法复现;材料中的代码已提醒不要在代码中硬编码密钥。

第三,Agent 的自主决策带来不确定性。同一问题在不同轮次可能选择不同工具组合,需要可预期流程时应改用 LCEL 手动编排;版本差异也需要注意,0.3 的 AgentExecutorZERO_SHOT_REACT_DESCRIPTION 写法在 1.x 中已由 create_agent 取代。

第四,安全与状态管理需要工程化。自定义计算器虽然用正则白名单限制输入,但生产环境仍应避免直接使用 eval,改用表达式解析库;对话历史存储在进程内字典,重启即丢失,多实例部署需要持久化会话存储。

工程启发

组件化是 LangChain 最有价值的工程思想:模型、提示、记忆、工具、链各自独立,替换任何一环都不影响其他部分。开发时先画任务的数据流,再决定每一段用 Chain、LCEL 还是 Agent。

工具的 docstring 就是工具的契约。Agent 能否在正确时机调用正确工具,直接取决于工具描述是否写清楚输入格式、示例和适用条件;自定义工具时应当把描述当作接口文档来写。

编排方式的选择原则可以概括为:流程固定、步骤明确时用 LCEL,代码可读、可调试、可测试;任务开放、需要根据内容自主选择工具时用 Agent,但要接受其决策的不确定性,并为关键路径设置约束或人工确认。

记忆策略的选择要结合上下文长度:信息必须完整时用全量存储,会话很长时用窗口或摘要,历史规模大且相关性重要时用向量检索。监控方面,LangSmith 把调试、回归测试与在线监控打通,多任务应用上线前应建立覆盖关键工具调用的回归用例。

小结

LangChain 多任务应用开发的核心是两套编排语义:LCEL 用数据流表达确定性的任务链,Agent 用 ReAct 循环表达不确定性的自主决策。基础案例说明组件如何组合,工具链案例说明多工具如何被调度,故障诊断案例说明串联型工具链如何完成复杂任务,框架对比则给出选型边界。对工程实践最有用的结论是:先定义任务的数据流,再选择编排方式,最后用工具描述和记忆策略控制 Agent 的行为质量。

参考资料

serpapi_tools = load_tools(["serpapi"]) tools = serpapi_tools + [calculator] agent = create_agent(llm, tools)

纯文本
这里的工程要点有两个:工具列表可以直接相加组合;`@tool` 的 docstring 是 Agent 判断调用时机的依据,因此描述必须写清楚输入格式和示例。自定义计算器还用正则白名单限制输入字符,避免把任意表达式交给 `eval`。

### 带记忆的对话链

`4-ConversationChain.py` 演示了多轮对话的实现,核心是三个组件配合:

```python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    MessagesPlaceholder(variable_name="history"),  # 历史消息占位符
    ("human", "{input}")
])

store = {}
def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

conversation = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="history"
)

config = {"configurable": {"session_id": "default"}}
output = conversation.invoke({"input": "Hi there!"}, config=config)

MessagesPlaceholder 在 Prompt 中插入历史消息占位符;RunnableWithMessageHistory 自动管理消息历史;session_id 用于区分不同用户或会话。第二轮对话时,模型已经能记住第一轮的上下文。注意会话历史存储在一个进程内字典中,服务重启后即丢失,生产环境需要替换为持久化存储。

ReAct 范式与本地知识智能客服

ReAct(Reasoning and Acting,推理与行动)来自论文《ReAct: Synergizing Reasoning and Acting in Language Models》(2022),核心思想是把推理和动作结合:模型在步骤之间先思考,再行动,再观察结果,从而克服大模型胡言乱语的问题,同时提高结果的可解释性和可信度。

ReAct 范式示意
ReAct 范式示意

图 4 是 ReAct 范式的示意。典型的 Agent 逻辑是:由 LLM 选择工具;执行工具后把输出返回给 LLM;不断重复,直到 LLM 认为自己找到答案。这个过程对应模板中的四个关键字段:Thought(思考)、Action(行动)、Action Input(行动输入)、Observation(观察),可以重复 N 次,最后以 Final Answer 结束。

5-product_llm.py 把 ReAct 落地为一个本地知识智能客服,工具不是外部搜索,而是自有数据:

Python
@tool
def find_product_description(product_name: str) -> str:
    """通过产品名称找到产品描述。输入产品名称如 Model 3, Model Y, Model X"""
    product_info = {
        "Model 3": "具有简洁、动感的外观设计,流线型车身和现代化前脸。定价23.19-33.19万",
        "Model Y": "在外观上与Model 3相似,但采用了更高的车身和更大的后备箱空间。定价26.39-36.39万",
        "Model X": "拥有独特的翅子门设计和更加大胆的外观风格。定价89.89-105.89万",
    }
    return product_info.get(product_name, "没有找到这个产品")

@tool
def find_company_info(query: str) -> str:
    """当用户询问公司相关的问题时使用。输入用户的问题"""
    context = "特斯拉最知名的产品是电动汽车,其中包括Model S、Model 3、Model X和Model Y等多款车型。..."
    prompt = CONTEXT_QA_PROMPT.format(query=query, context=context)
    response = llm.invoke(prompt)
    return response.content

tools = [find_product_description, find_company_info]
agent = create_agent(llm, tools)

程序主体是 while True 循环,用户输入问题后交给 Agent,回答逐字动态打印。这个案例的关键在于把知识封装进工具:产品信息是本地字典,公司信息先组装成问答模板再调用模型生成,Agent 根据问题描述决定用哪个工具,而不是把所有知识塞进系统提示词。

代表性案例

CASE 1:工具链组合(Agent 版)

工具链组合的目标是让 Agent 通过多个工具逐步处理复杂问题。1-simple_toolchain.py 定义了五个自定义工具:文本分析、数据转换、统计行数、查找文本、替换文本,并用 create_agent 组合。

以任务一为例:分析文本情感并统计行数。Agent 的执行轨迹展示了 ReAct 的完整推理过程:

纯文本
思考: 我需要先分析文本的情感倾向,然后统计其中的行数。
行动: 文本分析
行动输入: '这个产品非常好用,我很喜欢它的设计,使用体验非常棒!...'
观察: {'word_count': 34, 'char_count': 102, 'sentiment': 'positive'}
思考: 我已经得到了情感倾向,现在需要统计行数。
行动: 文本处理
行动输入: operation='count_lines', content='...'
观察: {'line_count': 3}
思考: 我现在已经有了最终答案
回答: 这段文本的情感倾向是积极的(positive),并且它共有3行。

任务二是数据格式转换,输入 CSV 数据,工具返回 JSON 数组,最终回答中直接呈现转换结果:

JSON
[
  {"name": "张三", "age": "25", "comment": "这个产品很好"},
  {"name": "李四", "age": "30", "comment": "服务态度差"},
  {"name": "王五", "age": "28", "comment": "性价比高"}
]

整体工作流程是:用户提交任务描述,Agent 分析任务并决定使用哪些工具,通过 ReAct 框架调用相应工具,系统整合各工具结果生成最终回答。

CASE 2:工具链组合(LCEL 版)

2-simple_toolchain.py 用 LCEL 重写同一套工具链。工具函数被包装成 RunnableLambda,放入工具字典,再提供单工具调用、链式组合、并行执行三种编排方式:

Python
from langchain_core.runnables import RunnableLambda, RunnableMap, RunnablePassthrough

text_analysis_chain = RunnableLambda(lambda x: text_analysis.run(x["text"]))

def lcel_task_chain(task_type, params):
    if task_type not in tools:
        return "不支持的工具类型"
    return tools[task_type].invoke(params)

# 链式组合:先文本分析,再统计行数
chain = (
    RunnablePassthrough.assign(
        analysis=lambda x: text_analysis_chain.invoke({"text": x["text"]})
    )
    | RunnableLambda(lambda x: {
        "analysis": x["analysis"],
        "line_count": count_lines_chain.invoke({"content": x["text"]})
    })
)

# 并行执行:同时运行多个工具
parallel_chain = RunnableMap({
    "analysis": text_analysis_chain,
    "line_count": count_lines_chain,
})

两版实现的区别是理解 LangChain 编排方式的关键:

对比维度

Agent 版(1-simple_toolchain)

LCEL 版(2-simple_toolchain)

决策主体

Agent 自动解析任务、选择工具

开发者显式指定每一步

推理能力

支持 ReAct 多轮推理与工具调用

无自主决策,流程完全可控

组合方式

工具列表交给 create_agent

RunnableLambdaRunnableMapRunnablePassthrough

适合场景

智能决策加多工具自动调度

自定义流程、明确步骤、可控组合

CASE 3:网络故障诊断 Agent

网络故障诊断的难点在于工具之间存在串联关系:第一个工具的输出往往是第二个工具的输入,例如先 DNS 解析得到 IP,再对 IP 做连通性检查。2-network_diagnosis_agent.py 用四个模拟工具覆盖一条诊断链路:

工具

输入

输出

使用场景

PingTool

目标主机名或 IP

连通性状态与延迟

验证网络连接是否通畅

DNSTool

主机名

解析后的 IP 或失败信息

诊断 DNS 解析问题

InterfaceCheckTool

可选接口名称

接口状态、IP、子网掩码

检查本地网络配置

LogAnalysisTool

关键词、可选时间范围

匹配的日志条目

查找历史网络错误

示例问题的诊断链路:无法访问 www.example.com,先 DNS 解析得到 IP 93.184.216.34,再检查连通性返回连接超时,随后检查本地接口状态正常,最后分析日志发现多条 timeout 记录,诊断结论指向网络路由问题或目标服务器不可用。

这类 Agent 依赖 Zero-Shot ReAct:大模型在没有额外示例的情况下,直接根据工具名称和描述推理如何调用。LangChain 会自动把工具列表拼接进系统提示词,每个工具的 name 和 description 决定模型能否正确选择工具,因此工具描述必须写清楚输入格式和适用条件。

实际运行轨迹示例:模型先调用连通性检查,得到 Ping 成功延迟 59ms;再调用 DNS 解析,得到 IP 正常;然后调用日志分析,发现三条超时记录;最终结论是网络连通性和 DNS 均正常,浏览器无法访问的原因可能来自防火墙规则、代理设置或浏览器配置。整个过程展示了 Agent 如何根据观察结果不断调整下一步行动。

CASE 4:LCEL 多任务链

3-lcel-demo.py 演示了 LCEL 最典型的串行多任务链:翻译到英文、分析文本、回译中文,并用 stream() 边生成边输出:

Python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key, stream=True)

translate_to_en = ChatPromptTemplate.from_template("Translate this to English: {input}") | llm | StrOutputParser()
process_text = ChatPromptTemplate.from_template("Analyze this text: {text}") | llm | StrOutputParser()
translate_to_cn = ChatPromptTemplate.from_template("Translate this to Chinese: {output}") | llm | StrOutputParser()

workflow = {"text": translate_to_en} | process_text | translate_to_cn

for chunk in workflow.stream({"input": "北京有哪些好吃的地方,简略回答不超过200字"}):
    print(chunk, end="", flush=True)

{"text": translate_to_en} 是字典形式的分支,表示把第一段输出以 text 键传入下一段;StrOutputParser 把模型输出转成字符串,方便后续组件消费。LCEL 支持串联、分支、并行和流式,适合多步骤任务的灵活组合。

结果与评估

各案例的输入输出汇总:

案例

输入

输出

基础 Chain

{"product": "colorful socks"}

公司命名建议

Agent 加搜索

今天日期与历史名人问题

结合 SerpAPI 结果的回答

多工具组合

北京温度华氏度与四分之一

搜索加计算后的数值结果

带记忆对话

多轮问候

能引用上一轮上下文的回复

本地知识客服

产品与公司问题

基于本地字典与上下文模板的回答

工具链组合任务一

情感分析加行数统计

情感 positive、共 3 行

工具链组合任务二

CSV 数据

合法 JSON 数组

故障诊断

无法访问网站

完整诊断链路与结论

LCEL 多任务链

中文美食问题

翻译、分析、回译的流式结果

评估边界需要明确三点。第一,网络诊断工具是模拟实现,Ping、DNS、接口和日志分析都返回预设结果,没有执行真实命令,用于验证 Agent 的推理与串联逻辑,真实场景需要替换为实际工具。第二,所有 Agent 场景依赖通义千问 API 与 SerpAPI,需要配置 DASHSCOPE_API_KEY 和网络环境,脚本中也明确提示生产环境不要硬编码密钥。第三,版本边界以 LangChain 1.0.2 为准,旧文档中的 ZERO_SHOT_REACT_DESCRIPTIONAgentExecutor 等属于 0.3 写法,1.x 统一用 create_agent

AI Agent 工具对比

多任务应用开发还需要在框架层面做选型。材料给出的工具定位对比:

工具

核心定位

架构特点

适用场景

LangChain

开源 LLM 应用开发框架

基于链的线性或分支工作流,支持 Agent 模式

快速构建 RAG、对话系统、工具调用等线性任务

LangGraph

LangChain 扩展,专注复杂工作流

基于图的循环和条件逻辑,支持多 Agent 协作

循环、动态分支、状态管理复杂任务

Qwen-Agent

通义千问的 AI Agent 框架

基于阿里云大模型,支持多模态与工具调用

开源、集成多种工具、MCP 调用

Coze

字节跳动的无代码 AI Bot 平台

可视化拖拽界面,内置知识库与多模态插件

社交平台机器人、轻量级工作流

Dify

开源 LLM 应用开发平台

API 优先,支持 Prompt 工程与灵活编排

深度集成或私有化部署

四个维度的对比结论:工作流编排上,LangChain 适合固定流程,LangGraph 支持循环和条件边,Coze 可视化但灵活性较低,Dify 基于自然语言定义工作流;工具调用与扩展性上,LangChain 与 LangGraph 把工具作为链或图的节点,支持自定义与重试,Coze 依赖预置插件生态,Dify 支持 OpenAPI 集成;RAG 能力上,LangChain 开箱即用,LangGraph 需手动设计节点但支持反馈循环,Dify 提供基础 RAG,Coze 依赖知识库管理;多模态与部署上,Coze 支持图像视频生成并可发布到社交平台,Qwen-Agent 开源且支持 MCP(Model Context Protocol,模型上下文协议)调用,Dify 专注私有化部署。

选择建议:无代码开发用 Coze;快速原型用 LangChain 或 Qwen-Agent;复杂 Agent 系统用 LangGraph 或 Dify;企业私有化用 Dify、Qwen-Agent 或 LangChain 加 LangGraph 组合。

Coze 工作流中的节点与数据流关系
Coze 工作流中的节点与数据流关系

图 5 以 Coze 工作流为例展示节点间的关系:数据流表示上游节点的输出变量作为下游输入参数;控制流表示条件分支决定后续执行路径;HTTP 请求节点可以与其他节点并行执行;全局变量跨节点共享状态。这套关系同样适用于理解 LangGraph 等基于图的工作流。Coze 适合标准化诊断流程、多工具串联、条件分支决策和团队知识沉淀,局限在于无法直接 SSH 登录设备、复杂协议分析依赖外部系统、超过 50 节点的大规模拓扑需要拆分子工作流。

问题、限制与改进

第一,模拟工具与真实工具存在差距。故障诊断案例中的 Ping、DNS、日志工具都是返回预设结果的模拟实现,Agent 的推理链路可以被验证,但输出不能代表真实网络状态,生产落地需要把工具替换为真实命令或系统接口。

第二,外部依赖是运行前提。搜索和模型能力依赖 SerpAPI 与通义千问 API,网络不通或 Key 缺失时案例无法复现;材料中的代码已提醒不要在代码中硬编码密钥。

第三,Agent 的自主决策带来不确定性。同一问题在不同轮次可能选择不同工具组合,需要可预期流程时应改用 LCEL 手动编排;版本差异也需要注意,0.3 的 AgentExecutorZERO_SHOT_REACT_DESCRIPTION 写法在 1.x 中已由 create_agent 取代。

第四,安全与状态管理需要工程化。自定义计算器虽然用正则白名单限制输入,但生产环境仍应避免直接使用 eval,改用表达式解析库;对话历史存储在进程内字典,重启即丢失,多实例部署需要持久化会话存储。

工程启发

组件化是 LangChain 最有价值的工程思想:模型、提示、记忆、工具、链各自独立,替换任何一环都不影响其他部分。开发时先画任务的数据流,再决定每一段用 Chain、LCEL 还是 Agent。

工具的 docstring 就是工具的契约。Agent 能否在正确时机调用正确工具,直接取决于工具描述是否写清楚输入格式、示例和适用条件;自定义工具时应当把描述当作接口文档来写。

编排方式的选择原则可以概括为:流程固定、步骤明确时用 LCEL,代码可读、可调试、可测试;任务开放、需要根据内容自主选择工具时用 Agent,但要接受其决策的不确定性,并为关键路径设置约束或人工确认。

记忆策略的选择要结合上下文长度:信息必须完整时用全量存储,会话很长时用窗口或摘要,历史规模大且相关性重要时用向量检索。监控方面,LangSmith 把调试、回归测试与在线监控打通,多任务应用上线前应建立覆盖关键工具调用的回归用例。

小结

LangChain 多任务应用开发的核心是两套编排语义:LCEL 用数据流表达确定性的任务链,Agent 用 ReAct 循环表达不确定性的自主决策。基础案例说明组件如何组合,工具链案例说明多工具如何被调度,故障诊断案例说明串联型工具链如何完成复杂任务,框架对比则给出选型边界。对工程实践最有用的结论是:先定义任务的数据流,再选择编排方式,最后用工具描述和记忆策略控制 Agent 的行为质量。

END