Jump to content

서비스에 바로 쓰는 라우터, 한 끗 차이를 만드는 팁


Recommended Posts

image.png.657190647ff52137d8cc879885ae9779.png

 

라우터는 자연어 설명만으로 다양한 입력을 정교하게 다룰 수 있다는 점에서 강점을 가진 솔루션입니다. 이 글에서는 라우터를 실제 서비스에 적용하기 위해 꼭 알아야 할 설계 및 평가의 노하우를 정리했습니다. 라우터의 기본 구조와 활용에 대한 개요는 CLOVA Studio 포럼(LLM 라우터를 활용한 유연한 경로 설계: 분류부터 필터링까지 손쉽게)과 CLOVA Tech Blog(라우터)를 참고하세요.

 

라우터의 성능을 만드는 작은 차이들

라우터의 정확도는 도메인과 필터를 어떻게 설명하는가에 달려 있습니다. 케이스에 따라 최적의 전략은 다를 수 있으므로, 아래의 설계 팁을 참고해 여러 번 테스트하며 다듬어가는 것을 권장합니다. 

1. 역할에 맞게 명료한 설명 작성하기

도메인과 필터는 모두 자연어 설명에 기반해 작동하지만, 설계 전략은 서로 다릅니다. 도메인 설명은 일반화하되 경계를 명확히 하는 것이 핵심입니다. 지나치게 포괄적인 설명은 경계가 무너지고, 반대로 너무 좁은 설명은 실제 다양성을 수용하지 못하게 됩니다. 예를 들어 '건강에 관련된 모든 내용을 포함합니다.'라는 기준은 어떤 입력을 포함하고 배제해야 할지 명확하지 않고, '건강, 의료, 의학, 헬스케어, 메디컬, 웰빙에 대한 내용입니다.'는 지나치게 중복되고 불필요할 수 있습니다. 이상적인 설명은 '질병 진단, 치료법, 약물 복용 등 임상적 의료 행위에 대한 내용입니다.'와 같이 일반화할 수 있는 핵심 기준을 제시하면서도, 포함되는 범위와 포함되지 않는 범위를 암묵적으로 구분할 수 있어야 합니다.

필터 설명은 오히려 제한적이고 명시적으로 작성하는 것이 좋습니다. 포함 기준을 명확히 하고 구체적인 표현이나 입력 패턴 중심으로 설명하는 것이 좋고, 예를 들어 '논란이 될 수 있는 내용입니다.'보다는 '정치적 편향, 종교적 주장, 지역 감정을 유발할 수 있는 표현입니다.'처럼 분명하게 작성하는 것이 바람직합니다.

1.thumb.gif.347aed97de50d51ed6a84b26de4addb4.gif

2. 도메인과 필터, 겹치지 않게 구분하기

분류의 기준이 되는 도메인(또는 필터) 간 경계가 명확하지 않으면, 라우터는 어떤 기준으로 분류해야 할지 혼란스러워질 수 있습니다. 특히 제로샷 방식으로 동작하는 라우터는 설명의 차이를 기반으로 판단하기 때문에, 의미적 중첩을 최대한 피해야 합니다. 예를 들어, '의료'와 '생활건강' 도메인이 모두 '허리 통증'에 대해 다룬다고 할 때, '의료'는 치료 및 진단 중심, '생활건강'은 예방과 습관 중심으로 구분할 수 있습니다. 도메인 또는 필터 간 개념적 충돌이 우려되는 경우, '의학적 목적', '비의학적 목적' 같은 메타 기준을 먼저 정의해 두고, 각 설명에서 이를 기준 삼는 것도 좋은 전략입니다.

2.thumb.gif.b66b568dbc15fae107bc4d132438188d.gif

3. 직관적인 네이밍 사용하기

도메인 및 필터의 설명뿐만 아니라, 이름 자체도 모델의 분류 판단에 영향을 미치는 요소입니다. 이름이 추상적이거나 이중적인 의미를 가지면, 생성형 모델 기반의 라우터는 분류 기준을 혼동할 수 있습니다. 이름은 해당 설명과 의미적으로 자연스럽게 어울려야 하며, 이름만 보고도 대략적인 역할이나 경계를 유추할 수 있어야 합니다. 설명이 아무리 정교하더라도 '도메인1', '카테고리A'와 같은 임의의 이름은 분류 기준을 흐릴 수 있습니다.

도메인의 경우, 사용자 입력의 의도나 주제를 드러내는 내용 기반의 명확한 키워드나 목적 중심의 명칭(예: 식이요법, 심리 상담 등)이 적합합니다. 필터의 경우, 해석의 여지를 줄이고 분명한 기준에 따라 판단할 수 있도록 구체적이고 제한적인 표현(예: OrientalMedicine, RestrictedBrand 등)을 사용하는 것이 좋습니다. 

3.thumb.gif.da34efbd78e05f54cc6e6c11509026c8.gif

4. 필요에 따라 예시를 활용하기

설명만으로 기대한 성능이 나오지 않거나 특정 유형의 입력에서 성능이 특히 낮은 경우, 예시를 추가해 보조할 수 있습니다.

