Программирование

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

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-словарей):

json
[
 {"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.

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. Пример упрощённый:

python
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 и официальную документацию.


Токены, усечение истории и суммаризация

Диалоги ограничены суммарным числом токенов (вход + ответ). Что делать, когда история становится слишком длинной?

  1. Обрезать старые реплики (FIFO) — простой подход: удаляйте самые старые user/assistant пары, оставляя system.
  2. Компрессировать историю: попросите модель кратко суммировать старые сообщения и храните вместо полного текста один сводный блок (например, роль assistant или system с меткой “summary”).
  3. RAG: вынесите факты/фрагменты в векторную БД (embeddings) и при новом запросе извлекайте только релевантные куски.
  4. Хранить ключевые факты (профиль пользователя, предпочтения) в отдельном short-term «system» или «user» сообщении и не дублировать весь разговор.

Как подсчитать токены? Для точного подсчёта используйте библиотеку tiktoken; она поможет понять, сколько токенов займут ваши сообщения для выбранной модели: https://github.com/openai/tiktoken. Простейшая стратегия усечения:

python
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: удаляйте чувствительную информацию перед логированием и хранением.

Частая ошибка — просто накапливать весь разговор без контроля токенов. Результат: запросы упрутся в лимит, или расходы станут непредсказуемыми.


Источники

  1. Chat Completions — API reference
  2. Guides: Chat — OpenAI Documentation
  3. openai-python — официальный репозиторий клиента
  4. tiktoken — токенизация

Заключение

Коротко: да — для каждого нового ответа вы вызываете client.chat.completions.create, и да — системный промпт должен быть включён в messages (или добавляться вашему приложением перед отправкой) чтобы поддерживать требуемое поведение. Историю диалога передавайте в виде списка сообщений (role/content), контролируйте длину через усечение, суммаризацию или RAG, и храните системные и профильные инструкции отдельно. Такой подход к OpenAI API из Python (openai api python) даёт предсказуемое поведение и позволяет масштабировать диалоги без потери контекста.

Авторы
Проверено модерацией
Модерация
OpenAI API Python: последовательные запросы и контекст