[Deep Agents:LangChain的Agent Harness-04]TodoListMiddleware的任务拆解与状态流转
TodoListMiddleware赋予Agent显式的规划和任务跟踪能力。它强制Agent将复杂的多步骤目标分解为一组结构化的可执行项,从而将被动型Agent转变为主动型Agent。它通过拦截Agent的推理循环来注入规划逻辑和工具:
- 规划工具:它为Agent提供了
write_todos工具来创建、更新和替换其整个任务列表; - 状态管理:它维护一个
PlanningState状态来跟踪当前任务列表; - 系统提示注入:它注入系统提示词用来指导LLM何时进行规划以及如何有效地使用任务列表,以避免在长时间运行的任务中出现目标漂移;
Agent通常以简单的思考-行动-观察循环运行,Deep Agents则利用TodoListMiddleware来处理长期任务,合理使用它可以带来以下好处:
- 降低识别负荷:可以动态卸载不必要的任务,防止它们占据上下文窗口。也就是说,上下文窗口可以指存储必要的任务列表,以提高推理性能;
- 可视性和调试:它实时存储了任务列表及其状态,如果Agent遇到问题,这些信息会准确地显示它正在尝试执行的步骤;
- 结构化委托:当与
SubAgentMiddleware一起使用时,待办事项列表充当交接点,Main-Agent可以在此定义专门的Sub-Agent的任务;
1. 提供工具将TodoList写入当前状态
我们先来看看TodoListMiddleware维护的状态类型PlanningState。PlanningState是一个AgentState类型的子类,它利用todos字段存储表示任务列表的一组Todo对象。表示单个待办事项的Todo是一个TypedDict,两个字段content和status分别表示任务内容描述和当前状态。从todos字段的定义可以看出,由于没有指定reduer函数,所以对应的通道类型为LastValue,这意味着它采用的是全量更新,而非增量添加。
class PlanningState(AgentState[ResponseT]):
todos: Annotated[NotRequired[list[Todo]], OmitFromInput]
class Todo(TypedDict):
content: str
status: Literal["pending", "in_progress", "completed"]
TodoListMiddleware利用注入的提示词指导LLM采用结构化的方式来创建和管理待办事项列表,并提供了一个配套write_todos工具来提供辅助。当我们调用__init__方法创建TodoListMiddleware实例时,可以指定该工具的描述和系统提示词。如果你不能保证提供的工具描述和系统提示词比默认提供的更好,那么建议直接使用默认值即可。任务写入工具对应的函数内嵌在__init__方法中的write_todos,它接受一个待办事项列表和自动注入的工具调用ID,针对任务的全量更新利用返回的Command完成。
class TodoListMiddleware(AgentMiddleware[PlanningState[ResponseT], ContextT, ResponseT]):
state_schema = PlanningState
def __init__(
self,
*,
system_prompt: str = WRITE_TODOS_SYSTEM_PROMPT,
tool_description: str = WRITE_TODOS_TOOL_DESCRIPTION,
) -> None:
super().__init__()
self.system_prompt = system_prompt
self.tool_description = tool_description
@tool(description=self.tool_description)
def write_todos(
todos: list[Todo], tool_call_id: Annotated[str, InjectedToolCallId]
) -> Command[Any]:
return Command(
update={
"todos": todos,
"messages": [
ToolMessage(f"Updated todo list to {todos}", tool_call_id=tool_call_id)
],
}
)
self.tools = [write_todos]
如下所示的是TodoListMiddleware为提供的工具write_todos的定义的描述,可以作为工具描述的范本。
Use this tool to create and manage a structured task list for your current work session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
Only use this tool if you think it will be helpful in staying organized. If the user's request is trivial and takes less than 3 steps, it is better to NOT use this tool and just do the task directly.
## When to Use This Tool
Use this tool in these scenarios:
1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
3. User explicitly requests todo list - When the user directly asks you to use the todo list
4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
5. The plan may need future revisions or updates based on results from the first few steps
## How to Use This Tool
1. When you start working on a task - Mark it as in_progress BEFORE beginning work.
2. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation.
3. You can also update future tasks, such as deleting them if they are no longer necessary, or adding new tasks that are necessary. Don't change previously completed tasks.
4. You can make several updates to the todo list at once. For example, when you complete a task, you can mark the next task you need to start as in_progress.
## When NOT to Use This Tool
It is important to skip using this tool when:
1. There is only a single, straightforward task
2. The task is trivial and tracking it provides no benefit
3. The task can be completed in less than 3 trivial steps
4. The task is purely conversational or informational
## Task States and Management
1. **Task States**: Use these states to track progress:
- pending: Task not yet started
- in_progress: Currently working on (you can have multiple tasks in_progress at a time if they are not related to each other and can be run in parallel)
- completed: Task finished successfully
2. **Task Management**:
- Update task status in real-time as you work
- Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
- Complete current tasks before starting new ones
- Remove tasks that are no longer relevant from the list entirely
- IMPORTANT: When you write this todo list, you should mark your first task (or tasks) as in_progress immediately!.
- IMPORTANT: Unless all tasks are completed, you should always have at least one task in_progress to show the user that you are working on something.
3. **Task Completion Requirements**:
- ONLY mark a task as completed when you have FULLY accomplished it
- If you encounter errors, blockers, or cannot finish, keep the task as in_progress
- When blocked, create a new task describing what needs to be resolved
- Never mark a task as completed if:
- There are unresolved issues or errors
- Work is partial or incomplete
- You encountered blockers that prevent completion
- You couldn't find necessary resources or dependencies
- Quality standards haven't been met
4. **Task Breakdown**:
- Create specific, actionable items
- Break complex tasks into smaller, manageable steps
- Use clear, descriptive task names
Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully
Remember: If you only need to make a few tool calls to complete a task, and it is clear what you need to do, it is better to just do the task directly and NOT call this tool at all.
2. 通过系统提示词指导LLM进行规划
系统提示词的设置通过重写的wrap_model_call/awrap_model_call方法来实现的。由于任务列表采用全量更新的方式,所以在同一个推理步骤中针对write_todos工具的多次调用会导致之前的任务列表被覆盖,这是我们不希望看到的,也是不应该出现的现象。TodoListMiddleware重写了wrap_tool_call/awrap_tool_call方法来检测是否出现了并行修改任务列表的情况,并生成一个警告性的ToolMessage。
class TodoListMiddleware(AgentMiddleware[PlanningState[ResponseT], ContextT, ResponseT]):
def wrap_model_call(
self,
request: ModelRequest[ContextT],
handler: Callable[[ModelRequest[ContextT]], ModelResponse[ResponseT]],
) -> ModelResponse[ResponseT] | AIMessage
async def awrap_model_call(
self,
request: ModelRequest[ContextT],
handler: Callable[[ModelRequest[ContextT]], Awaitable[ModelResponse[ResponseT]]],
) -> ModelResponse[ResponseT] | AIMessage
@override
def after_model(
self, state: PlanningState[ResponseT], runtime: Runtime[ContextT]
) -> dict[str, Any] | None
@override
async def aafter_model(
self, state: PlanningState[ResponseT], runtime: Runtime[ContextT]
) -> dict[str, Any] | None
如下所示的是TodoListMiddleware提供的默认系统提示词的内容。我个人觉得去学习如何写好提示词的最好途径就是去阅读框架内部的提示词是如何撰写的,比如Deep Agents的很多中间件提供的提示词都非常具有指导性和启发性。
## `write_todos`
You have access to the `write_todos` tool to help you manage and plan complex objectives.
Use this tool for complex objectives to ensure that you are tracking each necessary step and giving the user visibility into your progress.
This tool is very helpful for planning complex objectives, and for breaking down these larger complex objectives into smaller steps.
It is critical that you mark todos as completed as soon as you are done with a step. Do not batch up multiple steps before marking them as completed.
For simple objectives that only require a few steps, it is better to just complete the objective directly and NOT use this tool.
Writing todos takes time and tokens, use it when it is helpful for managing complex many-step problems! But not for simple few-step requests.
## Important To-Do List Usage Notes to Remember
- The `write_todos` tool should never be called multiple times in parallel.
- Don't be afraid to revise the To-Do list as you go. New information may reveal new tasks that need to be done, or old tasks that are irrelevant.
3. 利用TodoListMiddleware指定一个旅游规划
在下面的演示程序中,我们创建了一个Agent,并在其中注册了TodoListMiddleware。我们通过调用Agent帮助规划一个为期三天的赴日旅行安排。演示程序展示了如何使用TodoListMiddleware来实现一个结构化的任务管理流程,以及如何通过系统提示词来指导Agent进行有效的规划。由于我们在提供的提示词中建议Agent尽可能多地使用write_todos工具来管理任务列表,因此在Agent的推理过程中,我们可以看到它多次调用write_todos工具来更新任务列表,并且每次更新都会生成一个新的工具调用结果,显示当前的待办事项列表。
from langchain.agents import create_agent
from langchain.agents.middleware import TodoListMiddleware
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
import asyncio
load_dotenv()
agent = create_agent(
model=ChatOpenAI(model= "gpt-5.2-chat"),
middleware=[TodoListMiddleware()],
)
prompt = """\
Conduct a simple plan to travle in Japan for 3 days, including the cities to visit, the attractions to see, the food to try, and the transportation to use.
Provide a day-by-day itinerary with specific recommendations and tips for each day.
Try to use `write_todos` tool as possible as you can.
"""
async def main():
result = await agent.ainvoke(input= {"messages": [{"role": "user", "content": prompt}]})
for message in result["messages"]:
message.pretty_print()
asyncio.run(main())
输出
================================ Human Message =================================
Conduct a simple plan to travle in Japan for 3 days, including the cities to visit, the attractions to see, the food to try, and the transportation to use.
Provide a day-by-day itinerary with specific recommendations and tips for each day.
Try to use `write_todos` tool as possible as you can.
================================== Ai Message ==================================
Tool Calls:
write_todos (call_qedNqFlya1ESQdj9sqmtvwwi)
Call ID: call_qedNqFlya1ESQdj9sqmtvwwi
Args:
todos: [{'content': 'Design overall 3-day Japan itinerary structure and choose cities', 'status': 'in_progress'}, {'content': 'Create detailed Day 1 itinerary (Tokyo) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Design overall 3-day Japan itinerary structure and choose cities', 'status': 'in_progress'}, {'content': 'Create detailed Day 1 itinerary (Tokyo) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
write_todos (call_BW4mtEOTYpQOQkbTCNkyNuJK)
Call ID: call_BW4mtEOTYpQOQkbTCNkyNuJK
Args:
todos: [{'content': 'Design overall 3-day Japan itinerary structure and choose cities', 'status': 'completed'}, {'content': 'Create detailed Day 1 itinerary (Tokyo) with attractions, food, transport, tips', 'status': 'in_progress'}, {'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Design overall 3-day Japan itinerary structure and choose cities', 'status': 'completed'}, {'content': 'Create detailed Day 1 itinerary (Tokyo) with attractions, food, transport, tips', 'status': 'in_progress'}, {'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
write_todos (call_wk8Dp7mtu5j1DnxHnZAFpQ9b)
Call ID: call_wk8Dp7mtu5j1DnxHnZAFpQ9b
Args:
todos: [{'content': 'Create detailed Day 1 itinerary (Tokyo) with attractions, food, transport, tips', 'status': 'completed'}, {'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'in_progress'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Create detailed Day 1 itinerary (Tokyo) with attractions, food, transport, tips', 'status': 'completed'}, {'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'in_progress'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'pending'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
write_todos (call_764zNPUyX5zQ0m8TfXu1OKwt)
Call ID: call_764zNPUyX5zQ0m8TfXu1OKwt
Args:
todos: [{'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'completed'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'in_progress'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Create detailed Day 2 itinerary (Kyoto) with attractions, food, transport, tips', 'status': 'completed'}, {'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'in_progress'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'pending'}]
================================== Ai Message ==================================
Tool Calls:
write_todos (call_nEtItfmDhsDxJE0b26L93AdH)
Call ID: call_nEtItfmDhsDxJE0b26L93AdH
Args:
todos: [{'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'completed'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'in_progress'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Create detailed Day 3 itinerary (Osaka) with attractions, food, transport, tips', 'status': 'completed'}, {'content': 'Review itinerary for clarity and add general travel tips', 'status': 'in_progress'}]
================================== Ai Message ==================================
Tool Calls:
write_todos (call_uBOYfWFACuFyvQPhlJudPwtq)
Call ID: call_uBOYfWFACuFyvQPhlJudPwtq
Args:
todos: [{'content': 'Review itinerary for clarity and add general travel tips', 'status': 'completed'}]
================================= Tool Message =================================
Name: write_todos
Updated todo list to [{'content': 'Review itinerary for clarity and add general travel tips', 'status': 'completed'}]
================================== Ai Message ==================================
Below is a **simple, first‑time‑friendly 3‑day Japan travel plan** covering **Tokyo, Kyoto, and Osaka**. It balances famous sights, local food, and efficient transportation, with practical tips each day.
---
## 🇯🇵 3‑Day Japan Travel Itinerary (Tokyo → Kyoto → Osaka)
### Overview
- **Best for**: First-time visitors
- **Pace**: Moderate (highlights only)
- **Main transport**: Trains (Shinkansen + local lines)
- **Cities**: Tokyo → Kyoto → Osaka
---
## 📍 Day 1: Tokyo – Modern City & Tradition
### Morning
**Visit: Asakusa & Senso‑ji Temple**
- Tokyo’s oldest Buddhist temple
- Walk through **Nakamise Street** for souvenirs and snacks
**Try food:**
- Ningyo-yaki (sweet cakes)
- Melon pan
- Matcha ice cream
**Transport:**
- Tokyo Metro (Ginza Line / Asakusa Line)
---
### Afternoon
**Visit: Shibuya**
- Famous **Shibuya Crossing**
- Hachiko Statue (photo spot)
**Lunch suggestion:**
- Ramen (Ichiran / Ippudo)
- Gyudon (Sukiya, Yoshinoya)
---
### Evening
**Visit: Shinjuku**
- Tokyo Metropolitan Government Building (free city view)
- Kabukicho lights at night
**Dinner:**
- Izakaya (Japanese pub)
- Yakitori (grilled chicken skewers)
**Tips for Day 1**
- Buy a **Suica or Pasmo IC card** for easy transport
- Avoid rush hours (7–9 AM, 5–7 PM)
- Wear comfortable walking shoes
---
## 🚄 Day 2: Kyoto – Culture & History
### Morning
**Travel: Tokyo → Kyoto**
- **Shinkansen (bullet train)**
- ⏱ ~2.5 hours
- 🚄 Nozomi or Hikari trains
---
### Late Morning
**Visit: Fushimi Inari Shrine**
- Famous red torii gates
- Walk as far as comfortable (no need to finish full hike)
---
### Afternoon
**Visit: Kiyomizu‑dera Temple**
- Wooden temple with city views
- Walk through **Higashiyama** historic streets
**Lunch:**
- Udon or soba noodles
- Yudofu (tofu specialty)
---
### Evening
**Visit: Gion District**
- Traditional streets
- Chance to spot geiko/maiko
**Dinner:**
- Kaiseki (if budget allows)
- Simple Kyoto-style set meal
**Tips for Day 2**
- Kyoto buses get crowded—trains are often faster
- Dress modestly at temples
- Carry cash for small shops
---
## 🍜 Day 3: Osaka – Food & Fun
### Morning
**Travel: Kyoto → Osaka**
- JR Train (15–30 minutes)
---
### Morning Visit
**Osaka Castle**
- Symbol of Osaka
- Nice park for walking and photos
---
### Afternoon
**Visit: Dotonbori**
- Neon signs & street food heaven
- Glico running man sign
**Must‑try food:**
- Takoyaki (octopus balls)
- Okonomiyaki (savory pancake)
- Kushikatsu (deep-fried skewers)
---
### Evening
**Option 1:** Umeda Sky Building (city view)
**Option 2:** Shinsaibashi shopping street
**Tips for Day 3**
- Osaka is casual—relaxed manners
- Street food is best eaten standing near stalls
- Trains run late but check last train times
---
## ✅ General Travel Tips
- **Wi‑Fi/SIM**: Rent pocket Wi‑Fi or buy eSIM
- **Luggage**: Use coin lockers or luggage delivery
- **Language**: Basic English is common in cities
- **Payments**: IC cards + some cash recommended
---
If you want, I can:
- Adjust this for **budget / luxury**
- Make it **family‑friendly**
- Focus on **anime, food, or nature**
- Add **hotel recommendations**
Just tell me! 😊
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)