作者:逆境不可逃

技术永无止境

希望我的内容可以帮助到你!!!!

本文承接《Agent 记忆不只是聊天记录:讲透会话、Profile、TaskState、召回与删除治理》。

如果记忆系统解决的是 “任务中断后如何记住做到哪里”,规划与执行系统解决的就是 “面对复杂目标,下一步做什么、如何验证、什么时候停止,以及何时把控制权交还给人类”。

摘要

很多 Agent Demo 的核心只是一个循环:模型思考、调用工具、读取结果,然后继续思考。它适合短任务,却很难直接承担真实业务中的长流程。一旦任务涉及多个依赖步骤、外部系统、副作用、审批、预算和失败恢复,就会出现计划不可执行、工具无限重试、任务重复运行、结果缺少证据、模型反复自我修正、失败后无法恢复等问题。

可靠的规划与执行系统,不是让模型 “想得更久”,而是建立受控的任务运行时:先把目标表示为 Goal Contract,再拆成 Milestone 和 Work Item;用 Workflow 管理全局阶段,用 Plan-and-Execute 管理任务依赖,用受限 ReAct 处理局部不确定性,用 Verification Contract 检查产物;同时通过 Attempt、Artifact、Checkpoint、Budget、Plan Version、Lease、Termination Record 和 Handoff Package 保证任务可追踪、可恢复、可停止、可接管。

本文围绕,以 “Payment SDK 迁移调研助手” 为贯穿案例,系统讲解任务拆解、状态表示、ReAct、Plan-and-Execute、Reflection、Workflow 与 Agent 的边界、终止与降级、人工接管以及端到端测试。目标不是做一个永远运行的自主 Agent,而是做一个在正确边界内自主、在证据不足时诚实停止的工程系统。

关键词

Agent、任务规划、ReAct、Plan-and-Execute、Workflow、Reflection、Checkpoint、幂等、预算控制、人工接管、后端工程


一、先纠正误解:复杂任务不是把单轮对话循环得更久

一个最小 Agent 往往长这样:

用户目标
→ 模型决定动作
→ 调用工具
→ 把结果交给模型
→ 模型继续决定
→ 直到模型说完成

这个模式可以完成天气查询、简单检索和单次数据转换,但复杂任务会提出更多工程问题:

  • 目标是否已经明确;
  • 哪些步骤必须先完成;
  • 哪些步骤可以并行;
  • 中间产物保存在哪里;
  • 工具超时后能否重试;
  • 重试会不会产生重复副作用;
  • 模型为什么认为任务已经完成;
  • 报告中的结论是否有证据;
  • 预算耗尽后返回什么;
  • 服务重启后从哪里恢复;
  • 哪些风险必须由人类确认。

如果这些问题都交给模型临场判断,系统就会变成一个不可预测的大循环。

真正可靠的执行链路应该是:

明确目标
→ 生成结构化计划
→ 校验计划
→ 按依赖调度任务
→ 受控调用工具
→ 保存中间产物
→ 校验结果
→ 必要时有限修正或重规划
→ 完成、降级、暂停或人工接管

核心变化不是 “模型能力更强”,而是应用层开始承担状态、边界和恢复责任。


二、四种机制分工:Workflow、Plan、ReAct 与 Reflection

规划与执行系统经常同时使用四种机制。它们不是竞争关系,而是不同控制层。

机制 解决的问题 适合范围 主要风险
Workflow 全局流程按什么阶段运行 稳定业务阶段、审批、等待、补偿 过度固定会缺少适应性
Plan-and-Execute 复杂目标如何拆解和调度 多里程碑、依赖任务、长期执行 计划陈旧或不可执行
ReAct 信息不足时下一步探索什么 局部检索、诊断、参数调整 无限循环、重复动作
Reflection 产物是否合格,能否修正 报告、代码、结构化结果 自我评价偏差、无限改写

推荐采用四层控制:

第一层:Workflow 管全局阶段
第二层:Plan-and-Execute 管任务依赖
第三层:局部 ReAct 管开放式探索
第四层:Artifact Reflection 管产物质量

例如 “生成迁移评估报告” 的全局阶段可以固定:

INTAKE
→ PLAN
→ VALIDATE_PLAN
→ EXECUTE
→ VERIFY
→ HUMAN_APPROVAL
→ DELIVER

其中 “寻找 SDK 封装层” 可以使用最多 5 步的局部 ReAct;“检查报告是否遗漏风险” 可以使用 Reflection;但 ReAct 和 Reflection 都不能擅自改变全局目标、重置预算或跳过审批。

一句话概括:

Workflow 管全局,Plan 管任务,ReAct 管局部探索,Reflection 管产物质量。


三、先定义 Goal Contract,不要急着列步骤

用户经常只给出一句模糊目标:

