Экзамен: Структурированный вывод (Pydantic): solution.py

This commit is contained in:
2026-05-28 16:46:01 +00:00
parent 2ae6e2dd39
commit 889499ec93
+149
View File
@@ -0,0 +1,149 @@
import os
import sys
from typing import List, Optional
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
# ------------------------------------------------------------------
# 1. Pydantic модели
# ------------------------------------------------------------------
class PersonInfo(BaseModel):
name: str = Field(..., description="Имя человека")
age: Optional[int] = Field(None, description="Возраст (если известен)")
profession: str = Field(..., description="Профессия или должность")
skills: List[str] = Field(..., description="Список навыков")
class MeetingNotes(BaseModel):
date: str = Field(..., description="Дата встречи в формате YYYY-MM-DD")
participants: List[str] = Field(
..., description="Имена участников встречи"
)
topics: List[str] = Field(..., description="Темы обсуждения")
decisions: List[str] = Field(
..., description="Принятые решения и выводы"
)
next_steps: List[str] = Field(
...,
description="Следующие шаги после встречи",
)
# ------------------------------------------------------------------
# 2. Создание парсера
# ------------------------------------------------------------------
def get_parser(model_cls):
return PydanticOutputParser(pydantic_object=model_cls)
person_parser = get_parser(PersonInfo)
meeting_parser = get_parser(MeetingNotes)
# ------------------------------------------------------------------
# 3. Prompt шаблоны (один общий, но с разными инструкциями)
# ------------------------------------------------------------------
prompt_template = """
{format_instructions}
Входной текст:
"{text}"
"""
prompt = PromptTemplate(
input_variables=["text", "format_instructions"],
template=prompt_template,
)
# ------------------------------------------------------------------
# 4. LLM
# ------------------------------------------------------------------
# Для работы нужен API‑ключ OpenAI в переменной окружения OPENAI_API_KEY
llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo")
# ------------------------------------------------------------------
# 5. Функция выбора схемы и выполнения цепочки
# ------------------------------------------------------------------
def extract_structured(text: str):
"""
Определяем тип текста (person vs meeting) по эвристике
и возвращаем валидированный объект Pydantic.
"""
# простая эвристика: наличие слова "встреча" или "meeting"
if any(word in text.lower() for word in ["встреча", "meeting"]):
parser = meeting_parser
else:
parser = person_parser
chain = prompt | llm | parser
result = chain.invoke(
{
"text": text,
"format_instructions": parser.get_format_instructions(),
}
)
return result
# ------------------------------------------------------------------
# 6. CLI
# ------------------------------------------------------------------
def main():
examples = [
(
"Анна, 28 лет, Python-разработчик. Навыки: FastAPI, Docker.",
PersonInfo,
),
(
"""Встреча 2023-08-15
Участники:
- Иванов И.И.
- Петров П.П.
Темы:
1. Обновление проекта
2. Распределение задач
Решения:
- Завершить модуль X к 01/09
- Назначить ответственных за Y
Следующие шаги:
- Подготовить презентацию
- Отправить отчёт команде""",
MeetingNotes,
),
]
if len(sys.argv) > 1 and sys.argv[1] == "--example":
for idx, (txt, model_cls) in enumerate(examples, start=1):
print(f"\n=== Пример {idx} ===")
obj = extract_structured(txt)
print(obj.model_dump(indent=2))
else:
# пользовательский ввод
print("Введите текст (Ctrl-D/Enter для завершения):")
user_text = sys.stdin.read().strip()
if not user_text:
print("Пустой ввод.")
return
obj = extract_structured(user_text)
print("\nРезультат:")
print(obj.model_dump(indent=2))
if __name__ == "__main__":
main()