2026년 5월 16일 | 개인 프로젝트 GraphRAG
GraphRAG의 observation review report가 만들어지자 바로 다음 빈칸이 보였다. observe 상태 profile을 “계속 관찰”, “승격 후보”, “비활성 후보”로 분류하는 데까지는 왔는데, 그 결과를 registry 갱신 루틴에 바로 넘길 수는 없었다. 전 단계에서 만든 report가 판단을 말하고 있는데, 정작 registry를 고치는 도구는 다른 형식의 action report만 알아듣는 상태였다.
나는 이런 틈을 꽤 싫어한다. 기능이 커질수록 한 파일은 판단을 만들고, 다른 파일은 실행을 맡는데, 둘 사이의 작은 필드명 차이가 다음 반복에서 계속 사람 손을 부른다. 이번 GraphRAG 작업은 그래서 점수 계산을 건드리기보다 registry-observation-review.json을 profile_registry 갱신 입력으로 읽을 수 있게 연결하는 쪽으로 잡았다.
막혀 있던 지점
iter35에서 만든 observation review는 observe profile을 현재 quality history와 다시 맞춰 보고, 추천 행동을 붙인다. 예를 들어 PASS가 몇 번 이어지면 promote-candidate, hard-fail이 길어지면 disable-candidate, warning이면 keep-observing으로 떨어뜨린다. 읽는 입장에서는 꽤 편해졌다. summary 상단에서 observe profile 하나가 지금 어떤 상태인지 바로 볼 수 있었기 때문이다.
그런데 registry sync 쪽은 아직 과거 형식에 묶여 있었다. 기존 profile_registry.py는 recommended_action이라는 필드를 찾고, 값이 observe-candidate나 exclude-candidate일 때만 status를 갱신했다. 반면 observation review는 일부러 recommended_registry_action이라는 이름을 썼다. 같은 “추천 행동”인데, 입력 계약이 달라서 서로 이어지지 않았다.
처음에는 그냥 report를 사람이 보고 직접 registry를 고쳐도 되지 않나 싶었다. 하지만 이미 action report 기반 sync를 만들어 둔 상태라면, observation review도 같은 통로로 preview할 수 있어야 한다. 그래야 실제로 registry를 덮어쓰기 전에 몇 개가 매칭됐는지, status가 몇 개 바뀌는지, 모르는 profile이 섞였는지를 같은 기준으로 볼 수 있다.
이번에 바꾼 것
핵심 변경은 작다. action entry를 읽는 부분에 정규화 단계를 하나 넣었다. 기존 recommended_action이 있으면 그대로 쓰고, 없으면 recommended_registry_action을 같은 의미로 받아들인다. observation review의 review_reason은 registry의 last_action.action_reason으로 옮기고, warning scope나 hard-fail scope는 blocking_scopes로 보존한다.
상태 매핑도 늘렸다. 예전에는 exclude와 observe 후보만 있었는데, 이제 observation review에서 나온 세 가지 판단도 registry 상태로 이어진다.
| review 추천값 | registry 상태 | 의미 |
|---|---|---|
promote-candidate |
active |
observe profile이 PASS streak로 회복됐을 때 승격 후보로 반영 |
keep-observing |
observe |
warning band를 유지하면서 최신 판단 근거만 갱신 |
disable-candidate |
disabled |
hard-fail streak가 이어진 profile을 sweep 제외 후보로 반영 |
여기서 마음에 든 부분은 자동 갱신을 바로 강제하지 않았다는 점이다. 같은 CLI로 preview 파일을 만들 수 있고, 안전하다고 판단될 때만 in-place로 넘기면 된다. GraphRAG 실험처럼 profile 상태가 곧 다음 sweep의 입력이 되는 구조에서는 이 한 단계가 중요하다. 바로 고치는 것보다 먼저 “무슨 일이 일어날지”를 파일로 남겨 두는 편이 덜 불안하다.
테스트에서 고정한 장면
테스트는 두 profile을 일부러 observe 상태로 두고 시작했다. 하나는 promote-candidate, 다른 하나는 disable-candidate를 담은 observation review payload를 넣었다. 기대값은 단순하다. 첫 번째 profile은 active로 올라가고, 두 번째 profile은 disabled로 내려가야 한다. 그리고 두 profile 모두 last_action에 원래 review reason과 source report path를 남겨야 한다.
이 테스트가 필요한 이유는 숫자가 아니라 경계 때문이다. keep-observing은 실제 operational run에서 이미 자주 보이는 케이스다. 반면 promote와 disable은 자주 나오지 않아서, 실제 상황이 오기 전까지 코드가 맞게 움직이는지 확인하기 어렵다. 그래서 synthetic fixture로 먼저 고정했다. 이런 테스트는 좀 허무해 보일 때도 있지만, 막상 나중에 profile 상태를 자동 반영할 때는 이 작은 fixture가 되돌림 기준선이 된다.
전체 테스트는 41개가 통과했다. 전 단계보다 하나 늘었다. 기능 자체는 얇지만, registry와 observation review 사이의 입력 계약을 테스트로 박아 두었다는 점이 이번 변경의 핵심이다.
preview로 확인한 실제 상태
실제 iter35 observation review report도 새 sync 루틴에 preview로 넣어 봤다. 결과는 조용했다. path_bridge_probe 하나가 매칭됐고, 추천 행동은 keep-observing이었다. unmatched action은 0개였고, status 변화도 0개였다. 최종 registry 분포는 active: 1, observe: 1, disabled: 1 그대로다.
처음 보면 “아무것도 안 바뀐 것 아닌가?” 싶을 수 있다. 그런데 나는 이 결과가 오히려 좋았다. 지금 path_bridge_probe는 아직 warning band에 있다. 그러면 status를 active로 올리거나 disabled로 내리는 게 아니라, observe를 유지하는 게 맞다. 달라진 것은 status가 아니라 provenance다. preview registry 안의 last_action은 이제 예전 stale-origin action report가 아니라 최신 observation review의 keep-observing 판단을 가리킨다.
이 차이는 다음에 다시 열 때 꽤 크다. 예전에는 이 profile이 왜 observe인지 보려면 과거 action report를 다시 따라가야 했다. 이제는 “최근 observation review에서도 계속 관찰로 판단했다”는 흔적이 바로 남는다. 상태값 하나는 그대로여도, 그 상태를 유지한 이유가 최신화되는 셈이다.
하면서 느낀 점
GraphRAG 프로젝트가 처음에는 검색 품질을 올리는 쪽으로만 보였다. 그런데 몇 주째 작은 report와 registry를 붙이다 보니, 지금은 “검색 실험의 상태를 어떻게 안전하게 읽을 것인가”가 더 큰 비중을 차지한다. query 하나의 top-1이 바뀌는 것도 중요하지만, 그 변화를 보고 profile을 승격할지, 보류할지, 끌지 결정하는 장부가 없으면 실험은 금방 흐릿해진다.
이번 변경도 그런 장부 정리에 가깝다. 멋진 모델을 붙인 것도 아니고, retrieval 점수가 오른 것도 아니다. 대신 observe profile의 판단 결과가 registry sync까지 이어지는 길을 하나 더 닦았다. 나는 이런 작업이 나중에 더 큰 실험을 할 때 시간을 아껴 준다고 믿는 편이다. 실험이 커질수록 “왜 이 설정이 아직 살아 있지?”라는 질문이 자주 나오고, 그때 답이 코드와 report 안에 남아 있어야 한다.
다음에 볼 것
다음 단계는 promote-candidate를 실제 operational history에서 재현하는 쪽이다. 지금은 테스트 안에서만 승격 장면을 만들었다. 실제 query set에서 observe profile이 PASS streak로 회복되는 상황을 만들 수 있는지 봐야 한다. 반대로 keep-observing이 너무 길어지는 profile에는 관찰 종료 조건을 붙여야 할 수도 있다.
그리고 preview 결과를 언제 in-place로 반영할지도 정해야 한다. 내 기준으로는 status change가 있는 날일수록 바로 덮어쓰기보다 preview report를 먼저 읽고, unmatched action이 0개인지 확인한 뒤 반영하는 쪽이 안전하다. GraphRAG의 다음 반복은 아마 이 preview와 in-place 사이의 작은 runbook을 더 단단하게 만드는 일이 될 것 같다.
'[AI 실험실] > [개인 프로젝트] GraphRAG' 카테고리의 다른 글
| GraphRAG | Observation aging의 registry preview 연결 (0) | 2026.05.19 |
|---|---|
| GraphRAG | observe profile 장기 관찰 큐 (0) | 2026.05.18 |
| GraphRAG | Observe profile 검토 리포트 (0) | 2026.05.15 |
| GraphRAG | Registry 상태 요약 렌즈 (0) | 2026.05.14 |
| GraphRAG | Action report 기반 registry 갱신 (0) | 2026.05.13 |