首页 / 文章 / 实用笔记:第三部分 | “工具使用”,端到端:三阶段的智能代理循环

实用笔记:第三部分 | “工具使用”,端到端:三阶段的智能代理循环

《实用笔记》第三部分操作指南:‘tooluse’端到端流程——适用于采用该模式的团队的代理循环机制,包括合同、校验以及即插即用代码模块。

3502 词

可将此内容作为“第三部分 | ‘tool_use’,端到端:三轮迭代中的智能循环”中理念的面向操作员的重构版本:清晰的阶段划分、有序的代码模块以及能够贯穿交接过程的恢复说明。 将“概览”阶段视为可度量的界面使用效果最为理想。在扩大范围之前,先记录一份最佳案例、一个故障场景以及回滚说明。 需同时记录正常流程与恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的组成部分,而非后续的优化内容。

1. 循环的结构

对于第1点“阶段的架构”,在修改代码之前需明确输入参数、该步骤的负责人以及退出标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。相比庞大的脚本,更应采用小型且可测试的单元。当某个步骤失败时,故障原因应能指向单一责任主体,而非复杂的流程链。应在网关处进行身份验证,在数据层再次授权——仅凭承载令牌并不足以界定租户边界。

2. 工具声明

在“声明工具”阶段,需在修改代码之前明确输入内容、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与已验证输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 在网关处进行身份验证,在数据层再次授权。仅凭承载令牌并不足以界定租户边界。

"tools": [
  {
    "name": "get_calendar_event",
    "description": "Look up a calendar event by a natural-language query. Returns the event's start time and location.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "query": { "type": "string", "description": "What to search for, e.g. 'meeting in London tomorrow'" }
      },
      "required": ["query"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_weather",
    "description": "Get the forecast for a city on a given date. Returns condition and temperature in Celsius.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "city": { "type": "string", "description": "City name, e.g. 'London'" },
        "date": { "type": "string", "description": "ISO date, e.g. '2026-07-14'" }
      },
      "required": ["city", "date"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_travel_time",
    "description": "Estimate door-to-door travel time between two places. Returns minutes.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "origin": { "type": "string", "description": "Starting location" },
        "destination": { "type": "string", "description": "Ending location" }
      },
      "required": ["origin", "destination"],
      "additionalProperties": false
    }
  }
]

2.1. 仅输入——没有输出或错误模式

在仅输入的2 1阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 在功能结果旁记录执行时间以及令牌或查询成本。提前显示成本可避免在流程从演示环境切换到共享环境时出现意外费用。 在网关处进行身份验证,在数据层面重新授权。仅凭承载令牌并不足以界定租户边界。 在仅输入的2 1阶段,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 需同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及死信处理都是产品功能的一部分,而非后续需要补充的内容。

2.2. 控制 Claude 调用工具的时机

在处理“2.2 控制时机”这一阶段时,首先需明确相关规范:所需输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改不会出错。 建议使用小型、可测试的单元而非庞大的脚本。当某个步骤失败时,故障应能指向具体的责任模块,而非复杂的流程链。 需为每次工具调用记录工具名称、参数哈希值、响应延迟及最终结果。没有这些记录的话,调试代理循环会耗费大量时间。

{
  "type": "auto" | "any" | "tool" | "none",
  "name": "get_weather",              // required ONLY when type is "tool"
  "disable_parallel_tool_use": false  // optional; default false
}
response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "any", "disable_parallel_tool_use": True},  # must call exactly one tool
    messages=messages,
)

3. 第一次迭代 — Claude 请求工具

在完成第1轮的3次Claude迭代时,首先写下契约:所需的输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将这一阶段视为输入与验证后输出之间的契约。为相关成果命名,明确成功判定标准,杜绝无声的半完成状态。 需记录每次调用的工具名称、参数哈希值、延迟时间以及最终结果。没有这些记录,调试代理将陷入无休止的循环,耗费大量时间。

