# 工具调用 (/docs/zh-CN/tool-calling)

你在请求里描述自己的函数。模型需要用某个函数时，不会直接给出最终回答，而是返回函数名和 JSON 参数。你的代码执行函数、把结果发回去，模型再接着回答。模型自己从不执行任何东西。

工具只需按你正在用的端点格式写一次：Chat Completions、Responses 或 Anthropic Messages。同一套定义适用于该端点上的所有模型，所以把一段工具调用循环从 GPT 换到 Claude 或 GLM，只需改一行模型名。整个循环都可以用 `ohmygpt/mock` 免费测试。

## Chat Completions [#chat-completions]

### 1. 发送工具定义 [#1-发送工具定义]

```bash
curl https://api.ohmygpt.com/v1/chat/completions \
  -H "Authorization: Bearer $OHMYGPT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.4-nano",
    "messages": [{"role": "user", "content": "What is the weather in Paris?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city.",
        "parameters": {
          "type": "object",
          "properties": {"city": {"type": "string"}},
          "required": ["city"]
        }
      }
    }]
  }'
```

模型返回 `finish_reason: "tool_calls"`，以及它要发起的调用（节选）：

```json
{
  "choices": [
    {
      "index": 0,
      "finish_reason": "tool_calls",
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_wwN71lk5akb6aFGYQv9f234b",
            "type": "function",
            "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" }
          }
        ]
      }
    }
  ]
}
```

`arguments` 是 JSON 字符串，使用前先解析。

### 2. 回传结果 [#2-回传结果]

先把 assistant 消息原样追加到对话里，再为每个调用追加一条 `tool` 消息，带上对应的 `tool_call_id`，然后带着同样的 `tools` 重新发送整段对话。Python 完整示例：

```python
import json
import os

from openai import OpenAI

client = OpenAI(api_key=os.environ["OHMYGPT_API_KEY"], base_url="https://api.ohmygpt.com/v1")

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather for a city.",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string", "description": "City name, e.g. Paris"}},
                "required": ["city"],
            },
        },
    }
]


def get_weather(city: str) -> dict:
    return {"city": city, "temperature_c": 18, "condition": "cloudy"}


messages = [{"role": "user", "content": "What's the weather in Paris?"}]

response = client.chat.completions.create(model="openai/gpt-5.4-nano", messages=messages, tools=tools)
message = response.choices[0].message
messages.append(message)

for call in message.tool_calls or []:
    args = json.loads(call.function.arguments)
    messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(get_weather(**args))})

final = client.chat.completions.create(model="openai/gpt-5.4-nano", messages=messages, tools=tools)
print(final.choices[0].message.content)
```

```text
In **Paris**, it’s currently **cloudy** with a temperature of **18°C**.
```

同一段程序把模型换成 `model="anthropic/claude-haiku-4-5"`，输出为 `The weather in Paris is currently **cloudy** with a temperature of **18°C** (about 64°F).`

### 控制工具调用 [#控制工具调用]

| `tool_choice` | 效果 |
|---|---|
| `"auto"`（默认） | 由模型决定是否调用工具 |
| `"none"` | 模型直接用文本回答 |
| `"required"` | 模型必须至少调用一个工具 |
| `{"type": "function", "function": {"name": "get_time"}}` | 模型必须调用 `get_time` |

## 免费测试整个循环 [#免费测试整个循环]

`ohmygpt/mock` 的回答是确定的。请求里带有工具时，它会调用第一个工具（或 `tool_choice` 指定的那个），所有必填参数都填对应类型的零值；收到工具结果后，再回复一段文本。把上面第一个请求的模型换成 `"model": "ohmygpt/mock"`，返回：

```json
{
  "id": "chatcmpl-ohmygpt-mock",
  "object": "chat.completion",
  "model": "mock",
  "choices": [
    {
      "index": 0,
      "finish_reason": "tool_calls",
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_mock_1",
            "type": "function",
            "function": { "name": "get_weather", "arguments": "{\"city\":\"\"}" }
          }
        ]
      }
    }
  ],
  "usage": { "prompt_tokens": 73, "completion_tokens": 8, "total_tokens": 81 }
}
```

账户完成充值后即可使用 mock 模型。

## Responses [#responses]

工具定义是扁平的（`name` 和 `parameters` 与 `type` 并列）。模型的调用以 `function_call` 条目出现在 `output` 里；把结果作为 `function_call_output` 条目发回，并带上相同的 `call_id`：

```bash
curl https://api.ohmygpt.com/v1/responses \
  -H "Authorization: Bearer $OHMYGPT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ohmygpt/mock",
    "input": [
      {"role": "user", "content": "What is the weather in Paris?"},
      {"type": "function_call", "call_id": "call_mock_1", "name": "get_weather", "arguments": "{\"city\":\"Paris\"}"},
      {"type": "function_call_output", "call_id": "call_mock_1", "output": "{\"temperature_c\":18,\"condition\":\"cloudy\"}"}
    ],
    "tools": [{
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
    }]
  }'
```

第一轮返回的 output 条目如下：

```json
{ "type": "function_call", "id": "fc_0", "call_id": "call_mock_1", "name": "get_weather", "arguments": "{\"city\":\"\"}", "status": "completed" }
```

## Anthropic Messages [#anthropic-messages]

工具定义使用 `input_schema`。模型的调用是一个 `tool_use` 内容块，同时返回 `stop_reason: "tool_use"`；在下一条 user 消息里用 `tool_result` 块发回结果，并带上相同的 ID：

```bash
curl https://api.ohmygpt.com/v1/messages \
  -H "x-api-key: $OHMYGPT_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ohmygpt/mock",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "What is the weather in Paris?"},
      {"role": "assistant", "content": [{"type": "tool_use", "id": "call_mock_1", "name": "get_weather", "input": {"city": "Paris"}}]},
      {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "call_mock_1", "content": "{\"temperature_c\":18,\"condition\":\"cloudy\"}"}]}
    ],
    "tools": [{
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
    }]
  }'
```

第一轮返回的内容块如下：

```json
{ "type": "tool_use", "id": "call_mock_1", "name": "get_weather", "input": { "city": "" } }
```

## 流式输出 [#流式输出]

设置 `"stream": true` 后，调用会分段到达：先是函数名，然后是一段段字符串形式的参数片段（Chat Completions 上是 `tool_calls[].function.arguments` 增量，Responses 上是 `response.function_call_arguments.delta` 事件，Messages 上是 `input_json_delta` 事件）。把片段拼接起来，等流结束后再解析 JSON。
