src/agentcompass/runtime/results/store.py 中的 RunStore,明细结构整理逻辑位于 detail.py,聚合逻辑位于 summary.py,经过校验的指标类型位于 src/agentcompass/runtime/metrics/。
结果目录与持久化边界
RunStore 预留以下目录结构:
output.run_name、Model ID 和运行 ID 部分会在使用前规范化;Benchmark 目录使用已选中的注册 Benchmark ID。显式 run_id 对应的目录不能已经存在;未指定时,存储模块会生成基于时间戳的 ID,并在需要时递增,以原子方式预留唯一目录。
核心产物如下:
进度报告器与 runtime 日志注册表会把进度和日志路径加入返回的
paths 映射。
RunRequest.to_task_payload 序列化完整的执行请求,并在 metadata 非空时包含它;run_info.json 保存脱敏后的序列化数据。RunRequest.to_persistence_params 只提供存储与复用所需的 Benchmark、Model、输出、复用和元数据值,params.json 再将其压缩为脱敏后的 Benchmark、Model 与输出数据。Harness、Environment 和执行设置应查看 run_info.json.request。
疑似敏感的字段和值会在持久化边界被替换。已解析的计划使用明确的字段白名单视图,而不是转储完整的 ExecutionPlan。增加持久化字段时,既要确认它对可复现性确有必要,也要确认嵌套凭证不会随之泄漏。
结果层级
不要把所有结果都当成RunResult。各层的生成方、职责和持久化位置如下:
RunResult 定义在 src/agentcompass/runtime/models/ 下的 result.py。
save_partial_result 会立即以原子方式写入任务明细。它递归脱敏密钥,使用暂存文件与 fsync,防止并发写入覆盖已有正常结果,并在后续成功时移除过期的 _error_ 文件。
Benchmark.aggregate_metrics 返回的请求指标必须通过 MetricResult 校验:包含 schema_version、metrics 中至少一个有限数值,以及 counts.total、counts.evaluated、counts.error 和可选的 details、extra。这些请求级对象都不是任务 RunResult。
结果复用
选择来源。RunRuntimeSpec 包含 reuse 与 reuse_run_id,非空 reuse_run_id 会自动启用复用。
在任何编排请求预留输出目录前,Orchestrator._preflight 都会调用 UnifiedEvaluationRuntime.freeze_reuse_source,避免隐式查找误选同一次编排先前创建的运行目录。
源查找遵循以下规则:
- 设置
reuse_run_id时,使用当前运行名称、Benchmark 和 Model 根目录下的对应目录,不存在则失败; reuse=True且未指定 ID 时,选择该根目录下包含run_info.json的最新目录;- 隐式复用找不到源时,该请求会禁用复用并作为新运行继续;
- 多个
launch请求共用同一 Benchmark 与 Model 时,系统无法确定隐式复用源,应为每个请求指定明确的源 ID。
run_info.json,或明确指定已知来源。
物化任务明细。 RunStore.materialize_reused_details 始终以新预留的运行目录为目标:
- 为当前选中的每个
task_id查找正常明细文件,优先使用包含对应类别的文件名; - 将源文件硬链接到新的
details/,无法链接时回退到shutil.copy2; - 忽略缺失的任务和全部
_error_文件; - 使用
load_partial_results加载已放入新目录的正常明细; - 只调度新运行中没有正常明细的任务 ID。
run_info.json.reused_from 记录源运行 ID 与路径,源运行保持不变。
兼容性规则
持久化的明细文件会被复用、用于重新生成摘要、分析以及供外部工具读取。修改时应遵循:- 数据集每次加载都保持
task_id稳定; - 尽量以新增方式扩展尝试字段,并提供兼容默认值;
- 保持正常文件与
_error_文件名的语义; - 将重试诊断留在
details/之外; - 既测试写入新运行,也测试读取已有运行目录;
- 让
MetricResult.counts与实际分母保持一致; - 保留原子写入与递归脱敏。
