서론
지난 회차까지는 Agent를 분할하고, Middleware를 통해 횡단 관심사 (Cross-cutting Concerns)를 집약하는 방법을 배웠습니다.
분할된 Agent를 어떻게 "배분할 것인가"가 다음 설계 과제입니다.
제6회의 테마는 개방-폐쇄 원칙 (OCP: Open/Closed Principle) 입니다.
잘못된 코드: if문으로 라우팅을 직접 구현하는 경우
고객 지원 시스템을 예로 들어 생각해보겠습니다. 문의 내용에 따라 담당 Agent를 전환하고 싶다는 요구사항은 자주 등장합니다.
import asyncio
from agent_framework.openai import OpenAIChatClient
client = OpenAIChatClient()
...
"작동하는" 코드입니다. 하지만, 이것을 보고 무언가 느껴지는 점이 있나요?
무엇이 문제인가: 개방-폐쇄 원칙 위반
**개방-폐쇄 원칙 (OCP: Open/Closed Principle)**은 "모듈은 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다"는 원칙입니다. [1]
Agent Framework에서의 해결책: HandoffBuilder
Microsoft Agent Framework의 HandoffBuilder를 사용하면, Agent 스스로가 어느 Agent에게 인계할지를 판단하는 "핸드오프형 멀티 에이전트 (Handoff-type Multi-agent)"를 구성할 수 있습니다.
개선 후의 코드
import asyncio
from agent_framework.openai import OpenAIChatClient
from agent_framework.orchestrations import HandoffBuilder
...
무엇이 개선되었는가
| 관점 | ❌️ 개선 전 | ⭕️ 개선 후 |
|---|
| Agent 추가 | route 함수에 elif를 추가 | participants에 추가하기만 하면 됨 |
| 라우팅 판단 | 키워드 매칭 (문자열 의존) | Agent의 LLM 판단 (description 참조) |
| OCP 준수 | 확장을 할 때마다 기존 코드를 수정 | 기존 코드를 수정하지 않고 Agent를 추가할 수 있음 |
HandoffBuilder의 포인트
- 각 Agent의
description이 핸드오프의 판단 근거가 된다. LLM이 description을 읽고 인계 대상을 판단한다.
- 기본적으로 모든 Agent가 모든 Agent에게 핸드오프 가능하다 (메시 토폴로지 (Mesh Topology)).
add_handoff(source, targets)로 라우팅을 명시적으로 제한할 수 있다.
with_start_agent(agent)로 워크플로의 입구가 되는 Agent를 지정한다.
라우팅의 명시적인 제한
기본 메시 토폴로지는 Agent 수가 늘어나면 예상치 못한 라우팅이 발생할 가능성이 있습니다. add_handoff를 통해 인계 대상을 제한할 수 있습니다.
workflow = (
HandoffBuilder(participants=[triage_agent, return_agent, billing_agent])
.with_start_agent(triage_agent)
...
GroupChatBuilder와의 차이점
HandoffBuilder와 유사한 메커니즘으로 GroupChatBuilder가 있습니다. 양자의 차이점을 정리합니다.
| 구분 | HandoffBuilder | GroupChatBuilder |
|---|
| 토폴로지 (Topology) | 분산형 | 중앙 집권형 |
| 인계의 명시성 | Agent가 도구 호출 (Tool Call)을 통해 명시적으로 지명 | 오케스트레이터 (Orchestrator)가 내부에서 판단 (각 Agent는 다음 단계를 모름) |
| 적합한 케이스 | 문의 대응·승인 플로 등 담당이 일의적으로 결정되는 태스크 | 조사·집필·리뷰 등 여러 Agent가 협조하는 태스크 |
요약
라우팅은 OCP 위반이며, Agent 추가 시마다 기존 코드를 수정해야 합니다. 키워드 매칭을 통한 라우팅은 LLM의 출력 변동성(Output Fluctuation)으로 인해 깨지기 쉽습니다.
- Agent Framework의 HandoffBuilder를 사용하면, Agent 스스로가
description을 바탕으로 인계 대상을 판단하여 라우팅 로직을 제거할 수 있습니다.
다음 회차에서는 "상태를 전역 변수로 관리하는" 문제와 WorkflowContext에 대해 해설합니다.
- SOLID 원칙의 O에 해당합니다. "Software entities should be open for extension, but closed for modification." (소프트웨어 엔티티는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 한다.) ↩︎