라우팅으로 멀티 소스 지식 베이스 만들기
라우팅으로 멀티 소스 지식 베이스 만들기 (Build a multi-source knowledge base with routing)
라우터 패턴은 멀티 에이전트 아키텍처의 하나로, 라우팅 단계가 입력을 분류해 전문화된 에이전트로 보내고, 그 결과를 결합된 응답으로 합성하는 방식이에요. 조직의 지식이 서로 다른 버티컬(각각 전문화된 도구와 프롬프트를 가진 에이전트가 필요한 분리된 지식 도메인)에 흩어져 있을 때 이 패턴이 빛을 발합니다.
이 튜토리얼에서는 현실적인 엔터프라이즈 시나리오로 멀티 소스 지식 베이스 라우터를 만듭니다. 시스템은 세 명의 전문가를 조율해요:
- 코드, 이슈, pull request를 검색하는 GitHub 에이전트
- 내부 문서와 위키를 검색하는 Notion 에이전트
- 관련 스레드와 토론을 검색하는 Slack 에이전트
사용자가 "API 요청을 인증하려면 어떻게 하나요?"라고 물으면, 라우터가 질의를 소스별 하위 질문으로 분해하고 관련 에이전트에 병렬로 보낸 뒤 결과를 하나의 일관된 답으로 합성합니다.
왜 라우터를 쓰나요? (Why use a router?)
라우터 패턴의 장점:
- 병렬 실행: 여러 소스를 동시에 질의해서 순차 접근보다 지연 시간을 줄입니다.
- 전문화된 에이전트: 각 버티컬이 자신의 도메인에 최적화된 집중된 도구와 프롬프트를 갖습니다.
- 선택적 라우팅: 모든 질의가 모든 소스를 필요로 하지 않아요. 라우터가 관련 버티컬만 지능적으로 선택합니다.
- 맞춤형 하위 질문: 각 에이전트가 자신의 도메인에 맞게 조정된 질문을 받아 결과 품질이 좋아집니다.
- 깔끔한 합성: 여러 소스의 결과가 단일하고 일관된 응답으로 결합됩니다.
다루는 개념: 멀티 에이전트 시스템, 워크플로 오케스트레이션을 위한 StateGraph, 병렬 실행을 위한 Send API.
설정 (Setup)
langchain과 langgraph 패키지가 필요합니다 (설치 가이드 참고). LangSmith를 설정해 에이전트 내부를 살펴보고, 채팅 모델은 LangChain 통합 목록에서 고르세요.
1. 상태 정의 (Define state)
먼저 상태 스키마를 정의합니다. 세 가지 타입을 사용해요:
AgentInput: 각 서브에이전트에 전달되는 단순 상태(질의만)AgentOutput: 각 서브에이전트가 반환하는 결과(소스 이름 + 결과)RouterState: 질의, 분류, 결과, 최종 답을 추적하는 메인 워크플로 상태
results 필드는 리듀서(Python의 operator.add, JS의 concat 함수)를 사용해 병렬 에이전트 실행의 출력을 하나의 리스트로 모읍니다.
2. 각 버티컬의 도구 정의 (Define tools for each vertical)
각 지식 도메인의 도구를 만듭니다. 프로덕션에서는 실제 API를 호출하겠지만, 튜토리얼이라 목 데이터를 반환하는 스텁 구현을 사용해요. 3개 버티컬에 걸쳐 7개 도구를 정의합니다: GitHub(코드·이슈·PR 검색), Notion(문서 검색·페이지 가져오기), Slack(메시지 검색·스레드 가져오기).
3. 전문화된 에이전트 만들기 (Create specialized agents)
각 버티컬에 에이전트를 만듭니다. 각 에이전트는 도메인 특화 도구와 해당 지식 소스에 최적화된 프롬프트를 가져요. 세 에이전트 모두 같은 패턴을 따릅니다 — 도구와 시스템 프롬프트만 다를 뿐이죠.
4. 라우터 워크플로 구축 (Build the router workflow)
StateGraph로 라우터 워크플로를 만듭니다. 워크플로에는 네 가지 주요 단계가 있어요.
- 분류 (Classify): 질의를 분석하고 어떤 에이전트를 어떤 하위 질문으로 호출할지 결정합니다.
- 라우팅 (Route):
Send를 사용해 선택된 에이전트에 병렬로 팬아웃합니다. - 에이전트 질의 (Query agents): 각 에이전트가 단순한
AgentInput을 받고AgentOutput을 반환합니다. - 합성 (Synthesize): 수집된 결과를 일관된 응답으로 결합합니다.
5. 워크플로 컴파일 (Compile the workflow)
노드를 엣지로 연결해 워크플로를 조립합니다. 핵심은 라우팅 함수와 add_conditional_edges를 사용해 병렬 실행을 가능하게 하는 것이에요. add_conditional_edges 호출은 route_to_agents 함수를 통해 classify 노드를 에이전트 노드에 연결합니다. route_to_agents가 여러 Send 객체를 반환하면 그 노드들이 병렬로 실행됩니다.
6. 라우터 사용 (Use the router)
여러 지식 도메인에 걸친 질의로 라우터를 테스트하세요. 라우터는 질의를 분석해 어떤 에이전트를 호출할지 분류하고(기술 질문이라면 GitHub와 Notion은 호출하되 Slack은 제외하는 식으로), 두 에이전트를 병렬로 질의하며, 결과를 하나의 일관된 답으로 합성하는 것을 확인할 수 있습니다.
7. 아키텍처 이해하기 (Understanding the architecture)
분류 단계 (Classification phase)
classify_query 함수는 구조화된 출력을 사용해 사용자 질의를 분석하고 호출할 에이전트를 결정합니다. 라우팅 지능이 여기 살아 있어요:
- Pydantic 모델(Python) 또는 Zod 스키마(JS)를 사용해 유효한 출력을 보장합니다.
- 각각
source와 맞춤형query를 가진Classification객체 목록을 반환합니다. - 관련 소스만 포함합니다 — 무관한 것은 그냥 생략되죠.
이 구조화된 접근은 자유 형식 JSON 파싱보다 신뢰성이 높고 라우팅 로직을 명시적으로 만듭니다.
Send로 병렬 실행 (Parallel execution with Send)
route_to_agents 함수는 분류 결과를 Send 객체로 매핑합니다. 각 Send는 대상 노드와 전달할 상태를 지정합니다. 각 에이전트 노드는 전체 라우터 상태가 아니라 query 필드만 가진 단순한 AgentInput을 받아요. 이렇게 하면 인터페이스가 깔끔하고 명시적으로 유지됩니다.
리듀서로 결과 수집 (Result collection with reducers)
에이전트 결과는 리듀서를 통해 메인 상태로 돌아갑니다. 리듀서(Python의 operator.add)가 이 리스트들을 이어 붙여 모든 병렬 결과를 state["results"]에 모읍니다.
합성 단계 (Synthesis phase)
모든 에이전트가 완료되면 synthesize_results 함수가 수집된 결과를 순회합니다:
- 모든 병렬 분기가 완료되기를 기다립니다(LangGraph가 자동 처리).
- 원래 질의를 참조해 답이 사용자가 물은 것에 대응하도록 합니다.
- 중복 없이 모든 소스의 정보를 결합합니다.
8. 완전한 동작 예시 (Complete working example)
여기까지 만든 모든 것을 하나의 실행 가능한 스크립트로 합칩니다.
9. 고급: 상태 보존 라우터 (Advanced: Stateful routers)
지금까지 만든 라우터는 무상태(각 요청이 메모리 없이 독립 처리)예요. 다중 턴 대화에는 상태 보존 접근이 필요합니다.
도구 래퍼 접근 (Tool wrapper approach)
대화 메모리를 추가하는 가장 단순한 방법은 무상태 라우터를 대화형 에이전트가 호출할 수 있는 도구로 감싸는 것이에요. 이 접근은 라우터를 무상태로 유지하면서 대화형 에이전트가 메모리와 컨텍스트를 처리하게 합니다. 사용자는 다중 턴 대화를 할 수 있고, 에이전트는 필요할 때 라우터 도구를 호출하죠.
전체 지속 접근 (Full persistence approach)
라우터 자체가 상태를 유지해야 한다면 — 예를 들어 이전 검색 결과를 라우팅 결정에 사용하려면 — 영속성으로 라우터 레벨에 메시지 기록을 저장하세요.
10. 핵심 요점 (Key takeaways)
라우터 패턴은 다음이 있을 때 빛을 발합니다:
- 분리된 버티컬: 각각 전문화된 도구와 프롬프트가 필요한 분리된 지식 도메인
- 병렬 질의 필요성: 여러 소스를 동시에 질의하는 게 좋은 질문
- 합성 요구: 여러 소스의 결과를 일관된 응답으로 결합해야 함
패턴에는 세 단계가 있어요: 분해(decompose)(질의를 분석하고 맞춤형 하위 질문 생성), 라우팅(route)(질의를 병렬 실행), 합성(synthesize)(결과 결합).
다음 단계 (Next steps)
- 에이전트 간 대화를 위한 handoffs 배우기
- 집중 오케스트레이션을 위한 subagents 패턴 탐색
- 패턴 비교를 위한 멀티 에이전트 개요 읽기
- LangSmith로 라우터 디버깅하고 모니터링하기