Agent 中间件双雄实战:Tool Selector 与 To-do List 完全指南
让 LLM 工具调用既精准又清晰——两个中间件,搞定 Agent 的两大痛点。
📖 写在前面
随着 LangChain Agent 越来越普及,开发者会很快撞上两堵"墙":
- 工具太多:给 Agent 挂了 20 个工具,模型在调用时一脸懵。
- 任务太长:跨多步的复杂任务跑下来,用户只看到一行最终回复,根本不知道推进到哪了。
这两堵墙,Tool Selector 中间件 和 To-do List 中间件 正好能分别拆掉。
本文会带你用 10 分钟彻底搞懂这两个中间件:
| 你会学到 | 对应章节 |
|---|---|
| Tool Selector 的概念与运行逻辑 | 2 |
| Tool Selector 的代码创建与参数 | 2.5 |
| To-do List 的概念与实战调用 | 3 |
To-do List 的 write_todos 运行机制 | 3.5 |
| 二者对比与组合实战 | 4、5 |
一、问题背景:Agent 的两个典型痛点
- 痛点 ① 多工具 → 用
LLMToolSelectorMiddleware。 - 痛点 ② 多步任务 → 用
TodoListMiddleware。 - 两件事可以同时做,互不冲突。
二、Tool Selector 中间件
2.1 一句话概念
在调用主模型前,利用 LLM 智能筛选相关工具,把"大工具池"压缩成"当前任务够用的小工具集"。
2.2 架构与运行逻辑
6 步工作流:
- 用户提交任务
- 模型面对工具池选择困难
- 模型把"本次调用信息"发给 Tool Selector
- Tool Selector 从工具池筛工具
- 返回"少量相关工具"
- 模型基于筛选后的工具集继续推理
2.3 适用场景速查
| # | 场景 | 说明 |
|---|---|---|
| 1 | 多工具 | 工具数 ≥ 10,多数与查询无关 |
| 2 | 高成本 | 想通过过滤减少 token 消耗 |
| 3 | 高精度 | 想通过减少冗余工具提升聚焦度 |
触发决策树:
2.4 钩子类型与触发机制
tool_selector是before_model类型的钩子,会在每次对模型调用前,基于当前消息列表触发筛选。
2.5 代码实战
from langchain.agents import create_agent
from langchain.agents.middleware import LLMToolSelectorMiddleware
agent = create_agent(
model=model,
tools=[tool_1, tool_2, tool_3, tool_4, ...], # 完整工具池
middleware=[
LLMToolSelectorMiddleware(
model=model, # ① 负责选取工具的模型
max_tools=2, # ② 选取出来的工具数量
always_include=["tool_4"], # ③ 始终被选取的工具名称
),
],
)
参数说明
| 参数 | 含义 | 备注 |
|---|---|---|
model | 负责选工具的模型 | 可与主模型相同,也可指定更轻量的模型以省 token |
max_tools | 筛选后保留的工具上限 | 控制最终下发给主模型的数量 |
always_include | 强制保留的工具名列表 | 类型是 list[str],不是工具对象 |
⚠️ 易踩坑
tools=[...]传的是工具对象(callable)。always_include=[...]传的是字符串名称。- 类型别混。
三、To-do List 中间件
3.1 一句话概念
为 Agent 配备"复杂多步骤任务"的规划与追踪能力。
适用场景:
- ✅ 需要跨工具协同的复杂多步骤任务
- ✅ 需要进度可见性的长期运行操作
3.2 创建 Agent
from langchain.agents import create_agent
from langchain.agents.middleware import TodoListMiddleware
agent = create_agent(
model=model,
tools=[internet_search, calculate],
middleware=[TodoListMiddleware()],
)
3.3 调用与拿到 todos
res = agent.invoke({
"messages": ["""你要一步一步的详细规划以下内容再进行回答。
请分析美国加利福尼亚中央谷地的杏仁种植业在未来 30 年面临的气候变化风险,
并估算其经济影响。
"""]
})
print(res["todos"])
3.4 todos 的结构
[
{'content': 'Research the current climate trends affecting almond farming in California',
'status': 'completed'},
{'content': 'Analyze predictive models for climate change impacts up to 2050',
'status': 'completed'},
{'content': 'Estimate the percentage decrease in almond production by 2050',
'status': 'completed'},
{'content': 'Calculate the economic impact of reduced almond yields on California economy',
'status': 'completed'},
{'content': 'Search for the exchange rate for USD to Bitcoin as of November 2025',
'status': 'completed'},
{'content': 'Calculate how many Bitcoins could be purchased with the estimated USD loss',
'status': 'completed'},
]
字段定义:
| 字段 | 含义 |
|---|---|
content | 子任务的具体内容(自然语言) |
status | 当前执行状态,取值为 pending / progress / completed |
3.5 运行逻辑:自动注入 write_todos 工具
为 Agent 新增
write_todos工具,让 Agent 能创建并管理结构化任务清单,跟踪进度、整理任务、为用户提供可视化状态。
状态机
架构图
5 个关键洞察:
write_todos由TodoListMiddleware自动注入,用户无需手写。- 它与"原有工具"并存,模型可同时调用。
write_todos内部生成结构化子任务清单。- 子任务回流到模型,作为下一轮推理输入。
- 每个子任务带状态,对外可视化。
四、对比速查表
4.1 维度对照
| 维度 | LLMToolSelectorMiddleware | TodoListMiddleware |
|---|---|---|
| 核心目标 | 筛选相关工具 | 规划与追踪多步任务 |
| 解决痛点 | 工具太多选花眼 | 长任务一团乱麻 |
| 改动方式 | 拦截调用、过滤工具 | 注入新工具 write_todos |
| 钩子时机 | before_model | 围绕任务执行过程 |
| 典型场景 | 工具 ≥ 10 / 高 token / 高精度 | 跨工具多步 / 长期运行 |
| 结果可见性 | 透明 | res["todos"] |
| 输出 schema | 工具名+描述 | [{content, status}, ...] |
4.2 一句话差异
🔑 Tool Selector 让模型"看得更少",Todo List 让模型"做得更清晰"。
五、二者组合实战(推荐)
from langchain.agents import create_agent
from langchain.agents.middleware import (
LLMToolSelectorMiddleware,
TodoListMiddleware,
)
agent = create_agent(
model=model,
tools=[search, calc, db, mail, doc, ...], # 大量工具
middleware=[
LLMToolSelectorMiddleware( # ① 先按 query 筛工具
model=model,
max_tools=3,
always_include=["search"],
),
TodoListMiddleware(), # ② 再做多步规划与追踪
],
)
组合后的请求流
六、一页思维导图(复习专用)
七、写在最后
如果你正在搭建生产级 LangChain Agent,强烈建议把这两个中间件默认打开:
- 🧠 Tool Selector 让你不惧工具膨胀。
- 📋 Todo List 让你不惧长任务。
一句话总结全文:
Tool Selector 让 Agent 选得准,Todo List 让 Agent 想得清。两者组合,攻守兼备。
📌 附录 · 一行速记表
| 关注点 | Tool Selector | Todo List |
|---|---|---|
| 干嘛用 | 筛选工具 | 规划任务 |
| 怎么实现 | 拦截调用 | 注入工具 |
| 看得见吗 | 透明 | 看 res["todos"] |
| 啥时候用 | 工具 ≥ 10 | 任务 ≥ 3 步 |
如果觉得本文有帮助,欢迎 点赞 + 收藏 + 关注,我们下期再见 👋
许可协议:
CC BY 4.0