Глава 01 · Фундамент

LLM с точки зрения API

LLM — это функция: список сообщений на входе, новое сообщение на выходе. Никакого «состояния», никакой памяти между вызовами. Если хотите, чтобы модель помнила вчерашний разговор — складывайте всю историю в массив messages сами.

Реальный запрос · POST /v1/messages
POST https://api.anthropic.com/v1/messages
content-type: application/json
x-api-key: sk-ant-...
anthropic-version: 2023-06-01

{
  "model": "claude-sonnet-4-5",
  "max_tokens": 1024,
  "messages": [
    {"role": "user", "content": "Привет, кто ты?"}
  ]
}
HTTP/1.1 200 OK
content-type: application/json

{
  "id": "msg_01ABC...",
  "type": "message",
  "role": "assistant",
  "content": [
    {"type": "text", "text": "Я Claude, ассистент от Anthropic..."}
  ],
  "model": "claude-sonnet-4-5",
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 12,
    "output_tokens": 24
  }
}

Запрос и ответ

Messages API устроен обманчиво просто. В минимальном запросе три обязательных поля: model (какая модель отвечает), max_tokens (потолок длины ответа) и messages (история разговора). Никаких сессий, никаких идентификаторов диалога, никаких «продолжить с прошлого раза». Только эти три поля — и ключ авторизации в заголовке.

Каждый элемент массива messages — это объект с двумя полями: role и content. Роль может быть только "user" или "assistant"; модели обучены работать на чередовании этих двух ролей, и если в запросе подряд идут два сообщения одной роли, API склеит их в одно. Системный промпт сюда не входит: для него есть отдельный top-level параметр system, а роли "system" в Messages API просто не существует.

Ответ симметричен: тот же формат, что и входящие сообщения, плюс служебные поля. В content — массив блоков с текстом (или другими типами, об этом ниже). В usage — точный счёт: сколько токенов было на входе, сколько модель сгенерировала на выходе. Это и есть единица биллинга. Никакой «стоимости диалога» — каждый вызов оплачивается отдельно, по своему usage.

Никакого состояния

Messages API — stateless. Сервер не помнит, что вы у него спрашивали минуту назад. Если вы хотите, чтобы модель учитывала прошлые реплики, вы должны положить их все в массив messages сами — в том порядке, в котором они звучали. В документации это прямо подчёркнуто: API годится «для одиночных запросов или для stateless multi-turn разговоров». Многоходовый разговор здесь — это не сессия, это просто массив подлиннее.

У этого решения есть очевидная цена. Каждый следующий вызов перепрогоняет весь контекст с нуля: модель видит первый «привет» пользователя, ответ ассистента, второе сообщение, ответ, третье — и за всё это вы платите input-токенами на каждом вызове. На длинных диалогах счёт растёт квадратично: чем дольше разговор, тем дороже каждая следующая реплика. Это та боль, ради которой существуют главы 4 (контекст и компакция) и 11 (prompt caching) — но в базовом случае никакой магии нет: что положили в массив, за то и заплатили. Сам API ограничивает запрос потолком в 100 000 сообщений — это уже область, где без сжатия истории не обойтись.

stop_reason: почему модель остановилась

Поле stop_reason в ответе — это маленькое, но важное окно в то, что произошло. Модель не просто «выдала текст»: у каждого ответа есть причина, по которой генерация прекратилась. И эти причины задают разную логику обработки на стороне клиента.

Для базового чата хватает end_turn. Для агента — нет. Когда мы доберёмся до цикла, tool_use станет тем самым сигналом «я ещё не закончил, дай мне выполнить инструмент и верни результат».

Content blocks: почему content — это массив

Можно положить в content просто строку — это синтаксический сахар для массива из одного text-блока. Но в общем случае content — это массив типизированных блоков, и это важно. В одном ответе модель может выдать сразу несколько кусков разной природы.

Полный список типов из документации: text, image, document, tool_use, tool_result, thinking, search_result, server_tool_use. Для этой главы важен только text: обычный текст, который модель сгенерировала. Остальные — это якоря последующих глав: tool_use и tool_result разберём в главе 3, thinking — там же, где будем говорить про extended thinking, image и document относятся к мультимодальному входу. Здесь достаточно запомнить: content — это не строка, это структура. Парсер на клиенте должен уметь ходить по типам.

Где здесь агент?

Нигде. Один такой вызов — это чат, а не агент. Вы отправили список сообщений, модель сгенерировала следующее, разговор кончился. Если пользователь напишет ещё раз, вы снова соберёте весь массив руками, отправите его снова, получите ещё один ответ.

Чтобы получился агент, нужна одна вещь, которой здесь нет: цикл. Маленький while, который смотрит на stop_reason, и если там tool_use — выполняет инструмент, дописывает результат в messages и зовёт API ещё раз. И ещё раз. И ещё. Пока модель сама не скажет end_turn. Этому циклу посвящена следующая глава — и, если читать одну главу из всего курса, читать стоит именно её.

Send a structured list of input messages with text and/or image content, and the model will generate the next message in the conversation. The Messages API can be used for either single queries or stateless multi-turn conversations.

— Anthropic Documentation, Messages API

Источники главы