2026년 5월 12일 | 개인 프로젝트 · GraphRAG
exclude-candidate로 표시해 둔 profile이 다음 실행에서도 계속 평가되는 게 최근 GraphRAG 루프에서 조금 찜찜했다. iter30에서 stale origin action queue를 붙이면서 path_bridge_focus는 제외 후보, path_bridge_probe는 관찰 후보로 잘 갈라졌다. 그런데 막상 다음 profile sweep을 돌리면, 명령어에 세 profile을 그대로 넣는 한 제외 후보도 다시 평가 대상에 들어왔다.
그래서 이번 반복은 새 점수식을 만드는 쪽이 아니라, 이전 report의 판단을 다음 실행에 반영하는 쪽으로 잡았다. 이름은 거창하게 action exclusion sweep이라고 붙였지만, 실제로 한 일은 단순하다. history-stale-origin-actions.json을 입력으로 받아서 exclude-candidate인 profile을 profile 비교 전에 건너뛰게 했다.
1. report가 실행을 바꾸지 못하면 반쪽짜리다
최근 GraphRAG 쪽 작업은 검색 모델을 크게 갈아엎기보다, evaluation history를 어떻게 읽고 다음 실험 대상을 줄일지에 가까웠다. quality gate, history namespace, status streak, stale status queue, stale origin queue를 차례로 붙였다. iter30에서는 그 위에 action queue를 얹어서 HARD-FAIL origin streak는 exclude-candidate, WARN origin streak는 observe-candidate로 나눴다.
여기까지는 사람이 읽기에는 꽤 좋아졌다. 문제는 실행 루프였다. action report가 “이 profile은 제외 후보”라고 말해도, 다음 실행에서 내가 --profile configs/path_bridge_focus.json를 그대로 넣으면 다시 bundle에 들어온다. 결과적으로 report는 판단을 기록하지만, 실행을 가볍게 만들지는 못했다. 이 간극이 은근히 신경 쓰였다.
나는 이런 종류의 report를 만들 때 자주 헷갈린다. 관찰용 report인지, 제어용 report인지가 섞이기 쉽다. 관찰용이면 사람이 읽고 끝나도 된다. 하지만 이번 action queue는 이름부터 “다음 행동”을 말하고 있으니, 적어도 선택적으로 실행 제어에 쓸 수 있어야 했다.
2. 옵션은 일부러 좁게 열었다
새로 추가한 옵션은 --exclude-action-report다. 여기에 이전 run의 history-stale-origin-actions.json 경로를 넘기면, 내부에서 report의 profiles를 읽는다. 그중 recommended_action이 exclude-candidate인 항목만 골라 현재 sweep의 profile 목록과 맞춘다.
매칭은 두 겹으로 했다. 우선 report에 저장된 profile_path가 현재 넘긴 profile path와 같으면 제외한다. 경로가 살짝 달라지는 경우를 대비해 profile_name, 즉 파일 stem도 같이 본다. 너무 영리하게 만들지는 않았다. 지금 단계에서는 “이전 action report에서 제외 후보로 찍힌 같은 profile을 다음 sweep에서 빼자”는 좁은 용도만 잘 맞으면 충분하다.
대신 그냥 조용히 빠지는 방식은 피했다. summary에는 profile_action_exclusion을 따로 남기고, text output 상단에도 제외 사실을 한 줄로 보여 준다.
profile-action-exclusion: .../history-stale-origin-actions.json | skipped=1 | actions=exclude-candidate:1
이 줄이 있어야 나중에 summary만 봐도 “왜 이번 bundle에 path_bridge_focus가 없지?”를 바로 알 수 있다. 실패 profile을 지운 것이 아니라, 이전 report 판단에 따라 이번 sweep에서 스킵한 것이다.
3. iter31 결과
iter30의 action report를 그대로 입력으로 넣고 iter31 run을 만들었다. 테스트는 34개가 모두 통과했다. 기존 33개에 이번 exclusion 동작을 검증하는 테스트가 하나 더 붙었다.
| profile | iter31 처리 | 상태 | 메모 |
|---|---|---|---|
default |
평가 | PASSx7 |
기준선으로 계속 유지 |
relation_weight_dense |
평가 | PASSx7 |
안정 profile 유지 |
path_bridge_probe |
평가 | WARNx7 |
observe-candidate로 계속 추적 |
path_bridge_focus |
스킵 | exclude-candidate |
iter30 action report 기준으로 제외 |
재미있는 건 새 stale origin action report도 자연스럽게 줄었다는 점이다. iter30에서는 exclude-candidate:1, observe-candidate:1이었는데, iter31에서는 제외 후보였던 path_bridge_focus가 실행에서 빠졌으니 새 report에는 observe-candidate:1만 남았다. 그러니까 이번 변경은 단순히 출력에서 한 줄을 숨긴 게 아니라, 다음 history report의 후보군 자체를 줄인 셈이다.
4. 조용히 빼는 기능일수록 흔적이 필요하다
이 기능을 붙이면서 가장 조심한 부분은 “왜 안 보이는지”였다. profile을 스킵하는 기능은 편하지만, 흔적이 없으면 나중에 결과를 읽는 사람이 더 헷갈린다. 특히 history 기반 evaluation에서는 빠진 profile이 실패해서 없는지, 명령에서 빠졌는지, 이전 report 때문에 제외됐는지가 모두 다른 의미다.
그래서 summary에 skipped_profiles를 남겼다. 여기에는 현재 넘긴 profile path, report에서 온 source profile, action reason, blocking scopes가 같이 들어간다. 즉 path_bridge_focus가 이번 bundle에 없더라도, “hard-fail origin streak 때문에 제외됐다”는 근거는 JSON 안에 남아 있다.
이런 기록은 조금 장황해 보이지만, 나중에 회귀를 찾을 때 도움이 된다. 실험 결과가 좋아졌다고 생각했는데 사실은 어려운 profile을 빼서 좋아진 것일 수 있기 때문이다. 그래서 스킵은 기능이면서 동시에 provenance 문제다. 무엇을 평가했는지뿐 아니라, 무엇을 일부러 평가하지 않았는지도 남겨야 한다.
5. 다음에는 registry 쪽으로 넘길 수 있을까
이번 단계에서는 action report 하나만 입력으로 받게 했다. 아직 profile registry나 allowlist까지 만들지는 않았다. 너무 빨리 일반화하면 작은 MVP가 또 설정 파일만 늘어나는 방향으로 흐를 것 같았다. 지금은 “이전 run에서 제외 후보로 표시된 profile을 다음 sweep에서 한 번 빼 보기” 정도가 딱 맞다.
다음에 볼 지점은 두 가지다. 하나는 observe-candidate가 operational query set에서 실제로 회복될 수 있는지다. 샘플 query set에서는 계속 WARN이지만, 질문 묶음이 달라지면 bridge profile의 의미가 달라질 수 있다. 다른 하나는 제외 후보를 완전히 지우지 않고 어떤 registry에 보관할지다. 당장은 skipped_profiles로 충분하지만, profile 수가 늘면 별도 목록이 필요할 수도 있다.
오늘 붙인 건 작은 옵션 하나지만, GraphRAG 실험 루프에서는 꽤 마음이 놓이는 변경이었다. 실패를 발견하는 것에서 끝나지 않고, 그 실패를 다음 실행에서 어떻게 다룰지까지 연결했기 때문이다. 검색 점수 하나가 오른 건 아니어도, 같은 실패를 계속 다시 읽는 시간은 확실히 줄었다.
'[AI 실험실] > [개인 프로젝트] GraphRAG' 카테고리의 다른 글
| GraphRAG | Stale origin action queue 추가 (0) | 2026.05.07 |
|---|---|
| GraphRAG | Same-status stale queue 추가 (0) | 2026.05.06 |
| GraphRAG | History mismatch 상태 전이 연결 (0) | 2026.05.06 |
| GraphRAG | Stale transition split 추가 (0) | 2026.05.02 |
| GraphRAG | History stale status queue 추가 (0) | 2026.05.01 |