fix: wrap diagnosis run_log with StepsJsonRunLog (restore algo #7 traces)
This commit is contained in:
@@ -2168,13 +2168,15 @@ class Runner:
|
||||
self, run_id: str, *, question_ids: list[str] | None = None
|
||||
) -> DiagnosisResult:
|
||||
"""执行两阶段诊断。"""
|
||||
from app.harness.baseline_run_log import StepsJsonRunLog
|
||||
from app.harness.log import RunLogImpl
|
||||
from app.harness.workspace import VersionedSkillStore
|
||||
from app.question_gen import load_benchmark
|
||||
from core.evolution.diagnose import run_diagnosis
|
||||
|
||||
questions = load_benchmark(self._paths.questions_dir)
|
||||
run_log = RunLogImpl(str(self._paths.db_path))
|
||||
# traces 表空时(如训练 rollout 只落 steps_json)从 steps_json 重建轨迹,恢复算法 #7
|
||||
run_log = StepsJsonRunLog(RunLogImpl(str(self._paths.db_path)))
|
||||
skill_store = VersionedSkillStore(self._paths.skills_dir)
|
||||
diagnose_prompts = self._load_diagnose_prompts()
|
||||
|
||||
|
||||
@@ -147,6 +147,70 @@ def _fake_question(question_id: str, video_id: str) -> object:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_diagnosis_reads_traces_from_steps_json(
|
||||
runner_with_real_store: Runner,
|
||||
) -> None:
|
||||
"""traces 表为空但 predictions.steps_json 有轨迹时,诊断仍拿到非空 traces。
|
||||
|
||||
构造一条只写 steps_json、不写 traces 表的 predictions 行;patch run_diagnosis
|
||||
捕获传入的 run_log,直接 await 其 get_traces 断言经 StepsJsonRunLog 从
|
||||
steps_json 重建出非空轨迹(算法 #7 恢复)。
|
||||
"""
|
||||
from app.harness.inference import PREDICTIONS_SCHEMA
|
||||
from app.harness.log import HarnessLog
|
||||
|
||||
steps_json = json.dumps(
|
||||
[
|
||||
{
|
||||
"thought": "先看整体",
|
||||
"tool_call": {"tool": "search_tree", "args": {"query": "开场"}},
|
||||
"tool_output": "命中 L2 节点 A",
|
||||
}
|
||||
],
|
||||
ensure_ascii=False,
|
||||
)
|
||||
with HarnessLog(str(runner_with_real_store._paths.db_path), "infer_adhoc") as log:
|
||||
log.create_table("predictions", PREDICTIONS_SCHEMA)
|
||||
log.create_table("traces", {"video_id": "TEXT", "question_id": "TEXT", "step": "INTEGER"})
|
||||
log.insert(
|
||||
"predictions",
|
||||
{
|
||||
"video_id": _REAL_VIDEO_ID,
|
||||
"question_id": _REAL_QUESTION_ID,
|
||||
"task_type": "Action Reasoning",
|
||||
"prediction": "A",
|
||||
"answer": "B",
|
||||
"evidence": "",
|
||||
"reasoning": "",
|
||||
"steps_used": 1,
|
||||
"prompt_tokens": 0,
|
||||
"completion_tokens": 0,
|
||||
"stop_reason": "finished",
|
||||
"steps_json": steps_json,
|
||||
},
|
||||
)
|
||||
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
async def _fake_run_diagnosis(**kwargs: object) -> DiagnosisResult:
|
||||
captured["run_log"] = kwargs["run_log"]
|
||||
return _empty_diagnosis_result()
|
||||
|
||||
with patch(
|
||||
"core.evolution.diagnose.run_diagnosis",
|
||||
new=AsyncMock(side_effect=_fake_run_diagnosis),
|
||||
):
|
||||
await runner_with_real_store._run_diagnosis(
|
||||
"infer_adhoc", question_ids=[_REAL_QUESTION_ID]
|
||||
)
|
||||
|
||||
run_log = captured["run_log"]
|
||||
traces = await run_log.get_traces("infer_adhoc", question_ids=[_REAL_QUESTION_ID])
|
||||
assert traces, "traces 表空时应从 steps_json 重建出非空轨迹"
|
||||
assert traces[0]["tool_name"] == "search_tree"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_diagnosis_full_scan_loads_all_video_trees(
|
||||
runner_with_real_store: Runner,
|
||||
|
||||
Reference in New Issue
Block a user