课程大纲 › 领域 1:Agent 架构与编排

1.4 用强制与交接模式实现多步骤工作流

タスクステートメント1.4:強制とハンドオフのパターンを用いて複数ステップのワークフローを実装する

官方大纲原文(日文):知识 3 条 · 技能 3 条

需要掌握的知识

  • ワークフローの順序付けにおける、プログラムによる強制(フック、前提条件ゲート)とプロンプトベースのガイダンスの違い
  • 決定論的な遵守が求められる場合(例:金銭に関わる操作の前の本人確認)、プロンプトの指示だけでは失敗率がゼロにならないこと
  • プロセス途中でのエスカレーションのための、顧客の詳細、根本原因の分析、推奨アクションを含む構造化されたハンドオフプロトコル

需要能做到的事

  • 前提となるステップが完了するまで下流のツール呼び出しをブロックする、プログラムによる前提条件を実装する(例:get_customerが検証済みの顧客IDを返すまでprocess_refundをブロックする)
  • 複数の懸案を含む顧客リクエストを個別の項目に分解し、共有コンテキストを使ってそれぞれを並列に調査したうえで、統一された解決策にまとめる
  • 会話の記録にアクセスできない人間の担当者にエスカレーションする際に、構造化されたハンドオフサマリー(顧客ID、根本原因、返金額、推奨アクション)を作成する

课程讲解 · AI 草稿,未经人工审核 以官方文档为准

这一条考什么

考你能否区分"用程序强制"和"用提示引导"两种控制工作流顺序的方式,并在需要确定性合规的场景(例如涉及资金的操作前必须完成身份验证)选择程序强制。还考两个配套能力:把包含多个诉求的客户请求拆开并行处理再合并;以及在中途升级给人工时,生成一份结构化、可直接决策的交接摘要。

核心概念

程序强制 vs. 提示引导

控制"先做 A 再做 B"有两类手段:

  • 提示引导:在系统提示里写"退款前必须先调用 get_customer 验证身份"。模型大多数时候会遵守,但这是概率性的,无法做到 100%。
  • 程序强制:在代码层面设置前置条件门(prerequisite gate)或 Hook,当前置步骤未完成时直接拒绝下游工具调用。不论模型怎么推理,违规调用都不会被执行。

二者并不互斥:提示负责让模型"知道该怎么做"、减少被拦截的次数;程序强制负责兜底,保证"绝不会发生"。

为什么提示无法把失败率降到零

LLM 的行为是概率性的。即使提示写得再强调(全大写的 CRITICAL、NEVER),再加 few-shot 示例,在长对话、上下文冲突、用户诱导等情况下依然会偶发违规。对于"给未验证身份的人退款"这类事故,哪怕千分之一的失败率也不可接受。所以判断标准很简单:如果业务要求确定性遵守,就必须在代码里强制。

前置条件门的实现思路

在执行工具的那一层维护会话状态:

  1. get_customer 成功返回且验证通过时,记录 verified_customer_id。
  2. 收到 process_refund 调用时,先检查状态:没有已验证的客户 ID,或调用参数中的客户与已验证的不一致,就不执行,而是返回一个 is_error: true 的 tool_result,说明"需要先完成身份验证"。
  3. 模型收到这个错误后会自行补上验证步骤。

这种门可以写在你的工具分发函数里,也可以用 Agent SDK 的 PreToolUse Hook 实现(见 1.5)。

多诉求请求的分解与合并

客户一次说了三件事:"上周的订单少发了一件、这个月被重复扣费、顺便改一下收货地址"。较好的处理方式:

  1. 先识别并列出独立的诉求项。
  2. 基于共享上下文(同一个已验证客户、同一组订单数据)分别调查每一项;彼此独立的调查可以在同一轮里并行发出多个工具调用。
  3. 汇总所有调查结果,给出一个统一的回复和解决方案,而不是让客户分三次来回沟通。

结构化交接协议

当流程进行到一半需要升级给人工(例如金额超出授权、需要政策例外),接手的人看不到对话记录。交接内容应当是"可直接决策"的状态,而不是原始素材。推荐字段:

