OpenAI · GPT-6 Astra

GPT-6 Astra Function Calling 2026: вызов API, баз данных и собственных инструментов

2026.09.11 · ~15 мин чтения

Function Calling несложен — сложности в неправильном tool loop, отсутствии изоляции прав и привязке к Chat Completions, блокирующей хостинговые инструменты. Ниже: схема инструмента HTTP API, полный tool loop, read-only паттерн БД, сравнение функциональных и хостинговых инструментов, матрица и 7 шагов.

Разработчик отлаживает tool loop GPT-6 Astra Function Calling на мониторе

Function Calling в GPT-6 Astra — это движок AI-агентов: модель решает, какой инструмент вызвать и с какими аргументами; ваш runtime исполняет побочный эффект; результат возвращается модели для продолжения рассуждений. Когда этот цикл реализован правильно, Astra может самостоятельно запрашивать API, читать базы данных и выполнять пользовательскую логику. Когда цикл ошибочен — он зависает, либо права инструментов выходят за допустимые рамки. Что такое Function Calling описано в сравнении протоколов; как получить API-ключ — в туториале по API. В этой статье разбираются три шаблона инструментов, переводящих агента из состояния «работает» в «безопасно деплоится».

Responses
Единственный путь для инструментов
function_call
Тип события в output
allowlist
Базовая безопасность DB-инструментов
Responses API обязателен
Вызовы инструментов, хостинговые инструменты (веб-поиск, code interpreter, Computer Use) и асинхронные tool loop требуют Responses API. Хостинговый инструмент в запросе Chat Completions вернёт HTTP 400. Весь код этой статьи использует Responses и предполагает работающий текстовый путь.

Шаг 1: Определить схему инструмента

Схема инструмента — JSON-объект, который сообщает модели имя инструмента, что он делает и какие параметры принимает. Пример: инструмент, вызывающий HTTP API погоды.

Схема инструмента (HTTP API инструмент)
import json
from openai import OpenAI

client = OpenAI()

tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "Get current weather for a city via HTTP API.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "City name, e.g. Tokyo, London, Shanghai",
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Temperature unit. Default celsius.",
                },
            },
            "required": ["city"],
            "additionalProperties": False,
        },
    }
]

description должен описывать, что инструмент делает — не просто повторять его имя. Модель читает это поле, чтобы решить, вызывать ли инструмент. Обязательные поля перечисляются в required; необязательные — в properties, но не в required. additionalProperties: false снижает вероятность передачи неожиданных ключей. Несколько инструментов кладут в один список; модель выбирает один или несколько. При параллельных вызовах цикл должен обработать все результаты перед продолжением.

Шаг 2: Полный tool loop

Паттерн: отправить запрос → проверить function_call в output → выполнить → добавить результаты к input → отправить снова, пока не останется новых function_call. Цикл должен быть while True — одиночный if не получит финальный текстовый ответ модели.

Полный tool loop (Responses API)
import json
import requests
from openai import OpenAI

client = OpenAI()

def call_weather_api(city: str, unit: str = "celsius") -> dict:
    """Replace with your real HTTP endpoint."""
    url = "https://api.example.com/weather"
    r = requests.get(url, params={"city": city, "unit": unit}, timeout=5)
    r.raise_for_status()
    return r.json()  # e.g. {"city": "Tokyo", "temp": 22, "condition": "sunny"}

# Initial request — model may call tools
response = client.responses.create(
    model="gpt-6-astra",
    input="What is the weather in Tokyo right now?",
    tools=tools,
    reasoning={"effort": "low"},
)

# Tool loop: keep going until model stops calling tools
while True:
    tool_calls = [o for o in response.output if o.type == "function_call"]
    if not tool_calls:
        break  # model is done — final answer is in response.output_text

    tool_results = []
    for call in tool_calls:
        args = json.loads(call.arguments)
        if call.name == "get_weather":
            result = call_weather_api(**args)
        else:
            result = {"error": f"Unknown tool: {call.name}"}
        tool_results.append({
            "type": "function_call_output",
            "call_id": call.call_id,
            "output": json.dumps(result, ensure_ascii=False),
        })

    # Append history + results and continue
    response = client.responses.create(
        model="gpt-6-astra",
        input=response.output + tool_results,
        tools=tools,
        reasoning={"effort": "low"},
    )

