[AI 실험실]/[개인 프로젝트] GraphRAG / GraphRAG | History scope growth queue 추가.md

GraphRAG | History scope growth queue 추가

조회

시리즈: GraphRAG 구축기 #7

이전: 6편 | 목록 | 다음: 8편

2026년 4월 30일 | 개인 프로젝트 GraphRAG


GraphRAG profile_eval의 history 쪽을 다시 만지다 보니, 내가 계속 같은 곳에서 헷갈린다는 걸 알았다. 상태가 WARN인지 HARD-FAIL인지 보는 것까지는 좋은데, 막상 다음에 어디를 열어야 하는지는 여전히 한 번 더 손으로 골라야 했다. 특히 baseline mismatch가 같이 잡히는 날에는 더 그렇다. query set이 달라진 건지, gate 기준이 달라진 건지, 아니면 정말 실패 범위가 새로 넓어진 건지를 한 화면에서 나눠 보고 싶었다.

그래서 이번 반복에서는 history report에 scope growth queue를 하나 더 붙였다. 이름은 조금 길지만 역할은 단순하다. compatible history 기준으로 warning scopehard-fail scope가 새로 늘어난 profile만 따로 모아 두는 파일이다. 상태 전이를 모두 다시 읽기 전에, 실패 범위가 커진 후보부터 먼저 여는 작은 inspection queue라고 보면 된다.

GraphRAG history scope growth queue 흐름도

Figure 1: history summary, baseline mismatch report, scope growth queue를 나눠 읽는 흐름

1. 상태 전이만으로는 부족했던 지점

지난번에는 history mismatch context를 붙였다. baseline mismatch report 안에 reason section을 만들고, 각 section 안에 profile별 status transition을 같이 넣었다. 이 덕분에 query_set mismatch가 있는지, quality_gate mismatch가 있는지, 그리고 그때 상태가 PASS에서 WARN으로 내려갔는지 같은 정보는 바로 보이게 됐다.

그런데 실제로 다시 실행해 보니 내 관심은 조금 더 좁았다. 상태가 WARN→WARN으로 유지됐더라도 warning scope가 하나 늘었으면 그 profile은 다시 열어야 한다. 반대로 query_set mismatch가 남아 있어도 warning scope와 hard-fail scope가 그대로라면, 그 profile은 당장 trace diff를 열 우선순위가 낮다. 즉 내가 필요했던 건 상태 전이 전체가 아니라 실패 범위가 새로 커진 항목이었다.

2. 이번에 붙인 작은 queue

이번 구현은 크게 복잡하지 않게 잡았다. profile별 history summary를 읽고, 이전 run과 최신 run의 failure scope 목록을 비교한다. 여기서 warning_scope_delta > 0 또는 hard_fail_scope_delta > 0인 profile만 새 report에 넣는다. report 안에는 profile 이름, status transition, 새로 생긴 warning scope, 새로 생긴 hard-fail scope, baseline mismatch reason을 같이 남겼다.

내가 의도한 사용 순서는 이렇다.

  • history_summary에서 profile별 PASS/WARN/HARD-FAIL 흐름을 먼저 본다.
  • history-baseline-mismatches에서 query set이나 gate 기준이 달랐던 run을 분리한다.
  • history-scope-growth에서 새 failure scope가 늘어난 profile만 다시 연다.

이렇게 해두면 report가 하나 더 생기기는 하지만, 읽는 순서는 오히려 줄어든다. 큰 summary를 다 훑기 전에 scope growth queue가 비었는지만 먼저 보면 된다. 비어 있으면 “이번 run에서는 실패 범위가 새로 커지지 않았다”는 신호로 쓸 수 있고, 비어 있지 않으면 그 profile부터 열면 된다.

3. 실제 iter24 결과

이번 샘플 run에서는 일부러 기존 iter23 history를 복사해 iter24로 다시 돌렸다. 결과적으로 baseline mismatch는 그대로 남았지만, compatible history 안에서 품질 상태는 flat line이었다. 그래서 새로 만든 scope growth queue도 비어 있는 것이 맞다.

항목 iter24 결과 해석
baseline mismatch query_set 4건 오래된 probe entry는 여전히 기준선이 다름
status transition PASS→PASS, WARN→WARN, HARD-FAIL→HARD-FAIL compatible history 기준 상태는 유지됨
scope growth queue profile_count 0 새로 늘어난 failure scope 없음

처음에는 빈 report를 굳이 남기는 게 애매하지 않을까 싶었다. 그런데 막상 다시 보니 빈 queue가 오히려 유용했다. baseline mismatch가 있다는 사실과 실패 범위가 늘지 않았다는 사실을 분리해서 말해 주기 때문이다. 예전 같으면 mismatch report를 열고 profile별 scope를 다시 비교했을 텐데, 이제는 queue의 count만 보고 우선순위를 낮출 수 있다.

4. 테스트에는 일부러 non-empty case를 넣었다

실제 샘플 run이 비어 있으면 기능이 살아 있는지 감이 약하다. 그래서 테스트에는 반대로 scope growth가 생기는 synthetic case를 넣었다. 이전 history에서는 path_bridge_probe를 HARD-FAIL로 두고, 현재 run에서는 WARN으로 올라오게 만들었다. 동시에 warning scope는 늘어나도록 구성했다. 이 경우 새 queue는 profile 1개를 잡고, 새 warning scope 안에 cluster:doc-bridges.top1_hit_rate가 들어와야 한다.

이 테스트가 마음에 드는 이유는 “상태가 좋아졌는데도 warning scope는 늘어날 수 있다”는 장면을 잡아주기 때문이다. HARD-FAIL에서 WARN으로 올라온 건 좋아진 신호지만, warning scope가 넓어졌다면 다음 튜닝에서는 그 범위를 다시 봐야 한다. 단순히 좋아졌다/나빠졌다로 닫지 않고, 어떤 실패 면이 새로 생겼는지를 따로 남기는 게 이번 변경의 핵심이다.

5. 다음에 볼 것

이제 history 계층은 꽤 운영 도구에 가까워졌다. 처음에는 profile별 점수 비교에서 시작했는데, 지금은 rank shift, reason label, query group, quality gate, gate history, baseline mismatch, scope growth queue까지 이어졌다. 조금 과하게 잘게 쪼갠 것 같아도, 내가 실제로 디버깅할 때는 이 작은 queue들이 시간을 줄여준다.

다음에는 두 갈래 중 하나를 보려고 한다. 하나는 scope growth queue가 실제로 비지 않는 운영 history fixture를 하나 만들어 회귀 테스트를 더 직접적으로 고정하는 일이다. 다른 하나는 sample query set과 운영 query set의 history report를 서로 다른 namespace로 나누는 일이다. 지금처럼 샘플 기준선을 계속 단단하게 만들다 보면, 나중에 임베딩 기반 검색기로 바꿔도 같은 history 레이어 위에서 비교할 수 있을 것 같다.

작게 보면 report 파일 하나를 더 만든 정도지만, 내 입장에서는 어느 파일을 먼저 열지를 정해 주는 장치가 하나 생긴 셈이다. GraphRAG 실험은 점수 하나가 틀어지는 순간보다, 틀어진 이유를 찾기 위해 파일을 너무 많이 여는 순간에 더 자주 느려진다. 이번 queue는 그 느려지는 지점을 조금 줄여 보려는 쪽에 가깝다.

시리즈: GraphRAG 구축기 #7

이전: 6편 | 목록 | 다음: 8편

댓글

홈으로 돌아가기

검색 결과

"" 검색 결과입니다.