---
title: Структурированные выходные данные
url: https://platform.claude.com/docs/ru/build-with-claude/structured-outputs
description: Получайте проверенные результаты в формате JSON из агентных рабочих процессов
featureMetadata:
  status: ga
  zdr:
    eligibility: eligible
    note: Excludes [Covered Models](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements).
  supportedModels:
    - claude-fable-5-1
    - claude-mythos-5-1
    - claude-fable-5
    - claude-mythos-5
    - claude-mythos-preview
    - claude-opus-5-5
    - claude-opus-5
    - claude-opus-4-8
    - claude-opus-4-7
    - claude-opus-4-6
    - claude-sonnet-5-5
    - claude-sonnet-5
    - claude-sonnet-4-6
    - claude-sonnet-4-5-20250929
    - claude-opus-4-5-20251101
    - claude-haiku-5-5
    - claude-haiku-4-5-20251001
  supportedPlatforms:
    Claude API: ga
    Claude Platform on AWS: ga
    Amazon Bedrock:
      availability: ga
      note: В Amazon Bedrock структурированные выходные данные доступны в устаревшей интеграции [Amazon Bedrock (Opus 4.6 и более ранние)](https://platform.claude.com/docs/ru/build-with-claude/claude-on-amazon-bedrock-legacy) для Claude Opus 4.6, Claude Sonnet 4.6, Claude Sonnet 4.5, Claude Opus 4.5 и Claude Haiku 4.5, но не в [Claude in Amazon Bedrock](https://platform.claude.com/docs/ru/build-with-claude/claude-in-amazon-bedrock).
    Google Cloud: ga
    Microsoft Foundry: ga
---

«Structured outputs» (структурированные выходные данные) ограничивают ответы Claude так, чтобы они следовали определённой схеме, обеспечивая валидный, поддающийся разбору вывод для последующей обработки. Структурированные выходные данные предоставляют две взаимодополняющие функции:

* **Выходные данные JSON** (`output_config.format`): получайте ответ Claude в определённом формате JSON, например для извлечения данных из изображений или текста, создания структурированных отчётов или форматирования ответов API. Эта страница посвящена выходным данным JSON.
* **Строгое использование инструментов** (`strict: true`): гарантируйте валидацию схемы для имён и входных данных инструментов. См. [Строгое использование инструментов](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/strict-tool-use).

Вы можете использовать эти функции независимо или [вместе в одном запросе](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#using-both-features-together).

## Зачем использовать структурированные выходные данные

Без структурированных выходных данных Claude может генерировать некорректные ответы JSON или невалидные входные данные инструментов, которые ломают ваши приложения. Даже при тщательном составлении подсказок вы можете столкнуться с:

* Ошибками разбора из-за невалидного синтаксиса JSON
* Отсутствующими обязательными полями
* Несогласованными типами данных
* Нарушениями схемы, требующими обработки ошибок и повторных попыток

Структурированные выходные данные гарантируют соответствующие схеме ответы благодаря ограниченному декодированию:

* **Всегда валидны:** больше никаких ошибок `JSON.parse()`
* **Типобезопасны:** гарантированные типы полей и обязательные поля
* **Надёжны:** не нужны повторные попытки из-за нарушений схемы

## Как это работает

<Steps>
  <Step title="Определите схему">
    Опишите нужную структуру в виде JSON-схемы или типа в вашем языке. Схема следует JSON Schema с некоторыми [ограничениями](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#json-schema-limitations).
  </Step>

  <Step title="Отправьте её в output_config.format">
    Запрос передаёт схему в `output_config.format` с `type: "json_schema"`. Вспомогательные функции SDK задают это за вас.
  </Step>

  <Step title="Прочитайте ответ">
    Claude возвращает корректный JSON, соответствующий вашей схеме, в текстовом блоке содержимого ответа. Вспомогательные функции SDK разбирают его в ваш тип.
  </Step>
</Steps>

## Использование

<Tabs>
  <Tab title="cURL">
    ```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
            }
          }
        }
      }'
    ```

    Claude возвращает JSON такого вида в текстовом блоке содержимого ответа:

    ```json Output
    {
      "name": "John Smith",
      "email": "john@example.com",
      "plan_interest": "Enterprise",
      "demo_requested": true
    }
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    ant messages create \
      --transform 'content.#(type=="text").text|@fromstr' \
      --format jsonl <<'YAML'
    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
    YAML
    ```

    Чтобы вывести только некоторые свойства выходных данных JSON, передайте [путь GJSON](https://platform.claude.com/docs/ru/cli-sdks-libraries/cli/using#transform-output-with-gjson) в `--transform`.

    Приведённый выше пример выводит:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```
  </Tab>

  <Tab title="Python">
    ```python
    from pydantic import BaseModel
    # ...


    class ContactInfo(BaseModel):
        name: str
        email: str
        plan_interest: str
        demo_requested: bool


    client = Anthropic()

    response = client.messages.parse(
        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_format=ContactInfo,
    )

    print(response.parsed_output)
    ```

    Передайте модель [Pydantic](https://docs.pydantic.dev/) в `client.messages.parse()` (рекомендуемый метод) в качестве `output_format`. SDK преобразует схему модели, отправляет её как `output_config.format`, проверяет ответ и возвращает разобранную модель в `parsed_output`.

    Приведённый выше пример выводит:

    ```text Output wrap
    name='John Smith' email='john@example.com' plan_interest='Enterprise' demo_requested=True
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    import { z } from "zod";
    import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";

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

    const client = new Anthropic();

    const response = await client.messages.parse({
      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: zodOutputFormat(ContactInfoSchema) }
    });

    // Автоматически разбирается и проверяется
    console.log(response.parsed_output);
    ```

    Оберните схему [Zod](https://zod.dev/) в `zodOutputFormat()` и передайте её в `client.messages.parse()` как `output_config.format`. `zodOutputFormat()` преобразует схему, а `parse()` проверяет ответ и возвращает разобранный результат в `parsed_output`, типизированный в соответствии со схемой.

    Приведённый выше пример выводит:

    ```javascript Output
    {
      name: 'John Smith',
      email: 'john@example.com',
      plan_interest: 'Enterprise',
      demo_requested: true
    }
    ```
  </Tab>

  <Tab title="C#">
    ```csharp
    using Anthropic;
    using Anthropic.Models.Messages;
    using Anthropic.Services;

    var client = new AnthropicClient();

    var response = await client.Messages.Create<ContactInfo>(new MessageCreateParams
    {
        Model = Model.ClaudeOpus5_5,
        MaxTokens = 1024,
        Messages = [new() {
            Role = 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."
        }],
    });

    if (response.Content.Select(block => block.Parsed()).OfType<ContactInfo>().FirstOrDefault() is { } contact)
    {
        Console.WriteLine(contact);
    }

    public record ContactInfo
    {
        public string Name { get; set; } = "";
        public string Email { get; set; } = "";
        public string PlanInterest { get; set; } = "";
        public bool DemoRequested { get; set; }
    }
    ```

    Передайте обычный класс или record C# в обобщённую перегрузку `Create<T>()`. SDK выводит JSON-схему из типа, преобразует её и разбирает каждый текстовый блок обратно в этот тип.

    Приведённый выше пример выводит:

    ```text Output wrap
    ContactInfo { Name = John Smith, Email = john@example.com, PlanInterest = Enterprise, DemoRequested = True }
    ```
  </Tab>

  <Tab title="Go">
    ```go
    type ContactInfo struct {
    	Name          string `json:"name"`
    	Email         string `json:"email"`
    	PlanInterest  string `json:"plan_interest"`
    	DemoRequested bool   `json:"demo_requested"`
    }

    func main() {
    	client := anthropic.NewClient()

    	var contact ContactInfo
    	_, err := client.Beta.Messages.New(context.Background(), anthropic.BetaMessageNewParams{
    		Model:     anthropic.ModelClaudeOpus5_5,
    		MaxTokens: 1024,
    		Messages: []anthropic.BetaMessageParam{
    			anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock(
    				"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.",
    			)),
    		},
    		OutputConfig: anthropic.BetaOutputConfigParam{
    			Format: anthropic.BetaJSONOutputFormatParam{Schema: &contact},
    		},
    	})
    	if err != nil {
    		panic(err)
    	}

    	fmt.Printf("%#v\n", contact)
    }
    ```

    <Note>
      Передача структуры в качестве схемы в Go находится в бета-версии, поэтому в этом примере используется `client.Beta.Messages.New`. Чтобы использовать общедоступный `client.Messages.New`, передайте JSON-схему, как показано в разделе [Использование необработанной JSON-схемы](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#using-a-raw-json-schema).
    </Note>

    SDK генерирует и преобразует JSON-схему из структуры и десериализует ответ в неё.

    Приведённый выше пример выводит:

    ```text Output wrap
    main.ContactInfo{Name:"John Smith", Email:"john@example.com", PlanInterest:"Enterprise", DemoRequested:true}
    ```
  </Tab>

  <Tab title="Java">
    ```java
    static class ContactInfo {
        public String name;
        public String email;
        public String plan_interest;
        public boolean demo_requested;
    }

    void main() throws Exception {
        AnthropicClient client = AnthropicOkHttpClient.fromEnv();

        StructuredMessageCreateParams<ContactInfo> params = MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024)
            .addUserMessage("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.")
            .outputConfig(ContactInfo.class)
            .build();

        StructuredMessage<ContactInfo> response = client.messages().create(params);
        ContactInfo contact = response.content().stream()
            .flatMap(block -> block.text().stream())
            .findFirst().orElseThrow().text();
        IO.println(new ObjectMapper().writeValueAsString(contact));
    }
    ```

    Когда вы передаёте класс Java в `outputConfig()`, SDK выводит из него JSON-схему и проверяет её. Затем построитель создаёт `StructuredMessageCreateParams<T>`. Вместо преобразования схемы локальная проверка SDK отклоняет [ограничения, не поддерживаемые API](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#json-schema-limitations). Прочитайте разобранный результат с помощью `response.content().stream().flatMap(block -> block.text().stream()).findFirst().orElseThrow().text()`.

    Приведённый выше пример выводит:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```

    <Note>
      Объявляйте ваши классы схем как классы верхнего уровня или вложенные классы `static`. Это требование исходит от библиотеки Jackson Databind (`com.fasterxml.jackson.databind`), которую SDK использует для десериализации ответов JSON в экземпляры ваших классов и которая не может создавать экземпляры нестатических внутренних классов.
    </Note>

    <Accordion title="Стирание обобщённых типов">
      Java сохраняет информацию об обобщённых типах для полей в метаданных класса, но в других областях видимости применяется стирание обобщённых типов. Хотя схему JSON можно вывести из поля `BookList.books` с типом `List<Book>`, валидную схему JSON нельзя вывести из локальной переменной того же типа.

      Если при преобразовании ответа JSON в экземпляр класса Java возникает ошибка, сообщение об ошибке включает ответ JSON для помощи в диагностике. Если ваш ответ JSON может содержать конфиденциальную информацию, избегайте его прямого логирования или убедитесь, что вы удалили все конфиденциальные сведения из сообщения об ошибке.
    </Accordion>

    <Accordion title="Локальная валидация схемы">
      Структурированные выходные данные поддерживают [подмножество языка JSON Schema](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#json-schema-limitations). SDK автоматически генерирует схемы из классов в соответствии с этим подмножеством. Метод `outputConfig(Class<T>)` выполняет проверку валидации схемы, выведенной из указанного класса.

      Ключевые моменты:

      * **Локальная валидация** происходит без отправки запросов к удалённой модели ИИ.
      * **Удалённая валидация** также выполняется моделью ИИ при получении схемы JSON.
      * **Совместимость версий:** локальная валидация может завершиться неудачей, тогда как удалённая валидация пройдёт успешно, если версия SDK устарела.
      * **Отключение локальной валидации:** передайте `JsonSchemaLocalValidation.NO`, если вы столкнулись с проблемами совместимости:

      ```java
      import com.anthropic.core.JsonSchemaLocalValidation;
      // ...

      static class BookList {
          public List<String> books;
      }

      void main() {
          StructuredMessageCreateParams<BookList> createParams = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(2048)
              .outputConfig(BookList.class, JsonSchemaLocalValidation.NO)
              .addUserMessage("List some famous late twentieth century novels.")
              .build();
      }
      ```
    </Accordion>

    <Accordion title="Потоковая передача">
      Структурированные выходные данные также работают с потоковой передачей. Поскольку ответы поступают в событиях потока, вам нужно накопить полный ответ перед десериализацией JSON.

      Используйте `MessageAccumulator` для сбора строк JSON из потока. После накопления вызовите `MessageAccumulator.message(Class<T>)`, чтобы преобразовать накопленное `Message` в `StructuredMessage`, которое автоматически десериализует JSON в ваш класс Java.
    </Accordion>

    <Accordion title="Свойства схемы JSON">
      Когда SDK выводит схему JSON из ваших классов Java, он по умолчанию включает все свойства, представленные полями `public` или геттерами `public`, и исключает не-`public` поля и геттеры.

      Вы можете управлять видимостью с помощью аннотаций:

      * `@JsonIgnore` исключает поле или геттер `public`
      * `@JsonProperty` включает не-`public` поле или геттер

      Если вы определяете поля `private` с геттерами `public`, SDK выводит имя свойства из геттера (например, поле `private` `myValue` с методом `public` `getMyValue()` даёт свойство `"myValue"`). Чтобы использовать нестандартное имя геттера, аннотируйте метод с помощью `@JsonProperty`.

      Каждый класс должен определять хотя бы одно свойство для схемы JSON. Ошибка валидации возникает, если никакие поля или геттеры не могут дать свойства схемы, например когда:

      * В классе нет полей или геттеров
      * Все члены `public` аннотированы `@JsonIgnore`
      * У всех не-`public` членов отсутствуют аннотации `@JsonProperty`
      * Поле использует тип `Map`, который даёт пустое поле `"properties"`
    </Accordion>

    <Accordion title="Композиция и наследование">
      Ваши классы Java могут использовать композицию и наследование для совместного использования структуры при определении схем JSON. Каждый паттерн по-разному влияет на структуру вывода.

      **Композиция** даёт вложенный вывод JSON. Вывод схемы из класса `Composed`, который компонует `A` и `B`:

      ```java
      static class A {
          public String a;
      }

      static class B {
          public String b;
      }

      static class Composed {
          public A composedA;
          public B composedB;
      }
      ```

      Вывод JSON имеет такую вложенную структуру:

      ```json
      {
        "composedA": { "a": "hello" },
        "composedB": { "b": "world" }
      }
      ```

      **Наследование** даёт плоский вывод JSON. Вывод схемы из класса `Derived`, который расширяет `Base`:

      ```java
      static class Base {
          public String a;
      }

      static class Derived extends Base {
          public String b;
      }
      ```

      Вывод JSON имеет такую плоскую структуру:

      ```json
      {
        "a": "hello",
        "b": "world"
      }
      ```
    </Accordion>

    <Accordion title="Аннотации (Jackson и Swagger)">
      Вы можете использовать аннотации Jackson Databind для обогащения схемы JSON, выведенной из ваших классов Java:

      ```java
      import com.fasterxml.jackson.annotation.JsonClassDescription;
      import com.fasterxml.jackson.annotation.JsonIgnore;
      import com.fasterxml.jackson.annotation.JsonPropertyDescription;

      static class Person {

        @JsonPropertyDescription("The first name and surname of the person")
        public String name;

        public int birthYear;

        @JsonPropertyDescription("The year the person died, or 'present' if the person is living.")
        public String deathYear;
      }

      @JsonClassDescription("The details of one published book")
      static class Book {

        public String title;
        public Person author;

        @JsonPropertyDescription("The year in which the book was first published.")
        public int publicationYear;

        @JsonIgnore
        public String genre;
      }

      static class BookList {
        public List<Book> books;
      }
      ```

      Сводка аннотаций:

      * `@JsonClassDescription`: добавить описание к классу
      * `@JsonPropertyDescription`: добавить описание к полю или геттеру
      * `@JsonIgnore`: исключить поле или геттер `public` из схемы
      * `@JsonProperty`: включить не-`public` поле или геттер в схему

      Если вы используете `@JsonProperty(required = false)`, SDK игнорирует значение `false`. Схемы, выведенные из классов, всегда помечают все свойства как обязательные.

      Вы также можете использовать аннотации Swagger Core (OpenAPI 3) `@Schema` и `@ArraySchema` для ограничений, специфичных для типов:

      ```java
      import io.swagger.v3.oas.annotations.media.ArraySchema;
      import io.swagger.v3.oas.annotations.media.Schema;

      static class Article {

        @ArraySchema(minItems = 1)
        public List<String> authors;

        public String title;

        @Schema(format = "date")
        public String publicationDate;

        public int pageCount;
      }
      ```

      Локальная валидация проверяет, что вы не использовали неподдерживаемые ключевые слова ограничений, но значения ограничений локально не валидируются. Например, неподдерживаемое значение `"format"` может пройти локальную валидацию, но вызвать удалённую ошибку.

      Если вы используете аннотации и Jackson, и Swagger для установки одного и того же поля схемы, приоритет имеет аннотация Jackson.
    </Accordion>
  </Tab>

  <Tab title="PHP">
    ```php
    use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
    use Anthropic\Lib\Contracts\StructuredOutputModel;

    $client = new Client();

    class ContactInfo implements StructuredOutputModel
    {
        use StructuredOutputModelTrait;

        public string $name;
        public string $email;
        public string $plan_interest;
        public bool $demo_requested;
    }

    $message = $client->messages->create(
        maxTokens: 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.',
            ],
        ],
        model: 'claude-opus-5-5',
        outputConfig: ['format' => ContactInfo::class],
    );

    $contact = $message->parsedOutput();
    if ($contact instanceof ContactInfo) {
        var_dump($contact);
    }
    ```

    Определите класс, который реализует `StructuredOutputModel` и использует `StructuredOutputModelTrait`, и передайте его имя в `outputConfig: ['format' => MyClass::class]`. SDK выводит JSON-схему из типов свойств PHP 8 класса, преобразует её и возвращает типизированный экземпляр из `$message->parsedOutput()`.

    `parsedOutput()` возвращает экземпляр вашей модели при успехе или `null` (или массив ошибок), если разбор не удался. Используйте `instanceof`, чтобы сузить тип перед доступом к полям.

    Приведённый выше пример выводит:

    ```text Output wrap
    object(ContactInfo)#42 (4) {
      ["name"]=>
      string(10) "John Smith"
      ["email"]=>
      string(16) "john@example.com"
      ["plan_interest"]=>
      string(10) "Enterprise"
      ["demo_requested"]=>
      bool(true)
    }
    ```

    <Accordion title="Вывод типов">
      SDK сопоставляет нативные типы свойств PHP 8 с JSON Schema:

      | Тип PHP                                    | JSON Schema                          |
      | ------------------------------------------ | ------------------------------------ |
      | `string`                                   | `"string"`                           |
      | `int`                                      | `"integer"`                          |
      | `float`                                    | `"number"`                           |
      | `bool`                                     | `"boolean"`                          |
      | `array`                                    | `"array"` (см. следующее примечание) |
      | `?type` (может быть null)                  | Необязательное поле                  |
      | Класс, реализующий `StructuredOutputModel` | Вложенный объект                     |

      Для свойств `array` SDK добавляет схему `items` только тогда, когда тип элемента — вложенный `StructuredOutputModel`, объявленный с помощью `#[Constrained(itemClass: MyModel::class)]` или docblock `/** @var MyModel[] */`. Массивы скаляров (`string[]`, `int[]`) дают неограниченный `{"type":"array"}`.

      Все не-nullable свойства становятся обязательными полями.
    </Accordion>

    <Accordion title="Ограничения с атрибутом #[Constrained]">
      Добавляйте ограничения с помощью атрибута `#[Constrained]`:

      ```php
      use Anthropic\Lib\Attributes\Constrained;
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      class Address implements StructuredOutputModel { use StructuredOutputModelTrait; public string $street; }

      class Profile implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          #[Constrained(description: 'Age in years', minimum: 0, maximum: 150)]
          public int $age;

          #[Constrained(format: 'email')]
          public string $email;

          #[Constrained(itemClass: Address::class, minItems: 1)]
          public array $addresses;
      }
      ```

      **Ограничения, применяемые API** (отправляются в схеме): `description`, `format`, `const`, `itemClass`, `minItems` (только 0 или 1).

      **Ограничения, валидируемые SDK** (удаляются из передаваемой схемы, добавляются к описанию и валидируются по ответу): `minimum`, `maximum`, `multipleOf`, `minLength`, `maxLength`.
    </Accordion>
  </Tab>

  <Tab title="Ruby">
    ```ruby
    client = Anthropic::Client.new

    class ContactInfo < Anthropic::BaseModel
      required :name, String
      required :email, String
      required :plan_interest, String
      required :demo_requested, Anthropic::Boolean
    end

    message = client.messages.create(
      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: ContactInfo}
    )

    contact = message.parsed_output
    puts contact
    ```

    Определите класс, расширяющий `Anthropic::BaseModel`, и передайте его в `messages.create()` как `output_config: {format: Model}`. SDK выводит JSON-схему из класса, преобразует её и присваивает разобранный результат атрибуту `parsed_output` ответа в виде типизированного объекта Ruby.

    Приведённый выше пример выводит:

    ```text Output wrap
    {name: "John Smith", email: "john@example.com", plan_interest: "Enterprise", demo_requested: true}
    ```

    <Accordion title="Расширенные возможности моделей">
      Ruby SDK поддерживает дополнительные возможности определения моделей для более богатых схем:

      * **Ключевое слово `doc:`:** добавляйте описания к полям для более информативного вывода схемы
      * **`Anthropic::ArrayOf[T]`:** типизированные массивы. Передавайте ограничения уровня массива (`min_items:`, `max_items:`) как ключевые слова в `required`/`optional`, а не в сам `ArrayOf`
      * **`Anthropic::EnumOf[:a, :b]`:** поля-перечисления с ограниченными значениями
      * **`Anthropic::UnionOf[T1, T2]`:** типы-объединения, сопоставляемые с `anyOf`

      ```ruby
      class FamousNumber < Anthropic::BaseModel
        required :value, Float
        optional :reason, String, doc: "why is this number mathematically significant?"
      end

      class Output < Anthropic::BaseModel
        required :numbers, Anthropic::ArrayOf[FamousNumber], min_items: 3, max_items: 5
      end

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 1024,
        messages: [{role: "user", content: "give me some famous numbers"}],
        output_config: {format: Output}
      )

      message.parsed_output
      # => #<Output numbers=[#<FamousNumber value=3.14159... reason="Число пи — это...">...]>
      ```
    </Accordion>
  </Tab>
</Tabs>

## Как работает преобразование в SDK

Большинство вспомогательных функций SDK преобразуют схемы, использующие неподдерживаемые возможности. Этапы преобразования:

1. **Удаление неподдерживаемых ограничений** (например, `minimum`, `maximum`, `minLength`, `maxLength`)
2. **Обновление описаний** путём добавления каждого неподдерживаемого ограничения в описание поля (например, `{minimum: 100}`)
3. **Добавление `additionalProperties: false`** ко всем объектам
4. **Фильтрация строковых форматов** только до поддерживаемого списка
5. **Проверка ответов** по вашей исходной схеме и всем её ограничениям, если вспомогательная функция проверяет ответы

Claude получает упрощённую схему, но вспомогательная функция, проверяющая ответы, по-прежнему применяет каждое ограничение в вашем коде.

**Пример:** поле с `minimum: 100` становится обычным целым числом в отправляемой схеме, а SDK добавляет `{minimum: 100}` в описание поля. Вспомогательная функция, проверяющая ответы, по-прежнему проверяет ответ на соответствие `minimum: 100`.

## Использование необработанной JSON-схемы

Чтобы использовать JSON-схему из файла, спецификации OpenAPI или кода, который строит её во время выполнения, передайте её в `output_config.format`.

<Tabs>
  <Tab title="cURL">
    ```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
            }
          }
        }
      }'
    ```

    Claude возвращает JSON такого вида в текстовом блоке содержимого ответа:

    ```json Output
    {
      "name": "John Smith",
      "email": "john@example.com",
      "plan_interest": "Enterprise",
      "demo_requested": true
    }
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    ant messages create \
      --transform 'content.#(type=="text").text|@fromstr' \
      --format jsonl <<'YAML'
    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
    YAML
    ```

    Приведённый выше пример выводит:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```
  </Tab>

  <Tab title="Python">
    ```python
    client = anthropic.Anthropic()

    response = client.messages.create(
        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,
                },
            }
        },
    )
    text = next(block.text for block in response.content if block.type == "text")
    contact = json.loads(text)
    print(contact)
    ```

    Приведённый выше пример выводит:

    ```text Output wrap
    {'name': 'John Smith', 'email': 'john@example.com', 'plan_interest': 'Enterprise', 'demo_requested': True}
    ```

    Чтобы перенести [ограничения, не поддерживаемые API](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#json-schema-limitations), в описания полей, пропустите схему через `transform_schema()` из пакета `anthropic` перед отправкой и при необходимости отредактируйте результат. `transform_schema()` также принимает модель Pydantic. В отличие от `client.messages.parse()`, она возвращает преобразованную схему, а не отправляет её.
  </Tab>

  <Tab title="TypeScript">
    ```typescript
    import { jsonSchemaOutputFormat } from "@anthropic-ai/sdk/helpers/json-schema";

    const client = new Anthropic();

    const response = await client.messages.parse({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: "Extract contact info: John Smith, john@example.com, interested in the Pro plan"
        }
      ],
      output_config: {
        format: jsonSchemaOutputFormat({
          type: "object",
          properties: {
            name: { type: "string" },
            email: { type: "string" },
            planInterest: { type: "string" }
          },
          required: ["name", "email", "planInterest"],
          additionalProperties: false
        } as const)
      }
    });

    // response.parsed_output имеет тип { name: string; email: string; planInterest: string } | null
    console.log(response.parsed_output);
    ```

    Используйте `jsonSchemaOutputFormat()`, чтобы передать обычную JSON-схему в `parse()` без установки Zod. API возвращает ответ, соответствующий схеме, и если вы объявите схему с `as const`, TypeScript автоматически выведет тип `parsed_output` из вашей схемы. Для импортированной или сгенерированной схемы `parsed_output` имеет тип `unknown`.

    По умолчанию вспомогательная функция [преобразует схему](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#how-sdk-transformation-works) так же, как `zodOutputFormat()`. Передайте `{ transform: false }` вторым аргументом, чтобы отправить её без изменений. В отличие от `zodOutputFormat()`, она не проверяет ответ, поэтому не обнаружит нарушения [ограничений, не поддерживаемых API](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#json-schema-limitations), таких как `minimum`.

    Приведённый выше пример выводит:

    ```javascript Output
    { name: 'John Smith', email: 'john@example.com', planInterest: 'Pro' }
    ```
  </Tab>

  <Tab title="C#">
    ```csharp
    using System.Text.Json;
    using Anthropic;
    using Anthropic.Models.Messages;

    var client = new AnthropicClient();

    var response = await client.Messages.Create(new MessageCreateParams
    {
        Model = Model.ClaudeOpus5_5,
        MaxTokens = 1024,
        Messages = [new() {
            Role = 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."
        }],
        OutputConfig = new OutputConfig
        {
            Format = new JsonOutputFormat
            {
                Schema = new Dictionary<string, JsonElement>
                {
                    ["type"] = JsonSerializer.SerializeToElement("object"),
                    ["properties"] = JsonSerializer.SerializeToElement(new
                    {
                        name = new { type = "string" },
                        email = new { type = "string" },
                        plan_interest = new { type = "string" },
                        demo_requested = new { type = "boolean" },
                    }),
                    ["required"] = JsonSerializer.SerializeToElement(
                        new[] { "name", "email", "plan_interest", "demo_requested" }),
                    ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                },
            },
        },
    });

    if (response.Content.Select(b => b.Value).OfType<TextBlock>().FirstOrDefault() is { } textBlock)
    {
        // JSON гарантированно соответствует схеме
        var contact = JsonSerializer.Deserialize<JsonElement>(textBlock.Text);
        Console.WriteLine(contact);
    }
    ```

    Приведённый выше пример выводит:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}
    ```
  </Tab>

  <Tab title="Go">
    ```go
    type ContactInfo struct {
    	Name          string `json:"name"`
    	Email         string `json:"email"`
    	PlanInterest  string `json:"plan_interest"`
    	DemoRequested bool   `json:"demo_requested"`
    }

    func main() {
    	client := anthropic.NewClient()

    	message, _ := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
    		Model:     anthropic.ModelClaudeOpus5_5,
    		MaxTokens: 1024,
    		Messages: []anthropic.MessageParam{
    			anthropic.NewUserMessage(anthropic.NewTextBlock(
    				"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.",
    			)),
    		},
    		OutputConfig: anthropic.OutputConfigParam{
    			Format: anthropic.JSONOutputFormatParam{
    				Schema: map[string]any{
    					"type": "object",
    					"properties": map[string]any{
    						"name":           map[string]string{"type": "string"},
    						"email":          map[string]string{"type": "string"},
    						"plan_interest":  map[string]string{"type": "string"},
    						"demo_requested": map[string]string{"type": "boolean"},
    					},
    					"required":             []string{"name", "email", "plan_interest", "demo_requested"},
    					"additionalProperties": false,
    				},
    			},
    		},
    	})

    	for _, block := range message.Content {
    		switch variant := block.AsAny().(type) {
    		case anthropic.TextBlock:
    			var contact ContactInfo
    			json.Unmarshal([]byte(variant.Text), &contact)
    			fmt.Printf("%#v\n", contact)
    		}
    	}
    }
    ```

    Приведённый выше пример выводит:

    ```text Output wrap
    main.ContactInfo{Name:"John Smith", Email:"john@example.com", PlanInterest:"Enterprise", DemoRequested:true}
    ```

    Чтобы SDK преобразовал схему в виде map, пропустите её через `BetaJSONSchemaOutputFormat()` в бета-API.
  </Tab>

  <Tab title="Java">
    ```java
    import com.anthropic.core.JsonValue;
    import com.anthropic.models.messages.JsonOutputFormat;
    // ...
    import com.anthropic.models.messages.OutputConfig;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;

    void main() throws Exception {
        AnthropicClient client = AnthropicOkHttpClient.fromEnv();

        JsonOutputFormat.Schema schema = JsonOutputFormat.Schema.builder()
            .putAdditionalProperty("type", JsonValue.from("object"))
            .putAdditionalProperty("properties", JsonValue.from(Map.of(
                "name", Map.of("type", "string"),
                "email", Map.of("type", "string"),
                "plan_interest", Map.of("type", "string"))))
            .putAdditionalProperty("required", JsonValue.from(
                List.of("name", "email", "plan_interest")))
            .putAdditionalProperty("additionalProperties", JsonValue.from(false))
            .build();

        OutputConfig outputConfig = OutputConfig.builder()
            .format(JsonOutputFormat.builder().schema(schema).build())
            .build();

        MessageCreateParams createParams = MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024)
            .outputConfig(outputConfig)
            .addUserMessage(
                "John Smith (john@example.com) is interested in our Enterprise plan.")
            .build();

        String json = client.messages().create(createParams).content().stream()
            .flatMap(contentBlock -> contentBlock.text().stream())
            .findFirst()
            .orElseThrow()
            .text();

        JsonNode contact = new ObjectMapper().readTree(json);
        IO.println(contact);
    }
    ```

    Приведённый выше пример выводит:

    ```text Output wrap
    {"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise"}
    ```

    Более подробный пример, который строит вложенную схему с массивами и описаниями, см. в [`StructuredOutputsRawExample.java`](https://github.com/anthropics/anthropic-sdk-java/blob/main/anthropic-java-example/src/main/java/com/anthropic/example/StructuredOutputsRawExample.java) в репозитории SDK.
  </Tab>

  <Tab title="PHP">
    ```php
    use Anthropic\Messages\OutputConfig;
    use Anthropic\Messages\JSONOutputFormat;

    $client = new Client();

    $message = $client->messages->create(
        maxTokens: 1024,
        messages: [
            [
                'role' => 'user',
                'content' => 'Extract the key information from this email: '
                    . 'John Smith (john@example.com) is interested in our Enterprise plan.',
            ],
        ],
        model: 'claude-opus-5-5',
        outputConfig: OutputConfig::with(format: JSONOutputFormat::with(schema: [
            'type' => 'object',
            'properties' => [
                'name' => ['type' => 'string'],
                'email' => ['type' => 'string'],
                'plan_interest' => ['type' => 'string'],
            ],
            'required' => ['name', 'email', 'plan_interest'],
            'additionalProperties' => false,
        ])),
    );

    $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
    $contact = json_decode($textBlock->text, associative: true);
    var_dump($contact);
    ```

    Передайте схему в виде ассоциативного массива в `OutputConfig::with()` и декодируйте ответ с помощью `json_decode()`.

    Приведённый выше пример выводит:

    ```text Output wrap
    array(3) {
      ["name"]=>
      string(10) "John Smith"
      ["email"]=>
      string(16) "john@example.com"
      ["plan_interest"]=>
      string(10) "Enterprise"
    }
    ```
  </Tab>

  <Tab title="Ruby">
    ```ruby
    client = Anthropic::Client.new

    response = client.messages.create(
      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
          }
        }
      }
    )

    text = response.content.find { it.type == :text }.text
    contact = JSON.parse(text)
    p contact
    ```

    Приведённый выше пример выводит:

    ```text Output wrap
    {"name" => "John Smith", "email" => "john@example.com", "plan_interest" => "Enterprise", "demo_requested" => true}
    ```
  </Tab>
</Tabs>

## Распространённые сценарии использования

<AccordionGroup>
  <Accordion title="Извлечение данных">
    Извлекайте структурированные данные из неструктурированного текста:

    <CodeGroup>
      ```bash cURL
      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": 4096,
          "messages": [
            {
              "role": "user",
              "content": "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Total: $500.00"
            }
          ],
          "output_config": {
            "format": {
              "type": "json_schema",
              "schema": {
                "type": "object",
                "properties": {
                  "invoice_number": {"type": "string"},
                  "date": {"type": "string"},
                  "total_amount": {"type": "number"},
                  "line_items": {
                    "type": "array",
                    "items": {"type": "object", "additionalProperties": false}
                  },
                  "customer_name": {"type": "string"}
                },
                "required": ["invoice_number", "date", "total_amount", "line_items", "customer_name"],
                "additionalProperties": false
              }
            }
          }
        }'
      ```

      ```bash CLI
      ant messages create \
        --transform 'content.#(type=="text").text|@fromstr' \
        --format jsonl <<'YAML'
      model: claude-opus-5-5
      max_tokens: 4096
      messages:
        - role: user
          content: "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Total: $500.00"
      output_config:
        format:
          type: json_schema
          schema:
            type: object
            properties:
              invoice_number: {type: string}
              date: {type: string}
              total_amount: {type: number}
              line_items:
                type: array
                items: {type: object, additionalProperties: false}
              customer_name: {type: string}
            required: [invoice_number, date, total_amount, line_items, customer_name]
            additionalProperties: false
      YAML
      ```

      ```python Python
      from pydantic import BaseModel


      class Invoice(BaseModel):
          invoice_number: str
          date: str
          total_amount: float
          line_items: list[dict]
          customer_name: str


      client = anthropic.Anthropic()
      invoice_text = "Invoice #12345, Date: 2024-01-15, Total: $500.00"

      response = client.messages.parse(
          model="claude-opus-5-5",
          max_tokens=4096,
          output_format=Invoice,
          messages=[
              {"role": "user", "content": f"Extract invoice data from: {invoice_text}"}
          ],
      )

      print(response.parsed_output)
      ```

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

      const client = new Anthropic();

      const InvoiceSchema = z.object({
        invoice_number: z.string(),
        date: z.string(),
        total_amount: z.number(),
        line_items: z.array(z.record(z.string(), z.any())),
        customer_name: z.string()
      });

      const invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";
      const response = await client.messages.parse({
        model: "claude-opus-5-5",
        max_tokens: 4096,
        output_config: { format: zodOutputFormat(InvoiceSchema) },
        messages: [{ role: "user", content: `Extract invoice data from: ${invoiceText}` }]
      });
      console.log(response.parsed_output);
      ```

      ```csharp C#
      AnthropicClient client = new();

      string invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";

      var parameters = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 4096,
          OutputConfig = new OutputConfig
          {
              Format = new JsonOutputFormat
              {
                  Schema = new Dictionary<string, JsonElement>
                  {
                      ["type"] = JsonSerializer.SerializeToElement("object"),
                      ["properties"] = JsonSerializer.SerializeToElement(new
                      {
                          invoice_number = new { type = "string" },
                          date = new { type = "string" },
                          total_amount = new { type = "number" },
                          line_items = new
                          {
                              type = "array",
                              items = new
                              {
                                  type = "object",
                                  additionalProperties = false,
                              },
                          },
                          customer_name = new { type = "string" },
                      }),
                      ["required"] = JsonSerializer.SerializeToElement(new[] { "invoice_number", "date", "total_amount", "line_items", "customer_name" }),
                      ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                  },
              },
          },
          Messages = [new() { Role = Role.User, Content = $"Extract invoice data from: {invoiceText}" }]
      };

      var message = await client.Messages.Create(parameters);
      Console.WriteLine(message);
      ```

      ```go Go
      client := anthropic.NewClient()

      invoiceText := "Invoice #12345, Date: 2024-01-15, Total: $500.00"

      schema := map[string]any{
      	"type":                 "object",
      	"additionalProperties": false,
      	"properties": map[string]any{
      		"invoice_number": map[string]any{"type": "string"},
      		"date":           map[string]any{"type": "string"},
      		"total_amount":   map[string]any{"type": "number"},
      		"line_items": map[string]any{
      			"type": "array",
      			"items": map[string]any{
      				"type":                 "object",
      				"additionalProperties": false,
      				"properties": map[string]any{
      					"description": map[string]any{"type": "string"},
      					"quantity":    map[string]any{"type": "number"},
      					"unit_price":  map[string]any{"type": "number"},
      				},
      				"required": []string{"description", "quantity", "unit_price"},
      			},
      		},
      		"customer_name": map[string]any{"type": "string"},
      	},
      	"required": []string{"invoice_number", "date", "total_amount", "line_items", "customer_name"},
      }

      response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 4096,
      	OutputConfig: anthropic.OutputConfigParam{
      		Format: anthropic.JSONOutputFormatParam{
      			Schema: schema,
      		},
      	},
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock(fmt.Sprintf("Extract invoice data from: %s", invoiceText))),
      	},
      })
      if err != nil {
      	log.Fatal(err)
      }
      for _, block := range response.Content {
      	switch variant := block.AsAny().(type) {
      	case anthropic.TextBlock:
      		fmt.Println(variant.Text)
      	}
      }
      ```

      ```java Java
      import com.fasterxml.jackson.annotation.JsonProperty;

      static class LineItem {
          @JsonProperty("description")
          public String description;

          @JsonProperty("quantity")
          public int quantity;

          @JsonProperty("unit_price")
          public double unitPrice;
      }

      static class Invoice {
          @JsonProperty("invoice_number")
          public String invoiceNumber;

          @JsonProperty("date")
          public String date;

          @JsonProperty("total_amount")
          public double totalAmount;

          @JsonProperty("line_items")
          public List<LineItem> lineItems;

          @JsonProperty("customer_name")
          public String customerName;
      }

      void main() {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          String invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";

          StructuredMessageCreateParams<Invoice> params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(4096L)
              .outputConfig(Invoice.class)
              .addUserMessage("Extract invoice data from: " + invoiceText)
              .build();

          StructuredMessage<Invoice> response = client.messages().create(params);
          Invoice invoice = response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst().orElseThrow().text();
          IO.println(invoice.invoiceNumber + ": $" + invoice.totalAmount);
      }
      ```

      ```php PHP
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      $client = new Client();

      class Invoice implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          public string $invoice_number;
          public string $date;
          public float $total_amount;
          public array $line_items;
          public string $customer_name;
      }

      $invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";

      $message = $client->messages->create(
          maxTokens: 4096,
          messages: [
              ['role' => 'user', 'content' => "Extract invoice data from: $invoiceText"]
          ],
          model: 'claude-opus-5-5',
          outputConfig: ['format' => Invoice::class],
      );

      $invoice = $message->parsedOutput();
      if ($invoice instanceof Invoice) {
          echo "Invoice {$invoice->invoice_number}: \${$invoice->total_amount}\n";
      }
      ```

      ```ruby Ruby
      client = Anthropic::Client.new

      class LineItem < Anthropic::BaseModel
        required :description, String
        required :amount, Float
      end

      class Invoice < Anthropic::BaseModel
        required :invoice_number, String
        required :date, String
        required :total_amount, Float
        required :line_items, Anthropic::ArrayOf[LineItem]
        required :customer_name, String
      end

      invoice_text = "Invoice #12345, Date: 2024-01-15, Total: $500.00"

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 4096,
        output_config: {format: Invoice},
        messages: [
          {role: "user", content: "Extract invoice data from: #{invoice_text}"}
        ]
      )

      invoice = message.parsed_output
      puts "Invoice #{invoice.invoice_number}: $#{invoice.total_amount}"
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Классификация">
    Классифицируйте контент по структурированным категориям:

    <CodeGroup>
      ```bash cURL
      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": "Classify this feedback: Great product, fast shipping!"
            }
          ],
          "output_config": {
            "format": {
              "type": "json_schema",
              "schema": {
                "type": "object",
                "properties": {
                  "category": {"type": "string"},
                  "confidence": {"type": "number"},
                  "tags": {"type": "array", "items": {"type": "string"}},
                  "sentiment": {"type": "string"}
                },
                "required": ["category", "confidence", "tags", "sentiment"],
                "additionalProperties": false
              }
            }
          }
        }'
      ```

      ```bash CLI
      ant messages create \
        --transform 'content.#(type=="text").text|@fromstr' \
        --format jsonl <<'YAML'
      model: claude-opus-5-5
      max_tokens: 1024
      messages:
        - role: user
          content: "Classify this feedback: Great product, fast shipping!"
      output_config:
        format:
          type: json_schema
          schema:
            type: object
            properties:
              category:
                type: string
              confidence:
                type: number
              tags:
                type: array
                items:
                  type: string
              sentiment:
                type: string
            required:
              - category
              - confidence
              - tags
              - sentiment
            additionalProperties: false
      YAML
      ```

      ```python Python
      from pydantic import BaseModel

      client = Anthropic()


      class Classification(BaseModel):
          category: str
          confidence: float
          tags: list[str]
          sentiment: str


      feedback_text = "Great product, but the delivery was slow."
      response = client.messages.parse(
          model="claude-opus-5-5",
          max_tokens=1024,
          output_format=Classification,
          messages=[{"role": "user", "content": f"Classify this feedback: {feedback_text}"}],
      )

      print(response.parsed_output)
      ```

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

      const client = new Anthropic();

      const ClassificationSchema = z.object({
        category: z.string(),
        confidence: z.number(),
        tags: z.array(z.string()),
        sentiment: z.string()
      });

      const feedbackText = "Great product, but the delivery was slow.";
      const response = await client.messages.parse({
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: { format: zodOutputFormat(ClassificationSchema) },
        messages: [{ role: "user", content: `Classify this feedback: ${feedbackText}` }]
      });

      console.log(response.parsed_output);
      ```

      ```csharp C#
      string feedbackText = "Great product, fast shipping!";

      var parameters = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Messages = [new() { Role = Role.User, Content = $"Classify this feedback: {feedbackText}" }],
          OutputConfig = new OutputConfig
          {
              Format = new JsonOutputFormat
              {
                  Schema = new Dictionary<string, JsonElement>
                  {
                      ["type"] = JsonSerializer.SerializeToElement("object"),
                      ["properties"] = JsonSerializer.SerializeToElement(new
                      {
                          category = new { type = "string" },
                          confidence = new { type = "number" },
                          tags = new { type = "array", items = new { type = "string" } },
                          sentiment = new { type = "string" },
                      }),
                      ["required"] = JsonSerializer.SerializeToElement(new[] { "category", "confidence", "tags", "sentiment" }),
                      ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                  },
              },
          },
      };

      var message = await client.Messages.Create(parameters);
      Console.WriteLine(message);
      ```

      ```go Go
      feedbackText := "Great product, fast shipping!"

      schema := map[string]any{
      	"type": "object",
      	"properties": map[string]any{
      		"category":   map[string]any{"type": "string"},
      		"confidence": map[string]any{"type": "number"},
      		"tags":       map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
      		"sentiment":  map[string]any{"type": "string"},
      	},
      	"required":             []string{"category", "confidence", "tags", "sentiment"},
      	"additionalProperties": false,
      }

      response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 1024,
      	OutputConfig: anthropic.OutputConfigParam{
      		Format: anthropic.JSONOutputFormatParam{
      			Schema: schema,
      		},
      	},
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock(fmt.Sprintf("Classify this feedback: %s", feedbackText))),
      	},
      })
      if err != nil {
      	log.Fatal(err)
      }
      for _, block := range response.Content {
      	switch variant := block.AsAny().(type) {
      	case anthropic.TextBlock:
      		var result map[string]any
      		json.Unmarshal([]byte(variant.Text), &result)
      		fmt.Println(result)
      	}
      }
      ```

      ```java Java
      import com.fasterxml.jackson.annotation.JsonProperty;

      static class Classification {
          @JsonProperty("category")
          public String category;

          @JsonProperty("confidence")
          public double confidence;

          @JsonProperty("tags")
          public List<String> tags;

          @JsonProperty("sentiment")
          public String sentiment;
      }

      void main() {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          String feedbackText = "Great product, fast shipping!";

          StructuredMessageCreateParams<Classification> params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024L)
              .outputConfig(Classification.class)
              .addUserMessage("Classify this feedback: " + feedbackText)
              .build();

          StructuredMessage<Classification> response = client.messages().create(params);
          Classification result = response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst().orElseThrow().text();
          IO.println(result.category + " (" + result.confidence + ")");
      }
      ```

      ```php PHP
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      $client = new Client();

      class Classification implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          public string $category;
          public float $confidence;
          public array $tags;
          public string $sentiment;
      }

      $feedbackText = "Great product, fast shipping!";

      $message = $client->messages->create(
          maxTokens: 1024,
          messages: [
              ['role' => 'user', 'content' => "Classify this feedback: {$feedbackText}"]
          ],
          model: 'claude-opus-5-5',
          outputConfig: ['format' => Classification::class],
      );

      $result = $message->parsedOutput();
      if ($result instanceof Classification) {
          echo "{$result->category} ({$result->confidence}): {$result->sentiment}\n";
      }
      ```

      ```ruby Ruby
      client = Anthropic::Client.new

      class Classification < Anthropic::BaseModel
        required :category, String
        required :confidence, Float
        required :tags, Anthropic::ArrayOf[String]
        required :sentiment, String
      end

      feedback_text = "Great product, fast shipping!"

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: {format: Classification},
        messages: [
          {role: "user", content: "Classify this feedback: #{feedback_text}"}
        ]
      )
      puts message.parsed_output
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Форматирование ответов API">
    Генерируйте ответы, готовые для API:

    <CodeGroup>
      ```bash cURL
      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": "Process this request: ..."
            }
          ],
          "output_config": {
            "format": {
              "type": "json_schema",
              "schema": {
                "type": "object",
                "properties": {
                  "status": {"type": "string"},
                  "data": {"type": "object", "additionalProperties": false},
                  "errors": {
                    "type": "array",
                    "items": {"type": "object", "additionalProperties": false}
                  },
                  "metadata": {"type": "object", "additionalProperties": false}
                },
                "required": ["status", "data", "metadata"],
                "additionalProperties": false
              }
            }
          }
        }'
      ```

      ```bash CLI
      ant messages create \
        --transform 'content.#(type=="text").text' \
        --raw-output <<'YAML'
      model: claude-opus-5-5
      max_tokens: 1024
      output_config:
        format:
          type: json_schema
          schema:
            type: object
            properties:
              status:
                type: string
              data:
                type: object
                additionalProperties: false
              errors:
                type: array
                items:
                  type: object
                  additionalProperties: false
              metadata:
                type: object
                additionalProperties: false
            required:
              - status
              - data
              - metadata
            additionalProperties: false
      messages:
        - role: user
          content: "Process this request: ..."
      YAML
      ```

      ```python Python
      from pydantic import BaseModel

      client = Anthropic()


      class APIResponse(BaseModel):
          status: str
          data: dict
          errors: list[dict] | None
          metadata: dict


      response = client.messages.parse(
          model="claude-opus-5-5",
          max_tokens=1024,
          output_format=APIResponse,
          messages=[{"role": "user", "content": "Process this request: ..."}],
      )

      print(response.parsed_output)
      ```

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

      const client = new Anthropic();

      const APIResponseSchema = z.object({
        status: z.string(),
        data: z.record(z.string(), z.any()),
        errors: z.array(z.record(z.string(), z.any())).optional(),
        metadata: z.record(z.string(), z.any())
      });

      const response = await client.messages.parse({
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: { format: zodOutputFormat(APIResponseSchema) },
        messages: [{ role: "user", content: "Process this request..." }]
      });

      console.log(response.parsed_output);
      ```

      ```csharp C#
      var parameters = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Messages = [new() { Role = Role.User, Content = "Process this request: ..." }],
          OutputConfig = new OutputConfig
          {
              Format = new JsonOutputFormat
              {
                  Schema = new Dictionary<string, JsonElement>
                  {
                      ["type"] = JsonSerializer.SerializeToElement("object"),
                      ["properties"] = JsonSerializer.SerializeToElement(new
                      {
                          status = new { type = "string" },
                          data = new { type = "object", additionalProperties = false },
                          errors = new
                          {
                              type = "array",
                              items = new { type = "object", additionalProperties = false },
                          },
                          metadata = new { type = "object", additionalProperties = false },
                      }),
                      ["required"] = JsonSerializer.SerializeToElement(new[] { "status", "data", "metadata" }),
                      ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
                  },
              },
          },
      };

      var message = await client.Messages.Create(parameters);
      Console.WriteLine(message);
      ```

      ```go Go
      client := anthropic.NewClient()

      response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 1024,
      	OutputConfig: anthropic.OutputConfigParam{
      		Format: anthropic.JSONOutputFormatParam{
      			Schema: map[string]any{
      				"type":                 "object",
      				"additionalProperties": false,
      				"properties": map[string]any{
      					"status": map[string]any{
      						"type": "string",
      					},
      					"data": map[string]any{
      						"type":                 "object",
      						"additionalProperties": false,
      					},
      					"errors": map[string]any{
      						"type": "array",
      						"items": map[string]any{
      							"type":                 "object",
      							"additionalProperties": false,
      						},
      					},
      					"metadata": map[string]any{
      						"type":                 "object",
      						"additionalProperties": false,
      					},
      				},
      				"required": []string{"status", "data", "metadata"},
      			},
      		},
      	},
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock("Process this request: ...")),
      	},
      })
      if err != nil {
      	log.Fatal(err)
      }
      for _, block := range response.Content {
      	switch variant := block.AsAny().(type) {
      	case anthropic.TextBlock:
      		fmt.Println(variant.Text)
      	}
      }
      ```

      ```java Java
      import com.fasterxml.jackson.annotation.JsonProperty;

      static class APIData {
          @JsonProperty("message")
          public String message;

          @JsonProperty("resource_id")
          public String resourceId;
      }

      static class APIError {
          @JsonProperty("code")
          public String code;

          @JsonProperty("message")
          public String message;
      }

      static class APIMetadata {
          @JsonProperty("request_id")
          public String requestId;

          @JsonProperty("timestamp")
          public String timestamp;
      }

      static class APIResponse {
          @JsonProperty("status")
          public String status;

          @JsonProperty("data")
          public APIData data;

          @JsonProperty("errors")
          public List<APIError> errors;

          @JsonProperty("metadata")
          public APIMetadata metadata;
      }

      void main() {
          AnthropicClient client = AnthropicOkHttpClient.fromEnv();

          StructuredMessageCreateParams<APIResponse> params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024L)
              .outputConfig(APIResponse.class)
              .addUserMessage("Process this request: ...")
              .build();

          StructuredMessage<APIResponse> response = client.messages().create(params);
          APIResponse result = response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst().orElseThrow().text();
          IO.println(result.status);
      }
      ```

      ```php PHP
      use Anthropic\Lib\Attributes\Constrained;
      use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
      use Anthropic\Lib\Contracts\StructuredOutputModel;

      $client = new Client();

      class Payload implements StructuredOutputModel { use StructuredOutputModelTrait; public string $message; }

      class APIError implements StructuredOutputModel { use StructuredOutputModelTrait; public string $code; public string $detail; }

      class Metadata implements StructuredOutputModel { use StructuredOutputModelTrait; public string $request_id; }

      class APIResponse implements StructuredOutputModel
      {
          use StructuredOutputModelTrait;

          public string $status;
          public Payload $data;
          #[Constrained(itemClass: APIError::class)]
          public ?array $errors;
          public Metadata $metadata;
      }

      $message = $client->messages->create(
          maxTokens: 1024,
          messages: [
              ['role' => 'user', 'content' => 'Process this request: ...']
          ],
          model: 'claude-opus-5-5',
          outputConfig: ['format' => APIResponse::class],
      );

      $result = $message->parsedOutput();
      if ($result instanceof APIResponse) {
          echo "{$result->status}: {$result->data->message}\n";
      }
      ```

      ```ruby Ruby
      client = Anthropic::Client.new

      class Payload < Anthropic::BaseModel
        required :message, String
      end

      class APIError < Anthropic::BaseModel
        required :code, String
        required :detail, String
      end

      class Metadata < Anthropic::BaseModel
        required :request_id, String
      end

      class APIResponse < Anthropic::BaseModel
        required :status, String
        required :data, Payload
        optional :errors, Anthropic::ArrayOf[APIError]
        required :metadata, Metadata
      end

      message = client.messages.create(
        model: "claude-opus-5-5",
        max_tokens: 1024,
        output_config: {format: APIResponse},
        messages: [
          {role: "user", content: "Process this request: ..."}
        ]
      )
      puts message.parsed_output
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

