
4개의 AI 에이전트가 서로 논쟁하게 만들기 (헥사고날 아키텍처 버전)
요약
여러 개의 AI 에이전트가 서로 다른 페르소나를 가지고 논쟁하며 최적의 결론을 도출하는 'Council of Agents' 시스템을 소개합니다. 헥사고날 아키텍처를 적용하여 다양한 LLM 제공자로 쉽게 교체할 수 있는 구조를 제안합니다.
핵심 포인트
- 낙관주의자, 비판가 등 4가지 페르소나 에이전트 활용
- 의장(Chairman) 에이전트가 논쟁을 종합하여 최종 결정 합성
- 단일 에이전트의 편향성을 극복하고 트레이드오프 분석 가능
- 헥사고날 아키텍처를 통한 유연한 에이전트 및 SDK 교체 구조
라이브 데모: https://council-of-agents-pi.vercel.app
소스 코드: https://github.com/ashishbot120/Council_of_Agents
문제점
AI에게 아키텍처 조언을 구할 때 발생하는 문제
표준 LLM (Large Language Model)에게 "마이크로서비스 (microservices)를 도입해야 할까요?"라고 물으면, 놀라울 정도로 자신만만한 답변을 내놓을 것입니다. 눈에 보이는 트레이드오프 (trade-offs)도 없고, 고려된 예외 케이스 (edge cases)도 없으며, 왜 그런 결론에 도달했는지에 대한 통찰력도 전혀 없습니다.
하지만 실제 엔지니어링 결정은 그런 식으로 이루어지지 않습니다.
실제 아키텍처 선택에는 논쟁이 필요합니다. 저는 실제 팀의 역학 관계에 더 가까운 무언가를 만들고 싶었습니다. 즉, 여러 개의 뚜렷한 AI 관점들이 트레이드오프 매트릭스 (trade-off matrix)의 각 측면을 두고 논쟁하고, 그 뒤에 단순히 한쪽 편을 드는 것이 아니라 논거를 실제로 검토하는 합성기 (synthesizer)를 두는 방식입니다.
아이디어
Council of Agents: 낙관주의자 (Optimist), 비판가 (Critic), 분석가 (Analyst), 악마의 변호인 (Devil's Advocate)이라는 네 가지 페르소나가 동일한 질문에 독립적으로 답변합니다. 다섯 번째 에이전트인 의장 (Chairman)이 네 명의 답변을 모두 읽고 최종 결정을 합성합니다.
실제 실행 질문: "스타트업 팀을 위해 모노레포 (Monorepo)를 사용할까요, 아니면 여러 개의 레포지토리 (multiple repos)를 사용할까요?"
낙관주의자 (85%): 모노레포 (monorepo)를 통한 통합된 툴링 (tooling), 더 빠른 온보딩 (onboarding)
비판가 (87%): 여러 개의 레포지토리는 규모가 커질수록 구축 복잡성을 유발함
분석가 (80%): 초기에는 모노레포를 사용하고, 팀이 성장함에 따라 재검토할 것
악마의 변호인 (85%): 여러 개의 레포지토리는 단일 장애점 (single point of failure)을 방지함
의장의 합성 결과: 모노레포를 도입하되, 반대 의견들이 제기한 우려 사항을 해결하기 위해 엄격한 모듈형 경계 (modular boundaries)와 액세스 제어 (access controls)를 강제할 것.
이것은 단일 에이전트의 답변보다 훨씬 유용합니다. 반대 의견을 무시하는 대신 하나의 주의 사항 (caveat)으로 흡수했기 때문입니다.
왜 헥사고날 (Ports & Adapters) 인가
가설: 만약 구체적인 SDK 대신 인터페이스 (interface)를 중심으로 설계한다면, 제공자 (provider)를 교체하고 현실 세계의 혼란에 대응하는 비용이 얼마나 저렴해질 것인가?
domain/ <- 순수 비즈니스 로직 (business logic), 프레임워크/SDK 임포트(import) 없음
entities.py Agent, Proposal, Council, Decision
services/
deliberation_engine.py 4개의 에이전트를 동시에 실행하며, 부분적 실패 (partial failure)를 허용함
consensus_strategy.py 교체 가능한 알고리즘 (Chairman, MajorityVote)
application/
ports/ LLMProviderPort — 구현 (implementation)이 아닌 계약 (contract)
use_cases/ 도메인 (domain) + 포트 (ports)를 오케스트레이션 (orchestrate)
adapters/
outbound/llm/ OpenRouterAdapter, GroqAdapter
inbound/rest/ FastAPI 라우트 (routes)
infrastructure/
container.py 포트 (ports)를 어댑터 (adapters)에 연결하는 단 하나의 파일
이 구조를 실제로 헥사고날로 만드는 규칙: domain/와 application/은 구체적인 어댑터 (concrete adapter)를 절대 임포트 (import)하지 않습니다. DeliberationEngine은 어떤 제공자가 뒤에 있는지 전혀 모른 채 llm_provider.get_response(role, query)를 호출합니다.
이것이 단순한 이론이 아니라는 증거: 시스템 전체를 OpenRouter에서 Groq으로 전환하는 데는 환경 변수(environment variable) 하나면 충분했습니다. container.py 외부에서는 단 한 줄의 코드도 변경되지 않았습니다. 심지어 요청(request)마다 제공자를 오버라이드 (override)할 수도 있습니다:
POST /council/query
{
"text": "우리가 마이크로서비스 (microservices)를 채택해야 할까요?",
"provider": "groq"
}
세 번째 제공자를 추가하는 데 드는 비용: 약 50줄
- get_response(role, query) -> Proposal을 구현하는 OllamaAdapter 작성
- container.py에 등록
- 완료 — domain/, application/, 또는 REST 레이어의 그 무엇도 건드릴 필요가 없습니다.


실제 운영 환경에서 발생한 4가지 문제 사례
- 프로젝트 도중에 모델이 사용 불가(deprecated) 상태가 되었습니다. deepseek/deepseek-r1:free는 선택하고 테스트하기 사이에 사라졌습니다. 해결책: 모델 이름들을 하나의 딕셔너리에 보관하여, 교체가 추적하는 작업이 아닌 한 줄의 변경으로 가능하게 했습니다.
이것이 유용한 용도
Ports & Adapters (포트 및 어댑터) 패턴의 실시간, 비-장난감(non-toy) 예시
트레이드오프(tradeoff)가 중요한 결정 사항(아키텍처, 채용, 자체 개발 vs 구매)을 위한 의사결정 지원 패턴
신뢰할 수 없는 제3자 API (third-party APIs)를 기반으로 구축하는 모든 이를 위한 회복탄력성 (resilience) 사례 연구
다음 단계
영속성 (persistence)을 위한 Postgres 어댑터 (동일한 포트 사용, 도메인 변경 없음)
더 많은 합의 전략 (consensus strategies) (가중 투표, 반박 라운드)
개별 에이전트 응답 스트리밍
완전한 무료 경로를 위한 로컬 Ollama 어댑터
시간 경과에 따른 합의 전략을 비교하는 평가 하네스 (eval harness)
기여 환영
이 프로젝트는 완성된 것이 아니라 매우 활발하게 진행 중인 프로젝트입니다. 합의 전략을 추가하거나, 새로운 프로바이더 어댑터를 연결하거나, 혹은 단순히 아키텍처의 허점을 찾아내고 싶다면 PR (Pull Requests)과 이슈 (issues)를 언제든 환영합니다. 시도해 보기 좋은 첫 과제들: 로컬 Ollama 어댑터, Postgres 의사결정 저장소, 또는 새로운 페르소나 (persona).
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
