19장. 조건 분기와 라우팅
판단은 모델, 길 안내는 코드 — 라우터를 둘로 나눈다
한 줄 요약
문의를 알맞은 처리 노드로 보내는 일을 라우팅(routing) 이라고 하고, 그 일을 하는 부분을 라우터(router) 라고 부릅니다. 이번 장의 라우터는 두 부분으로 이루어집니다. 문의를 읽고 유형을 정하는 것은 모델이고, 유형을 보고 길을 정하는 것은 코드입니다.
1. 라우터의 두 조각
| 단계 | 누가 하나 | 무엇을 하나 | 코드에서 |
|---|---|---|---|
| 판단 | 모델 (LLM) | 고객 문장을 읽고 유형 하나를 고른다 | classify_node (4장 분류기) |
| 길 안내 | 우리 코드 | 유형을 노드 이름으로 바꾼다 | route (딕셔너리 한 개) |
판단 단계는 4장에서 만든 classify()를 그대로 불러 씁니다.
def classify_node(state: CSState) -> dict:
result = classify(state["question"])
return {"intent": result.intent.value,
"log": state["log"] + [f"분류 → {result.intent.value}"]}
4장의 분류기는 구조화 출력을 썼습니다. 그래서 intent에는 주문배송조회, 환불교환처럼 미리 정해 둔 일곱 값 가운데 하나만 들어옵니다. "주문 관련인 것 같아요" 같은 문장은 올 수 없습니다. route의 딕셔너리가 안심하고 그 값을 키로 쓸 수 있는 이유입니다.
2. 모델에게 다음 노드를 직접 고르게 하면 안 되나
됩니다. 모델에게 "order, policy, human, general 중 하나를 골라라"라고 시킬 수도 있습니다. 그런데 둘로 나누면 얻는 것이 있습니다.
| 나누면 | 왜 좋은가 |
|---|---|
| 규칙이 코드에 보인다 | "환불교환은 policy로 간다"가 딕셔너리 한 줄로 적혀 있습니다. 프롬프트 속 문장을 뒤질 필요가 없습니다 |
| 규칙을 한 줄로 바꾼다 | 계정결제를 다른 노드로 보내려면 딕셔너리의 값 하나만 고칩니다. 모델을 다시 시험할 필요가 없습니다 |
| 틀린 곳을 가려낸다 | 로그에 분류 → 환불교환이 찍혔는데 길이 틀렸다면 코드 문제, 분류부터 틀렸다면 분류기 문제입니다 |
| 길 안내는 흔들리지 않는다 | 같은 유형은 몇 번을 실행해도 같은 노드로 갑니다. 코드이기 때문입니다 |
8장에서 "누구의 주문을 볼 수 있는가는 모델이 아니라 세션이 정한다"고 했고, 10장에서 "몇 번까지 돌 수 있는가는 코드가 정한다"고 했습니다. 같은 생각입니다.
모델은 고객의 말을 읽는 데 씁니다. 읽은 결과로 무엇을 할지는 코드가 정합니다.
3. 라우팅 표 — 한 줄 한 줄이 결정이다
route 안의 딕셔너리를 표로 옮기면 이렇습니다. 이것을 라우팅 표라고 부르겠습니다.
분류 결과 (intent) |
가는 노드 | 그렇게 정한 이유 |
|---|---|---|
| 주문배송조회 | order |
답이 주문 데이터에 있다 |
| 환불교환 | policy |
답이 정책 문서에 있다 |
| 멤버십적립금 | policy |
멤버십 규정도 정책 문서에 있다. 처리가 같으면 길도 같다 |
| 상담원연결 | human |
답변이 아니라 접수가 필요하다 |
| 계정결제 | human |
우리 도구로 해결할 수 없는 문제가 많다 |
| 제품문의, 기타 | general |
표에 없는 유형은 모두 여기로 온다 |
이 표는 모델이 만든 것이 아니라 개발자가 정한 것입니다. 유형은 일곱 개인데 노드는 네 개입니다. 유형과 노드가 꼭 하나씩 짝지어질 필요는 없습니다.
마지막 줄을 눈여겨봅니다. route는 표에 없는 값이 오면 general로 보냅니다. 어떤 값이 오든 갈 곳이 반드시 하나 있습니다. 이런 노드를 흔히 기본 경로(default route) 라고 합니다. 기본 경로가 없으면 표에 없는 유형이 왔을 때 그래프가 오류로 멈춥니다.
4. 지나온 길을 상태에 적는다
각 노드는 일을 마칠 때 상태의 log에 한 줄씩 덧붙입니다.
"log": state["log"] + [f"분류 → {result.intent.value}"]
실행이 끝나면 log에 이런 기록이 남습니다.
분류 → 환불교환 → 정책 RAG 노드 처리
이 한 줄로 "무엇으로 분류했고, 어느 노드가 처리했는지"를 알 수 있습니다. 답이 이상할 때 가장 먼저 볼 곳입니다.
5. 라우터가 맡는 범위
라우터는 문의 하나를 길 하나로 보냅니다. 한 가지를 묻는 문의에는 이것으로 충분하고, 이번 장의 네 문의가 모두 그렇습니다.
한 문장에 일이 둘 이상 든 문의("반품 배송비가 얼마인지, 그리고 검정 270 재고가 있는지")는 문의를 먼저 여러 작업으로 나눈 뒤 작업마다 길을 정합니다. 그 구조는 20장에서 만듭니다.
핵심 정리
- 라우터는 판단(모델) 과 길 안내(코드) 두 조각으로 나눕니다.
- 판단 결과는 구조화 출력으로 정해진 값 가운데 하나로 받습니다. 그래야 코드가 그 값으로 길을 고를 수 있습니다.
- 라우팅 표는 개발자가 정한 규칙입니다. 코드에 보이고, 한 줄로 바꿀 수 있습니다.
- 표에 없는 값이 갈 기본 경로를 반드시 둡니다.
- 노드마다
log에 한 줄씩 남기면 어느 길로 갔는지 확인할 수 있습니다. - 라우터는 문의 하나를 길 하나로 보냅니다. 일이 여럿인 문의를 나누는 구조는 20장에서 다룹니다.