帮我评估 Payment SDK v1 升级到 v2 的影响。

直接生成步骤会留下大量歧义:范围是一个仓库还是整个组织?只调研还是允许改代码?最终交付报告还是 Pull Request?什么叫评估完成?

因此先建立 Goal Contract:

{
  "goal_id": "goal-payment-migration-001",
  "objective": "分析 Payment SDK v1 到 v2 的迁移影响",
  "scope": {
    "repository_group": "payment-services",
    "expected_repository_count": 12,
    "document_spaces": ["engineering", "payment-platform"]
  },
  "deliverables": [
    "repository-inventory.json",
    "api-usage-inventory.json",
    "risk-matrix.json",
    "migration-assessment.md"
  ],
  "constraints": {
    "write_access": false,
    "max_tool_calls": 120,
    "deadline_minutes": 45,
    "high_risk_requires_approval": true
  },
  "success_criteria": [
    "覆盖所有可访问仓库",
    "关键结论可追溯到证据",
    "明确记录不可访问范围",
    "给出迁移顺序和测试建议"
  ],
  "failure_criteria": [
    "没有权威迁移文档",
    "可访问仓库比例低于 80%",
    "预算不足以完成风险校验"
  ],
  "evidence_requirements": {
    "high_risk_claim": "至少一个权威来源和一个独立佐证"
  }
}

3.1 硬约束与软约束

类型 示例 违反后处理
硬约束 只读访问、租户隔离、预算上限、审批门禁 阻止执行或人工接管
软约束 优先低成本工具、报告尽量简洁、优先并行 记录偏差并继续

模型不能为了 “完成任务” 突破硬约束。

3.2 完成条件必须可验证

下面这些条件无法稳定验收:

充分调研
尽可能覆盖
报告质量较高
没有明显问题

应改成:

每个可访问仓库都有 ANALYZED 或 NO_USAGE_FOUND 状态
每条高风险结论至少关联一个权威 Evidence
报告包含规定的 10 个章节
仓库数量与 inventory Artifact 一致

计划的第一原则是:先定义 “怎样算完成”,再讨论 “怎么做”。


四、三层任务模型:Goal、Milestone 与 Work Item

复杂任务不应只有一张扁平待办列表。

4.1 Goal

Goal 描述最终业务结果,通常对应一次完整 Run。

4.2 Milestone

Milestone 是可以独立验收的中间成果,例如:

  1. 范围和资源清点完成;
  2. 权威迁移知识建立完成;
  3. 所有仓库使用情况分析完成;
  4. 风险矩阵完成;
  5. 报告校验和交付完成。

Milestone 不应只是 “调用一次工具”。

坏例子:执行 search_code
好例子:完成所有可访问仓库的 SDK 使用清单

4.3 Work Item

Work Item 是可调度、可重试、可验收的最小工作单元:

{
  "work_item_id": "W10",
  "milestone_id": "M3",
  "title": "寻找 SDK 封装层和动态调用",
  "task_type": "LOCAL_REACT",
  "dependencies": ["W08", "W09"],
  "required_capabilities": ["search_code", "get_file_section"],
  "output_spec": {
    "artifact_type": "indirect-api-usage",
    "schema_version": "1.0"
  },
  "completion_criteria": [
    "每条记录包含仓库、文件和调用链",
    "搜索范围覆盖所有可访问仓库",
    "未确认项标记置信度"
  ],
  "retry_policy": {
    "max_attempts": 3,
    "retryable_errors": ["TIMEOUT", "RATE_LIMITED"]
  },
  "max_react_steps": 5,
  "risk_level": "LOW"
}

4.4 计划是 DAG,不是数组

Work Item 之间通常形成有向无环图:

W01 规范化目标
├─ W02 获取仓库清单
│  ├─ W08 搜索依赖声明
│  └─ W09 搜索直接调用
└─ W03 获取文档来源
   └─ W05 搜索迁移文档
      └─ W06 抽取破坏性变更

W08 + W09 + W06
→ W10 寻找封装层
→ W11 合并使用清单
→ W12 覆盖校验

只有依赖全部成功、审批已经满足、预算足够时,任务才能进入 READY


五、状态必须结构化:不要把聊天历史当执行数据库

一个长期任务至少需要区分以下对象:

对象 作用
Plan 当前执行计划及版本
Work Item 一个可调度任务
Attempt Work Item 的一次具体尝试
Artifact 一次尝试产生的可复用产物
Evidence 支撑产物和结论的来源
Run State 整个任务当前状态
Checkpoint 可恢复的状态快照

5.1 Work Item 状态机

PENDING
→ READY
→ RUNNING
→ SUCCEEDED

