Function calling: как агент взаимодействует с внешними системами
Модель сама ничего не вызывает: она лишь просит вашу программу выполнить функцию. Разбираем весь цикл по шагам, с кодом на Python и расчётом цены.
5 мин · · агенты · разработка
Когда говорят, что агент «сходил в базу» или «создал задачу в трекере», может показаться, что модель сама подключается к системам. На деле всё проще и надёжнее: взаимодействие агента с внешними системами через function calling построено на том, что модель только формулирует просьбу, а выполняет её ваш код. Ниже — полный цикл по шагам, рабочий пример на Python и расчёт того, во что такой цикл обходится.
Идея в одном абзаце
Вы описываете модели набор функций: имя, назначение, параметры. Модель читает вопрос пользователя и либо отвечает сразу, либо возвращает структурированную просьбу вида «вызови get_order_status с order_id = A-1042». Ваша программа выполняет вызов, отправляет результат обратно, и модель формулирует финальный ответ. Модель ничего не запускает и не получает доступа к вашим системам — только к тексту, который вы ей вернули.
Цикл по шагам
- Описание инструментов. В запрос добавляется список
toolsс JSON-схемой параметров каждой функции. - Решение модели. Если нужна функция, ответ приходит не с текстом, а с вызовом: имя и аргументы в JSON. Признак — поле
tool_callsв OpenAI-формате или блокtool_useиstop_reason: "tool_use"в формате Anthropic. - Выполнение. Ваш код разбирает аргументы, проверяет их и вызывает настоящую функцию: запрос в базу, HTTP-вызов, чтение файла.
- Возврат результата. Вы добавляете в историю сообщение с результатом, привязанное к идентификатору вызова.
- Повтор. Вы снова отправляете всю историю. Модель либо делает ещё вызов, либо пишет ответ. Цикл заканчивается, когда в ответе нет вызовов.
Этот цикл и есть агент: всё остальное (память, планирование, сабагенты) надстраивается сверху.
Пример на Python (OpenAI-формат)
Код ниже работает через /v1/chat/completions. Адрес оканчивается на /v1, как для любого клиента на OpenAI SDK.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_ваш_ключ")
def get_order_status(order_id: str) -> dict:
# здесь был бы запрос в вашу систему
return {"order_id": order_id, "status": "shipped", "eta_days": 2}
REGISTRY = {"get_order_status": get_order_status}
tools = [{
"type": "function",
"function": {Что здесь важно:
for _ in range(5)— предохранитель. Агент, который по ошибке зовёт функцию снова и снова, расходует баланс. О защите — в статье агент зациклился и потратил бюджет.- Аргументы приходят строкой с JSON и могут быть невалидными: оборачивайте
json.loadsвtry, а результат ошибки возвращайте модели как данные, чтобы она могла поправиться. - Функции берутся из белого списка
REGISTRY, а не черезeval: имя от модели нельзя исполнять напрямую. - Результат всегда строка. Верните компактный JSON, а не страницу HTML.
Параметры и поля ответа описаны в справочнике по chat completions.
То же в формате Anthropic
Для Claude можно использовать /v1/messages. Структура отличается названиями, суть цикла та же:
import anthropic
client = anthropic.Anthropic(base_url="https://api.zukko.pro", api_key="fetch_ваш_ключ")
tools = [{
"name": "get_order_status",
"description": "Возвращает статус заказа по его номеру.",
"input_schema": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
}]
Здесь base_url без /v1: официальный Anthropic SDK добавляет путь сам. Подробный разбор формата — в статье tool use в Claude на Python.
Ollama и другие локальные рантаймы
Запрос «ollama tool calling» отражает тот же принцип: локальная модель тоже получает описание функций и возвращает просьбу о вызове. Но поддержка зависит от конкретной модели и версии Ollama, а формат запроса определяет сама программа. Сверяйтесь с документацией Ollama: какие модели умеют вызывать инструменты и как передаются tools. Цикл на стороне вашего кода остаётся тем же.
Что влияет на стоимость
Каждый круг цикла — отдельный запрос, в который снова входят описание инструментов, вся история и результаты функций. Поэтому цена растёт не от числа вызовов самих по себе, а от длины истории.
Расчёт-пример (цены на 18 октября 2026, gpt-6.1-sol: вход $0.27, выход $1.32 за 1M). Допущения: описание инструмента и вопрос — 500 токенов, решение модели — 80 токенов, результат функции — 150 токенов, финальный ответ — 200 токенов.
- Круг 1: вход 500, выход 80. 500 × 0.27 / 1 000 000 + 80 × 1.32 / 1 000 000 = $0.000135 + $0.0001056 = $0.0002406.
- Круг 2: вход 500 + 80 + 150 = 730, выход 200. 730 × 0.27 / 1 000 000 + 200 × 1.32 / 1 000 000 = $0.0001971 + $0.000264 = $0.0004611.
- Итого $0.0007017, около $0.0007 за диалог; на 1 000 диалогов выходит примерно $0.70.
На deepseek-v4.1-flash ($0.013 / $0.038) те же числа дают около $0.027 на 1 000 диалогов, на claude-sonnet-5-5 ($0.4 / $2) около $1.05. Реальные суммы зависят от размера схем и результатов.
Как это уменьшить:
- Сокращайте описания и не подключайте инструменты, которые не нужны в этом диалоге.
- Возвращайте из функций только нужные поля.
- Для длинных агентных сессий используйте кэш. Для Claude скидку за чтение из кэша шлюз видит в формате
/v1/messages; в OpenAI-формате весь вход для Claude идёт по цене входа. У GPT чтение кэша видно в обоих форматах. Подробнее про кэш — на странице лимитов и кэша. - Логируйте поле
usageкаждого ответа: так видно, как растёт вход от круга к кругу и какой инструмент раздувает историю.
Какая модель надёжнее справится именно с вашим набором функций, заранее не скажешь: прогоните одни и те же сценарии на двух-трёх моделях и сравните результат и стоимость.
Частые вопросы
Модель сама подключается к базе или API?
Нет. Она возвращает имя функции и аргументы, а выполняет вызов ваш код. Поэтому права и ограничения вы задаёте сами.
Чем function calling отличается от MCP?
Function calling — механизм на уровне запроса к модели. MCP — стандарт, по которому клиент получает описания инструментов от внешнего сервера и пересылает ему вызовы, а сами функции выполняет сервер; модели клиент всё равно передаёт эти описания как tools.
Можно ли вызвать несколько функций за один раз?
Модель может вернуть несколько вызовов в одном ответе. Обработайте их все и добавьте по сообщению с результатом на каждый tool_call_id.
Что делать, если модель выдумывает аргументы?
Проверяйте схему на своей стороне, делайте параметры строгими (перечисления, обязательные поля) и возвращайте понятную ошибку, чтобы модель могла исправиться. Ключ для опытов можно создать в кабинете Zukko.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Промпт-инъекция: что это и как защитить бота и агентаОбъясняем, как работает промпт-инъекция через пользовательский ввод и чужие документы, и какие меры снижают ущерб: изоляция данных, права инструментов, лимиты ключа.
- Claude Code YOLO: режимы разрешений и работа без подтвержденийОтдельного режима YOLO в Claude Code нет, зато есть шесть режимов разрешений и гибкие правила. Разбираем, как перестать нажимать «Да» и не лишиться файлов.
- Claude Code: чек-лист лучших практик для ежедневной работыПривычки, которые делают работу с Claude Code предсказуемой: короткий CLAUDE.md, план перед правками, мелкие задачи, проверка результата и контроль расхода.
- MCP-сервер на Java: минимальный пример с одним инструментомПишем минимальный MCP-сервер на Java с одним инструментом, регистрируем его в Claude Code и учимся находить причину, если агент его не видит.