예시는 두 가지 방식으로 활용할 수 있습니다. 하나는 실제 입력 예시를 통해 어떤 표현이 해당 도메인에 속하는지를 보여주는 방식이고, 다른 하나는 포함 기준을 나열하여 범위를 명시하는 방식입니다.  예를 들어 '의료' 도메인의 경우 '질병의 원인, 진단, 치료법, 약물 정보 등'과 같이 설명만으로 범위를 분명히 하는 동시에, '대상포진 치료 방법은?', '고혈압 진단 기준 알려주세요'처럼 대표적인 입력 예시도 함께 제공하면 성능을 높이는 데 도움이 됩니다. 단, 예시는 너무 많을 경우 편향을 유도할 수 있으므로 1~2개 수준으로 제한하는 것이 좋습니다. 또한 예시는 설명과 일관된 기준을 따르면서도, 길이 제한이나 유사 표현 확장 등을 고려해 작성하는 것이 좋습니다.

4.thumb.gif.bf9c716d4d32bbbce3ec84fe876543f3.gif

 

라우터 성능을 평가하는 법

LLM 기반 라우터는 자연어 설명에 따라 동작하기 때문에, 설계자의 설명 방식이나 기준 설정에 따라 성능이 크게 달라질 수 있습니다. 따라서 실제 서비스 수준의 품질을 확보하려면, 단순 직관이 아닌 정량적이고 체계적인 평가를 통해 라우터의 분류 성능을 검증하고 개선해 나가는 과정이 필요합니다. 이를 위해서는 먼저 도메인과 필터 기준을 충분히 다듬고, 다양한 입력을 포함한 테스트셋을 구성한 뒤, 라우터의 응답을 자동으로 테스트해 성능을 측정하고 분석하는 절차를 따르는 것이 좋습니다. 이 과정을 반복하면서, 라우터가 실제 서비스 환경에서도 안정적이고 일관된 분류를 수행할 수 있도록 조정할 수 있습니다.

1. 테스트셋 준비하기

서비스에 적용 가능한 수준의 라우터를 만들기 위해서는 먼저 실제 서비스 맥락을 반영한 테스트셋을 준비해야 합니다. 대표적인 입력만 포함하는 것이 아니라, 다양한 상황을 커버할 수 있도록 입력 유형을 체계적으로 나눠 준비해야 합니다. 예를 들어 다음과 같은 유형을 포함하면 좋습니다. 

  • 대표 케이스: 자주 등장하는 일반적인 입력(ex. 고혈압 치료 방법 알려줘)
  • 표현 다양화: 동일 의도의 다양한 표현(ex. 고혈압 약 뭐 먹어야 해?, 혈압 낮추는 약 알려줘)
  • 무관한 입력: 해당 도메인(또는 필터)에 속하지 않는 내용(ex. 오늘 날씨 어때?)
  • 비정형 표현: 실제로 발생할 수 있는 철자 오류 등의 비정형의 입력(ex. 고혀랍약 추천해줘)

이처럼 테스트셋은 모델이 어떤 유형의 입력에 강하고 어떤 유형에 취약한지를 진단할 수 있도록 구성되어야 합니다. 또한 테스트셋은 모든 도메인 및 필터별로 최소 수량 이상 확보하여 균형 있게 구성해야 하며, 각 입력에 대해 어느 도메인이 정답인지 명확하게 정의해두는 것이 중요합니다. 그리고 이 정답 기준은 도메인(또는 필터) 설명과 일관되어야 합니다.

2. 벌크로 테스트하기

벌크 테스트를 본격적으로 실행하기 전에는, 반드시 샘플 데이터로 사전에 개별 테스트를 선행하는 것을 권장합니다. 개별 입력에 대해 수차례 테스트하고 설명을 조정하며 라우터의 응답을 안정화시키는 과정을 먼저 거친 후에 대량 데이터로 테스트를 실행하는 것이 좋습니다. 

벌크 테스트를 위한 예시 코드는 다음을 참고하세요. 

import requests
import time
import pandas as pd
from tqdm import tqdm

# 0. 라우터 API 정보
ROUTER_ID = "YOUR_ROUTER_ID"
ROUTER_VERSION = "YOUR_ROUTER_VERSION"
API_KEY = "YOUR_API_KEY"
REQUEST_ID = "YOUR_REQUEST_ID"

# 1. 라우터 API 호출 함수
def router_api(query, chat_history=None):
    url = f"https://clovastudio.stream.ntruss.com/testapp/v1/routers/{ROUTER_ID}/versions/{ROUTER_VERSION}/route"
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "X-NCP-CLOVASTUDIO-REQUEST-ID": REQUEST_ID,
        "Content-Type": "application/json"
    }
    data = {"query": query}
    if chat_history:
        data["chatHistory"] = chat_history

    # 이용량 초과 시 재시도
    while True:
        response = requests.post(url, headers=headers, json=data)
        if response.status_code == 429:
            time.sleep(5)
            continue
        return response.json()

