# Function calling

Как в OpenAI: опишите функции в `tools`, модель вернёт `tool_calls` и `finish_reason: tool_calls`. Выполните функцию у себя, добавьте в историю ответ модели и результат сообщением с `role: tool` и `tool_call_id` вызова, затем повторите запрос. Инструменты работают на вашей стороне и стоят только токенов.

- `tools` — Тип `function`. Тип `custom` (свободный текст, как `apply_patch` в Codex) — в Responses
- `tool_choice` — `none`, `auto`, `required`, конкретная функция или `allowed_tools` из таких функций. `allowed_tools` понимают не все модели
- `functions` — Старые `functions` и `function_call` шлюз пропускает, но модели их не понимают: ответ 400 или функции не видны модели. Пишите `tools`
- `responses` — Функция описывается без обёртки: `{"type": "function", "name": …, "parameters": …}`. Модель вернёт элемент `function_call`, результат отправьте элементом `function_call_output` с тем же `call_id`. `previous_response_id` не работает: шлите весь `input` вместе с `function_call`

**Пример запроса**

curl:

```bash
curl https://api.polyapi.ru/v1/chat/completions \
  -H "Authorization: Bearer $POLYAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-6.1-sol",
    "messages": [{"role": "user", "content": "Погода в Москве?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "parameters": {
          "type": "object",
          "properties": {"city": {"type": "string"}},
          "required": ["city"]
        }
      }
    }]
  }'
```

Python:

```python
import json
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["POLYAPI_KEY"],
    base_url="https://api.polyapi.ru/v1",
)

def get_weather(city):
    return {"city": city, "temp_c": -3}

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]
messages = [{"role": "user", "content": "Погода в Москве?"}]

r = client.chat.completions.create(model="openai/gpt-6.1-sol", messages=messages, tools=tools)
msg = r.choices[0].message
messages.append(msg)
for call in msg.tool_calls or []:
    result = get_weather(**json.loads(call.function.arguments))
    messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

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

Node.js:

```js
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.POLYAPI_KEY,
  baseURL: "https://api.polyapi.ru/v1",
});

const getWeather = ({ city }) => ({ city, temp_c: -3 });

const tools = [{
  type: "function",
  function: {
    name: "get_weather",
    parameters: {
      type: "object",
      properties: { city: { type: "string" } },
      required: ["city"],
    },
  },
}];
const messages = [{ role: "user", content: "Погода в Москве?" }];

let r = await client.chat.completions.create({ model: "openai/gpt-6.1-sol", messages, tools });
const msg = r.choices[0].message;
messages.push(msg);
for (const call of msg.tool_calls ?? []) {
  const result = getWeather(JSON.parse(call.function.arguments));
  messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(result) });
}

r = await client.chat.completions.create({ model: "openai/gpt-6.1-sol", messages, tools });
console.log(r.choices[0].message.content);
```

**Ответ: модель просит вызвать функцию**

```json
{
  "id": "chatcmpl-5f0c2b9e7d3a4e18a6c1d2b3e4f5a6b7",
  "object": "chat.completion",
  "created": 1794052800,
  "model": "openai/gpt-6.1-sol",
  "choices": [
    {
      "index": 0,
      "finish_reason": "tool_calls",
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_7Qx2mV9k",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"Москва\"}"
            }
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 58,
    "completion_tokens": 17,
    "total_tokens": 75
  }
}
```

Встроенные инструменты — `web_search`, `file_search`, `code_interpreter`, `mcp` — не поддерживаем: ответ 400 с `param: tools`. Исключение — `web_search` в Responses: его молча убираем из `tools`, и модель отвечает без поиска, иначе Codex не работал бы. Названный в `tool_choice`, он даёт 400. `web_search_options` в Chat Completions — тоже 400.

Источник: https://polyapi.ru/docs/tools
