Методика измерений: версия для чтения. Оригинал на английском: benchmarks/retrieval/README.md, ревизия репозитория 61e75e9aa9a8719dfb480bf1f5226553b3a21d70 (2026-10-04). Перевод сохраняет методику, даты, измерения и статус, зафиксированные в этой ревизии. Приведённые прошлые результаты относятся к описанным запускам и не гарантируют производительность текущего продукта или качество ответов модели.
Этот инструмент для разработчиков сравнивает старый MCP-инструмент буквального поиска search_concepts с новым лексическим поиском search_sections на одних и тех же искусственных Markdown-документах и 24 заранее заданных запросах: 20 с ответом и четыре без ответа, на английском и русском языках. Он измеряет поиск и привязку результатов к источникам. Качество ответов языковой модели, выдуманные сведения и готовность агента вызывать инструмент здесь не измеряются.
Документы и эталонные подтверждения были зафиксированы до реализации поиска по разделам. Не меняйте testdata/corpus, testdata/queries.json или testdata/freeze.json, чтобы улучшить результаты. Для нового набора нужны новая фиксация и новое базовое измерение; исходные строки результатов следует сохранить. Файл testdata/freeze.json в репозитории побайтно совпадает с исходной записью происхождения .cursor/tasks/evidence/016/corpus-freeze.json. Поэтому запуск воспроизводится из свежей копии репозитория без локального каталога задачи, исключённого из Git.
Запускайте команды из корня репозитория. Нужны Go 1.25.5 или новее, Git и Python 3. Поставщик моделей и внешний сервис не требуются. Команды ниже собирают настоящий базовый сервер из коммита 8e822ea631caaac058fb40aa65c5821352048278, а итоговый — из текущего рабочего дерева, включая незакоммиченные изменения. Создавать коммит не требуется. Временные файлы и кеш Go остаются вне репозитория.
work=$(mktemp -d /tmp/okf-retrieval.XXXXXX)
mkdir "$work/baseline-source" "$work/go-cache"
git archive 8e822ea631caaac058fb40aa65c5821352048278 | tar -x -C "$work/baseline-source"
GOCACHE="$work/go-cache" go -C "$work/baseline-source" build -o "$work/baseline-mcp" ./cmd/okf-mcp
GOCACHE="$work/go-cache" go build -o "$work/final-mcp" ./cmd/okf-mcp
GOCACHE="$work/go-cache" go build -o "$work/eval" ./benchmarks/retrieval/cmd/okf-retrieval-eval
GOCACHE="$work/go-cache" go test ./benchmarks/retrieval/cmd/okf-retrieval-eval -count=1
go version
uname -a
"$work/eval" --server "$work/baseline-mcp" --tool search_concepts --output "$work/baseline.json"
"$work/eval" --server "$work/final-mcp" --tool search_sections --output "$work/final.json"
python3 - "$work/baseline.json" "$work/final.json" <<'PY'
import json, statistics, sys
reports = [json.load(open(p)) for p in sys.argv[1:]]
for path, report in zip(sys.argv[1:], reports):
rows = report['rows']
print(path)
print('Hit@5:', report['hit_at_5'], 'MRR@5:', report['mrr_at_5'])
print('No-answer nonempty:', report['no_answer_nonempty'], '/', report['no_answer'])
print('mean/median latency ms:', statistics.mean(r['latency_ns'] for r in rows)/1e6,
statistics.median(r['latency_ns'] for r in rows)/1e6)
print('mean/max response bytes:', statistics.mean(r['response_bytes'] for r in rows),
max(r['response_bytes'] for r in rows))
baseline, final = reports
assert baseline['queries_sha256'] == final['queries_sha256']
assert baseline['frozen_corpus_sha256'] == final['frozen_corpus_sha256']
assert baseline['expected_snapshot_revision'] == final['expected_snapshot_revision']
assert final['hit_at_5'] >= baseline['hit_at_5']
assert final['mrr_at_5'] >= baseline['mrr_at_5']
assert final['hit_at_5'] > baseline['hit_at_5'] or final['mrr_at_5'] > baseline['mrr_at_5']
print('Retrieval acceptance gate passed on this frozen corpus.')
PY
Файл, указанный в --output, не должен существовать: инструмент отказывается перезаписывать отчёт. Абсолютный путь к каталогу OKF передаётся обоим серверам в аргументах MCP-инструмента. Сам сервер stdio не принимает аргумент -root. По умолчанию используются указанные выше пути к зафиксированным документам, запросам и манифесту. Необязательные --bundle, --corpus, --freeze позволяют перенести их, только если точные байты и перечень файлов по-прежнему соответствуют манифесту.
До запуска любого сервера инструмент проверяет все зафиксированные SHA256, общую контрольную сумму манифеста, точный перечень файлов, а также каждый вручную заданный эталонный заголовок, физическую строку и подтверждение внутри раздела. При расхождении запуск прерывается. Для нового поиска дополнительно проверяются идентификаторы заметок и путей в каждом результате, включительный диапазон физических строк и конец раздела, заголовок, указатель с процентным кодированием, SHA256 источника, непустой фрагмент текста и ревизия снимка всего каталога OKF. Проверка рассчитана на простые ATX-заголовки этого фиксированного набора. Она не заменяет проверки парсера продукта на блоках кода и других формах Markdown-заголовков.
Каждый вариант запускает новый сервер stdio, инициализирует MCP, затем выполняет каждый запрос один раз в одинаковом порядке с limit: 5. Повторные результаты одного документа удаляются с сохранением первого появления; так получается упорядоченный список максимум из пяти документов. Hit@5 и MRR@5 используют места в этом списке документов и заданные эталонные идентификаторы заметок. Несколько разделов одного документа занимают общий для обоих вариантов лимит в пять результатов, поэтому новый поиск может вернуть меньше разных документов. Полнота поиска по разделам здесь не измеряется: эталонные разделы нужны для проверки подтверждений и привязки к источникам, а не для второй метрики. Случаи без ответа учитываются только в no_answer_nonempty и не входят в знаменатель ни одной из двух метрик.
Задержка — одно измерение прошедшего времени на вызов инструмента: от отправки tools/call до получения результата MCP. Она включает выполнение инструмента, межпроцессное взаимодействие и декодирование JSON, но исключает запуск сервера, инициализацию и проверки привязки к источникам и оценки результата. Повторных попыток и прогревочных запусков нет. Средние значения и медианы описывают этот единственный последовательный запуск; они не доказывают статистически значимую разницу в скорости. Размер ответа — размер сериализованного объекта результата MCP, включая содержимое и структурированное содержимое, без внешней оболочки JSON-RPC. Он измеряется одинаково для обоих вариантов. Количество токенов не оценивается.
Каждый JSON-отчёт содержит все исходные ответы MCP, строки результатов, итоговые оценки, контрольные суммы запросов и документов, ожидаемую ревизию источников и фактическую SHA256 исполняемого файла сервера. Сохраните отчёты вместе с командами, сведениями о машине и версии Go, базовым коммитом и контрольной суммой изменений итогового рабочего дерева в материалах проверки задачи. Сохраняйте исходные строки, чтобы метрики можно было пересчитать без повторного поиска.