## Строгое использование инструментов

Чтобы обеспечить соответствие входных данных инструментов JSON Schema с помощью сэмплирования, ограниченного грамматикой, см. [Строгое использование инструментов](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/strict-tool-use).

### Совместное использование обеих функций

Выходные данные JSON и строгое использование инструментов решают разные задачи и работают вместе:

* **Выходные данные JSON** управляют форматом ответа Claude (что говорит Claude)
* **Строгое использование инструментов** валидирует параметры инструментов (как Claude вызывает ваши функции)

В сочетании Claude может вызывать инструменты с гарантированно валидными параметрами И возвращать структурированные ответы JSON. Это полезно для агентных рабочих процессов, где вам нужны и надёжные вызовы инструментов, и структурированные итоговые выходные данные.

<CodeGroup>
  ```bash cURL
  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": "Help me plan a trip to Paris departing May 15, 2026"
        }
      ],
      "output_config": {
        "format": {
          "type": "json_schema",
          "schema": {
            "type": "object",
            "properties": {
              "summary": {"type": "string"},
              "next_steps": {"type": "array", "items": {"type": "string"}}
            },
            "required": ["summary", "next_steps"],
            "additionalProperties": false
          }
        }
      },
      "tools": [
        {
          "name": "search_flights",
          "strict": true,
          "input_schema": {
            "type": "object",
            "properties": {
              "destination": {"type": "string"},
              "date": {"type": "string", "format": "date"}
            },
            "required": ["destination", "date"],
            "additionalProperties": false
          }
        }
      ]
    }'
  ```

  ```bash CLI
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  messages:
    - role: user
      content: Help me plan a trip to Paris departing May 15, 2026
  # Выходные данные JSON: структурированный формат ответа
  output_config:
    format:
      type: json_schema
      schema:
        type: object
        properties:
          summary:
            type: string
          next_steps:
            type: array
            items:
              type: string
        required: [summary, next_steps]
        additionalProperties: false
  # Строгое использование инструментов: гарантированные параметры инструментов
  tools:
    - name: search_flights
      strict: true
      input_schema:
        type: object
        properties:
          destination:
            type: string
          date:
            type: string
            format: date
        required: [destination, date]
        additionalProperties: false
  YAML
  ```

  ```python Python
  response = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[
          {
              "role": "user",
              "content": "Help me plan a trip to Paris departing May 15, 2026",
          }
      ],
      # JSON outputs (выходные данные JSON): структурированный формат ответа
      output_config={
          "format": {
              "type": "json_schema",
              "schema": {
                  "type": "object",
                  "properties": {
                      "summary": {"type": "string"},
                      "next_steps": {"type": "array", "items": {"type": "string"}},
                  },
                  "required": ["summary", "next_steps"],
                  "additionalProperties": False,
              },
          }
      },
      # Strict tool use (строгое использование инструментов): гарантированные параметры инструментов
      tools=[
          {
              "name": "search_flights",
              "strict": True,
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "destination": {"type": "string"},
                      "date": {"type": "string", "format": "date"},
                  },
                  "required": ["destination", "date"],
                  "additionalProperties": False,
              },
          }
      ],
  )

  print(response)
  ```

  ```typescript TypeScript
  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Help me plan a trip to Paris departing May 15, 2026" }],
    // Выходные данные JSON: структурированный формат ответа
    output_config: {
      format: {
        type: "json_schema",
        schema: {
          type: "object",
          properties: {
            summary: { type: "string" },
            next_steps: { type: "array", items: { type: "string" } }
          },
          required: ["summary", "next_steps"],
          additionalProperties: false
        }
      }
    },
    // Строгое использование инструментов: гарантированные параметры инструментов
    tools: [
      {
        name: "search_flights",
        description: "Search for available flights to a destination on a specific date",
        strict: true,
        input_schema: {
          type: "object",
          properties: {
            destination: { type: "string" },
            date: { type: "string", format: "date" }
          },
          required: ["destination", "date"],
          additionalProperties: false
        }
      }
    ]
  });

  // Claude может сначала вызвать инструмент (tool_use) или ответить в формате JSON (text)
  console.log("Stop reason:", response.stop_reason);
  for (const block of response.content) {
    switch (block.type) {
      case "tool_use":
        console.log(`Tool call: ${block.name}(${JSON.stringify(block.input)})`);
        break;
      case "text":
        console.log("Response:", block.text);
        break;
    }
  }
  ```

  ```csharp C#
  var parameters = new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [new() { Role = Role.User, Content = "Help me plan a trip to Paris departing May 15, 2026" }],
      // JSON outputs (выходные данные JSON): структурированный формат ответа
      OutputConfig = new OutputConfig
      {
          Format = new JsonOutputFormat
          {
              Schema = new Dictionary<string, JsonElement>
              {
                  ["type"] = JsonSerializer.SerializeToElement("object"),
                  ["properties"] = JsonSerializer.SerializeToElement(new
                  {
                      summary = new { type = "string" },
                      next_steps = new { type = "array", items = new { type = "string" } },
                  }),
                  ["required"] = JsonSerializer.SerializeToElement(new[] { "summary", "next_steps" }),
                  ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
              },
          },
      },
      // Strict tool use (строгое использование инструментов): гарантированные параметры инструментов
      Tools =
      [
          new Tool
          {
              Name = "search_flights",
              Strict = true,
              InputSchema = new InputSchema(new Dictionary<string, JsonElement>
              {
                  ["properties"] = JsonSerializer.SerializeToElement(new Dictionary<string, object>
                  {
                      ["destination"] = new { type = "string" },
                      ["date"] = new { type = "string", format = "date" },
                  }),
                  ["required"] = JsonSerializer.SerializeToElement(new[] { "destination", "date" }),
                  ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
              }),
          }
      ],
  };

  var message = await client.Messages.Create(parameters);
  Console.WriteLine(message);
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Help me plan a trip to Paris departing May 15, 2026")),
  	},
  	// Вывод в формате JSON: структурированный формат ответа
  	OutputConfig: anthropic.OutputConfigParam{
  		Format: anthropic.JSONOutputFormatParam{
  			Schema: map[string]any{
  				"type":                 "object",
  				"additionalProperties": false,
  				"properties": map[string]any{
  					"summary":    map[string]any{"type": "string"},
  					"next_steps": map[string]any{"type": "array", "items": map[string]any{"type": "string"}},
  				},
  				"required": []string{"summary", "next_steps"},
  			},
  		},
  	},
  	// Строгое использование инструментов: гарантированные параметры инструментов
  	Tools: []anthropic.ToolUnionParam{
  		{OfTool: &anthropic.ToolParam{
  			Name:   "search_flights",
  			Strict: anthropic.Bool(true),
  			InputSchema: anthropic.ToolInputSchemaParam{
  				Properties: map[string]any{
  					"destination": map[string]any{"type": "string"},
  					"date":        map[string]any{"type": "string", "format": "date"},
  				},
  				Required: []string{"destination", "date"},
  				ExtraFields: map[string]any{
  					"additionalProperties": false,
  				},
  			}}},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response.Content)
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  // Выходные данные JSON: структурированный формат ответа
  JsonOutputFormat.Schema outputSchema = JsonOutputFormat.Schema.builder()
      .putAdditionalProperty("type", JsonValue.from("object"))
      .putAdditionalProperty("properties", JsonValue.from(Map.of(
          "summary", Map.of("type", "string"),
          "next_steps", Map.of("type", "array", "items", Map.of("type", "string"))
      )))
      .putAdditionalProperty("required", JsonValue.from(List.of("summary", "next_steps")))
      .putAdditionalProperty("additionalProperties", JsonValue.from(false))
      .build();

  // Строгое использование инструментов: гарантированные параметры инструментов
  InputSchema toolSchema = InputSchema.builder()
      .properties(JsonValue.from(Map.of(
          "destination", Map.of("type", "string"),
          "date", Map.of("type", "string", "format", "date")
      )))
      .putAdditionalProperty("required", JsonValue.from(List.of("destination", "date")))
      .putAdditionalProperty("additionalProperties", JsonValue.from(false))
      .build();

  MessageCreateParams params = MessageCreateParams.builder()
      .model(Model.CLAUDE_OPUS_5_5)
      .maxTokens(1024L)
      .addUserMessage("Help me plan a trip to Paris departing May 15, 2026")
      .outputConfig(OutputConfig.builder()
          .format(JsonOutputFormat.builder().schema(outputSchema).build())
          .build())
      .addTool(Tool.builder()
          .name("search_flights")
          .description("Search for available flights to a destination on a specific date")
          .strict(true)
          .inputSchema(toolSchema)
          .build())
      .build();

  Message response = client.messages().create(params);
  IO.println(response);
  ```

  ```php PHP
  use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
  use Anthropic\Lib\Contracts\StructuredOutputModel;
  use Anthropic\Messages\ToolUseBlock;

  $client = new Client();

  class TripPlan implements StructuredOutputModel
  {
      use StructuredOutputModelTrait;

      public string $summary;
      public array $next_steps;
  }

  $message = $client->messages->create(
      maxTokens: 1024,
      messages: [
          ['role' => 'user', 'content' => 'Help me plan a trip to Paris departing May 15, 2026']
      ],
      model: 'claude-opus-5-5',
      // Выходные данные JSON: структурированный формат ответа
      outputConfig: ['format' => TripPlan::class],
      // Строгое использование инструментов: гарантированные параметры инструментов
      tools: [
          [
              'name' => 'search_flights',
              'strict' => true,
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'destination' => ['type' => 'string'],
                      'date' => ['type' => 'string', 'format' => 'date']
                  ],
                  'required' => ['destination', 'date'],
                  'additionalProperties' => false
              ]
          ]
      ],
  );

  // Claude может сначала вызвать инструмент (tool_use) или ответить в формате JSON (text)
  $plan = $message->parsedOutput();
  if ($plan instanceof TripPlan) {
      echo $plan->summary, "\n";
  } elseif ($toolUse = array_find($message->content, fn($block) => $block instanceof ToolUseBlock)) {
      echo "Tool call: {$toolUse->name}(", json_encode($toolUse->input), ")\n";
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [
      {role: "user", content: "Help me plan a trip to Paris departing May 15, 2026"}
    ],
    # JSON outputs (выходные данные JSON): структурированный формат ответа
    output_config: {
      format: {
        type: :json_schema,
        schema: {
          type: "object",
          properties: {
            summary: {type: "string"},
            next_steps: {type: "array", items: {type: "string"}}
          },
          required: ["summary", "next_steps"],
          additionalProperties: false
        }
      }
    },
    # Strict tool use (строгое использование инструментов): гарантированные параметры инструментов
    tools: [
      {
        name: "search_flights",
        strict: true,
        input_schema: {
          type: "object",
          properties: {
            destination: {type: "string"},
            date: {type: "string", format: "date"}
          },
          required: ["destination", "date"],
          additionalProperties: false
        }
      }
    ]
  )
  puts message
  ```