{
  "customer_id": "C-20931",
  "verified": true,
  "issue_summary": "促销价未生效导致多收费",
  "root_cause": "订单 A-7781 下单时促销码校验失败,按原价结算",
  "order_refs": ["A-7781"],
  "refund_amount": 680.00,
  "actions_taken": ["已核实身份", "已确认促销在有效期内", "退款因超过 500 美元授权上限被拦截"],
  "recommended_action": "批准 680.00 美元退款并补发促销确认邮件",
  "customer_sentiment": "不满,已第二次来电"
}

只传用户原话不够(人工得从头调查);把整段对话和工具输出全部存库再交接也不好(信息量大、需要人工重新提炼);先尝试执行越权操作、失败了再升级更是错误。

正确做法与反模式

  • 正确:在工具执行层设置前置条件,get_customer 返回已验证 ID 之前阻断 process_refund。反模式:只在系统提示里强调"必须先验证"。
  • 正确:被阻断时返回清晰的错误说明,引导模型补齐前置步骤。反模式:静默丢弃调用或直接抛异常结束会话。
  • 正确:把多诉求请求拆成独立项,基于共享上下文分别(可并行)调查,最后统一答复。反模式:只处理第一个诉求,或让客户分多次提出。
  • 正确:升级时生成包含客户 ID、根因、金额、已做操作、建议动作的结构化摘要。反模式:只转发用户原始消息,或把完整对话日志丢给人工。
  • 正确:提示与程序强制配合使用。反模式:认为加了 few-shot 示例就等于有了保证。

常见陷阱

  • "用更强烈的措辞强化系统提示(CRITICAL / NEVER)"——仍是概率性遵守,题目若强调"必须""确定性""合规",就选程序强制。
  • "添加 few-shot 示例展示不同金额下的正确行为"——能提升遵守率,但不能归零失败率。
  • "让工具在超额时返回错误信息'请升级'"——比纯提示好,但真正的拦截点与重定向应在调用发出前(前置条件 / PreToolUse Hook),题目常把 Hook 作为最佳答案。
  • "调用 escalate_to_human 时只附上客户原话"或"先把整段对话存库再升级"——接手的人需要的是提炼好的、可决策的结构化信息。
  • "先尝试处理,系统拒绝了再升级"——在明知越权时先尝试是错误流程。

实操练习

目标:在 anthropic SDK 的 Agent 循环中实现一个前置条件门,验证"未验证身份时退款被阻断"。

  1. 复用 1.1 的循环结构,把工具分发换成下面的 dispatch。
  2. 用户消息使用"我是 C-1,订单 A-1 请退款 50 元"。
  3. 观察第一次 process_refund(如果模型跳过验证)是否被门拦截,以及模型随后是否补调 get_customer。
import json

state = {"verified_customer_id": None}

def dispatch(name, args):
    """返回 (content, is_error)"""
    if name == "get_customer":
        # 假设校验通过
        state["verified_customer_id"] = args["customer_id"]
        return json.dumps({"customer_id": args["customer_id"], "verified": True}), False

    if name == "process_refund":
        vid = state["verified_customer_id"]
        if vid is None:
            return ("PRECONDITION_FAILED: 尚未验证客户身份。"
                    "请先调用 get_customer 并获得 verified=true。"), True
        if args.get("customer_id") != vid:
            return "PRECONDITION_FAILED: 退款客户与已验证客户不一致。", True
        return json.dumps({"refund_id": "R-1", "amount": args["amount"]}), False

    return f"未知工具 {name}", True

# 在循环中:
# content, is_err = dispatch(block.name, block.input)
# results.append({"type": "tool_result", "tool_use_id": block.id,
#                 "content": content, "is_error": is_err})

工具定义中 get_customer 需要 customer_id,process_refund 需要 customer_id、order_id、amount。检查结果:无论系统提示怎么写,process_refund 只有在 get_customer 成功后才会真正执行;把系统提示里"先验证"的说明删掉再跑几次,门依然有效。

自测清单

  • 程序强制与提示引导分别提供怎样的保证?各自适合什么场景?
  • 为什么即使有 few-shot 和强调措辞,提示也无法让违规率归零?
  • 设计一个前置条件门:它需要记录什么状态?被拦截时应该返回什么?
  • 客户一次提出三个诉求时,你的分解、调查、合并流程是怎样的?
  • 交接给看不到对话记录的人工时,摘要至少应包含哪些字段?

对应题目(2)

题目归类由 AI 判断,仅供参考。

练习这 2 道题