본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 22. 03:52

인터넷 탐정 AI 구축하기: 프로덕션급 멀티 에이전트 (Multi-Agent) AI 시스템

요약

개인의 디지털 발자국을 분석하여 상세한 보고서를 생성하는 7-에이전트 AI 파이프라인 구축 사례를 소개합니다. Next.js 15 기반의 바이럴 앱이자, 프로덕션 환경에 즉시 적용 가능한 참조 아키텍처를 제공합니다.

핵심 포인트

  • 7개의 에이전트로 구성된 멀티 에이전트 파이프라인 설계
  • 어댑터 패턴을 활용한 다양한 AI 프로바이더(OpenAI, Anthropic 등) 추상화
  • Next.js 15 기반의 확장 가능한 프로덕션급 아키텍처 구현
  • 단순 데모를 넘어선 실제 서비스 가능한 엔지니어링 구조 제시

당신의 LinkedIn, GitHub, Twitter, 그리고 이력서를 붙여넣으세요 — 당신의 전체 인터넷 인격에 대한 잔혹할 정도로 솔직한 AI 조사를 받아보세요.

서론 (Introduction)

Internet Detective AI는 개인의 디지털 발자국(LinkedIn URL, GitHub URL, Twitter 핸들, 이력서 텍스트)을 입력받아 **7-에이전트 AI 파이프라인 (7-agent AI pipeline)**을 통해 상세하고 재미있는 조사 보고서를 생성하는 Next.js 15 애플리케이션입니다. 출력 결과에는 증거 기반 사실, 행동 신호, 숨겨진 집착, 커리어 예측, 스타트업 패러디 피치, 동료의 인용구, 잔혹한 비난 (brutal roast), 인터넷 인격 점수, 그리고 "요리된 정도 (cooked level)" 미터기가 포함됩니다.

이 시스템은 두 가지 목적을 동시에 수행합니다:

  1. 바이럴 소비자 앱 (A viral consumer app) — 공유 가능하고, 재미있으며, 놀라울 정도로 통찰력이 있습니다. 사용자들은 최고의 비난과 인격 점수를 얻기 위해 경쟁합니다.
  2. 프로덕션 AI 엔지니어링을 위한 참조 아키텍처 (A reference architecture for production AI engineering) — 모든 계층은 교육적이고, 확장 가능하며, 프로덕션 환경에 즉시 적용할 수 있도록 설계되었습니다.

전체 시스템은 24시간 만에 구축되었으며, 현대 AI 엔지니어링의 14개 영역을 아우르고 있으며, 각 영역은 docs/ 폴더에 독립적으로 문서화되어 있습니다.

비전 (The Vision)

대부분의 AI 데모 프로젝트는 재미있지만 얕거나(예쁜 UI로 감싼 단일 API 호출), 교육적이지만 지루한(프론트엔드가 없는 Jupyter notebook) 경우가 많습니다. Internet Detective AI는 이 간극을 메웁니다:

진정으로 재미있는 소비자 앱인 동시에 포괄적인 참조 아키텍처 역할을 하는 단일 코드베이스.

모든 엔지니어링 결정은 두 그룹의 청중을 염두에 두고 내려졌습니다: 자신의 비난을 보고 싶어 하는 최종 사용자, 그리고 프로덕션 AI 시스템이 어떻게 작동하는지 이해하고 싶어 하는 개발자입니다. 그 결과,

┌─────────────────────────────────────────────────────┐
│                   Next.js 15 App                     │
│  ┌─────────────┐  ┌──────────────┐  ┌────────────┐ │
...

요청 흐름은 다음과 같습니다: HTTP Request → API Route → Context Builder → Orchestrator → 7 Agents → Governance Loop → Synthesis → Response.

프로바이더 추상화 (Provider Abstraction)

가장 근본적인 아키텍처 결정은 **모든 에이전트 (Agent)**를 **특정 AI 프로바이더 (Provider)**로부터 분리하는 것이었습니다. 우리는 ProviderAdapter 인터페이스를 사용하여 어댑터 패턴 (Adapter pattern)을 사용합니다:

