API и SDKИнструкция
Function calling в Python через OpenAI-совместимый API
Передайте tools, прочитайте tool_calls и верните результат с role tool: двухшаговый цикл function calling на Python с MiniMax-M2.7.

Содержание
Function calling (вызов инструментов) позволяет модели попросить ваш код выполнить функцию. Вы передаёте в запросе список tools, модель вместо текста отвечает tool_calls, вы сами выполняете функцию и возвращаете её результат в сообщении с role: tool. После этого модель пишет итоговый ответ. В статье весь цикл разобран на Python для OpenAI-совместимого адреса https:/ с моделью MiniMax-M2.7 (id MiniMaxAI/, контекст 180K, до 8 192 токенов в ответе).
Вызов инструментов указан как поддерживаемый для каждой модели каталога (документация CheapTokens: docs, проверено 22 октября 2026 года). Нужен API-ключ; если вы ещё не делали запросов, начните с первого запроса к API.
Как работает function calling#
Модель ничего не запускает. Она лишь формирует структурированную просьбу: «вызови get_weather с {\"city\": \"Paris\"}». Реальную работу делает ваша программа и сообщает результат. Получается цикл из двух запросов:
- Запрос 1. Вы отправляете сообщение пользователя и список
tools. Модель отвечает текстом либо возвращает один или несколькоtool_calls. - Ваш код. Вы разбираете каждый вызов, запускаете нужную функцию и собираете результат.
- Запрос 2. Вы снова отправляете всю переписку: исходные сообщения, сообщение ассистента с
tool_callsи по одному сообщениюrole: toolна каждый вызов. По результатам модель пишет итоговый ответ.
Каждый запрос заново отправляет всю историю, поэтому цикл с инструментами тратит больше входных токенов, чем один вопрос. Если вы ещё не знакомы с этим, прочитайте что такое токен.
Настройка клиента#
Установите OpenAI SDK (pip install openai) и положите ключ в переменную окружения, а не в код:
export CHEAPTOKENS_API_KEY="your-key-here"Базовый адрес — https:/. Id модели берите из документации CheapTokens: у разных провайдеров одна и та же модель называется по-разному. В статье используется MiniMaxAI/.
Описание функции и первый запрос#
Функция описывается в массиве tools. Каждый элемент содержит type: function и объект function с полями name, description и parameters в виде JSON Schema. По description модель решает, когда вызвать функцию, поэтому пишите его коротко и конкретно.
Ниже — полный скрипт. Функция погоды — заглушка с выдуманными данными, поэтому внешние сервисы не нужны:
import json
import os
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'MiniMaxAI/MiniMax-M2.7'
def get_weather(city: str) -> dict:
# Stub with fake data: replace with a real lookup
fake = {'Paris': 14, 'Tokyo': 19}
return {'city': city, 'temp_c': fake.get(city, 10)}
FUNCTIONS = {'get_weather': get_weather}
tools = [
{
'type': 'function',
'function': {
'name': 'get_weather',
'description': 'Get the current temperature in Celsius for a city.',
'parameters': {
'type': 'object',
'properties': {
'city': {'type': 'string', 'description': 'City name, for example Paris'},
},
'required': ['city'],
},
},
}
]
messages = [{'role': 'user', 'content': 'What is the weather in Paris right now?'}]
# Step 1: the model decides whether to call a function
first = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = first.choices[0].message
if not message.tool_calls:
print(message.content)
raise SystemExit
# Step 2: run every requested call and send the results back
messages.append(message)
for call in message.tool_calls:
args = json.loads(call.function.arguments)
result = FUNCTIONS[call.function.name](**args)
messages.append({
'role': 'tool',
'tool_call_id': call.id,
'content': json.dumps(result),
})
final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
print(final.choices[0].message.content)От трёх деталей зависит, заработает ли цикл:
call.— это строка с JSON, а не словарь. Разберите её черезfunction. arguments json.loads.- Каждое сообщение
role: toolдолжно содержатьtool_call_idвызова, на который оно отвечает, то естьcall.id. contentсообщения-инструмента — строка. Для структурированных результатов используйтеjson.dumps.
Что вы увидите#
Если после первого запроса напечатать поля, они будут выглядеть так (id вызова при каждом запуске разный):
finish_reason: tool_calls
call.id: call_abc123
call.function.name: get_weather
call.function.arguments: {"city": "Paris"}Затем скрипт печатает итоговый ответ — обычное предложение вроде «Сейчас в Париже 14 °C». Формулировка от запуска к запуску меняется, а число берётся из вашей функции.
Несколько вызовов и длинные циклы#
Модель может вернуть больше одного вызова в одном ответе, например если спросить о погоде в двух городах. Поэтому в примере цикл идёт по message., и на каждый вызов отвечает сообщение с его собственным id. Руководство OpenAI по function calling описывает то же поведение: при tool_choice по умолчанию (auto) модель может вызвать ноль, одну или несколько функций (документация OpenAI, проверено 22 октября 2026 года; у страницы нет даты обновления, и она описывает новую форму Responses API, а в этой статье используется форма Chat Completions для адреса /).
Агенты повторяют два шага, пока модель не перестанет просить инструменты. Оберните запросы в цикл и всегда задавайте предел шагов:
for _ in range(5): # safety limit against endless loops
response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = response.choices[0].message
if not message.tool_calls:
print(message.content)
break
messages.append(message)
for call in message.tool_calls:
args = json.loads(call.function.arguments)
result = FUNCTIONS[call.function.name](**args)
messages.append({'role': 'tool', 'tool_call_id': call.id, 'content': json.dumps(result)})Если хотите выводить ответ по мере генерации, совместите это со стримингом в Python.
Почему MiniMax-M2.7 подходит для циклов с инструментами#
Цикл с инструментами отправляет много запросов с растущей историей. Для такого сценария в CheapTokens есть MiniMax-M2.7: контекст 180K, до 8 192 токенов в ответе, одна цена в любое время суток без пиковых часов и один баланс на все модели. В сумме, с учётом входа и выхода, модель дешевле референсной цены OpenRouter (сравнение цен CheapTokens, проверено 31 октября 2026 года).
Актуальные цены за 1M токенов: вход $0.05, выход $0.15. Для примера нагрузки (это не замер): двухзапросный цикл выше при примерно 2 700 входных и 350 выходных токенах в сумме стоит $0.00019. Полный список цен — на странице цен.
Чтобы попробовать другую модель, поменяйте только id; список id — на странице моделей.
Если не работает#
message.равенtool_ calls None. Модель ответила текстом. Сделайтеdescriptionфункции конкретнее и проверьте, что вопросу действительно нужна эта функция.json.наJSONDecodeError arguments. Модель выдала некорректный JSON. Обернитеjson.loadsвtry/exceptи верните текст ошибки как результат инструмента, чтобы модель повторила вызов с исправленными аргументами.- Второй запрос падает или модель игнорирует результат. Проверьте, что на каждый вызов приходится ровно одно сообщение
role: toolс совпадающимtool_call_idи что сообщение ассистента сtool_callsстоит в истории перед ними. KeyErrorвFUNCTIONS[...]. Модель назвала функцию, которую вы не зарегистрировали. Верните короткую строку с ошибкой как результат инструмента, а не роняйте программу.- Ответ обрывается. Посмотрите
finish_reason: значениеlengthозначает, что достигнут лимит токенов ответа. См. почему ответ ИИ обрывается на полуслове. - 401 или ошибки авторизации. Проверьте, что ключ лежит в
CHEAPTOKENS_, а базовый адрес заканчивается наAPI_ KEY /v1.
Что дальше#
Замените заглушку настоящей функцией: запросом к базе, поиском или калькулятором. Добавляйте записи в tools и в FUNCTIONS и делайте результат каждой функции коротким: он попадает в историю при каждом следующем запросе. Чтобы получить ключ и сделать первый вызов, откройте документацию CheapTokens.



