/
Вопросы и ответы
/
Промт-инжиниринг
/

Как тестировать промпты?

Как тестировать промпты?

11 часов назад

Никита Вихров

Ответы

0

Как тестировать промпты

Большинство разработчиков итерируют промпты так: изменил что-то — попробовал вручную — «кажется лучше» — оставил. Это не тестирование, это угадывание. Через неделю промпт работает хуже на новых данных, и непонятно почему.

Систематическое тестирование промптов — это тест-кейсы, метрики и воспроизводимые результаты.


Шаг 1: Тестовый датасет

Собери реальные примеры входных данных и ожидаемых выходов. Минимум 20–30 штук, лучше 100:

# test_cases.py
TEST_CASES = [
    {
        "input": "Заказ #123 от Ивана, сумма 500р, доставлен вчера",
        "expected": {"order_id": 123, "customer": "Иван", "amount": 500, "status": "доставлен"},
        "tags": ["simple"]
    },
    {
        "input": "Номер заказа: 456. Клиент: ООО Рога и Копыта. К оплате: 15 000 рублей. Статус: в обработке",
        "expected": {"order_id": 456, "customer": "ООО Рога и Копыта", "amount": 15000, "status": "в обработке"},
        "tags": ["company_name", "large_amount"]
    },
    {
        "input": "заказ пятьсот двадцать один, петров, триста пятьдесят рублей",
        "expected": {"order_id": 521, "customer": "Петров", "amount": 350, "status": None},
        "tags": ["words_not_digits", "missing_status"]
    },
    # ... ещё 50 примеров
]

Важно включить граничные случаи: нестандартные форматы, опечатки, пропущенные поля, нетипичные значения.


Шаг 2: Функция оценки

from anthropic import Anthropic
import json
from dataclasses import dataclass

client = Anthropic()


@dataclass
class TestResult:
    passed: bool
    input: str
    expected: dict
    actual: dict | None
    error: str | None


def run_prompt(prompt_template: str, input_text: str) -> dict | None:
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=256,
        temperature=0,  # детерминированность при тестировании
        messages=[{
            "role": "user",
            "content": prompt_template.format(input=input_text)
        }]
    )

    try:
        text = response.content[0].text.strip()
        text = text.replace("```json", "").replace("```", "").strip()
        return json.loads(text)
    except json.JSONDecodeError:
        return None


def evaluate_result(expected: dict, actual: dict | None) -> bool:
    if actual is None:
        return False
    for key, value in expected.items():
        if value is None:
            continue  # пропускаем опциональные поля
        if actual.get(key) != value:
            return False
    return True


def run_evaluation(prompt_template: str, test_cases: list) -> dict:
    results = []

    for case in test_cases:
        actual = run_prompt(prompt_template, case["input"])
        passed = evaluate_result(case["expected"], actual)

        results.append(TestResult(
            passed=passed,
            input=case["input"],
            expected=case["expected"],
            actual=actual,
            error=None if actual else "Не удалось распарсить JSON"
        ))

    passed_count = sum(1 for r in results if r.passed)
    total = len(results)

    return {
        "score": passed_count / total,
        "passed": passed_count,
        "total": total,
        "failures": [r for r in results if not r.passed]
    }

Шаг 3: Сравниваем версии промптов

PROMPT_V1 = """Извлеки данные заказа из текста в JSON.
Поля: order_id (число), customer (строка), amount (число), status (строка или null).

Текст: {input}
JSON:"""

PROMPT_V2 = """Извлеки данные заказа из текста. Отвечай только JSON без пояснений.

<fields>
- order_id: номер заказа (integer)
- customer: имя клиента или название компании (string)
- amount: сумма в рублях (float, только число без слова "рублей")
- status: статус заказа (string или null если не указан)
</fields>

<rules>
- Числа словами переводи в цифры ("пятьсот" → 500)
- Если поле не найдено — используй null
</rules>

<input>{input}</input>
JSON:"""

print("Тестируем V1...")
result_v1 = run_evaluation(PROMPT_V1, TEST_CASES)
print(f"Score: {result_v1['score']:.1%} ({result_v1['passed']}/{result_v1['total']})")

print("\nТестируем V2...")
result_v2 = run_evaluation(PROMPT_V2, TEST_CASES)
print(f"Score: {result_v2['score']:.1%} ({result_v2['passed']}/{result_v2['total']})")

# Смотрим на что именно V2 лучше
print("\nПроблемы V1:")
for failure in result_v1["failures"]:
    print(f"  - {failure.input[:60]}...")
    print(f"    Ожидали: {failure.expected}")
    print(f"    Получили: {failure.actual}")

Шаг 4: Фиксируй что сломал

При каждом изменении промпта — прогоняй весь датасет. Регрессии часто незаметны вручную:

# Добавь в CI или запускай перед деплоем
python test_prompts.py --threshold 0.90

# Если score < 90% — падаем

Как тестировать и итерировать промпты на реальных задачах — разбирается на курсе «ИИ для разработчиков» на Хекслете.

11 часов назад

Никита Вихров

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845