LangChain DeepAgents 速通指南(三)—— 让Agent告别混乱:Tool Selector与Todo List中间件解析

前言

上篇文章《LangChain DeepAgents 速通指南(二)------ Summarization中间件为Agent作记忆加减法》 深入探讨了LangChain DeepAgents内置的Summarization中间件 。该中间件能够自动压缩对话历史,有效解决大模型上下文窗口限制的问题。本期笔者将继续深入介绍LangChain DeepAgents框架预置的两个非常实用的中间件------Tool Selector (工具选择器)和Todo List(待办列表)。这两个中间件能够帮助Agent智能体在面对复杂任务和庞大工具集时,依然保持高效、专注与准确,让Agent的决策过程更加条理清晰。

一、Tool Selector 中间件:为Agent的工具箱做减法

1.1 为什么需要Tool Selector?

在构建面向真实业务场景的智能体应用时,大家常常需要为大模型赋予大量的工具,例如搜索引擎、计算器、数据库查询器、API调用器等。当任务环境变得复杂,智能体可能拥有成百上千个工具。然而在执行一个具体任务时,实际用到的工具往往只是其中的一小部分。大量无关的工具不仅不会在每一步都发挥作用,反而会持续占据宝贵的模型上下文窗口。这不仅造成了Token的浪费,更可能引入噪声,干扰主模型的判断,降低决策的准确率。

Tool Selector正是为了解决这一痛点而生。它是一个覆写了wrap_model_call钩子函数的中间件。其核心机制是:在每次调用主模型之前,ToolSelector中间件会基于当前的对话消息列表及用户问题,对全部工具列表进行一次智能预筛选,只保留与当前任务最相关的一小部分工具。随后,这个精简后的工具子集才会被传递给主模型,让主模型能够排除干扰,更专注、更准确地做出下一步的决策。

LangChain DeepAgents 框架通过内置的 LLMToolSelectorMiddleware 中间件实现了这一功能,其工作流程如下图所示:

1.2 Tool Selector中间件适用场景

Tool Selector中间件尤其适合以下场景:

  • 多工具管理:Agent拥有庞大的工具集,但每次查询仅涉及其中少数几个。
  • 成本控制:希望通过过滤无关的工具信息,显著减少Token消耗,优化API调用成本。
  • 精度提升:通过减少上下文中的冗余信息,提升模型在关键任务上的专注度与决策准确性。

1.3 如何使用Tool Selector?

在LangChain DeepAgents中使用Tool Selector非常简单,只需几个步骤即可完成配置。

  1. 环境准备与依赖引入: 首先在 langchain>=1.0.5python>=3.12 的环境中编写脚本,引入必要的依赖,并定义模型和工具。本例中使用 DeepSeek 模型。
python 复制代码
from dotenv import load_dotenv
from langchain_core.tools import tool
from langchain.agents import create_agent
from langchain.agents.middleware import LLMToolSelectorMiddleware
from langchain_deepseek import ChatDeepSeek

load_dotenv()

model = ChatDeepSeek(
    model="deepseek-chat",
)
  1. 为 Agent 定义工具列表: 编写一个核心的 calculate 工具,并同时定义 tool_1tool_4 作为备用工具,以模拟一个拥有较多工具的场景。
python 复制代码
@tool
def tool_1(input:str) -> str:
    """
    This is a useless tool, intended solely as an example.
    """
    return "This is a useless tool, intended solely as an example."
@tool
def tool_2(input:str) -> str:
    """
    This is a useless tool, intended solely as an example.
    """
    return "This is a useless tool, intended solely as an example."
@tool
def tool_3(input:str) -> str:
    """
    This is a useless tool, intended solely as an example.
    """
    return "This is a useless tool, intended solely as an example."
@tool
def tool_4(input:str) -> str:
    """
    This is a useless tool, intended solely as an example.
    """
    return "This is a useless tool, intended solely as an example."


