【Agent工程】7—— 单 Agent 任务闭环文章目录【Agent工程】7—— 单 Agent 任务闭环1. 单轮对话不等于任务闭环2. 闭环的六个阶段2.1 启动前校验不可跳过2.2 阶段边界不要混用3. 运行时上下文与状态机3.1 预算在循环内递减3.2 收集终态从哪来4. 贯穿示例工单升级闭环4.1 失败与降级路径4.2 对话层与编排层的分工5. 可运行示意最小编排器5.1 闭环主流程5.2 待确认与降级路径6. 与前几篇的衔接关系6.1 轨迹字段约定6.2 结案类型与对外展示7. 四个常见误区7.1 编排器与模型 API 的边界8. 适用边界8.1 从对话式原型迁移8.2 最小可观测性9. 术语速查10. 小结与下一篇摘要前几篇分别解决了任务卡片、验收、工具门禁与高危写确认。若运行时仍是一问一答、模型说完就算结束这些能力无法串成可判定流程。本篇描述单 Agent 任务闭环校验卡片、注入上下文、推理执行、收集终态、跑验收、结案或降级。贯穿示例继续用工单助手。适合读完 【Agent工程】6—— 危险写操作与二次确认、准备把分散模块收成一条运行链路的工程师。读完可以独立完成实现一版最小编排器驱动一张卡片从启动到验收。1. 单轮对话不等于任务闭环常见 Agent 服务形态是用户发一句 → 模型多轮 tool call → 返回一段总结。对话结束但系统不知道任务是否可验收地完成。单轮对话任务闭环结束条件 模型不再输出结束条件 验收通过或明确降级工具调用散落在聊天里轨迹写入 runtime context失败靠人工看日志失败有可复现状态与报告本专栏前几篇已经具备闭环所需的零件【Agent工程】2—— 模糊目标到任务卡片结构化输入【Agent工程】3—— 验收命令与完成定义完成判定【Agent工程】4—— 工具注册表与读写分离工具目录与门禁【Agent工程】5—— 工具作用域与对象级授权对象级授权【Agent工程】6—— 危险写操作与二次确认高危写 pending本篇回答这些零件在运行时按什么顺序衔接。编排单元从单 Agent 开始多 Agent 委托放在后续篇目。2. 闭环的六个阶段单 Agent 处理一张任务卡片建议固定六阶段顺序不要随模型「灵感」调整阶段输入输出1. 校验卡片自然语言或草稿卡片通过 / 拒绝启动2. 注入上下文合法卡片runtime context3. 推理执行上下文 模型工具轨迹、pending4. 收集终态业务系统 轨迹final_state5. 跑验收卡片 acceptance 终态验收报告6. 结案报告done / degraded / 待人工阶段 3内部仍走第 46 篇的门禁注册表 → scope → 高危 pending。阶段 5区分自动项与人工项口径与第 3 篇一致。编排器可以是独立进程也可以嵌在主服务里关键是六阶段的顺序与输入输出固定而不是某一家框架的类名。团队先用脚本把六阶段跑通再考虑接入 LangGraph、Temporal 等外部编排避免反过来被框架绑架阶段语义。2.1 启动前校验不可跳过卡片校验至少检查目标、允许工具、验收非空write_ticket_ids或等价 scope 存在写任务预算字段有上限步数或写调用次数校验失败应直接返回不启动模型。否则会出现「跑到一半才发现验收没写」的半成品任务。2.2 阶段边界不要混用六阶段里推理执行与跑验收的职责必须分开。常见错误是把验收逻辑写进系统提示让模型自己判断「做完了没有」。模型在阶段 3 只负责提议工具是否 done 由阶段 5 的验收运行器根据final_state决定。混用后轨迹里缺少结构化终态评测集也无法稳定回归。3. 运行时上下文与状态机每张卡片实例化一份runtime context运行时上下文生命周期与卡片绑定不跨卡片复用 scope 或轨迹。字段用途card_id关联卡片与审计allowed_tools, scope传给工具门禁budget步数、写调用、pending 上限trace.used_tools验收核对子集trace.pending_ids高危写确认链final_state验收输入status状态机当前值状态机建议至少包含状态含义pending已校验尚未开始推理running模型推理与工具调用中await_confirm存在未批准 pending执行暂停accepting执行结束跑验收done自动验收通过且无待人工项degraded超时、拒绝或部分失败有降级标记从await_confirm超时应转入degraded而不是无限等待。降级结果也要写入终态供验收解释「为何无 notified」。3.1 预算在循环内递减预算来自卡片典型字段{budget:{max_steps:12,max_write_calls:5,max_pending:2}}每发生一次模型步进、写工具执行或 pending 创建对应计数减一。归零时编排器应停止继续调模型进入「收集终态 → 验收」而不是悄悄放宽上限。3.2 收集终态从哪来阶段 4 的final_state应优先来自只读查询而不是模型口述字段建议来源priority, comment工单 API 查询notified通知回执或 pending 执行结果used_toolsruntime trace不用聊天解析查询键如 ticket_id来自卡片 scope。终态收集失败时不应标记为 done而应进入 failed 或 degraded并在报告里写明「终态不可达」。4. 贯穿示例工单升级闭环目标将T-1024升为紧急并通知值班。卡片含 scope、允许工具、验收与auto_confirm: false。步骤运行时动作校验确认write_ticket_ids[T-1024]验收含 priority 与 notify执行update_ticket_priority直接执行notify_oncall入 pending等待状态await_confirmAgent 不再重复 notify确认值班 approve 后执行通知写入notifiedTrue验收自动项检查 priority、comment、notify人工项检查措辞结案全通过 →donenotify 被拒 →degraded并记录原因闭环里模型不负责宣告完成。编排器在阶段 5 根据验收报告设置status对话摘要仅作展示。4.1 失败与降级路径情况建议处理工具门禁拒绝记录 reason模型可换方案超步数则进入验收pending 被拒degraded验收检查降级字段pending 超时同上标记「通知待人工补发」验收自动项失败不进入done可触发重试策略或人工接管重试策略应有限次、可配置且不能绕过门禁。常见做法是同一张卡片最多重跑 1 次推理仍失败则输出验收报告给值班。4.2 对话层与编排层的分工用户看到的聊天摘要应由编排器在结案后生成输入是验收报告与final_state而不是模型在阶段 3 的即兴总结。这样即使模型说「已完成」只要验收未通过对外状态仍是 failed 或 await_manual避免感觉完成与断言完成再次分叉见第 3 篇。5. 可运行示意最小编排器下面代码把校验、模拟执行、验收串成一条链。工具实现仍用占位函数重点看阶段顺序与状态变迁。5.1 闭环主流程from__future__importannotationsfromtypingimportAnydefvalidate_card(card:dict[str,Any])-dict[str,Any]:missing[]ifnotcard.get(goal):missing.append(goal)ifnotcard.get(allowed_tools):missing.append(allowed_tools)ifnotcard.get(acceptance):missing.append(acceptance)ifnot(card.get(scope)or{}).get(write_ticket_ids):missing.append(scope.write_ticket_ids)budgetcard.get(budget)or{}ifbudget.get(max_steps)isNone:missing.append(budget.max_steps)ifmissing:return{ok:False,missing:missing}return{ok:True}defrun_acceptance(card:dict[str,Any],final_state:dict[str,Any])-dict[str,Any]:acccard[acceptance]failed[]iffinal_state.get(priority)!acc.get(priority_equals):failed.append(priority_ok)ifacc.get(notify_required)andnot(final_state.get(notified)orfinal_state.get(notify_degraded)):failed.append(notify_ok)usedset(final_state.get(used_tools)or[])allowedset(card[allowed_tools])ifnotused.issubset(allowed):failed.append(tools_ok)manual[]ifacc.get(manual_tone_review):manual.append(tone_review)auto_passedlen(failed)0passedauto_passedandnotmanualreturn{auto_passed:auto_passed,passed:passed,failed:failed,manual:manual,}defrun_task_loop(card:dict[str,Any],executor_result:dict[str,Any])-dict[str,Any]:checkvalidate_card(card)ifnotcheck[ok]:return{status:rejected,reason:invalid_card,**check}ctx:dict[str,Any]{card_id:card.get(card_id,local),status:running,trace:executor_result.get(trace,{}),}ifexecutor_result.get(await_confirm):ctx[status]await_confirmreturnctx ctx[status]acceptingfinal_stateexecutor_result[final_state]reportrun_acceptance(card,final_state)ctx[acceptance]reportifreport[passed]:ctx[status]doneelifreport[auto_passed]andreport[manual]:ctx[status]await_manualeliffinal_state.get(notify_degraded):ctx[status]degradedelse:ctx[status]failedctx[final_state]final_statereturnctxif__name____main__:card{card_id:card-100,goal:将 T-1024 升级为紧急并通知值班,allowed_tools:[get_ticket,update_ticket_priority,notify_oncall,],scope:{write_ticket_ids:[T-1024]},acceptance:{priority_equals:urgent,notify_required:True,manual_tone_review:False,},budget:{max_steps:12,max_write_calls:5,max_pending:2},}executor_result{await_confirm:False,trace:{used_tools:[update_ticket_priority,notify_oncall]},final_state:{ticket_id:T-1024,priority:urgent,notified:True,used_tools:[update_ticket_priority,notify_oncall],},}print(run_task_loop(card,executor_result))5.2 待确认与降级路径if__name____main__:card{card_id:card-101,goal:将 T-1024 升级为紧急并通知值班,allowed_tools:[update_ticket_priority,notify_oncall],scope:{write_ticket_ids:[T-1024]},acceptance:{priority_equals:urgent,notify_required:True,},budget:{max_steps:12},}blockedrun_task_loop(card,{await_confirm:True,trace:{pending_ids:[p-abc]},final_state:{},},)assertblocked[status]await_confirmdegradedrun_task_loop(card,{await_confirm:False,trace:{used_tools:[update_ticket_priority]},final_state:{priority:urgent,notified:False,notify_degraded:True,used_tools:[update_ticket_priority],},},)assertdegraded[status]degradedprint(待确认暂停与 notify 降级路径正常)真实系统里阶段 3 的 executor 应调用模型与工具网关本篇编排器只规定何时停、何时验、如何结案。联调时建议用同一张工单卡片跑三条路径全成功 done、notify pending 阻塞、notify 降级 degraded。三条路径的 status 与验收报告应可重复生成便于接入 CI 回归。6. 与前几篇的衔接关系本篇阶段依赖的前文能力校验卡片第 2 篇字段定义工具调用第 4 篇注册表与门禁对象校验第 5 篇 scope高危写第 6 篇 pending结案第 3 篇验收报告闭环本身不替代任何一层。少一层就会在对应阶段失焦无 scope 则越权在轨迹里爆炸无 pending 则 notify 误发无验收则done只是主观判断。阶段 3 与阶段 4 之间建议留一个显式「执行结束」信号可以是模型输出结构化finish、也可以是编排器发现连续两轮无 tool call。没有该信号时不要提前拉终态否则容易在 notify 仍 pending 时误跑验收。6.1 轨迹字段约定建议在trace中统一记录used_tools注册表认可的 tool_id 列表rejected_calls门禁拒绝明细含 reasonpending_ids及最终 approved / rejected 状态step_count实际消耗步数验收与评测集应直接消费这些字段而不是解析聊天文本。6.2 结案类型与对外展示status对外含义典型后续done自动验收全通过关单await_manual自动通过人工项待确认待复核队列degraded有降级标记人工补通知等failed验收自动项失败重试或接管await_confirmpending 未决值班 approveUI 与 webhook 应订阅 status而不是订阅模型最后一句话。7. 四个常见误区误区典型表现更稳妥的做法无预算模型循环调工具卡片写 max_steps编排器强制停止跳过卡片校验自然语言直接开跑阶段 1 失败即返回pending 不阻塞验收时 notify 缺失await_confirm 暂停执行终态靠对话外部字段未拉取阶段 4 拉业务快照还有一种隐蔽做法把验收写在提示词里让模型「自检」。模型自检不能替代第 3 篇验收运行器闭环的阶段 5 必须读final_state与trace不能读模型总结。7.1 编排器与模型 API 的边界编排器负责阶段顺序、预算、状态机、调用门禁与 pending 回调。模型 API 负责在允许工具范围内提议下一步。不要把门禁逻辑写进 prompt 指望模型遵守也不要让模型直接修改status字段。两者接口清晰后续换模型或换工具实现时编排层可以保持稳定。8. 适用边界本篇方法适合单 Agent、单卡片、串行执行工具面已具备门禁与 pending需要可判定 done / failed / degraded本篇不覆盖多 Agent 分工与委托——下一篇编排单元展开并行子任务、队列调度——后续运行时篇目长时运行跨小时 human-in-the-loop——需持久化 context若任务极短、只有只读查询闭环可简化跳过 pending 相关状态但仍建议保留校验与验收骨架便于日后加写工具时不改架构。8.1 从对话式原型迁移存量对话式 Agent 迁移可以分三步补卡片与验收先把现有 prompt 里的目标、工具、完成条件抽成字段外挂编排器模型 API 不变工具调用改经门禁与 trace改结束条件由编排器根据验收设 statusUI 不再以「模型停止」为准每一步都可以单独上线但只有当第三步完成系统才称得上任务闭环。8.2 最小可观测性闭环上线时至少暴露以下指标便于值班与回归指标用途卡片校验失败率输入质量各 status 计数done / degraded 比例平均 step_count预算是否合理pending 平均等待时长值班响应指标应从 runtime context 汇总不要从聊天日志反推。9. 术语速查术语含义任务闭环从卡片校验到验收结案的完整运行链路运行时上下文单张卡片执行期的状态与轨迹容器编排器驱动阶段顺序、预算与状态机的组件final_state验收用的业务终态快照degraded部分完成或降级后的非成功结案状态await_confirm等待高危写 pending 批准时的暂停状态10. 小结与下一篇单 Agent 任务闭环把前几篇能力串成固定顺序校验卡片再启动拒绝半成品输入runtime context绑定卡片轨迹与 scope 不跨任务漂移推理执行走工具门禁与 pending预算在环内递减收集终态后跑验收用报告驱动 done / degraded下一篇继续编排单元多个子 Agent 如何分工、委托范围与成本如何控制避免「单 Agent 闭环」复制多份却无人协调。系列导航上一篇【Agent工程】6—— 危险写操作与二次确认下一篇【Agent工程】8—— 子 Agent 分工与委托边界撰写中