print(response.output_text)

Детали реализации. ① response.output — список смешанных типов; фильтруем только type == "function_call". ② При продолжении передавать response.output + tool_results как input; только tool_results теряет историю разговора. ③ call_id в результате должен совпадать с call_id вызова. ④ Сериализовать возвращаемые значения через json.dumps — не передавать сырой Python-dict.

Безопасность: allowlist инструментов и изоляция выполнения
Что инструмент может делать — решает runtime, а не модель. Проверять поле name по allowlist, проверять типы аргументов, добавлять timeout и allowlist доменов для HTTP-инструментов. DB-инструменты выполняют только предопределённые SQL-запросы — никогда не конкатенировать вывод модели в SQL. Инструменты, пишущие на диск или запускающие shell-команды, запускать на удалённом, одноразовом Mac.

Шаг 3: Read-only инструмент для базы данных

Три требования к безопасному DB-инструменту: соединение только на чтение (без INSERT, UPDATE, DELETE), параметризованные запросы (без SQL injection), SQL allowlist (без произвольного SQL).

Read-only DB-инструмент (allowlist + параметризация)
import sqlite3
from typing import Any

# Only these parameterized queries can be executed — no raw user SQL
ALLOWED_QUERIES: dict[str, str] = {
    "get_order":   "SELECT id, status, total, created_at FROM orders WHERE id = ?",
    "list_orders": "SELECT id, status, total FROM orders WHERE user_id = ? LIMIT 20",
}

def query_db(query_name: str, params: list[Any]) -> list[dict]:
    """Execute an allowlisted, parameterized read-only query.
    Never accepts raw SQL strings from the model.
    """
    sql = ALLOWED_QUERIES.get(query_name)
    if sql is None:
        raise ValueError(f"Query '{query_name}' not in allowlist")
    con = sqlite3.connect("orders.db", check_same_thread=False)
    con.row_factory = sqlite3.Row
    try:
        rows = con.execute(sql, params).fetchall()
        return [dict(r) for r in rows]
    finally:
        con.close()

# Schema exposed to the model
db_tool = {
    "type": "function",
    "name": "query_db",
    "description": "Query the orders DB. Only read-only allowlisted queries.",
    "parameters": {
        "type": "object",
        "properties": {
            "query_name": {
                "type": "string",
                "enum": list(ALLOWED_QUERIES.keys()),
                "description": "Name of the allowlisted query",
            },
            "params": {
                "type": "array",
                "items": {"type": ["string", "number"]},
                "description": "Positional parameters for the query",
            },
        },
        "required": ["query_name", "params"],
    },
}

В продакшне добавить: пул соединений, таймаут запроса, жёсткий лимит строк в каждом SQL, маскировку чувствительных полей. Результат, возвращаемый модели, должен быть резюме, а не сырым дампом таблицы — каждая строка потребляет токены ввода в следующем запросе.

Функциональные vs хостинговые инструменты

ИзмерениеФункциональные инструменты (type: function)Хостинговые инструменты (OpenAI)
Место выполненияВаш runtime (локально / удалённый Mac)Инфраструктура OpenAI
Лучше дляПриватные API, внутренние БД, кастомная логикаВеб-поиск, code interpreter, shell, Computer Use
Усилия на разработкуСхема + функция выполнения + циклУказать имя инструмента, OpenAI выполнит
ОплатаТолько токеныТокены + поштучная плата за инструмент
Требования к изоляцииПишущие инструменты требуют изолированной средыOpenAI управляет sandbox; данные — ваша ответственность

Оба типа можно смешивать в одном запросе. Результаты хостинговых инструментов автоматически попадают в историю разговора — ручная подача не нужна. Результаты функциональных инструментов нужно подавать вручную через function_call_output.

Матрица решений

