Кейс: совет подагентов OpenObserve
Updated Jul 2026
Вызов
OpenObserve, платформа наблюдаемости с открытым исходным кодом, написанная на Rust, столкнулась с критической проблемой: кодовая база с всего 380 тестами, многие из которых были нестабильными. Ручное написание тестов не поспевало за разработкой функциональности. Их решением стала мультиагентная система, ставшая одним из наиболее хорошо задокументированных реальных применений агентного тестирования.
Архитектура: восемь специализированных агентов
+------------------------+
| COUNCIL ORCHESTRATOR |
| (Test Plan Director) |
+-----------+------------+
|
+-------+-------+-------+---+---+-------+-------+-------+
| | | | | | | |
[1] [2] [3] [4] [5] [6] [7] [8]
Code Test Test Test Flaky Cov. Doc PR
Anal. Gen. Run. Fix. Detect Anal. Gen. Rev.
| Агент | Роль | Ключевая способность |
|---|---|---|
| Code Analyzer | Читает исходный код, определяет тестируемые функции | Составляет карту сигнатур функций, зависимостей, путей ошибок |
| Test Generator | Пишет новые тестовые сценарии | Использует анализ кода + спецификацию для создания Rust-тестов |
| Test Runner | Выполняет тесты, фиксирует результаты | Запускает cargo test, парсит stdout/stderr, сообщает pass/fail |
| Test Fixer | Исправляет падающие тесты | Читает сообщения об ошибках, определяет корневую причину, применяет исправление |
| Flaky Detector | Определяет недетерминированные тесты | Запускает каждый тест 5 раз, помечает несогласованные результаты |
| Coverage Analyzer | Измеряет покрытие кода, определяет пробелы | Запускает cargo tarpaulin, сообщает о непокрытых строках |
| Documentation Generator | Создаёт документацию к тестам | Создаёт документы тест-плана на основе набора тестов |
| PR Reviewer | Ревьюит PR с тестами перед слиянием | Проверяет качество, покрытие, соответствие стилю |
Результаты
| Метрика | До | После | Улучшение |
|---|---|---|---|
| Всего тестов | 380 | 700+ | +84% |
| Нестабильные тесты | -85% нестабильности | ||
| Покрытие кода | 34% | 58% | +24 процентных пункта |
| Время цикла тестирования | 45 мин (ручное) | 8 мин (автоматизированное) | -82% |
| Время ревью PR с тестами | 2-3 часа | 30 мин (предварительное ревью агентом) | -80% |
Ключевые проектные решения
1. Общая память с ограниченным контекстом
Каждый агент пишет в общий JSON-файл состояния, но читает только те разделы, которые релевантны его роли. Это предотвращает загрязнение контекста -- Test Runner не нуждается в полном выводе AST от Code Analyzer.
{
"code_analysis": {
"module": "src/handlers/search.rs",
"functions": [
{
"name": "execute_search",
"params": ["query: SearchQuery", "org_id: &str"],
"return_type": "Result<SearchResponse, Error>",
"error_paths": ["InvalidQuery", "PermissionDenied", "Timeout"],
"complexity": "high"
}
]
},
"test_generation": {
"generated_tests": ["..."],
"pending_review": ["..."]
},
"flaky_detection": {
"flagged_tests": ["test_search_timeout -- passed 3/5 runs"]
}
}
Почему ограниченный контекст важен: Когда Агент 2 (Test Generator) читает состояние, он загружает только code_analysis и test_generation. Он не загружает flaky_detection или coverage_analysis. Это держит промпт каждого агента сфокусированным и в пределах лимита токенов.
2. Шлюзы человеческого одобрения
Тесты не сливались автоматически. Агент PR Reviewer создавал pull request со структурированным резюме, и человек принимал окончательное решение о слиянии. Это сохраняло человека в контуре контроля качества.
Формат резюме PR:
## Agent-Generated Test PR
**Module:** src/handlers/search.rs
**Tests Added:** 12
**Tests Modified:** 3
**Coverage Change:** 34% → 41% (+7 pp)
### New Tests
- test_execute_search_valid_query (happy path)
- test_execute_search_invalid_query (error: InvalidQuery)
- test_execute_search_permission_denied (error: PermissionDenied)
- ... (9 more)
### Flaky Tests Fixed
- test_search_timeout: added explicit timeout mock (was relying on real network)
- test_concurrent_search: added mutex for shared test state
### Reviewer Notes
- All tests pass 5/5 runs
- Naming convention matches existing tests
- Fixtures reuse existing test helpers
3. Инкрементальное выполнение
Агенты не перегенерировали весь набор тестов при каждом запуске. Они анализировали, что изменилось (новые коммиты), определяли, что нуждается в новых тестах, и генерировали инкрементально.
class IncrementalAnalyzer:
def identify_changes(self, since_commit: str) -> list[Change]:
"""Find what changed since the last agent run."""
diff = git_diff(since_commit, "HEAD")
changed_functions = []
for file_change in diff:
if file_change.path.endswith(".rs") and "test" not in file_change.path:
# Source file changed -- needs test update
changed_functions.extend(
self.extract_changed_functions(file_change)
)
return changed_functions
Это делало стоимость токенов управляемой. Вместо анализа всей кодовой базы (миллионы токенов), каждый запуск анализировал только дельту (тысячи токенов).
Извлечённые уроки
1. Снижение нестабильности тестов стало главной победой
Агент Flaky Detector выявил тесты, которые люди игнорировали месяцами. Запуск каждого теста 5 раз и пометка несогласованностей устранил накопленный технический долг.
Как работает Flaky Detector:
class FlakyDetector:
def detect(self, test_name: str, runs: int = 5) -> FlakyReport:
results = []
for i in range(runs):
result = run_single_test(test_name)
results.append(result)
pass_count = sum(1 for r in results if r.passed)
fail_count = runs - pass_count
if 0 < fail_count < runs: # Mix of pass and fail = flaky
return FlakyReport(
test_name=test_name,
status="flaky",
pass_rate=pass_count / runs,
failure_reasons=self.analyze_failures(results)
)
return FlakyReport(test_name=test_name, status="stable")
Обнаруженные типичные причины нестабильности:
- Тесты, зависящие от реальных сетевых таймаутов
- Тесты, разделяющие мутабельное состояние через глобальные переменные
- Тесты, зависящие от порядка итерации HashMap (в Rust HashMap не упорядочены)
- Тесты, зависящие от временных меток файловой системы
2. Специализация агентов имеет значение
Ранние попытки с одним агентом «делай всё» давали посредственные результаты. Одиночный агент пытался анализировать код, генерировать тесты, запускать их и исправлять ошибки в одном цикле. Он терял контекст, принимал непоследовательные решения и производил результат более низкого качества, чем специализированная команда.
Одиночный агент (ранний подход): Средний показатель качества тестов: 62/100 Восемь специализированных агентов (финальный подход): Средний показатель качества тестов: 84/100
3. Агент Test Fixer оказался самым сложным
Ему нужно было понимать:
- Ошибки компилятора Rust (несовпадения типов, нарушения borrow checker)
- Формат вывода тестового фреймворка (stdout/stderr
cargo test) - Разницу между «ошибкой теста» и «ошибкой приложения»
Критически важный промпт для Test Fixer:
You are fixing a failing Rust test. Determine whether this is:
A) A TEST BUG: the test code is wrong (wrong assertion, missing import,
type mismatch, incorrect fixture setup). FIX the test.
B) AN APPLICATION BUG: the production code is wrong and the test correctly
detected it. DO NOT fix the test. REPORT the application bug.
Error output:
{cargo_test_stderr}
Test code:
{test_code}
Production code:
{source_code}
4. Контроль стоимости потребовал явного управления бюджетом
Без ограничений агенты итерировали бы бесконечно над крайними случаями. Был реализован бюджет токенов на модуль:
MODULE_BUDGETS = {
"src/handlers/": 100_000, # High-complexity, more budget
"src/models/": 50_000, # Medium complexity
"src/utils/": 25_000, # Low complexity, simple functions
}
Когда бюджет модуля исчерпывался, агенты прекращали работу над ним и переходили к следующему модулю. Это вынуждало расставлять приоритеты: модули с высокой сложностью получали больше внимания.
Применение уроков OpenObserve к вашим проектам
| Практика OpenObserve | Как применить | Минимальный размер команды |
|---|---|---|
| Специализированные агенты | Начните с 3: Analyzer, Generator, Runner | 1 инженер |
| Общий файл состояния | Используйте JSON-файл или базу данных SQLite | 1 инженер |
| Шлюзы человеческого одобрения | Требуйте PR-ревью для тестов, сгенерированных агентом | 1 инженер |
| Инкрементальное выполнение | Анализируйте только файлы, изменившиеся с последнего запуска | 1 инженер |
| Обнаружение нестабильности | Запускайте тесты 3-5 раз перед слиянием | 1 инженер |
| Бюджеты токенов | Установите лимиты на модуль в конфигурации | 1 инженер |
Ключевой вывод
Кейс OpenObserve доказывает, что мультиагентное тестирование работает в продакшене в масштабе. Ключевыми факторами стали специализация агентов (восемь сфокусированных агентов превзошли одного общего), шлюзы с участием человека (агенты предлагают, люди одобряют), инкрементальное выполнение (анализ дельт, а не всей кодовой базы) и явный контроль стоимости (бюджеты токенов на модуль). Снижение нестабильных тестов на 85% стало самым значимым результатом.