Структурированный вывод LangChain

В большинстве случаев вам нужен не произвольный текст, а структурированные данные — например, объект JSON.

LangChain Structured Output позволяет агенту возвращать результаты в указанном вами формате, что упрощает их прямое использование программами.


Зачем нужен структурированный вывод?

Предположим, вам нужно извлечь имя, возраст и профессию из описания пользователя:

МетодФормат выводаПоследующая обработка
Обычный ответЧжан Сань — 28 лет, он инженер.Требуется regex или повторный вызов модели для разбора
Структурированный вывод{name: "Чжан Сань", age: 28, job: "Инженер"}Используется напрямую как объект Python

Структурированный вывод избавляет от шага «разбора данных из текста», позволяя программам напрямую использовать вывод ИИ.


Простейшее использование — передача модели Pydantic

Просто передайте модель Pydantic в параметр response_format:

Пример

from dotenv import load_dotenv
load_dotenv()

from pydantic import BaseModel, Field
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


# Определите ожидаемую структуру выходных данных
class CourseInfo(BaseModel):
    """Пример результата извлечения учебного курса"""
    course_name: str = Field(description=Название курса)
    difficulty: str = Field(description=Сложность: Начальный/Средний/Продвинутый)
    estimated_hours: int = Field(description=Оценочная продолжительность обучения (часы))
    is_free: bool = Field(description=Является ли он бесплатным)


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    response_format=CourseInfo,  # Передайте модель Pydantic
    system_prompt=Вы — ассистент курса в Example Tutorial. Извлекайте информацию о курсе из описаний пользователей.,
)

# Пользователь вводит неструктурированное описание
result = agent.invoke({
    "messages": [HumanMessage(
        content=Я недавно изучаю учебник Python3 Basics, он для начинающих,
                На его изучение уходит около 20 часов, и он полностью бесплатный.
    )]
})

# Получите структурированный результат из structured_response
if "structured_response" in result:
    course = result["structured_response"]
    print(fНазвание курса: {course.course_name})
    print(fСложность: {course.difficulty})
    print(fОжидаемая продолжительность: {course.estimated_hours} часов)
    print(fБесплатно: {'Да' if course.is_free else 'Нет'})
    print(fТип объекта: {type(course)})

Результат выполнения:

Course name: Python3 基础教程
Difficulty: 入门
Duration: 20 小时
Free: 是
Object type: <class '__main__.CourseInfo'>

Возвращённый structured_response — это экземпляр модели Pydantic, а не обычный словарь. Это означает, что вы можете обращаться к атрибутам, таким как .course_name, а IDE может обеспечивать автодополнение.


Структурированный вывод вместе с инструментами

response_format и tools можно использовать вместе — Агент вызывает инструменты при необходимости и в итоге выводит структурированные данные:

Пример

from pydantic import BaseModel, Field
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langchain.tools import tool


@tool
def search_course(keyword: str) -> str:
    """Поиск информации о курсах на Example Tutorial"""
    courses = {
        "python": Учебник по основам Python3 | Для начинающих | Бесплатно | 30 глав | Около 20 часов,
        "java": Учебник по основам Java | Для начинающих | Бесплатно | 35 глав | Около 25 часов,
        Анализ данных: Анализ данных на Python | Средний уровень | Для участников | 25 глав | Около 30 часов,
    }
    return courses.get(keyword.lower(), fКурс не найден для '{keyword}')


class CourseRecommendation(BaseModel):
    """Результат рекомендации курса"""
    course_name: str = Field(description=Рекомендуемое название курса)
    reason: str = Field(description=Причина рекомендации)
    difficulty: str = Field(description=Сложность: Начальный/Средний/Продвинутый)


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[search_course],
    response_format=CourseRecommendation,
    system_prompt=Вы — консультант по курсам в Example Tutorial. Сначала найдите курсы, затем дайте рекомендации.,
)

result = agent.invoke({
    "messages": [HumanMessage(content=Я хочу изучать Python. Что вы порекомендуете?)]
})

rec = result["structured_response"]
print(fРекомендуемый курс: {rec.course_name})
print(fПричина рекомендации: {rec.reason})
print(fСложность: {rec.difficulty})

