
AI Agent 시스템을 만들기 시작하면 구조가 빠르게 커집니다.
처음에는 하나의 Agent가 여러 Tool을 사용합니다.
User
↓
Main Agent
↓
Tools
기능이 늘어나면 역할을 분리하기 시작합니다.
Main Agent
│
├─ Release Agent
├─ Refactoring Agent
├─ Migration Agent
└─ Research Agent
겉으로 보면 깔끔합니다.
각 Agent가 자기 역할만 담당하니 Microservice처럼 책임도 명확해 보입니다.
그런데 여기서 한 번 생각해볼 필요가 있습니다.
저 기능마다 정말 별도의 LLM Agent가 필요한가?
Microsoft가 9월 16일 공개한 Agent Framework 사례에서도 같은 질문을 던졌습니다.
기존에는 상위 Advisor가 여러 Specialist Agent를 A2A로 호출했지만, 일부 Specialist를 SKILL.md + MCP Tool 구조로 바꿨습니다.
서비스 자체를 합친 것은 아닙니다.
없어진 것은 Specialist마다 존재하던 별도의 Model Loop였습니다.
이 차이는 실제 개발 시스템에서 더 중요합니다.
예를 들어 Release Agent를 하나 만든다고 생각해보겠습니다.
구조는 단순해 보입니다.
Main Agent
↓
Release Agent
↓
CI / Git / App Store
하지만 실제 Release Agent 안에는 이런 것들이 들어갑니다.
Release Agent
├─ System Prompt
├─ Model
├─ Context
├─ Tools
├─ Agent Loop
└─ Result Generation
Main Agent가 Release Agent에게 일을 넘기면 Release Agent는 다시 모델을 호출합니다.
Main Agent
↓
Model 판단
↓
Release Agent 호출
↓
Release Agent Model 판단
↓
Tool 호출
↓
Release Agent Model 정리
↓
Main Agent
↓
최종 응답
단순히 기능 하나가 추가된 것 같지만 실제로는 Reasoning Layer 하나가 더 생긴 것입니다.
Agent가 늘어날수록 함께 늘어나는 것도 있습니다.
Model Call
Context
Token
Latency
Failure Point
Observability
Permission
그래서 Multi-Agent는 역할을 나누는 좋은 방법이지만, 무조건 가벼운 구조는 아닙니다.
Microsoft 사례에서는 Weather, Safety, Lift Traffic 같은 Specialist가 각각 독립적인 Agent였습니다.
구조는 이런 형태였습니다.
Advisor
↓
Specialist Agent
↓
Domain Tool
↓
Domain Service
이 구조를 다음처럼 바꿨습니다.
Advisor
↓
Skill
↓
MCP Tool
↓
Domain Service
여기서 중요한 것은 Domain Service가 그대로 남아 있다는 점입니다.
Weather Service
Safety Service
Lift Service
는 계속 독립적으로 배포되고 관리됩니다.
달라진 것은 어디에서 판단하느냐입니다.
기존에는:
Advisor Reasoning
+
Specialist Reasoning
이었다면,
변경 후에는:
Advisor Reasoning
하나가 Domain Operation까지 선택합니다.
Specialist가 가지고 있던 절차와 지식은 SKILL.md로 이동합니다.
이 구분이 중요합니다.
Microservice가 네 개 있다고 Agent도 네 개일 필요는 없습니다.
예를 들어 Backend가 이렇게 구성돼 있다고 해보겠습니다.
Release Service
Quality Service
Artifact Service
Notification Service
이걸 그대로
Release Agent
Quality Agent
Artifact Agent
Notification Agent
로 옮길 이유는 없습니다.
Service Boundary는 주로 이런 것을 위한 것입니다.
Business Logic
Data Ownership
Deployment
Scaling
Security
Team Ownership
Agent Boundary는 다릅니다.
Independent Reasoning
Private Context
Autonomy
Long-running Workflow
Specialized Model
즉
서비스가 분리돼 있다는 것과 Reasoning을 분리해야 한다는 것은 다른 문제입니다.
iOS 앱 배포를 자동화한다고 해보겠습니다.
Release Agent를 따로 만들 수도 있습니다.
Main Agent
↓
Release Agent
↓
Git
CI
TestFlight
App Store
하지만 실제 업무를 보면 꽤 정형화돼 있습니다.
현재 Branch 확인
↓
변경사항 확인
↓
Version / Build Number 확인
↓
Test 실행
↓
Archive
↓
Upload
↓
Release Note 생성
이 정도라면 별도의 LLM Agent보다 Release Skill이 더 자연스러울 수 있습니다.
Release Skill
1. release branch를 확인한다.
2. working tree가 clean인지 확인한다.
3. test를 실행한다.
4. build number를 증가시킨다.
5. archive를 생성한다.
6. TestFlight에 업로드한다.
실행 기능은 MCP Tool이나 다른 Tool Interface로 제공합니다.
git_status
run_tests
increment_build_number
archive_app
upload_testflight
구조는 단순해집니다.
Main Agent
↓
Release Skill
↓
필요한 Tool 선택
↓
CI / App Store
Release를 수행하는 방법은 Skill이 알려주고,
실제 실행은 Tool이 담당합니다.
같은 Release 영역이라도 질문이 달라질 수 있습니다.
예를 들어:
지금 이 버전을 배포해도 괜찮을까?
라면 단순 절차가 아닙니다.
다음 정보를 확인해야 할 수도 있습니다.
QA 결과
Crash 증가 여부
최근 Production 장애
Backend 호환성
Feature Flag
Rollout 상태
최근 Commit 위험도
그리고 상황에 따라 추가 정보를 다시 조회할 수도 있습니다.
Crash 증가
↓
특정 OS인가?
↓
해당 Feature 변경 확인
↓
최근 Commit 확인
↓
Rollout 범위 판단
이 정도가 되면 별도의 Release/Deployment Agent가 의미를 가질 수 있습니다.
즉 같은 Domain이라도 기준은 기능 이름이 아닙니다.
독립적인 Reasoning이 필요한가가 기준입니다.
두 번째 예는 Code Quality입니다.
처음에는 이런 구조를 만들기 쉽습니다.
Main Coding Agent
↓
Refactoring Agent
↓
SwiftLint
Tests
CodeQL
하지만 Refactoring Agent가 하는 작업을 자세히 보면:
SwiftLint violation 수정
unused code 제거
deprecated API 교체
간단한 중복 제거
test 실행
정도일 수 있습니다.
이런 작업은 대부분 절차가 명확합니다.
Code Quality Skill
1. Analyzer를 실행한다.
2. Finding을 Rule별로 분류한다.
3. 작은 Batch로 묶는다.
4. 코드를 수정한다.
5. Build한다.
6. Test한다.
7. Finding이 사라졌는지 확인한다.
Tool은:
run_swiftlint
find_usages
apply_patch
run_build
run_tests
만 제공하면 됩니다.
구조는:
Coding Agent
↓
Code Quality Skill
↓
Analyzer / Build / Test
로 충분합니다.
굳이 Refactoring Agent라는 두 번째 Reasoning Loop가 필요하지 않을 수 있습니다.
iOS 프로젝트를 Swift 6으로 Migration한다고 해보겠습니다.
Multi-Agent 구조를 과하게 만들면 이런 모습도 가능합니다.
Main Agent
│
├─ Concurrency Agent
├─ Sendable Agent
├─ Actor Agent
├─ Build Agent
└─ Test Agent
기능 이름만 보면 역할이 잘 분리돼 보입니다.
하지만 실제 Migration 절차는 상당 부분 정형화돼 있습니다.
Compiler Warning 수집
↓
오류 유형 분류
↓
Sendable 문제 확인
↓
Actor Isolation 확인
↓
@MainActor 적용 여부 확인
↓
코드 수정
↓
Build
↓
Test
이것을 하나의 Skill로 만들 수 있습니다.
Swift 6 Migration Skill
그리고 Tool은:
run_build
search_symbol
find_concurrency_diagnostics
apply_patch
run_tests
를 제공합니다.
Main Coding Agent
↓
Swift 6 Migration Skill
↓
Compiler / Search / Test
이 정도 구조면 상당수 Migration 작업을 처리할 수 있습니다.
지금까지 예를 보면 공통점이 있습니다.
Release
Code Quality
Swift Migration
모두 일정한 절차가 있습니다.
그리고 사용할 Tool도 명확합니다.
정리하면 이런 특징을 가진 기능은 Skill 후보입니다.
Bounded Domain
명확한 Procedure
명확한 Input / Output
Typed Tool
Parent Agent가 판단 가능
이런 업무에 매번 별도의 Agent를 만들면 Reasoning Layer만 불필요하게 늘어날 수 있습니다.
이번에는 반대 사례를 보겠습니다.
Production 장애가 발생했다고 해보겠습니다.
API Error Rate 급증
단순한 절차로 끝나지 않습니다.
Error Rate 확인
↓
최근 Deploy 확인
↓
특정 API인가?
↓
DB Latency 확인
↓
관련 Trace 확인
↓
최근 Commit 확인
↓
원인 가설 생성
↓
추가 로그 조회
↓
가설 수정
이 과정은 계속 달라집니다.
첫 번째 조사 결과에 따라 다음 Tool이 달라집니다.
Logs
Metrics
Tracing
Git
Deployment History
Feature Flag
를 어떤 순서로 사용할지도 미리 정하기 어렵습니다.
이런 작업은:
Explore
↓
Hypothesis
↓
Verify
↓
Re-plan
이 반복됩니다.
이 경우는 Skill보다 Incident Agent가 더 자연스럽습니다.
Microsoft의 실제 사례에서도 모든 Specialist를 Skill로 바꾸지는 않았습니다.
Web Research 기능은 Agent로 유지했습니다.
Research는 보통:
검색
↓
결과 판단
↓
추가 검색
↓
출처 비교
↓
새로운 질문
↓
재검색
↓
정리
과정을 반복합니다.
미리 정해진 Tool 호출 순서가 없습니다.
독립적인 Reasoning이 필요합니다.
그래서:
Main Agent
↓
Research Agent
↓
Search Tools
구조가 자연스럽습니다.
이 부분이 중요한 이유는 Microsoft 사례의 메시지가
“Multi-Agent를 없애라”
가 아니기 때문입니다.
Agent를 만들기 전에 다음 질문을 해보면 됩니다.
YES
→ Agent 후보
YES
→ Agent 후보
YES
→ Agent 후보
YES
→ Agent 후보
반대로:
YES
→ Skill 후보
YES
→ Skill 후보
YES
→ Skill 후보
결국 이렇게 줄일 수 있습니다.
정해진 절차
+
명확한 Tool
↓
Skill
탐색
+
가설
+
반복 판단
↓
Agent
SKILL.md는 Agent의 System Prompt를 재사용 가능한 자산으로 만든다Specialist Agent를 Skill로 바꿀 때 System Prompt가 사라지는 것은 아닙니다.
예를 들어 Release Agent에 이런 지침이 있었다고 해보겠습니다.
release branch에서만 배포한다.
working tree가 dirty면 중단한다.
test 실패 시 archive하지 않는다.
배포 후 build number를 기록한다.
기존에는 Release Agent의 System Prompt 안에 들어가 있습니다.
Release Agent
↓
System Prompt
Skill 구조에서는:
release/SKILL.md
로 이동합니다.
이 변화가 중요한 이유는 해당 지식이 더 이상 특정 Agent Runtime에 묶이지 않기 때문입니다.
Agent Prompt
가 아니라
Reusable Engineering Procedure
가 됩니다.
이 구조를 한 단계 더 확장하면 팀 내부 Engineering Rule도 Skill로 만들 수 있습니다.
예를 들어:
ios-feature-development/SKILL.md
안에:
1. Feature Module 생성
2. Domain Interface 정의
3. Repository 연결
4. ViewModel 작성
5. SwiftUI View 작성
6. Unit Test 추가
7. Build 검증
을 정의합니다.
다른 Skill로는:
swift6-migration
ios-release
code-quality
dependency-update
를 둘 수 있습니다.
이렇게 되면 팀의 Engineering Knowledge가
Wiki
Confluence
README
에만 있는 것이 아니라 Agent가 실행할 수 있는 형태로도 존재하게 됩니다.
여기서 Skill과 MCP를 하나로 생각하면 안 됩니다.
Skill은:
무엇을 해야 하는가?
어떤 순서로 해야 하는가?
어떤 기준을 따라야 하는가?
를 알려줍니다.
MCP Tool은:
무엇을 실행할 수 있는가?
를 제공합니다.
예를 들어:
Swift 6 Migration Skill
은 이런 절차를 설명합니다.
Concurrency Diagnostic을 먼저 분류한다.
MCP Tool은 실제 기능을 제공합니다.
run_build()
search_symbol()
apply_patch()
run_tests()
그리고 최종 판단은 Agent가 합니다.
Skill
→ Procedure
MCP
→ Capability
Agent
→ Reasoning
으로 나누면 이해하기 쉽습니다.
Agent 시스템이 커지면 Tool 수가 빠르게 늘어납니다.
예를 들어 개발 Agent에:
Git Tools 15개
CI Tools 10개
Xcode Tools 12개
GitHub Tools 20개
Monitoring Tools 18개
Database Tools 15개
가 있다면 이미 90개입니다.
모든 Tool Schema를 매 요청마다 모델에게 보여주는 것은 비효율적입니다.
Microsoft 사례에서는 Skill이 로드된 뒤 해당 Domain의 MCP Tool만 Context에 추가하는 방식을 사용했습니다.
처음
Release Skill
Migration Skill
Quality Skill
Incident Agent
정도만 보여줍니다.
사용자가:
Swift 6 Migration 진행해줘.
라고 하면:
load_skill("swift6-migration")
후에 관련 Tool만 추가합니다.
run_build
search_symbol
apply_patch
run_tests
나머지는 Context에 들어오지 않습니다.
이게 Progressive Disclosure의 핵심입니다.
Tool이 많아지는 문제는 단순 UI 문제가 아닙니다.
각 Tool에는:
Name
Description
Input Schema
Output Schema
가 있습니다.
전부 Context에 들어가면 Token을 소비합니다.
그래서:
100 Tools
전체를 넣는 대신
10 Skill Summaries
만 먼저 제공하고,
선택된 Skill의 Tool만 뒤에서 추가하는 구조가 더 유리할 수 있습니다.
즉 Agent Skill은 단순한 Prompt 관리 기법이 아니라 Context Engineering 전략이기도 합니다.
Microsoft는 동일한 Ski Resort 애플리케이션에서 기존 A2A Specialist 구조와 Skill + MCP 구조를 직접 비교했습니다.
A2A 구조에서는 세 번의 실행에서 Model Call이 각각:
6회
6회
7회
였습니다.
Skill + MCP 구조는 모두:
3회
였습니다.
Skill 방식에서는:
Model #1
→ 필요한 Skill 로드
Model #2
→ 필요한 MCP Operation 호출
Model #3
→ 최종 응답
으로 끝났습니다.
Specialist마다 별도의 Model Loop를 돌지 않았기 때문입니다.
여기서 중요한 결과가 하나 나옵니다.
Model Call이 줄었으니 Token도 줄었을 것 같지만 그렇지 않았습니다.
세 번의 실행을 합치면:
A2A
11,134 tokens
Skill 방식은:
13,533 tokens
이었습니다.
약 22% 많았습니다.
이유 중 하나는 Parent Agent의 Context가 계속 커졌기 때문입니다.
Skill Instruction
+
Tool Schema
+
Tool Result
+
Conversation Context
가 상위 Agent에 누적됩니다.
따라서
Model Call이 줄었다 = Token이 줄었다
는 공식은 성립하지 않습니다.
Specialist Agent를 유지하면 Context를 자연스럽게 분리할 수 있습니다.
예를 들어 Incident Agent는:
Logs
Metrics
Tracing
만 보면 됩니다.
Release Agent는:
Git
CI
App Store
만 봅니다.
Main Agent Context
≠
Incident Context
≠
Release Context
가 됩니다.
Skill 중심 구조에서는 Parent Agent가 더 많은 Domain Instruction과 Tool 정보를 가져가게 됩니다.
그래서 Agent를 줄이는 것이 항상 좋은 것도 아닙니다.
대규모 시스템에서는 Context Isolation 때문에 Agent를 분리하는 것이 더 나은 경우도 있습니다.
예를 들어 Release Skill에:
Production 배포는 관리자만 가능하다.
라고 적었다고 해보겠습니다.
이것은 Security Policy가 아닙니다.
LLM Instruction일 뿐입니다.
실제 Tool이나 Service에서는 반드시 다시 검증해야 합니다.
Authentication
Authorization
Validation
Audit Log
를 코드에서 강제해야 합니다.
구조는 이렇게 보는 것이 맞습니다.
Skill
→ 어떻게 작업할지 설명
Tool
→ 실행 가능한 Operation 제공
Service
→ 실제 Business Rule과 Security 강제
Agent Architecture에서 이 경계를 흐리면 위험합니다.
실제 개발 시스템에서는 다음 형태가 가장 현실적일 수 있습니다.
Main Coding Agent
│
┌───────────────┼───────────────┐
│ │ │
Release Skill Migration Skill Incident Agent
│ │ │
MCP Tools MCP Tools Agent Loop
│ │ │
CI Compiler Logs / Metrics
여기에:
Code Quality Skill
Dependency Update Skill
SPM Migration Skill
같은 것을 추가할 수 있습니다.
반면:
Incident Analysis
Research
Architecture Investigation
처럼 탐색과 판단이 필요한 작업은 Agent로 유지합니다.
멀티에이전트 시스템을 설계하다 보면 Agent가 많을수록 역할이 명확하고 구조가 고도화된 것처럼 보이기도 합니다.
하지만 Agent 하나는 단순한 Class 하나가 아닙니다.
Model
Context
Reasoning
Tools
Lifecycle
Failure
Observability
Cost
를 가진 Runtime입니다.
그래서 기능 하나가 추가될 때마다 먼저 물어볼 질문은:
어떤 Agent를 만들까?
가 아니라
이 기능에
별도의 Reasoning Loop가 필요한가?
가 되어야 합니다.
필요 없다면:
Skill
+
Tool
이 더 단순합니다.
필요하다면:
Agent
가 맞습니다.
Multi-Agent Architecture가 잘못된 것은 아닙니다.
독립적인 판단과 긴 Workflow가 필요한 작업에서는 여전히 강력합니다.
하지만
Release
Code Quality
Migration
Dependency Update
처럼 절차가 비교적 명확한 기능까지 각각 Agent로 만드는 것은 과할 수 있습니다.
이런 영역은:
SKILL.md
+
MCP Tools
정도로도 충분히 구현할 수 있습니다.
반대로:
Incident Response
Research
Architecture Investigation
처럼
탐색
↓
가설
↓
검증
↓
재계획
이 반복되는 작업은 별도의 Agent가 자연스럽습니다.
Microsoft의 사례에서도 같은 결론이 나옵니다.
일부 Specialist Agent를 Skill + MCP로 바꾸면서 Model Call은 줄었지만 Token 사용량까지 자동으로 줄지는 않았고, Research처럼 독립성이 필요한 기능은 계속 Agent로 유지했습니다.
결국 기준은 간단합니다.
정해진 절차와 명확한 Tool이 있다면 Skill.
탐색하고 가설을 세우고 다시 판단해야 한다면 Agent.
그리고 Multi-Agent Architecture를 설계할 때는 Agent를 하나 더 만들기 전에 한 번쯤 물어볼 필요가 있습니다.
이 기능에 정말 또 하나의 LLM이 필요한가?
Microsoft Agent Framework — From Specialist Agents to Distributed Skills over MCP
Specialist Agent 구조를 Skill + MCP Tool 구조로 변경하고 Model Call, Latency, Token 사용량을 직접 비교한 Microsoft 공식 사례입니다.
공식 글 보기
Microsoft Agent Framework — Discover Agent Skills from MCP servers in .NET
MCP Server에서 Skill을 중앙 배포하고, Agent가 필요한 Skill을 On-demand로 가져오는 구조와 Progressive Disclosure 방식을 확인할 수 있습니다.
공식 글 보기
Microsoft Agent Framework — Give Your Agents Domain Expertise with Agent Skills
SKILL.md를 중심으로 Domain Instruction, Reference, Script 등을 Agent에 필요할 때만 제공하는 기본 Agent Skills 구조를 설명합니다.
공식 글 보기
Microsoft Agent Framework — Agent Skills for .NET Is Now Released
Agent Skills for .NET의 Stable API와 Production 환경에서 Skill을 재사용·배포하는 방식을 확인할 수 있습니다.
공식 글 보기
Microsoft 공식 사례 기준으로 보면, 이번 Architecture 변경의 핵심은 Domain Service를 합치는 것이 아닙니다. Service와 Data, Deployment Boundary는 그대로 유지하고 Specialist가 갖고 있던 별도 Model Loop만 제거한 뒤, Domain Instruction은 Skill로, 실행 기능은 MCP Tool로 제공했습니다.
같은 질문을 비교한 세 번의 실행에서 A2A Specialist 방식은 6회·6회·7회의 Model Call이 발생했고 Skill + MCP 방식은 모두 3회였습니다. 반면 전체 Token 사용량은 Skill 방식이 13,533개로 A2A의 11,134개보다 약 22% 많았습니다. Microsoft 역시 이 결과를 통제된 성능 비교로 보지 말아야 한다고 명시하고 있습니다.
또한 Research Agent처럼 독립적인 탐색, 긴 Workflow, 별도 Context나 Specialized Model이 필요한 Component는 Agent로 유지했습니다. 실제 Production Architecture 역시 Agent 또는 Skill 중 하나를 고르는 구조보다, 둘을 역할에 따라 함께 사용하는 Hybrid 형태가 더 현실적입니다.