> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inputapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 工具调用

> 接收函数调用、执行本地逻辑，再把结果交还模型。

当前 Chat ↔ Responses 函数工具转换没有复制 strict 字段；不要将原生声明、协议转换与上游默认值视为相同保证。工具参数仍需应用验证。详见 [工具选择与并行控制](/zh/guides/tool-controls)。

工具调用由应用完成执行。模型返回函数名和参数，网关负责转发或协议转换；声明一个工具不会让网关替你执行本地函数。

## 完成一次调用循环

1. 请求携带 `tools`，选择明确支持函数工具和所用参数的模型。
2. 检查 assistant 返回的 `tool_calls`；没有工具调用时，按普通回复处理。
3. 校验工具名称和参数，在应用中执行允许的函数。
4. 将原 assistant 消息和每个调用对应的 `role: tool` 结果追加到历史，再请求模型。
5. 模型可能继续请求工具，因此限制轮数、执行时间和总工作量。

## 可运行示例：本地乘法

按 [TypeScript SDK](/zh/guides/typescript)准备环境，保存为 `tool-calling.mts`，运行 `node tool-calling.mts`。示例只开放纯计算函数 `multiply`，最多请求模型三次；使用 `strict: true`，需要模型和渠道支持严格工具参数。

```typescript theme={null}
import OpenAI from 'openai';

const { API_BASE_URL, API_KEY, API_MODEL } = process.env;
if (!API_BASE_URL || !API_KEY || !API_MODEL) {
  throw new Error('Set API_BASE_URL, API_KEY, and API_MODEL first.');
}
const client = new OpenAI({
  baseURL: API_BASE_URL.replace(/\/+$/, ''),
  apiKey: API_KEY,
  timeout: 60_000,
  maxRetries: 0,
});
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
  { role: 'user', content: 'What is 7 times 8? Use multiply.' },
];
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [{
  type: 'function',
  function: {
    name: 'multiply',
    description: 'Multiply two finite numbers.',
    strict: true,
    parameters: {
      type: 'object',
      properties: { a: { type: 'number' }, b: { type: 'number' } },
      required: ['a', 'b'],
      additionalProperties: false,
    },
  },
}];

try {
  let completed = false;
  for (let round = 0; round < 3; round++) {
    const result = await client.chat.completions.create({ model: API_MODEL, messages, tools });
    const choice = result.choices[0];
    if (!choice || choice.message.refusal) throw new Error('No usable reply.');
    const calls = choice.message.tool_calls ?? [];
    if (calls.length === 0) {
      if (choice.finish_reason !== 'stop' || !choice.message.content) {
        throw new Error('Incomplete text reply.');
      }
      console.log(choice.message.content);
      completed = true;
      break;
    }
    if (choice.finish_reason !== 'tool_calls') throw new Error('Incomplete tool calls.');
    messages.push(choice.message);
    for (const call of calls) {
      if (call.type !== 'function' || call.function.name !== 'multiply' || !call.id) {
        throw new Error('Unsupported tool call.');
      }
      const args = JSON.parse(call.function.arguments);
      if (!args || Array.isArray(args) || Object.keys(args).length !== 2
        || !Number.isFinite(args.a) || !Number.isFinite(args.b)) {
        throw new Error('Invalid tool arguments.');
      }
      const value = args.a * args.b;
      if (!Number.isFinite(value)) throw new Error('Invalid tool result.');
      messages.push({ role: 'tool', tool_call_id: call.id, content: JSON.stringify({ value }) });
    }
  }
  if (!completed) throw new Error('Tool round limit reached.');
} catch (error) {
  console.error(error instanceof OpenAI.APIError && error.status
    ? `Request failed (HTTP ${error.status}). Check the request logs.`
    : 'Tool workflow failed: check completion, tool names, arguments, and round limit.');
  process.exitCode = 1;
}
```

本例允许一次回复中出现多个调用，并逐一回传 `tool_call_id`。模型也可能直接回答，结果文本由实际模型决定。未知函数、非法参数、非完成输出或达到轮数上限时，示例以失败退出。

`function.arguments` 是 JSON 字符串，不是可信代码。即使使用严格模式，执行前也要做业务校验。真实系统中的查数据、写数据等工具，还必须根据当前用户权限限制可操作范围；不能把模型生成的参数当作授权。不要用 `eval`、任意 shell 或动态函数名分发来实现此示例。

## Chat Completions 与 Responses 的区别

| 内容 | Chat Completions | Responses |
| - | - | - |
| 函数定义 | `tools[].function.name` / `parameters` | 函数的 `name` / `parameters` 位于工具对象顶层 |
| 模型调用 | `message.tool_calls[]` | `output` 中的 `function_call` 项 |
| 回传结果 | `role: tool`，关联 `tool_call_id` | `type: function_call_output`，关联 `call_id`，结果放入 `output` |

Responses 的 `call_id` 不等同于输出项自身的 `id`。不要把上面的 Chat 消息原样发送到 Responses；还需保留该模型要求的其他输出项和上下文。