# Просмотреть весь процесс
print("\n"=== Процесс выполнения ===")
for msg in result["messages"]:
    if msg.type == "tool":
        print(f" Вызов {msg.name}: {msg.content}")

Результат выполнения:

Recommended course: Python3 基础教程
Reason: 该课程免费且适合Python初学者,学习时长约20小时
Difficulty: 入门

=== 执行过程 ===
  调用 search_course: Python3 基础教程 | 入门 | 免费 | 30章 | 约20小时

Сложные вложенные структуры

Pydantic поддерживает сложные структуры, такие как вложенность, списки, перечисления и т. д.:

Пример

from pydantic import BaseModel, Field
from typing import Literal
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


class Topic(BaseModel):
    """Тема"""
    name: str = Field(description=Название темы)
    order: int = Field(description=Порядок изучения, начиная с 1)
    minutes: int = Field(description=Рекомендуемое время обучения (minutes))


class LearningPlan(BaseModel):
    """Учебный план"""
    goal: str = Field(description=Обзор цели обучения)
    level: Literal[Beginner, Intermediate, Advanced] = Field(description=Уровень сложности)
    total_hours: float = Field(description=Общая длительность (hours))
    topics: list[Topic] = Field(description=Список тем)


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    response_format=LearningPlan,
    system_prompt=Вы — планировщик обучения в Example Tutorial.,
)

result = agent.invoke({
    "messages": [HumanMessage(
        content=Помоги мне создать план обучения Python для начинающих, уложившись в общее время 10 часов
    )]
})

plan = result["structured_response"]
print(fЦель: {plan.goal})
print(fСложность: {plan.level})
print(fОбщая длительность: {plan.total_hours} часов)
print(f"\n"Список тем ({len(plan.topics)} элементов):")
for topic in plan.topics:
    print(f" {topic.order}. {topic.name} ({topic.minutes} минут)")

Результат выполнения:

目标: 掌握 Python 基础语法,能够独立编写简单的 Python 程序
Difficulty: 入门
总时长: 9.5 小时

知识点列表 (6 个):
  1. 环境搭建与基础语法 (60分钟)
  2. 数据类型与变量 (90分钟)
  3. 条件判断与循环 (120分钟)
  4. 函数与模块 (120分钟)
  5. 列表与字典 (90分钟)
  6. 综合练习 (90分钟)

Получение структурированного вывода из сообщений

Если вам не нужна возможность вызова инструментов у Agent и вы просто хотите извлечь структурированную информацию из текста, вы можете использовать модель напрямую:

Пример

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model


class SentimentResult(BaseModel):
    """Результат анализа тональности"""
    sentiment: str = Field(description=Положительный/Отрицательный/Нейтральный)
    score: float = Field(description=Интенсивность тональности 0~1)
    keywords: list[str] = Field(description=Ключевые слова тональности)


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# Используйте with_structured_output() напрямую на модели
# Agent не нужен
structured_model = model.with_structured_output(SentimentResult)

texts = [
    Учебник Example действительно отлично подходит для использования. Настоятельно рекомендуется!,
    В этом учебнике слишком мало содержания. Он того не стоит.,
    Сегодня хорошая погода.,
]

for text in texts:
    result = structured_model.invoke(text)
    print(fТекст: {text[:30]}...)
    print(f" Тональность: {result.sentiment}, Интенсивность: {result.score}, Ключевые слова: {result.keywords}")

Результат выполнения:

Text: Example 真的太好用了,强烈推荐!...
  Sentiment: 积极, 强度: 0.95, 关键词: ['好用', '推荐']
Text: 这个教程内容太少了,不太值。...
  Sentiment: 消极, 强度: 0.7, 关键词: ['内容太少', '不太值']
Text: 今天天气不错。...
  Sentiment: 中性, 强度: 0.1, 关键词: ['不错']

with_structured_output() — это метод модели, и его можно использовать без Agent. Если ваш сценарий — «извлечение информации», а не «многошаговое рассуждение», использование with_structured_output() напрямую проще и эффективнее.

Другие расширения