eval_ph1 — 코드 아키텍처 맵
AutoGen 멀티에이전트 팀을 trace DB로 평가·개선하는 시스템의 전체 코드 구조 (도식·표·workflow)
repo kiyaaa/eval_ph1 100 py · 8,880 LOC 12 migrations
11 CLI 명령 49 팀 7 도메인 기준일 2026-06-16
🔬 한 단계 더 — 런타임 플로우 완전 해부 →
run_stream 한 건이 이벤트별로 mapping·logger·scorer를 지나 events/runs의 어느 컬럼에 떨어지는지, v1→v6 차이까지 raw 수준으로.
📈 v1→v6 개선 실제 과정 (실험 원장) →
각 버전이 겨냥한 실패·가설·1변수 개입·temp=0 A/B 측정·promoted/rejected 판정을 실제 experiments(EXP-37~148) 수치로.
🗃 데이터 라이프사이클 & 배치 카탈로그 →
어떤 컬럼이 phase별로 언제 저장되는지(시작 INSERT vs 종료 계산 vs 안 채움) + live DB 실제 배치 전수.
🔭 메트릭 발견 — 방법과 근거 (MAST·업계) →
더 유의미한 메트릭을 찾는 발견 루프 + corr 분리력 실측 + 왜 이 메트릭인지 내부증거×MAST/τ-bench 근거.
📊 전체 메트릭 카탈로그 (수집 + 도출) →
runs·events 원시 컬럼부터 집계 뷰·스코어러·검증 뷰 도출까지 ≈134개 신호를 5축(정확·비용·효율·근거·신뢰)으로 전수 정리 + 1순위 8종 + 겹침vs함의 통찰.
🧪 메트릭 가공·취합 레시피 (pass@1·k·p95) →
리포트 숫자 한 칸이 raw run/event→채점→runs UPDATE→REFRESH mv_* 4단계 중 어디서 어떤 SQL/코드로 만들어지는지 + mv vs live view 구분 + live DB 실측 검산.
1 시스템 아키텍처 — 한 장
cli → runner → registry(AC9) → teams → AutoGen run_stream → logger → DB(events/runs) → 집계 뷰 → report/Grafana. 개선은 experiments 원장을 거쳐 1변수씩 팀으로 되먹임.
cli.py · typer 11 commands (run/score/report/compare/failures/load-*/export-team)
runner.run_batch 동시성 Semaphore · runs 수명주기
registry.build_registered_team AC9 prompt_bundle_hash 가드
teams/ · 49 팀 P-E-C selector / RoundRobin / solo
tracing/logger (TraceLogger) + mapping (event→message_type)
도메인 scorer gaia·research·analysis·cppx·extract·sql·roles
runs success·tokens·latency
mv_batch_summary · mv_passk · mv_tool_summary + grounding 뷰 v_analysis_grounded 등
report.py · cli report/compare/failures
실행은 runner, 기록은 TraceLogger, 채점은 도메인 scorer, 집계는 mat view — 책임이 분리돼 있다
📋 ① 아키텍처 — 전체 용어 (도식 잘림 대비 텍스트 원문) flowchart TD
CLI["cli.py · typer 11 commands (run/score/report/compare/failures/load-* /export-team)"] --> RUN["runner.run_batch · 동시성 Semaphore · runs 수명주기"]
RUN --> REG["registry.build_registered_team · AC9 prompt_bundle_hash 가드"]
REG --> TEAM["teams/ · 49 팀 · P-E-C selector / RoundRobin / solo"]
TEAM --> AG["AutoGen run_stream"]
AG --> LOG["tracing/logger (TraceLogger) + mapping (event→message_type)"]
LOG --> EV[("events · 이벤트 시퀀스 trace")]
RUN --> SC["도메인 scorer · gaia·research·analysis·cppx·extract·sql·roles"]
SC --> RUNS[("runs · success·tokens·latency")]
EV --> MV["mv_batch_summary · mv_passk · mv_tool_summary + grounding 뷰 v_analysis_grounded 등"]
RUNS --> MV
MV --> REP["report.py · cli report/compare/failures"]
MV --> GRAF["Grafana 대시보드"]
REP --> EXP[("experiments · 개선 원장")]
EXP -.->|1변수 개입 → 새 team_id| TEAM
책임 분리 (핵심 설계). runner=runs 수명주기·동시성 · TraceLogger=events 적재·집계 · registry=팀 빌드·AC9 재현성 가드 · mapping=순수 변환 · 도메인 scorer=채점. 로깅 실패는 배치를 죽이지 않는다(fail-open).
3 CLI 명령 (cli.py)
narrate(LLM 서사 리포트)는 SPEC §0.3대로 의도적 미구현 (M6 이후).
4 실행 라이프사이클 + 트레이싱
cli run --team --batch --attempts
_select_tasks tasks WHERE benchmark
Semaphore(concurrency) task × attempt
_prepare_run_row INSERT runs(status=running)
build_team + build_run_message
TraceLogger.log_stream ← team.run_stream
events INSERT final_answer·tokens·latency 집계
score_fn(answer, gold) benchmark 분기
UPDATE runs(completed) success·format_valid·tokens·latency
db.refresh_views mv_* REFRESH
runs는 runner가 직접(running→completed), events는 TraceLogger 전담. 배치 종료 시 mv_* REFRESH
📋 ② 실행 라이프사이클 — 전체 용어 (도식 잘림 대비 텍스트 원문) flowchart LR
A["cli run · --team --batch --attempts"] --> B["_select_tasks · tasks WHERE benchmark"]
B --> C["Semaphore(concurrency) · task × attempt"]
C --> D["_prepare_run_row · INSERT runs(status=running)"]
D --> E["build_team + build_run_message"]
E --> F["TraceLogger.log_stream ← team.run_stream"]
F --> G["events INSERT · final_answer·tokens·latency 집계"]
G --> H["score_fn(answer, gold) · benchmark 분기"]
H --> I["UPDATE runs(completed) · success·format_valid·tokens·latency"]
I --> J["db.refresh_views · mv_* REFRESH"]
AutoGen 이벤트 → message_type 매핑 (tracing/mapping.py)
logger.py 핵심 (719 LOC). events 20컬럼 INSERT(content/tool_args/result/error는 jsonb) · 비밀 마스킹 단일지점 _mask_secrets(tool_args) · tool_call↔result 짝 은 call.id 전파로 보장(DB CHECK 아님) · content 8192/result 2048자 절단+sha256 · INSERT 실패는 warning만(fail-open).
5 도메인 × 스코어러 매트릭스
러너가 benchmark로 score_fn 분기(runner.py:257). 공통 시그니처 ScoreResult(success, format_valid). 정답성과 근거(grounding)는 별도 축 .
6 grounding 파이프라인 — "호출"이 아니라 "성공"
전 도메인 공통 철학: success(형식/정답) ⊥ grounded(실검색 근거) ⊥ recency(최신처럼 보임) . recency만으로는 "근거 없이 2026을 써넣은 환각"을 못 거른다.
web_tool.web_search Firecrawl /v1/search or DDG 폴백(키 없을 때)
events: tool_error 또는 '(검색 실패)'
grounding_guard is_grounded = n_search_ok≥1 AND not simulated
recency.py 약신호 as_of·current_year_ratio
hallucination_risk = recency≥0.5 AND not grounded
v_analysis_grounded grounded = 검색 성공(호출 아님)
score_analysis_grounding 배치 표 grounded%·risk
web_tool → events(tool_result/error) → grounding_guard(성공 기준) → v_analysis_grounded → 배치 채점. recency는 약신호로 hallucination_risk에만 기여
📋 ③ grounding 파이프라인 — 전체 용어 (도식 잘림 대비 텍스트 원문) flowchart LR
Q["analyst 검색 의도"] --> WT["web_tool.web_search · Firecrawl /v1/search · or DDG 폴백(키 없을 때)"]
WT -->|성공 결과| TR["events: tool_result"]
WT -->|실패·빈결과| TE["events: tool_error 또는 '(검색 실패)'"]
TR --> GG["grounding_guard · is_grounded = n_search_ok≥1 AND not simulated"]
TE --> GG
REC["recency.py 약신호 · as_of·current_year_ratio"] --> HR
GG --> HR["hallucination_risk = recency≥0.5 AND not grounded"]
GG --> VW["v_analysis_grounded · grounded = 검색 성공(호출 아님)"]
VW --> SCORE["score_analysis_grounding · 배치 표 grounded%·risk"]
이번 사건의 교훈 (코드에 반영됨). 키리스 DDG가 봇차단으로 실검색 0%였는데 모델이 2026을 환각 → migration 010이 v_analysis_grounded에서 grounded = n_search_ok≥1 (호출이 아닌 성공 )으로 재정의. grounding_guard.is_grounded = n_search_ok>0 AND not simulated, hallucination_risk = recency≥0.5 AND not grounded.
research 심화
generator.py — 합성 코퍼스 결정적 생성. 사실을 3개 문서에 분산 (person→team→project)해 멀티홉 강제. hard면 이름충돌 decoy 문서 추가.
corpus.py — 임베딩 없는 어휘 검색 도구(search_corpus, 폐쇄망·결정적). demote_inactive면 archived/disbanded 문서 강등(freshness 필터 모사).
claim_verify.py — gold 불필요 교차검증 (faithfulness): 인용 출처를 다른 모델(Claude)이 뒷받침 판정 → events.evaluator_score.
7 팀 카탈로그 — 49 피평가 팀
팀 = 피평가 단위(1급 객체). 모든 빌더 (settings, model_client)→(Team, meta). 1변수 개입 = 새 team_id (AC9). topology 분포: selector 11 · roundrobin-solo 9 · roundrobin-multi 27 · 어댑터 2 · swarm 0.
GAIA ladder (selector P-E-C)
research ladder (멀티홉 QA · search_corpus)
analyst flywheel (개방형 분석 · RoundRobin 4-agent)
⚠️ v4/v5/v6-analyst-web은 team_id와 모듈명(lite/cited/dedup)이 어긋남 — 모듈 컬럼 참조.
HQ (정밀·무결성, RoundRobin) · metric-demo · role · cppx · sql/extract
registry / AC9. TEAM_REGISTRY(team_id→빌더). ensure_team_record: DB hash ≠ 현재 prompt_bundle_hash면 즉시 TeamConfigMismatchError . config_full엔 도구 impl_sha 까지 기록(같은 이름 다른 구현 v1 vs v5 read_attached_file 구분).
8 DB 스키마 (PostgreSQL · 스키마 eval_ph1 · ORM 없음)
migration → 생성 객체
핵심 테이블 · 정합성 불변식
집계 패턴. 정확도(runs.success)와 독립적으로 근거품질(*_grounding)을 잰다. mv_*만 materialized → 배치 종료 시 REFRESH(안 하면 stale); v_* grounding 뷰는 일반 뷰(즉시 최신). "tool_call마다 result/error 존재"는 DB CHECK가 아니라 검증 SQL(NOT EXISTS=0행)로 보장.
9 리포팅 · 개선 플라이휠
3계층: L1 Grafana(추이) → L2 experiments 원장(구조화) → L3 narrate(서사, 미구현).
report.py — cli report/compare/failures가 import. mv_batch_summary/mv_passk/mv_tool_summary + runs/events 직접 읽어 텍스트 표.
experiments.py — record_start(가설·개입·before/after) → record_conclude(verdict·key_evidence·lesson). team FK라 팀 등록 선행.
플라이휠 : run 기록 → 메트릭 특이점 → 진단 → 1변수 개입(새 team_id) → matched A/B → promoted/rejected → 원장. (실측 EXP-40~70, 채택 13/기각 5/보류 2)
참고. 소스 단일 진실원 docs/SPEC.md · 절대규칙 CLAUDE.md · 재현 핸드오프 docs/INHOUSE_HANDOFF_REPRODUCE.md.
· 라이브 발표/대시보드: eval-presentation · Grafana .
· 이 페이지는 repo 코드 실측(100 py·8,880 LOC) 매핑 기반.