2026년 7월 10일 | 개인 프로젝트 · GraphRAG
manual-incident 질의의 1위가 GraphRAG overview에서 Retrieval planner로 바뀌었다. 이전 회차의 평가표에서도 이 변화는 보였다. 다만 보고서가 알려 준 것은 순위가 뒤집혔다는 사실과 path-over-coverage 같은 원인 라벨까지였다. 어느 엣지가 새 1위를 밀어 올렸고, 벡터 점수 손해를 무엇이 상쇄했는지는 두 trace 파일을 직접 펼쳐야 했다.
나는 이 상태가 조금 답답했다. profile 후보를 조정할 때 중요한 것은 “바뀌었다”보다 “왜 이 문서가 이겼는가”다. 그래서 이번 회차에는 rank-shift report 안에 두 winner의 점수와 supporting edge를 나란히 넣는 top-1 evidence comparison을 추가했다.
순위 변화 라벨만으로는 부족했던 지점
기존 profile 비교기는 default와 candidate의 top-k를 대조해 top-1 일치율, 순위 이동, overlap, edge·path·coverage 점수 변화를 계산했다. 이 정도면 회귀가 생겼는지 찾는 데는 충분하다. 하지만 top-1이 달라진 질의를 사람이 검토하려면 여전히 세 가지를 따로 찾아야 했다.
- 기존 1위와 새 1위가 각각 어떤 엣지를 근거로 삼았는가
- 같은 profile 안에서 새 1위가 어느 점수 항목으로 앞섰는가
- relation weight 조정이 두 문서에 서로 다르게 작용했는가
파일 이름과 chunk id를 맞춰 가며 이 셋을 손으로 계산할 수는 있다. 문제는 profile 후보가 늘어날수록 검토 시간이 평가 실행 시간보다 길어진다는 점이다. 자동 평가의 결과가 다시 수작업 스프레드시트가 되는 순간이었다.
두 winner를 같은 보고서에 묶었다
새 비교 레이어는 top-1 flip이 감지되면 default winner와 candidate winner의 snapshot을 만든다. snapshot에는 title, chunk id, vector score, edge score, path score, coverage score, final score가 들어간다. supporting edge는 원문 문장을 통째로 복제하지 않고 source-relation-target 구조만 남겼다. 통합 보고서를 공유할 때 문서 원문이 불필요하게 넓게 퍼지는 것을 피하기 위해서다.
두 winner가 양쪽 trace의 top-k 안에 모두 있으면 profile 변경 전후의 점수 변화도 계산한다. candidate profile 안에서는 새 1위와 기존 1위의 차이를 vector, edge, path, coverage 네 항목으로 분해한다. final margin과 항목 합이 어긋나는 경우를 놓치지 않도록 rounding residual도 별도 필드로 남겼다.
{
"status": "complete",
"candidate_winner_margin": {
"final_score": 0.3339,
"components": {
"vector_score": -0.3994,
"edge_score": 1.2000,
"path_score": 0.0000,
"coverage_score": -0.4667
}
}
}
숫자만 봐도 해석이 달라진다. Retrieval planner는 벡터 유사도에서 0.3994, 커버리지에서 0.4667을 잃었다. 대신 supporting edge 두 개에서 1.2000의 우위를 얻어 최종적으로 0.3339 앞섰다. 새 profile이 이 문서를 전반적으로 강하게 끌어올린 것은 아니었다. 오히려 후보 문서 자체 점수는 default 대비 0.05 내려갔고, 기존 1위가 0.45 더 크게 내려가면서 순위가 뒤집혔다.
uses 가중치 하향이 만든 비대칭
relation weight를 같이 놓고 보니 뒤집힘의 모양이 더 분명했다. 기존 1위 GraphRAG overview는 GraphRAG-uses-Product Manual 엣지 하나를 주로 썼다. candidate에서는 uses 가중치가 1.2에서 0.9로 내려갔다. 반면 Retrieval planner는 retrieves와 links 두 엣지를 근거로 삼았다. retrieves는 1.1에서 1.0으로 조금 내려갔지만 links는 1.05에서 1.1로 올라갔다.
여기서 내가 처음 예상한 설명은 “links를 올려서 Retrieval planner가 급상승했다”였다. 실제 결과는 조금 달랐다. 새 1위의 절대 점수는 오히려 소폭 내려갔다. 핵심은 uses 중심의 기존 1위가 더 크게 깎였다는 데 있었다. 단일 가중치 변화의 효과를 문서 하나만 보고 해석하면 놓치기 쉬운 부분이다. winner 쌍을 같이 보니 profile 조정이 만든 상대적 비대칭이 드러났다.
top-k가 작아도 가능한 근거는 남긴다
구현하면서 한 번 막힌 곳은 top_k=1이었다. 처음 버전은 두 winner가 반대쪽 trace에도 존재할 때만 evidence comparison을 만들었다. top-k가 1이면 순위가 바뀐 순간 상대 winner는 반대쪽 결과에 없으니, 정작 가장 작은 설정에서 새 기능이 항상 사라졌다. 테스트를 추가하고 나서야 이 허점이 바로 보였다.
지금은 counterpart가 없더라도 각 profile의 1위 snapshot과 supporting edge는 남긴다. 교차 profile 점수 변화처럼 계산할 수 없는 항목만 null로 두고, 상태를 partial로 표시한다. 왜 비었는지는 default_winner_not_in_candidate_top_k 같은 unavailable reason으로 적는다. 정보가 모자란 상황과 점수가 0인 상황을 섞지 않는 쪽을 택했다.
같은 원칙을 오래된 trace에도 적용했다. scoring config나 score component가 없으면 0으로 채우지 않는다. 기본값처럼 보이는 가짜 숫자는 검토를 더 어렵게 만든다. 누락은 unknown으로 남기고, relation key만 빠진 정상 config에는 실제 retriever와 동일하게 1.0 기본값을 적용했다.
보고서가 로그를 망가뜨리지 않게 한 방어
trace에서 가져온 title과 relation은 결국 터미널 요약과 CI 로그에 출력된다. 제어문자나 ANSI escape가 섞이면 결과 한 줄이 여러 줄처럼 보이거나 색상 코드로 뒤집힐 수 있다. 그래서 새 evidence 행뿐 아니라 text renderer의 최종 출력 전체에서 C0/C1 제어문자, Unicode line separator, bidi formatting 문자를 정리했다.
이 부분은 기능 설명보다 눈에 덜 띄지만, 평가 보고서를 자동으로 쌓을수록 중요해진다. 검색 대상 문서는 항상 내가 만든 깨끗한 샘플만 들어온다는 보장이 없다. 보고서가 입력 문서의 제목 때문에 로그 구조를 바꾸지 않는 것도 재현성의 일부라고 봤다.
실험 결과와 다음 판단
샘플 query set으로 다시 평가했을 때 candidate의 전체 top-1 hit rate는 80%, full coverage는 80%를 유지했다. manual-incident 한 건의 top-1 flip도 그대로 남았다. 새 리포트는 이 변화를 감추지 않고, edge 우위 +1.2000과 vector·coverage 손해를 같은 줄에 보여 줬다. 전체 테스트는 59개를 통과했고, 프로젝트 저장소에도 같은 회차 변경을 커밋했다.
이번 결과만으로 profile을 active baseline으로 승격하지는 않을 생각이다. evidence를 읽어 보니 relation weight를 전역으로 조금 더 움직이는 것보다, 여러 엣지가 단일 uses 엣지를 압도하는 조건을 별도 guard로 보는 편이 낫다. 다음 회차에서는 edge 개수와 coverage 손실이 동시에 큰 질의를 모아, 문서 수가 늘어도 같은 비대칭이 반복되는지 확인하려 한다.
'[AI 실험실] > [개인 프로젝트] GraphRAG' 카테고리의 다른 글
| GraphRAG | Rank Guard 적용·거절 근거 리포트 (1) | 2026.07.17 |
|---|---|
| GraphRAG | 문서 브리지 질의의 Full-Coverage 순위 보정 (0) | 2026.07.14 |
| GraphRAG | Scoring Profile 후보 검증 (0) | 2026.07.07 |
| GraphRAG | Exit Policy preview action 적용 (0) | 2026.07.03 |
| GraphRAG | Exit Policy action preview 리포트 (0) | 2026.06.30 |