Структурированный вывод LangChain
В большинстве случаев вам нужен не произвольный текст, а структурированные данные — например, объект JSON.
LangChain Structured Output позволяет агенту возвращать результаты в указанном вами формате, что упрощает их прямое использование программами.
Зачем нужен структурированный вывод?
Предположим, вам нужно извлечь имя, возраст и профессию из описания пользователя:
| Метод | Формат вывода | Последующая обработка |
|---|---|---|
| Обычный ответ | Чжан Сань — 28 лет, он инженер. | Требуется regex или повторный вызов модели для разбора |
| Структурированный вывод | {name: "Чжан Сань", age: 28, job: "Инженер"} | Используется напрямую как объект Python |
Структурированный вывод избавляет от шага «разбора данных из текста», позволяя программам напрямую использовать вывод ИИ.
Простейшее использование — передача модели Pydantic
Просто передайте модель Pydantic в параметр response_format:
Пример
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 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 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 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() напрямую проще и эффективнее.