Optimize agent capabilities
Put every tool, MCP server, and skill in a searchable catalog and disclose only what each turn needs — fewer tokens per turn, tool selection as good or better.
An agent's direct tool list should carry only what the current turn needs — everything else stays in the catalog, out of the prompt. Stack up a few dozen definitions and each turn opens with the model reading tools it will never call, paying in tokens and accuracy. Ratel keeps the catalog searchable instead, so the model pulls the rest in on demand.
Progressive disclosure
Register everything once — tools and upstream MCP servers into a ToolCatalog, skills into a SkillCatalog — and hand the model three capability tools instead of the whole list:
search_capabilitiesfinds tools and skills by intent,invoke_toolruns a hit by id,get_skill_contentloads a skill's playbook.
Each turn now carries the top-K hits for the current message plus those three tools, no matter how large the catalog grows. The rest of the catalog stays one search away — the three tools are the model's escape hatch when the pre-filtered set is not enough.
from ratel_ai import (
ToolCatalog,
SkillCatalog,
search_capabilities_tool,
invoke_tool_tool,
get_skill_content_tool,
ExecutableTool,
)
catalog = ToolCatalog()
skills = SkillCatalog()
# ...register every tool, MCP server, and skill once...
# The three capability tools reach the whole catalog.
capabilities = [
search_capabilities_tool(catalog, skills),
invoke_tool_tool(catalog),
get_skill_content_tool(skills),
]
# Each turn: the top-K hits for the user's message, plus the three tools.
def tools_for_turn(user_message: str) -> list[ExecutableTool]:
top_k = [
executable
for hit in catalog.search(user_message, 3) # BM25: the 3 most relevant tools
if (executable := catalog.get_executable(hit.tool_id)) is not None
]
return [*capabilities, *top_k]import {
ToolCatalog,
SkillCatalog,
searchCapabilitiesTool,
invokeToolTool,
getSkillContentTool,
type ExecutableTool,
} from "@ratel-ai/sdk";
const catalog = new ToolCatalog();
const skills = new SkillCatalog();
// ...register every tool, MCP server, and skill once...
// The three capability tools reach the whole catalog.
const capabilities = [
searchCapabilitiesTool(catalog, skills),
invokeToolTool(catalog),
getSkillContentTool(skills),
];
// Each turn: the top-K hits for the user's message, plus the three tools.
function toolsForTurn(userMessage: string): ExecutableTool[] {
const topK = catalog
.search(userMessage, 3) // BM25: the 3 most relevant tools
.map((hit) => catalog.getExecutable(hit.toolId))
.filter((t): t is ExecutableTool => t !== undefined);
return [...capabilities, ...topK];
}The exact request and result shapes, the error contract, and how to construct the tools are on Progressive disclosure tools.
Efficiency
Ratel's value is measured in what the model reads: fewer tokens per turn, with tool selection as good or better.
What changes in the model's context
Ratel does not change your model or your prompts. It changes which tool and skill definitions reach the model on each turn:
| Without Ratel | With Ratel |
|---|---|
| Every tool schema is sent up front | Only the relevant top-K and capability tools are sent |
| The model must choose from one crowded list | Local retrieval ranks candidates for the current request |
| Each integration expands the model's tool surface | One catalog stays searchable behind capability tools |
| Runbooks compete with tool definitions for tokens | Skill bodies load only after the model selects one |
Why it compounds
Without Ratel, prompt cost scales with catalog size: the benchmark sweeps pools from 30 to 600 tools, and the baseline pays for all of them every turn. With Ratel, the model reads the top-K hits plus three capability tools no matter how large the catalog grows. That is the mechanism behind progressive disclosure.
Benchmark-backed numbers
On the BFCL tools suite (Ratel 0.4.0, dense retrieval, ratel-full arm vs
control-baseline), token savings grow with catalog size while accuracy holds at
or near baseline — only the smallest local model gives up a few points:
| Model | Mean total tokens | Accuracy (multiple / simple split) |
|---|---|---|
| Claude Haiku 4.5 | −86% | +26.0 / +6.5 pt |
| Claude Sonnet 4.6 | −87% | +0.5 / +0.5 pt |
| GPT 5.4 Mini | −89% | +1.0 / −1.0 pt |
| Qwen3 4b | −91% | −5.5 / −3.3 pt |
Smaller models gain the most: Haiku 4.5 jumps 26 points on the multiple split once the crowded list is gone.
Benchmark covers the methodology; the live results at benchmark.ratel.sh let you switch model, version, and retrieval method.
Choosing a retrieval method
Every query into the catalog is ranked. BM25 keyword search is the default — in-process, deterministic, zero setup. Semantic and hybrid ranking are a per-catalog opt-in for when your queries paraphrase the definitions and no rewording closes the gap; they load a local embedding model and cost a little memory and register-time work.
Stay on BM25 until you see missed recall; when you do opt in, hybrid is usually the safer choice. The full decision guide — what each method does and when to reach for it — is on Keyword vs semantic vs hybrid.
Next steps
Progressive disclosure tools
The contract the three capability tools expose to the model: request and result shapes, the error table, and how to construct them.
Retrieval and search
How BM25 ranks a schema-aware projection, how to write definitions the index can find, and when to opt into semantic or hybrid.
Register tools (TypeScript)
Fill the catalog the capability tools search: local functions and upstream MCP servers.
Register tools (Python)
The same registration flow, idiomatic Python.