# 2. 테스트셋 구성
testset = [
    {"input": "고혈압 치료 방법 알려줘", "domain": "의료"},
    {"input": "혈압 낮추는 약 알려줘", "domain": "의료"},
    {"input": "오늘 날씨 어때?", "domain": ""},
    # 라우터에 필터를 함께 설정한 경우 다음과 같이 테스트셋 구성
    # {"input": "디스크 터진 것 같은데 어떡하죠", "domain": "의료", "content": "[]", "safety": "[]"},
    # {"input": "소음인한테 좋은 약 추천해주세요", "domain": "의료", "content": "['OrientalMedicine']", "safety": "[]"},
    # {"input": "(특정 국가)인들 때문에 전염된 코로나 증상이랑 치료법은?", "domain": "의료", "content": "[]", "safety": "['unethical']"}
    # ...
]

# 3. 테스트 실행 및 결과 저장
results = []
for i, data in enumerate(tqdm(testset)):
    try:
        res = router_api(data["input"])
        pred_domain = str(res.get("result", {}).get("domain", {}).get("result"))
        # pred_content = str(res.get("result", {}).get("blockedContent", {}).get("result", []))
        # pred_safety = str(res.get("result", {}).get("safety", {}).get("result", []))
        results.append({
            "input": data["input"],
            "domain": data["domain"],
            # "content": data["content"],
            # "safety": data["safety"],        
            "pred_domain": pred_domain,
            # "pred_content": pred_content,
            # "pred_safety": pred_safety,
            "is_correct_domain": data["domain"] == pred_domain,
            # "is_correct_content": data["content"] == pred_content,
            # "is_correct_safety": data["safety"] == pred_safety
        })
    except Exception as e:
        print(e)

# 4. 결과 확인
df = pd.DataFrame(results)
print(df)
출력 결과
           input         domain     pred_domain    is_correct_domain
0  고혈압 치료 방법 알려줘     의료        의료            True
1   혈압 낮추는  알려줘     의료        의료            True
2      오늘 날씨 어때?                                True
줄 바꿈 활성화

3. 테스트 결과 분석하기

테스트 결과를 수집했다면, 다음 단계는 이를 기반으로 성능을 정량적으로 분석하고 개선 포인트를 도출하는 것입니다. 아래는 분류 성능 분석에서 흔히 활용되는 기준입니다.

  • 정탐 (TP, True Positive): 실제로 해당 도메인(또는 필터)에 속하는 입력을 모델이 올바르게 해당 도메인(또는 필터)으로 예측한 경우
  • 오탐 (FP, False Positive): 실제로는 해당 도메인(또는 필터)에 속하지 않지만, 모델이 잘못 해당 도메인(또는 필터)으로 예측한 경우
  • 미탐 (FN, False Negative): 실제로는 해당 도메인(또는 필터)에 속하지만, 모델이 이를 인식하지 못해 예측 결과가 누락된 경우
  • 정확도 (Accuracy): 전체 테스트 입력 중 정답을 맞춘 비율. (정탐 수 ÷ 전체 입력 수)

앞선 '2. 벌크로 테스트하기'에 이어서 성능 지표를 산출하기 위한 예시 코드는 다음을 참고하세요. 

# 1. 정탐, 오탐, 미탐, 정확도 계산
tp = ((df["domain"] != "") & (df["domain"] == df["pred_domain"])).sum()
fp = ((df["pred_domain"] != "") & (df["domain"] != df["pred_domain"])).sum()
fn = ((df["domain"] != "") & (df["pred_domain"] == "")).sum()
accuracy = round((df["is_correct_domain"].sum()) / len(df), 3)

# 2. 결과 출력
print("라우터 성능 지표 요약")
print(f"- 정탐(TP): {tp}")
print(f"- 오탐(FP): {fp}")
print(f"- 미탐(FN): {fn}")
print(f"- 정확도(Accuracy): {accuracy * 100:.1f}%")
출력 결과
라우터 성능 지표 요약
- 정탐(TP): 2
- 오탐(FP): 0
- 미탐(FN): 0
- 정확도(Accuracy): 100.0%

오탐이나 미탐된 케이스는 별도로 수집해 도메인/필터 설명을 개선하는 데 활용할 수 있고, 필요 시 예시 문장을 추가하거나 도메인을 재구성하는 것도 고려할 수 있습니다. 이러한 분석-개선 루프를 꾸준히 반복하면, 실제 서비스 환경에서도 라우터가 안정적이고 일관된 결과를 도출할 수 있습니다.

 

마무리

라우터의 성능을 높이기 위해서는 설명을 개선하고 반복적으로 테스트하는 과정이 핵심입니다. 라우터 설계 → 테스트셋 구성 → 벌크 테스트 → 결과 분석 → 라우터 수정이라는 일련의 사이클을 통해, 라우터의 품질을 점진적으로 끌어올릴 수 있습니다. 이 과정에서 CLOVA Studio에서 제공하는 샘플 라우터를 참고하는 것도 좋습니다. 본 가이드를 참고하여 똑똑한 맞춤형 라우터를 만들어 보세요. 🚀

 

 

image.png.9fa441f51bb41b4e6e37c93868108b2b.png

 

링크 복사
다른 사이트에 공유하기

게시글 및 댓글을 작성하려면 로그인 해주세요.



로그인
×
×
  • Create New...