RUNNING → RETRY_WAIT → READY
RUNNING → FAILED
PENDING → BLOCKED
READY → WAITING_FOR_APPROVAL
任意非终态 → CANCELLED

状态应由事实推导,而不是模型一句 “已经完成”:

def derive_work_item_status(item, attempts, verification):
    if item.cancelled:
        return "CANCELLED"

    if item.approval_required and not item.approved:
        return "WAITING_FOR_APPROVAL"

    if verification and verification.passed:
        return "SUCCEEDED"

    if has_retryable_failure(attempts):
        return "RETRY_WAIT"

    if retry_exhausted(attempts):
        return "FAILED"

    if dependencies_failed(item):
        return "BLOCKED"

    if dependencies_satisfied(item):
        return "READY"

    return "PENDING"

5.2 Attempt 不能省略

只在 Work Item 上保存最后一个错误,会丢失关键过程:

  • 第一次为什么失败;
  • 第二次是否修改了参数;
  • 三次失败是否为同一原因;
  • 哪次调用产生了部分结果;
  • 是否应该触发重复失败终止。

Attempt 至少保存 attempt_id、序号、输入快照哈希、工具调用引用、输出 Artifact、错误和最终 Outcome。

5.3 Artifact 必须可复用和可校验

Artifact 应包含类型、Schema Version、内容地址、内容哈希、来源 Attempt 和 Evidence 引用。

修正产物时创建新版本:

risk-matrix:v1
risk-matrix:v2

不要原地覆盖 v1,否则无法知道报告使用的是哪次结果。


六、Plan-and-Execute:规划、执行、校验必须分离

一个完整 Plan-and-Execute 系统至少包含五个角色。

角色 负责 不负责
Goal Builder 整理目标和约束 决定详细步骤
Planner 生成 Milestone、Work Item 和依赖 调用业务工具
Executor 执行一个明确 Work Item 随意改目标
Verifier 对照契约校验 Artifact 无限改写
Replanner 事实变化时创建 Plan Patch 覆盖旧计划

6.1 Planner 输出不能直接执行

模型生成的计划可能存在:

  • ID 重复;
  • 依赖引用不存在;
  • 环依赖;
  • 工具未注册;
  • 完成条件为空;
  • 高风险步骤没有审批;
  • 预算明显不够;
  • 步骤超出 Goal Scope。

因此需要 Plan Validator:

def validate_plan(plan, capability_registry, budget):
    issues = []
    issues += check_unique_ids(plan)
    issues += check_dependency_references(plan)
    issues += check_acyclic_graph(plan)
    issues += check_completion_criteria(plan)
    issues += check_capabilities(plan, capability_registry)
    issues += check_scope_boundaries(plan)
    issues += check_approval_rules(plan)
    issues += estimate_budget_feasibility(plan, budget)

    return {
        "passed": not has_blocking_issue(issues),
        "issues": issues
    }

6.2 Plan Version 与 Plan Patch

计划会因新事实而变化,但不能悄悄覆盖:

Plan v1:覆盖 12 个仓库
Plan v2:发现 1 个仓库无权限,调整验收范围
Plan v3:迁移文档版本冲突,增加权威来源确认任务

Plan Patch 至少记录基础版本、变更原因、支撑 Evidence、新增或修改的任务,以及需要保留的已完成 Work Item。这样既能调整计划,也不会丢失 W01、W02 等有效产物。

短暂超时通常只需重试,不需要重规划。只有范围、事实、能力或约束发生变化,使当前计划不再可执行时才需要 Replanner。


七、ReAct:把开放探索限制在局部任务中

ReAct 的基本闭环是:

Observation
→ Decision
→ Action
→ New Observation

工程上不需要展示模型的完整内部思维过程。系统只应保存足以审计的结构化决策摘要:

{
  "decision_id": "decision-801",
  "work_item_id": "W10",
  "objective": "寻找 SDK 间接调用",
  "observation_refs": ["obs-31", "obs-32"],
  "selected_action": {
    "tool": "search_code",
    "arguments": {
      "query": "PaymentGateway"
    }
  },
  "reason_summary": "直接 SDK 搜索覆盖不足,继续定位内部封装类",
  "remaining_steps": 3
}

7.1 受限循环

async def run_local_react(item, context):
    observations = []
    evidence_ids = []

    for step in range(item.max_react_steps):
        if context.pause_requested:
            return partial_result("PAUSE_REQUESTED", observations)

        if not context.budget.can_continue():
            return partial_result("BUDGET_EXHAUSTED", observations)

        decision = model.decide_next_action(
            objective=item.description,
            observations=compact(observations),
            allowed_tools=item.allowed_tools,
        )

        if decision.type == "FINISH":
            return build_artifact(observations, evidence_ids)

        validate_action(decision, item.allowed_tools)
        result = await tool_gateway.invoke(decision.tool_call, context)
        observation = normalize_observation(result)

        observations.append(observation)
        evidence_ids.extend(observation.evidence_ids)

        if no_progress_detected(observations):
            return partial_result("NO_PROGRESS", observations)

    return partial_result("STEP_LIMIT", observations)

