Claude API 工具调用如何限制次数?用轮数、调用预算和停止条件控制循环

用应用层模型轮数、工具执行预算和停止原因约束 Claude API 工具循环。包含只读订单演示、tool_result 回传、超预算停止与验证方法。

Claude API 的客户端工具会把执行权交给你的程序。要限制它调用多少次,最直接的办法是给程序设置三道边界:最多请求模型几轮、最多执行工具几次,以及遇到什么响应就停止。只在提示词里写“最多调用三次”,不能替代执行前的计数判断。

本文面向用 Python 自建工具循环的开发者,使用直连 Anthropic Messages API。下面的订单查询是虚构的本地演示数据,没有接入真实订单系统,也没有进行付费 API 实测。接口依据于 2026 年 10 月 1 日核对。

Claude API 工具调用如何限制次数?用轮数、调用预算和停止条件控制循环

先区分三种容易混淆的“次数”

要限制什么 在哪一层控制 本例的设置
向模型发送请求的轮数 应用中的循环 最多 6 轮,防止一直请求下一步
实际执行客户端工具的次数 调用本地函数前 最多 3 次,失败的执行尝试也计数
同一响应中的并行工具调用 tool_choice 参数与应用校验 请求每轮最多一个工具调用,仍检查实际返回数量

官方工具使用说明区分客户端工具与服务器工具。本文只控制由自己程序执行的客户端工具;web_search 等服务器工具在 Anthropic 一侧运行,不能直接套用这里的本地函数计数。账户的请求速率与费用限制也是另一层配置。

disable_parallel_tool_use: true 配合 tool_choice.type: auto 用于限制单轮并行调用,不代表整个会话只会调用一次工具。总次数仍需在应用层维护。

准备运行环境和一个只读工具

  1. 安装 Python 3.10 或更新版本,在终端执行 python -m pip install requests。
  2. 在运行脚本的进程中配置 ANTHROPIC_API_KEY,并把 ANTHROPIC_MODEL 设置为账户可用、支持工具调用的准确模型 ID。模型名称与能力可查官方模型说明。
  3. 把下面代码保存为 tool_budget.py,执行 python tool_budget.py。脚本会发出模型请求,实际费用以账户用量为准;先用演示查询核对控制逻辑。

环境变量没有配置时,脚本会立即停止。密钥仅放在请求头中,不要写进工具参数、网页代码或打印日志。

完整示例:先检查预算,再执行工具

import json
import os
import time
import requests

MAX_ROUNDS = 6
MAX_TOOL_CALLS = 3
DEADLINE_SECONDS = 90
model = os.environ["ANTHROPIC_MODEL"]
headers = {
    "x-api-key": os.environ["ANTHROPIC_API_KEY"],
    "anthropic-version": "2023-06-01",
    "content-type": "application/json",
}
tools = [{
    "name": "lookup_demo_order",
    "description": "查询本地演示订单状态;不会修改订单。",
    "input_schema": {
        "type": "object",
        "properties": {"order_id": {"type": "string"}},
        "required": ["order_id"],
        "additionalProperties": False,
    },
}]
messages = [{"role": "user", "content":
    "请调用查询工具,告诉我演示订单 DEMO-1001 的状态。"}]

def dispatch(call):
    if call["name"] != "lookup_demo_order":
        raise ValueError("工具不在允许名单中")
    order_id = call["input"].get("order_id")
    if not isinstance(order_id, str) or len(order_id) > 80:
        raise ValueError("订单参数不合法")
    # 虚构演示数据;真实项目替换为自己的只读查询函数。
    data = {"DEMO-1001": {"status": "已发货"}}
    return data.get(order_id, {"status": "未找到演示订单"})

