Structured Output – Union событий API
📖 Описание
solution.py – практическое задание, в котором из сырого лога (несколько строк разного формата) извлекаются типизированные события через Pydantic v2 и LangChain ≥1.0.
Задача закрепляет работу с Union + Enums + StructuredOutput: одна входная лента, разные схемы, явный type/kind для маршрутизации.
Цель – получить список типизированных событий
ApiEventиз произвольного текста, а затем вывести их в табличном виде.
📦 Установка зависимостей
# Создайте и активируйте виртуальное окружение (необязательно)
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Установите зависимости
pip install langchain-core langchain-openai pydantic python-dotenv
Важно:
langchain-openai– подключает OpenAI API.- Для работы с другими LLM (например, Ollama) замените
langchain-openaiнаlangchain-ollamaи поправьте импорт вsolution.py.- В файле
.envукажите переменнуюOPENAI_API_KEY(илиOLLAMA_BASE_URLдля Ollama).
🏃♂️ Запуск
1. Запуск по умолчанию (пример лога)
python solution.py
Вы увидите вывод, где каждая строка лога преобразована в объект
ApiEventи напечатана в виде таблицы:
Вход: 3 строки лога разного формата
Выход:
┌───────┬───────────────────────┬────────┬───────────────┐
│ kind │ path │ status │ duration_ms │
├───────┼───────────────────────┼────────┼───────────────┤
│ ok │ /api/v1/users │ 200 │ 123 │
│ error │ /api/v1/orders │ 404 │ 0 │
│ error │ /api/v1/payments │ 500 │ 0 │
└───────┴───────────────────────┴────────┴───────────────┘
2. Передача собственного текста
python solution.py --text "GET /api/v1/products 200 45ms\nPOST /api/v1/cart 500 Internal Server Error"
Скрипт разбивает входной текст на строки, отправляет каждую в LLM, получает типизированный объект и выводит таблицу.
3. Использование собственного файла лога
python solution.py --file path/to/your.log
Внутри
solution.pyреализована простая логика: если указан--file, то читается содержимое файла и используется в качестве входного текста.
📦 Структура проекта
.
├── solution.py # Основной скрипт
├── .env # Переменные окружения (OPENAI_API_KEY)
└── README.md # Это файл
🔧 Как это работает
-
Модели
class HttpOkEvent(BaseModel): kind: Literal["ok"] = Field(..., description="Тип события: OK") status: Literal[200] = Field(..., description="HTTP статус 200") path: str = Field(..., description="Запрошенный путь") duration_ms: int = Field(..., description="Время выполнения в миллисекундах") class HttpErrorEvent(BaseModel): kind: Literal["error"] = Field(..., description="Тип события: Ошибка") status: int = Field(..., description="HTTP статус 4xx/5xx") path: str = Field(..., description="Запрошенный путь") error_message: str = Field(..., description="Текст ошибки") -
Union
ApiEvent = Annotated[ Union[HttpOkEvent, HttpErrorEvent], Field(discriminator="kind") ] -
Парсинг
- Для каждой строки лога создаётся промпт, который задаёт задачу LLM: «Преобразуй строку в JSON, соответствующий
ApiEvent». - Используется
PydanticOutputParser(илиwith_structured_output) для строгой валидации.
- Для каждой строки лога создаётся промпт, который задаёт задачу LLM: «Преобразуй строку в JSON, соответствующий
-
Вывод
- Список
ApiEventсериализуется черезmodel_dump()и печатается в табличном формате (можно заменить наtabulateилиpandas).
- Список
📌 Пример использования в коде
from solution import parse_log, print_events
log_text = """
GET /api/v1/users 200 123ms
POST /api/v1/orders 404 Not Found
GET /api/v1/payments 500 Internal Server Error
"""
events = parse_log(log_text)
print_events(events)
🤝 Вклад
Если хотите улучшить скрипт (добавить поддержку новых форматов, улучшить промпт, добавить кэширование), создайте Pull Request. Убедитесь, что все тесты (если есть) проходят.
📄 Лицензия
MIT © 2026