#!/usr/bin/env python3 """PR-DocSrv-Hier-PassageRAG-Diagnose-1 c3 — /ask capture for prehier vs hier_sim_clean. 각 Q × variant 호출 → JSONL 박제 (judge 입력 raw). EVAL-ONLY.""" import json, sys, time, os import httpx, yaml BASE = "http://100.110.63.63:8000" VARIANTS = ["prehier", "hier_sim_clean"] SUBSET = "tests/search_eval/queries_passage_rag.yaml" def trim_citations(cits): out = [] for c in cits or []: out.append({k: c.get(k) for k in ("n", "doc_id", "chunk_id", "section_title", "span_text", "rerank_score")}) return out def main(): token = os.environ["DOCSRV_TOKEN"] out_path = sys.argv[1] if len(sys.argv) > 1 else "reports/passage_rag_capture.jsonl" d = yaml.safe_load(open(SUBSET)) queries = d["queries"] recs = [] with httpx.Client(timeout=90.0) as cli: for q in queries: g2 = set(q.get("targets_g2") or []) for variant in VARIANTS: params = {"q": q["query"], "debug": "true", "corpus_variant": variant, "exact_knn": "true"} t0 = time.perf_counter() try: r = cli.get(f"{BASE}/api/search/ask", headers={"Authorization": f"Bearer {token}"}, params=params) lat = (time.perf_counter() - t0) * 1000 r.raise_for_status() data = r.json() except Exception as exc: print(f" ✗ {q['id']}/{variant}: {type(exc).__name__}: {repr(exc)[:120]}", flush=True) recs.append({"q_id": q["id"], "variant": variant, "error": f"{type(exc).__name__}"}) continue cits = trim_citations(data.get("citations")) used = data.get("used_citations") or [c.get("n") for c in (data.get("citations") or []) if c.get("n")] cited_docs = {c["doc_id"] for c in cits if c.get("doc_id")} target_doc_present = bool(cited_docs & g2) # cited span from a target doc that actually appears in the answer (used citation) used_set = set(used or []) target_span_used = any((c.get("doc_id") in g2) and (c.get("n") in used_set) for c in cits) ans = data.get("ai_answer") or "" rec = { "q_id": q["id"], "category": q["category"], "query": q["query"], "variant": variant, "targets_g2": sorted(g2), "targets_g3": q.get("targets_g3"), "answer_hint": q.get("notes"), "ai_answer": ans, "answer_len_chars": len(ans), "evidence": cits, "used_citations": sorted(used_set), "cited_docs": sorted(cited_docs), "target_doc_present": target_doc_present, "target_span_used_in_citation": target_span_used, "synthesis_status": data.get("synthesis_status"), "completeness": data.get("completeness"), "covered_aspects": data.get("covered_aspects"), "missing_aspects": data.get("missing_aspects"), "confidence": data.get("confidence"), "refused": data.get("refused"), "backend_used": data.get("backend_used"), "synthesis_ms": data.get("synthesis_ms"), "latency_ms": round(lat, 1), "debug": data.get("debug"), } recs.append(rec) print(f" ✓ {q['id']}/{variant}: ans_len={len(ans)} cited={sorted(cited_docs)} " f"tgt_present={target_doc_present} tgt_used={target_span_used} status={data.get('synthesis_status')}", flush=True) with open(out_path, "w") as f: for rec in recs: f.write(json.dumps(rec, ensure_ascii=False) + "\n") print(f"\nwrote {len(recs)} records → {out_path}") if __name__ == "__main__": main()