messages = [{"role": "user",
             "content": "I have a meeting in London tomorrow
                         — should I bring an umbrella, and
                         when should I leave home to be on time?"}]

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,                    # the three strict definitions from Section 2
    tool_choice={"type": "auto"},   # let Claude decide whether, and what, to call
    messages=messages,
)
{
  "id": "msg_01...",
  "role": "assistant",
  "stop_reason": "tool_use",
  "content": [
    { "type": "text", "text": "Let me check your meeting details and the London forecast." },
    { "type": "tool_use", "id": "toolu_01Cal", "name": "get_calendar_event",
      "input": { "query": "meeting in London tomorrow" } },
    { "type": "tool_use", "id": "toolu_01Wx", "name": "get_weather",
      "input": { "city": "London", "date": "2026-07-14" } }
  ]
}
tool_calls = [block for block in response.content if block.type == "tool_use"]

4. 执行工具

在完成“执行工具”这四个阶段时,首先需明确相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改始终符合预期。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。 需为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。没有这些记录,调试过程将会浪费大量时间。 在完成“执行工具”这四个阶段时,首先需明确相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改始终符合预期。 需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误处理方式都是产品功能的一部分,而非后续需要补充的内容。

5. 工具使用前的准备步骤与使用后的处理步骤

将“5个前置及阶段工作”视为可度量的对象来处理效果最佳。在扩大范围之前,先记录一份成功的案例、一个失败案例以及回滚说明。 相较于庞大的脚本,应优先选择小型且可测试的单元。当某一步骤失败时,故障应指向单一责任点,而非复杂的流程链。 使用结构明确的工具,并为各种副作用添加清晰的标签。主机需要在自动批准之前知道哪些调用会改变状态。

for block in tool_calls:
    if not pre_tool_use(block):                       # validate / guard
        results.append(error_result(block.id, "Blocked by policy."))
        continue
    output = execute(block.name, block.input)         # run the tool
    output = post_tool_use(block, output)             # redact / log / reshape
    results.append(tool_result(block.id, output))

6. 返回结果

将“返回结果”阶段视为可度量的界面来处理效果最佳。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。 把这一阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,绝不允许默许部分完成的情况。 使用具有严格结构定义和明确副作用标注的工具。主机需要在自动批准之前知道哪些调用会改变状态。

{
  "role": "user",
  "content": [
    {
        "type": "tool_result",
        "tool_use_id": "toolu_01Cal",
        "content": "{\"start\": \"2026-07-14T15:00\", \"location\": \"Canary Wharf, London\"}"
    },
    {
        "type": "tool_result",
        "tool_use_id": "toolu_01Wx",
        "content": "{\"condition\": \"rain\", \"temp_c\": 12}"
    }
  ]
}

延续契约

将延续合同阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,需记录一份理想运行案例、一个故障案例以及回滚说明。 在功能结果旁同时记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外账单。 应提供具有明确结构规范和清晰副作用标注的工具。主机方需要在自动批准之前知晓哪些调用会改变系统状态。 将延续合同阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,需记录一份理想运行案例、一个故障案例以及回滚说明。 需同时记录正常流程与恢复流程。重试机制、人工审核环节以及死信处理都是产品的一部分,而非后续需要补充的功能。

将所有结果视为不可信的输入

在修改代码之前,应遵循“将每个结果视为一个阶段”的原则,明确输入参数、该步骤的负责人以及退出标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。相比庞大的脚本,更应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能指向具体的责任主体,而非复杂的流程链。应在网关处进行身份验证,在数据层再次授权——仅凭承载令牌并不足以界定租户边界。

7. 第二次迭代——依赖调用

在第二次迭代的第7阶段,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与已验证输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许的半完成状态。 在网关处进行身份验证,在数据层再次授权。仅凭承载令牌并不足以界定租户边界。

{
  "role": "assistant",
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_02Tt",
      "name": "get_travel_time",
      "input": {
        "origin": "home",
        "destination": "Canary Wharf, London"
      }
    }
  ]
}
{
  "role": "user",
  "content": [
    { "type": "tool_result", "tool_use_id": "toolu_02Tt", "content": "{\"minutes\": 45}" }
  ]
}

