ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • LLM tool calling, '지원'한다면서요? — 스펙과 현실 사이의 간극
    IT 2026. 3. 14. 21:00

    발단: 잘 되던 게 갑자기 안 된다?

    OpenClaw에 Samsung SmartThings를 연동해서 이것저것 시험해보고 있었습니다. OpenClaw와 연동된 텔레그램에서 "거실 공기청정기 켜줘"라고 보내면 실제로 공기청정기가 켜지는, 이미 잘 동작하는 시스템이었죠.

    그런데 새로운 서버 환경에 OpenClaw을 다시 셋업하면서, 한 가지 욕심이 생겼습니다. 응답 속도가 더 빠른 모델을 찾아보자. 기존 모델도 잘 동작했지만, 무료 모델 중에 더 빠른 게 있다면 바꿔볼 만하지 않을까? OpenRouter에서 무료 모델들을 스캔해보니, tool calling을 지원하면서도 응답 속도가 빠른 모델이 몇 개 눈에 들어왔습니다.

    그중 arcee-ai/trinity-mini가 응답 속도 1.4초로 가장 빨랐습니다. 스펙상 tool calling도 지원한다고 표시되어 있었고요. 바로 primary 모델로 설정했습니다.

    그리고 기존에 잘 동작하던 "거실 공기청정기 켜줘"를 보냈습니다. 3번 연속 실패.

    3번의 실패: 같은 명령, 매번 다른 방식으로 틀림

    1차 시도: 리눅스 디바이스 파일을 만들어버림

    제가 "거실 공기청정기 켜줘"라고 보내자, 모델이 내린 명령은 이것이었습니다:

    echo "on" | sudo tee /dev/airpurifier

    SmartThings 도구가 있다는 걸 완전히 무시하고, 존재하지도 않는 리눅스 디바이스 파일 /dev/airpurifier에 "on"을 쓰려고 한 겁니다. 마치 공기청정기가 USB 장치처럼 커널에 연결되어 있다고 착각한 것 같았습니다.

    2차 시도: 디바이스 ID를 "air"로

    다시 시도하니 이번에는 SmartThings 스크립트를 호출하긴 했습니다. 하지만:

    smartthings_tool.py on air

    SmartThings API에서 디바이스를 식별하려면 aabbccdd-eeff-gghh-iijj-kkllmmnnoopp 같은 UUID가 필요합니다. 그런데 모델은 "air"라는 문자열을 device_id로 넣었습니다. 당연히 400 Bad Request.

    3차 시도: 파일명조차 제대로 못 씀

    세 번째 시도에서 모델이 실행한 명령:

    smartthings/smart

    파일명이 잘렸습니다. smartthings_tool.py를 치려다 중간에 끊긴 것 같은 결과물이었습니다. 당연히 "No such file or directory".

    3번 모두 실패. 도구 문서에 사용법이 명확하게 적혀 있는데도요.

    원인 추적: 왜 "지원"하는데 안 되는 걸까?

    처음에는 제 도구 설명이 부족한 건가 싶어서 TOOLS.md를 고치고, 세션을 재시작하고, 예제를 더 추가해봤습니다. 하지만 같은 모델에서는 계속 실패했습니다.

    그래서 모델 자체를 의심하기 시작했습니다.

    arcee-ai/trinity-mini의 스펙을 다시 살펴보니, 총 파라미터는 26B(260억)로 꽤 큰 모델처럼 보입니다. 하지만 핵심은 이겁니다:

    MoE(Mixture of Experts) 아키텍처로, 실제 활성 파라미터는 3B(30억)에 불과.

    26B라는 숫자에 속았던 겁니다. 실제로 추론에 참여하는 뉴런은 3B뿐이니, 사실상 소형 모델과 다를 바 없었습니다.

    "지원"과 "신뢰성"은 완전히 다른 문제

    여기서 중요한 깨달음을 얻었습니다. LLM의 tool calling에는 두 가지 레벨이 있습니다:

    레벨 1: 형식적 지원 (Format Support) — 모델이 tool calling JSON 형식을 파싱하고 생성할 수 있다는 의미입니다. OpenRouter 같은 플랫폼에서 "tool calling 지원"이라고 표시하는 기준이 바로 이겁니다.

    레벨 2: 신뢰성 있는 실행 (Reliable Execution) — 올바른 도구 선택 + 정확한 argument + 적절한 타이밍이 모두 맞아야 합니다. 이건 완전히 다른 차원의 능력입니다.

    Docker의 실험 결과가 이를 잘 보여줍니다: Llama 3.2 (1B) 모델은 tool calling 성공률(success rate)이 100%이지만, 정확도(accuracy)는 40%에 불과했습니다. 형식은 완벽하게 맞추는데, 내용이 엉뚱한 거죠. 제가 겪은 것과 정확히 같은 상황입니다.

    소형 모델이 tool calling에 실패하는 구조적 이유

    올바른 tool calling은 사실 꽤 복잡한 다단계 추론을 요구합니다:

    1. 의도 파악: "거실 공기청정기 켜줘" → switch on 명령이구나
    2. 도구 선택: SmartThings 도구를 써야지, sudo tee가 아니라
    3. 정보 매핑: "거실 공기청정기" → 해당 디바이스 ID로 변환
    4. 인자 구성: 올바른 형식으로 명령어 조합

    활성 3B짜리 모델은 이 체인의 어딘가에서 반드시 실패합니다. 제 사례에서는 4단계 모두에서 실패했고요.

    해결: 모델을 바꾸니 한 방에 해결

    결국 primary 모델을 stepfun/step-3.5-flash로 교체했습니다. 응답 속도는 2.9초로 trinity-mini(1.4초)보다 느리지만, 마찬가지로 OpenRouter 무료 모델이고 256K 컨텍스트 윈도우에 tool calling 성능이 검증된 모델입니다.

    결과: 바꾸자마자 바로 동작했습니다. 같은 TOOLS.md, 같은 스크립트, 같은 "거실 공기청정기 켜줘" 명령어. 달라진 건 모델뿐입니다. 빠른 응답 속도를 쫓다가 돌아온 셈이죠.

    추가 개선: 도구도 "모델 친화적"으로

    모델을 바꿔서 해결은 됐지만, 한 가지 더 개선했습니다. 혹시 다른 모델로 바꿔도 잘 동작하도록, 도구 자체를 모델이 쓰기 쉽게 만든 것입니다:

    • UUID 대신 이름 허용: aabbccdd-eeff-... 대신 거실공청기라고 써도 동작
    • 에러 메시지에 힌트 포함: 틀린 이름을 넣으면 "사용 가능한 디바이스: 거실공청기, 침실공청기, ..."를 보여줌
    • 단계 줄이기: "목록 조회 → ID 추출 → 명령 실행" 3단계를 "이름으로 바로 실행" 1단계로

    모델의 추론 부담을 줄여주니, 더 작은 모델에서도 성공률이 올라갑니다.

    교훈: AI 도구 연동 시 꼭 기억할 것

    이 시행착오에서 얻은 핵심 교훈 세 가지입니다:

    1. "tool calling 지원"이라는 스펙을 믿지 마세요. 반드시 실제 시나리오로 테스트해야 합니다. 형식을 통과하는 것과 정확하게 실행하는 것은 완전히 다른 문제입니다.
    2. 모델 크기를 볼 때 "활성 파라미터"를 확인하세요. MoE 모델은 총 파라미터 수가 크더라도 실제 추론에 쓰이는 파라미터는 훨씬 적을 수 있습니다. Tool calling 신뢰성을 원한다면 활성 파라미터 기준 최소 7B 이상을 권장합니다.
    3. 도구를 모델 친화적으로 설계하세요. UUID 대신 자연어 이름을 허용하고, 에러 메시지에 힌트를 주고, 필요한 단계 수를 최소화하세요. 모델이 실수할 여지를 줄여주는 것도 개발자의 몫입니다.

    이미 잘 되던 기능이 모델만 바꿨을 뿐인데 3번 연속 실패하는 걸 보면서, LLM tool calling의 "지원"과 "신뢰성" 사이에 얼마나 큰 간극이 있는지 뼈저리게 배웠습니다. 빠른 응답 속도에 혹해서 모델을 바꿨다가 같은 상황을 겪고 계신 분이 있다면 — 코드를 의심하기 전에 모델을 의심해보세요.


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.