
로직 그래프 검증 시스템 (Logic-Graph Verification System)
요약
오픈 웨이트 모델의 추론 과정을 유향 그래프로 외재화하여 기계적으로 검증하는 시스템을 제안합니다. 모델의 자기 수정 한계를 극복하기 위해 독립적인 샘플링과 그래프 위상 분석을 통해 결론의 신뢰도를 확보합니다.
핵심 포인트
- 모델의 자기 수정(Self-correction) 실패 문제를 그래프 검증으로 해결
- 추론 과정을 유향 그래프로 변환하여 순환 논리 및 고아 노드 탐지
- N개의 독립적 추론 호출을 통한 상관관계 제거 및 교차 검증
- 결론의 신뢰도를 증거와 결론 사이의 독립적 경로 수로 측정
상태: 초안 v1 · 2026-07-02
저자: design session (Claude Fable 5)
구현자: SYSTEM-DESIGN.md에 따른 모든 역량 있는 코딩 모델
1. 한 줄 요약 (One-liner)
오픈 웨이트 (open-weight) 사고 모델의 저렴한 토큰 처리량 (token throughput)을 검증된 결론으로 전환합니다. 모델의 추론 과정을 그래프로 외재화하고, 이를 N번 독립적으로 샘플링하며, 모델의 느낌 (vibes)이 아닌 기계적인 그래프 체크를 통해 무엇이 생존할지 결정합니다.
2. 문제 (Problem)
- 프롬프팅을 통한 자기 수정 (Self-correction)의 실패. 모델에게 자신의 사고 사슬 (chain-of-thought, "다시 검토해 보자...")을 다시 입력하는 것은 모델이 자신의 토큰에 닻을 내리게(anchor) 하여 스스로를 승인(rubber-stamp)하게 만듭니다. 이는 이미 알려진 결과입니다 (Huang et al., "LLMs Cannot Self-Correct Reasoning Yet").
- 초당 토큰 수 (tokens/sec)는 쓸모없는 지표입니다. 확신에 찬 헛소리를 100만 토큰이나 내뱉는 저렴한 모델은 가치가 전혀 없습니다. 중요한 지표는 **달러당 정확한 결론 (correct conclusions per dollar)**입니다.
- LLM을 통한 검증 (Verification-by-LLM)은 문제를 그대로 계승합니다. 모델에게 "이것이 사실인가요?"라고 묻는 것은 단지 느낌 (vibes)의 단계를 한 단계 위로 올릴 뿐입니다. 우리에게 필요한 것은 모델의 판단이 아닌, 계산 가능하고 결정론적인(deterministic) 기계적 (mechanical) 체크입니다.
- 저렴한 모델은 사전 학습 (pretraining) 데이터로부터 환각 (confabulate)을 일으킵니다. 주장이 반드시 가져온 소스(imported sources)로 추적되어야 하는 시스템은, 자신의 가중치 (weights)로부터 조용히 답변하는 모델을 허용할 수 없습니다.
3. 핵심 통찰 (Core insights, 제품 테제)
- 진실 여부와 상관없이 형태(Shape)는 검증 가능하다. 유향 그래프 (directed graph)로 외재화된 논증은 기계적 검증을 허용한다: 지지되지 않는 전제 (고아 노드, orphans), 순환 논리 (사이클, cycles), 단절된 결론 (도달 가능성, reachability), 반박된 주장이 여전히 하중을 견디고 있는 상태 등.
- "진실성 (Truthiness)"은 위상 (topology)이 된다. 결론에 대한 신뢰도는 증거와 결론을 연결하는 노드 분리 (node-disjoint) 체인이 얼마나 많은가에 비례한다 (멩거의 정리, Menger's theorem). 로마로 가는 길이 하나뿐이라면 취약하지만, 세 개의 독립적인 길이 있다면 공격자는 세 개의 별개 주장을 깨뜨려야만 한다.
- 독립성은 요청하는 것이 아니라 샘플링하는 것이다. 하나의 컨텍스트에 "3개의 독립적인 논증"을 요구하면 동일한 논증을 세 번 의역한 결과가 나온다. 반면 N개의 독립적인 추론 호출 (N independent inference calls) (새로운 컨텍스트, temperature > 0)을 수행하면 진정으로 상관관계가 제거된 시도들을 얻을 수 있다. 이는 탐정의 기법과 같다: 개별적으로 심문한 뒤, 교차 검증하는 것이다. 실행 간의 모순은 심문 과정에서의 실수이며, 이는 단일 전사 기록(transcript) 내부에서는 보이지 않는다.
- 주의(attention)를 분산시키지 말고 직접적으로 집중시켜라. "당신의 추론을 다시 검토하라"는 명령은 모델이 모든 것을 얕게 훑어보게 만든다. 반면 "에지(Edge) 7은 하중을 견디고 있으나 검증되지 않았다"는 명령은 모델이 예산(budget) 전체를 정확한 지점에 쏟게 만든다. 최소 컷 (Min-cut) / 매개 중심성 (betweenness)은 그 지점이 어디인지 계산한다.
- 정식화 비용 (formalization tax)은 기능이다. 모호한 단계는 타입이 지정된 에지(typed edges)를 가진 타입 지정 노드(typed node)로 작성되어야 할 때 눈에 띄게 모호해진다.
4. 사용자 및 사용 사례 (Users & use cases)
- 주요 사용자: 최첨단 모델(frontier-model)의 가격을 지불하지 않고도 신뢰성이 필요한 개발자/연구자로서, 저렴한 오픈 웨이트 (open-weight) 모델(OpenRouter 또는 로컬 추론을 통해)로 다단계 추론(multi-step reasoning) 또는 문서 기반 연구(research-over-documents) 워크로드를 실행하는 사람.
- 사용 사례:
- U1: 제공된 문서에 대한 멀티홉 질의응답 (Multi-hop question answering), 출력물로 감사 가능한 논증 그래프를 제공.
- U2: 주장 검증 (Claim verification) — "여기에 결론이 있습니다. 이 결론이 실패하려면 얼마나 많은 부분이 틀려야 합니까?"
- U3: 모든 에이전트가 사용할 수 있는 MCP 도구로서, 논증을 위한 외부 작업 기억(working memory)과 구조적 자기 검증 기능을 제공.
5. 목표 및 성공 지표 (Goals & success metrics)
| # | 목표 (Goal) | 지표 (Metric) | 목표치 (Target) |
|---|---|---|---|
| G1 | 스크리닝을 통해 근거가 확실한 모델 식별 | 스크리닝 결과 모델별 근거 기반(grounded%) / 암기 기반(memorized%) / 기권(abstain%) 비율 산출 | 스크리닝 엔드-투-엔드(end-to-end) 실행 비용 < $1 |
| ... |
6. 비목표 (Non-goals)
- 진리 판독기(truth oracle)가 아님. 그래프는 논증의 _형태(shape)_를 검증합니다. 모든 에지는 오직 모델에 의해서만 의미론적으로 보증됩니다. 유효하게 연결된 쓰레기 데이터(garbage)도 구조 검사를 통과합니다. 이는 설계 의도에 따른 것으로, 구조 계층은 의미론적 노력(재질의)이 어디로 향할지를 결정할 뿐입니다.
- 파인튜닝(fine-tuning)이나 추론 루프 수정(inference-loop surgery)을 하지 않음. 모든 기능은 표준 채팅 완료(chat-completions) + 도구 호출(tool calls)을 통해 작동합니다. 커스텀 샘플링, 템플릿 해킹,
</think>에서 멈추는 가로채기(interception) 등은 사용하지 않습니다. - 지속성(persistence) 없음. 그래프는 세션 범위 내에서만 존재하며 휘발성(in-memory)입니다. 데이터베이스는 사용하지 않습니다.
- 범용 정리 증명기(general theorem prover)가 아님. 자연어 주장 및 휴리스틱 중복 제거(heuristic dedup)를 수행하며, 형식 논리(formal logic)를 다루는 것이 아닙니다.
시스템 설계 (System Design)
1. 아키텍처 (Architecture)
그래프 서버를 위한 두 가지 배포 모드가 있으며, 코드베이스는 동일합니다:
- 라이브러리 모드 (Library mode) (오케스트레이터의 기본값): 오케스트레이터가
graph_server.store를 직접 임포트하며, MCP 전송(transport)을 사용하지 않습니다. 더 단순하고 빠르며, P3/P4 단계에서 사용합니다. - MCP 모드:
server.py가 동일한 함수들을 stdio를 통해 MCP 도구(tools)로 노출하므로, MCP 기능이 있는 모든 에이전트(Claude Code 등)가 그래프를 외부 작업 기억(working memory)으로 사용할 수 있습니다. 얇은 래퍼(thin wrapper)일 뿐이며, 전송 계층에는 로직이 전혀 없습니다.
2. 컴포넌트 A — 근거 스크리닝 (Component A — Grounding screen) (P1, 존재함)
이미 리포지토리 루트에 구현되어 있습니다: screen.py, items.jsonl (50개 항목), models.json. 규약: temperature 0, 항목/모델당 1회 호출, 정규 표현식(regex) 기반 채점. README.md를 참조하세요. 출력값은 하나의 결정, 즉 오케스트레이터가 기본값으로 사용할 모델 ID를 제공합니다. 버그 수정을 제외하고는 수정하지 마십시오.
3. 컴포넌트 B — 그래프 서버 (Component B — Graph server) (P2)
3.1 데이터 모델 (Data model)
In-memory 전용. 하나의 GraphStore는 graph_id (문자열, 호출자 제공)를 키로 하여 많은 독립적인 그래프들을 보유합니다.
Node:
id: str # 호출자 제공, 그래프 내에서 고유함, 예: "r2:n4" (run 2, node 4)
claim: str # 자연어 주장 (natural-language claim), 한 문장
...
각 graph_id당 하나의 networkx.MultiDiGraph를 기반으로 합니다 (multi인 이유는 동일한 쌍 사이에 지지(support)와 공격(attack)이 모두 존재할 수 있기 때문입니다). 노드 속성(Node attrs)은 Node 필드를 보유하며, 엣지 속성(edge attrs)은 관계(relation)/신뢰도(confidence)/run_ids를 보유합니다.
수집 시 검증 (에러 메시지와 함께 거부하며, 크래시를 발생시키지 않음): 알 수 없는 type/relation, 수집 후 엣지 엔드포인트가 그래프에 존재하지 않음, 신뢰도가 [0,1] 범위를 벗어남, 다른 주장(claim) 텍스트를 가진 중복된 노드 ID (동일한 ID + 동일한 주장 = 멱등성(idempotent), run_ids 병합).
3.2 공개 함수 / MCP 도구 (Public functions / MCP tools)
8개의 함수. 아래의 시그니처(Signatures)는 라이브러리 API이며, MCP 도구 스키마는 graph_id가 항상 첫 번째 파라미터인 상태로 이를 1:1로 반영합니다.
| # | 함수 (Function) | 파라미터 (Params) | 반환값 (Returns) |
|---|---|---|---|
| 1 | assert_graph | graph_id, nodes[], edges[] | {accepted_nodes, accepted_edges, rejected: [{item, reason}], auto_merged: [[kept_id, merged_id], ...]} — 기존 노드들에 대해 새로운 노드들의 중복 제거(§3.3)를 자동으로 실행합니다 |
| ... |
1, 2, 7번을 제외한 모든 함수는 반드시 순수 읽기(pure-read)여야 합니다. 모든 함수는 반드시 JSON 직렬화 가능한 딕셔너리(dict)를 반환해야 합니다. 에러는 {error: "..."}를 반환하며, MCP 경계를 넘어 예외(raise)를 발생시켜서는 안 됩니다.
3.3 중복 제거 / 병합 (Dedup / merge) (핵심 구성 요소)
목적: 서로 다른 실행(run)에서 발생한 동일한 주장은 반드시 하나의 노드로 병합되어야 합니다. 그렇지 않으면 (a) 의역(paraphrase)으로 인해 지지 폭(support width)이 부풀려지고, (b) 모순(contradictions)이 서로 만나지 못하게 됩니다.
정규화 (Normalization) norm(claim):
- 소문자 변환; 유니코드 NFC
- 숫자 내부의
.및%를 제외한 구두점 제거 - 숫자 정규화 (canonicalize): 천 단위 구분 기호 제거 (
84,200→84200) - 공백 축소 (collapse whitespace)
- 공백 기준으로 토큰화 (tokenize); 영어 불용어(stopwords) 제거 (작은 고정 목록: a, an, the, is, are, was, were, of, in, on, at, to, that, this, it, and)
부정 가드 (Negation guard) (유사도 검사 전에 확인): NEG = {not, no, never, cannot, "n't", without, false}라고 정의합니다. 만약 tokens(a) - NEG == tokens(b) - NEG를 만족하지만, 두 토큰의 부정 토큰 개수 기우성(parity)이 다르다면 → 병합하지 마십시오. 대신 두 노드 사이에 상호 attacks (공격) 에지를 생성하고 contradictions_created (생성된 모순)에 보고하십시오.
수치 충돌 가드 (Numeric-conflict guard): 토큰 집합이 서로 다른 숫자 토큰을 제외하고는 동일하다면 (예: "trellium melts at 412" vs "trellium melts at 350") → 병합하지 마십시오. 상호 attacks 에지를 생성하고 보고하십시오.
유사도 (Similarity) (가드 통과 시에만 수행): jaccard(tokens_a, tokens_b) >= 0.7 이거나 difflib.SequenceMatcher(None, norm_a, norm_b).ratio() >= 0.85인 경우에만 병합합니다. 두 임계값은 설정을 통해 조절 가능(tunable)합니다. (v1 업그레이드 경로로서, 소규모 문장 임베딩 모델(sentence-embedding model)을 이용한 코사인 유사도(cosine similarity) 방식은 현재 범위 외 사항입니다. 인터페이스는 동일하게 유지하십시오.)
병합 정책 (Merge policy): 가장 이른 단언(assertion)을 가진 노드를 유지합니다 (안정적 순서: 첫 번째 run_id, 그다음 node id). run_ids와 별칭(aliases)은 합집합(union) 처리합니다. 최대 신뢰도(max confidence)를 유지하고, 모든 에지를 유지된 노드로 재지정(re-point)합니다. 동일한 관계를 가진 결과적인 병렬 에지들은 하나로 통합합니다 (최대 신뢰도 적용, run_ids 합집합). 병합된 노드들의 타입(type)이 서로 다를 경우, given 타입이 inference 타입보다 우선하며, inference는 assumption 타입보다 우선합니다. refuted=True (반박됨) 노드를 활성(live) 노드에 병합하지 마십시오. 활성 노드를 반박된 노드에 병합하는 것은 가능하며, 이 경우 반박된 상태를 유지합니다.
클러스터링 (Clustering): 쌍별 매칭(pairwise matches)에 대해 유니온 파인드(union-find)를 적용합니다 (O(n²) 쌍별 연산은 괜찮습니다. 그래프는 수백 개의 노드 규모이며 수백만 개가 아닙니다).
3.4 구조적 검사 (networkx 레시피)
별도의 명시가 없는 한, supports+assumes 서브그래프 (supports+assumes subgraph) (attacks 에지는 제외)를 대상으로 작업합니다. 멀티그래프(multigraph)를 축소하여 (src, dst)당 최대 신뢰도를 유지하는 D = nx.DiGraph 뷰를 구축합니다.
- orphans (고아 노드):
type=given이 아니면서type=assumption도 아닌, 진입 차수(in-degree)가 0인 노드들 (가정(assumptions)은 실수(float)로 선언되지만, 페이로드에는 여전히assumptions로 별도 보고됩니다 — 구현 시assumptions: [id]키를 포함할 것). - cycles (사이클):
list(nx.simple_cycles(D))를 사용하며, 출력은 처음 10개로 제한합니다. - unreachable_conclusion (도달 불가능한 결론): 모든 주어진(given)
g에 대해descendants(D, g)에 결론이 포함되지 않는 경우입니다. 한 번만 계산합니다:reachable = 모든 given g에 대해 nx.descendants(D, g) | {g}의 합집합; 결론이reachable에 포함되지 않으면 도달 불가능한 것으로 간주합니다. - refuted_but_feeding (반박되었으나 영향을 주는 노드):
refuted=True이지만 여전히D에서 결론까지의 경로가 존재하는 노드들입니다. - critical_links (임계 링크):
nx.minimum_node_cut(D_aug, s, t)및nx.betweenness_centrality_subset(D, sources=givens, targets=[conclusion])를 통한 매개 중심성(betweenness centrality)을 계산합니다. 여러 소스가 있는 s-t 계산의 경우, 모든 given에 에지를 연결하는 가상 슈퍼 소스(super-source)__S__를 추가하고(신뢰도 1.0), 결론을 싱크(sink)로 사용합니다. 결과에__S__를 절대 보고하지 마십시오. 브리지 에지(Bridge edges): 제거 시 결론에 도달할 수 없게 만드는 에지입니다 (경로 상의 각 에지를 테스트합니다; 그래프 규모가 작으므로 브루트 포스(brute force) 방식도 괜찮습니다).
3.5 support_width & surviving_claims
support_width (지지 폭) (Menger 정리): D_aug (슈퍼 소스 __S__ → 모든 반박되지 않은 given) 상에서 계산:
disjoint_paths = len(list(nx.node_disjoint_paths(D_aug, "__S__", conclusion)))— 보고되는 경로에서__S__를 제거합니다.NetworkXNoPath발생 시 0으로 처리합니다.max_flow (최대 유량): 용량(capacities) = 에지 신뢰도; 노드 용량 = 노드 신뢰도 (표준 노드 분할(node-splitting) 방식을 통해 구현: v → v_in, v_out, 용량 = 신뢰도). 분할된 그래프에서nx.maximum_flow_value를 계산합니다. Given 및__S__에지는 무한대(∞) 용량을 가집니다 (1e9 사용).
surviving_claims (생존하는 주장) (공격에 대한 근거 기반 의미론(grounded semantics), 이후 도달 가능성 검토):
A = 공격 에지만 있는 서브그래프 (모든 노드, 공격 에지)
모든 노드에 UNDEC 레이블 부여
변화가 없을 때까지 반복:
...
전체 레이블링과 surviving을 반환합니다.
3.6 disputed_nodes
contradiction_pairs: §3.3의 가드(guards)에 의해 생성된 상호 공격(mutual attacks)으로 연결된 모든 쌍과, 호출자(caller)가 명시적인 상호 공격을 주장한 모든 쌍.isolated_load_bearing:len(run_ids) == 1이면서 (주어진 조건에서 결론까지의 매개 중심성 부분집합(betweenness_subset) > 0 이거나, 해당 노드가 주어진 조건→결론 사이의 임의의 단순 경로(simple path) 상에 위치함)을 만족하는 노드. 이들은 주요 환각(confabulation) 의심 대상이며, 오케스트레이터(orchestrator)는 이들을 가장 먼저 재심문합니다.
4. Component C — Orchestrator (P3)
CLI: python -m orchestrator.run --task task.json --model <id> --n 6 --k 2 --budget-calls 20 --temp 0.8
task.json: {"question": str, "documents": [str], "expected_answer": str|null} (expected_answer는 평가 하네스(eval harness)에서만 사용됨).
4.1 제어 루프 (Control loop)
1. FAN OUT: N개의 병렬 심문 호출 (각각 새로운 컨텍스트, temperature=temp).
각 호출은 다음을 받음: 시스템 프롬프트 (§4.2) + 문서(documents) + 질문(question).
각 응답의 JSON 그래프 (§4.3)를 파싱함. run_id="r{i}"로 assert_graph 수행,
...
4.2 프롬프트 템플릿 (Prompt templates) (있는 그대로의 시작점; 평가 증거를 통해서만 반복 개선함)
Template A — 심문 (interrogation) (system):
당신은 엄격한 논증을 구축하고 있습니다. 문서를 읽고, 명시적인 추론 그래프(reasoning graph)를 구성하여 질문에 답하십시오.
...
Template B — 검증 (verification) (system; 새로운 컨텍스트, 그래프 미표시):
문서에 근거하여 하나의 주장(claim)을 평가하십시오. 오직 JSON으로만 응답하십시오:
{"verdict": "supported" | "refuted" | "not_determinable",
"reason": "<문서 또는 공백을 인용하는 한 문장>"}
...
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기