先验证非流式循环，再接入流式工具调用。流式 `arguments` 可能被拆分成多个片段，应按调用索引/ID 汇总，等参数完整后再解析和执行，不能每收到一段就调用一次函数。

[Chat Completions 参考](/zh/api-reference/chat-completions) · [流式输出](/zh/guides/streaming)

## Python：Responses 函数调用循环

保存为 `responses-tools.py`，按 [Python SDK](/zh/guides/python)配置后运行 `python responses-tools.py`。选择支持 Responses、严格函数参数及无状态历史重放的模型和渠道。请求还使用 `store: false` 与 `include: ["reasoning.encrypted_content"]`，兼容前提见[多轮对话](/zh/guides/conversations)。

```python theme={null}
import json
import math
import os
from openai import OpenAI, APIConnectionError, APIStatusError

history = [{"role": "user", "content": "What is 7 times 8? Use multiply."}]
tools = [{
    "type": "function", "name": "multiply", "description": "Multiply two finite numbers.",
    "strict": True,
    "parameters": {
        "type": "object", "properties": {"a": {"type": "number"}, "b": {"type": "number"}},
        "required": ["a", "b"], "additionalProperties": False,
    },
}]
seen_call_ids = set()
with OpenAI(base_url=os.environ["API_BASE_URL"].rstrip("/"),
            api_key=os.environ["API_KEY"], timeout=60.0, max_retries=0) as client:
    try:
        for round_index in range(3):
            result = client.responses.create(
                model=os.environ["API_MODEL"], input=history, tools=tools,
                instructions="Use multiply for arithmetic, then answer briefly.",
                store=False, include=["reasoning.encrypted_content"],
            )
            if result.status != "completed":
                raise ValueError("Response did not complete.")
            calls = []
            for item in result.output:
                if item.type == "function_call":
                    if getattr(item, "status", None) not in (None, "completed"):
                        raise ValueError("Function call did not complete.")
                    calls.append(item)
                elif item.type == "message":
                    if item.status != "completed" or any(part.type != "output_text" for part in item.content):
                        raise ValueError("Refusal or incomplete message.")
                elif item.type != "reasoning":
                    raise ValueError("Unsupported output item.")
            if not calls:
                if not result.output_text.strip():
                    raise ValueError("No final text.")
                print(result.output_text)
                break
            if round_index == 2 or len(calls) > 4:
                raise ValueError("Tool round or call limit reached.")
            outputs = []
            for call in calls:
                if (call.name != "multiply" or not isinstance(call.call_id, str)
                        or not call.call_id.strip() or call.call_id in seen_call_ids):
                    raise ValueError("Unknown tool or invalid call ID.")
                args = json.loads(call.arguments)
                if not isinstance(args, dict) or set(args) != {"a", "b"}:
                    raise ValueError("Invalid tool arguments.")
                if any(type(value) not in (int, float) or not math.isfinite(value) for value in args.values()):
                    raise ValueError("Expected finite numbers.")
                value = args["a"] * args["b"]
                if not math.isfinite(value):
                    raise ValueError("Invalid tool result.")
                seen_call_ids.add(call.call_id)
                outputs.append({
                    "type": "function_call_output", "call_id": call.call_id,
                    "output": json.dumps({"value": value}, allow_nan=False),
                })
            history.extend(item.model_dump(exclude_none=True) for item in result.output)
            history.extend(outputs)
    except APIStatusError as error:
        raise SystemExit(f"Request failed (HTTP {error.status_code}). No automatic retry.")
    except APIConnectionError:
        raise SystemExit("Connection failed. No automatic retry.")
    except (ValueError, TypeError, AttributeError, OverflowError):
        raise SystemExit("Tool workflow failed: check output, call IDs, arguments, and limits.")
```

示例最多发起三次模型请求，每轮最多接受四个函数调用；最后一轮仍要求工具时直接失败，不再执行。它保留完整输出项，通过 `call_id` 关联结果，拒绝重复调用 ID、未知工具、布尔值冒充数字、非有限数值和溢出结果。函数只做本地乘法，没有外部副作用；业务工具需额外设计授权、幂等和执行超时。每次模型请求的 60 秒超时不是整个流程的总时限。

参考：[OpenAI 函数调用说明](https://developers.openai.com/api/docs/guides/function-calling)。

## 原生协议与流式工具

[Claude Messages](/zh/guides/native-claude)与 [Gemini generateContent](/zh/guides/native-gemini)提供独立的原生协议接入示例。需要组装工具参数分片并执行函数时，见 [Chat / Responses 流式工具调用](/zh/guides/streaming-tools)。

原生协议的可运行 SSE 与工具闭环见 [Claude](/zh/guides/native-claude-streaming)和 [Gemini](/zh/guides/native-gemini-streaming)，包含完成校验与签名保留。

[Read in English](/en/guides/tool-calling)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.