MeshProof: 두 모델이 합의할 때까지 수렴하는 QA 시스템
consensus-verifiers로 만드는 신뢰형 LLM 파이프라인
(1/3) 왜 "두 모델 합의(Consensus)"인가 — 문제 정의 → 설계
🎯 한 문장 요약
MeshProof는 GPT와 Claude가 서로의 답을 검증하고 합의할 때까지 수렴시켜 신뢰 가능한 최종 답을 만드는 QA 시스템입니다.
🔍 문제 정의
현재 LLM의 한계
문제점 설명 예시
| 틀린 확신 | Hallucination으로 잘못된 정보를 확신있게 전달 | "2024년 노벨물리학상은 김철수가 수상했습니다" |
| 형식 오류 | 요청한 형태와 다른 응답 형식 | JSON 요청했는데 일반 텍스트로 응답 |
| 검증 불가 | 답변의 근거나 신뢰도를 알 수 없음 | "이 정보가 정확한가?" → 별도 확인 필요 |
| 출처 부족 | 중요한 사실 확인이 필요한데 링크나 날짜 없음 | "한국 수출 통계" → 출처나 기준일 미표기 |
사용자가 원하는 것
- ✅ 정확성: 검증된 올바른 정보
- ✅ 설명가능성: 단순한 답이 아닌 검증 가능한 이유
- ✅ 신뢰도: 답변에 대한 정량적 신뢰 지표
- ✅ 추적가능성: 출처와 근거가 명확한 답변
💡 핵심 가설
1. 중복성 (Redundancy)
// 동시에 두 모델 호출
const [gptAnswer, claudeAnswer] = await Promise.all([
askOpenAI(question),
askAnthropic(question)
]);
// 결과가 같으면 신뢰도 ⬆
if (isConsensus(gptAnswer, claudeAnswer)) {
return { confidence: 0.95, agreed: true };
}
이질적인 두 모델이 같은 결론이면 신뢰도가 오른다.
2. 규칙 검증 (Verification)
const registry = new VerifierRegistry()
.use(MathSumVerifier()) // 수학 계산 정확성
.use(FactCitationVerifier({ // 출처 검증
minLinks: 2, // 최소 2개 링크
requireDeepLinks: true, // 상세 페이지 필요
requireDatesInReasoning: true // 날짜 표기 필수
}))
.use(BasicQualityVerifier()) // 기본 품질
.use(FormatRegexVerifier()); // 형식 검증
// 점수 산출: 0.6 * 기본통과 + 0.2 * 깊은링크비율 + 0.2 * 도메인가중치
**도메인 전용 검증기(Verifier)**로 답을 정량 평가하면 품질이 오른다.
3. 합의 (Consensus)
// 수학 문제: 정수쌍 정규화로 세트 동치 비교
function canonicalizePairs(text: string): string {
// "(1,4), (2,3)" → "[[1,4],[2,3]]"
// "(2,3), (1,4)" → "[[1,4],[2,3]]" (동일)
}
// 일반 문제: OpenAI Judge 활용
const verdict = await judgeOpenAI(question, gptAnswer, claudeAnswer);
// → { relation: "equivalent"|"different", winner: "A"|"B"|"tie" }
다르면 정규화 비교 또는 Judge AI 판정으로 최종 답 결정.
🏗️ 시스템 아키텍처
graph TB
A[React Frontend<br/>Vite + TypeScript] --> B[Express.js API Server<br/>Node.js + TypeScript]
B --> C[Authentication<br/>JWT Cookie + CSRF]
B --> D[Key Vault<br/>AES-256-GCM Encryption]
B --> E[Orchestrator Engine]
E --> F[OpenAI Provider<br/>gpt-5 + Responses API]
E --> G[Anthropic Provider<br/>claude-sonnet-4]
E --> H[OpenAI Judge<br/>답변 동치성 판정]
B --> I[Verifier Registry<br/>플러그인 시스템]
I --> J[math.sum<br/>정수쌍 합계 검증]
I --> K[fact.citation<br/>출처 링크 검증]
I --> L[basic.quality<br/>답변 품질 검증]
I --> M[format.regex<br/>형식 검증]
B --> N[(SQLite Database<br/>사용자/암호화키)]
style E fill:#fff3e0
style I fill:#e8f5e8
style F fill:#e3f2fd
style G fill:#fce4ec
핵심 데이터 타입
// 표준화된 답변 스키마
type Answer = {
answer: string; // 최종 답변
reasoning?: string; // 근거 (출처 링크 포함)
confidence?: number; // 0~1 자체 신뢰도
assumptions?: string[]; // 전제 조건들
};
// 검증 결과
type VerifyResult = {
ok: boolean; // 통과 여부
score?: number; // 0~1 정량 점수
notes?: string[]; // 상세 메모
evidence?: string[]; // 추출된 링크들
category?: string; // 검증기 분류
};
⚖️ 합의 전략 (도메인별 실제 구현)
📊 수학 문제: 정수쌍 정규화
// 질문: "더해서 5가 나오는 정수 2개의 쌍은?"
function canonicalizePairs(text: string): string {
const pairs: Array<[number, number]> = [];
// (x,y) 패턴 추출
for (const m of text.matchAll(/\((-?\d+)\s*[,;]\s*(-?\d+)\)/g)) {
const a = Number(m[1]), b = Number(m[2]);
pairs.push([Math.min(a, b), Math.max(a, b)]);
}
// "x + y" 패턴 추출
for (const m of text.matchAll(/(-?\d+)\s*\+\s*(-?\d+)/g)) {
const a = Number(m[1]), b = Number(m[2]);
pairs.push([Math.min(a, b), Math.max(a, b)]);
}
// 중복 제거 후 정렬
const uniq = Array.from(new Set(pairs.map(([a,b]) => `${a},${b}`)))
.map(s => s.split(",").map(Number) as [number, number]);
uniq.sort((p, q) => (p[0] - q[0]) || (p[1] - q[1]));
return JSON.stringify(uniq);
}
// 예시 비교
GPT: "(1,4), (2,3)" → "[[1,4],[2,3]]"
Claude: "(2,3), (1,4)" → "[[1,4],[2,3]]" ✅ 동치!
🧠 일반 지식: Judge AI 판정
const judgePrompt = `You are a strict judge. Output a JSON object with keys:
relation: "equivalent"|"different"
winner: "A"|"B"|"tie"
rationale: short string`;
// 실제 판정 예시
{
"relation": "different",
"winner": "B",
"rationale": "Answer B provides more comprehensive analysis with concrete examples"
}
🔗 출처 검증: 실제 링크 품질 평가
const FactCitationVerifier = ({
minLinks: 2, // 최소 2개 링크 필요
requireDeepLinks: true, // 루트 도메인 금지
minDeepLinks: 1, // 깊은 링크 최소 1개
requireDatesInReasoning: true, // YYYY-MM-DD 날짜 필수
weights: {
whitelistBoost: {
"kostat.go.kr": 0.25, // 통계청 가산점
"bok.or.kr": 0.2, // 한국은행 가산점
"kita.net": 0.15 // 무역협회 가산점
},
blacklistPenalty: {
"medium.com": 0.2, // 개인 블로그 감점
"tistory.com": 0.15 // 개인 블로그 감점
}
}
});
// 점수 계산: 0.6 * 기본통과 + 0.2 * 깊은링크비율 + 0.2 * 도메인가중치
🔄 오케스트레이션 플로우
flowchart TD
A[질문 입력] --> B[병렬 모델 호출]
B --> C[GPT 답변]
B --> D[Claude 답변]
C --> E[검증기 실행]
D --> F[검증기 실행]
E --> G{수학 문제?}
F --> G
G -->|Yes| H[정수쌍 정규화 비교]
G -->|No| I[Judge AI 판정]
H --> J{세트 동치?}
I --> K{동치 판정?}
J -->|Yes| L[✅ 합의 달성<br/>즉시 반환]
K -->|equivalent| L
J -->|No| M[재시도 필요?]
K -->|different| N[승자 선택]
M -->|Yes| O[출처 보강 재요청]
M -->|No| N
O --> B
N --> P[최종 답변 반환]
L --> P
style L fill:#c8e6c9
style P fill:#fff3e0
실제 정지 조건 (우선순위)
순위 조건 행동 신뢰도
| 1순위 | 🎯 수학 세트 동치<br/>canonicalizePairs(A) === canonicalizePairs(B) | 즉시 정지 | 최고 (95%+) |
| 2순위 | 🤝 Judge: equivalent<br/>verdict.relation === "equivalent" | 검증점수 높은 쪽 | 높음 (85-95%) |
| 3순위 | 🏆 Judge: 명확한 승자<br/>verdict.winner !== "tie" | 승자 선택 | 중간 (70-85%) |
| 4순위 | 🔄 재시도 조건<br/>출처 부족 시 1회 재요청 | 보강 후 재판정 | 개선됨 |
| 5순위 | ⚖️ 점수 기반 선택<br/>verifierScore + confidence | 높은 점수 선택 | 낮음 (50-70%) |
🎪 실제 동작 예시
Case 1: 수학 문제 (세트 동치 합의)
📝 질문: "더해서 5가 나오는 정수 2개의 쌍은?"
🤖 GPT: {
answer: "(1,4), (2,3)",
reasoning: "1+4=5, 2+3=5 입니다.",
confidence: 0.95
}
🤖 Claude: {
answer: "(2,3), (1,4)",
reasoning: "기본적인 정수쌍입니다. 2+3=5, 1+4=5",
confidence: 0.90
}
🔍 정규화:
GPT → "[[1,4],[2,3]]"
Claude → "[[1,4],[2,3]]" ✅ 동치!
🎯 결과: 즉시 합의 달성 (신뢰도: 95%)
Case 2: 출처 부족으로 재시도
📝 질문: "2024년 한국 수출 통계는?"
🤖 GPT (1차): {
answer: "2024년 한국 수출은 전년 대비 증가했습니다",
reasoning: "무역 관련 데이터 분석 결과입니다" ❌ 출처 없음
}
🔍 검증 결과: minLinks 미달, 날짜 표기 없음
🔄 재시도 요청:
"[중요 지시]
- reasoning에 최신 출처를 최소 2개 포함하세요
- 홈페이지 루트 링크 금지, 상세 페이지(Deep link) URL 사용
- 발표/게시 날짜(YYYY-MM-DD) 표기하세요"
🤖 GPT (2차): {
answer: "2024년 한국 수출은 6,835억 달러로 전년 대비 8.9% 증가",
reasoning: "관세청 수출입 통계(2024-12-01): https://unipass.customs.go.kr/stats/2024/export-stats,
KOTRA 보고서(2024-11-28): https://kita.net/trade-report/2024-export-analysis",
confidence: 0.88
}
✅ 검증 통과: 깊은 링크 2개, 날짜 표기 완료
Case 3: Judge 개입 (서로 다른 관점)
📝 질문: "블록체인 기술의 미래 전망은?"
🤖 GPT: "기술적 혁신과 확장성 개선이 핵심..."
🤖 Claude: "규제 환경과 사회적 수용성이 더 중요..."
⚖️ Judge 판정: {
"relation": "different",
"winner": "B",
"rationale": "Claude's answer covers broader perspective including regulatory aspects"
}
🏆 결과: Claude 답변 선택 (신뢰도: 78%)
🛠️ 기술적 특징
플러그인형 검증 시스템
// 새로운 검증기 추가가 간단
const registry = new VerifierRegistry()
.use(MathSumVerifier())
.use(FactCitationVerifier({
weights: {
whitelistBoost: { "stat.kita.net": 0.25 } // 도메인별 가중치
}
}))
.use(BasicQualityVerifier())
.use(FormatRegexVerifier(/^\d{4}-\d{2}-\d{2}$/)); // 날짜 형식 강제
// 모든 검증기 실행 후 집계
const result = await registry.verifyAndAggregate(question, answer);
안전한 키 관리 시스템
// AES-256-GCM 암호화로 API 키 저장
app.put("/api/auth/me/keys", authRequired, async (req, res) => {
const { openaiKey, anthropicKey } = req.body;
const encryptedKeys = await encryptKeys({ openaiKey, anthropicKey });
await saveUserKeys(req.user.id, encryptedKeys);
res.json({ success: true });
});
// BYOK (Bring Your Own Key) 또는 저장된 키 자동 사용
app.post("/api/orchestrate", async (req, res) => {
const keys = req.body.keys || await loadUserKeys(req.user?.id);
const result = await orchestrate(req.body.q, req.body.debug, keys);
res.json(result);
});
🔮 다음 편 예고
2편에서는 MeshProof의 핵심 검증기와 오케스트레이션 엔진 구현을 깊이 파헤칩니다:
- 🧮 MathSumVerifier: 정수쌍 추출과 정규화 알고리즘
- 🔗 FactCitationVerifier: URL 추출과 도메인 가중치 시스템
- 🤖 Judge System: OpenAI 기반 답변 동치성 판정 로직
- 🔄 Orchestration Engine: 재시도와 합의 수렴 메커니즘
- 🛡️ Security: JWT + CSRF + 키 암호화 완전 구현
핵심 질문: "어떻게 서로 다른 AI 모델들을 정교하게 검증하고 안전하게 조율할 수 있을까?"
MeshProof는 단순한 AI 답변 비교가 아닙니다.
정량적 검증과 체계적 합의를 통해 더 신뢰할 수 있는 지식을 만들어내는 엔지니어링 시스템입니다.
'MyStory > Consensus_Verifiers' 카테고리의 다른 글
| MeshProof: 두 모델이 합의할 때까지 수렴하는 QA 시스템(3) (0) | 2025.08.24 |
|---|---|
| MeshProof: 두 모델이 합의할 때까지 수렴하는 QA 시스템(2) (2) | 2025.08.24 |