7.2 无进展检测

满足任一条件就应停止:

  • 连续两次结果哈希相同;
  • 连续两步没有新增 Evidence;
  • 重复提出已经失败的动作;
  • 查询词只做无意义改写;
  • 置信度没有提升但预算持续消耗。

7.3 ReAct 不适合什么

  • 固定审批流程;
  • 高风险副作用;
  • 跨天长任务的全局调度;
  • 可以用确定性程序完成的转换;
  • 需要严格事务一致性的流程。

ReAct 是局部探索器,不是整个系统的操作系统。


八、Workflow 与 Agent:概率性判断要嵌入确定性骨架

一个稳健 Workflow 可以包含以下节点:

节点类型 示例 是否允许模型决定状态
RULE 预算检查、路由、状态守卫
MODEL 目标整理、风险解释、报告生成 只能返回建议
TOOL 查询仓库、获取文档
VALIDATION Schema、证据、覆盖率检查 否或受限
HUMAN 高风险审批、范围确认 由可信身份决定
WAIT/TIMER 等待回调、截止时间
COMPENSATION 撤销预留、标记失效

模型节点不应该直接:

  • 修改 Workflow State;
  • 跳过审批;
  • 扩大工具权限;
  • 覆盖历史 Artifact;
  • 重置 Budget;
  • 宣布高风险副作用成功。

节点契约应明确节点类型、输入 Artifact、输出 Schema、工具白名单、超时、调用预算和成功或失败后的路由。

节点只接收所需 Artifact,而不是整个对话历史。上下文越小,越容易测试、复现和控制成本。


九、工具执行:权限、重试和幂等必须统一治理

Executor 不应绕过 Tool Gateway 直接访问外部系统。

async def invoke_tool(call, context):
    tool = registry.get(call.tool_name)

    validate_schema(tool.input_schema, call.arguments)
    authorize(context.principal, tool.permission, call.arguments)
    enforce_goal_scope(context.goal.scope, call.arguments)
    reserve_budget(context.budget, tool.estimated_cost)

    safe_args = normalize_arguments(call.arguments)
    idempotency_key = build_idempotency_key(context, call, safe_args)

    try:
        raw = await with_timeout(
            tool.execute(safe_args, idempotency_key=idempotency_key),
            seconds=tool.timeout_seconds,
        )
        result = validate_schema(tool.output_schema, raw)
        result = truncate_and_redact(result, tool.max_result_bytes)
        record_success(call, result)
        return result
    except Exception as error:
        normalized = normalize_tool_error(error)
        record_failure(call, normalized)
        raise normalized

9.1 错误分类决定下一步

错误 通常处理
TIMEOUT 有界重试,结果未知时先对账
RATE_LIMITED 按 Retry-After 或退避重试
SERVICE_UNAVAILABLE 重试、熔断或备用来源
PERMISSION_DENIED 不盲目重试,记录缺口或接管
INVALID_ARGUMENT 修正参数后新 Attempt
SCHEMA_MISMATCH 阻断并记录契约错误
RESULT_TOO_LARGE 分页、缩小查询或生成摘要 Artifact

9.2 UNKNOWN_OUTCOME

超时只表示客户端没有及时收到结果,不代表外部动作失败。

对于发送消息、发布报告、创建工单等副作用:

调用超时
→ Attempt 标记 UNKNOWN_OUTCOME
→ 使用幂等键查询外部系统
→ 已成功则补记状态
→ 明确失败才允许重试
→ 无法判断则人工接管

这条规则可以避免最常见的重复副作用事故。


十、Reflection:检测、诊断、修正和重验不能混在一起

“让模型检查自己的答案” 过于宽泛。工程上的结果校验应分成四步:

Detection:发现问题
→ Diagnosis:定位原因
→ Repair:生成最小修正
→ Revalidation:重新执行全部必要校验

10.1 程序校验优先

确定性规则适合检查:

  • JSON Schema;
  • 必需章节;
  • 数量一致性;
  • Evidence 引用存在性;
  • 仓库覆盖率;
  • 重复 ID;
  • 敏感字段;
  • Artifact 哈希。
def verify_report(report, run_state):
    issues = []

    for section in REQUIRED_SECTIONS:
        if section not in report.sections:
            issues.append(issue("MISSING_SECTION", section))

    if report.repository_count != run_state.analyzed_repository_count:
        issues.append(issue("REPOSITORY_COUNT_MISMATCH"))

    for claim in report.key_claims:
        if not claim.evidence_ids:
            issues.append(issue("CLAIM_WITHOUT_EVIDENCE", claim.id))

    if contains_sensitive_content(report.content):
        issues.append(issue("SENSITIVE_CONTENT"))

    return issues