// src/lib/providers/types.ts
export interface ProviderAdapter {
  name: ProviderType;
...

모든 프로바이더는 이 인터페이스를 구현합니다. 팩토리 (Factory)가 인스턴스화 및 설정을 처리합니다:

// src/lib/providers/factory.ts
export class ProviderFactory {
  private static registry = loadConfig();
...

레지스트리 (Registry)는 기본적으로 7개의 프로바이더를 지원합니다: Zen, OpenAI, Anthropic, Gemini, OpenRouter, Featherless, 그리고 Ollama. 각 프로바이더는 환경 변수 (Environment variables)에 의해 제어됩니다. 만약 키가 누락되면, getAllAvailableProviders()에서 단순히 제외됩니다.

BaseProvider 추상 클래스는 재시도 로직 (Retry logic)을 포함한 에러 핸들링 (Error handling), 지연 시간 측정 (Latency measurement), 그리고 비용 계산 (Cost calculation)과 같은 공통 동작을 추가합니다:

// src/lib/providers/base.ts
export abstract class BaseProvider implements ProviderAdapter {
  abstract name: ProviderType;
...

결과적으로: 어떤 에이전트든 어떤 프로바이더든 사용할 수 있습니다. 환경 변수 하나만 바꾸면 앱 전체를 GPT-4o에서 Claude 또는 Gemini로 전환할 수 있습니다. 새로운 프로바이더를 추가하는 것은 정확히 하나의 어댑터 파일을 작성하는 것을 의미합니다.

멀티 에이전트 아키텍처 (Multi-Agent Architecture)

오케스트레이터 (Orchestrator)는 유향 파이프라인 (Directed pipeline)에서 7개의 에이전트를 실행합니다. 각 에이전트는 단일 책임 (Single responsibility)을 가집니다:

에이전트 (Agent)입력 (Input)출력 (Output)책임 (Responsibility)
Profile AnalystContextPackFacts, digital profile summary직접 관찰 가능한 사실 추출
...

각 에이전트는 공통 인프라를 제공하는 BaseAgent를 확장(extends)합니다:

// src/lib/agents/base.ts
export abstract class BaseAgent {
  protected config: AgentConfig;
...

모든 에이전트는 **안전한 기본값(safe defaults)과 폴백 출력(fallback outputs)**을 가집니다. 에이전트 호출이 실패하더라도(타임아웃, 파싱 오류, 프로바이더 장애 등), 오케스트레이터(orchestrator)가 이를 포착하여 전체 파이프라인을 중단시키는 대신 성능이 저하된 데이터(degraded data)를 가지고 작업을 계속 진행합니다.

오케스트레이터는 에이전트들을 순차적으로 실행하며, 그 출력값을 다음 단계로 전달합니다:

// src/lib/agents/orchestrator.ts
export class InvestigationOrchestrator {
  async investigate(context: ContextPack) {
...

거버넌스 루프(governance loop)가 핵심입니다. 만약 거버넌스 에이전트가 위반 사항을 발견하면, 오케스트레이터는 입력을 정화(sanitize)하고 사용 가능한 최선의 결과를 수락하기 전까지 최대 2회까지 재시도합니다. 이는 **자기 수정 파이프라인 (self-correcting pipeline)**을 형성합니다.

컨텍스트 엔지니어링 (Context Engineering)

가공되지 않은 프로필 입력은 LinkedIn URL, GitHub 사용자 이름, 자유 형식의 이력서, Twitter 바이오 등 다양한 형태로 들어옵니다. ContextBuilder 클래스는 이 모든 것을 구조화된 ContextPack으로 정규화(normalize)합니다.

컨텍스트 파이프라인은 세 가지 단계로 구성됩니다:

  1. 추출 (Extraction) — LinkedIn, GitHub, Twitter 및 이력서 텍스트로부터 학력, 경력, 기술, 리포지토리(repos) 및 통계 데이터를 독립적으로 파싱하여 추출합니다.
  2. 중복 제거 (Deduplication) — 복합 키(composite keys)를 사용하여 중복을 제거하며 여러 소스 간의 데이터를 병합합니다:
   private deduplicateEducation(items: Education[]): Education[] {
     const seen = new Set<string>();
     return items.filter((item) => {
...
  1. 압축 (Compression) — 중복된 줄을 제거하고, 공백을 정규화하며, 압축률을 계산합니다:
   private compressContent(text: string): string {
     if (!text || text.length < 500) return text;
     const lines = text.split("\n");
...

빌더(Builder)는 또한 경력 연수, 리더십 역할, 주요 기업, 오픈 소스 인기, 트렌드 중심 분야와 같은 **핵심 신호 (key signals)**를 초기에 추출하며, 이는 모든 에이전트에게 컨텍스트 (context)로 전달됩니다. 이러한 조기 신호 추출은 각 에이전트가 명백한 패턴을 다시 발견해야 하는 부담을 줄여주어, 토큰 (tokens)을 절약하고 정확도를 향상시킵니다.

구조화된 출력 (Structured Outputs)

모든 에이전트는 타입이 지정된 JSON을 반환합니다. 전체 보고서 스키마 (schema)는 TypeScript로 정의됩니다:

// src/lib/types.ts
export interface InvestigationReport {
  id: string;
...

에이전트는 JSON 모드 (response_format: { type: "json_object" })와 파싱 (parsing) 및 오류 복구 (error recovery)를 처리하는 chatJSON<T> 헬퍼 (helper)를 사용합니다:

// src/lib/ai.ts
async chatJSON<T>(
  options: AIRequestOptions,
...
```
{% endraw %}
json\s*/gi, "")
    .replace(/\n{% raw %}\n```\s*$/g, "")
    .trim();

  let parsed: T;
...

모든 JSON 응답은 파서 복구 (parser recovery) 과정을 거칩니다. 시스템은 마크다운 코드 펜스 (markdown code fences)를 제거하고, 공백을 다듬으며, 출력이 잘못된 형식일 경우 부분 일치 (partial matching) 방식으로 전환합니다. safeProcess 패턴과 결합되어, 이는 단일 에이전트의 실패가 전체 조사 과정을 중단시키지 않음을 의미합니다.

프롬프트 엔지니어링 (Prompt Engineering)

프롬프트 (Prompts)는 prompts/system/ 디렉토리에 별도의 마크다운 파일로 저장되며 PromptRegistry에 의해 로드됩니다:

// src/lib/prompts/index.ts
export class PromptRegistry {
  private prompts: Map<AgentType, string> = new Map();
...

이는 코드를 수정하지 않고도 프롬프트를 편집할 수 있음을 의미하며, 기술적 지식이 없는 이해관계자와의 반복 작업(iteration)이나 프롬프트 변형에 대한 A/B 테스트를 수행할 때 유용합니다.

모든 프롬프트 파일은 일관된 구조를 따릅니다: 목적 (Purpose) → 버전 (Version) → 예상 입력 (Expected Inputs) → JSON 스키마 (JSON Schema) → 단계별 지침 (Step-by-Step Instructions) → 실패 모드 (Failure Modes) → 가드레일 (Guardrails) → 예시 출력 (Example Outputs) → "이것이 중요한 이유 (Why This Matters)".

"이것이 중요한 이유" 섹션은 핵심적인 교육적 기능입니다. 예를 들어, Roast Agent 프롬프트는 자신의 설계 선택이 왜 효과적인지를 설명합니다:

🎭 페르소나 기반 프롬프팅 (Persona-Driven Prompting): "독설가 코미디언(roast comedian)" 페르소나는 의도적인 선택입니다. 이는 모델을 특정 어조, 어휘, 그리고 윤리적 프레임워크(ethical framework) 내로 제한합니다. 페르소나 프롬프트는 모델의 사회적 역할에 대한 이해를 활성화하기 때문에 가장 효과적인 프롬프트 엔지니어링 (prompt engineering) 기술 중 하나입니다.

📎 구체성 = 가장 큰 재미 (Specificity = Funniest): 항상 실제 프로필 데이터를 참조하라는 지침은 코미디 이론에 근거합니다. 즉, 구체적인 유머가 일반적인 유머보다 더 뛰어난 성능을 발휘합니다. "그들의 GitHub에는 별점이 0개인 저장소가 47개나 있습니다"라는 표현은 "그들은 코딩을 많이 합니다"보다 더 재미있습니다.

⚖️ 친절함의 관문 (The Kindness Gate): "친절함 체크(kindness check)" 단계를 추가하는 것은 윤리적인 프롬프트 엔지니어링 패턴입니다. 이는 단순한 가드레일("무례하게 굴지 마세요")을 설정하는 대신, 모델의 마음 이론 (theory of mind) 능력을 활용한 사회적 시뮬레이션으로 체크 과정을 프레임화합니다.

이러한 문서 우선 (documentation-first) 접근 방식은 프롬프트 디렉토리를 교육용 리소스로 변모시킵니다.

거버넌스 및 안전 (Governance & Safety)

이 시스템은 파이프라인의 서로 다른 시점에서 실행되는 **두 개의 독립적인 안전 계층 (safety layers)**을 갖추고 있습니다.

입력 안전 (SafetyChecker)

어떠한 에이전트가 데이터를 처리하기 전에 실행됩니다. 네 가지 위협 카테고리를 탐지합니다:

// src/lib/safety/index.ts
export class SafetyChecker {
  checkPrompt(input: string): SafetyCheck {
...

프롬프트 인젝션 (Prompt injection) 탐지는 일반적인 탈출 기법("ignore all previous instructions", "you are now...", "DAN", "developer mode")을 겨냥한 19개의 정규 표현식 (regex) 패턴을 사용합니다. 개인정보 (PII) 탐지는 이메일, 전화번호, 사회보장번호 (SSN), 신용카드, 주소 및 여권 번호를 포착합니다.

출력 거버넌스 (GovernanceValidator)

에이전트가 콘텐츠를 생성한 후에 실행됩니다. 7가지 금지된 속성에 대해 검사합니다: 인종, 민족, 종교, 성적 지향, 정신 건강, 의학적 진단, 정치적 성향 및 범죄 활동.

// src/lib/governance/index.ts
export class GovernanceValidator {
  validate(report: Partial<InvestigationReport>): GovernanceCheck {
...

거버넌스 에이전트 (Governance Agent)는 오케스트레이터 (Orchestrator) 내에서 validate → retry → sanitize 루프를 통해 작동합니다. 위반 사항이 발견되면, 오케스트레이터는 문제가 되는 사실을 제거하고 거버넌스 체크 (Governance Check)를 재시도합니다. 만약 MAX_GOVERNANCE_RETRIES 이후에도 위반 사항이 지속되면, 해당 내용은 편집 (Redaction)을 통해 정화 (Sanitize)되고 메타데이터 (Metadata)로 기록됩니다.

평가 (Evaluations)

평가 프레임워크는 생성된 모든 보고서를 **5가지 지표 (Metrics)**를 통해 측정합니다:

// src/lib/eval/index.ts
computeMetrics(report: InvestigationReport, context: ContextPack) {
  return {
...
  • JSON 준수 여부 (JSON Compliance) — 모든 필수 필드가 존재하고 예상된 타입과 일치하는지 확인합니다.
  • 일관성 (Consistency) — 사실 관계가 요약, 경력 예측 및 타임라인과 얼마나 잘 일치하는지 측정합니다.
  • 환각률 (Hallucination Rate) — 단어 중첩 분석 (Word-overlap analysis)을 사용하여 사실 텍스트를 소스 컨텍스트 (Source Context)와 비교합니다.
  • 유머 점수 (Humor Score) — 풍자 (Roasts)의 다양성, 강도 분포 및 품질 신호를 평가합니다.
  • 정확도 (Accuracy) — 환각률의 역수입니다.

평가 데이터셋에는 4가지 카테고리(개발자, 디자이너, 창업자, 크리에이터)에 걸친 20개의 프로필이 포함되어 있으며, 각 프로필은 예상 점수 범위와 최소 사실 개수를 가집니다:

{
  "id": "dev-1",
  "name": "Senior Full-Stack Developer",
...

compareModelsWithConfigs 메서드는 동일한 데이터셋을 여러 모델/제공자 (Model/Provider) 쌍에 대해 실행하여 지연 시간 (Latency), 비용 (Cost) 및 품질 점수 (Quality Scores)를 나란히 비교하여 생성하며, 이를 통해 데이터 기반...

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0