OpenAI API Python: последовательные запросы и контекст
Как организовать последовательные запросы к OpenAI API из Python: передача истории диалога, системный промпт, примеры кода, управление токенами. Лучшие практики для chat.completions.create и поддержания контекста.
Как правильно организовать несколько последовательных запросов к OpenAI API из Python? Нужно ли каждый раз вызывать client.chat.completions.create и включать системный промпт? Как передавать историю диалога для поддержания контекста между запросами?
OpenAI API из Python (openai api python) работает без сохранения состояния: каждый раз, когда вам нужен новый ответ, вы вызываете client.chat.completions.create и отправляете актуальную последовательность сообщений. Системный промпт (system) следует включать в messages при отправке запроса, а история диалога передаётся как список сообщений с ролями — вы либо отправляете весь накопленный список, либо сокращаете/суммируете его по токен-лимиту.
Содержание
- Как организовать последовательные запросы к OpenAI API из Python
- Формат messages и роль системного промпта
- Простой синхронный пример (openai api python)
- Асинхронный пример и потоковая передача
- Токены, усечение истории и суммаризация
- Лучшие практики и типичные ошибки
- Источники
- Заключение
Как организовать последовательные запросы к OpenAI API из Python
API чат‑моделей статeless: сервер не хранит ваш разговор между вызовами. Это значит: если вы хотите, чтобы модель «помнила» предшествующие реплики, ваше приложение должно передавать нужный контекст в поле messages при каждом вызове client.chat.completions.create. Вызывайте создание завершения (create) всякий раз, когда ожидаете новую реплику — это нормальная практика.
Зачем так? Потому что модель получает контекст только из переданных сообщений. Никакой «сессии» на стороне API, которая сама бы сохраняла историю, нет. Можно хранить системный промпт и историю локально (в памяти, базе данных, векторном хранилище) и передавать их на каждый запрос — либо весь набор сообщений, либо лишь релевантную его часть.
Подробнее о параметрах метода и формате запроса смотрите в официальной документации по Chat Completions: https://platform.openai.com/docs/api-reference/chat/create.
Формат messages и роль системного промпта
messages — это упорядоченный список объектов с полями role и content. Типичные роли:
- system — инструкции для ассистента (то, что задаёт поведение),
- user — пользовательский ввод,
- assistant — предыдущие ответы модели.
Пример структуры (в виде JSON / Python-словарей):
[
{"role": "system", "content": "You are a concise Russian-speaking assistant."},
{"role": "user", "content": "Привет! Как дела?"},
{"role": "assistant", "content": "Привет! Всё хорошо, спасибо."},
{"role": "user", "content": "Напиши краткий план статьи о Docker."}
]
Нужно ли включать системный промпт при каждом запросе? Да — с точки зрения API, инструкции действуют только в пределах одного вызова. Если вам важно постоянное поведение, добавляйте system как первый элемент messages при каждом create. Вы можете хранить системный текст в переменной и просто ставить его в начало списка перед отправкой.
(Если вы хотите сменить поведение динамически — обновляйте system. Но помните: слишком длинный системный текст увеличит потребление токенов.)
Больше практик по работе с чат‑форматом и рекомендациям по промптам — в руководстве по чатам: https://platform.openai.com/docs/guides/chat.
Простой синхронный пример (openai api python)
Ниже — минимальный шаблон, где история хранится в списке conversation и отправляется при каждом запросе. Код использует современную библиотеку openai-python (пример клиента): https://github.com/openai/openai-python.
from openai import OpenAI
client = OpenAI() # API ключ берётся из окружения OPENAI_API_KEY
system_msg = {"role": "system", "content": "Вы — полезный ассистент, отвечайте кратко и по-русски."}
conversation = [system_msg]
def user_turn(user_text):
# добавить ввод пользователя
conversation.append({"role": "user", "content": user_text})
# вызвать API — каждый раз передаём текущую последовательность сообщений
resp = client.chat.completions.create(
model="gpt-4o-mini", # замените на нужную модель
messages=conversation,
temperature=0.6
)
assistant_text = resp.choices[0].message.content
# сохранить ответ модели в истории
conversation.append({"role": "assistant", "content": assistant_text})
return assistant_text
# пример использования
print(user_turn("Как правильно организовать логирование в Flask?"))
Обратите внимание: здесь мы всегда отправляем system_msg в начале conversation. Это гарантирует предсказуемое поведение модели.
Асинхронный пример и потоковая передача
Если вы используете asyncio или хотите стриминг, библиотека обычно поддерживает await. Пример упрощённый:
import asyncio
from openai import OpenAI
client = OpenAI()
async def async_user_turn(conversation, user_text):
conversation.append({"role": "user", "content": user_text})
resp = await client.chat.completions.create(
model="gpt-4o-mini",
messages=conversation
)
assistant_text = resp.choices[0].message.content
conversation.append({"role": "assistant", "content": assistant_text})
return assistant_text
# запуск
# asyncio.run(async_user_turn(conversation, "Привет"))
Стриминг реализаций может отличаться в зависимости от версии клиента — см. разделы про стриминг в репозитории и документации библиотеки: https://github.com/openai/openai-python и официальную документацию.
Токены, усечение истории и суммаризация
Диалоги ограничены суммарным числом токенов (вход + ответ). Что делать, когда история становится слишком длинной?
- Обрезать старые реплики (FIFO) — простой подход: удаляйте самые старые user/assistant пары, оставляя system.
- Компрессировать историю: попросите модель кратко суммировать старые сообщения и храните вместо полного текста один сводный блок (например, роль assistant или system с меткой “summary”).
- RAG: вынесите факты/фрагменты в векторную БД (embeddings) и при новом запросе извлекайте только релевантные куски.
- Хранить ключевые факты (профиль пользователя, предпочтения) в отдельном short-term «system» или «user» сообщении и не дублировать весь разговор.
Как подсчитать токены? Для точного подсчёта используйте библиотеку tiktoken; она поможет понять, сколько токенов займут ваши сообщения для выбранной модели: https://github.com/openai/tiktoken. Простейшая стратегия усечения:
import tiktoken
def count_tokens(messages, model="gpt-4o-mini"):
enc = tiktoken.encoding_for_model(model)
total = 0
for m in messages:
total += len(enc.encode(m["content"]))
return total
MAX_TOKENS = 6000
# сокращение истории:
while count_tokens(conversation) > MAX_TOKENS:
# не удаляем system (index 0)
if len(conversation) > 2:
# удалить вторую по старшинству (первая после system)
conversation.pop(1)
else:
break
Суммаризация старых блоков — более экономный по токенам метод: попросите модель сжать 10 старых сообщений в 1-2 предложения с фактическими данными, затем замените их на одно «assistant/system: summary».
Лучшие практики и типичные ошибки
- Всегда храните system отдельно и добавляйте его в начало messages перед отправкой — иначе модель не получит инструкций.
- Не полагайтесь на «память» API: каждое create — независимый запрос.
- Логируйте исходящие и входящие сообщения (без чувствительных данных), чтобы воспроизводить ошибки.
- Следите за токен-лимитами и используйте усечение/суммаризацию/RAG.
- Разделяйте: системные инструкции (статичные), профиль пользователя (полустатичный) и текущую сессию (динамичный поток).
- Если модель «теряет персонаж» — попробуйте воссоздать поведение через явный системный промпт или краткое обновление контекста.
- Берегите PII: удаляйте чувствительную информацию перед логированием и хранением.
Частая ошибка — просто накапливать весь разговор без контроля токенов. Результат: запросы упрутся в лимит, или расходы станут непредсказуемыми.
Источники
- Chat Completions — API reference
- Guides: Chat — OpenAI Documentation
- openai-python — официальный репозиторий клиента
- tiktoken — токенизация
Заключение
Коротко: да — для каждого нового ответа вы вызываете client.chat.completions.create, и да — системный промпт должен быть включён в messages (или добавляться вашему приложением перед отправкой) чтобы поддерживать требуемое поведение. Историю диалога передавайте в виде списка сообщений (role/content), контролируйте длину через усечение, суммаризацию или RAG, и храните системные и профильные инструкции отдельно. Такой подход к OpenAI API из Python (openai api python) даёт предсказуемое поведение и позволяет масштабировать диалоги без потери контекста.