실무 Multi-Agent 오케스트레이션 7장 · 다중 도구 라우팅 2 / 7 ← 이전목차다음 → TechLead Cro

7장. 다중 도구 라우팅

모델은 도구를 어떻게 고르는가 — 이름과 설명이 전부다

한 줄 요약

모델은 도구의 코드를 보지 못합니다. 보는 것은 이름, 설명, 인자 설명 세 가지 글뿐입니다. 도구를 고른다는 것은 고객의 질문과 그 글들을 나란히 놓고 "어느 것이 어울리는가"를 판단하는 일입니다. 그래서 라우팅을 고치는 일은 대부분 글을 고치는 일입니다.


1. 모델에게 건너가는 것

5장에서 도구를 함수 선언(function declaration) 으로 모델에 알려 주었습니다. 6장부터는 파이썬 함수를 tools=[...]에 그대로 넘겼고, 선언은 SDK가 함수에서 뽑아 만들었습니다. 무엇을 뽑는지 이번 장의 도구 하나로 봅니다.

def check_stock(product_id: str) -> dict:
    """상품ID로 현재 재고 수량을 확인한다. 교환 가능 여부·재입고 문의에 사용한다.

    Args:
        product_id: 상품ID. 'P'로 시작한다. 예: P008
    """
    row = PRODUCTS[PRODUCTS["product_id"] == product_id]
    ...
모델이 보는 것 어디서 오나 위 예에서
도구 이름 함수 이름 check_stock
도구 설명 독스트링 전체 (Args: 부분까지) "상품ID로 현재 재고 수량을 확인한다. … Args: product_id: 상품ID. 'P'로 시작한다. 예: P008"
인자 이름과 타입 함수의 매개변수와 타입 힌트 product_id, 문자열, 필수

독스트링(docstring) 은 함수 바로 아래에 """로 감싸 적는 설명문입니다. 사람이 읽으라고 쓰는 글이지만, 여기서는 모델이 읽는 도구 설명서가 됩니다.

SDK가 이 함수에서 만들어 낸 선언을 그대로 출력하면 이렇습니다. 독스트링이 Args:까지 통째로 description에 들어가 있습니다.

{'name': 'check_stock',
 'description': "상품ID로 현재 재고 수량을 확인한다. 교환 가능 여부·재입고 문의에 사용한다.\n\nArgs:\n    product_id: 상품ID. 'P'로 시작한다. 예: P008",
 'parameters': {'type': OBJECT, 'properties': {'product_id': {'type': STRING}}, 'required': ['product_id']}}

이 교재에서는 독스트링의 Args: 아래에 적은 글을 인자 설명이라고 부르겠습니다.

row = PRODUCTS[...] 아래의 본문은 모델에게 가지 않습니다. 함수가 CSV를 읽는지, 데이터베이스를 보는지 모델은 모릅니다.


2. 설명에 적을 세 가지

도구가 하나일 때는 "무엇을 하는 도구인가"만 적어도 됩니다. 여러 개일 때는 다른 도구와 어떻게 다른가까지 적어야 합니다.

search_products의 독스트링입니다.

"""상품명·카테고리·설명에서 키워드로 하루마켓 판매 상품을 검색한다.
상품의 가격, 옵션, 특징, 소재 등 '상품 자체'에 대한 문의에 사용한다.
주문·배송 상태 조회에는 사용하지 않는다.

Args:
    keyword: 검색어. 예: '텀블러', '이불커버', '운동화'