8. 第三次迭代——综合与end_turn

在第8次迭代的第3阶段合成工作中,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 应在功能结果旁记录执行时间以及令牌或查询成本。提前显示成本可避免在流程从演示环境转向共享环境时出现意外费用。 在网关处进行身份验证,在数据层面重新授权。仅凭承载令牌并不足以界定租户边界。 在第8次迭代的第3阶段合成工作中,修改代码之前需明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 需同时记录正常流程与故障恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的组成部分,而非后续需要补充的功能。

{
  "role": "assistant",
  "stop_reason": "end_turn",
  "content": [
    {
      "type": "text",
      "text": "Yes, bring an umbrella — rain is forecast in London tomorrow, around 12°C. Your meeting is at 3:00 PM in Canary Wharf, roughly 45 minutes away, so leave home by about 2:00 PM to arrive with a buffer."
    }
  ]
}

9. 代码中的完整循环

在处理“9. 完整循环”这一阶段时,首先需明确相关约定:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 建议采用小型、可测试的单元而非冗长的脚本。当某个步骤出现故障时,故障应指向单一的责任模块,而非复杂的流程链。 需为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。没有这些记录的话,调试循环结构将会耗费大量时间。

import anthropic
client = anthropic.Anthropic()

messages = [{"role": "user", "content": user_request}]
MAX_ITERATIONS = 10
for _ in range(MAX_ITERATIONS):
    response = client.messages.create(
        model="claude-opus-4-8", max_tokens=1024, tools=tools, messages=messages,
    )
    messages.append({"role": "assistant", "content": response.content})
    if response.stop_reason != "tool_use":
        break   # end_turn (or another reason): done
    results = []
    for block in (b for b in response.content if b.type == "tool_use"):
        if not pre_tool_use(block):   # your guard - may block the call
            results.append({"type": "tool_result", "tool_use_id": block.id,
                            "content": "Blocked by policy.", "is_error": True})
            continue
        try:
            output = execute(block.name, block.input)   # run it (concurrently if independent)
            output = post_tool_use(block, output)   # redact / log / reshape
            results.append({"type": "tool_result", "tool_use_id": block.id, "content": output})
        except Exception as e:
            results.append({"type": "tool_result", "tool_use_id": block.id,
                            "content": f"Error: {e}", "is_error": True})
    messages.append({"role": "user", "content": results})   # one result per tool_use
print(response.content[-1].text)

10. 考试相关

在完成“10个考试准备步骤”时,首先写下合同条款:所需的输入参数、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合约定。 将这一阶段视为输入与验证后输出之间的契约。为相关成果命名,明确成功判定标准,杜绝无声的半完成状态。 每次调用时都要记录工具名称、参数哈希值、延迟时间以及执行结果。没有这些记录,调试过程将会浪费大量时间。

系列内容下一篇

在处理系列中的“Next”阶段时,首先需明确接口规范:所需的输入参数、成功标识以及部分失败时的处理方式。这份清单能确保后续的代码修改始终符合预期。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。 需为每次调用记录工具名称、参数哈希值、延迟时间以及最终结果。没有这些记录,调试过程将会浪费大量时间。 在处理系列中的“Next”阶段时,首先需明确接口规范:所需的输入参数、成功标识以及部分失败时的处理方式。这份清单能确保后续的代码修改始终符合预期。 需同时记录正常流程与异常恢复流程。重试机制、人工审核环节以及错误消息处理都是产品功能的一部分,而非后续需要补充的内容。

操作检查清单

在处理操作检查清单阶段时,首先写下合同细节:所需输入、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。

将配置信息与应用程序代码分开。环境文件、密钥存储和功能开关应集中存放,以便操作人员无需查看整个系统结构即可进行审计。

为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。没有这些记录,调试代理将陷入无止境的循环,耗费大量时间。

保持系统状态结构简洁且类型明确。嵌套的数据结构会掩盖哪个节点修改了哪个字段,还会导致中断后无法继续执行。

