Give your agent the right 15 tools, not all 3,000.
Two small, independent plug-ins for agentic systems: a hybrid retrieval engine that narrows a large tool registry down to the handful relevant to one query, and a provider-agnostic normalizer that keeps non-English queries from breaking that retrieval. Copy them in or pip install them — no framework lock-in.
The problem
LLM tool-calling accuracy degrades measurably once the available tool count passes roughly 20–30, and drops sharply beyond a few hundred. Independent of accuracy, every tool declaration in a prompt costs tokens — a registry of 3,000 tools at ~200 tokens each is 600,000 tokens per request, more than the context window of essentially any production model. Both plug-ins here exist to fix a version of this problem: tool_curator narrows the tool registry per query before it reaches the model; multilingual_normalizer keeps that narrowing from silently breaking the moment a query isn’t in English.
How tool_curator works
Two independent retrieval passes run per query and get fused:
- Dense retrieval —
BAAI/bge-small-en-v1.5encodes the query and every tool description into 384-dimensional vectors; FAISSIndexFlatIPdoes exact cosine-similarity search. This is what matches “raise a formal complaint” to a tool namedsubmit_grievancewith zero shared words. - Sparse retrieval —
BM25Okapiscores tools by keyword overlap, catching exact-terminology queries (“CGPA” →get_cgpa) that embeddings alone can dilute. - Fusion — Reciprocal Rank Fusion (RRF, k=60) merges both rankings using rank position only, so no manual score-weighting between two incompatible scales is needed.
Layered on top: a name-token anchor that force-includes a tool whenever its own name closely matches the query, compound-query splitting for multi-intent queries, adaptive expansion when retrieval confidence is low, and a disk-cached index keyed by a content hash so tool or vocabulary edits invalidate the cache automatically. See Tool Curator Architecture for the full mechanics.
How multilingual_normalizer works
tool_curator’s dense retrieval is trained on English text — a non-English query embeds nowhere near its English-described tools, and retrieval degrades to noise. multilingual_normalizer sits one stage earlier and translates non-English queries to English before they reach the curator, restoring retrieval accuracy without changing anything about how the curator itself works. English queries take a zero-cost local fast-path — no network call, no added latency — and the fast-path is a majority-vocabulary check, not a bare ASCII check, so it correctly catches romanized non-English text that would otherwise slip through untranslated. See Multilingual Normalizer.
Two plug-ins, one repo
Both packages are independent — installing or using one never requires the other:
pip install rag-tool-curator # tool_curator only
pip install "rag-tool-curator[normalizer]" # + multilingual_normalizer's Gemini backend
from tool_curator import get_curator
from multilingual_normalizer import get_normalizer
Neither package knows anything about MCP, a specific LLM SDK, or a transport protocol — both operate on plain strings and (name, description) pairs. The bundled example/ is a full reference deployment (a simulated university system, 191 tools across 8 MCP servers) used to validate the curator against a 281-case hand-labeled evaluation suite — it’s a proof point and a template to copy from, not a dependency of either plug-in.