Claude API 的客户端工具会把执行权交给你的程序。要限制它调用多少次,最直接的办法是给程序设置三道边界:最多请求模型几轮、最多执行工具几次,以及遇到什么响应就停止。只在提示词里写“最多调用三次”,不能替代执行前的计数判断。
本文面向用 Python 自建工具循环的开发者,使用直连 Anthropic Messages API。下面的订单查询是虚构的本地演示数据,没有接入真实订单系统,也没有进行付费 API 实测。接口依据于 2026 年 10 月 1 日核对。

先区分三种容易混淆的“次数”
| 要限制什么 | 在哪一层控制 | 本例的设置 |
|---|---|---|
| 向模型发送请求的轮数 | 应用中的循环 | 最多 6 轮,防止一直请求下一步 |
| 实际执行客户端工具的次数 | 调用本地函数前 | 最多 3 次,失败的执行尝试也计数 |
| 同一响应中的并行工具调用 | tool_choice 参数与应用校验 | 请求每轮最多一个工具调用,仍检查实际返回数量 |
官方工具使用说明区分客户端工具与服务器工具。本文只控制由自己程序执行的客户端工具;web_search 等服务器工具在 Anthropic 一侧运行,不能直接套用这里的本地函数计数。账户的请求速率与费用限制也是另一层配置。
disable_parallel_tool_use: true 配合 tool_choice.type: auto 用于限制单轮并行调用,不代表整个会话只会调用一次工具。总次数仍需在应用层维护。
准备运行环境和一个只读工具
- 安装 Python 3.10 或更新版本,在终端执行
python -m pip install requests。 - 在运行脚本的进程中配置
ANTHROPIC_API_KEY,并把ANTHROPIC_MODEL设置为账户可用、支持工具调用的准确模型 ID。模型名称与能力可查官方模型说明。 - 把下面代码保存为
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