</CodeGroup>

## Важные соображения

### Компиляция и кэширование грамматик

Структурированные выходные данные используют ограниченное сэмплирование со скомпилированными артефактами грамматик. Это вносит некоторые особенности производительности, о которых следует знать:

* **Задержка первого запроса:** при первом использовании конкретной схемы возникает дополнительная задержка, пока грамматика компилируется

* **Автоматическое кэширование:** скомпилированные грамматики кэшируются на 24 часа с момента последнего использования, что делает последующие запросы значительно быстрее

* **Инвалидация кэша:** кэш инвалидируется, если вы изменяете:

  * Структуру схемы JSON
  * Набор инструментов в вашем запросе (при совместном использовании структурированных выходных данных и использования инструментов)
  * Изменение только полей `name` или `description` не инвалидирует кэш

### Модификация подсказки и стоимость токенов

При использовании структурированных выходных данных Claude автоматически получает дополнительную «system prompt» (системную подсказку), объясняющую ожидаемый формат вывода. Это означает:

* Количество ваших входных токенов немного выше
* Внедрённая подсказка стоит вам токенов, как и любая другая системная подсказка
* Изменение параметра `output_config.format` инвалидирует любой [кэш подсказок](https://platform.claude.com/docs/ru/build-with-claude/prompt-caching) для этой ветки разговора

### Ограничения JSON Schema

Структурированные выходные данные поддерживают стандартную JSON Schema с некоторыми ограничениями. Эти ограничения общие как для выходных данных JSON, так и для строгого использования инструментов.

<Accordion title="Поддерживаемые возможности">
  * Все базовые типы: object, array, string, integer, number, boolean, null
  * `enum` (только строки, числа, логические значения или null — без сложных типов). Об оговорке относительно регистра см. [Невалидные выходные данные](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#invalid-outputs).
  * `const`
  * `anyOf` и `allOf` (с ограничениями — `allOf` с `$ref` не поддерживается)
  * `$ref`, `$def` и `definitions` (внешние `$ref` не поддерживаются)
  * Свойство `default` для всех поддерживаемых типов
  * `required` и `additionalProperties` (должно быть установлено в `false` для объектов)
  * Строковые форматы: `date-time`, `time`, `date`, `duration`, `email`, `hostname`, `uri`, `ipv4`, `ipv6`, `uuid`
  * `minItems` для массивов (поддерживаются только значения 0 и 1)
</Accordion>

<Accordion title="Не поддерживается">
  * Рекурсивные схемы
  * Сложные типы внутри перечислений
  * Внешние `$ref` (например, `'$ref': 'http://...'`)
  * Числовые ограничения (такие как `minimum`, `maximum`, `multipleOf`)
  * Строковые ограничения (`minLength`, `maxLength`)
  * Ограничения массивов, кроме `minItems` со значением 0 или 1
  * `additionalProperties`, установленное в любое значение, кроме `false`

  Если вы используете неподдерживаемую возможность, вы получите ошибку 400 с подробностями.
</Accordion>

<Accordion title="Поддержка паттернов (regex)">
  **Поддерживаемые возможности regex:**

  * Полное совпадение (`^...$`) и частичное совпадение
  * Квантификаторы: `*`, `+`, `?`, простые случаи `{n,m}`
  * Классы символов: `[]`, `.`, `\d`, `\w`, `\s`
  * Группы: `(...)`

  **НЕ поддерживается:**

  * Обратные ссылки на группы (например, `\1`, `\2`)
  * Опережающие/ретроспективные проверки (например, `(?=...)`, `(?!...)`)
  * Границы слов: `\b`, `\B`
  * Сложные квантификаторы `{n,m}` с большими диапазонами

  Простые паттерны regex работают хорошо. Сложные паттерны могут приводить к ошибкам 400.
</Accordion>

<Tip>
  Вспомогательные функции SDK могут преобразовывать схемы с [ограничениями, не поддерживаемыми API](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#json-schema-limitations). См. [Как работает преобразование в SDK](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#how-sdk-transformation-works).
</Tip>

### Порядок свойств

При использовании структурированных выходных данных свойства в объектах сохраняют порядок, определённый в вашей схеме, с одной важной оговоркой: **обязательные свойства идут первыми, за ними следуют необязательные свойства**.

Например, для такой схемы:

```json
{
  "type": "object",
  "properties": {
    "notes": { "type": "string" },
    "name": { "type": "string" },
    "email": { "type": "string" },
    "age": { "type": "integer" }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}
```

Вывод упорядочит свойства так:

1. `name` (обязательное, в порядке схемы)
2. `email` (обязательное, в порядке схемы)
3. `notes` (необязательное, в порядке схемы)
4. `age` (необязательное, в порядке схемы)

Это означает, что вывод может выглядеть так:

```json
{
  "name": "John Smith",
  "email": "john@example.com",
  "notes": "Interested in enterprise plan",
  "age": 35
}
```

Если порядок свойств в выводе важен для вашего приложения, пометьте все свойства как обязательные или учтите это переупорядочивание в вашей логике разбора.

### Невалидные выходные данные

Хотя структурированные выходные данные гарантируют соответствие схеме в большинстве случаев, существуют сценарии, в которых вывод может не соответствовать вашей схеме:

**Отказы** (`stop_reason: "refusal"`)

Claude сохраняет свои свойства безопасности и полезности даже при использовании структурированных выходных данных. Если Claude отказывается выполнить запрос по соображениям безопасности:

* Ответ имеет `stop_reason: "refusal"`
* Вы получите код состояния 200
* Вам будет выставлен счёт за сгенерированные токены
* Вывод может не соответствовать вашей схеме, поскольку сообщение об отказе имеет приоритет над ограничениями схемы

Свойство, запрашивающее размышления модели или пошаговые рассуждения, может привести к отказу `reasoning_extraction`. Вместо этого запросите краткое объяснение. См. [Храните рассуждения в блоках размышлений](https://platform.claude.com/docs/ru/build-with-claude/refusals-and-fallback#keep-reasoning-in-thinking-blocks).

**Достигнут лимит токенов** (`stop_reason: "max_tokens"`)

Если ответ обрезан из-за достижения лимита `max_tokens`:

* Ответ имеет `stop_reason: "max_tokens"`
* Вывод может быть неполным и не соответствовать вашей схеме
* Повторите запрос с более высоким значением `max_tokens`, чтобы получить полные структурированные выходные данные

**Регистр значений перечислений**

Структурированные выходные данные не гарантируют регистр букв строковых значений `enum` и `const`: Claude может вернуть значение, отличающееся от вашей схемы только регистром, обычно в первой букве слова, следующего за пробелом. Например, для такой схемы:

```json
{
  "type": "string",
  "enum": ["Conversation Topic 1", "Conversation Topic 2", "Conversation topic 3"]
}
```

Вывод может содержать `"Conversation Topic 3"` (заглавная «T»), хотя именно такого значения нет в перечислении. Ответ завершается нормально, без ошибки и без специального `stop_reason`. Это относится как к выходным данным JSON, так и к строгому использованию инструментов. Сравнивайте значения перечислений без учёта регистра и избегайте значений перечислений, отличающихся только регистром.

### Лимиты сложности схем

Структурированные выходные данные работают путём компиляции ваших схем JSON в грамматику, ограничивающую вывод Claude. Более сложные схемы дают более крупные грамматики, компиляция которых занимает больше времени. Для защиты от чрезмерного времени компиляции API применяет несколько лимитов сложности.

#### Явные лимиты

Следующие лимиты применяются ко всем запросам с `output_config.format` или `strict: true`:

| Лимит                             | Значение | Описание                                                                                                                                                                                                              |
| --------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Строгих инструментов на запрос    | 20       | Максимальное количество инструментов с `strict: true`. Нестрогие инструменты не учитываются в этом лимите.                                                                                                            |
| Необязательных параметров         | 24       | Общее количество необязательных параметров во всех схемах строгих инструментов и схемах выходных данных JSON. Каждый параметр, не указанный в `required`, учитывается в этом лимите.                                  |
| Параметров с типами-объединениями | 16       | Общее количество параметров, использующих `anyOf` или массивы типов (например, `"type": ["string", "null"]`), во всех строгих схемах. Они особенно затратны, поскольку создают экспоненциальную стоимость компиляции. |

<Note>
  Эти лимиты применяются к совокупному итогу по всем строгим схемам в одном запросе. Например, если у вас 4 строгих инструмента с 6 необязательными параметрами каждый, вы достигнете лимита в 24 параметра, хотя ни один отдельный инструмент не кажется сложным.
</Note>

#### Дополнительные внутренние лимиты

Помимо явных лимитов в предыдущей таблице, существуют дополнительные внутренние лимиты на размер скомпилированной грамматики. Эти лимиты существуют потому, что сложность схемы не сводится к одному измерению: такие возможности, как необязательные параметры, типы-объединения, вложенные объекты и количество инструментов, взаимодействуют друг с другом так, что скомпилированная грамматика может стать непропорционально большой.

При превышении этих лимитов вы получите ошибку 400 с сообщением «Schema is too complex for compilation.» Эти ошибки означают, что совокупная сложность ваших схем превышает то, что можно эффективно скомпилировать, даже если каждый отдельный лимит в предыдущей таблице соблюдён. В качестве последней меры API также применяет **тайм-аут компиляции в 180 секунд**. Схемы, проходящие все явные проверки, но дающие очень большие скомпилированные грамматики, могут упереться в этот тайм-аут.

#### Советы по снижению сложности схем

Если вы упираетесь в лимиты сложности, попробуйте эти стратегии по порядку:

1. **Помечайте как строгие только критически важные инструменты.** Если у вас много инструментов, оставьте строгий режим для инструментов, где нарушения схемы вызывают реальные проблемы, и полагайтесь на естественное следование Claude схеме для более простых инструментов.

2. **Сократите количество необязательных параметров.** Делайте параметры `required`, где это возможно. Каждый необязательный параметр примерно удваивает часть пространства состояний грамматики. Если у параметра всегда есть разумное значение по умолчанию, рассмотрите возможность сделать его обязательным и поручить Claude явно указывать это значение по умолчанию.

3. **Упростите вложенные структуры.** Глубоко вложенные объекты с необязательными полями усугубляют сложность. Делайте структуры плоскими, где это возможно.

4. **Разделите на несколько запросов.** Если у вас много строгих инструментов, рассмотрите возможность распределить их по отдельным запросам или субагентам.

При постоянных проблемах с валидными схемами [обратитесь в поддержку](https://support.claude.com/en/articles/9015913-how-to-get-support), приложив определение вашей схемы.

## Переход с бета-версии

Параметр `output_format` перемещён в `output_config.format`, и бета-заголовки больше не требуются. Параметр `output_format` устарел и будет удалён в будущем. Чтобы всё же использовать его, добавьте бета-заголовок `structured-outputs-2025-11-13`. Без него API возвращает ошибку 400.

Python SDK (v1.0 и более поздние версии) не принимает `output_format={...}` в `client.beta.messages.create()` или `count_tokens()` и выдаёт `TypeError`. Вместо этого используйте `output_config`. Обновлённую форму API см. в разделе [Использование необработанной JSON-схемы](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#using-a-raw-json-schema).

## Хранение данных

Подсказки и ответы обрабатываются с ZDR при использовании структурированных выходных данных. Однако сама схема JSON временно кэшируется на срок до 24 часов с момента последнего использования в целях оптимизации. Никакие данные подсказок или ответов не сохраняются после ответа API.

Структурированные выходные данные соответствуют требованиям HIPAA, но **PHI не должна включаться в определения схем JSON**. API компилирует схемы JSON в грамматики, которые кэшируются отдельно от содержимого сообщений, и эти кэшированные схемы не получают той же защиты PHI, что подсказки и ответы. Не включайте PHI в имена свойств схемы, значения `enum`, значения `const` или регулярные выражения `pattern`. PHI должна появляться только в содержимом сообщений (подсказках и ответах), где она защищена мерами безопасности HIPAA.

О соответствии требованиям ZDR и HIPAA для всех функций см. [API и хранение данных](https://platform.claude.com/docs/ru/manage-claude/api-and-data-retention).

## Совместимость функций

**Работает с:**

* **[Пакетная обработка](https://platform.claude.com/docs/ru/build-with-claude/batch-processing):** обрабатывайте структурированные выходные данные в масштабе со скидкой 50%
* **[Подсчёт токенов](https://platform.claude.com/docs/ru/build-with-claude/token-counting):** подсчитывайте токены без компиляции
* **[Потоковая передача](https://platform.claude.com/docs/ru/build-with-claude/streaming):** передавайте структурированные выходные данные потоком, как обычные ответы
* **[Совместное использование](https://platform.claude.com/docs/ru/build-with-claude/structured-outputs#using-both-features-together):** используйте выходные данные JSON (`output_config.format`) и строгое использование инструментов (`strict: true`) вместе в одном запросе

**Несовместимо с:**

* **[Цитирование](https://platform.claude.com/docs/ru/build-with-claude/citations):** цитирование требует чередования блоков цитат с текстом, что конфликтует со строгими ограничениями схемы JSON. Возвращает ошибку 400, если цитирование включено вместе с `output_config.format`.
* **Предзаполнение сообщений:** несовместимо с выходными данными JSON

<Tip>
  **Область действия грамматики:** грамматики применяются только к прямому выводу Claude, а не к вызовам использования инструментов, результатам инструментов или тегам размышлений (при использовании [размышлений](https://platform.claude.com/docs/ru/build-with-claude/thinking)). Состояние грамматики сбрасывается между секциями, позволяя Claude свободно размышлять, при этом по-прежнему выдавая структурированные выходные данные в итоговом ответе.
</Tip>

## Следующие шаги

<CardGroup cols={2}>
  <Card title="Цитирование" icon="book-bookmark" href="https://platform.claude.com/docs/ru/build-with-claude/citations">
    Поручите Claude ссылаться на источники при ответах на вопросы о предоставленных документах.
  </Card>

  <Card title="Строгое использование инструментов" icon="check" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/strict-tool-use">
    Обеспечьте соответствие входных данных инструментов Claude JSON Schema с помощью сэмплирования, ограниченного грамматикой.
  </Card>

  <Card title="Использование инструментов с Claude" icon="wrench" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/overview">
    Подключите Claude к внешним инструментам и API. Узнайте, где выполняются инструменты и как работает агентный цикл.
  </Card>

  <Card title="Цены" icon="calculator" href="https://platform.claude.com/docs/ru/about-claude/pricing">
    Узнайте о структуре цен Anthropic на модели и функции.
  </Card>
</CardGroup>