@tool
def calculate(expression: str) -> str:
    """Perform mathematical calculations and return the result.
    Args:
        expression: Mathematical expression to evaluate
        (e.g., "2 + 3 * 4", "sqrt(16)", "sin(pi/2)")
    Returns:
        The calculated result as a string
    """
    result = str(eval(expression))
    return result
  1. 集成 LLMToolSelectorMiddleware 中间件: 使用Tool Selector功能需要引入LLMToolSelectorMiddleware中间件。配置该中间件需要以下几个关键参数:
  • model: 负责执行工具筛选的模型实例,本例中与主模型共用同一个model
  • max_tools: 每次为主模型筛选出的最大工具数量。
  • always_include: 一个列表,用于指定无论如何都必须被选中 的工具名称。需要注意的是,create_agenttools参数传入的是工具对象列表,而always_include中传入的是这些工具对应的名称字符串。
python 复制代码
agent = create_agent(
    model=model,
    tools=[tool_1, tool_2, tool_3, tool_4,calculate],
    middleware=[
        LLMToolSelectorMiddleware(
            model=model,
            max_tools=2,
            always_include=['tool_1'],
        ),
    ],
)
  1. 运行测试: 最后通过一个数学计算任务来测试效果。从运行结果可以看到,尽管工具列表庞大,但智能体依然能够准确地选择并使用 calculate 工具来完成计算,这证明了Tool Selector在筛选工具方面的有效性。
python 复制代码
status = {
    'messages': '请计算2+3*4的值'
}

result = agent.invoke(status)
print(result)

二、Todo List 中间件:为复杂任务绘制路线图

2.1 为什么需要 Todo List 中间件?

当智能体需要执行一个多步骤、跨工具的复杂任务时,如果没有任务规划能力,Agent很容易在步骤中迷失,或者忘记已经完成的部分。大家工作中都使用Trae、Claude Code等编程智能体时也能观察到,当用户下达一个复杂任务时,这些智能体的首要工作往往是生成一份清晰的任务规划清单。

Todo List中间件的设计正是为了赋予Agent这种规划能力。它的实现方式与传统钩子函数不同,而是以额外工具 的形式,向Agent注入一个名为write_todo的工具。其工作流程如下:

当用户输入一个复杂任务后,主模型会首先判断该任务是否需要多步处理。如果需要,它会主动调用write_todo工具,生成结构化的子任务列表,并将其保存在Agent的持久化状态(todos字段)中。随后,Agent会严格按照这个任务列表的顺序执行:当前正在处理的子任务状态标记为progress,完成后更新为completed,并自动推进到下一个状态为pending的子任务,如此循环,直至所有子任务完成。最终,Agent汇总所有步骤收集到的信息,给出完整的最终回复。这一机制确保了Agent能够有条不紊地完成复杂任务。整个流程可以用下图清晰地展示:

2.2 Todo List 中间件适用场景

  • 复杂多步骤任务:需要调用多个工具协同完成,且步骤之间存在明确的前后依赖关系。
  • 需要进度可见性的长期运行任务 :通过查看todos状态,开发者或用户能够实时了解任务执行的进展,知道当前进行到哪一步,哪些步骤已经完成。

2.3 如何使用 Todo List 中间件?

下面通过代码示例,详细讲解如何在LangChain的create_agent API中集成并使用Todo List功能。

  1. 环境准备与依赖引入:langchain>=1.0.5python>=3.12的环境中编写脚本,引入必要的依赖,并定义模型。本例中使用 DeepSeek 模型。
python 复制代码
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.agents.middleware import TodoListMiddleware
from langchain_deepseek import ChatDeepSeek

load_dotenv()

model = ChatDeepSeek(
    model="deepseek-chat",
)
  1. 集成 TodoListMiddleware 中间件: 使用TodoListMiddleware中间件的方法极其简单,只需在创建Agent时,将其加入到middleware列表中即可,write_todo工具会由中间件自动注入。