"""
줄 답하는 질문
첫째 줄 무엇을 하는가 — 키워드로 상품을 검색한다
둘째 줄 언제 쓰는가 — 가격·옵션·특징 등 상품 자체의 문의
셋째 줄 언제 쓰지 않는가 — 주문·배송 조회

셋째 줄이 여러 도구가 있을 때의 핵심입니다. "텀블러 주문한 거 어디쯤이에요?"에는 "텀블러"라는 상품 이름이 들어 있습니다. 상품 검색 쪽으로 끌려갈 수 있는 질문입니다. "주문·배송 상태 조회에는 사용하지 않는다"가 그 경계를 긋습니다.

사람이 헷갈리는 두 설명은 모델도 헷갈립니다. "주문 조회"와 "배송 조회"라고만 적힌 두 도구 앞에서 "주문한 거 어떻게 됐어요?"는 어느 쪽일까요.


3. 인자 설명의 예시가 하는 일

인자 설명에 형식과 예시를 넣으면 모델이 두 가지를 얻습니다.

product_id: 상품ID. 'P'로 시작한다. 예: P008      # check_stock
keyword: 검색어. 예: '텀블러', '이불커버', '운동화'   # search_products
order_id: 하루마켓 주문번호. 'HR'로 시작한다.        # track_shipping
  • 인자를 바르게 채웁니다. 질문 속의 "P008"을 그대로 product_id에 넣습니다.
  • 도구를 고르는 단서가 됩니다. 질문에 P008이 보이면 check_stock, HR…이 보이면 주문 도구, 상품 이름만 보이면 search_products입니다.

고객이 "에어프라이어 재고 있어요?"라고만 물으면 어떻게 될까요. check_stock은 상품ID를 받는데, 고객은 상품ID를 모릅니다. 그러면 올바른 순서는 먼저 search_products로 상품을 찾고, 거기서 나온 상품ID로 check_stock을 부르는 것입니다. 이 순서도 우리 코드가 정하지 않습니다. 모델이 인자 설명을 읽고 정합니다. 「따라하기」에서 확인합니다.


4. 이름도 설명이다

도구 이름은 식별자이면서 가장 짧은 설명입니다. check_stock이라는 이름만으로도 "재고를 확인한다"가 전해집니다.

네 도구의 이름을 나란히 놓아 봅니다.

이름 이름만으로 전해지는 것
get_order_status 주문의 상태를 가져온다
track_shipping 배송을 추적한다
search_products 상품을 검색한다
check_stock 재고를 확인한다

모델이 기대는 단서는 이름, 설명, 인자 설명 셋입니다. 이름이 큰 갈래를 전하고, 설명이 "언제 쓰고 언제 쓰지 않는가"의 경계를 긋고, 인자 설명이 값을 어떻게 채울지 알려 줍니다. 도구가 늘고 질문이 애매해질수록 경계를 그어 주는 문장이 일을 합니다. 그래서 이름은 뜻이 드러나게 짓고, 설명은 경계가 드러나게 씁니다.


5. 판단을 덜어 주는 반환값

도구의 반환값도 모델이 읽는 글입니다. check_stock이 돌려주는 값을 봅니다.

return {
    "found": True, "product_id": product_id, "product_name": r["product_name"],
    "stock": stock, "in_stock": stock > 0,
}

stock만 줘도 모델은 "있다/없다"를 판단할 수 있습니다. 그런데 in_stock을 코드가 계산해서 함께 줍니다. 코드로 확정할 수 있는 판단은 코드가 하고, 모델에게는 결과를 넘깁니다. 모델이 틀릴 자리가 하나 줄어듭니다.

search_products는 결과를 .head(5)로 최대 5건만 돌려줍니다. 검색 결과도 모델의 입력이 되기 때문입니다. 30건을 전부 돌려주면 토큰이 늘고, 모델이 답할 때 골라야 할 것도 늘어납니다.


핵심 정리

  • 모델이 도구에 대해 아는 것은 이름, 설명(독스트링 전체), 인자 이름·타입뿐입니다. 함수 본문은 보지 못합니다.
  • 설명에는 무엇을 하는가, 언제 쓰는가, 언제 쓰지 않는가를 적습니다.
  • 인자 설명의 형식과 예시는 인자를 채우는 데도, 도구를 고르는 데도 쓰입니다.
  • 이름도 설명입니다. 이름은 뜻이 드러나게, 설명은 경계가 드러나게 씁니다.
  • 코드로 확정할 수 있는 판단(in_stock)은 코드가 계산해서 넘깁니다.
← 이전 절왜 라우팅을 따져야 하는가 — 도구가 늘면 고르는 일이 생긴다다음 절 →도구 선언의 비용 — 도구는 매 호출마다 실려 간다
오명운 · macro@prag-ai.com