模型校验适合检查:

  • 是否把推测写成事实;
  • 结论是否真正被证据支持;
  • 是否把相关性写成因果;
  • 是否遗漏显著冲突;
  • 建议是否回应用户目标。

10.2 Verification 不只是 PASS 和 FAIL

PASS:满足契约
FAIL:确定不满足,可以修正或终止
UNKNOWN:证据不足,无法可靠判断

UNKNOWN 不能被当成 PASS

10.3 有限修正

def decide_after_verification(result, artifact):
    if result.status == "PASS":
        return "ACCEPT"

    if result.has_security_issue:
        return "HUMAN_HANDOFF"

    if result.repairable and artifact.repair_count < 1:
        return "REPAIR_ONCE"

    if result.can_deliver_partial:
        return "DEGRADED_DELIVERY"

    return "HUMAN_HANDOFF"

无限 Reflection 会造成成本失控,还可能修复一个问题后引入另一个问题。自动修正必须有次数预算。


十一、Checkpoint、暂停和恢复

任务状态不能只存在进程内存或 Prompt 中。

11.1 Checkpoint 保存什么

{
  "checkpoint_version": 23,
  "run_id": "run-payment-001",
  "workflow_state": "RUNNING",
  "active_plan_version": 2,
  "work_item_states": {
    "W01": "SUCCEEDED",
    "W02": "SUCCEEDED",
    "W03": "SUCCEEDED",
    "W09": "RUNNING"
  },
  "active_attempt_ids": ["attempt-W09-01"],
  "artifact_ids": [
    "goal:v1",
    "repository-inventory:v1",
    "migration-document-set:v1"
  ],
  "budget": {
    "used_tool_calls": 31,
    "used_model_calls": 8,
    "used_tokens": 42600,
    "used_elapsed_seconds": 712
  },
  "saved_at": "2026-07-15T10:15:30+08:00"
}

至少在这些时机保存:

  • Plan 创建或变更后;
  • Work Item 开始前和结束后;
  • Artifact 写入后;
  • 进入暂停或人工等待前;
  • 进入终态前。

11.2 暂停不是直接杀进程

RUNNING → PAUSING → PAUSED

PAUSING 阶段要停止启动新任务,让短调用安全结束,取消可取消的长调用,保存 Attempt 和 Checkpoint,再释放执行 Lease。

11.3 恢复前先对账

async def resume_run(run_id, principal):
    checkpoint = checkpoint_store.load_latest_valid(run_id)
    authorize_resume(principal, checkpoint)

    lease = acquire_run_lease(run_id, principal)
    reconcile_inflight_attempts(checkpoint)
    verify_artifact_hashes(checkpoint.artifact_ids)
    restore_remaining_budget(checkpoint.budget)
    recompute_ready_items(checkpoint)

    trace.append("RUN_RESUMED", run_id=run_id)
    return scheduler.continue_run(run_id, lease)

恢复时不能重置预算,也不能直接把所有 RUNNING 任务改回 PENDING。应先根据幂等键、外部调用状态和 Artifact 证据判断它是否已经成功。

11.4 Lease 防止双重执行

同一个 Run 同时只能有一个有效 Lease。Worker 定期续租,状态写入携带 lease_version,旧 Lease 的提交必须被拒绝。

否则两个 Worker 可能同时恢复同一任务,产生重复调用、重复扣费和重复交付。


十二、会停止才是真正的可控 Agent

停止不是异常,而是一类正式结果。

状态 含义
COMPLETED 完整满足完成条件
PARTIALLY_COMPLETED 完成可交付子集,并明确缺口
PAUSED 已保存状态,等待恢复
WAITING_FOR_HUMAN 等待审批或决策
FAILED 已知无法完成且不能安全降级
CANCELLED 用户或上游明确取消

12.1 多维 Budget

不要只限制循环次数。完整 Budget 至少包括:

{
  "max_elapsed_seconds": 2700,
  "max_tool_calls": 120,
  "max_model_calls": 35,
  "max_tokens": 180000,
  "max_total_attempts": 80,
  "max_replans": 2,
  "max_reflections_per_artifact": 1
}

启动 Work Item 前应预留预算。如果剩余工具调用只有 2 次,而任务预计需要 8 次,就不应启动后再半途失败。

12.2 无进展和重复失败

常见停止信号:

  • 连续多步没有新增 Evidence;
  • 相同输入重复调用相同工具;
  • 相同错误连续出现;
  • Plan 连续修改却没有新增可执行任务;
  • Artifact 反复校验失败;
  • 预算消耗但完成度不变。

