news 2026/7/27 10:54:26

Microsoft Agent Framework — Harness 中 Agent 的待办清单:Todo 模块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Microsoft Agent Framework — Harness 中 Agent 的待办清单:Todo 模块

目录

1. Todo 模块的职责

2. 如何理解 Todos

它解决什么问题、为什么值得用

3. Todos 的生命周期

3.1 默认守则如何指挥模型动手

3.2 状态与条目的生命周期

3.3 每轮自动注入清单

4. 类型清单

5. 相关类型解析

5.1 TodoProvider

5.2 TodoProviderOptions

5.3 TodoItem

5.4 内部类型

6. 暴露给模型的工具

7. 行为要点

8. 与其它模块的关系

9. 扩展与最佳实践

10. 小结



上一篇

基于 MAF .NET1.13.0,实验性 API(MAAI001
程序集:Microsoft.Agents.AI(核心包) · 源码目录:dotnet/src/Microsoft.Agents.AI/Harness/Todo/

1. Todo 模块的职责

给智能体一份会话级待办清单,让它在执行多步复杂任务时能把任务拆成可追踪的条目、逐项完成、随时增删。它本质上是一个AIContextProvider:每次调用前往系统指令里注入"怎么用待办清单"的守则,并把 5 个待办操作工具暴露给模型;同时在每轮调用开头注入一条合成消息,把当前待办列表"念给模型听",确保它始终知道还有哪些事没干完。

待办状态存在会话状态袋(AgentSessionStateBag)里,跨同一会话的多次调用保持;不同会话互相隔离。

2. 如何理解 Todos

把 Todos 想象成智能体随手贴在桌面上的一叠便利贴清单——接到一个多步骤的活儿时,它先把活儿拆成一条条“待办”写下来,干完一条划掉一条;你随时能凑过去看它写了什么、还剩几条没干。

举个例子。你对一个研究助理说:

“帮我调研 A、B、C 三家云厂商的 Serverless 冷启动延迟,最后给一份对比报告。”

这是个典型的多步骤任务。智能体不会闷头一次写完,而是(在默认守则引导下)先判断“这活儿复杂”,于是调todos_add把它拆成一串待办:

1 [open] 调研 A 厂商冷启动延迟 2 [open] 调研 B 厂商冷启动延迟 3 [open] 调研 C 厂商冷启动延迟 4 [open] 汇总对比、撰写报告

接下来它一条条推进:查完 A 就调todos_complete把 #1 划成 done,再往下走。你中途插一句“顺便加上 D 厂商”,它就调todos_add添一条;你要是改主意说“算了,不看 C 了”,它会调todos_remove把 #3 删掉。(如果你跑起了 Harness 的 Console 示例,输入/todos就能看到这份清单的实时状态)

反过来,如果你只是问一句“现在几点”这种一步就能答的简单问题,智能体不会建待办——默认守则明确要求它先分辨“复杂 vs 简单”,简单的直接做,别为难自己搞一堆清单。

它解决什么问题、为什么值得用

大语言模型的“记性”受上下文窗口限制,长任务里很容易忘掉前面定好的步骤、漏掉某一环、或跑着跑着跑偏。Todos 的本质是把计划从“对话里的一段话”外化成一份结构化、会持久化的状态,好处有四:

  • 不掉步、不跑偏:每轮调用开头,MAF 都会把当前清单重新“念”给模型(一条合成 user 消息),它始终清楚“还剩哪些没干”。

  • 天然支持“先规划、后执行”:把一个模糊的大请求变成可确认、可追踪的计划——配合AgentMode的 plan / execute 就是一条完整的规划闭环。

  • 抗上下文压缩:待办存在会话状态袋里,不是普通对话消息,因此不会被 Compaction 当作旧消息压缩掉;哪怕历史被砍,计划还在。

  • 可自主、可观测:Loop 能读它判断“是否全部干完”来决定要不要再跑一圈(无人值守续跑);宿主代码 / UI 也能读它给人看实时进度。

一句话:Todos 让智能体从“一次性尽力而为”变成“有计划、能追踪、可恢复、看得见”。

3. Todos 的生命周期

Todos 的“创建 → 改状态 → 删除”全部由模型的工具调用驱动,而“每轮把清单念给模型”则由MAF 自动注入。下面按时间线拆开。

3.1 默认守则如何指挥模型动手

TodoProvider注入的DefaultInstructions决定了模型“何时该建 / 改 / 删”:

  1. 先判断任务是复杂(多步)还是简单(一步)。

  2. 复杂 → 拆成待办、todos_add进清单;简单 → 不建待办,直接做。

  3. 需要澄清时先问用户,再据此建待办。

  4. 用户对计划有反馈 → 增删条目调整;用户切换话题 / 改主意 → 移除无关项、清空或重建清单。

  5. 执行中随手todos_complete标记完成、todos_remove删掉不再需要的。

3.2 状态与条目的生命周期

阶段

触发者

发生了什么

状态创建

首次访问

第一次调用 Provider / 工具时,GetOrInitializeState懒创建一个空TodoStateItems=[]NextId=1),存进会话状态袋(key =TodoProvider

条目创建

todos_add

每条分配Id = NextId++(从 1 起),Title / Description 去首尾空白,IsComplete默认 false,写回状态

状态变更

todos_complete

按 ID 把未完成项的IsComplete置 true;只有确实完成 ≥1 条才写回。reason只引导模型说清“怎么完成的”,不落盘

条目删除

todos_remove

按 ID 批量删除;删掉 ≥1 条才写回。ID 不回收NextId只增不减,删了也不复用)

