Практические заметки: Разработка, основанная на оценке: подход инженерии программного обеспечения к
Пошаговое руководство по практическим заметкам: Разработка, основанная на оценке: подход инженерии программного обеспечения к контрактам, проверкам и слотам для вставки кода для команд, использующих эту модель.
В этом руководстве показано, как пройти путь от сырья до рабочей системы для проекта Eval-Driven Development: A Software Engineering Approach to Production-Grade AI Agents. Основное внимание уделяется практическим шагам, четким проверкам и коду, который можно просто добавить в репозиторий без необходимости догадываться о его назначении. На этапе обзора необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии системы. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение затрат с самого начала помогает избежать неожиданных расходов при переходе от демо-версии к общедоступным средам.
Краткое резюме
На этапе подготовки краткого обзора сначала запишите условия контракта: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Храните конфигурацию отдельно от кода приложения. Файлы с настройками окружения, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь кодовый граф. Создавайте контрольные точки после дорогостоящих операций. Функция возобновления работы не должна снова взимать плату за один и тот же вызов большой языковой модели, когда оператор пытается выполнить следующий шаг.
Введение
На этапе введения сначала запишите условия контракта: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Документируйте одновременно успешный и восстановительный пути работы. Повторные попытки, проверки со стороны оператора и обработка некорректных сообщений являются частью продукта, а не элементами последующей доработки. Устанавливайте контрольные точки после дорогостоящих операций. Система возобновления работы не должна повторно взимать плату за один и тот же вызов большой языковой модели, если оператор попытается выполнить следующий этап заново.
Производственная цепочка: общая структура
При работе над этапом «Производственная цепочка» сначала запишите контракт: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист помогает сохранять честность при последующих изменениях кода. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг терпит неудачу, ошибка должна указывать на конкретную ответственность, а не на запутанную структуру цепочки. Вводите контрольные точки после дорогостоящих шагов. Механизм возобновления работы не должен повторно взимать плату за один и тот же вызов большой языковой модели, когда оператор пытается выполнить следующий узел.
1. Контракт: разделение и версионирование промпта
При работе над этапом «1. Разделение через контракт» сначала запишите условия контракта: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет избежать ошибок при последующих изменениях кода. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия соответствующим элементам, определите критерии успешности и не допускайте молчаливого частичного выполнения задачи. Храните в кэше стабильные инструкции системы и схемы инструментов. Повторная отправка одинаковых данных является распространенной причиной избыточных ресурсов.
[
{
"agent_id": "financial_market_headlines",
"version": 1,
"agent_model": "openai:gpt-4",
"prompt": "What are today's major financial market headlines?",
"eval": {
"contains": ["market"],
"max_model_requests": 3,
"min_tool_calls": 1,
"max_tool_calls": 5,
"judge_rubric": "The answer should be a useful response to the user's financial markets question. It should summarize market-relevant information, avoid obviously unrelated content, avoid investment advice, and avoid claiming certainty beyond what the retrieved information supports."
}
}
]
2. Время выполнения: движок исполнения
При работе над этапом «Время выполнения» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает избегать ошибок при последующих изменениях кода. Рядом с функциональными результатами записывайте время выполнения и стоимость токенов или запросов. Отслеживание затрат с самого начала предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды. Выполняйте контрольные точки после дорогостоящих операций. Функция возобновления работы не должна снова взимать плату за один и тот же вызов большой языковой модели, если оператор пытается выполнить последующий шаг.
3. Слой наблюдаемости: без слепых зон
При работе над этапом «Слой наблюдаемости» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Создавайте контрольные точки после дорогостоящих операций. Функция возобновления работы не должна снова взимать плату за один и тот же вызов большой языковой модели, когда оператор пытается выполнить следующий шаг.
4. Слой оценки: CI/CD для ИИ
При работе над этапом «Слой оценки» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Документируйте одновременно успешный и восстановительный сценарии работы. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не элементами последующей доработки. Выполняйте контрольные точки после дорогостоящих операций. Механизм возобновления работы не должен повторно взимать плату за один и тот же вызов большой языковой модели, когда оператор пытается выполнить следующий этап.
Оценка: принуждение к детерминизму в недетерминистичной системе
При работе над модулем Evals Forcing Determinism сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность последующих изменений в коде. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое какого-либо шага причина неудачи должна указывать на конкретную ответственность, а не на запутанную цепочку операций. Вносите контрольные точки после дорогостоящих шагов. Механизм возобновления работы не должен повторно взимать плату за один и тот же вызов большой языковой модели при повторной попытке обработки последующего узла. При работе над модулем Evals Forcing Determinism сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность последующих изменений в коде. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости на ранних этапах предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам.
Уровень 1: Тесты в реальном времени с детерминированным поведением
Этап уровня 1 с тестами в реальном времени и детерминированным поведением работает наилучшим образом, если рассматриваться как измеримая структура. Сначала необходимо зафиксировать один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объем тестирования. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь граф структуры. Состояние графа должно быть простым и иметь четкую типизацию. Вложенные структуры данных маскируют информацию о том, какой узел записал тот или иной поле, что приводит к нарушению возобновления работы после перерывов.
uv run python tests/unittest_eval_agent.py
evaluators=[
*[Contains(value, case_sensitive=False) for value in case.eval.contains],
MaxModelRequests(case.eval.max_model_requests),
MinToolCalls(case.eval.min_tool_calls),
MaxToolCalls(case.eval.max_tool_calls),
]
(financial-agent2) alex@pop-os:/ssd/ai_works/financial_agent2$ uv run python tests/unittest_eval_agent.py
Running each eval case 3 time(s)
Evaluating task ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
Evaluation Summary: task
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Case ID ┃ Metrics ┃ Assertions ┃ Duration ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━┩
│ financial_market_headlines_v1 [1/3] │ tool_calls: 1 │ ✔✔✔✔ │ 18.8s │
│ │ requests: 2 │ │ │
│ │ input_tokens: 1,325 │ │ │
│ │ output_tokens: 278 │ │ │
│ │ cost: 0.0564 │ │ │
├─────────────────────────────────────┼───────────────────────┼────────────┼──────────┤
│ financial_market_headlines_v1 [2/3] │ tool_calls: 1 │ ✔✔✔✔ │ 8.8s │
│ │ requests: 2 │ │ │
│ │ input_tokens: 1,195 │ │ │
│ │ output_tokens: 82 │ │ │
│ │ cost: 0.0408 │ │ │
├─────────────────────────────────────┼───────────────────────┼────────────┼──────────┤
│ financial_market_headlines_v1 [3/3] │ tool_calls: 1 │ ✔✔✔✔ │ 13.5s │
│ │ requests: 2 │ │ │
│ │ input_tokens: 1,292 │ │ │
│ │ output_tokens: 388 │ │ │
│ │ cost: 0.0620 │ │ │
├─────────────────────────────────────┼───────────────────────┼────────────┼──────────┤
│ Averages │ requests: 2.00 │ 100.0% ✔ │ 13.7s │
│ │ output_tokens: 249.3 │ │ │
│ │ tool_calls: 1.00 │ │ │
│ │ cost: 0.0531 │ │ │
│ │ input_tokens: 1,270.7 │ │ │
└─────────────────────────────────────┴───────────────────────┴────────────┴──────────┘
Уровень 2: Детерминированное тестирование регрессии на основе трейсов
Этап детерминистической регрессии уровня 2 работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ.
uv run python tests/regression_eval_traces.py
Trace: ff5a53e3392dc26cd0a2890782be70ec
Eval case: financial_market_headlines v1
Status: PASS
Model requests: 2
Tool calls: 1
contains('market'): PASS
MaxModelRequests: PASS
MaxToolCalls: PASS
Уровень 3: Недетерминистические тесты — ИИ в роли судьи
Этап Layer 3 Non Deterministic работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое какого-либо шага причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций. Установите лимиты на количество токенов за ход и за сессию. Инструменты агентного типа активно расширяют объём контекста; жесткие ограничения помогают избежать неожиданных счетов. Этап Layer 3 Non Deterministic работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости на ранних этапах предотвращает неожиданные счета при переходе от демо-версии к общедоступным средам.
[
{
"agent_id": "financial_market_headlines",
"version": 1,
"agent_model": "openai:gpt-4",
"prompt": "What are today's major financial market headlines?",
"eval": {
"contains": ["market"],
"max_model_requests": 3,
"min_tool_calls": 1,
"max_tool_calls": 5,
"judge_rubric": "The answer should be a useful response to the user's financial markets question. It should summarize market-relevant information, avoid obviously unrelated content, avoid investment advice, and avoid claiming certainty beyond what the retrieved information supports."
}
}
]
LLMJudge(
rubric=case.eval_case.eval.judge_rubric,
model=args.judge_model,
include_input=True,
score={"evaluation_name": "judge_score", "include_reason": True},
assertion={"evaluation_name": "judge_pass", "include_reason": True},
)
uv run python tests/regression_llm_judge_traces.py --sample-percent 50
Trace selection: fetched=1 sampled=1 judging=1 lookback_minutes=1440 sample_percent=50 max_traces=5
Trace case: trace_id=3891f0b8432c9bbcb00e5e8adce1600b agent_id=financial_market_headlines prompt_version=1 answer_chars=207
Judging 1 trace(s) with openai:gpt-5.4
Evaluating task ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
Evaluation Summary: task
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Case ID ┃ Inputs ┃ Outputs ┃ Scores ┃ Assertions ┃ Duration ┃
┡━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ financial_market_he… │ {'trace_id': │ Today's major │ judge_score: 0.000 │ judge_pass: ✗ │ 469µs │
│ │ '3891f0b8432c9bbcb00 │ financial market │ Reason: The │ Reason: The │ │
│ │ e5e8adce1600b', │ headlines can be │ response does not │ response does not │ │
│ │ 'agent_id': │ found on major │ summarize any actual │ summarize any │ │
│ │ 'financial_market_he │ business and finance │ market headlines or │ actual market │ │
│ │ adlines', │ news outlets │ provide │ headlines or │ │
│ │ 'prompt_version': 1, │ including CNBC, │ market-relevant │ provide │ │
│ │ 'agent_model': │ Yahoo Finance, │ information; it only │ market-relevant │ │
│ │ 'openai:gpt-4', │ Reuters, and │ redirects the user │ information; it │ │
│ │ 'judge_model': │ Bloomberg. For more │ to news websites. It │ only redirects the │ │
│ │ 'openai:gpt-5.4', │ specific stories, │ avoids investment │ user to news │ │
│ │ 'prompt': "What are │ please visit their │ advice, but it is │ websites. It avoids │ │
│ │ today's major │ websites. │ not a useful answer │ investment advice, │ │
│ │ financial market │ │ to the user's │ but it is not a │ │
│ │ headlines?"} │ │ question. │ useful answer to │ │
│ │ │ │ │ the user's │ │
│ │ │ │ │ question. │ │
│ │ │ │ │ │ │
│ │ │ │ │ │ │
├──────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┼─────────────────────┼──────────┤
│ Averages │ │ │ judge_score: 0.000 │ 0.0% ✔ │ 469µs │
└──────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┴─────────────────────┴──────────┘
uv run python tests/regression_llm_judge_traces.py --sample-percent 10 --lookback-minutes 30
Trace selection: fetched=1 sampled=1 judging=1 lookback_minutes=30 sample_percent=10 max_traces=5
Trace case: trace_id=38fa3a54134d8818c7d7a5afbf50967e agent_id=financial_market_headlines prompt_version=1 answer_chars=654
Judging 1 trace(s) with openai:gpt-5.4
Evaluating task ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
Evaluation Summary: task
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Case ID ┃ Inputs ┃ Outputs ┃ Scores ┃ Assertions ┃ Duration ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ financial_market_… │ {'trace_id': │ Here are today's │ judge_score: 0.450 │ judge_pass: ✗ │ 441µs │
│ │ '38fa3a54134d8818c │ major financial │ Reason: The │ Reason: The │ │
│ │ 7d7a5afbf50967e', │ market headlines: │ response is │ response is │ │
│ │ 'agent_id': │ │ market-related and │ market-related │ │
│ │ 'financial_market_ │ 1. Wall Street's │ avoids investment │ and avoids │ │
│ │ headlines', │ riskiest trades │ advice, but it │ investment │ │
│ │ 'prompt_version': │ are suddenly back │ mostly lists │ advice, but it │ │
│ │ 1, 'agent_model': │ on top: Chart of │ article headlines │ mostly lists │ │
│ │ 'openai:gpt-4', │ the Day - Yahoo │ and links rather │ article headlines │ │
│ │ 'judge_model': │ Finance │ than providing a │ and links rather │ │
│ │ 'openai:gpt-5.4', │ [Link](https://fi │ useful summary of │ than providing a │ │
│ │ 'prompt': "What │ nance.yahoo.com/) │ the key financial │ useful summary of │ │
│ │ are today's major │ 2. S&P 500 │ market │ the key financial │ │
│ │ financial market │ notches │ developments. │ market │ │
│ │ headlines?"} │ record-high close │ │ developments. │ │
│ │ │ as rate-hike │ │ │ │
│ │ │ worries ease - │ │ │ │
│ │ │ Reuters │ │ │ │
│ │ │ [Link](https://ww │ │ │ │
│ │ │ w.reuters.com/mar │ │ │ │
│ │ │ kets/us/) │ │ │ │
│ │ │ 3. Treasury │ │ │ │
│ │ │ yields rise as │ │ │ │
│ │ │ U.S. threatens │ │ │ │
│ │ │ Iran with more │ │ │ │
│ │ │ economic │ │ │ │
│ │ │ sanctions - CNBC │ │ │ │
│ │ │ [Link](https://ww │ │ │ │
│ │ │ w.cnbc.com/) │ │ │ │
│ │ │ 4. Latest stock │ │ │ │
│ │ │ market, financial │ │ │ │
│ │ │ and business news │ │ │ │
│ │ │ - MarketWatch │ │ │ │
│ │ │ [Link](https://ww │ │ │ │
│ │ │ w.marketwatch.com │ │ │ │
│ │ │ /) │ │ │ │
│ │ │ 5. Latest finance │ │ │ │
│ │ │ and stock market │ │ │ │
│ │ │ news covering the │ │ │ │
│ │ │ Dow, S&P 500, │ │ │ │
│ │ │ banking, │ │ │ │
│ │ │ investing and │ │ │ │
│ │ │ regulation - WSJ │ │ │ │
│ │ │ [Link](https://ww │ │ │ │
│ │ │ w.wsj.com/finance │ │ │ │
│ │ │ ) │ │ │ │
├────────────────────┼────────────────────┼───────────────────┼────────────────────┼───────────────────┼──────────┤
│ Averages │ │ │ judge_score: 0.450 │ 0.0% ✔ │ 441µs │
└────────────────────┴────────────────────┴───────────────────┴────────────────────┴───────────────────┴──────────┘mar
{
"id": "financial_market_headlines",
"version": 2,
"agent": "websearch",
"prompt": "Use the web-search tool to find and verify today's major financial-market headlines. Report the 3 to 5 most consequential developments across equities, rates, currencies, commodities, or macroeconomic policy. For each item, state what happened, identify the affected market or region, explain briefly why it matters, and name the source with a link when available. Include the relevant date and units for numerical claims. Cross-check any surprising index level, percentage move, policy decision, or economic release against a second reliable source; if it cannot be verified, omit it or clearly label it as unconfirmed. State when the information was current, distinguish facts from developing reports or interpretation, and say when reliable current information is insufficient. Do not invent facts, present stale information as today's news, or give personalized investment advice.",
"contains": ["market"],
"max_model_requests": 4,
"min_tool_calls": 1,
"max_tool_calls": 7,
"judge_rubric": "The response should provide 3 to 5 current, consequential financial-market developments based on web research. Each item should identify what happened, the affected market or region, why it matters, and its source, preferably with a link. Numerical claims should include meaningful dates and units; surprising figures should be corroborated by a second reliable source or explicitly marked unconfirmed. The answer should state when the information was current, distinguish verified facts from developing reports or interpretation, and acknowledge insufficient evidence rather than inventing details. It must stay relevant, avoid stale news presented as current, avoid unsupported certainty, and avoid personalized investment advice. A polished but uncited answer containing an implausible or unverifiable market figure should fail."
},
Преобразование шаблона в CI/CD
При преобразовании шаблона в этап необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища конфиденциальных данных и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь граф процессов. Для операций, связанных с тратой денег или изменением производственных данных, необходимо предусмотреть утверждение человеком. Подключения, созданные во время компиляции, не гарантируют полноты охвата бизнес-процессов.
Ссылки
На этапе разработки ссылок необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо задокументировать как успешный, так и аварийный сценарии работы. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. Внедрять утверждение человеком для операций, связанных с тратой денег или изменением производственных данных. Настройка на этапе компиляции не заменяет полноты бизнес-логики.
Чек-лист операционной работы
Этап чек-листа операционной работы работает наилучшим образом, когда рассматривается как измеримая основа. Соберите один эталонный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ.
Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия всем элементам, определите критерии успеха и не допускайте молчаливого частичного завершения работ.
Сохраняйте состояние графа простым и типизированным. Вложенные структуры данных скрывают информацию о том, какой узел заполнил какое поле, и нарушают возможность продолжения работы после прерываний.
Оценивайте ответы, даные за один этап, и траектории, формирующиеся в несколько этапов, отдельно. Суммирование оценок чатов маскирует сбои в работе циклов обработки.
Напишите краткое руководство: как заменять ключи, как опустошать очередь, как откатывать последнюю загрузку данных.
Задокументируйте как успешный, так и восстановительный пути работы. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не последующими улучшениями.
Перед внедрением новой структуры сохраните версии, сделайте запись эталонного варианта работы для критических сценариев и убедитесь в наличии шагов для отката. В совместных средах необходимы ограничения на скорость обработки, проверки принадлежности ресурсов и четко определенный ответственный за замену секретов. Лучше надежность без изысков, чем красивые одноразовые демонстрации.
Примечание к пакету 4a86f3fd2d9a: не храните ключи поставщиков в репозитории, установите лимит токенов на сессию и сохраняйте транскрипции рядом с фиксами для оценки, чтобы последующие замены моделей оставались сопоставимыми.