12.3 Circuit Breaker

工具连续失败后,应避免所有任务一起制造重试风暴:

CLOSED:正常调用
→ 连续失败达到阈值
OPEN:快速失败,暂不调用
→ 冷却时间结束
HALF_OPEN:允许少量探测
→ 成功回到 CLOSED,失败回到 OPEN

Circuit Breaker 是工具级可靠性控制,不能替代单次 Attempt 的重试策略。


十三、证据不足时,降级比编造更有价值

一个成熟系统应提供降级阶梯:

完整报告
→ 缺少部分仓库的报告
→ 只输出事实清单和风险候选
→ 只输出已完成 Artifact 索引
→ 生成 Handoff Package
→ 安全失败

部分结果必须标明:

  • 原目标;
  • 已完成范围;
  • 未完成范围;
  • 降级原因;
  • 已验证结论;
  • 不可下结论的部分;
  • 继续所需条件;
  • 已消耗预算。

例如 12 个仓库中只有 7 个可访问,不能写成 “迁移调研已经完成,只缺少少量信息”。覆盖缺口本身就是交付结果的一部分。

13.1 Evidence Sufficiency

风险等级和置信度必须分开:

风险 置信度 处理
明确提示风险并进入审批
标记未知,人工确认
可以形成低风险结论
不能声称安全

“没有发现风险” 只说明搜索没有找到,不等于 “风险很低”。


十四、人工接管不是失败,而是控制权协议

以下情况通常需要接管:

  • 高风险低置信度;
  • 权威来源冲突;
  • 同一工具多次失败;
  • 权限缺失导致范围不足;
  • 两次重规划后仍不可执行;
  • 非幂等调用结果未知;
  • 安全策略发现敏感信息;
  • 用户主动暂停或接管。

14.1 Handoff Package

字段 内容
原因 结构化 Reason Code 和人类可读说明
当前状态 Goal、Plan Version、已完成和阻塞任务
尝试历史 Attempt 次数、参数变化和最后错误
证据 相关 Artifact 与 Evidence 引用
决策选项 授权后继续、接受部分范围或取消
恢复信息 Budget 快照、Checkpoint 和 Resume Point

好的接管问题应说明:发生了什么、已经尝试什么、影响范围、可选方案和每个方案的后果。

接管前 Agent 应停止启动新任务、保存 Checkpoint、释放 Lease,再把控制权交给可信的人类身份。人工决定本身也要进入审计记录。


十五、贯穿案例:Payment SDK 迁移调研助手

15.1 初始计划

Milestone Work Item 摘要
M1 范围确认 规范化目标、获取仓库与文档、校验实际范围
M2 迁移知识 搜索权威文档、抽取破坏性变更、校验版本
M3 代码分析 搜索依赖和直接调用、用局部 ReAct 找封装层、校验覆盖率
M4 风险分析 关联变化、分析测试缺口、规则打分、语义复核
M5 报告交付 生成迁移顺序和报告、双层校验、有限修正、人工审批

15.2 正常执行

系统发现 12 个仓库,其中 11 个可访问。文档侧找到官方迁移指南和 v2 发布说明,抽取出 8 项破坏性变更。代码搜索识别 37 个直接或间接调用点,规则计算出 3 个高风险模块和 5 个中风险模块。

报告 v1 的确定性校验发现一项高风险结论缺少 Evidence,语义校验发现一个迁移顺序建议表达过度确定。系统执行一次有限修正,生成报告 v2,并再次运行全部必要校验。

最终状态:

{
  "status": "COMPLETED",
  "completion_mode": "DEGRADED",
  "plan_version": 2,
  "coverage": {
    "expected": 12,
    "accessible": 11,
    "analyzed": 11
  },
  "unresolved_issues": [
    "billing-worker 仓库无访问权限"
  ],
  "final_artifact": "migration-assessment:v2"
}

15.3 工具连续失败

如果文档搜索服务连续三次超时:

错误分类
→ 指数退避重试
→ 重试耗尽
→ Circuit Breaker OPEN
→ 查询已审核缓存或备用只读来源
→ 仍无结果则生成 Handoff Package

系统不能使用模型记忆编造迁移规则,也不能擅自扩展到未授权互联网来源。

15.4 预算耗尽

如果任务在测试缺口分析时耗尽工具预算,系统应保留仓库清单、文档变更和 API 使用清单,只交付已确认事实,不生成未经校验的最终风险排名,并给出继续执行所需的预算估算。

15.5 暂停与恢复

用户请求暂停
→ 不再启动新 Work Item
→ 当前工具调用到安全点
→ 保存 Artifact 和 Checkpoint
→ Run 进入 PAUSED