清空

todos_remove

没有专门的 clear 工具——“清空”就是模型把条目全删掉;底层TodoStateNextId仍在,不重置

状态销毁

会话结束

待办状态随会话生命周期存在,跨同一会话多次调用一直保持;MAF 不做自动过期 / 清理。会话被丢弃时状态随之消失,不同会话相互隔离

3.3 每轮自动注入清单

每次调用前,MAF 把当前清单格式化成一条合成 user 消息注入(形如### Current todo list加上- {id} [open/done] {title}: {desc},空清单则为- none yet),受SuppressTodoListMessage/TodoListMessageBuilder控制。这一步不增删条目,但它是“模型每轮都记得清单”的关键。

关键点:清单不会“自动清理”。一条待办从建立到消失,中间每一次状态变化都对应模型的一次显式工具调用;MAF 只负责持久化和每轮提醒,不替模型做增删决策。

4. 类型清单

类型

可见性

种类

职责

TodoProvider

public

AIContextProvider

,IDisposable

模块主体:注入指令、暴露工具、维护状态

TodoProviderOptions

public

配置类

自定义指令、是否注入清单消息、清单消息格式

TodoItem

public

数据模型

单个待办项(Id / Title / Description / IsComplete)

TodoState

internal

会话状态

持有List<TodoItem>与自增NextId

TodoItemInput

internal

工具入参

todos_add

的入参(Title / Description)

TodoCompleteInput

internal

工具入参

todos_complete

的入参(Id / Reason)

5. 相关类型解析

5.1 TodoProvider

模块主体,继承AIContextProvider、实现IDisposable。核心职责有三:

  • 注入上下文:覆写的ProvideAIContextAsync返回一个AIContext,里面装着待办使用守则(Instructions)、5 个工具(Tools),以及(默认情况下)一条合成 user 消息——把当前待办列表格式化后注入,让模型每轮开头就看到"还剩哪些没干"。

  • 维护状态:通过ProviderSessionState<TodoState>在会话状态袋里申请一个独立 key 存取TodoState

  • 线程安全:所有读写都用"每会话一把锁"(SemaphoreSlim,按AgentSessionConditionalWeakTable缓存;无会话时用一把兜底锁)序列化,避免并发产生重复 ID、丢更新或脏读。

它还对外暴露两个公开方法,供宿主代码绕过模型直接读状态(官方示例的/todos控制台命令即用此实现):

  • GetAllTodosAsync(session, ct)—— 取全部待办(含已完成)。

  • GetRemainingTodosAsync(session, ct)—— 只取未完成的。

注意:这两个方法返回的是内部状态里的活引用(live reference),改它们的属性会直接改动 Provider 状态。

5.2 TodoProviderOptions

控制TodoProvider行为的可选配置:

  • Instructionsstring?)—— 整段替换默认注入的待办守则。默认守则会教模型"先判断任务复杂度,复杂才拆 todo,简单直接做"。

  • SuppressTodoListMessagebool)—— 关掉"每轮注入当前清单"的合成消息。默认false(即会注入)。

  • TodoListMessageBuilderFunc<IReadOnlyList<TodoItem>, string>?)—— 自定义那条清单消息的文本格式。不设则用内置格式化。

