Промпт для извлечения структурированных данных из текста
Готовый промпт-рецепт для извлечения структурированных данных (JSON) из любого неструктурированного текста — резюме, счетов, отзывов, писем. С примерами, вариациями и советами.
Задача
Вам приходят неструктурированные тексты — резюме кандидатов, клиентские отзывы, счета от поставщиков, описания вакансий, письма — и нужно автоматически извлечь из них ключевые поля в формате JSON. Руками это долго и ненадёжно. LLM справляется за секунды.
Этот рецепт даёт вам универсальный шаблон промпта, который адаптируется под любой тип документа.
Для кого
- Аналитики данных — быстрый парсинг отчётов и документов
- HR-специалисты — обработка резюме и заявок
- Маркетологи — анализ отзывов и упоминаний бренда
- Разработчики — интеграция извлечения данных в пайплайны
- Предприниматели — автоматизация рутинной обработки документов
Как работает промпт
graph LR
A["📄 Неструктурированный текст"] --> B["🔧 Промпт с JSON-схемой"]
B --> C["🤖 LLM анализирует"]
C --> D["📊 Структурированный JSON"]
D --> E["💾 БД / Таблица / API"]
Принцип прост: вы даёте модели текст + схему нужных полей, и она возвращает заполненный JSON. Ключ к качеству — точное описание каждого поля и правила обработки неопределённости.
Промпт
Ты — система извлечения структурированных данных. Твоя задача — проанализировать
входной текст и извлечь информацию строго по заданной схеме.
<schema>
{
"fields": [
{"name": "ПОЛЕ_1", "type": "string", "description": "Описание, что именно извлекать"},
{"name": "ПОЛЕ_2", "type": "number", "description": "Описание числового поля"},
{"name": "ПОЛЕ_3", "type": "array", "description": "Список значений"},
{"name": "ПОЛЕ_4", "type": "string", "enum": ["вариант_а", "вариант_б", "вариант_в"], "description": "Категория из фиксированного списка"}
]
}
</schema>
<rules>
- Извлекай ТОЛЬКО то, что явно указано или однозначно следует из текста
- Если значение отсутствует — используй null, НЕ додумывай
- Числа возвращай без единиц измерения (единицы укажи в отдельном поле, если нужно)
- Даты приводи к формату YYYY-MM-DD
- Массивы сортируй по релевантности (самое важное — первым)
- Если текст содержит противоречия — извлеки оба варианта и добавь поле "conflicts"
</rules>
<output_format>
Верни ТОЛЬКО валидный JSON. Без пояснений, без markdown-обёрток.
Структура:
{
"extracted": { ...поля по схеме... },
"confidence": "high|medium|low",
"notes": "краткие заметки о качестве извлечения, если есть неоднозначности"
}
</output_format>
<input_text>
{{ВСТАВЬТЕ_ТЕКСТ_СЮДА}}
</input_text>
<schema>, <rules>, <input_text>) для разделения блоков. Claude и GPT-4o лучше распознают структуру промпта, когда секции явно размечены — это подтверждается официальной документацией Anthropic.Пример: извлечение данных из резюме
Входной текст:
Мария Иванова, 28 лет. Опыт работы 5 лет в IT. Последнее место —
старший аналитик данных в Яндексе (2023–2025). До этого — джуниор
аналитик в Сбере, 2 года. Владеет Python, SQL, Tableau, Power BI.
Английский — Upper-Intermediate. Ожидаемая зарплата от 250 000 руб.
Готова к переезду в Москву или удалённой работе. Закончила МГУ,
факультет ВМК, магистратура по прикладной математике (2021).
Промпт со схемой для резюме:
<schema>
{
"fields": [
{"name": "full_name", "type": "string", "description": "ФИО кандидата"},
{"name": "age", "type": "number", "description": "Возраст"},
{"name": "total_experience_years", "type": "number", "description": "Общий опыт работы в годах"},
{"name": "current_position", "type": "string", "description": "Последняя/текущая должность"},
{"name": "current_company", "type": "string", "description": "Последняя/текущая компания"},
{"name": "skills", "type": "array", "description": "Технические навыки"},
{"name": "education", "type": "string", "description": "Образование: вуз и специальность"},
{"name": "salary_expectation", "type": "number", "description": "Ожидаемая зарплата в рублях"},
{"name": "work_format", "type": "array", "enum": ["офис", "удалёнка", "гибрид", "переезд"], "description": "Предпочтительный формат работы"},
{"name": "english_level", "type": "string", "description": "Уровень английского"}
]
}
</schema>
Результат:
{
"extracted": {
"full_name": "Мария Иванова",
"age": 28,
"total_experience_years": 5,
"current_position": "Старший аналитик данных",
"current_company": "Яндекс",
"skills": ["Python", "SQL", "Tableau", "Power BI"],
"education": "МГУ, факультет ВМК, магистратура по прикладной математике (2021)",
"salary_expectation": 250000,
"work_format": ["удалёнка", "переезд"],
"english_level": "Upper-Intermediate"
},
"confidence": "high",
"notes": "Все поля извлечены однозначно. Зарплата указана как минимальная ('от 250 000')."
}
Сравнение подходов к извлечению данных
| Параметр | Ручной парсинг (regex) | LLM-извлечение | Structured Outputs API |
|---|---|---|---|
| Время настройки | Часы-дни | Минуты | Минуты |
| Гибкость формата | Низкая | Высокая | Высокая |
| Точность на «чистых» данных | 95-99% | 90-97% | 95-99% |
| Работа с «грязным» текстом | Плохо | Хорошо | Хорошо |
| Стоимость на 1000 документов | Бесплатно | $2-15 | $2-15 |
| Гарантия валидного JSON | Да | Нет* | Да |
| Нужны примеры | Нет | Желательно | Желательно |
При промпт-подходе модель может иногда вернуть невалидный JSON. Structured Outputs API (доступен в Claude и OpenAI) решает эту проблему — схема компилируется в грамматику, и модель физически не может нарушить формат.
confidence и проверяйте результаты для критичных задач.Вариации и настройки
1. Пакетная обработка
Если нужно обработать несколько документов за один запрос:
<batch_mode>
Обработай каждый документ из списка ниже отдельно.
Верни массив JSON-объектов в том же порядке.
Если документ невозможно обработать — верни {"error": "причина"} на его позиции.
</batch_mode>
<documents>
[ДОКУМЕНТ 1]
---
[ДОКУМЕНТ 2]
---
[ДОКУМЕНТ 3]
</documents>
2. Извлечение из отзывов (сентимент + сущности)
<schema>
{
"fields": [
{"name": "sentiment", "type": "string", "enum": ["positive", "negative", "mixed", "neutral"]},
{"name": "rating_inferred", "type": "number", "description": "Предполагаемая оценка 1-5"},
{"name": "product_mentions", "type": "array", "description": "Упомянутые продукты/функции"},
{"name": "pain_points", "type": "array", "description": "Проблемы и жалобы"},
{"name": "praise_points", "type": "array", "description": "Что понравилось"},
{"name": "action_required", "type": "boolean", "description": "Требует ли отзыв реакции"}
]
}
</schema>
3. Извлечение из счетов и инвойсов
<schema>
{
"fields": [
{"name": "vendor_name", "type": "string"},
{"name": "invoice_number", "type": "string"},
{"name": "date", "type": "string", "description": "Дата в формате YYYY-MM-DD"},
{"name": "items", "type": "array", "description": "Список позиций: {name, quantity, unit_price, total}"},
{"name": "subtotal", "type": "number"},
{"name": "tax", "type": "number"},
{"name": "total", "type": "number"},
{"name": "currency", "type": "string"}
]
}
</schema>
Советы по улучшению
Добавьте few-shot примеры
Один-два примера «вход → выход» резко повышают точность. Модель перестаёт гадать формат и следует образцу:
<example>
Input: "Иван Петров, Python-разработчик, 3 года опыта, ищет от 200к"
Output: {"full_name": "Иван Петров", "position": "Python-разработчик",
"experience_years": 3, "salary_expectation": 200000}
</example>
Используйте цепочку рассуждений для сложных случаев
Для текстов с неявной информацией добавьте блок рассуждений:
<rules>
Перед извлечением:
1. Определи тип документа
2. Выдели ключевые сущности
3. Разреши противоречия (если есть)
4. Только потом заполни JSON
Рассуждения помести в поле "reasoning" (строка).
</rules>
Reasoning: “Общий опыт = 2 + 3 = 5 лет. Текущая позиция — тимлид. Компания одна, но не названа → company = null”
Без chain-of-thought модель может указать опыт как 2 или 3 года вместо суммарных 5.
Валидируйте результат программно
Не полагайтесь на модель — проверяйте JSON на стороне кода:
import json
from pydantic import BaseModel, validator
from typing import Optional
class CandidateData(BaseModel):
full_name: str
age: Optional[int] = None
total_experience_years: Optional[float] = None
skills: list[str] = []
salary_expectation: Optional[int] = None
@validator("age")
def age_must_be_reasonable(cls, v):
if v is not None and not (16 <= v <= 100):
raise ValueError(f"Unreasonable age: {v}")
return v
# Парсинг и валидация ответа LLM
raw = json.loads(llm_response)
candidate = CandidateData(**raw["extracted"])
Используйте Structured Outputs API для продакшена
В Claude (модели Sonnet 4.5, Opus 4.5, Haiku 4.5) и OpenAI (GPT-4o) доступны нативные structured outputs — схема компилируется в грамматику на уровне inference, и модель физически не может вернуть невалидный JSON. Для продакшен-пайплайнов это надёжнее промпт-подхода.
Промпт-извлечение — это не замена базы данных и не замена парсера. Это мост между хаосом неструктурированного текста и порядком структурированных данных. Используйте его там, где regex сдаётся, а полноценный NLP-пайплайн — избыточен.