Компания Anthropic представила функцию Structured Outputs для своих ведущих моделей в API. Эта возможность гарантирует, что результаты, генерируемые моделью, точно соответствуют предоставленным разработчиками JSON-схемам.
Такая функция решает распространенную задачу: когда система или процесс использует вывод от LLM для дальнейшей обработки, ей нужно четко понимать, какой формат данных ожидать, чтобы справиться с ними правильно.
Аналогично, при показе результатов модели пользователю важно, чтобы формат оставался единообразным каждый раз.
До сих пор добиться стабильного формата вывода от моделей Anthropic было непросто. Но теперь эта компания устранила проблему для своих основных моделей. Из их объявления следует, что платформа Claude Developer поддерживает структурированный вывод для Claude Sonnet 4.5 и Opus 4.1. Функция доступна в публичной бета-версии и обеспечивает соответствие ответов API указанным JSON-схемам или определениям инструментов.
Платформа Claude Developer теперь поддерживает структурированный вывод для Claude Sonnet 4.5 и Opus 4.1. Доступна в публичной бета-версии, эта функция гарантирует, что ответы API всегда соответствуют вашим JSON-схемам или определениям инструментов.
Перед рассмотрением примеров кода стоит напомнить: Anthropic обеспечивает соблюдение моделью заданного формата, но не полную точность содержимого. Модели все равно могут иногда выдавать неверные данные.
Получается идеально оформленные, но ошибочные ответы!
Подготовка среды разработки
Прежде чем разбирать примеры на Python, полезно создать изолированную среду разработки. В ней можно устанавливать нужное ПО и тестировать код, не затрагивая другие проекты.
Для этого подойдет Miniconda, хотя можно выбрать любой удобный инструмент.
Если решите использовать Miniconda и его еще нет, скачайте с официального сайта.
Чтобы повторить примеры, понадобится ключ API от Anthropic и средства на аккаунте. На выполнение кода в статье ушло около 12 центов. Если аккаунт уже есть, ключ можно получить в консоли Anthropic по адресу https://console.anthropic.com/settings/keys.
Создание среды и установка библиотек
Вот команды для WSL2 Ubuntu на Windows.
(base) $ conda create -n anth_test python=3.13 -y
(base) $ conda activate anth_test
(anth_test) $ pip install anthropic beautifulsoup4 requests
(anth_test) $ pip install httpx jupyterЗапуск Jupyter
Введите в терминале 'jupyter notebook'. В браузере откроется Jupyter Notebook. Если не запустится автоматически, в выводе команды найдите URL вроде http://127.0.0.1:8888/tree?token=3b9f7bd07b6966b41b68e2350721b2d0b6f388d248cc69 и вставьте его вручную.
Примеры кода
В двух примерах мы задействуем новый параметр output_format из бета-версии API. Для задания структурированного вывода доступны два подхода.
Первый — прямая JSON-схема. Здесь структура определяется блоком JSON-схемы, передаваемым в определение формата вывода.
Второй — класс модели Pydantic. Это обычный класс Python на базе BaseModel из Pydantic, который описывает желаемые данные. Такой метод компактнее, чем полная JSON-схема.
Пример 1: Суммаризация текста
Эта функция пригодится, если нужно суммировать разные тексты, но сохранить одинаковую структуру сводок. Мы возьмем статьи из Википедии о известных ученых и извлечем ключевые факты в организованном виде.
В сводке для каждого ученого требуется следующая информация:
- Имя ученого
- Дата и место рождения
- Основное достижение
- Год получения Нобелевской премии
- Дата и место смерти
Большинство текстов в Википедии, кроме цитат, распространяется под лицензией Creative Commons Attribution-Sharealike 4.0 International (CC-BY-SA) и GNU Free Documentation License (GFDL). Это позволяет свободно делиться материалом в любом формате или средстве, а также адаптировать его — перерабатывать, преобразовывать и строить на его основе, даже в коммерческих целях.
Разобьем код на части с пояснениями.
Сначала импортируем библиотеки и настраиваем связь с Anthropic через ключ API.
import anthropic
import httpx
import requests
import json
import os
from bs4 import BeautifulSoup
http_client = httpx.Client()
api_key = 'YOUR_API_KEY'
client = anthropic.Anthropic(
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": "The name of the Scientist"},
"born": {"type": "string", "description": "When and where the scientist was born"},
"fame": {"type": "string", "description": "A summary of what their main claim to fame is"},
"prize": {"type": "integer", "description": "The year they won the Nobel Prize. 0 if none."},
"death": {"type": "string", "description": "When and where they died. 'Still alive' if living."}
},
"required": ["name", "born", "fame", "prize", "death"],
"additionalProperties": False
}
Эта функция связывает скрипт Python с API Anthropic. Она берет неструктурированный текст статьи и заставляет ИИ вернуть структурированный JSON-объект с полями вроде имени ученого, даты рождения и деталей о Нобелевской премии.
Функция использует client.messages.create для отправки запроса модели. Температура 0.2 снижает креативность, чтобы данные были точными. Параметр extra_headers активирует бета-функцию через заголовок anthropic-beta со значением structured-outputs-2025-11-13, что включает логику Structured Outputs и обеспечивает валидный 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", # Use the latest available model
max_tokens=1024,
temperature=0.2,
messages=[
{
"role": "user",
"content": f"Summarize this article:\n\n{text}"
}
],
# Enable the beta feature
extra_headers={
"anthropic-beta": "structured-outputs-2025-11-13"
},
# Pass the new parameter here
extra_body={
"output_format": {
"type": "json_schema",
"schema": summary_schema
}
}
)
# The API returns the JSON directly in the text content
return json.loads(response.content[0].text)
except anthropic.BadRequestError as e:
print(f"API Error: {e}")
return None
except Exception as e:
print(f"Error: {e}")
return None
Здесь собираем все воедино. Указываем URL для парсинга, передаем контент модели и выводим результаты.
urls = [
"https://en.wikipedia.org/wiki/Albert_Einstein",
"https://en.wikipedia.org/wiki/Richard_Feynman",
"https://en.wikipedia.org/wiki/James_Clerk_Maxwell",
"https://en.wikipedia.org/wiki/Alan_Guth"
]
print("Scraping and analyzing articles...")
for i, url in enumerate(urls):
print(f"\n--- Processing Article {i+1} ---")
content = get_article_content(url)
if content:
summary = get_article_summary(content)
if summary:
print(f"Scientist: {summary.get('name')}")
print(f"Born: {summary.get('born')}")
print(f"Fame: {summary.get('fame')}")
print(f"Nobel: {summary.get('prize')}")
print(f"Died: {summary.get('death')}")
else:
print("Failed to generate summary.")
else:
print("Skipping (No content)")
print("\nDone.")
При запуске кода получился такой результат.
Scraping and analyzing articles...
--- Processing Article 1 ---
Scientist: Albert Einstein
Born: 14 March 1879 in Ulm, Kingdom of Württemberg, German Empire
Fame: Developing the theory of relativity and the mass-energy equivalence formula E = mc2, plus contributions to quantum theory including the photoelectric effect
Nobel: 1921
Died: 18 April 1955
--- Processing Article 2 ---
Scientist: Richard Phillips Feynman
Born: May 11, 1918, in New York City
Fame: Path integral formulation of quantum mechanics, quantum electrodynamics, Feynman diagrams, and contributions to particle physics including the parton model
Nobel: 1965
Died: February 15, 1988
--- Processing Article 3 ---
Scientist: James Clerk Maxwell
Born: 13 June 1831 in Edinburgh, Scotland
Fame: Developed the classical theory of electromagnetic radiation, unifying electricity, magnetism, and light through Maxwell's equations. Also key contributions to statistical mechanics, color theory, and numerous other fields of physics and mathematics.
Nobel: 0
Died: 5 November 1879
--- Processing Article 4 ---
Scientist: Alan Harvey Guth
Born: February 27, 1947 in New Brunswick, New Jersey
Fame: Pioneering the theory of cosmic inflation, which proposes that the early universe underwent a phase of exponential expansion driven by positive vacuum energy density
Nobel: 0
Died: Still alive
Done.
Хороший итог! Алан Гут, конечно, рад, что жив, но Нобелевской премии пока нет. Джеймс Клерк Максвелл ушел из жизни до учреждения премии.
Пример 2: Автоматизированный агент по безопасности и рефакторингу кода.
Это другой сценарий, полезный для разработки ПО. Обычно запрос к LLM на исправление кода дает разговорный ответ с блоками кода, что усложняет интеграцию в CI/CD или плагины IDE.
С Structured Outputs модель возвращает чистый код, список конкретных ошибок и оценку рисков безопасности в одном JSON-объекте, готовом для машины.
Сценарий
Мы подаем модели функцию Python с уязвимостью SQL-инъекции и плохими практиками. Модель выявляет проблемы и переписывает код безопасно.
import anthropic
import httpx
import os
import json
from pydantic import BaseModel, Field, ConfigDict
from typing import List, Literal
# --- SETUP ---
http_client = httpx.Client()
api_key = 'YOUR_API_KEY'
client = anthropic.Anthropic(api_key=api_key, http_client=http_client)
# Intentionally bad code
bad_code_snippet = """
import sqlite3
def get_user(u):
conn = sqlite3.connect('app.db')
c = conn.cursor()
# DANGER: Direct string concatenation
query = "SELECT * FROM users WHERE username = '" + u + "'"
c.execute(query)
return c.fetchall()
"""
# --- DEFINE SCHEMA WITH STRICT CONFIG ---
# We add model_config = ConfigDict(extra="forbid") to ensure
# "additionalProperties": false is generated in the schema.
class BugReport(BaseModel):
model_config = ConfigDict(extra="forbid")
severity: Literal["Low", "Medium", "High", "Critical"]
line_number_approx: int = Field(description="The approximate line number where the issue exists.")
issue_type: str = Field(description="e.g., 'Security', 'Performance', 'Style'")
description: str = Field(description="Short explanation of the bug.")
class CodeReviewResult(BaseModel):
model_config = ConfigDict(extra="forbid")
is_safe_to_run: bool = Field(description="True only if no Critical/High security risks exist.")
detected_bugs: List[BugReport]
refactored_code: str = Field(description="The complete, fixed Python code string.")
explanation: str = Field(description="A brief summary of changes made.")
# --- API CALL ---
try:
print("Analyzing code for security vulnerabilities...\n")
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
temperature=0.0,
messages=[
{
"role": "user",
"content": f"Review and refactor this Python code:\n\n{bad_code_snippet}"
}
],
extra_headers={
"anthropic-beta": "structured-outputs-2025-11-13"
},
extra_body={
"output_format": {
"type": "json_schema",
"schema": CodeReviewResult.model_json_schema()
}
}
)
# Parse Result
result = json.loads(response.content[0].text)
# --- DISPLAY OUTPUT ---
print(f"Safe to Run: {result['is_safe_to_run']}")
print("-" * 40)
print("BUGS DETECTED:")
for bug in result['detected_bugs']:
# Color code the severity (Red for Critical)
prefix = "🔴" if bug['severity'] in ["Critical", "High"] else "🟡"
print(f"{prefix} [{bug['severity']}] Line {bug['line_number_approx']}: {bug['description']}")
print("-" * 40)
print("REFACTORED CODE:")
print(result['refactored_code'])
except anthropic.BadRequestError as e:
print(f"API Schema Error: {e}")
except Exception as e:
print(f"Error: {e}")
Этот код работает как автоматический аудитор безопасности. Вместо болтовни об ошибках ИИ заполняет строгий цифровой формуляр с деталями багов и рисков.
Процесс в трех шагах.
- Сначала код определяет формат ответа через классы Python с Pydantic. Это указывает ИИ: верни JSON с списком ошибок, оценкой серьезности (Critical, Low и т.д.) и строкой исправленного кода.
- При отправке уязвимого кода в API схема Pydantic передается через output_format. Это жестко ограничивает модель, не давая добавлять лишнее или фантазировать. Ответ должен точно соответствовать схеме.
- Скрипт получает гарантированно читаемый JSON, парсит его и выводит отчет: отмечает SQL-инъекцию как Critical и показывает безопасную версию кода.
Вот результат запуска.
Analyzing code for security vulnerabilities...
Safe to Run: False
----------------------------------------
BUGS DETECTED:
🔴 [Critical] Line 7: SQL injection vulnerability due to direct string concatenation in query construction. Attacker can inject malicious SQL code through the username parameter.
🟡 [Medium] Line 4: Database connection and cursor are not properly closed, leading to potential resource leaks.
🟡 [Low] Line 1: Function parameter name 'u' is not descriptive. Should use meaningful variable names.
----------------------------------------
REFACTORED CODE:
import sqlite3
from contextlib import closing
def get_user(username):
"""
Retrieve user information from the database by username.
Args:
username (str): The username to search for
Returns:
list: List of tuples containing user data, or empty list if not found
"""
with sqlite3.connect('app.db') as conn:
with closing(conn.cursor()) as cursor:
# Use parameterized query to prevent SQL injection
query = "SELECT * FROM users WHERE username = ?"
cursor.execute(query, (username,))
return cursor.fetchall()
Почему это сильно?
Готово к интеграции. Скрипт можно запустить в GitHub Action. Если is_safe_to_run False, автоматически заблокировать Pull Request.
Разделение данных. Метаданные (ошибки, серьезность) отделены от содержимого (кода). Не нужно регулярками вырезать фразы вроде "Вот исправленный код".
Строгая типизация. Поле severity ограничено Enum (Critical, High и т.д.), так что логика не сломается, если модель выдаст "Severe" вместо "Critical".
Итог
Введение нативных Structured Outputs от Anthropic меняет правила для разработчиков, которым нужна надежность, а не просто чат. Строгие JSON-схемы позволяют использовать большие языковые модели как предсказуемые компоненты ПО, а не болтливых собеседников.
В статье показано, как применять эту бета-функцию для упрощения извлечения данных и создания автоматизированных процессов, интегрируемых с Python. Пользователям API Anthropic больше не придется мучиться с хрупкими регулярками для разбора ответов ИИ.
Подробности о бета-функции — в официальной документации Anthropic: https://platform.claude.com/docs/en/build-with-claude/structured-outputs.