5.3 TodoItem

公开数据模型,一个待办项就是它:

  • Idint)—— 会话内自增的唯一标识,从 1 起。

  • Titlestring)—— 标题。

  • Descriptionstring?)—— 可选描述。

  • IsCompletebool)—— 是否已完成。

字段都带[JsonPropertyName],因为它要随会话状态序列化持久化。

5.4 内部类型

  • TodoState—— 会话状态本体,持有ItemsList<TodoItem>)和NextId(下一个要分配的自增 ID,从 1 起)。

  • TodoItemInput——todos_add工具的入参形状:Title+ 可选Description

  • TodoCompleteInput——todos_complete工具的入参形状:Id+Reason

6. 暴露给模型的工具

TodoProvider通过AIFunctionFactory.Create(...)动态生成 5 个工具:

工具名

入参

返回

说明

todos_addList<TodoItemInput>

新建的TodoItem列表

一次可加一个或多个,自动分配自增 ID

todos_completeList<TodoCompleteInput>

实际标记完成的条数

按 ID 把未完成项标记为完成

todos_removeList<int>

(ID 列表)

实际删除的条数

按 ID 删除待办项

todos_get_remaining

未完成的TodoItem列表

查还剩哪些

todos_get_all

全部TodoItem列表

查全量(含已完成)

7. 行为要点

  • ID 从 1 起自增,由TodoState.NextId维护,删除不回收 ID。

  • todos_completereason不持久化:入参里要Reason,但代码只把对应项的IsComplete置为true,并不存这个理由。它的作用是引导模型"说清为什么算完成了"(对模型推理与日志有益),而非写进状态。这是个容易误以为"理由被存下来了"的反直觉点。

  • 每轮注入合成消息:默认每次调用都会把当前清单作为一条 user 消息注入(受SuppressTodoListMessage/TodoListMessageBuilder控制)。这依赖管线里的消息注入能力把"第三方造的 user 消息"插到正确位置。

  • 批量友好:增 / 删 / 完成都支持一次传多个,鼓励模型在一次工具调用里处理一批,减少往返。

8. 与其它模块的关系

  • HarnessAgent(门面):默认装配TodoProvider,用HarnessAgentOptions.DisableTodoProvider关闭。

  • LoopTodoCompletionLoopEvaluatorTodoProvider的状态,判断"待办是否全部清空"来决定循环是否继续。

  • AgentMode:默认的plan模式守则里就要求"把任务拆成 todo",两者在"先规划后执行"工作流里配合。

  • Console 脚手架/todos命令通过agent.GetService<TodoProvider>()拿到 Provider 后调GetAllTodosAsync,不发起模型调用就打印清单。

9. 扩展与最佳实践

可定制的三个扩展点(都在TodoProviderOptions,构造TodoProvider时传入):

  • Instructions—— 整段替换默认守则。想改语气、改成中文、或收紧 / 放宽“何时拆 todo”的纪律时用它;不传就用内置守则(已覆盖大多数场景)。

  • SuppressTodoListMessage—— 关掉“每轮注入当前清单”的合成消息。默认不要关:它是模型不掉步的关键。只有当你已用别的方式让模型看到进度、又想省 token 时才考虑关。

  • TodoListMessageBuilder—— 自定义那条清单消息的文本格式(比如换成表格、加优先级列)。

