llama-3.1-8b 기반 멀티 툴 오케스트레이터 — 기능 라우팅, 기본 거부(deny-by-default) 권한, 그리고 2.97배의 병렬
요약
Llama-3.1-8b 모델을 활용하여 프레임워크 없이 직접 구현한 멀티 툴 오케스트레이터 구축 사례를 소개합니다. 기능 기반 라우팅, 기본 거부(deny-by-default) 권한 체계, 병렬 실행을 통해 에이전트의 효율성과 보안성을 검증합니다.
핵심 포인트
- 기능(Capability) 기반 라우팅으로 툴 추가 시 라우터 수정 불필요
- Deny-by-default 권한 설정을 통해 모델의 환각에 의존하지 않는 보안 구현
- 다수결 원칙과 타임스탬프를 활용한 데이터 충돌 해결 방식 적용
- 병렬 실행 최적화를 통해 기존 대비 약 2.97배의 성능 향상 달성
Agentic AI from Zero의 네 번째 프로젝트는 프레임워크 없이 직접 제작한 멀티 툴 오케스트레이터(multi-tool orchestrator)입니다. 저는 이를 NVIDIA NIM의 meta/llama-3.1-8b-instruct를 대상으로 실제로 실행했으며, 모든 라우팅(routing) 및 합성(synthesis) 호출은 integrate.api.nvidia.com에 대한 실제 HTTP/1.1 200 OK 응답을 생성했습니다. 한 번의 실행을 통해 다섯 가지 아이디어, 즉 동적 툴 레지스트리(dynamic tool registry), 기능 기반 라우팅(capability-based routing), 기본 거부(deny-by-default) 권한, 병렬 실행(parallel execution), 그리고 충돌 해결(conflict resolution)을 검증합니다. 아래 내용은 해당 실행 결과에서 그대로 가져온 것입니다.
툴이 스스로를 등록함
6개의 툴은 모듈이 임포트되는 즉시 @tool(...) 데코레이터를 통해 스스로를 등록합니다. 각 툴은 이름, 기능(capabilities) 세트, 권한(permission) 범위, 그리고 JSON 인자 스키마(JSON arg schema)를 선언합니다. 라우터(router)는 툴의 이름을 절대 보지 않으며, 오직 기능(capability)을 통해 레지스트리(registry)에 질의할 뿐입니다. 새로운 툴을 추가하면 라우터를 수정하지 않고도 라우팅이 가능해집니다. 즉, 레지스트리만이 유일하게 변경되는 요소입니다.
이 6개의 툴은 의도적으로 넓은 범위를 포괄합니다. 세 개의 가격 피드(price_alpha/beta/gamma, 모두 network), 읽기 전용인 weather_lookup 및 fx_convert, 그리고 유일한 write 툴인 ledger_write가 있습니다. 피드가 두 개가 아닌 세 개인 이유는 다수결(majority vote)이 실제로 의미를 갖게 하기 위함이며, 각 피드는 신뢰 우선순위(trust priority)와 as_of 타임스탬프를 가지고 있어 동점 상황 발생 시 해결 방식이 완전히 명시됩니다.
이름이 아닌 기능 기반의 라우팅
"AAPL의 현재 기준 가격은 무엇인가요?"라는 질문을 받으면, 모델에는 툴이 아닌 광고된 기능들(price_quote, weather, persist, …)이 제시되며, 모델은 작업에 필요한 기능을 선택합니다. 오케스트레이터는 해당 기능들을 구체적인 툴로 변환합니다. 실행 과정은 다음과 같습니다: route via=llm caps=['price_quote'] → ['price_alpha', 'price_beta', 'price_gamma']. 라우팅은 레지스트리를 기준으로 검증되며, 환각(hallucinated)된 기능은 폐기됩니다. 또한 키워드 폴백(keyword fallback)이 via=fallback으로 기록되어, 작은 8B 모델이 파이프라인을 방해하는 일이 발생하지 않도록 합니다.
기본 거부(Deny-by-default) 권한 — 실제 거부
동일한 "원장에 감사 메모 기록(record an audit note in the ledger)" 작업을 두 번 실행했습니다. ['network','read']라는 제한된 권한(grant) 하에서는 라우팅(routing)이 write 권한이 필요한 ledger_write로 연결되어, 실행이 **거부(DENIED)**되고 로그에 기록되며, 실행 결과는 수행할 수 없다고 답변합니다. ['network','read','write'] 권한을 부여하면, 동일한 라우팅이 이제 원장에 항목을 기록합니다. 유일한 차이점은 범위(scope)였습니다. 강제 집행(enforcement)은 순수 Python으로 이루어지며, 안전 결정은 모델에 의존하지 않습니다.
병렬 실행 (Parallel execution) — 측정값 2.97배
세 개의 가격 피드(price feeds)는 독립적이므로 스레드 풀(thread pool)에서 동시에 실행됩니다. 각 피드의 비용은 0.60초입니다. 직렬(serially)로 실행하면 실제 시간(wall-clock)은 1.80초가 걸리지만, 병렬(concurrently)로 실행하면 0.61초가 걸립니다. 이는 정확히 동일한 도구 세트에서 측정된 2.97배 빠른 속도입니다. 이는 README의 주장이 아니라, 동일한 실행 내에서 시간을 측정한 실제 A/B 테스트 결과입니다. 동일한 세 개의 피드를 한 번은 차례대로, 한 번은 동시에 실행하여 절약된 시간을 출력했습니다.
충돌 해결 (Conflict resolution) — 피드 간의 불일치
세 개의 피드가 일치하지 않았습니다: alpha $150.25, beta $172.40, gamma $150.25. 문서화된 결정론적 정책(deterministic policy) — 다수결 우선, 그다음 신뢰 우선순위(trust-priority), 그다음 최신성(freshness) 순 — 에 따라 이를 해결합니다. 따라서 2대 1 투표로 $150.25가 승리하며, 충돌 내용은 기록(recorded) 됩니다: 세 가격 모두, 누가 불일치했는지, 그리고 어떤 정책 단계가 결정했는지 기록됩니다. 의도적인 반전은 다음과 같습니다: beta는 우선순위상 실제로 가장 신뢰할 수 있는(most-trusted) 피드임에도 불구하고, 다수결 우선 원칙이 이를 올바르게 제치고 승리합니다. 정책 순서를 바꾸면 승자가 바뀌며, 이것이 바로 정책을 암시적으로 남겨두지 않고 문서로 작성하는 정확한 이유입니다.
재실행 시 안정적인 요소
8B 모델은 온도가 0일 때조차 완벽하게 결정론적이지 않으므로, 재실행 시 라우팅 이유나 최종 답변의 문구가 달라질 수 있습니다. 하지만 모델이 선택하는 기능(capabilities), 거부(denial), 타이밍 형태(timing shape), 그리고 _충돌 승자(conflict winner)_는 안정적입니다. 라우팅은 레지스트리(registry)를 통해 검증되고, 권한 강제 및 충돌 해결은 모델 출력이 아닌 결정론적인 Python으로 처리되기 때문입니다. 오직 라우팅과 최종 합성(synthesis)만이 LLM의 영역입니다.
전체 기록된 실행 결과:
실시간 데모: https://dev48v.infy.uk/agentic/project4-orchestrator.html
저장소(Repo): https://github.com/dev48v/agentic-ai-from-zero
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기