用户恢复
→ 获取 Lease
→ 加载最新有效 Checkpoint
→ 对账运行中 Attempt
→ 校验 Artifact 哈希
→ 恢复剩余 Budget
→ 从 Ready Work Item 继续

已经成功的仓库搜索不会重复执行。


十六、后端实现参考

推荐组件边界:

API / Command Handler
├─ Goal Service
├─ Planning Service
│  ├─ Planner
│  ├─ Plan Validator
│  └─ Replanner
├─ Workflow Runtime
│  ├─ Scheduler
│  ├─ Executor
│  └─ State Guard
├─ Tool Gateway
├─ Verification Service
├─ Artifact Store
├─ Checkpoint Store
├─ Budget & Termination Service
├─ Handoff Service
└─ Trace / Metrics

主循环可以保持简单:

async def run_agent(run_id):
    state = run_store.load(run_id)

    while not state.is_terminal:
        lease_service.renew(state.run_id)

        control = termination_service.evaluate(state)
        if control.action != "CONTINUE":
            return await handle_control_action(state, control)

        ready_items = scheduler.find_ready_items(state)

        if not ready_items:
            resolution = resolve_no_ready_items(state)

            if resolution == "VERIFY":
                await verifier.verify_run(state)
            elif resolution == "REPLAN":
                await replanner.create_patch(state)
            elif resolution == "COMPLETE":
                await delivery_service.finalize(state)
            else:
                await handoff_service.create(state, "NO_RUNNABLE_WORK")

            state = run_store.load(run_id)
            continue

        batch = scheduler.select_batch(ready_items, max_parallel=4)
        results = await executor.execute_batch(batch, state)

        run_store.persist_results_atomically(results, state)
        checkpoint_store.save(state)
        state = run_store.load(run_id)

    return run_store.build_summary(run_id)

注意这里没有:

while model_says_continue:
    ...

是否继续由状态、依赖、预算、策略和用户意图共同决定。

第一版可以使用单体服务、PostgreSQL、数据库任务队列和对象存储。先证明状态语义、幂等与恢复,再考虑分布式 Workflow 引擎和大规模并行调度。


十七、可观测性:不仅看调用成功率,还要看任务是否前进

Trace 层级可以设计为:

Run Span
  Plan Span
    Milestone Span
      Work Item Span
        Attempt Span
          Model Call Span
          Tool Call Span
          Verification Span

关键事件包括 Run 创建、Goal 规范化、Plan 创建与校验、Attempt 开始、模型决策、工具成功或失败、Artifact 创建、Verification 完成、Plan Patch、暂停恢复、Budget 阈值、Handoff、人工决定以及各类终态。

推荐指标:

维度 关键指标
规划质量 Plan 首次校验通过率、平均重规划次数、环依赖拦截数
执行效率 Work Item 成功率、关键路径耗时、并行度、重复调用率
工具可靠性 超时率、重试成功率、熔断次数、UNKNOWN_OUTCOME 对账时间
结果质量 Verification 通过率、无 Evidence 结论数、修正后回归失败率
恢复能力 Checkpoint 恢复成功率、重复副作用数、双 Worker 拦截数
控制能力 Budget 超限数、无进展停止数、降级率、人工接管率

Trace 不应复制完整敏感文档或模型内部思维过程。优先记录 ID、版本、哈希、原因码、决策摘要和 Evidence 引用。


十八、测试:异常路径比 Happy Path 更重要

测试域 必测行为
Goal 与 Plan 范围完整;依赖无环;未知工具被拒绝;高风险任务有审批
Scheduler 依赖满足后才运行;并发受限;老任务不饥饿
Tool Gateway 权限前置;可恢复错误重试;权限错误不重试;结果受限和脱敏
ReAct 工具白名单;最多 5 步;无进展终止;部分结果可保存
Verification 缺章节、缺 Evidence、数字冲突、敏感信息都被发现
Reflection 最多修正一次;修正产生新 Artifact;重验覆盖必要规则
Checkpoint 重启后不重复成功任务;运行中 Attempt 先对账
Budget 恢复不重置预算;预算不足时不启动大任务;可降级交付
Handoff 包含状态、尝试、证据、选项和恢复点;人工决定可审计
安全 提示注入不改变工具权限;跨租户访问为零

练习项目可以设置以下硬门槛:

非法状态转换成功次数 = 0
未授权工具调用次数 = 0
重复副作用次数 = 0
高风险无 Evidence 交付次数 = 0
预算重置次数 = 0
双 Worker 同时执行次数 = 0
无限 ReAct 或 Reflection 次数 = 0
暂停恢复正确率 = 100%