最佳实践:

  • 把 Todos 当“工作便签”,别当持久业务数据。它是会话级、模型驱动的:会话结束即失、reason不落盘、ID 删了不回收。需要审计或长期留存的清单,另建业务存储,别指望 Todo 状态。

  • 做实时待办 UI 就走读方法。用GetAllTodosAsync/GetRemainingTodosAsync直接读,别为了拿清单去发一次模型调用。注意返回的是内部状态的活引用——UI 只读、别改属性,否则会串改 Provider 状态。

  • 配合 Loop 自主续跑时务必设安全阀TodoCompletionLoopEvaluator会“待办没清完就再跑一圈”,一定要给LoopAgentOptions.MaxIterations兜底,避免模型迟迟不收敛导致空转。

  • 待办的增 / 改 / 删交给模型经工具完成。模块对宿主只开放了读方法(无宿主侧的增 / 删 API),这样清单与模型的认知才不会脱节。

10. 小结

Todo 是 Harness 里最轻、最独立的一块积木:一个AIContextProvider+ 5 个工具 + 一份会话状态,解决"长任务里模型容易忘记自己要干什么"的问题。它的设计取舍很清楚——状态会话隔离、操作批量化、每轮把清单念给模型、并发用每会话锁兜底;同时把GetAllTodosAsync等读方法开放给宿主,方便做实时待办 UI。

下一篇

引入地址

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/27 10:52:54

3DS游戏格式转换终极指南:5分钟掌握3dsconv工具

3DS游戏格式转换终极指南&#xff1a;5分钟掌握3dsconv工具 【免费下载链接】3dsconv Python script to convert Nintendo 3DS CCI (".cci", ".3ds") files to the CIA format 项目地址: https://gitcode.com/gh_mirrors/3d/3dsconv 还在为3DS游戏文…

作者头像 李华
网站建设 2026/7/27 10:52:29

3步搞定!用Dashy打造企业级Proxmox监控中心的完整指南

3步搞定&#xff01;用Dashy打造企业级Proxmox监控中心的完整指南 【免费下载链接】dashy &#x1f680; A self-hostable personal dashboard built for you. Includes status-checking, widgets, themes, icon packs, a UI editor and tons more! 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/7/27 10:52:23

TPS65919-Q1 GPIO与GPADC模块配置详解与实战应用

1. 深入理解TPS65919-Q1的GPIO与GPADC模块在汽车电子和工业控制这类对可靠性和实时性要求极高的领域&#xff0c;一颗集成了复杂电源管理和丰富接口的PMIC&#xff08;电源管理集成电路&#xff09;往往是系统稳定运行的基石。德州仪器&#xff08;TI&#xff09;的TPS65919-Q1…

作者头像 李华
网站建设 2026/7/27 10:51:56

拼团与优惠券工具在教培机构招生中的应用效果研究——BBWEYY GEO服务解决教培机构获客难题,含零代码SAAS、AI编程、源码定制交付

拼团与优惠券工具在教培机构招生中的应用效果研究——BBWEYY GEO服务解决教培机构获客难题 基于数字化工具与招生流程协同的应用研究 摘要&#xff1a;在获客成本上升、家长决策周期延长和渠道碎片化的背景下&#xff0c;中小教培机构需要从单次广告投放转向可沉淀、可测量、…

作者头像 李华
网站建设 2026/7/27 10:51:44

实测4款AI工具,AI专著写作不再难,20万字专著轻松一键生成!

学术专著写作与AI工具的应用 学术专著的核心在于严密的逻辑推理&#xff0c;但这也是写作过程中最难掌握的部分。专著写作必须围绕中心观点展开详细分析&#xff0c;不仅要充分说明每个论点&#xff0c;还要应对各种不同学派的争论&#xff0c;保证整个理论体系前后一致&#…

作者头像 李华
网站建设 2026/7/27 10:50:20

SpringBoot+Vue非遗文化管理系统全栈开发实践

1. 项目概述&#xff1a;当非遗文化遇上全栈技术 甘肃作为丝绸之路黄金段&#xff0c;拥有花儿、皮影、香包刺绣等多项国家级非物质文化遗产。传统的线下展示方式受限于时间和空间&#xff0c;而简单的静态网页又难以实现动态管理和交互体验。这个基于SpringBootVue的全栈项目&…

作者头像 李华