여기서 게으름을 피우고 AI를 신뢰하면, 그럴듯한 거짓 인용문이 그냥 지나간다. 대조에 떨어진 메모는 에러 로그를 뱉으며 그 자리에서 폐기되고, 작성 프롬프트의 컨텍스트에는 한 글자도 전달되지 않는다. 'AI가 원 기사에 없는 문장을 인용처럼 조작하는' 버그는 이 지저분한 문자열 대조로 물리적으로 막힌다.
하지만 대조가 보장하는 것은 인용이 본문에 실제로 존재한다는 것까지이다. 요약문의 문장이 메모 내용에 충실한지는 별개의 문제로 남는다. 그래서 7.5단계의 뒷받침(裏取り)에서, 요약문을 한 문장씩 근거 메모와 대조한다.
2장에서 화려하게 오발했던 '지지 판정'을 또 넣었나 싶을 수도 있다. 넣었다. 다만, 판정부터 삭제까지의 흐름을 바꿨다.
- 근거 메모가 연결되지 않은 문장은 코드가 기계적으로 제거한다
- AI는 문장별로 '메모에 의해 지지되는지'를 판단하고, 부분적으로만 지지되는 문장에는 수정안을 덧붙인다
- 수정안은 다시 대조를 거쳐 완전히 지지되었을 때만 채택한다. 수정안이 없거나 통과하지 못하면 제거한다
- 근거가 전혀 없는 문장은 여전히 제거한다. 이것은 오발이 아니라, 제거해야 할 문장이다
- 판정이 돌아오지 않는 등 예외적인 경우에는, 제거하지 않는 쪽으로 기울인다
구 경로는 '완전히 지지되는' 것 외의 모든 것을 삭제했다. 지금은 부분적으로 지지될 수 있는 문장에 복구할 길이 있다. 그리고 삭제를 결정하는 것은 항상 코드가다.
또 하나, 상류(上流) 변화도 크다. 구 경로에서는 AI가 자유롭게 쓴 장문을 나중에 판정했다. 지금은 대조가 완료된 메모만을 재료로 쓰기 때문에, 애초에 근거에서 멀리 떨어진 문장이 생겨나기 어렵다. 문장은 메모로부터 쓰고, 메모는 원문으로부터 쓴다. 구 경로의 오발을 막는 핵심은 판정 규칙 개선보다, 이 구조라고 생각한다.
솔직히 말하자면, 이것은 설계상의 의도일 뿐 효과를 측정해낸 것은 아니다. 신구(新旧)를 같은 조건으로 비교한 기록은 없으며, 복원 규칙과 상류 변화 중 어느 것이 얼마나 효과가 있었는지 분리하여 측정할 수 없다. 이곳이 앞으로의 숙제다. 그럼에도 불구하고 빠져나가는 요약의 오차는 마지막 심의에서 다룰 것을 전제로 설계하고 있다.
### 4-2. '확실성'은 AI에게 점수 매기게 하지 않는다
출력된 게시물에는 객관적인 '확실성 배지(確からしさバッジ)'가 붙는다. 여기에서도 AI가 자체 신고하는 '신뢰도 점수' 같은 것은 일절 믿지 않는다. 판정의 관점은 다음 4가지다.
- 1차 자료에 근거했는지
- 서로 독립적인 여러 정보원이 일치하는지
- 당사자의 주장으로만 그치는 것은 아닌지
- 자료들 사이에 모순이 없는지
배지를 결정하는 것은, 모인 메타데이터와 출처의 정보를 바탕으로 한 코드의 순수 함수다. 같은 입력이라면, 몇 번을 반복해도 똑같은 배지가 붙는다. 그런 것이 AI에게 맡겼을 때는 보장할 수 없었다.
의미 판단이 필요한 관점에서는 AI의 역할도 있다. 모순이 좋은 예시다.
- 날짜나 숫자가 서로 다른 메모 묶음을 코드가 기계적으로 찾아낸다
- 그것이 진짜 모순인지, 보기상의 차이에 불과한지 AI가 판단한다
- 그 판단을 채택할지, 배지를 붙일지는 코드가 결정한다
**'판단은 AI, 결정은 코드'를 하나의 관점 안에서 분업하면 이렇게 된다.**
### 4-3. 공개 게이트의 '멈추는 기준'을 좁히다
과거에는 '조금이라도 논리가 의심스러우면 멈춘다'는 방침으로 운영 불능에 빠졌다. v1에서는 코드가 공개를 보류하는 조건을 극소수로 좁혔다.
예를 들어, 근거 메모가 하나도 연결되지 않은 문장이 있는 경우다. 나머지 조건들도 생각은 같아서, '기계가 명확하게 판단할 수 있고, 놓치면 실해가 큰 것'만을 선택하고 있다.
그 외의 사소한 뉘앙스의 흔들림이나 미확인 사항은 게시물을 멈추는 이유로 삼지 않는다. '요 확인' 표시를 한 후, 커뮤니티 공개 심의 장소에 넘긴다.
심층 분석(深層分析) 게시물은 판정 '사실 아님', 상태 '심의 중'으로 공개한다. 일반 게시물과는 다른, 심층 분석만만의 방침이다. AI는 답을 단정하지 않는다. 출처와 함께 정리되어 있어도, 그것이 사실인지를 결정하는 것은 심의이고, 이 초기값은 심의에서 뒤집힐 때까지의 출발점에 불과하다.
**기계가 멈추는 것은, 기계가 확실하게 판정할 수 있는 것만.** 그 외는 인간의 심의에 맡긴다.
## 5. 세부 사항으로 내린 의사결정
파이프라인의 골격이 잡힌 후에도, 세세한 함정은 아직 이어졌다.
### 5-1. 경량 모델로 오프로드하면서 표시 품질이 붕괴했다
판정 계정 과정은, 경량 모델의 정밀도로 충분할지 알 수 없었기 때문에 일단 Pro 클래스로 시작했다. 구성이 잡히면, 단계적으로 등급을 낮춰도 괜찮은지 시험해 볼 생각이었다.
그 전초전으로, 기계적 처리로 보이는 '모순 의미 판단'과 '직역'만 경량한 소형 모델(Gemini Flash 등)에 오프로드해 보았다. 뒷받침 자료 확인과 답 판정은 Pro 클래스로 유지했다.
태스크는 완수한다. 수치상의 포괄도도 유지된다. 대시보드만 보면 성공이다. 그런데 화면을 열어보니, 표시 품질이 눈에 띄게 무너져 있었다.
- 해외 조직명이 일본어로 번역되지 않고, 대부분 영어 그대로 잔류
- 주체와 주장의 요약 표시가 무너진다
- 번역 과정에서 원문에 없는 뉘앙스를 추가하여 모호한 표현을 오해한다
모두 직역의 열화가 주요 원인이었다. 같은 시기에는 표시 측 코드의 버그도 겹쳤기 때문에, 모든 것을 모델 탓으로 할 수는 없다. 그래도, 번역의 질이 떨어지면, 그 다음 표시가 연쇄적으로 무너지는 것은 확실했다.
2장에서는 '놓치는 주원인은 모델이 아니라 과정이다'라고 썼다. 모순되는 것 같지만, 그렇지 않다. 과정을 줄였기 때문에, 남은 하나하나의 과정의 질이 그대로 출력의 질에 직결되게 된 것이다.
### 5-2. 전체 요약(테마 지도)은 AI에게 글을 쓰게 하는 것을 그만두었다
조사의 전반적인 모습을 조망하는 '테마 지도'. 초기에는 AI에게 시계열이나 대립 구조를 에세이 형식으로 정리하게 했다. 망가지는 방식은 다채로웠다.
- 스키마 없는 JSON의 파싱에 실패하여, 요약란 전체가 사라진다
- 'OO 통신은 ~', '△△ 신문은 ~'처럼, 매체명만 나열된다
- 역사의 탄생 배경만 골라 담고, 핵심 사건이 빠진다
프롬프트를 고치면, 다른 곳이 망가졌다. 완전히 모래성 쌓기였다.
### 5-3. 출처 URL: canonical 통합을 폐지했다
당초에는, 전재 기사나 중복 URL을 영리하게 모으기 위해, `canonical URL`와 `og:url`로 체계를 정규화한 후 출처 번호를 매겼다.
실제 검증 테스트에서는 거의 모든 것이 일치했지만, 아주 미세한 불일치가 발생했다. 진단 결과, 동일한 형식을 사용하지만 연도가 다른 별도의 문서를 URL 정규화 로직이 같은 문서로 오판하여 병합(삭제)하고 있었다. 공개 시스템에서 다른 연도의 자료를 출처로 표시하는 것은 단 한 번이라도 치명적이다.
그래서 출처 번호는 정규화를 거치지 않고, 메모 획득 시의 원본 `sourceUrl`로부터 직접 부여하도록 변경했다. 똑똑한 정규화 과정에서 다른 버전을 오판할 위험을 감수하는 것보다, 있는 그대로의 생(生) URL로 보내는 것이 공개 시스템으로서 신뢰성을 유지하는 방법이다.
### 5-4. 상태 기계: 세션 좀비 처리하기
마지막 이야기는 AI와 관련이 없다. 반복 가능 키(冪等キー) 제약으로 다음 작업이 생성되지 않아, 할 일은 아무것도 없는데도 '실행 중' 상태로 끝나지 않는 세션이 발생했다. LLM 이야기를 하고 있었지만, 마지막에 가로막은 것은 고전적인 상태 관리였다.
대책은 작업 사슬의 끝에서 후속 작업의 유무를 코드로 확인하고, 없다면 `no_scheduled_work` (예정 작업 없음)으로 명시적으로 정상 종료시키는 것이다. 여기서도 '끝났는지 여부'를 결정하는 것은 코드다.
## 6. 요약: 아키텍처의 경계선
쌓아온 시행착오를 한마디로 총괄하자면, AI에 대한 과도한 기대를 버리고 코드가 결정론을 향해 돌아가게 만든 역사였다.