只要预算允许,就在持续集成过程中使用测试用例而非真实的付费 API 来执行关键路径的冒烟测试。

将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,并拒绝默许的半完成状态。

在升级整个系统之前,先冻结各版本,为关键流程记录标准输出文本,并确认回滚步骤。共享环境需要设置访问速率限制、租户身份验证,以及明确的密钥轮换负责人。与其追求花哨的一次性演示,不如注重扎实的可靠性。

针对 87cde7765dfc 的批量处理说明:不要将服务提供商的密钥放入代码仓库,为每个会话设置令牌使用上限,并将输出文本与评估用文件一起存储,以便后续更换模型时仍能保持对比性。

在将加固阶段视为可测量的表面时,第0阶段的处理效果最佳。在扩大范围之前,需记录一份完美的测试用例、一个故障案例以及回滚说明。 应将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,绝不允许默许不完整的处理结果。

加固细节0/929:需测量该阶段的执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观判断来决定是否保留该变更。

在强化措施的第一阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审计。

强化措施细节 1/929:针对此项措施,需统计执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观经验来决定是否保留该变更。

在处理强化措施的第2阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合要求。 相比冗长的脚本,更应采用小型且可测试的单元。当某个步骤失败时,故障应能指向单一的责任模块,而非复杂的流程链。

强化措施细节2/929:需测量该步骤的运行时间、错误类型以及代币消耗情况,然后依据固定的评估标准而非主观判断来决定是否保留该修改。

将强化措施的第3阶段视为可量化的目标面处理效果最佳。在扩大范围之前,先记录一份理想的运行示例、一个失败案例以及回滚说明。 在功能结果旁同时记录时间消耗及代币或查询成本。提前明确成本情况,可避免在从演示环境过渡到共享环境时出现意外支出。

强化措施细节3/929:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个别案例来决定是否保留该变更。

在强化措施的第4阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新执行该步骤,而无需猜测隐藏状态。需同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及错误处理方式都是产品本身的组成部分,而非后续的优化工作。

强化措施细节4/929:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个别案例来决定是否保留该变更。

在处理强化措施的第5阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合约定。 将这一阶段视为输入与验证后输出之间的契约。为相关产物命名,明确成功判定标准,杜绝默许部分完成的情况。

强化措施细节5/929:需测量该步骤的耗时、错误类型以及令牌消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留该变更。

将强化措施的第6阶段视为可度量的对象来处理效果最佳。在扩大范围之前,先记录一份标准操作示例、一个失败案例以及回滚说明。 应将配置信息与应用程序代码分开。环境文件、密钥存储和功能开关应集中存放于一处,以便操作人员无需查看全部代码结构即可进行审计。

强化措施细节6/929:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在强化措施的第7阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。相比复杂的脚本,更应采用小型且可测试的单元。当某一步骤失败时,故障原因应能指向单一责任方,而非混乱的整个流程。

强化措施细节7/929:为该记录测量运行时间、错误类型以及令牌消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在处理强化建议的第8阶段时,首先写下相关约定:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合初始要求。

在功能结果旁记录执行时间以及令牌或查询成本。提前了解这些成本信息,可避免在系统从演示环境过渡到共享环境时出现意外费用。

强化建议的第8/929条要求:先测量该建议对应的执行时间、错误类型以及令牌消耗情况,再依据固定的评估标准而非个人经验来决定是否保留相关修改。

将强化建议的第9阶段视为可度量的工作面来处理效果最佳。在扩大范围之前,先记录一个理想运行案例、一个失败案例以及回滚说明。

应同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及死信处理都属于产品功能的一部分,而非后续需要补充的内容。

强化措施细节 9/929:记录该任务的执行时间、错误类型以及代币消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

在强化措施的第10阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。应将此阶段视为输入参数与验证后输出结果之间的契约,为相关成果命名、定义成功检测标准,并拒绝默许的半完成状态。

强化措施细节 10/929:记录该任务的执行时间、错误类型以及代币消耗情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。