环境:Spring Boot 3.5.0
1. 简介
大语言模型普遍存在中途失忆故障 —— 会遗忘长上下文里潜藏的任务。当 AI 智能体同时处理文件编辑、测试运行和文档更新等多项工作时,重要步骤常会悄无声息地被遗漏。受 Claude Code 启发,有一种解决方案:借助专用的 TodoWrite 工具,让任务规划变得清晰可见、可全程追溯。最终实现:智能体绝不跳步,工作流可实时监控。
什么是 TodoWriteTool?
TodoWriteTool 是一款 Spring AI 工具,能让大语言模型在任务执行过程中创建、跟踪、更新任务清单。该工具灵感源自 Claude Code 的 TodoWrite 功能,可把隐性任务规划,转化为显性化、可追踪的工作流程。
当智能体(Agent)接到复杂任务,例如在设置页面添加深色模式切换开关并运行测试时,会先通过 TodoWriteTool 拆解任务,再开始执行,如下执行流程:

大语言模型但凡需要更新任务规划时,就会调用该工具—— 无论是创建初始任务、标记进度,还是新增临时发现的待办工作。
该工具可接收待办事项列表,每条事项包含编号、任务内容(待执行事项)和状态。每条待办任务都遵循一套简洁的生命周期流程。

该工具设有一条重要约束:同一时间只能有一个任务处于进行中状态。这一规则强制任务按顺序、专注执行,而非分散精力并行乱做。以下是任务执行过程中的实时进度展示效果:
Progress: 2/4 tasks completed (50%)[✓] Find top 10 Tom Hanks movies[✓] Group movies in pairs[→] Print inverted titles[ ] Final summary
接下来,我们将详细的完成一个示例。
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId></dependency><dependency><groupId>org.springaicommunity</groupId><artifactId>spring-ai-agent-utils</artifactId></dependency>
spring:ai:openai:api-key: ${API_KEY}base-url: ${BASE_URL}chat:model: deepseek-v4-flash
@RestController@RequestMapping("/ai/task")public class AiTaskControler {private final ChatClient chatClient ;public AiTaskControler(ChatClient.Builder builder, ApplicationContext context) {this.chatClient = builder.defaultTools(TodoWriteTool.builder().todoEventHandler(event ->context.publishEvent(new TodoUpdateEvent(this, event.todos()))).build()).defaultAdvisors(ToolCallAdvisor.builder().conversationHistoryEnabled(false).build(),MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().maxMessages(500).build()).build()).build() ;}@GetMapping("/execute")public String execute() {String response = chatClient.prompt().user("找出周星驰评分最高的 6 部电影,将它们两两分组,并把每部电影的片名倒序拼写输出。使用 TodoWrite 来梳理、规划你的执行任务。").advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "C-0001")).call().content() ;return response ;}}
⚠️ 重要提示:将 conversationHistoryEnabled(false) 设置为关闭后,会禁用内置的工具调用历史记录,转而使用 MessageChatMemoryAdvisor 来维护会话上下文。
@Componentpublic class TodoProgressListener {@EventListenerpublicvoidonTodoUpdate(TodoUpdateEvent event) {System.err.println(event.getTodos());int completed = (int) event.getTodos().stream().filter(t -> t.status() == Todos.Status.completed).count();int total = event.getTodos().size();System.out.printf("\nProgress: %d/%d tasks completed (%.0f%%)\n", completed, total, (completed * 100.0 / total));}}
public class TodoUpdateEvent extends ApplicationEvent {private final List<TodoItem> todos;public TodoUpdateEvent(Object source, List<TodoItem> todos) {super(source);this.todos = todos;}public List<TodoItem> getTodos() {return todos;}}



别再瞎拼 URL 了!Spring Boot 这套 URI 工具太香
效率提升300%!Spring Boot 单接口动态实现6种数据格式
告别@JsonView缺陷!自定义@ResponseFilter实现灵活字段控制
别只会 Controller 校验!90% 人不懂的 Spring 高级校验方案
Spring Boot 超大请求/响应 JSON(100M)如何避免OOM?
手动造数据OUT了!用DataFaker生成百万级真实感演示数据
性能相差60倍!Spring Boot 批量插入你做对了吗?5种方式对比










夜雨聆风