ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 문장을 잘게 쪼개 검증한다 — Claim 분해와 앵커 없는 주장 걸러내기
    IT 2026. 7. 7. 23:00
    문장을 잘게 쪼개 검증한다 — Claim 분해와 앵커 없는 주장 걸러내기

    긴 글은 한 덩어리가 아니다

    요즘 LLM(대형 언어 모델, 사람의 말을 학습해 글을 생성하는 모델)에게 "○○에 대해 설명해줘"라고 하면 술술 한 편의 글을 써준다. 내가 직접 써보면서 깨달은 함정은, 그 글이 통째로 맞거나 통째로 틀리지 않는다는 점이다. 한 문장 안에서도 어떤 부분은 정확하고 어떤 부분은 슬쩍 틀린다.

    예를 들어 코드 설명 문서에 이런 문장이 들어 있다고 하자.

    "verify_token 함수는 입력이 비면 예외를 던지고, JWT 토큰의 서명을 검증한다."

    앞부분(빈 입력에 예외)은 실제 코드와 맞는데, 뒷부분(서명 검증)은 틀렸다고 하자. 실제 코드는 그냥 문자열을 비교할 뿐이라면 말이다. 그런데 이 문장 전체에 "맞음/틀림" 도장 하나만 찍어야 한다면? 어쩔 수 없이 "틀림"을 줄 수밖에 없고, 그 순간 "빈 입력에 예외를 던진다"라는 멀쩡한 정보까지 같이 버려진다. 반대로 "맞음"을 주면 서명 검증이라는 거짓 설명이 통과된다. 이것이 긴 글 사실 검증의 출발점이다. 채점 단위가 너무 크면 정보가 손실된다.

    diagram

    다이어그램 설명. 한 문장이 사실은 여러 개의 독립된 주장 조각으로 이루어져 있음을 보여준다. 사람이 이 문장을 읽을 때는 무의식적으로 이렇게 나눠서 판단하지만, 자동 검증 시스템은 누군가 명시적으로 쪼개주지 않으면 문장 전체를 하나의 덩어리로 다룬다. 그래서 "쪼개기"가 모든 것의 시작이다. 함정은, 쪼개지 않으면 멀쩡한 절반이 틀린 절반에 끌려 함께 폐기된다는 점이다.

    큰 단위 채점이 가리는 것들

    문장 통째로 이진(binary, 맞음/틀림 둘 중 하나로만 판정) 판정을 하면 부분적 사실성이 사라진다. 위 예시처럼 "절반은 맞다"는 정보가 0과 1 사이 어딘가가 아니라 그냥 0(틀림)으로 뭉개진다.

    diagram

    ▲ 방식 1: 문장 통째로 이진 판정

    다이어그램 설명. 맞는 정보와 틀린 정보가 섞인 문장에 통째로 "틀림" 한 도장을 찍으면, 멀쩡했던 정보까지 함께 0점으로 날아간다. 문장 전체가 최악의 한 조각에 끌려 내려가는 구조라 정보 손실이 불가피하다.

    diagram

    ▲ 방식 2: 주장 조각 단위 판정

    다이어그램 설명. 같은 문장을 두 개의 주장 조각으로 분해해 따로 채점하면, 틀린 조각만 골라내고 맞는 설명은 그대로 살릴 수 있다. 이렇게 하면 정보 손실 없이 "어느 주장이 깨졌는지"를 콕 집어 보고할 수 있다. 함정은 분해를 어떻게 하느냐인데, 그 얘기는 다음 절에서 이어진다.

    직관 먼저 — 잘게 쪼갤수록 근거를 콕 집기 쉽다

    핵심 직관은 단순하다. 큰 주장은 근거를 대기 어렵지만, 작은 주장은 근거를 콕 집기 쉽다.

    요리에 비유하면, "이 음식은 맛있다"는 통째 평가는 동의/반대가 갈린다. 하지만 "소금이 너무 많다", "면이 덜 익었다"처럼 잘게 나누면 각각을 명확히 확인할 수 있다. 코드 설명 검증도 똑같다. 서술을 원자적 주장(atomic claim, 더 못 쪼개는 최소 단위 주장)으로 나누면, 각 조각을 코드의 특정 위치 한 곳에 정확히 매칭해 따져볼 수 있다.

    이 골격을 흔히 분해 후 검증(Decompose-Then-Verify)이라 부른다. 긴 글을 작은 주장으로 쪼갠 뒤, 조각마다 근거를 찾아 진위를 따지는 흐름이다. 학계에는 분해 자체를 LLM으로 정교하게 하는 방법(예: 대명사·생략 주어를 복원해 조각이 혼자서도 말이 되게 만드는 방식)도 있지만, 그런 LLM 기반 분해기는 출력이 매번 달라지는 비결정적 동작에 호출 비용까지 든다. 그래서 내가 만들고 있는 코드 위키 자동 생성 시스템은 지금은 LLM 없이 돌아가는 결정적(deterministic) 문장 분해를 택했다 — 비용 0, 결과가 항상 같아 테스트하기 쉽다는 이유에서다. 더 정교한 LLM 분해는 옵션으로 열어 두되, 현재 기본값은 결정적 분해다.

    내가 채택한 것 — 결정적 문장 분해

    실제 구현은 단순하다. LLM에게 "이 문단을 주장 단위로 쪼개줘"라고 묻지 않는다. 대신 마침표·물음표·느낌표 뒤에서 문장을 끊는 정해진 규칙(휴리스틱)으로 쪼갠다. 다만 한 가지 함정이 있다. 코드 설명에는 payments.py:10:handle 같은 점(.)이 박힌 식별자가 자주 등장하는데, 이걸 그냥 마침표로 보면 엉뚱한 데서 문장이 끊긴다. 그래서 백틱(`)으로 감싼 코드 조각은 잠시 안전한 자리표시자로 치환해 두고, 문장을 나눈 다음 원래대로 되돌린다.

    diagram

    다이어그램 설명. 결정적 문장 분해의 실제 동작이다. 핵심은 점이 박힌 코드 식별자가 문장 끊는 기준을 망치지 못하도록, 코드 조각을 잠시 빼뒀다가 분해가 끝난 뒤 제자리에 돌려놓는다는 점이다. 이렇게 하면 같은 입력에 항상 같은 결과가 나와 테스트가 쉽고, 모델 호출이 없어 비용도 들지 않는다. 트레이드오프는 거친 경계인데, 한 문장에 주장 둘이 묶여 들어가면 둘 다 근거가 있어야 통과하므로 오히려 보수적으로 작동한다.

    코드로 보면 이 정도다.

    _SENTENCE_SPLIT_RE = re.compile(r"(?<=[.!?。])\s+") — 마침표류 뒤의 공백에서 끊는다.
    _BACKTICK_RE = re.compile(r"`[^`]*`") — 백틱으로 감싼 코드 조각을 먼저 찾아 보호한다.

    주장을 뽑은 다음, 각 주장이 같은 문단 안에서 어떤 코드 위치(앵커)를 가리키는지 매핑한다. 여기서 가장 중요한 규칙이 등장한다.

    하드 게이트 — 앵커 없는 주장은 곧장 '근거 없음'

    분해한 주장 중에는 가리킬 코드 근거가 아예 없는 것이 있다. 어떤 코드 줄도 인용하지 않은 채 그냥 단언하는 문장이다. 내가 만든 시스템은 이런 주장을 검증 모델에게 물어볼 것도 없이 곧장 '근거 없음(unsupported)'으로 처리한다. 인용이 없다는 것은 곧 검증할 방법이 없다는 뜻이기 때문이다. 이를 "하드 게이트"라 부른다.

    diagram

    다이어그램 설명. 분해된 주장이 검증으로 넘어가기 전 거치는 갈림길이다. 가리키는 코드 근거가 없는 주장은 모델에게 묻지도 않고 바로 '근거 없음'으로 떨어뜨린다. 이건 비용 절약인 동시에 정책의 표현이기도 하다 — "인용 없는 주장은 통과시키지 않는다"를 코드로 못 박은 것이다. 함정은, 사람이 보기엔 맞는 말 같아도 코드 근거가 없으면 가차 없이 막힌다는 점인데, 바로 그 엄격함이 근거 없는 날조를 원천에서 차단한다.

    무엇이 좋아지고, 무엇이 한계인가

    좋아지는 점은 분명하다. 첫째, "절반 맞음"이 0이나 1로 뭉개지지 않고 조각별로 남는다. 어느 주장이 깨졌는지 페이지와 줄 번호로 콕 집어 보고할 수 있다. 둘째, 비용이 들지 않는다. 분해도 하드 게이트도 LLM 없이 돌아가므로, 야간에 모든 문서를 통째로 돌려도 청구서가 0이다.

    한계도 분명하다. 결정적 문장 분해는 거칠다. 너무 잘게 쪼개지 못해 한 문장에 주장 둘이 묶여 들어갈 수 있다(다만 이 경우 둘 다 근거가 있어야 통과하므로 보수적으로 작동한다). 그리고 대명사·지시어로 흐려진 주장("이 함수가…")을 실제 대상으로 복원하지 않는다. 이런 정교한 분해는 비결정적 LLM 분해기로만 가능한데, 비용과 재현성 때문에 현재는 보류해 두고 옵션으로만 남겨 뒀다.

    내 코드 위키 자동 생성 시스템과의 연결

    내가 이 주제를 파게 된 계기는 코드를 읽고 사람이 읽을 설명 문서를 LLM이 자동으로 써내는 작업이었다. 여기서 가장 위험한 실패는 "그럴듯하지만 코드에 없는 한 문장"이다. 한 문단 안에 맞는 설명과 거짓 주장이 섞이면, 문단 전체를 통째로 신뢰하거나 통째로 버리는 양자택일에 몰린다.

    그래서 내 시스템의 검증 1단계는 이 글이 정리한 그대로다. 지금은 결정적 문장 분해로 주장을 뽑고, 그중 코드 앵커가 없는 주장은 자동으로 '근거 없음' 처리한다. 앵커가 붙은 주장만이 다음 단계, 즉 "인용된 코드가 정말 이 주장을 뒷받침하는가"를 따지는 의미 검증으로 넘어간다. 분해와 하드 게이트가 비용 0으로 날조를 먼저 걸러내 주는 덕분에, 더 무거운 검증은 정말 따져볼 가치가 있는 주장에만 쓰인다. 긴 글의 사실성을 다루는 어떤 작업이든, 결국 "쪼개고 → 근거 없는 건 버리고 → 남은 것만 검증한다"는 이 흐름으로 돌아오게 된다는 게 내가 얻은 결론이다.


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.