跳到正文
Agent 工程实践输出校验与动作执行
返回课程/Agent 工程实践
第 14 / 15 章 约 6 分钟

输出校验与动作执行

校验结构和引用,为外部动作增加执行边界。

这个模块在 Agent 里的位置

模型输出不是终点。这个模块决定:

  • 结果是否符合结构。
  • 引用是否真实。
  • 是否有权限执行。
  • 是否需要人审。
  • 外部动作是否幂等。
  • 是否有终态和审计。

它是业务正确性的最后一道闸门。

先记住几个概念

概念含义为什么重要
Proposal模型生成的结构化建议不直接执行
Validatorschema、引用、权限、业务规则校验防止错误进入执行
Human approval人工审批高风险动作的确认
Action executor真正执行外部动作的组件与模型解耦
Action key幂等键防止重复执行
Terminal result成功 / 失败 / 取消等终态防止任务假成功

从一个真实问题开始:页面显示已取消,邮件还是发出去了

一个分析 Agent 生成结论:

供应商 A 风险上升,建议通知负责人。

系统直接根据这段自然语言发送了邮件。

后来用户在页面上点了取消,但后台没有阻断 pending action。几分钟后,用户又收到一封“任务完成”的邮件。

排查发现:

  1. 模型输出是自由文本,不是结构化 proposal。
  2. 没有校验收件人是否在当前租户内。
  3. 没有幂等 key。
  4. 取消只改了 UI 状态,没有阻断 action。
  5. 动作没有 terminal result 和审计。

这类问题的根因不是“模型不稳定”,而是输出和执行之间缺少契约。

模型只生成 proposal,不直接执行

正确链路:

模型输出
  -> 结构化 proposal
  -> schema / 引用 / 权限校验
  -> 自动策略或人工审批
  -> action executor
  -> terminal result
  -> audit

模型可以建议“发通知”,但不能自己决定:

  • 发给谁。
  • 是否有权限。
  • 是否要人审。
  • 是否重复执行。

这些必须由服务端策略控制。

一个合格的 proposal

{
    "entities": [
        {
            "entityId": "entity-9182",
            "riskScore": 87.4,
            "evidenceRefs": ["win-1001", "win-1002"]
        }
    ],
    "proposedAction": {
        "type": "send_notification",
        "recipient": "owner:9182",
        "riskLevel": "high",
        "message": "高风险实体风险上升"
    }
}

执行前至少校验:

  1. evidenceRefs 是否存在。
  2. recipient 是否属于当前租户。
  3. riskLevel 是否符合策略。
  4. actionType 是否允许。
  5. actionKey 是否已经执行。

输出校验分五层

层校验内容失败处理
Schema字段、类型、枚举、数量拒绝或让模型修正
引用evidence / source 是否存在拒绝
权限是否允许操作目标拒绝并记录
业务规则风险等级、收件人、金额、频率拒绝或要求补充
幂等action key 是否已执行返回已有结果

只做 schema 校验是不够的。模型完全可以输出一个结构正确但引用伪造的 JSON。

数据库设计

create table agent_action_proposals (
  id bigint primary key,
  run_id bigint not null,
  tenant_id bigint not null,
  action_type text not null,
  payload jsonb not null,
  risk_level text not null,
  status text not null,
  created_at timestamptz not null
);

create table agent_action_executions (
  id bigint primary key,
  proposal_id bigint not null,
  action_key text not null,
  status text not null,
  result jsonb,
  created_at timestamptz not null,
  unique (proposal_id, action_key)
);

设计要点:

  1. proposal 和 execution 分表。
  2. action_key 做幂等。
  3. 执行结果必须有终态。
  4. 人审结果和拒绝原因写入审计。

幂等 key 怎么设计

一个可用的 action key:

notify:run-9f27:owner:9182

含义:

  • 动作类型。
  • 所属 run。
  • 目标对象。

如果重试、worker 恢复或网络超时,只要 action key 相同,就不应重复发送。

取消必须阻断 pending action

用户取消 run 时,系统必须:

  1. 停止模型。
  2. 停止工具。
  3. 停止子任务。
  4. 阻断所有 pending action。

如果 action 已经在执行中,要尽量 abort;如果不能 abort,必须记录终态并告知用户。

不能出现:

UI: cancelled
Action: succeeded
Audit: no result

终态必须可观测

一个执行记录示例:

{
    "proposalId": "proposal-551",
    "runId": "run-9f27",
    "actionType": "send_notification",
    "payload": {
        "recipient": "owner:9182",
        "message": "高风险实体风险上升"
    },
    "validation": {
        "schemaValid": true,
        "evidenceRefsValid": true,
        "permissionValid": true,
        "requiresHumanApproval": true
    },
    "execution": {
        "actionKey": "notify:run-9f27:owner:9182",
        "status": "succeeded",
        "terminalResult": {
            "deliveredAt": "2026-09-24T10:02:00Z"
        }
    }
}

这能回答:

  • 是谁提议的。
  • 是否通过校验。
  • 是否需要人审。
  • 是否执行。
  • 是否成功。
  • 何时完成。

常见工程错误

错误实际后果正确做法
自由文本触发动作不可审计、不可解析结构化 proposal
只做 schema 校验引用可能伪造evidence 校验
无权限校验越权操作服务端 permission policy
无幂等 key重复发通知 / 写数据action key
无终态任务假成功terminal result
取消不阻断 action用户已取消但副作用发生block pending action
人审结果不入审计无法追溯记录审批和拒绝原因

上线前检查

  1. 输出有 schema。
  2. 引用可校验。
  3. 权限在服务端判断。
  4. 高风险动作有人审。
  5. 执行幂等。
  6. 有 terminal status。
  7. 审计完整。
  8. run 取消时阻断 pending action。