Если нужноИспользоватьПочему
Вызвать внутренний REST APIФункциональный инструментПриватная сеть недоступна из инфры OpenAI
Запросить внутреннюю БД (только чтение)Функциональный инструмент + SQL allowlistПриватные данные; права доступа управляются самостоятельно
Поиск в публичном вебе в реальном времениХостинговый web_search_previewОбход и ранжирование — задача OpenAI
Модель запускает PythonХостинговый code_interpreterВыполнение в sandbox OpenAI, без локальных ресурсов
Модель управляет десктопом/браузеромХостинговый computer_use + изолированный MacНужен видимый рабочий стол; изоляция от случайных изменений
Shell-команды с записью на дискФункциональный инструмент + удалённый MacПрава на запись только на одноразовом хосте

A — Одиночный разработчик/прототип: локальная машина, функциональные инструменты для HTTP API (без записи на диск). Написать схему, стабилизировать цикл, логировать call_id. Переходить на несколько инструментов только после стабильной работы одного.

B — Небольшая команда: функциональные инструменты за внутренними сервисами с token-авторизацией. DB-инструмент: только чтение, пул соединений, таймаут. Хостинговые инструменты активировать по типу задачи. Логику выполнения покрывать unit-тестами.

C — Enterprise: все вызовы инструментов через API-шлюз с аудит-логом. БД — read-only реплика + row-level security. Computer Use — на одноразовых изолированных Mac-нодах. Учётные данные и условия доставки — в центре поддержки; стоимость нодов — на странице цен.

Распространённые ошибки

  1. Цикл выполняется один раз (if вместо while): финальный ответ модели никогда не приходит.
  2. Результаты подаются без истории: передача только tool_results в input лишает модель контекста.
  3. Вывод модели напрямую конкатенируется в SQL/shell: allowlist + параметризованные запросы устраняют класс атак.
  4. Нет таймаута у HTTP-инструментов: зависший downstream-сервис замораживает всю сессию агента.
  5. Инструменты возвращают большие дампы: строки потребляют токены и могут запустить апселл 272K.

План действий: 7 шагов

  1. Сначала убедиться, что текстовый путь Responses работает (см. туториал по API).
  2. Написать первую схему инструмента. description — глагольная фраза, required заполнен, additionalProperties: false.
  3. Реализовать функцию выполнения. Для HTTP — timeout. Для DB — allowlist + параметризованные запросы.
  4. Отправить Responses-запрос с параметром tools; распечатать response.output и убедиться в наличии function_call.
  5. Реализовать цикл while True. Сопоставить call_id, подать function_call_output, включить историю в input.
  6. При необходимости добавить хостинговые инструменты (web_search, code_interpreter). Их результаты не нужно подавать вручную.
  7. Инструменты с записью на диск, shell-командами или управлением браузером перевести на изолированный удалённый Mac; уничтожить workspace по окончании сессии.

FAQ

Обязателен ли Responses API для Function Calling?

Да. Вызовы инструментов, хостинговые инструменты и async tool loop требуют Responses API.

Сколько инструментов можно определить на запрос?

Нет строгого малого лимита, но больше инструментов = больше токенов промпта. Передавать только нужные для текущей задачи.

Как предотвратить SQL-инъекцию?

Параметризованные запросы с ? в сочетании с SQL allowlist. Никогда не конкатенировать вывод модели в SQL.

Когда функциональный, а когда хостинговый инструмент?

Приватный API, внутренняя БД, кастомная логика → функциональный. Веб-поиск, code interpreter, Computer Use → хостинговый.

Можно ли стримить финальный ответ после tool calls?

Да. Сначала стабилизировать нестримящий цикл, затем добавить stream=True.

Заключение

Три основы Function Calling в GPT-6 Astra: схема с ясным description, цикл while, подающий полную историю с каждым результатом, и DB-инструмент на allowlist с параметризованными запросами — пишущие инструменты на изолированном Mac. Удалённые Mac-ноды на страницах аренды и цен; вопросы по аккаунту — в центре поддержки.

Читать дальше

Инструменты вызывают реальные API? Запускайте на изолированном Cloud Mac

Вызывать публичный HTTP-эндпоинт локально — нормально. Инструмент, пишущий на диск, редактирующий репозиторий или управляющий браузером, не должен делить повседневный рабочий стол. Удалённые Mac-ноды изолируют рабочее пространство на сессию.

Заказать · Смотреть цены

GPT-6 Astra Function Calling

Инструменты вызывают реальные API? Запускайте на изолированном Cloud Mac

Cloud Mac · isolated agent runtime

Заказать
Mac Заказать