故障注入至少覆盖:

  1. 工具超时一次后恢复;
  2. 工具连续失败三次;
  3. 仓库权限拒绝;
  4. Planner 生成环依赖;
  5. ReAct 重复相同搜索;
  6. 报告缺少 Evidence;
  7. Budget 中途耗尽;
  8. 工具成功后、Checkpoint 前崩溃;
  9. 两个 Worker 同时恢复;
  10. 文档中包含提示注入;
  11. 两个权威来源冲突;
  12. 高风险但低置信度。

十九、常见故障与定位

故障 主要原因 修复方向
Agent 一直循环 没有步数、预算和无进展检测 使用局部 ReAct,增加多维 Budget 和停止原因
计划执行到一半才发现工具不存在 Planner 输出直接执行 增加 Capability Registry 和 Plan Validator
恢复后重复调用 只保存当前步骤名 Attempt、幂等键、Artifact 和外部状态对账
一个任务失败导致全部重跑 没有 Plan Version 和产物复用 使用 Plan Patch,保留成功 Work Item
报告结论无法解释 没有 Evidence 数据模型 结论、Artifact 与 Evidence 建立引用
Reflection 反复改写 没有修正次数和验收契约 Verification Contract、最小 Repair、全量重验
权限错误重复重试 所有异常使用同一策略 错误分类,永久错误直接阻断或接管
预算耗尽仍宣称完成 没有 Completion Mode 使用 PARTIALLY_COMPLETED 和降级报告
两个 Worker 重复执行 没有 Lease 和版本守卫 Run Lease、心跳和乐观锁
人工接管后无法继续 只发送错误消息 生成结构化 Handoff Package 和 Resume Point
搜索为空就判断无风险 把缺少证据当成低风险 区分 Risk 与 Confidence,允许 UNKNOWN
文档提示改变了 Agent 行为 把外部内容当系统指令 数据与指令隔离,工具权限由 Gateway 控制

二十、推荐实现顺序

  1. 定义 Goal、Plan、Work Item、Attempt、Artifact、Evidence 和 Run State;
  2. 实现确定性状态机和非法转换守卫;
  3. 使用固定 Plan 跑通 Scheduler、Executor 和 Artifact Store;
  4. 实现 Plan Validator,覆盖依赖、能力、范围和预算检查;
  5. 用 Fixture 构造仓库、文档、超时和权限错误;
  6. 接入 Planner,但所有输出先做 Schema 和计划校验;
  7. 只在少数开放任务中加入有界 ReAct;
  8. 先实现程序校验,再增加证据驱动的语义 Reflection;
  9. 加入 Checkpoint、幂等、UNKNOWN_OUTCOME 对账和 Lease;
  10. 加入多维 Budget、无进展检测、熔断和终止记录;
  11. 实现降级交付和 Handoff Package;
  12. 补齐 Trace、指标和故障注入测试。

不要一开始就引入多个 Agent、分布式消息队列和复杂图编排。先用单体和固定 Fixture 证明:状态能恢复、调用不重复、结果有证据、预算会生效、失败能安全停止。


二十一、总结

可靠的 Agent 规划与执行系统,不是 “让模型自主完成一切”,而是把自主判断限制在明确、可观察、可停止的边界中。

需要记住的核心原则:

  1. 复杂任务不是把单轮 Agent 循环得更久;
  2. 先建立 Goal Contract,再生成执行步骤;
  3. Goal、Milestone 和 Work Item 分层,计划使用 DAG 表达依赖;
  4. Work Item、Attempt、Artifact 和 Evidence 必须分离;
  5. Planner 输出必须经过确定性 Plan Validator;
  6. Plan 变化要创建新版本,不能覆盖历史;
  7. Workflow 管全局,ReAct 只处理局部不确定性;
  8. 模型负责语义判断,程序负责状态、权限和预算;
  9. Reflection 要分成检测、诊断、修正和重验;
  10. Checkpoint、幂等和 Lease 是暂停恢复的基础;
  11. Budget、无进展和 Circuit Breaker 决定系统能否安全停止;
  12. 证据不足时应降级或接管,不能为了完成而编造;
  13. Handoff 是正式控制权协议,不是一句 “请人工处理”;
  14. 只有通过崩溃、并发、越权和预算测试,才能证明任务真正可控。

完整闭环可以压缩为:

用户目标
→ Goal Contract
→ Plan 与 Plan Validator
→ Scheduler 按依赖调度
→ Executor 通过 Tool Gateway 执行
→ Attempt、Artifact 与 Evidence 持久化
→ Verification 与有限 Reflection
→ Checkpoint 与 Plan Version
→ Budget、无进展和终止判断
→ 完整交付、降级交付或 Human Handoff
→ Trace、审计和持续评估

当这条链路建立起来后,Agent 才不只是 “能够连续调用工具”,而是能在任务复杂、环境变化、服务失败、预算有限和人类介入时,仍然保持状态一致、结果可验证、过程可恢复、风险可控制。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