로컬 LLM이 도구를 못 고르는 이유, 그리고 해결하는 4가지 전략
도구가 늘어날수록 무너지는 로컬 LLM
AI 에이전트의 핵심 능력은 적절한 도구를 골라 쓰는 것이다. 웹 검색이 필요한 질문에 파일 읽기 도구를 호출하면 아무 의미가 없다. GPT-4나 Claude 같은 대형 모델은 수십 개 도구 앞에서도 비교적 안정적으로 올바른 선택을 내렸다. 그런데 로컬에서 돌리는 8B 규모의 모델에게 같은 일을 시키면 이야기가 달라졌다.
문제의 근본 원인은 두 가지였다. 첫째, 컨텍스트 윈도우의 한계. 도구 하나의 JSON 스키마는 평균 수백 토큰을 차지한다. 도구가 100개면 그것만으로 수만 토큰이 사라진다. Speakeasy의 측정에 따르면, 400개 도구를 정적으로 로드하면 약 405,000 토큰이 소비되어 대부분의 모델이 컨텍스트 윈도우를 초과했다1. 둘째, 선택지 과잉에 따른 혼란. 소형 모델은 비슷한 이름의 도구가 여럿 있으면 어느 것을 골라야 할지 판단하지 못했다. MCP-Bench에서 LLaMA-3.1-8B-Instruct가 기록한 점수는 0.428로, GPT-4o-mini(0.557)에도 크게 못 미쳤다2.
결국 로컬 LLM에게 도구 선택을 맡기려면, 모델이 보는 도구 목록 자체를 줄여주는 외부 장치가 필요했다. 이 글에서 다루는 전략들은 모두 그 하나의 원칙에서 출발한다. LLM이 판단해야 할 선택지를 미리 걸러서, 소형 모델도 감당할 수 있는 범위로 좁히는 것이다.
시맨틱 라우터: LLM 호출 없이 밀리초 만에 분류하기
가장 먼저 적용할 수 있는 계층은 시맨틱 라우터(Semantic Router)였다. aurelio-labs가 공개한 이 라이브러리는 사용자 쿼리를 임베딩 벡터로 변환한 뒤, 사전에 정의해 둔 경로(Route)와의 유사도를 비교해서 카테고리를 결정했다3. LLM을 호출하지 않으므로 지연 시간이 밀리초 단위에 불과했다.
작동 방식은 단순했다. “파일을 읽어줘”, “디렉토리 목록을 보여줘” 같은 예시 발화를 file_operations라는 경로에 등록하고, “웹에서 검색해줘”, “URL 내용을 가져와줘”는 web_operations에 등록했다. 새로운 쿼리가 들어오면 임베딩 유사도만으로 어느 카테고리에 속하는지 판별했다. all-MiniLM-L6-v2 같은 경량 임베딩 모델을 쓰면 API 키 없이 완전히 로컬에서 실행할 수 있었다.
시맨틱 라우터는 도구가 20개 이하일 때 특히 효과적이었다. 카테고리 4–5개로 나눠 놓으면, 각 카테고리에 속한 도구는 3–5개 수준이어서 8B 모델도 무리 없이 처리했다. 다만 “파일에서 데이터를 읽어서 DB에 저장해줘”처럼 여러 도메인에 걸치는 복합 쿼리에는 약했다. 하나의 경로만 반환하기 때문에, 파일 도구는 선택되고 DB 도구는 누락되는 식이었다. 이 한계를 보완하는 것이 다음 단계인 Tool RAG였다.
Tool RAG: 벡터 검색으로 도구 후보를 추리다
Tool RAG는 도구 설명을 임베딩하여 벡터 데이터베이스에 저장하고, 쿼리와의 시맨틱 유사도로 관련 도구를 검색하는 방식이었다. ChromaDB나 Qdrant 같은 경량 벡터 DB를 사용하면 로컬 환경에서도 수백 개 도구를 인덱싱할 수 있었다.
핵심은 top_k 파라미터였다. 100개 도구 중 상위 5개만 검색해서 LLM에 전달하면, 컨텍스트 소비량이 약 90% 이상 줄어들었다. 8B 모델이 100개 도구의 전체 스키마를 한꺼번에 소화하는 건 불가능했지만, 5개라면 안정적으로 처리했다.
시맨틱 라우터와 Tool RAG를 함께 쓰면 2단계 파이프라인이 완성되었다. 1단계에서 시맨틱 라우터가 카테고리를 결정하고, 2단계에서 해당 카테고리 내의 도구를 벡터 검색으로 세부 선별했다. 도구가 30–100개인 환경에서 이 조합이 가장 현실적인 해법이었다.
그런데 검색 품질은 도구 설명의 품질에 직접적으로 의존했다. “Search for things”라고만 적힌 도구와 “Search the web using Brave Search API. Returns titles, URLs, and text snippets”라고 적힌 도구는 검색 정밀도에서 큰 차이를 보였다. 이것이 MCP 도구 설명 최적화 문제로 이어졌다.
MCP 도구 설명 최적화: 모델이 읽을 수 있게 써라
MCP(Model Context Protocol) 생태계가 확산되면서, 도구 설명의 품질이 도구 선택 정확도를 좌우하는 핵심 변수로 부상했다. Dynamic ReAct 논문은 이를 Description Enrichment라는 체계적 기법으로 정리했다4.
Enrichment의 원칙은 다섯 가지였다. 첫째, What — 도구가 무엇을 하는지 구체적으로 서술한다. 둘째, When — 어떤 상황에서 이 도구를 써야 하는지 “Use this when…” 패턴으로 명시한다. 셋째, Not — 이 도구를 쓰면 안 되는 경우를 “Do NOT use this for…” 형태로 추가한다. 넷째, Related — 연관 도구나 동작을 언급하여 검색 그물을 넓힌다. 다섯째, Category — 소속 앱이나 도메인 분류를 태그로 붙인다.
이 원칙의 효과는 소형 모델일수록 극적이었다. 대형 모델은 부실한 설명도 맥락에서 추론해 냈지만, 8B 모델은 설명에 적힌 그대로만 이해했다. 파라미터에도 같은 원칙이 적용되었다. 각 파라미터에 개별 description을 달고, enum으로 가능한 값을 명시적으로 제한하고, 구체적인 예시를 포함하면 인자 구성 오류가 눈에 띄게 줄었다.
토큰 절약도 중요한 고려사항이었다. MCP 커뮤니티에서는 SEP-1576 제안을 통해 공통 스키마를 $ref로 참조하여 중복을 제거하는 방식이 논의되고 있었다5. 도구 설명을 200자 이내로 압축하되 핵심 정보는 빠짐없이 담는 균형이 필요했다.
Validation Feedback: 실패해도 다시 시도하게 만들기
도구를 올바르게 선택했더라도, 인자를 잘못 구성하면 실행은 실패한다. 소형 모델에서 이 문제가 특히 빈번했다. 한국 AI 기업 wrtn labs가 공개한 Agentica 프레임워크는 이에 대한 실용적인 해법을 제시했다6.
Agentica의 핵심 패턴은 두 가지였다. 첫 번째는 Selector Agent로, 전체 함수 목록에서 이름과 요약만 보고 후보를 추리는 경량 에이전트였다. 전체 스키마 대신 한 줄 요약만 전달하므로 토큰 소비가 80% 이상 줄었고, 이 작업은 4B 모델로도 충분했다.
두 번째가 Validation Feedback이었다. 도구 호출 결과가 스키마 검증에 실패하면 — 필수 파라미터가 누락되었거나 타입이 맞지 않으면 — 오류 메시지를 LLM에 되돌려 주고 재시도를 유도했다. typia 기반의 런타임 타입 검증을 사용했으며, 최대 3회까지 재시도했다. 이 피드백 루프가 8B 모델의 인자 구성 정확도를 극적으로 개선했다. 한 번에 완벽한 인자를 만들지 못하더라도, 오류를 보고 수정하는 능력은 소형 모델도 갖추고 있었기 때문이다.
도구가 수백 개일 때: Progressive Search와 Search-and-Load
도구 수가 100개를 넘어가면 앞서 소개한 전략만으로는 부족했다. 이 규모에서는 두 가지 접근법이 주목받았다.
Speakeasy의 Gram은 Progressive Search 방식을 도입했다1. 전체 도구를 계층 구조로 조직하고, list_tools·describe_tools·execute_tool이라는 3개의 메타 도구만 LLM에 바인딩했다. LLM이 먼저 list_tools로 카테고리를 탐색하고, 필요한 도구를 찾으면 describe_tools로 상세 스키마를 가져온 뒤, execute_tool로 실행하는 구조였다. Gram의 벤치마크에 따르면, 400개 도구 환경에서 Progressive Search의 초기 토큰은 약 2,500으로, Static 방식의 405,100 대비 99% 이상 절감되었다.
Dynamic ReAct 논문이 제안한 Search-and-Load 아키텍처도 비슷한 원리를 따랐다4. search_tools로 벡터 검색을 수행하고, LLM이 결과에서 필요한 도구만 골라 load_tools로 바인딩했다. 핵심 차이는 LLM이 원자적(atomic) 검색 쿼리를 직접 구성한다는 점이었다. “트위터 멘션을 모니터링하고 구글 시트에 정리해줘”라는 복합 요청이 들어오면, LLM이 이를 “retrieve Twitter mentions”와 “create Google Sheets spreadsheet” 두 개의 검색 쿼리로 분리해서 각각 검색했다. 사용자의 원문 쿼리를 그대로 검색하는 것보다 정밀도가 훨씬 높았다.
벤치마크가 말해주는 현실
이론적 전략이 실제로 얼마나 효과적인지는 벤치마크 수치가 보여주었다.
BFCL(Berkeley Function Calling Leaderboard)은 LLM의 함수 호출 정확도를 평가하는 가장 권위 있는 벤치마크로, ICML 2025에서 발표되었다7. 소형 모델 중 가장 눈에 띄는 결과는 ToolACE-8B였다. LLaMA-3.1-8B-Instruct를 도구 사용 데이터로 파인튜닝한 이 모델은 BFCL-v1에서 GPT-4 수준의 성능에 도달했다8. 8B 규모에서 이 정도 성능은 전례가 없었다.
범용 모델 중에서는 Qwen3-8B가 사실상의 표준으로 자리 잡았다. r/LocalLLaMA 커뮤니티에서는 “agentic tasks에서 미친 성능”이라는 평가가 반복적으로 등장했고, 131,072 토큰의 긴 컨텍스트 윈도우도 도구 선택에 유리하게 작용했다9.
| 모델 | 크기 | 특징 |
|---|---|---|
| ToolACE-8B | 8B | BFCL-v1에서 GPT-4급, 도구 호출 특화 파인튜닝 |
| Qwen3-8B | 8B | 범용 모델 중 최강의 도구 호출 능력, 131K 컨텍스트 |
| Qwen3-30B-A3B | 30B(3B 활성) | MoE 구조, 실질 3B만 활성화하여 가벼움 |
| Qwen3-4B | 4B | 4B 규모에서도 도구 호출이 안정적 |
MCP-Bench는 MCP 서버를 통한 실제 도구 사용 능력을 평가하는 벤치마크로, NeurIPS 2025 Workshop에서 채택되었다2. 이 벤치마크에서 8B 모델(LLaMA-3.1-8B-Instruct)의 점수 0.428은 GPT-5의 0.749에 크게 못 미쳤다. 그러나 이 수치는 도구 선택 최적화 없이 모든 도구를 직접 바인딩한 결과였다. 앞서 설명한 전략들 — Tool RAG로 후보를 줄이고, Enriched Description으로 설명을 보강하고, Validation Feedback으로 오류를 교정하면 — 그 격차는 상당 부분 좁혀질 수 있었다.
도구 수에 따른 실전 조합
모든 전략을 한꺼번에 적용할 필요는 없었다. 도구 수에 따라 적절한 조합이 달랐다.
| 도구 수 | 권장 전략 | 이유 |
|---|---|---|
| 1–10개 | 전부 정적 로드 | 오버헤드가 없고, 8B 모델도 10개 이하는 안정적으로 처리 |
| 10–30개 | 시맨틱 라우터 + 카테고리별 부분 로드 | 밀리초 단위 분류 후 관련 도구만 전달 |
| 30–100개 | Tool RAG(top_k=5) + Validation Feedback | 벡터 검색으로 후보 축소, 재시도로 정확도 보완 |
| 100–500개 | Gram Progressive Search 또는 Dynamic ReAct Search-and-Load | 메타 도구 기반 동적 탐색, 초기 토큰 2,500 이하 |
| 500개 이상 | 전용 라우팅 인프라 | vLLM Semantic Router Iris 같은 MoM 기반 플랫폼10 |
가장 현실적인 시나리오는 30–100개 도구 환경이었다. MCP 서버 2–3개를 연결하면 금방 이 범위에 도달했다. 이 구간에서는 시맨틱 라우터로 1차 분류, Tool RAG로 2차 선별, Enriched Description으로 설명 품질 확보, Validation Feedback으로 안전망 구축이라는 4중 파이프라인이 가장 안정적이었다.
결국 로컬 LLM의 도구 선택 문제는 모델 자체의 한계가 아니라, 모델에게 주어지는 정보의 양과 질의 문제였다. 적절한 필터링과 보강 장치만 갖추면, 8B 모델도 수백 개 도구 환경에서 실용적인 에이전트로 동작할 수 있었다. 모델이 똑똑해지기를 기다리는 대신, 모델이 보는 세계를 정리해 주는 편이 훨씬 빠른 길이었다.
Footnotes
-
Speakeasy, “Comparing Progressive Discovery and Semantic Search for Powering Dynamic MCP”, 2025. https://www.speakeasy.com/blog/100x-token-reduction-dynamic-toolsets ↩ ↩2
-
Wang et al., “MCP-Bench: Benchmarking Tool-Using LLM Agents with Complex Real-World Tasks via MCP Servers”, NeurIPS 2025 Workshop. https://github.com/Accenture/mcp-bench ↩ ↩2
-
aurelio-labs, “Semantic Router”, GitHub. https://github.com/aurelio-labs/semantic-router ↩
-
Gaurav et al., “Dynamic ReAct: Scalable Tool Selection for Large-Scale MCP Environments”, arXiv:2509.20386, 2025. https://arxiv.org/abs/2509.20386 ↩ ↩2
-
MCP SEP-1576, “Token Bloat Mitigation”, GitHub. https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1576 ↩
-
wrtn labs, “Agentica: TypeScript AI Function Calling Framework”, GitHub. https://github.com/wrtnlabs/agentica ↩
-
Patil et al., “The Berkeley Function Calling Leaderboard (BFCL): From Tool Use to Agentic Evaluation of Large Language Models”, ICML 2025. https://gorilla.cs.berkeley.edu/leaderboard.html ↩
-
Team-ACE, “ToolACE-8B”, Hugging Face. https://huggingface.co/Team-ACE/ToolACE-8B ↩
-
Qwen Team, “Qwen3 Technical Report”, arXiv:2505.09388, 2025. https://arxiv.org/abs/2505.09388 ↩
-
vLLM Project, “Semantic Router v0.1 Iris”, 2026. https://blog.vllm.ai/2026/01/05/vllm-sr-iris.html ↩
댓글