Пока что модель была для нас условной функцией llm(prompt). Пора заменить её настоящим вызовом. Любой агент, сколько бы шагов и инструментов в нём ни было, в основе делает одно и то же: отправляет запрос к модели и разбирает ответ. Если этот базовый кирпичик написан небрежно — ключ лежит в коде, инструкции перемешаны с вопросом, длина ответа не ограничена, — проблемы будут во всём, что вы построите сверху.
После урока вы сможете безопасно подключить API-ключ, отправить запрос через Responses API, задать модели роль и правила, управлять длиной и разнообразием ответа и узнать из ответа точное число потраченных токенов.
Что уже умеем
В прошлом уроке вы разобрались, что модель измеряет текст токенами, что входные и выходные токены оплачиваются по разным тарифам и как оценить стоимость запроса заранее. Сегодня эти знания станут практикой: API сам скажет, сколько токенов ушло на запрос, и вы посчитаете его точную цену.
Что вы узнаете в рамках статьи
- как установить пакет
openaiи безопасно передать API-ключ; - как отправить запрос методом
client.responses.createи получить текст ответа; - чем
instructionsотличаются отinput; - как параметры
max_output_tokensиtemperatureвлияют на ответ; - как прочитать из ответа число токенов и посчитать стоимость.
Ключевые термины
- API — способ, которым ваша программа обращается к внешнему сервису: отправляет запрос и получает ответ.
- API-ключ — секретная строка, по которой сервис узнаёт вас и выставляет счёт.
- Responses API — современный интерфейс OpenAI для запросов к моделям; в Python это метод
client.responses.create. - instructions — указания модели о роли, стиле и правилах ответа, отделённые от вопроса пользователя.
- input — то, на что модель должна ответить: вопрос, текст для обработки.
- usage — поле ответа с фактическим числом входных и выходных токенов.
Подключение: пакет и ключ
Работа с моделями OpenAI из Python идёт через официальный пакет openai. Установите его в виртуальное окружение проекта:
pip install openai
Ключ создаётся в личном кабинете платформы OpenAI. Главное правило: ключ никогда не пишется в коде. Код попадает в репозиторий, в чаты, на скриншоты, а с утёкшим ключом кто угодно будет делать запросы за ваш счёт. Ключ хранится в переменной окружения OPENAI_API_KEY:
export OPENAI_API_KEY="sk-..." # macOS и Linux
setx OPENAI_API_KEY "sk-..." # Windows, затем перезапустите терминал
Клиент сам находит ключ в окружении, передавать его в код не нужно:
from openai import OpenAI
client = OpenAI() # ключ берётся из переменной OPENAI_API_KEY
Если переменная не задана, при создании клиента появится ошибка о том, что ключ не найден. Это хороший знак: программа не стартует молча с неправильной настройкой.
Первый запрос
Запрос отправляется методом client.responses.create. Обязательны два аргумента: model — имя модели и input — текст, на который нужно ответить.
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-luna",
input="Объясни в двух предложениях, что такое токен.",
)
print(response.output_text)
Что увидим в консоли: два предложения о том, что токен — это фрагмент текста, с которым работает модель. Запустите программу ещё раз — формулировка, скорее всего, изменится. Модель генерирует текст, а не достаёт готовый ответ из базы, поэтому одинаковый запрос может давать разные, но близкие по смыслу ответы.
Объект response содержит гораздо больше, чем текст: идентификатор ответа, имя модели, статус, список элементов вывода. Свойство output_text — удобный способ сразу получить итоговый текст, не разбирая структуру вручную.
instructions: роль и правила отдельно от вопроса
Можно было бы писать всё в одну строку: «Ты преподаватель Python, отвечай кратко. Вопрос: ...». Но правильнее разделять. Параметр instructions задаёт роль, стиль и ограничения, а input — сам вопрос. Модель относится к инструкциям как к правилам поведения с более высоким приоритетом, а вам проще менять вопрос, не трогая правила.
response = client.responses.create(
model="gpt-6-luna",
instructions=(
"Ты преподаватель Python для начинающих. "
"Отвечай не длиннее трёх предложений и приводи один короткий пример кода."
),
input="Что такое list comprehension?",
)
print(response.output_text)
Что увидим: короткое объяснение и однострочный пример вроде [x * 2 for x in range(5)]. Замените input на другой вопрос — стиль ответа сохранится, потому что правила заданы отдельно. Именно так в агентах задаётся «характер»: один и тот же набор инструкций применяется ко всем запросам пользователя.
Пишите инструкции конкретно. «Отвечай хорошо» модели ничего не говорит, а «отвечай не длиннее трёх предложений, на русском, без вводных фраз» — ясные правила, которые легко проверить.
Параметры ответа и подсчёт токенов
Два параметра пригодятся сразу. max_output_tokens ограничивает длину ответа в токенах — это страховка от неожиданно длинного и дорогого вывода. temperature управляет разнообразием: значения около 0 делают ответы более предсказуемыми, значения ближе к 1 и выше — более разнообразными. Для извлечения данных и классификации берите низкую температуру, для генерации идей — повыше. Некоторые модели поддерживают не все параметры; если API вернёт ошибку о неподдерживаемом параметре, просто уберите его.
После запроса поле usage сообщает точное число токенов:
PRICE_IN = 0.10 # долларов за 1M входных токенов
PRICE_OUT = 0.50 # долларов за 1M выходных токенов
response = client.responses.create(
model="gpt-6-luna",
instructions="Ты маркетолог. Отвечай нумерованным списком.",
input="Придумай 5 названий для кофейни у университета.",
temperature=0.9,
max_output_tokens=200,
)
print(response.output_text)
usage = response.usage
cost = (usage.input_tokens * PRICE_IN + usage.output_tokens * PRICE_OUT) / 1_000_000
print(f"Вход: {usage.input_tokens}, выход: {usage.output_tokens}, стоимость: ${cost:.6f}")
Что увидим в консоли:
1. Зачётный кофе
2. Пара до пары
...
Вход: 41, выход: 63, стоимость: $0.000036
Числа у вас будут другими, но порядок тот же. Обратите внимание: входные токены — это инструкции плюс вопрос, именно их вы оценивали в прошлом уроке через tiktoken, а теперь видите точное значение.
Если ответ упёрся в max_output_tokens, он оборвётся на полуслове, а поле response.status будет равно "incomplete". Проверяйте статус, если обрезанный ответ для вас критичен, и не ставьте лимит слишком низким.
Частые ошибки
- Ключ прямо в коде. Строка
OpenAI(api_key="sk-...")рано или поздно окажется в репозитории. Храните ключ только в переменной окруженияOPENAI_API_KEY. - Правила внутри вопроса. Когда роль и вопрос смешаны в
input, их трудно менять по отдельности. Роль и правила — вinstructions, вопрос — вinput. - Печать объекта вместо текста.
print(response)выведет громоздкую структуру. Текст ответа лежит вresponse.output_text. - Слишком маленький
max_output_tokens. Ответ оборвётся на середине. Ставьте лимит с запасом и проверяйтеresponse.status.
Наиболее частые вопросы
- Почему на один и тот же вопрос приходят разные ответы? — Модель генерирует текст с долей случайности. Понизьте
temperature, чтобы ответы стали стабильнее, но полной одинаковости не ждите. - Чем Responses API отличается от chat.completions? — Chat Completions — более старый интерфейс. Responses API — актуальный основной: в нём удобнее работать с инструкциями, диалогами и инструментами, его мы и используем в курсе.
- Нужен ли платный аккаунт? — Для запросов к API нужен аккаунт на платформе OpenAI с пополненным балансом. Учебные запросы к недорогой модели стоят доли цента.
- Можно ли не указывать instructions? — Можно, модель ответит в стиле по умолчанию. Но в агентах инструкции почти всегда нужны, чтобы поведение было предсказуемым.
Итоги
Поздравляем, вы отправили первый настоящий запрос к языковой модели! Условная функция llm из первого урока превратилась в рабочий код: вы безопасно подключили ключ, разделили правила и вопрос, ограничили длину ответа и научились считать точную стоимость по полю usage. Это фундамент, на котором будет стоять каждый ваш агент.
Пока каждый запрос живёт сам по себе: модель не помнит, о чём вы спрашивали минуту назад. В следующем уроке вы научите программу вести диалог — передавать историю сообщений и использовать previous_response_id, чтобы модель отвечала с учётом контекста.