Руководство разработчика по созданию идеального JSON и типизированных выходных данных от Claude Sonnet 4.5 и Opus 4.1
Делиться

Компания Anthropic недавно анонсировала структурированные выходные данные для своих ведущих моделей в своем API. Это новая функция, призванная гарантировать, что выходные данные, сгенерированные моделью, точно соответствуют схемам JSON, предоставленным разработчиками.
Это решает проблему, с которой сталкиваются многие разработчики, когда система или процесс используют выходные данные LLM для дальнейшей обработки. Важно, чтобы эта система «знала», чего ожидать от входных данных, чтобы иметь возможность обработать их соответствующим образом.
Аналогично, при отображении выходных данных модели пользователю необходимо, чтобы они каждый раз имели один и тот же формат.
До сих пор было сложно обеспечить единообразие форматов вывода данных для моделей Anthropic. Однако, похоже, Anthropic уже решила эту проблему для своих топовых моделей. В их заявлении (ссылка на которое приведена в конце статьи) говорится:
Платформа разработчика Claude теперь поддерживает структурированные выходные данные для Claude Sonnet 4.5 и Opus 4.1. Эта функция, доступная в публичной бета-версии, гарантирует, что ответы API всегда соответствуют указанным вами схемам JSON или определениям инструментов.
Прежде чем мы рассмотрим примеры кода, следует помнить, что Anthropic гарантирует, что выходные данные модели будут соответствовать заданному формату, но не гарантирует 100% точность любых выходных данных. Модели могут иногда давать сбои.
Поэтому вы можете получить идеально отформатированные неверные ответы!
Настройка среды разработки
Прежде чем рассматривать примеры кода на Python, рекомендуется создать отдельную среду разработки, где можно установить необходимое программное обеспечение и экспериментировать с кодом. Теперь всё, что вы делаете в этой среде, будет изолировано и не повлияет на другие ваши проекты.
Я буду использовать для этого Miniconda, но вы можете использовать любой другой метод, с которым вы лучше всего знакомы.
Если вы хотите использовать Miniconda и у вас её ещё нет, сначала установите. Скачать можно по этой ссылке:
https://docs.anaconda.com/miniconda/
Чтобы следовать моим примерам, вам также понадобится ключ API Anthropic и средства на вашем счёте. Для справки: запуск кода из этой статьи обошелся мне в 12 центов. Если у вас уже есть учётная запись Anthropic, вы можете получить ключ API через консоль Anthropic по адресу https://console.anthropic.com/settings/keys.
1/ Создаём новую среду разработки и устанавливаем необходимые библиотеки.
Я использую это на WSL2 Ubuntu для Windows.
(база) $ conda create -n anth_test python=3.13 -y (база) $ conda activate anth_test (anth_test) $ pip install anthropic beautifulsoup4 requests (anth_test) $ pip install httpx jupyter
2/ Запустить Jupyter
Теперь введите «jupyter notebook» в командной строке. В браузере должен открыться Jupyter Notebook. Если это не произойдёт автоматически, после команды вы, вероятно, увидите экран с информацией. Внизу вы найдёте URL-адрес, который нужно скопировать и вставить в браузер. Он будет выглядеть примерно так:
http://127.0.0.1:8888/tree?token=3b9f7bd07b6966b41b68e2350721b2d0b6f388d248cc69
Примеры кода
В наших двух примерах кодирования мы будем использовать новый параметр output_format, доступный в бета-версии API. При указании структурированного вывода мы можем использовать два разных стиля.
1. Необработанная схема JSON.
Как следует из названия, структура определяется блоком схемы JSON, который передается непосредственно в определение выходного формата.
2. Класс пидантической модели.
Это обычный класс Python, использующий BaseModel от Pydantic, который определяет данные, которые должна выводить модель. Это гораздо более компактный способ определения структуры, чем схема JSON.
Пример кода 1 — Резюмирование текста
Это полезно, если вам нужно реферировать несколько разных текстов, но при этом важно, чтобы рефераты имели одинаковую структуру. В этом примере мы обработаем статьи Википедии о некоторых известных учёных и извлечём ключевые факты о них в высокоорганизованном виде.
В нашем резюме мы хотим вывести следующую структуру для каждого ученого:
- Имя ученого
- Когда и где они родились
- Их главная претензия на славу
- Год, когда они получили Нобелевскую премию
- Когда и где они умерли
Примечание: Большая часть текста в Википедии, за исключением цитат, выпущена в соответствии с лицензией Creative Commons Attribution-Sharealike 4.0 International (CC-BY-SA) и лицензией GNU Free Documentation License (GFDL). Короче говоря, это означает, что вы свободны:
Поделиться — копировать и распространять материал на любом носителе или в любом формате
Адаптировать — перерабатывать, трансформировать и дополнять материал
для любых целей, даже коммерческих.
Давайте разобьем код на удобные для понимания разделы, каждый из которых будет снабжен пояснениями.
Сначала мы импортируем необходимые сторонние библиотеки и настраиваем соединения с Anthropic, используя наш API-ключ.
импорт антропогенный импорт httpx импорт запросов импорт json импорт os из bs4 импорт BeautifulSoup http_client = httpx.Client() api_key = 'YOUR_API_KEY' клиент = антропогенный.Антропогенный( api_key=api_key, http_client=http_client )
Это функция, которая будет извлекать данные из Википедии для нас.
def get_article_content(url): try: headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} response = requests.get(url, headers=headers) soup = BeautifulSoup(response.content, «html.parser») article = soup.find(«div», class_=»mw-body-content») if article: content = «n».join(p.text for p in article.find_all(«p»)) return content[:15000] else: return «» except Exception as e: print(f»Error scraping {url}: {e}») return «»
Далее мы определяем нашу схему JSON, которая задает точный формат выходных данных модели.
summary_schema = { «type»: «object», «properties»: { «name»: {«type»: «string», «description»: «Имя учёного»}, «born»: {«type»: «string», «description»: «Когда и где родился учёный»}, «fame»: {«type»: «string», «description»: «Краткое описание того, в чём заключается его главная слава»}, «prize»: {«type»: «integer», «description»: «Год получения Нобелевской премии. 0, если нет.»}, «death»: {«type»: «string», «description»: «Когда и где умер. 'Ещё жив', если жив.»} }, «required»: [«name», «born», «fame», «prize», «death»], «additionalProperties»: False }
Эта функция служит интерфейсом между нашим скриптом Python и антропогенным API. Её основная цель — получить неструктурированный текст (статью) и заставить ИИ вернуть структурированный объект данных (JSON), содержащий определённые поля, такие как имя учёного, дата рождения и информация о Нобелевской премии.
Функция вызывает client.messages.create для отправки запроса к модели. Она устанавливает температуру до 0,2, что снижает креативность модели, обеспечивая фактическую достоверность и точность извлекаемых данных. Параметр extra_headers включает специальную бета-функцию, которая пока не является стандартной. Передавая заголовок anthropic-beta со значением structured-outputs-2025-11-13, код сообщает API о необходимости активировать логику структурированных выходов для данного запроса, заставляя его генерировать корректный JSON-код, соответствующий заданной вами структуре.
Благодаря использованию параметра output_format модель возвращает необработанную строку, которая гарантированно является корректным JSON-форматом. Строка json.loads(response.content[0].text) преобразует эту строку в нативный словарь Python, делая данные сразу готовыми к программному использованию.
def get_article_summary(text: str): if not text: return None try: response = client.messages.create( model=»claude-sonnet-4-5″, # Использовать последнюю доступную модель max_tokens=1024, temperature=0.2, messages=[ {«role»: «user», «content»: f»Кратко о статье:nn{text}»} ], # Включить бета-функцию extra_headers={ «anthropic-beta»: «structured-outputs-2025-11-13» }, # Передайте сюда новый параметр extra_body={ «output_format»: { «type»: «json_schema», «schema»: summary_schema } } ) # API возвращает JSON непосредственно в текстовом содержимом return json.loads(response.content[0].text) except anthropic.BadRequestError as e: print(f»Ошибка API: {e}») возвращает None, за исключением Exception as e: print(f»Error: {e}») возвращает None
Здесь мы собираем всё воедино. Определяем различные URL-адреса, которые нужно собрать. Их содержимое передаётся в модель для обработки, прежде чем будут отображены конечные результаты.
urls = [ «https://en.wikipedia.org/wiki/Альберт_Эйнштейн», «https://en.wikipedia.org/wiki/Ричард_Фейнман», «https://en.wikipedia.org/wiki/Джеймс_Клерк_Максвелл», «https://en.wikipedia.org/wiki/Алан_Гут» ] print(«Извлечение и анализ статей…») for i, url in enumerate(urls): print(f»n— Обработка статьи {i+1} —«) content = get_article_content(url) if content: summary = get_article_summary(content) if summary: print(f»Ученый: {summary.get('name')}») print(f»Дата рождения: {summary.get('born')}») print(f»Известность: {summary.get('fame')}») print(f»Нобелевская премия: {summary.get('prize')}») print(f»Умер: {summary.get('death')}») else: print(«Не удалось создать сводку.») else: print(«Пропуск (нет контента)») print(«nГотово.»)
При запуске кода выше я получил такой результат.
Сбор и анализ статей… — Обработка статьи 1 — Ученый: Альберт Эйнштейн Родился: 14 марта 1879 г. в Ульме, Королевство Вюртемберг, Германская империя Известность: Разработка теории относительности и формулы эквивалентности массы и энергии E = mc², а также вклад в квантовую теорию, включая фотоэлектрический эффект Нобелевская премия: 1921 г. Умер: 18 апреля 1955 г. — Обработка статьи 2 — Ученый: Ричард Филлипс Фейнман Родился: 11 мая 1918 г. в Нью-Йорке Известность: Формулировка квантовой механики в виде интегралов по траекториям, квантовая электродинамика, диаграммы Фейнмана и вклад в физику элементарных частиц, включая партонную модель Нобелевская премия: 1965 г. Умер: 15 февраля 1988 г. — Обработка статьи 3 — Ученый: Джеймс Клерк Максвелл Родился: 13 июня 1831 г. в Эдинбурге, Шотландия Известность: Разработал классическую теорию электромагнитного излучения, объединив электричество, магнетизм и свет посредством уравнений Максвелла. Также внёс ключевой вклад в статистическую механику, теорию цвета и многие другие области физики и математики. Нобелевская премия: 0 Умер: 5 ноября 1879 г. — Обработка статьи 4 — Учёный: Алан Харви Гут Родился: 27 февраля 1947 г. в Нью-Брансуике, штат Нью-Джерси Слава: Основатель теории космической инфляции, предполагающей, что ранняя Вселенная претерпела фазу экспоненциального расширения под действием положительной плотности энергии вакуума. Нобелевская премия: 0 Умер: Ещё жив. Выполнено.
Неплохо! Алан Гут будет рад, что он ещё жив, но, увы, он пока не получил Нобелевскую премию. Кстати, Джеймс Клерк Максвелл умер ещё до того, как Нобелевская премия начала функционировать.
Пример кода 2 — Автоматизированный агент безопасности и рефакторинга кода .
Вот совершенно другой пример использования и весьма практичный для программной инженерии. Обычно, когда просишь LLM «исправить код», он получает ответ, состоящий из фрагментов кода. Это затрудняет интеграцию в конвейер CI/CD или плагин IDE.
Используя структурированные выходы, мы можем заставить модель возвращать чистый код , список конкретных найденных ошибок и оценку риска безопасности в одном машиночитаемом объекте JSON.
Сценарий
Мы передадим модели функцию Python, содержащую опасную уязвимость SQL-инъекции и примеры ненадлежащего программирования. Модель должна выявить конкретные уязвимости и переписать код безопасным способом.
import anthropic import httpx import os import json from pydantic import BaseModel, Field, ConfigDict from typing import List, Literal # — НАСТРОЙКА — http_client = httpx.Client() api_key = 'YOUR_API_KEY' client = anthropic.Anthropic(api_key=api_key, http_client=http_client) # Намеренно плохой код bad_code_snippet = «»» import sqlite3 def get_user(u): conn = sqlite3.connect('app.db') c = conn.cursor() # ОПАСНОСТЬ: Прямая конкатенация строк query = «SELECT * FROM users WHERE username = '» + u + «'» c.execute(query) return c.fetchall() «»» # — ОПРЕДЕЛЕНИЕ СХЕМЫ СО СТРОГОЙ КОНФИГУРАЦИЕЙ — # Добавляем model_config = ConfigDict(extra=»forbid») для обеспечения # «additionalProperties»: false генерируется в схеме. class BugReport(BaseModel): model_config = ConfigDict(extra=»forbid») intensity: Literal[«Low», «Medium», «High», «Critical»] line_number_approx: int = Field(description=»Примерный номер строки, в которой возникла проблема.») issue_type: str = Field(description=»Напр., 'Безопасность', 'Производительность', 'Стиль'») description: str = Field(description=»Краткое описание ошибки.») class CodeReviewResult(BaseModel): model_config = ConfigDict(extra=»forbid») is_safe_to_run: bool = Field(description=»True только при отсутствии критических/высоких угроз безопасности.») detect_bugs: List[BugReport] refactored_code: str = Field(description=»Полная исправленная строка кода Python.») explained: str = Field(description=»Краткое описание внесенных изменений.») # — ВЫЗОВ API — try: print(«Анализ кода на предмет уязвимостей…n») response = client.messages.create( model=»claude-sonnet-4-5″, max_tokens=2048, temperature=0.0, messages=[ { «role»: «user», «content»: f»Просмотрите и отреорганизуйте этот код Python:nn{bad_code_snippet}» } ], extra_headers={ «anthropic-beta»: «structured-outputs-2025-11-13» }, extra_body={ «output_format»: { «type»: «json_schema», «schema»: CodeReviewResult.model_json_schema() } } ) # Результат разбора result = json.loads(response.content[0].text) # — ОТОБРАЖЕНИЕ ВЫВОДА — print(f»Безопасно для запуска: {result['is_safe_to_run']}») print(«-» * 40) print(«ОБНАРУЖЕНЫ ОШИБКИ:») for bug in result['detected_bugs']: # Цветовой код серьезности (красный для критической) prefix = «🔴» if bug['severity'] in [«Critical», «High»] else «🟡» print(f»{prefix} [{bug['severity']}] Line {bug['line_number_approx']}: {bug['description']}») print(«-» * 40) print(«РЕФАКТОРИЗОВАННЫЙ КОД:») print(result['refactored_code']) except anthropic.BadRequestError as e: print(f»Ошибка схемы API: {e}») except Exception as e: print(f»Ошибка: {e}»)
Этот код действует как автоматизированный аудитор безопасности. Вместо того, чтобы просить ИИ «рассказывать» о коде, он заставляет его заполнять строгую цифровую форму, содержащую подробную информацию об ошибках и рисках безопасности.
Вот как это работает: три простых шага.
- Во-первых, код точно определяет, как должен выглядеть ответ, используя классы Python в сочетании с Pydantic. Он сообщает ИИ: «Предоставь мне JSON-объект, содержащий список ошибок, уровень серьёзности (например, «Критический» или «Низкий») для каждой ошибки и строку исправленного кода».
- При отправке уязвимого кода в API он передаёт схему Pydantic через параметр output_format. Это строго ограничивает модель, предотвращая её галлюцинации и добавление диалогового контента. Она должна возвращать корректные данные, соответствующие вашей схеме.
- Скрипт получает ответ ИИ, который гарантированно представляет собой машиночитаемый JSON-код. Затем он автоматически анализирует эти данные и выводит корректный отчёт, например, помечая SQL-инъекцию как «критическую» проблему и выводя безопасную, отрефакторенную версию кода.
Вот результат, который я получил после запуска кода.
Анализ кода на наличие уязвимостей… Безопасно для запуска: Ложь —————————————- ОБНАРУЖЕНЫ ОШИБКИ: 🔴 [Критический] Строка 7: Уязвимость SQL-инъекции из-за прямой конкатенации строк при построении запроса. Злоумышленник может внедрить вредоносный SQL-код через параметр имени пользователя. 🟡 [Средний] Строка 4: Подключение к базе данных и курсор не закрыты должным образом, что приводит к потенциальным утечкам ресурсов. 🟡 [Низкий] Строка 1: Имя параметра функции «u» не является описательным. Следует использовать осмысленные имена переменных. —————————————- РЕФАКТОРИЗОВАННЫЙ КОД: import sqlite3 from contextlib importclosure def get_user(username): «»» Извлечь информацию о пользователе из базы данных по имени пользователя. Аргументы: username (str): Имя пользователя для поиска Возвращает: list: Список кортежей, содержащих данные пользователя, или пустой список, если они не найдены «»» with sqlite3.connect('app.db') as conn: with close(conn.cursor()) as cursor: # Используйте параметризованный запрос для предотвращения SQL-инъекций query = «SELECT * FROM users WHERE username = ?» cursor.execute(query, (username,)) return cursor.fetchall()
Почему это так важно?
Готов к интеграции . Вы можете запустить этот скрипт в действии GitHub. Если is_safe_to_run равно False, вы можете автоматически заблокировать запрос на извлечение.
Разделение проблем . Вы получаете метаданные (ошибки, уровень серьёзности) отдельно от контента (кода). Вам не нужно использовать регулярные выражения, чтобы вырезать текст «Вот ваш исправленный код» из ответа.
Строгая типизация. Поле «Серьёзность» ограничено определёнными значениями Enum (критический, высокий и т. д.), что гарантирует отсутствие сбоев в работе логики, возникающих после ошибки, например, когда модель возвращает «Серьёзный» вместо «Критический».
Краткое содержание
Выпуск нативных структурированных выходных данных от Anthropic — это настоящий прорыв для разработчиков, которым важна надёжность, а не просто общение. Благодаря строгому соблюдению схем JSON мы теперь можем рассматривать большие языковые модели не как чат-ботов, а как детерминированные программные компоненты.
В этой статье я продемонстрировал, как использовать эту новую бета-функцию для оптимизации извлечения и вывода данных, а также для создания автоматизированных рабочих процессов, легко интегрируемых с кодом Python. Если вы используете API Anthropic, то дни написания ненадёжных регулярных выражений для анализа ответов ИИ наконец-то прошли.
Для получения дополнительной информации об этой новой бета-функции щелкните ссылку ниже, чтобы посетить официальную страницу документации Anthropics.
https://platform.claude.com/docs/en/build-with-claude/structured-outputs
Источник: towardsdatascience.com



























