# Claude Structured Outputs: надёжный JSON по схеме и ошибки 400

> Схему кладут в output_config.format, JSON приходит в текстовом блоке. minimum и рекурсия дают 400, а minLength шлюз принял, но не соблюдал.

- URL: https://blog.laozhang.ai/ru/posts/claude-structured-output
- Published: 2026-10-30
- Updated: 2026-10-30
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ru/about)
- Topic: Руководства по API
- Tags: Claude API, Structured Outputs, JSON Schema, Strict tool use, Pydantic

---
У Claude есть structured outputs, и по состоянию на 30 октября 2026 года это общедоступная функция Claude API, beta-заголовок для неё больше не нужен. Чтобы получить JSON, который код разберёт без правок, передайте JSON Schema в поле запроса `output_config.format` с `"type": "json_schema"`. Готовый JSON придёт в текстовом блоке ответа: обычно это `content[0].text`, а если включён thinking, то первый блок с `"type": "text"`. Если по схеме должны приходить аргументы вызова инструмента, а не сам ответ, ставьте `strict: true` в описании инструмента; обе функции можно включить в одном запросе.

Гарантия касается синтаксиса, обязательных полей и типов, но не всего остального. Перед разбором проверяйте `stop_reason`: при `refusal` и `max_tokens` JSON может не совпасть со схемой или оборваться на середине. Ограничения вроде `minimum` и `minLength` декодер не соблюдает, поэтому проверять их придётся в своём коде, а SDK делает это за вас только в хелперах `messages.parse()`. Старый верхнеуровневый параметр `output_format` из гайдов бета-периода устарел: по документации Anthropic без beta-заголовка он даёт 400.

Через прокси та же ошибка бывает тихой. 30 октября 2026 года запрос со старым `output_format` через LaoZhang API (Anthropic-совместимый `/v1/messages`) вернул 200 и обычный текст вместо JSON, а число входных токенов осталось таким же, как без схемы. Поэтому на любом шлюзе сначала убедитесь, что пришёл именно JSON и что `usage.input_tokens` вырос по сравнению с запросом без схемы. Прямой api.anthropic.com в этих тестах не участвовал, и результаты «через шлюз» ниже относятся только к этому маршруту.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

## Запрос с output_config.format: cURL и где лежит JSON

Минимальный рабочий запрос — обычный вызов Messages API с одним дополнительным полем `output_config.format`. Внутри лежит JSON Schema, и у каждого объекта в ней должно стоять `"additionalProperties": false`. Пример ниже взят из документации Anthropic: письмо клиента превращается в четыре поля.

```bash
curl https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 1024,
    "messages": [{
      "role": "user",
      "content": "Extract the key information from this email: John Smith (john@example.com) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
    }],
    "output_config": {
      "format": {
        "type": "json_schema",
        "schema": {
          "type": "object",
          "properties": {
            "name": {"type": "string"},
            "email": {"type": "string"},
            "plan_interest": {"type": "string"},
            "demo_requested": {"type": "boolean"}
          },
          "required": ["name", "email", "plan_interest", "demo_requested"],
          "additionalProperties": false
        }
      }
    }
  }'
```

Ответ — обычное сообщение, но в `content[0].text` лежит строка с JSON, которую можно сразу передать в `json.loads()` или `JSON.parse()`. 30 октября 2026 года тот же запрос с моделью `claude-haiku-5-5` через LaoZhang API (адрес `https://api.laozhang.ai/v1/messages`, остальное без изменений) вернул за 3,61 с `stop_reason: "end_turn"` и текст `{"demo_requested": true, "email": "john@example.com", "name": "John Smith", "plan_interest": "Enterprise"}`. Входных токенов было 333. Тот же промпт без схемы дал markdown-список вместо JSON и 64 входных токена: разница в 269 токенов — это схема и служебный промпт, который Claude получает вместе с ней.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

Функция работает на моделях от поколения 4.5 и новее: Opus 4.5–5.5, Sonnet 4.5–5.5, Haiku 4.5 и 5.5, Fable 5 и 5.1, Mythos. Claude 3.x и Opus 4.1 в списке поддерживаемых моделей в [документации Anthropic по structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) нет.

## Python и Pydantic: messages.parse() и parsed_output

