2026년 4월 29일 | 개인 프로젝트 GraphRAG
GraphRAG profile_eval에서 history mismatch report를 열 때마다 한 번 더 손이 갔다. 지난 반복에서 이미 query_set, quality_gate, dataset, top_k 같은 mismatch reason을 section으로 접어 두긴 했다. 그런데 실제로 report를 읽다 보면 reason을 확인한 뒤에도 곧바로 다른 값을 다시 봐야 했다. 이 mismatch가 단순히 기준선이 달라진 흔적인지, 아니면 같은 순간에 profile의 PASS/WARN/HARD-FAIL 상태도 흔들린 건지 한 화면에서 바로 안 보였기 때문이다.
그래서 이번 작업은 점수를 더 올리는 쪽이 아니라, 읽는 순서를 한 칸 더 줄이는 쪽으로 잡았다. history mismatch report 안에 각 profile의 history_context를 같이 넣었다. 이제 reason section을 열면 해당 profile이 compatible history 안에서 어떤 상태 전이를 보였는지, warning scope가 늘었는지, hard-fail scope가 늘었는지까지 같이 볼 수 있다.
왜 상태 전이를 같이 붙였나
처음에는 mismatch reason만 있으면 충분할 줄 알았다. 예를 들어 query_set mismatch가 잡히면 “아, 질문 세트가 달라졌구나” 하고 넘기면 될 것 같았다. 그런데 GraphRAG 실험이 조금 길어지니 이 판단이 그렇게 단순하지 않았다. 같은 날에 query set도 바뀌고, quality gate도 바뀌고, profile 점수도 흔들릴 수 있다. 이때 report가 이유만 말해 주면 다시 history sequence와 failure scope 목록을 열어야 한다.
내가 보고 싶었던 건 더 작은 질문이었다. 이 mismatch reason은 어떤 상태 변화와 같이 나타났나? 만약 WARN->HARD-FAIL 같은 전이가 동시에 보이면 바로 trace diff를 열어야 한다. 반대로 WARN->WARN으로 그대로라면, 우선 기준선 mismatch를 기록해 두고 실제 검색 품질 변화는 더 천천히 봐도 된다. 이 차이가 생각보다 작업 리듬을 많이 바꾼다.
이번에 추가한 필드
이번 변경의 핵심은 report를 크게 만드는 것이 아니다. query별 trace를 다시 복제하지 않고, profile-level에서 필요한 얇은 값만 붙였다. 내가 넣은 값은 다음과 같다.
| 필드 | 읽는 의미 |
|---|---|
| display_status_transition | 직전 compatible run에서 현재 run으로 넘어올 때 PASS/WARN/HARD-FAIL이 어떻게 변했는지 본다. |
| severity_delta | 상태가 나빠졌는지, 좋아졌는지, 그대로인지 숫자로 접는다. |
| top1_hit_rate_delta | 기대 문서 top-1 적중률이 compatible history 안에서 얼마나 움직였는지 남긴다. |
| warning_scope_delta | warning failure scope가 늘었는지 줄었는지 확인한다. |
| hard_fail_scope_delta | hard-fail failure scope가 늘어난 profile을 먼저 열 수 있게 한다. |
이 값들은 report의 profiles[]에도 들어가고, reason_sections[].profiles[]에도 같이 들어간다. 이유별로 먼저 접어 들어가도 상태 전이를 잃지 않게 한 셈이다. 여기에 section 단위 요약으로 transition_counts, warning_scope_growth_count, hard_fail_scope_growth_count도 붙였다.
이번 기준선에서 확인한 결과
기존 iter22 quality history를 복사해 iter23을 다시 돌렸다. 샘플에서는 오래된 iter18-query-set-probe 하나가 계속 query set mismatch로 잡힌다. 이번 run에서도 default, relation_weight_dense, path_bridge_probe, path_bridge_focus 네 profile 모두 같은 mismatch를 감지했다.
다만 중요한 건 상태 쪽이다. compatible history 안에서는 상태가 그대로 유지됐다. default와 dense는 PASS->PASS, probe는 WARN->WARN, focus는 HARD-FAIL->HARD-FAIL로 남았다. 그래서 이번 report의 transition summary는 PASS->PASS:2, WARN->WARN:1, HARD-FAIL->HARD-FAIL:1처럼 나온다. mismatch는 있지만 품질 상태가 새로 악화된 run은 아니라고 먼저 판단할 수 있었다.
테스트에는 조금 더 날카로운 synthetic case를 넣었다. compatible history에서는 path_bridge_probe를 일부러 HARD-FAIL로 두고, 현재 run에서는 WARN이 되게 만든 뒤, 동시에 오래된 entry 하나가 query_set mismatch로 잡히도록 했다. 이 경우 reason section 안의 context가 HARD-FAIL->WARN, severity_delta=-1, hard_fail_scope_delta=-1을 같이 들고 있어야 한다. 이 테스트가 통과하면서, 단순 flat line뿐 아니라 상태가 실제로 좋아지거나 나빠지는 장면도 같은 report로 읽을 수 있게 됐다.
작게 보이지만 읽는 비용이 줄어든 지점
이런 작업은 겉으로 보기엔 아주 작은 JSON 필드 추가다. 하지만 GraphRAG 실험처럼 profile, query set, gate, trace가 동시에 움직이는 프로젝트에서는 이런 작은 연결이 꽤 중요하다. 내가 싫어하는 상황은 “어디선가 WARN이 HARD-FAIL로 바뀌었는데, 그게 진짜 성능 악화인지 기준선 변경 때문인지 다시 손으로 맞춰 보는 일”이다. 이번 변경은 그 수동 대조를 줄이려는 쪽에 가깝다.
특히 failure scope는 숫자 평균보다 더 실무적인 신호다. top1_hit_rate가 그대로여도 특정 cluster나 tag에서 warning scope가 늘면, 다음 실험에서 그 family를 먼저 봐야 한다. 반대로 mismatch reason은 있는데 scope growth가 0이면, 지금은 score 튜닝보다 기준선 기록을 정리하는 쪽이 더 먼저일 수 있다.
이번 작업 후 남은 메모
이번 변경으로 history mismatch report는 네 가지 질문에 답하게 됐다. 어떤 profile에서 mismatch가 있었나, 어떤 reason이 원인이었나, 그 reason이 어떤 상태 전이와 같이 나타났나, failure scope가 늘어난 profile을 먼저 열어야 하나. 이 네 가지가 한 파일 안에 들어오니, 다음번 profile 비교를 읽는 순서가 꽤 단순해졌다.
다음 단계는 이 context report를 샘플 데이터셋에만 두지 않고 실제 운영 query set 쪽에도 붙이는 것이다. 그리고 reason section 안에서 scope growth가 있는 profile만 별도 queue로 한 번 더 줄이면 좋겠다. 지금은 “보인다”까지 왔고, 다음은 “먼저 열 것만 남긴다”로 가면 된다.
커밋 기준으로는 Add GraphRAG history mismatch context로 정리했다. 테스트는 pipeline과 profile_eval 묶음으로 28개를 돌렸고, 이번 반복에서는 전부 통과했다. 큰 기능은 아니지만, GraphRAG 트랙이 점점 “검색을 잘하는지”보다 먼저 “실험을 다시 읽을 수 있는지”를 갖춰 가는 느낌이 든다. 나는 이 순서가 아직은 맞다고 본다.
'[AI 실험실] > [개인 프로젝트] GraphRAG' 카테고리의 다른 글
| GraphRAG | Stale origin action queue 추가 (0) | 2026.05.07 |
|---|---|
| GraphRAG | Same-status stale queue 추가 (0) | 2026.05.06 |
| GraphRAG | Stale transition split 추가 (0) | 2026.05.02 |
| GraphRAG | History stale status queue 추가 (0) | 2026.05.01 |
| GraphRAG | History namespace 분리 (0) | 2026.04.30 |