AI 시스템 구축: RAG에서 에이전트까지
대부분의 팀은 RAG로 시작해서 한계를 발견한 뒤 파인튜닝을 덧붙입니다. 두 가지 모두 검색과 추론 문제를 해결합니다. 하지만 어느 쪽도 오케스트레이션은 해결하지 못합니다. 언제 행동할지, 에이전트를 몇 개 생성할지, 언제 멈출지, 합의가 무엇을 의미하는지를 결정하는 것 말입니다. 저는 이 세 가지를 모두 처리하는 멀티 에이전트 심의 시스템(Python 3,500줄, 훅 86개, 테스트 141개)을 구축했습니다.
요약
RAG는 쿼리 시점에 문서를 검색합니다. 파인튜닝은 도메인 데이터로 모델 가중치를 수정합니다. 둘 다 검색과 추론을 위한 도구입니다. 어느 쪽도 오케스트레이션을 처리하지 못합니다. 여러 에이전트를 조율하고, 합의를 검증하고, 특정 작업에 모델 호출이 한 번 필요한지 열두 번 필요한지 판단하는 것 말입니다. 저는 33개의 블로그 포스트에 대해 병렬 린팅, 깊이 점수 산정, 인용 검증, LLM 평가가 필요한 블로그 품질 시스템을 구축하면서 이 벽에 부딪혔습니다. 해결책은 신뢰도 기반 심의 트리거, 스폰 예산 관리, 4단계 합의 검증을 갖춘 에이전트 오케스트레이션 레이어였습니다. 이 글에서는 RAG 대 파인튜닝 결정을 다룬 후, 대부분의 가이드가 멈추는 지점 너머로 나아갑니다. 에이전트가 필요한 시점에 무슨 일이 일어나는지 말입니다.
1부: RAG vs 파인튜닝
2024년 Databricks 연구에 따르면 기업 AI 팀의 78%가 RAG를 먼저 선택했지만, 34%는 나중에 파인튜닝이 더 나은 접근이었음을 깨달았으며, 평균 3.2개월의 구현 시간을 낭비한 것으로 나타났습니다.1
이 결정은 양자택일이 아닙니다. 기법을 문제에 맞추는 것이 핵심입니다.
RAG가 유리한 경우
자주 변경되는 지식. RAG는 쿼리 시점에 최신 문서를 검색합니다. 지식 기반이 매일 업데이트되는 경우(제품 문서, 지원 문서, 규제 서류), RAG는 재훈련 없이 최신 정보를 제공합니다.2
출처 명시가 필요한 경우. RAG는 검색 과정에서 명시적인 출처 목록을 생성하기 때문에 특정 문서를 인용할 수 있습니다. 규제 산업(의료, 금융, 법률)에서 출처 명시는 컴플라이언스 요건인 경우가 많습니다.3
대규모 지식 기반. 1,000만 건의 문서에 대한 RAG 시스템은 검색 품질이 일관적이라면 100만 건 대비 동등한 성능을 보입니다. 파인튜닝된 모델은 모델 크기에 의해 결정되는 용량 한계에 도달합니다.4
파인튜닝이 유리한 경우
도메인별 추론 패턴. RAG는 정보를 제공합니다. 파인튜닝은 능력을 제공합니다. 의료 진단 대화로 파인튜닝된 모델은 감별 진단 패턴을 학습합니다. 증상에 가중치를 부여하는 방법, 희귀 질환을 고려해야 하는 시점, 추가 질문을 구성하는 방법 등입니다. RAG는 의학 지식을 제공할 수 있지만, 추론 패턴에는 가중치 조정이 필요합니다.5
엄격한 출력 형식 요건. 파인튜닝은 프롬프트 엔지니어링보다 구조화된 출력(JSON, XML, 특정 스키마)을 더 안정적으로 보장합니다. 형식 오류가 다운스트림 에러를 유발하는 시스템에서는 파인튜닝이 더 높은 신뢰성을 제공합니다.6
지연 시간이 중요한 애플리케이션. RAG는 검색 지연 시간이 추가됩니다. 쿼리를 임베딩하고, 벡터 데이터베이스를 검색하고, 문서를 가져와 프롬프트에 주입하는 과정입니다. 응답 목표가 200ms 미만인 애플리케이션에서는 파인튜닝을 통해 검색 과정을 제거해야 할 수 있습니다.7
비교 매트릭스
| 차원 | RAG | 파인튜닝 | 병합 |
|---|---|---|---|
| 지식 최신성 | 수 시간 | 수 주~수 개월 | 수 시간 |
| 초기 구축 비용 | 낮음~중간 | 중간~높음 | 높음 |
| 쿼리당 비용 | 높음 (검색 + 생성) | 낮음 (생성만) | 최고 |
| 출처 명시 | 기본 지원 | 어려움 | 부분 지원 |
| 출력 형식 제어 | 보통 | 높음 | 높음 |
| 도메인 추론 | 약함 | 강함 | 강함 |
| 지식 기반 규모 | 무제한 | 모델에 의해 제한 | 무제한 |
| 지연 시간 | 높음 | 낮음 | 최고 |
| 환각 제어 | 양호 (문서 기반) | 상이함 | 최상 |
결합 접근법
대부분의 프로덕션 시스템은 두 기법을 결합합니다. 도메인 추론 패턴과 출력 형식에 대해 모델을 파인튜닝합니다. RAG를 사용하여 쿼리 시점에 최신의 출처 명시 가능한 지식을 제공합니다. 파인튜닝된 모델은 해당 도메인에 대해 어떻게 추론할지를 알고 있습니다. RAG 시스템은 무엇에 대해 추론할지를 제공합니다.8
2부: 에이전트가 필요한 시점
RAG와 파인튜닝은 검색과 추론을 처리합니다. 어느 쪽도 오케스트레이션은 처리하지 못합니다. 특정 작업에 모델 호출이 한 번 필요한지 열두 번 필요한지 결정하고, 병렬 워커를 언제 생성할지, 그 출력을 어떻게 검증할지, 언제 사람에게 에스컬레이션할지를 판단하는 것 말입니다.
저는 블로그 품질 인프라를 구축하면서 이 벽에 부딪혔습니다. 33개의 블로그 포스트를 평가하고, 수정하고, 검증해야 했습니다. 포스트당 모델 호출 한 번으로는 부족했습니다. 각 포스트에는 린팅(12개 모듈), 깊이 점수 산정(5개 신호), 가독성 분석, 인용 검증, LLM 평가가 필요했습니다. 순차적으로 실행하면 시간이 너무 오래 걸렸습니다. 조율 없이 병렬로 실행하면 충돌과 일관성 없는 결과가 발생했습니다.
해결책은 더 많은 RAG나 더 나은 파인튜닝이 아니었습니다. 에이전트 오케스트레이션 레이어였습니다.
에이전트 오케스트레이션에 필요한 것
전통적인 ML 파이프라인은 선형 흐름을 가정합니다. 데이터 → 전처리 → 모델 → 평가 → 배포.9 에이전트 시스템은 비선형적입니다. 에이전트는 다음과 같은 동작을 할 수 있습니다:
- 자체 신뢰도를 평가하고 도움이 필요하다고 판단
- 서로 다른 전문성을 가진 5개의 병렬 하위 에이전트를 생성
- 그 출력을 수집하고 순위를 매김
- 에이전트들이 너무 빠르게 수렴하는 것(집단 사고)을 감지
- 품질 임계값에 대해 합의를 검증
- 최종 권고안을 생성
각 단계에는 RAG와 파인튜닝이 제공하지 않는 인프라가 필요합니다.
3부: 제가 구축한 것
아키텍처
제 심의 시스템은 12개 모듈에 걸쳐 Python 3,500줄로 구성되어 있습니다:
Deliberation System
├── confidence.py Triggers deliberation based on ambiguity/complexity/stakes
├── state_machine.py Workflow: idle → research → ranking → consensus
├── agents.py 5+ persona templates (Architect, Security, Performance...)
├── context_isolation.py RLM L0-L3 layers prevent context contamination
├── ranking.py Stack ranking with weighted consensus calculation
├── spawner.py Parallel agent spawning via Task API
├── conformity.py Detects groupthink and premature convergence
├── mailbox.py Multi-round debate protocol
├── memory.py Cross-session learning and persona tracking
├── scaling.py Dynamic agent count based on complexity
├── prd_generator.py Converts decisions into product requirements
└── observability.py Session metrics and audit replay
이 시스템은 6개의 라이프사이클 지점(PreToolUse, PostToolUse, Stop 및 기타 3개)에서 작업을 가로채는 86개의 훅 위에 구축되어 있습니다. 모든 에이전트 생성, 모든 파일 쓰기, 모든 Git 명령이 검증을 거칩니다.
신뢰도 트리거
모든 작업에 5개의 에이전트가 토론할 필요는 없습니다. 저는 4가지 차원을 평가하는 신뢰도 점수 산정 알고리즘을 구축했습니다:
- 모호성 — 쿼리에 여러 유효한 해석이 있는가? (패턴 매칭: “best way,” “should I,” “compare vs,” “pros and cons”)
- 도메인 복잡성 — 전문 지식이 필요한가? (패턴 매칭: “architecture,” “security,” “performance,” “database schema”)
- 위험도 — 결정이 되돌릴 수 있는가? (패턴 매칭: “production,” “breaking change,” “delete,” “security vulnerability”)
- 컨텍스트 의존성 — 더 넓은 시스템에 대한 이해가 필요한가?
점수는 세 가지 수준에 매핑됩니다:
- 높음 (0.85+): 심의 없이 진행
- 중간 (0.70-0.84): 신뢰도 메모를 기록하고 진행
- 낮음 (0.70 미만): 전체 멀티 에이전트 심의 트리거
임계값은 작업 유형에 따라 적응합니다. 보안 결정은 85% 합의가 필요합니다. 문서 변경은 50%만 필요합니다. 이를 통해 간단한 작업의 과잉 엔지니어링을 방지하면서도 위험한 결정에는 적절한 검토를 보장합니다.
스폰 예산 문제
첫 번째 구현에서는 깊이 기반 재귀 제한을 사용했습니다. 깊이 0의 에이전트가 깊이 1을 생성하고, 깊이 1이 깊이 2를 생성하며, 깊이 3에서 차단됩니다. 이는 즉시 실패했습니다. 심의 에이전트는 직렬이 아닌 병렬로 실행되어야 합니다. 깊이 1에서 5개의 에이전트는 깊은 재귀가 아닙니다. 넓은 협업입니다.
해결책은 스폰 예산 모델이었습니다. 루트 에이전트가 예산(최대 12개 에이전트)을 받습니다. 이 예산을 사용하여 병렬 워커를 생성합니다. 워커는 남은 예산을 상속받지만 초과할 수 없습니다. 이를 통해 심의에 필요한 병렬 실행을 허용하면서 무한 연쇄를 방지합니다.
실전 테스트는 번역된 블로그 포스트에 대해 10개의 리뷰 에이전트를 실행했을 때 찾아왔습니다. 재귀 가드가 스폰을 깊이 증가로 카운트했기 때문에 4번째부터 10번째 에이전트를 차단했습니다. 예산 모델로 전환한 후 10개 모두 성공적으로 실행되었습니다. 깊이는 1을 초과하지 않았습니다. 너비가 작업에 맞게 확장되었습니다.10
합의 검증
에이전트가 완료된 후 심의 후 훅이 4가지 검사를 실행합니다:
- 단계 준비 상태 — 심의가 연구 단계를 넘어 순위 단계로 진행되었는가?
- 에이전트 정족수 — 최소 2개의 에이전트가 완료되었는가? (작업 유형별로 설정 가능)
- 합의 임계값 — 동의율이 요구 수준을 충족하는가? (기본 70%, 보안은 85%)
- 반대 의견 문서화 — 에이전트들이 의견이 다른 경우, 우려 사항이 기록되어 있는가?
4번째 검사는 예상하지 못한 통찰이었습니다. 초기 실행에서는 에이전트가 단순히 첫 번째 응답에 동의하는 “합의”가 만들어졌습니다. 동조성 감지기는 이제 성급한 수렴을 표시합니다. 모든 에이전트가 높은 유사도 점수로 첫 번째 라운드에서 동의하면, 시스템이 두 번째 라운드의 적대적 분석을 강제합니다.
어렵게 배운 교훈들
원자적 파일 쓰기가 중요합니다. 여러 에이전트가 동시에 같은 상태 파일에 쓰면 JSON이 손상되었습니다. 해결책은 .tmp 파일에 먼저 쓴 다음 원자적으로 mv하는 것이었습니다. OS는 동일 파일시스템에서 mv의 원자성을 보장합니다. 이 한 줄 변경으로 경합 조건의 한 범주 전체가 제거되었습니다.
컨텍스트 격리가 집단 사고를 방지합니다. 각 에이전트는 4개의 레이어(L0: 기본 지식, L1: 작업별, L2: 페르소나별, L3: 라운드별)를 통해 독립적인 컨텍스트를 받습니다. 격리 없이는 에이전트들이 해결 공간을 탐색하는 대신 첫 번째 그럴듯한 답에 수렴합니다. 격리가 있으면 보안 에이전트와 성능 에이전트가 서로 다른 가정에서 출발하기 때문에 진정으로 다른 결론에 도달합니다.
에이전트 인프라를 테스트하는 것이 애플리케이션 코드보다 어렵습니다. 이 시스템에는 141개의 테스트가 있습니다. 훅 동작에 대한 48개의 bash 통합 테스트, 라이브러리 모듈에 대한 81개의 Python 단위 테스트, 12개의 엔드투엔드 파이프라인 시뮬레이션입니다. 프로젝트 메모리에 기록된 모든 실패 사례(스폰 예산 차단, 인용 부호 감지 오탐, 블로그 계획 파일이 실수로 포스트로 제공된 문제)가 수정 후 테스트 케이스가 되었습니다. 에이전트 버그는 타이밍, 순서, 동시 상태에 의존하기 때문에 애플리케이션 버그보다 재현이 어렵습니다.
인간과 에이전트의 역할 분담
| 인간의 책임 | 에이전트의 책임 |
|---|---|
| 문제 정의 | 파이프라인 실행 |
| 신뢰도 임계값 설정 | 임계값 내 실행 |
| 합의 요건 정의 | 합의 계산 |
| 품질 게이트 기준 | 품질 게이트 적용 |
| 오류 분석 | 오류 감지 |
| 아키텍처 결정 | 아키텍처 옵션 제시 |
| 도메인 컨텍스트 주입 | 문서 생성 |
패턴은 이렇습니다. 인간은 조직적 맥락, 윤리적 판단, 전략적 방향이 필요한 결정을 담당합니다. 에이전트는 넓은 가능성 공간에서 계산적 탐색이 필요한 결정을 담당합니다.11 이 역할 분담에 대해서는 에이전트 아키텍처 분석에서 더 자세히 다루었습니다.
에이전틱 ML 엔지니어는 파이프라인을 직접 코딩하지 않습니다. 에이전틱 ML 엔지니어는 목표, 제약 조건, 평가 기준을 정의합니다. 에이전트가 구현 루프를 처리합니다. 제안하고, 실행하고, 평가하고, 반복합니다. 인간의 역할은 빌더에서 아키텍트로 전환됩니다. 가드레일을 설정하고, 출력을 검토하고, 에이전트에게 부족한 도메인 컨텍스트가 필요한 판단을 내리는 것입니다.12
핵심 시사점
AI 시스템을 처음 구축하는 엔지니어를 위해: - 자주 변경되는 지식이나 출처 명시가 필요한 사용 사례에서는 RAG로 시작하세요. RAG는 며칠 만에 기능적 기준선을 제공하지만, 파인튜닝은 데이터 준비에만 수 주가 걸립니다 - 애플리케이션에 도메인 추론과 최신 지식이 모두 필요한 경우 RAG와 파인튜닝을 결합하세요 - 작업당 모델 호출이 두 번 이상 필요하다면 에이전트 오케스트레이션이 필요하며, 이는 RAG나 파인튜닝과는 다른 엔지니어링 문제입니다
에이전트 시스템을 구축하는 팀을 위해: - 에이전트를 구축하기 전에 신뢰도 점수 산정부터 구축하세요. 대부분의 작업은 심의가 필요 없으며, 에이전트를 언제 사용할지 아는 시스템이 에이전트 자체보다 더 가치 있습니다 - 병렬 에이전트 아키텍처에서는 깊이 제한이 아닌 스폰 예산을 사용하세요. 깊이 제한은 에이전트 심의에 필요한 넓은 협업 패턴을 차단합니다 - 합의의 존재 여부만이 아니라 합의의 품질을 테스트하세요. 성급한 동의는 합의가 없는 것보다 나쁩니다. 거짓 확신을 만들어내기 때문입니다
참고 문헌
-
Databricks, “State of Enterprise AI Architecture,” Databricks Research, 2024. ↩
-
Lewis, Patrick et al., “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks,” NeurIPS 2020. ↩
-
Gao, Luyu et al., “Precise Zero-Shot Dense Retrieval without Relevance Labels,” ACL 2023. ↩
-
Borgeaud, Sebastian et al., “Improving Language Models by Retrieving from Trillions of Tokens,” ICML 2022. ↩
-
Singhal, Karan et al., “Large Language Models Encode Clinical Knowledge,” Nature, 620, 172-180, 2023. ↩
-
Hu, Edward J. et al., “LoRA: Low-Rank Adaptation of Large Language Models,” ICLR 2022. ↩
-
Miao, Xupeng et al., “Towards Efficient Generative LLM Serving: A Survey from Algorithms to Systems,” arXiv:2312.15234, 2023. ↩
-
Anthropic, “RAG + Fine-Tuning: A Practical Architecture Guide,” Anthropic Cookbook, 2024. ↩
-
Sculley, D. et al., “Hidden Technical Debt in Machine Learning Systems,” NeurIPS 2015. ↩
-
Author’s experience building multi-agent deliberation infrastructure, documented in project MEMORY.md. 86 hooks, 141 tests, 12 Python modules. ↩
-
Sambasivan, Nithya et al., “‘Everyone Wants to Do the Model Work, Not the Data Work’: Data Cascades in High-Stakes AI,” CHI 2021, ACM. ↩
-
Hollmann, Noah et al., “Large Language Models for Automated Machine Learning,” arXiv:2402.08355, 2024. ↩