В Python удобнее всего описать ответ моделью Pydantic и вызвать `client.messages.parse()`. Хелпер сам превращает модель в схему, отправляет её в `output_config.format`, проверяет ответ и возвращает готовый объект в `response.parsed_output`. Аргумент здесь называется `output_format`, но это имя параметра хелпера, а не устаревшее поле запроса: в API SDK отправит именно `output_config.format`.

```python
from typing import Literal, Optional
from anthropic import Anthropic
from pydantic import BaseModel, Field

class Lead(BaseModel):
    name: str = Field(min_length=2)
    email: str
    plan: Literal["Starter", "Team", "Enterprise"]
    seats: int = Field(ge=1, le=500)
    phone: Optional[str] = None

client = Anthropic()  # для шлюза: Anthropic(base_url="https://api.laozhang.ai", api_key="...")

response = client.messages.parse(
    model="claude-haiku-5-5",
    max_tokens=512,
    messages=[{"role": "user", "content": "John Smith (john@example.com) wants the Enterprise plan for 40 seats."}],
    output_format=Lead,
)
print(response.parsed_output)
```

В модели есть `min_length`, `ge` и `le`, которых API не принимает, и SDK обходит это преобразованием схемы. Его результат можно посмотреть без запроса через `transform_schema(Lead)`. В anthropic 2.3.0 с pydantic 2.14 поле `name` ушло в API как обычная строка с описанием `{minLength: 2}`, `seats` — как integer с описанием `{maximum: 500, minimum: 1}`, необязательный `phone` превратился в `anyOf` из строки и `null`, а ко всему объекту добавилось `additionalProperties: false`. Модель видит ограничения только как подсказку в описании, а соблюдение проверяет уже Pydantic после ответа.

Это видно на проверке 30 октября 2026 года через LaoZhang API. Обычный запрос вернул `parsed_output` с `seats=40` и `phone=None` при 489 входных токенах. Во втором запросе в тексте честно было указано «0 seats»: API вернул `"seats": 0`, и SDK выбросил `pydantic.ValidationError` с сообщением `Input should be greater than or equal to 1`. Значит, `messages.parse()` нужно оборачивать в обработку `ValidationError`: схема не мешает модели передать значение, нарушающее ваше правило.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

В TypeScript то же самое делают через Zod: схема оборачивается в `zodOutputFormat()` и передаётся в `output_config.format` вызова `client.messages.parse()`, результат приходит в `parsed_output`.

```typescript
import Anthropic from "@anthropic-ai/sdk";
import { z } from "zod";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

const Contact = z.object({ name: z.string(), email: z.string(), plan_interest: z.string(), demo_requested: z.boolean() });

const response = await new Anthropic().messages.parse({
  model: "claude-opus-5-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Extract the key information from this email: ..." }],
  output_config: { format: zodOutputFormat(Contact) },
});
console.log(response.parsed_output);
```

Если вместо Zod используете `jsonSchemaOutputFormat()`, учтите, что он только преобразует схему, а ответ не проверяет. Java SDK поступает наоборот: неподдерживаемые ограничения он не переносит в описание, а отклоняет схему ещё на вашей стороне, до отправки запроса.

## JSON outputs или strict: true в инструменте: что выбрать

Выбор зависит от того, что должно соответствовать схеме. Если нужен сам ответ модели в виде данных (извлечение полей, классификация, итоговый отчёт агента), это JSON outputs через `output_config.format`. Если модель вызывает вашу функцию и её аргументы должны точно совпасть с типами, это `strict: true` в определении инструмента. В агенте, который и вызывает инструменты, и отдаёт итог в виде JSON, включайте оба: так строит пример и документация Anthropic.

| | JSON outputs | Strict tool use |
| --- | --- | --- |
| Где задаётся | `output_config.format` в запросе | `"strict": true` рядом с `name` и `input_schema` инструмента |
| Что ограничивает | Текст ответа Claude | Имя инструмента и его `input` |
| Где результат | Текстовый блок, `stop_reason: "end_turn"` | Блок `tool_use`, `stop_reason: "tool_use"` |
| Типичная задача | Извлечь данные, классифицировать, вернуть отчёт | Вызвать функцию с правильными типами (`2`, а не `"two"`) |
| Ограничения схемы | Общие: тот же поднабор JSON Schema | Те же, плюс не больше 20 strict-инструментов в запросе |

