Claude의 /deep-research 내부 구조 분석
요약
Claude의 /deep-research 기능이 작동하는 내부 오케스트레이션 구조를 분석합니다. JavaScript 기반의 결정론적 맵-리듀스 파이프라인과 가설 검증 루프를 통해 에이전트가 어떻게 정밀한 연구를 수행하는지 설명합니다.
핵심 포인트
- JavaScript 기반의 결정론적 맵-리듀스 파이프라인 구조
- 가설 생성 후 적대적 검증을 수행하는 bug-hunting 아키텍처 계보
- 도메인 모델링을 통한 엄격한 타입 지정 및 마이크로 태스크 제어
- 인용 관련성 향상을 위한 인용 우선 선택 및 NLI 필터링 전략
오늘 /deep-research를 한 번 호출하는 데 6.57M Fable 토큰이 소모되었습니다. 이를 대략적인 데이터 센터 에너지 추정치로 환산하면, 모델과 서빙 설정에 따라 책상용 스탠드를 몇 시간 또는 며칠 동안 켜두는 것과 맞먹는 수준입니다. 이 작업은 진정한 시스템 디자인 문제였습니다: 의료 녹취록을 평가할 때 로컬 10B MoE 모델이 인용 관련성 (citation relevance)에 대해 환각 (hallucination)을 일으키는 것을 어떻게 방지할 것인가?
그 통찰은 충분한 가치가 있었습니다. 유용한 방향은 명확했습니다: 인용 관련성을 상류 (upstream) 단계인 인용 우선 선택 (quote-first selection)으로 이동시킨 다음, 검증 레이어 (verification layer)로서 특화된 NLI/교차 인코더 (cross-encoder) 필터를 사용하는 것입니다.
하지만 저는 여전히 궁금했습니다: 이 모든 연산을 조율하는 로직은 무엇일까? 저는 무슨 일이 일어났는지 확인하기 위해 .jsonl 트레이스 (trace)와 로컬 .js 오케스트레이터 (orchestrator) 파일을 재구성했습니다.
런타임 형태는 결정론적 맵-리듀스 (Map-Reduce) 파이프라인을 실행하는 엄격한 JavaScript 파일입니다: 팬아웃 검색 (fan-out search), 가져오기 (fetch), 적대적 검증 (adversarial verify), 그리고 합성 (synthesize).
9번 라인의 주석이 그 계보를 알려줍니다:
// Ported from bughunter architecture. WebSearch/WebFetch instead of git/grep.
이것은 그들의 자동 버그 탐색 (bug-hunting) 루프를 포팅한 것으로 보입니다. 버그를 찾을 때, 실패 가설을 생성한 다음 코드에 대해 적대적으로 그 가설이 틀렸음을 입증하려고 시도합니다. 그 계보가 시스템의 형태를 설명해 줍니다: 가설을 생성하고, 그다음 그것을 제거하려고 시도하는 것입니다.
도메인 모델링: 하네스 (harness)의 해부학
소프트웨어 하네스 (software harness)는 엄격한 제약 조건 하에서 코드를 실행하도록 설계된 통제된 환경입니다. 실제로 이 스크립트는 모델에게 매번 작은 상자를 제공합니다: 질문의 범위를 정하고, 순위가 매겨진 소스를 반환하며, 인용구와 함께 주장 (claims)을 추출하고, 하나의 주장에 투표하거나, 검증된 증거를 합성합니다.
첫 번째 검색이 실행되기 전에, 스크립트는 연구 프로세스에 존재할 수 있는 것들을 정의합니다: SCOPE (범위), SEARCH (검색), EXTRACT (추출), VERDICT (판결), 그리고 REPORT (보고). 모든 LLM 호출은 강제된 타입의 출력(typed output)을 가진 마이크로 태스크 (micro-task)로 제한됩니다. 이 스키마 (schema)는 오케스트레이션 (orchestration)이 도구 호출 (tool-call) 수준에서 구조화된 JSON을 강제하기 때문에, 모델이 자유 형식의 산문으로 답변하는 것을 방지합니다. 반복되는 루트 질문 (root question)은 파이프라인 (pipeline) 후반부의 드리프트 (drift) 현상을 처리합니다.
도메인이 모델링되고 타입이 지정되면, 정렬(sort), 필터링(filter), 정족수 계산(count quorums)과 같이 표준 코드처럼 오케스트레이션을 작성할 수 있습니다.
예를 들어, 추출기 (extractor) 스키마는 claims[].quote를 요구합니다: 추출된 모든 주장 (claim)은 반드시 소스로부터 가져온 축자적 인용구 (verbatim quote)를 포함해야 합니다. 한 소스에서 추출기는 _"Simply switching stronger models cannot significantly improve..."_라는 인용구를 모델 용량 (model capacity)에 관한 주장으로 매핑했습니다. 이것이 축소판 형태의 하네스 (harness) 패턴입니다: 좁은 작업 (narrow task), 타입이 지정된 출력 (typed output), 그리고 첨부된 증거 (evidence).
네 가지 상수로 정의된 편집 정책
const VOTES_PER_CLAIM = 3
const REFUTATIONS_REQUIRED = 2
const MAX_FETCH = 15
...
시스템의 연구 정책 중 상당 부분은 파일 상단의 네 가지 변수에 위치합니다. 하나의 주장을 무효화하기 위해 얼마나 많은 의견이 필요한지, 우리가 읽을 수 있는 소스의 양은 얼마인지, 그리고 얼마나 많은 주장이 비용이 많이 드는 검증 단계 (verification step)를 거칠 가치가 있는지 등을 결정합니다.
이것이 하네스의 두 번째 절반입니다. 스키마는 작업의 형태를 제한하고, 상수 (constants)는 판단 정책 (judgment policy)을 제한합니다. 더 엄격한 검증을 원한다면 VOTES_PER_CLAIM을 5로 높이면 됩니다. 이렇게 하면 정책 변화가 디프 (diff)를 통해 명확히 드러납니다.
하나의 질문을 검색 작업으로 전환하기
스키마가 정의되면, 파이프라인은 Scope와 함께 시작됩니다. 첫 번째 에이전트 (agent)는 연구 질문을 받아 이를 좁은 범위의 검색 작업 (search jobs)으로 분해합니다.
제가 실행했을 때, 질문은 의료 녹취 평가에서의 인용구 관련성에 관한 것이었습니다: 로컬 10B MoE (Mixture of Experts) 판독기는 부분 문자열에 기반한 (substring-grounded) 인용구를 생성할 수 있었지만, 해당 인용구의 41%는 루브릭 기준 (rubric criterion)과 무관했습니다. 별도의 LLM 검증기 (verifier)는 이미 정밀도 (precision) 약 0.55에서 정체되어 있었으며, 목표치는 0.85였습니다.
Scope는 이를 구체적인 관점들로 전환했습니다:
선택 시점 기술 (Selection-time techniques) (추출형 / 제약된 인용 (extractive / constrained citation))증거 관련성을 위한 NLI / 교차 인코더 분류기 (NLI / cross-encoder classifier for evidence relevance) (저라벨 (low-label))속성 평가 관행 (Attribution evaluation practice) (ALCE, RARR, AIS, RAG 인용 시스템 (RAG citation systems))UX 저하 (UX degradation): 약하거나 누락된 증거를 정직하게 보여주기회의적 관점 (Skeptical): 왜 소형 LLM (small-LLM)의 자기 검증 (self-verification)이 실패하는가; 증류 라벨 경제성 (distillation label economics)
이는 모호한 시스템 문제를 작은 연구 영역들로 압축합니다: 인용 우선 생성 (quote-first generation), NLI 분류기 (NLI classifiers), 속성 벤치마크 (attribution benchmarks), 제품 저하 (product degradation), 그리고 전체 전제에 대한 회의적인 검토입니다.
검색 결과는 이러한 영역들을 따라갔습니다. 선택(selection) 관점에서는 Attribute First, FRONT, ReClaim을 찾아냈습니다. 분류기(classifier) 관점에서는 mDeBERTa, AttrScore, 도메인 NLI 체크포인트 (domain NLI checkpoints), SetFit, AttributionBench, CTKFactsNLI를 찾아냈습니다. 속성(attribution) 관점에서는 ALCE, RARR, AIS 및 관련 인용 품질 연구들을 찾아냈습니다. 회의적(skeptical) 관점은 나중에 중요해졌는데, 일반적인 LLM의 자기 검증 (self-verification)이 문제를 해결할 것이라는 주장에 대해 검증기 (verifier)에 반대 증거를 제공했기 때문입니다.
페이지를 주장 (claims)으로 전환하기
검색 작업은 페이지를 반환합니다. 페이지는 여전히 연구 결과가 아닙니다.
다음 단계는 Fetch/Extract (가져오기/추출하기)입니다: 선택된 각 페이지를 가져와서 작은 주장 (claim) 객체로 변환합니다.
이 시점에서 시스템은 관련성 추출 (relevance extraction)을 수행하고 있습니다. 시스템은 해당 페이지가 원래 질문에 중요한 구체적이고 인용 가능한 진술을 포함하고 있는지 확인합니다.
만약 그렇다면, 추출기 (extractor)는 다음과 같이 출력합니다:
{
claim: "...",
quote: "...",
...
만약 아니라면, 빈 리스트를 반환합니다.
원래의 연구 브리프 (research brief)가 추출기 프롬프트 (extractor prompt)에 반복되어, 모델이 근본적인 문제를 해결하는 데 도움이 되는 주장 (claims)을 끌어낼 수 있도록 합니다.
제 실행 과정에서, mDeBERTa-v3-base-xnli의 모델 카드 (model card)는 추출기가 이를 실제 작업, 즉 루브릭 기준 (rubric criterion)이 컨설팅의 인용구에 의해 뒷받침되는지 확인하는 작업과 연결했기 때문에 유용해졌습니다. AttrScore 또한 동일한 기준 설명 ↔ 인용된 증거 (criterion description ↔ quoted evidence) 구조로 매핑되었습니다.
최종 합성(synthesis) 과정은 여기서 매우 신중했습니다. UX 경로는 충분히 다뤄지지 않은 것으로 간주하여 의사결정 등급의 증거(decision-grade evidence)에서 제외했습니다. 이로 인해 증거 예산(evidence budget) 상 해당 분기는 부분적으로만 답변된 상태로 남게 되었습니다.
주장 풀(claim pool) 구축 및 순위 지정
스크립트의 중간 섹션은 Map-Reduce 파이프라인을 실행합니다. 이는 병렬 검색 쿼리(parallel search queries)를 조정하고, 중복된 URL을 필터링하며, 소스(sources)를 가져옵니다.
예산 관리는 일반 코드(plain code)가 담당합니다. 하네스(harness)는 MAX_FETCH = 15로 설정되어 있습니다. 여기에는 엄격한 규칙이 있습니다: 예산이 소진되면 medium 및 low 관련성 소스는 폐기되는 반면, high 관련성 소스는 통과됩니다.
제 실행 결과, 추출기(extractor)는 25개의 고유 소스로부터 122개의 가공되지 않은 주장(raw claims) 풀을 구축했습니다. 122개의 주장을 3인 투표 검증 패널(3-vote verifier panel)에 보내려면 366회의 값비싼 LLM 호출이 필요할 것입니다.
이 단계는 분류(triage) 단계입니다. 추출된 주장 중 검증 호출을 할 만큼 충분히 중요한 주장이 무엇인지 결정합니다.
하네스는 일반 코드로 작성된 2단계 정렬 로직을 사용합니다:
- 중요도에 따라 주장 정렬 (
central>supporting>tangential). - 중요도가 같다면 소스 품질에 따라 정렬 (
primary>secondary>blog>forum>unreliable).
상위 25개의 주장만이 검증기(verifiers)에게 전달됩니다. 나머지 97개는 버려집니다. 무엇을 확인할지 선택하는 과정은 데이터베이스 쿼리(database query)와 같습니다.
적대적 검증 (Adversarial verification)
이 단계에서 시스템은 마침내 지지 여부를 판단합니다. 상위 25개에 포함된 모든 주장은 세 명의 독립적인 에이전트(agents)에 의해 확인됩니다. 프롬프트는 과잉 해석(overreach), 모순되는 소스, 또는 체리피킹된 데이터(cherry-picked data)를 확인하는 실패 체크리스트 역할을 합니다. 명시적인 지침은 다음과 같습니다: "불확실할 경우 기본적으로 refuted=true로 설정하라." 입증 책임은 전적으로 주장에 있습니다.
다음은 적대적 패널이 제 실행 과정에서 어떻게 과잉 해석을 잡아냈는지 보여주는 사례입니다. 모델은 다음과 같은 주장을 추출했습니다: "미세 조정(fine-tuned)된 GPT-3.5조차 정밀도(precision)가 0.85를 훨씬 밑도는 수준에 갇혀 있다."
두 명의 검증 에이전트(verifier agents)가 refuted: true로 투표했습니다. 그들의 근거는 다음과 같습니다: 해당 소스 논문(AttributionBench)은 정적인 약 80%의 macro-F1만을 보고했습니다. macro-F1은 집계 지표(aggregate metric)이므로, 재현율(recall)을 희생함으로써 정밀도(precision)를 $\ge$0.85로 맞추도록 작동 임계값(operating threshold)을 조정할 수 있습니다. 해당 주장은 데이터의 범위를 넘어선 과잉 주장(overreaching)이라는 이유로 2-1로 기각되었습니다.
한편, _"강력한 모델만으로는 속성 부여(attribution) 문제를 해결할 수 없다"_라는 주장은 3-0으로 통과되었으며, 제로샷(zero-shot) GPT-4가 미세 조정(fine-tuned)된 770M FLAN-T5보다 성능이 낮음을 보여주는 기본 PDF를 통해 검증되었습니다.
또한, 이 구현체는 검증 실패(verifier failures)와 반박(refutations)을 분리합니다. 만약 검증 패널이 충돌(crash)하면 unverified를 반환합니다. 인프라 장애는 결론을 내릴 수 없는 상태(inconclusive)로 분류된 후 최종 보고서에 나타납니다.
웹을 신뢰할 수 없는 입력으로 취급하기
하네스(harness)는 모델 주변의 런타임(runtime)도 보호합니다. 에이전트가 공개 웹을 스크래핑(scrape)하고 나면, 페이지 제목, URL, 스니펫(snippets)은 로그와 진행 레이블(progress labels)로 흘러 들어가는 신뢰할 수 없는 입력(untrusted input)이 됩니다.
파일 중간에는 URL 호스트와 터미널 레이블을 정화(sanitizing)하기 위한 컴팩트한 정규 표현식(regex) 블록이 포함되어 있습니다. 주석에는 왜 URL에서 \가 경로 구분자(path separator)인지, 그리고 왜 ANSI 이스케이프 시퀀스(ANSI escape sequences), 양방향 텍스트 오버라이드(bidirectional text overrides), IDN 호모그래프(IDN homographs, 예: amazon.com의 키릴 문자 'a')를 제거하는지에 대해 설명되어 있습니다.
이 또한 하네스의 일부입니다. 이는 모델의 출력과 외부 입력이 런타임에 도달하기 전에 이를 제약합니다.
시사점
LLM이 어려운 작업을 신뢰성 있게 수행하도록 만들려면, 모델 외부에서 작업을 모델링하는 것부터 시작하십시오. 존재할 수 있는 객체(objects)를 정의하십시오. 작업을 작고 타입이 지정된 단계(typed steps)로 나누십시오. 추출된 모든 주장(claim)을 근거(evidence)와 결합하십시오. 검증하기 전에 순위를 매기십시오. 검증 실패를 그 자체의 상태로 취급하십시오. 외부 입력을 신뢰할 수 없는 것으로 취급하십시오.
모델은 국소적 추론(local reasoning)을 수행합니다. 하네스는 모델이 무엇을 보고, 내뱉고, 검증하고, 무시할 수 있는지를 결정합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기