Многоходовой разговор
Диалог из нескольких реплик и что делать, когда история становится слишком длинной.
Многоходовой разговор — диалог, где каждый новый запрос несёт всю предыдущую переписку, чтобы модель сохраняла контекст.
Почему память — это ваша забота
Раз API без состояния (раздел 1), «память» диалога целиком на вашей стороне: это просто список сообщений, который вы ведёте и отправляете заново при каждом запросе. Модель ничего не запоминает между вызовами — иллюзия непрерывного разговора возникает только потому, что вы каждый раз передаёте всю предысторию. Если приложение перезапустилось и список потерян — для модели диалога как не бывало.
Цикл диалога в коде
Менеджер диалога обычно хранит список сообщений и при каждой реплике пользователя: добавляет её, отправляет весь список, получает ответ, дописывает ответ в список.
import anthropic
client = anthropic.Anthropic()
history = []
def send(user_text):
history.append({"role": "user", "content": user_text})
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system="Ты дружелюбный ассистент.",
messages=history,
)
answer = "".join(b.text for b in resp.content if b.type == "text")
history.append({"role": "assistant", "content": answer})
return answer
print(send("Меня зовут Алиса."))
print(send("Как меня зовут?")) # модель помнит благодаря history
Проблема: контекст растёт и стоит денег
Каждое сообщение в истории — это токены, за которые вы платите при каждом запросе. Длинный диалог быстро раздувает входные токены и может упереться в контекстное окно модели. Решения два: обрезка (сохранять только последние N сообщений) и суммаризация (сжать старое в краткое содержание).
Окно истории — обрезка (запускаемо)
Простейшая стратегия: держать только последние N сообщений. Системную инструкцию хранят отдельно и не обрезают.
def trim_history(messages, max_messages=4):
# Системную инструкцию храним отдельно (не в messages).
# Оставляем только последние max_messages сообщений.
if len(messages) <= max_messages:
return messages
return messages[-max_messages:]
history = [
{"role": "user", "content": "сообщение 1"},
{"role": "assistant", "content": "ответ 1"},
{"role": "user", "content": "сообщение 2"},
{"role": "assistant", "content": "ответ 2"},
{"role": "user", "content": "сообщение 3"},
]
trimmed = trim_history(history, max_messages=3)
for m in trimmed:
print(m["role"], "->", m["content"])
print("Было:", len(history), "Стало:", len(trimmed))
Вывод:
user -> сообщение 2 assistant -> ответ 2 user -> сообщение 3 Было: 5 Стало: 3
Грубая обрезка по числу сообщений может разрезать пару user/assistant — в проде обрезают аккуратнее (по токенам, парами) или суммаризируют. Для длинных диалогов провайдеры предлагают и серверные механизмы сжатия контекста.
Итог
- Многоходовой диалог = передача всей истории в каждом запросе.
- История растёт и стоит токенов; контролируйте её размер.
- Стратегии: обрезка по последним N (или по токенам) и суммаризация старого.