Без strict-режима модель может передать в целочисленный параметр строку `"2"` или `"two"` или пропустить обязательное поле; со `strict: true` аргументы проходят через ту же грамматику, что и JSON outputs. 30 октября 2026 года через LaoZhang API инструмент `create_demo_booking` с перечислениями для тарифа и дня недели, целым `hour_24` и форматом `email` при принудительном `tool_choice` вернул `stop_reason: "tool_use"` и `input` `{"email": "john@example.com", "hour_24": 14, "plan": "Enterprise", "weekday": "Tue"}`. Фраза «next Tuesday at 2pm» превратилась в `"Tue"` и `14`, то есть в значения из схемы, а не в свободный текст.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

```json
{
  "name": "create_demo_booking",
  "description": "Book a product demo for a lead.",
  "strict": true,
  "input_schema": {
    "type": "object",
    "properties": {
      "email": {"type": "string", "format": "email"},
      "plan": {"type": "string", "enum": ["Starter", "Team", "Enterprise"]},
      "weekday": {"type": "string", "enum": ["Mon", "Tue", "Wed", "Thu", "Fri"]},
      "hour_24": {"type": "integer"}
    },
    "required": ["email", "plan", "weekday", "hour_24"],
    "additionalProperties": false
  }
}
```

Помечать строгими все инструменты подряд не стоит. Лимиты сложности считаются по всем strict-схемам запроса вместе, поэтому `strict: true` разумно оставлять там, где неверный тип действительно ломает ваш код. Подробности — в [документации Anthropic по strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use).

## Какие ключевые слова JSON Schema дают 400, а какие не соблюдаются

Structured outputs понимают только часть JSON Schema, и за её пределами возможны три исхода: ошибка 400, молчаливое принятие без соблюдения и нормальная работа. Документация Anthropic обещает 400 для любого неподдерживаемого ключевого слова, но через шлюз 30 октября 2026 года это подтвердилось не для всех. Ниже — что сказано в документации и что вернул LaoZhang API на `claude-haiku-5-5`; тексты ошибок приведены без перевода, как их вернул шлюз.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

| Ключевое слово | По документации Anthropic | Через LaoZhang API, 30.10.2026 | Что делать |
| --- | --- | --- | --- |
| `minimum`, `maximum`, `multipleOf` | Не поддерживаются, 400 | `minimum: 1` → 400: `output_config.format.schema: For 'integer' type, property 'minimum' is not supported` | Убрать из схемы (SDK делает это сам), проверять диапазон в коде |
| `minLength`, `maxLength` | Не поддерживаются, 400 | Приняты (200); при `minLength: 12` и `maxLength: 12` на просьбу вернуть код ABC пришло `{"code": "ABC"}` | Проверять длину в коде: ограничение не работает, хотя ошибки нет |
| Рекурсивный `$ref` | Не поддерживается | 400: `Invalid schema: Circular reference detected in schema definitions: node -> node. Self-referencing or mutually-referencing definitions are not supported.` | Развернуть дерево до фиксированной глубины |
| `additionalProperties` | Обязательно `false` у каждого объекта | Без него 200, ответ совпал со схемой | Всё равно ставить `false` явно: на другом маршруте может быть 400 |
| `enum` | Только строки, числа, булевы и `null`; регистр не гарантирован | 5 запросов из 5 вернули `"Conversation topic 3"` точно как в схеме | Сравнивать значения без учёта регистра |
| `pattern` | Простые regex; без lookahead/lookbehind, `\b`, обратных ссылок и больших `{n,m}` | — | Сложные проверки переносить в код |
| `minItems` | Только 0 или 1 | — | Проверять число элементов в коде |

Остальное поддерживается: все базовые типы, `const`, `anyOf`, `allOf` (кроме `allOf` с `$ref`), локальные `$ref` и `$defs`, `default`, а из форматов строк — `date-time`, `time`, `date`, `duration`, `email`, `hostname`, `uri`, `ipv4`, `ipv6` и `uuid`. Вложенные объекты тоже допустимы, так что «только плоские схемы» — это не ограничение API; запрещена рекурсия, а не вложенность.