python 复制代码
agent = create_agent(
    model=model,
    tools=[],
    middleware=[TodoListMiddleware()],
)
  1. 通过复杂案例测试: 设计了一个高度复杂的、需要多步分析和计算的综合性问题来测试。当用户下达这个任务后,Todo List机制会自动生效。

    在Agent的最终响应中,除了常规的messages(包含对话历史和最终答案),还会发现一个新增的todos字段。这个字段中包含了Agent对原始任务进行拆解后的详细子任务列表。每个子任务条目都包含content(任务描述)和status(状态)。

    子任务的状态共有三种:

    • pending:尚未执行的子任务。
    • progress:当前正在执行的子任务。
    • completed:已经完成的子任务。

    注意 :由于在这里使用的是invoke方法进行同步调用,Agent会执行完所有任务后才返回最终结果,因此最终打印出的所有子任务状态均为completed。若想观察子任务状态在执行过程中的动态变化(例如从pendingprogress再到completed的流转),可以参考笔者的另一篇文章 《LangChain1.0速通指南(二)------LangChain1.0 create_agent api 基础知识》 中介绍的流式输出方法。

python 复制代码
res = agent.invoke({"messages":["""你要一步一步的详细规划以下内容再进行回答。
请分析美国加利福尼亚中央谷地的杏仁种植业在未来30年面临的气候变化风险,并估算其经济影响。
具体需要回答,:
"假设当前气候趋势持续,到2050年,加利福尼亚中央谷地杏仁产量可能减少的百分比及其对该州经
济的潜在年度损失是多少美元?这些美元按照2025年11月的汇率能够购买多少比特币?
"""]})

print(res["messages"])
print("\n---------TODO---------------\n")
print(res["todos"])

三、总结

本期内容介绍了ToolSelector和TodoList两个中间件,ToolSelector中间件能够在调用主模型前,利用LLM智能筛选相关工具。TodoList中间件通过注入write_todo工具,让Agent在遇到复杂任务时自动拆解子任务并维护状态。LangChain DeepAgents框架正是通过这两个中间件提升了智能体执行复杂任务的性能。除了这两个中间件外,DeepAgents框架还需要有一个文件系统来存储中间结果、记忆结果等,下期内容笔者会分享LangChain DeepAgents框架 FileSystem的相关知识,大家敬请期待~

本系列相关内容均列于笔者的专栏《深入浅出LangChain&LangGraph AI Agent 智能体开发》,该专栏适合所有对 LangChain 感兴趣的学习者,无论之前是否接触过 LangChain。该专栏基于笔者在实际项目中的深度使用经验,系统讲解了使用LangChain/LangGraph如何开发智能体,目前已更新 40 讲,并持续补充实战与拓展内容。欢迎感兴趣的同学关注笔者的掘金账号与专栏,也可关注笔者的同名微信公众号大模型真好玩 ,每期分享涉及的代码均可在公众号私信: LangChain智能体开发免费获取。

相关推荐
孟祥_成都2 小时前
【全网最通俗!新手到AI全栈开发必读】 AI 是如何进化到大模型的
前端·人工智能·全栈
牛奶2 小时前
AI辅助开发的基础概念
前端·人工智能·ai编程
东坡肘子2 小时前
OpenClaw 不错,但我好像没有那么需要 -- 肘子的 Swift 周报 #125
人工智能·swiftui·swift
风象南10 小时前
普通人用AI加持赚到的第一个100块
人工智能·后端
牛奶10 小时前
2026年大模型怎么选?前端人实用对比
前端·人工智能·ai编程
牛奶11 小时前
前端人为什么要学AI?
前端·人工智能·ai编程
罗西的思考13 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
冬奇Lab14 小时前
OpenClaw 源码精读(2):Channel & Routing——一条消息如何找到它的 Agent?
人工智能·开源·源码阅读
冬奇Lab14 小时前
一天一个开源项目(第38篇):Claude Code Telegram - 用 Telegram 远程用 Claude Code,随时随地聊项目
人工智能·开源·资讯