started = time.monotonic()
calls_used = 0
for round_no in range(1, MAX_ROUNDS + 1):
    remaining = DEADLINE_SECONDS - (time.monotonic() - started)
    if remaining <= 0:
        raise RuntimeError("已到执行时限,停止请求和工具执行")
    response = requests.post(
        "https://api.anthropic.com/v1/messages",
        headers=headers,
        json={"model": model, "max_tokens": 2048,
              "tools": tools,
              "tool_choice": {"type": "auto",
                              "disable_parallel_tool_use": True},
              "messages": messages},
        timeout=(10, min(30, remaining)),
    )
    response.raise_for_status()
    message = response.json()
    blocks = message["content"]
    reason = message.get("stop_reason")
    print("round", round_no, "stop", reason, "calls_used", calls_used)

    if reason == "end_turn":
        print("\n".join(b["text"] for b in blocks if b["type"] == "text"))
        break
    if reason != "tool_use":
        # 包括 max_tokens;不执行可能未完成的工具输入。
        raise RuntimeError("模型未正常交出完整工具调用:" + str(reason))
    calls = [b for b in blocks if b["type"] == "tool_use"]
    if not calls:
        raise RuntimeError("tool_use 停止原因与内容不一致")
    if len(calls) > 1:
        raise RuntimeError("本例要求单轮一个工具,多调用响应停止执行")
    if calls_used + len(calls) > MAX_TOOL_CALLS:
        raise RuntimeError("工具预算不足,本轮工具全部停止执行")
    if time.monotonic() - started >= DEADLINE_SECONDS:
        raise RuntimeError("已到执行时限,本轮工具停止执行")

    results = []
    for call in calls:
        calls_used += 1
        result = {"type": "tool_result", "tool_use_id": call["id"]}
        try:
            result["content"] = json.dumps(dispatch(call), ensure_ascii=False)
        except (ValueError, TypeError, KeyError):
            result.update(is_error=True, content="查询失败,请检查工具和参数。")
        results.append(result)
    # 保留完整 assistant 内容,包括可能返回的 thinking 块。
    messages.append({"role": "assistant", "content": blocks})
    messages.append({"role": "user", "content": results})
else:
    raise RuntimeError("模型请求达到轮数上限,任务未完成")

这里先检查本轮全部调用是否装得进剩余预算,再开始执行,避免并行返回多个调用时只做了一半。每个 tool_result 用对应的 tool_use_id 回传,紧接在包含这些调用的 assistant 消息之后;格式依据官方工具结果处理文档。

怎样确认限制生效

  • 正常路径应看到一轮返回 tool_use,本地执行次数变为 1,之后在 end_turn 分支得到答案。答案措辞不固定,但订单状态应与本地“已发货”一致。
  • 把 MAX_TOOL_CALLS 改为 0,再运行原请求:当模型提出工具调用时,程序应在执行前报告预算不足;本地函数不应执行。
  • 把 MAX_ROUNDS 改为 1:如果第一轮仅发出工具调用,程序会在回传结果前结束并明确报任务未完成,不应伪装成已得到最终答案。
  • 给 dispatch 增加本地计数或使用模拟响应测试重复调用:即使模型不断请求,执行尝试也不能超过 3 次。记录的是预期验收方法,并非本文的线上测试结果。

循环停不下来时检查哪里

同一工具重复被调用,先看上一次结果是否给了模型需要的信息,再检查 tool_use_id 和消息顺序。工具总是失败,检查工具名称、输入字段与错误结果;不要把空字符串当成功结果回传。响应因为 max_tokens 停止时,先调整输出预算或减少任务,再重新发起经过核对的请求。

本例的时限在每轮与执行前检查,HTTP 连接和读取另有超时;它不能强行中断已经卡住的任意本地函数。接入数据库、远端服务时,函数本身也必须配置超时。查询有副作用、会扣费或改订单的工具,还需额外做权限校验和幂等控制,不能直接把这个只读演示改成无限重试。

相关问答

达到工具预算后,还能让模型写一段解释吗?

可以另发一个明确禁用工具、只总结已有结果的请求,但那也消耗一个模型请求和输出预算。应为它单独预留轮数,并把“查询未完成”告诉读者。本例直接停止,便于先验证限制确实有效。

设置单轮只调用一个工具,会不会保证任务成功?

不会。它控制并行行为;工具返回的数据、模型输出长度、网络状态和剩余总预算仍会影响完成情况。接受任务前先明确成功条件,完成时同时核对结果与停止原因。

Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30412.html

赞 (0)
AI小管家的头像AI小管家
Kimi 文献综述提示词怎么写?先建证据矩阵,再综合不同结论
上一篇 1天前
Kimi 怎么辅助写同人文?用设定卡和章节状态表避免人物前后矛盾
下一篇 1天前

相关推荐

联系我们

联系我们

1

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
分享本页
返回顶部