Отдельно действуют лимиты сложности на весь запрос: не больше 20 strict-инструментов, 24 необязательных параметров и 16 параметров с объединением типов (`anyOf` или `"type": ["string", "null"]`), считая все строгие схемы вместе. Даже если они соблюдены, слишком большая грамматика даёт 400 `Schema is too complex for compilation`, а компиляция прерывается через 180 секунд. Anthropic советует по порядку: оставить `strict` только для важных инструментов, сделать параметры обязательными, упростить вложенность и разбить запрос на несколько.

## Вместо JSON пришёл обычный текст: схема не дошла до модели

Если ответ пришёл обычным текстом, почти всегда схема не дошла до модели, и то, как это проявится, зависит от маршрута. Прямой API Anthropic по документации отвечает 400 на устаревший `output_format` без заголовка `anthropic-beta: structured-outputs-2025-11-13`. Через LaoZhang API 30 октября 2026 года тот же запрос и без заголовка, и с ним вернул 200 и markdown-список, причём входных токенов было 64, ровно как у запроса без схемы. Шлюз отбросил неизвестное поле, ничего не сообщив.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

![Три запроса через LaoZhang API: со схемой в output_config.format пришёл JSON и 333 входных токена, без схемы и со старым output_format — markdown-список и 64 токена](https://blog.laozhang.ai/posts/ru/claude-structured-output/img/schema-reached-model-check.webp)

Обратная ситуация — громкая ошибка там, где запрос правильный. Каналы, которые проверяют тело запроса по правилам Bedrock, отвечают 400 `ValidationException` с текстом `Extra inputs are not permitted` на поля, которых они не принимают; встречается, например, `output_config effort extra inputs are not permitted`. Об этом прямо пишет [справка LaoZhang API об ошибке 400 ValidationException](https://docs.laozhang.ai/faq/claude-code-aws-400-validation-error), а разбор других текстов 400 есть в статье [«Claude в AWS Bedrock отвечает 400: причина по тексту ошибки»](https://blog.laozhang.ai/ru/posts/aws-claude-400-error).

Когда что-то из этого случилось, пройдите по порядку:

- Убедитесь, что схема лежит в `output_config.format`, а не в верхнеуровневом `output_format` из старых примеров и не в `response_format`: это имя поля из API OpenAI, в Messages API Anthropic его нет.
- Сравните `usage.input_tokens` с тем же запросом без схемы. Если число не изменилось, схема до модели не дошла, даже если статус 200.
- Посмотрите, начинается ли `content[0].text` с `{` и проходит ли `json.loads()`. Markdown или текст с пояснениями означает, что формат не применился.
- Если запрос идёт через обёртку (LiteLLM, фреймворк агентов, собственный прокси), проверьте в логах исходящий запрос: передаёт ли она `output_config` дальше без изменений.
- При 400 `Extra inputs are not permitted` уберите из запроса поля, которые канал не принимает, или переключитесь на маршрут, который передаёт `output_config` полностью.

## Где «всегда валидный JSON» не гарантирован: отказ, max_tokens, ваша проверка

Грамматика гарантирует форму ответа, только если генерация закончилась нормально, то есть с `stop_reason: "end_turn"` для JSON outputs или `"tool_use"` для strict-инструментов. Во всех остальных случаях JSON может не совпасть со схемой, а ограничения, которые API не поддерживает, вы проверяете сами. Код, который сразу делает `json.loads()` и кладёт результат в базу, рано или поздно на этом сломается.

- Проверяйте `stop_reason` до разбора. При `refusal` Claude отказался отвечать по соображениям безопасности: статус 200, токены списаны, а текст отказа важнее схемы. Не делайте поле вида «пошаговое рассуждение» — оно может вызвать отказ `reasoning_extraction`; просите короткое объяснение.
- Ловите `max_tokens`. 30 октября 2026 года через LaoZhang API запрос 15 идей при `max_tokens: 30` вернул 200 и текст `{"ideas": ["REST vs GraphQL vs gRPC: How to Choose the`, который не разбирается. Повторяйте с бо́льшим лимитом, а не пытайтесь «дочинить» строку.
- Валидируйте значения после ответа: длины, диапазоны, регулярные выражения, число элементов массива. Пример с `"seats": 0` в разделе про Python показывает, что модель вернёт значение, нарушающее ваше правило, если так написано во входных данных.
- Не полагайтесь на порядок ключей. Документация обещает порядок схемы с обязательными полями впереди, но во всех ответах через LaoZhang API 30 октября 2026 года ключи шли по алфавиту. Обращайтесь к полям по имени.
- Считайте необязательное поле «отсутствующим или `null`». В том же тесте поле `phone` с типом `string` не было ни обязательным, ни nullable, но пришло как `"phone": null` вместо того, чтобы пропасть из ответа.
- Сравнивайте `enum` без учёта регистра и не заводите значения, которые отличаются только регистром. Anthropic предупреждает, что вместо `"Conversation topic 3"` может прийти `"Conversation Topic 3"` без всякой ошибки.

*Примечание: [laozhang.ai — наш собственный сервис](https://blog.laozhang.ai/ru/about#laozhang); его цены — наши тарифы, а не независимое сравнение.*

Ещё две несовместимости дают 400 сразу. Citations вместе с `output_config.format` API не принимает. Предзаполнение ответа `{` в последнем сообщении `assistant` тоже не работает: на `claude-haiku-5-5` через шлюз пришло `This model does not support assistant message prefill. The conversation must end with a user message.` Как заменить prefill на новых моделях, разобрано в статье [«Ошибка 400 prefill в Claude: на каких моделях и чем заменить»](https://blog.laozhang.ai/ru/posts/claude-opus-prefill-error-fix).

![Три проверки ответа перед кодом: stop_reason, начало текста с фигурной скобки и валидация Pydantic, на которой "seats": 0 даёт ValidationError](https://blog.laozhang.ai/posts/ru/claude-structured-output/img/response-checks-before-code.webp)

Все проверки помещаются в одну функцию-страховку. Она работает с сырым `messages.create()`, поэтому годится и там, где `messages.parse()` недоступен:

```python
from anthropic import Anthropic, transform_schema
from pydantic import ValidationError

client = Anthropic()
SCHEMA = transform_schema(Lead)  # модель Lead из раздела про Python

class NotJSON(Exception):
    pass

def extract_lead(text: str) -> Lead | None:
    resp = client.messages.create(
        model="claude-haiku-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": text}],
        output_config={"format": {"type": "json_schema", "schema": SCHEMA}},
    )
    if resp.stop_reason == "refusal":
        return None  # отказ: записать в лог, не разбирать
    if resp.stop_reason == "max_tokens":
        raise NotJSON("ответ обрезан: увеличьте max_tokens и повторите")
    raw = next(b.text for b in resp.content if b.type == "text")
    if not raw.lstrip().startswith("{"):
        raise NotJSON("схема не применилась: проверьте output_config на маршруте")
    try:
        return Lead.model_validate_json(raw)  # длины, диапазоны, значения enum
    except ValidationError as err:
        raise NotJSON(f"JSON не прошёл проверку: {err}") from err
```

Если в модели есть `Literal`, расхождение в регистре тоже даст здесь `ValidationError`. Когда `"Conversation Topic 3"` и `"Conversation topic 3"` для вас одно и то же, приводите такие поля к нужному написанию валидатором с `mode="before"` до основной проверки.

## Сколько стоит формат: +269 входных токенов на запрос

Structured outputs не тарифицируются отдельно, но Claude получает дополнительный системный промпт с описанием формата, и эти токены оплачиваются как обычный вход. В замере через шлюз из раздела про cURL схема из четырёх полей добавила 269 входных токенов на запрос. Для расчёта ниже эти 269 токенов умножены на прайс Anthropic за входные токены: 269 × 1 млн запросов = 269 млн токенов, умноженные на цену за 1 млн.

| Модель | Цена входа за 1 млн токенов | Надбавка на 1 млн запросов |
| --- | --- | --- |
| Claude Haiku 5.5 (промпт до 100 тыс. токенов) | $0,10 | $26,90 |
| Claude Sonnet 5.5 | $2 | $538 |
| Claude Opus 5.5 | $4 | $1 076 |

Цены взяты со [страницы цен Anthropic](https://platform.claude.com/docs/en/about-claude/pricing) по состоянию на 30 октября 2026 года; в Batch API они вдвое ниже. Расчёт верен для одной схемы и одного промпта: схема побольше добавит больше токенов. Выход в том же примере, наоборот, сократился с 91 токена прозы до 46 токенов JSON. На Sonnet 5.5 это экономит около $0,00045 на вызов при надбавке на входе около $0,000538, так что итог зависит от того, насколько многословен ваш ответ без схемы. Сравнение цен Claude с другими API — в статье [«Claude API или OpenAI API: где дешевле при вашей нагрузке»](https://blog.laozhang.ai/ru/posts/claude-api-vs-openai-api-pricing).

Две вещи влияют на счёт косвенно. Смена `output_config.format` сбрасывает кэш промпта для этой переписки, так что схему лучше не менять от запроса к запросу. Первый запрос с новой схемой, по документации, идёт медленнее из-за компиляции грамматики, которая потом кэшируется на 24 часа с последнего использования. Через шлюз эта задержка не выделилась: новая схема и два повтора ответили за 4,23, 3,33 и 4,28 с, и разброс сети оказался больше.

## Частые вопросы о Claude structured outputs

### Работают ли structured outputs в Amazon Bedrock и Google Cloud?

Да. По документации Anthropic на 30 октября 2026 года функция общедоступна в Claude API, Claude Platform on AWS, Amazon Bedrock (включая InvokeModel), Claude на Google Cloud (Vertex AI) и Microsoft Foundry. Недоступна она только в Managed Agents. Если облако или шлюз отвечает 400 на `output_config`, смотрите раздел про текст вместо JSON выше.

### Можно ли включить structured outputs со streaming и Batch API?

Да, по документации Anthropic оба режима совместимы: ответ стримится как обычно, а в Batch API запросы со схемой стоят вдвое дешевле. Подсчёт токенов через token counting тоже работает и компиляцию схемы не запускает. Учтите, что при стриминге JSON становится валидным только в конце, поэтому разбирайте его после завершения потока.

### Совместимы ли structured outputs с extended thinking?

Да. Грамматика ограничивает только итоговый ответ, а не блоки thinking, вызовы инструментов и их результаты. 30 октября 2026 года через LaoZhang API `claude-sonnet-5-5` с `thinking: {"type": "adaptive"}` и `output_config: {"effort": "low", "format": ...}` вернул один текстовый блок с валидным JSON; блока thinking при низком effort не было. Поэтому JSON ищите по типу блока, а не по индексу.

### Есть ли у Claude JSON mode, как у OpenAI?

Отдельного JSON mode у Claude нет: его роль выполняет `output_config.format` со схемой, а режим «просто валидный JSON без схемы» не предусмотрен. Как то же самое устроено у OpenAI, разобрано в статье [«Structured Outputs или Function Calling в OpenAI: что выбрать»](https://blog.laozhang.ai/ru/posts/structured-outputs-vs-function-calling).

### Structured outputs в Claude Code и Agent SDK — это то же самое?

Нет, это другой механизм: схема передаётся в `query()` через `outputFormat` (TypeScript) или `output_format` (Python), SDK сам проверяет итог агента, при несовпадении просит переделать и возвращает данные в `structured_output`. Подробности — в [документации Claude Agent SDK по structured outputs](https://code.claude.com/docs/en/agent-sdk/structured-outputs).

### Можно ли класть персональные данные в JSON-схему при ZDR или HIPAA?

В саму схему — нет. По документации Anthropic промпты и ответы со structured outputs не хранятся при Zero Data Retention, но схема кэшируется до 24 часов с последнего использования и не получает той же защиты. Поэтому имена свойств, значения `enum` и `const` и регулярные выражения в `pattern` не должны содержать PHI, то есть защищённые медицинские данные пациентов; им место только в тексте сообщений. По той же причине не стоит класть в схему и другие персональные данные.

## Источники

Внешние страницы, на которые ссылается это руководство, в порядке упоминания. Последнее обновление: 2026-10-30.

- [документации Anthropic по structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) (platform.claude.com)
- [документации Anthropic по strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use) (platform.claude.com)
- [страницы цен Anthropic](https://platform.claude.com/docs/en/about-claude/pricing) (platform.claude.com)
- [документации Claude Agent SDK по structured outputs](https://code.claude.com/docs/en/agent-sdk/structured-outputs) (code.claude.com)
