公司动态

Microsoft Agent Framework — Harness 模块:AgentMode

📅 2026/7/27 10:54:14
Microsoft Agent Framework — Harness 模块:AgentMode
目录1. 模块职责2. 从一个例子理解 AgentMode它解决什么问题、为什么值得用3. 模式的切换与运转3.1 默认守则如何指挥模型3.2 运行时状态一览3.3 两条切换路径的关键区别4. 类型清单5. 逐类型解析5.1 AgentModeProvider5.2 AgentModeProviderOptions5.3 AgentMode嵌套类型5.4 AgentModeStateinternal6. 暴露给模型的工具7. 行为要点8. 与其它模块的关系9. 扩展与最佳实践10. 小结上一篇基于 MAF .NET1.13.0实验性 APIMAAI001。 程序集Microsoft.Agents.AI核心包 · 源码目录dotnet/src/Microsoft.Agents.AI/Harness/AgentMode/1. 模块职责给智能体一台模式状态机让它在长任务里于若干操作模式间切换不同模式遵循不同的工作流。默认提供两种模式plan交互式规划——问清楚、出计划、等用户批准再动手和execute自主执行——不打扰用户、自己干到出结果。当前处于哪个模式会被写进系统指令模型每轮都能看到自己该按哪套流程办事。它也是一个AIContextProvider注入模式守则 各模式说明 当前模式并暴露查看/切换模式的工具。模式状态存在会话状态袋里跨同一会话保持。2. 从一个例子理解 AgentMode把 AgentMode 想象成智能体的“档位”——同一个智能体挂在“规划档”和“执行档”上会表现出两种截然不同的做事方式。举个例子。你把一个大任务交给研究助理“帮我调研三家云厂商的 Serverless 冷启动延迟出一份对比报告。”在plan规划模式下它像个谨慎的顾问先分析需求、把任务拆成待办需要时做点探索性检索然后一条条向你澄清还会把可选项列出来让你挑把计划写进文件记忆最后把计划摆给你、请你批准——没拿到批准绝不动手。你点头批准后它切到execute执行模式画风突变不再问你、也不等反馈凭最合理的判断自主推进遇到模糊就选个最靠谱的选项记下来继续走一条条标记完成直到把结果交出来。同一个智能体、同一段业务指令就因为“当前档位”不同行为逻辑完全不一样——这就是模式机在管的事。跑起 Harness 的 Console 示例时输入/mode就能看到 / 切换当前档位。它解决什么问题、为什么值得用一个能干长活的智能体往往需要在不同阶段有互相冲突的行为准则规划时要“多问、等批准”执行时要“少问、自主干”。把这两套准则硬塞进同一份指令模型很容易精神分裂或跑偏。AgentMode 的本质是把行为准则按“模式”分档只把当前模式的准则写进系统指令好处有三一个智能体多种人格互不打架规划的克制与执行的果断被拆到不同模式当前该用哪套模型每轮都从系统指令里看得一清二楚。人机协作的闸门plan模式把“先对齐、拿到批准再动手”做成硬规则避免智能体一上来就闷头执行、方向跑偏还收不住。可编程的阶段控制宿主 / UI 能用GetMode/SetMode读写当前模式把“现在是规划还是执行”变成一个可驱动确定性界面的状态Console 示例的规划 UX 就靠它判断该渲染成“带选项的追问”还是“流式执行输出”。3. 模式的切换与运转AgentMode 本质是一台状态机模式是预定义的固定集合运行期并不“创建 / 销毁模式”只是把CurrentMode在它们之间切换。下面拆三块看它怎么运转——守则怎么指挥、状态怎么随会话存续、切换的两条路径有何不同。3.1 默认守则如何指挥模型AgentModeProvider注入的DefaultInstructions定了模型“怎么用模式”用mode_get查当前模式、用mode_set切模式**除非用户明确允许否则别自行mode_set**。每个实质性请求哪怕是简短的事实问题都按当前模式的流程办。各模式的具体流程写在该模式的Description里见 5.3——plan是 7 步交互式规划分析 → 拆 todo → 探索性检索 → 逐条澄清 → 计划写进文件记忆 → 请求批准 → 批准后mode_set(execute)execute是自主执行先分辨简单 / 复杂复杂则不问用户、遇模糊选最合理项并记录、逐条标记完成、干到出结果。3.2 运行时状态一览阶段触发者发生了什么状态创建首次访问第一次读 / 写模式时GetOrInitializeState懒创建AgentModeStateCurrentMode取构造时定的初始模式DefaultMode默认为模式列表第一个即默认配置下的plan存进会话状态袋key AgentModeProvider模型自切mode_set工具模型自己调mode_set校验合法 → 直接改CurrentMode存回。不记前一模式、不注入切换通知——模型自己刚切的本就知道外部切换SetMode宿主宿主调SetMode如/mode命令、规划审批通过校验 → 改CurrentMode**若与原模式不同记下PreviousModeForNotification**供下一轮注入切换通知每轮注入每次调用前ProvideAIContextAsync把{current_mode}与{available_modes}各模式渲染成“#### 名字 说明”填进系统指令若有待通知的外部切换再注入一条[Mode changed: 从 X 切到 Y现按 Y 办事]的 user 消息随后清空该标记状态销毁会话结束模式随会话生命周期存在跨同一会话多次调用一直保持JSON 序列化持久化会话被丢弃时状态随之消失不同会话相互隔离MAF 不做自动过期3.3 两条切换路径的关键区别模式能被切换的两条路径已在上表列出模型经mode_set、宿主经SetMode它们最要紧的差异是下一轮要不要额外提醒模型关键点“自己切”静默、“被人切”才广播。模型经mode_set切换是无声的它自知只有宿主经SetMode切换下一轮才会多注入一条[Mode changed: ...]逼模型明确改按新模式办事。这条区别是模式机能和 Console 规划 UX批准即切 execute严丝合缝配合的关键。4. 类型清单类型可见性种类职责AgentModeProviderpublicAIContextProvider模块主体注入模式指令、暴露工具、维护当前模式AgentModeProviderOptionspublic配置类自定义指令、模式集合、初始模式AgentModeProviderOptions.AgentModepublic嵌套类型数据模型一个模式 名字 说明AgentModeStateinternal会话状态当前模式 待通知的前一模式5. 逐类型解析5.1 AgentModeProvider模块主体。构造时对模式集合做严格校验——每个模式不能为 null、名字不能为空白、名字不能重复否则抛ArgumentException初始模式取DefaultMode未设则取列表第一个且必须在模式集合内。运行期职责注入上下文ProvideAIContextAsync把指令模板里的{available_modes}渲染成各模式的#### 名字 说明列表和{current_mode}当前模式名替换成真值后注入。响应外部改模式如果模式是被外部改的比如控制台/mode命令调了SetMode会额外注入一条[Mode changed: ...]的 user 消息明确告诉模型模式从 X 切到了 Y现在按 Y 办事——不让它只靠系统指令里的静态文字去察觉变化。公开方法供宿主代码直接读写不经模型GetMode(session)—— 读当前模式名。SetMode(session, mode)—— 改当前模式若与原模式不同会记下前一模式以便下轮注入切换通知传入非法模式名抛ArgumentException。5.2 AgentModeProviderOptionsInstructionsstring?—— 整段替换默认模式守则。必须包含两个占位符{available_modes}注入模式清单和{current_mode}注入当前模式。ModesIReadOnlyListAgentMode?—— 替换默认的plan/execute定义你自己的模式集合。DefaultModestring?—— 新会话的初始模式须匹配Modes里某个模式名不设则用列表第一个。5.3 AgentMode嵌套类型一个模式的数据模型只有两个只读属性构造时Name与Description都要求非空白空串或纯空白都会抛ArgumentExceptionName—— 模式名模型用mode_set切换时传的就是它。Description—— 这个模式何时用、怎么用的说明会被渲染进系统指令是真正约束模型行为的地方。默认两个模式的Description写得很长plan内置 7 步分析 → 拆 todo → 探索性检索 → 逐条向用户澄清 → 把计划写进文件记忆 → 请求批准 → 调mode_set(execute)execute内置 5 步必要时补计划 → 自主推进不问用户 → 遇模糊选最合理项 → 标记完成 → 持续到出结果。5.4 AgentModeStateinternal会话状态本体CurrentMode—— 当前模式。字段默认值是plan但新会话的实际初始模式由 Provider 按DefaultMode设定见 3.2并非总是plan。PreviousModeForNotification—— 非空时表示模式刚被外部改过下轮要注入切换通知注入后即清空。6. 暴露给模型的工具工具名入参返回说明mode_setstring mode确认文本切换模式先校验合法性再保存mode_get无当前模式名查当前模式7. 行为要点当前模式进系统指令模式不是靠注入消息维持而是每轮把{current_mode}填进系统指令——系统提示权重更高、也能吃到 prompt 缓存。外部改模式才注入通知消息只有走SetMode如/mode命令才会触发[Mode changed: ...]消息模型自己调mode_set不会重复注入它自己知道刚切了。**默认守则要求只有用户许可才切模式**默认指令里明确除非用户明确允许否则不要自行mode_set避免模型在 plan 阶段擅自跳到 execute。模式名大小写敏感校验用StringComparer.Ordinal。8. 与其它模块的关系HarnessAgent门面默认装配用DisableAgentModeProvider关闭用AgentModeProviderOptions自定义模式。Todoplan模式守则要求把任务拆成 todo两者共同支撑先规划后执行。LoopTodoCompletionLoopEvaluator可限定只在某些模式下生效如Modes [execute]即execute 模式下待办没清完就自动再跑一圈。Console 脚手架/mode命令经GetMode/SetMode读写模式PlanningOutputObserver这类规划 UX 也依赖它判断当前阶段模式关掉则规划 UX 退化。9. 扩展与最佳实践可定制的三个扩展点都在AgentModeProviderOptions构造AgentModeProvider时传入Modes——整套替换默认的plan/execute定义你自己的模式机比如triage → research → review。每个AgentModeNameDescription其中Description才是真正约束模型的地方会渲染进系统指令要把“这个模式何时用、按什么流程走”写足。构造时对模式集合严格校验非空、名字非空白、名字不重复。Instructions—— 整段替换默认模式守则。必须保留{available_modes}和{current_mode}两个占位符分别注入模式清单和当前模式漏了不会报错但模型就看不到模式信息、模式机形同虚设。想改语气、讲中文、或调整“何时允许切模式”的纪律时用它。DefaultMode—— 新会话的起始模式须是Modes里的某个名字不设则用列表第一个。最佳实践把行为差异写进各模式的Description别散落在业务指令里。模式机的威力来自“当前模式说明进系统指令”——把“规划该多问、执行该少问”这类差异集中到每个模式的Description比在一份大指令里写一堆 if-else 更可靠、也更好维护。plan → execute的切换留“用户批准”这道闸。默认守则明确“除非用户明确允许否则别自行mode_set”。上无人值守前先确认这道闸符合你的信任模型别轻易放开让模型自己跳到执行。宿主切模式一律走SetMode别绕过它直接改状态。SetMode会触发下一轮的[Mode changed: ...]通知让模型察觉若你自己 hack 状态容易出现“系统指令说 execute、模型却没收到切换信号”的错位。模式名保持稳定、大小写一致。校验是StringComparer.Ordinal大小写敏感mode_set(Execute)匹配不上模式execute会抛ArgumentExceptionUI / 命令里务必对齐大小写。自定义模式集要有能自我收尾的“终态”。若流程是plan → executeexecute的守则要能自己干到出结果默认execute就是这么设计的别设计出“卡在某模式推进不下去”的死档。10. 小结AgentMode 把智能体在不同阶段该有不同行为这件事做成了一台可配置、可编程读写的模式状态机。它的关键设计模式说明进系统指令强约束、外部切换才补注入通知让模型察觉、模式集合可整套替换不止 plan/execute。配合 Todo 与 Loop它是 Harness 规划—执行—自动续跑闭环里的阶段控制器。引入地址