Documentação oficial desta página · v0.20.6
Busca de Ferramentas
Quando você tem muitos servidores MCP ou ferramentas de plugin fora do núcleo ligados a uma sessão, os schemas JSON delas podem consumir uma fatia grande da janela de contexto a cada turno — mesmo quando só algumas interessam para o que a pessoa de fato pediu.
A Busca de Ferramentas (Tool Search) é a camada opcional de divulgação progressiva do Hermes para esse problema. Quando ativa, as ferramentas de MCP e de plugin são substituídas, no array de ferramentas visível ao modelo, por três ferramentas-ponte, e o modelo carrega o schema de cada ferramenta específica sob demanda.
As ferramentas que formam o conjunto de capacidades do núcleo do Hermes (terminal, read_file,
write_file, patch, search_files, todo, memory, browser_*, web_search, web_extract,
clarify, execute_code, delegate_task, session_search e o resto de _HERMES_CORE_TOOLS) são
sempre carregadas direto. Só as ferramentas de MCP e as de plugin fora do núcleo podem ser
adiadas.
Como funciona
Quando a Busca de Ferramentas ativa num turno, o modelo vê três ferramentas novas no lugar das adiadas:
tool_search(queries, limit?) — busca no catálogo de ferramentas adiadas (uma ou mais consultas)
tool_describe(names) — carrega os schemas completos de uma ou mais ferramentas
tool_call(name, arguments) — invoca uma ferramenta adiada
Uma interação típica é assim:
Modelo: tool_search(["create a github issue", "send a slack message"])
→ { results: [ { query: "create a github issue",
matches: ["mcp_github_create_issue", ...] },
{ query: "send a slack message",
matches: ["mcp_slack_post_message", ...] } ],
tools: { mcp_github_create_issue: { description: "...",
required: ["title"], ... },
mcp_slack_post_message: { ... } } }
Modelo: tool_describe(["mcp_github_create_issue", "mcp_slack_post_message"])
→ { tools: { mcp_github_create_issue: { parameters: { ... } },
mcp_slack_post_message: { parameters: { ... } } } }
Modelo: tool_call("mcp_github_create_issue", { title: "...", body: "..." })
→ { ok: true, issue_number: 42 }
Cada consulta de uma chamada de tool_search é buscada de forma independente no mesmo catálogo (o
limit vale por consulta); os grupos de cada consulta trazem só nomes de ferramenta, enquanto o
mapa tools compartilhado guarda uma vez a descrição e os nomes de parâmetro obrigatórios de cada
ferramenta encontrada. As consultas passam por radicalização, então "issues" acha create_issue.
Todo grupo de consulta que não devolve resultado inclui um resumo available_sources dos servidores
conectados, para que uma falha léxica não seja confundida com capacidade inexistente. O
tool_describe resolve todos os nomes pedidos numa chamada só; nomes desconhecidos são reportados
em not_found sem derrubar o resto do lote.
Quando o modelo invoca o tool_call, o Hermes desembrulha a ponte e despacha a ferramenta
subjacente exatamente como se o modelo a tivesse chamado direto. Hooks de pré-chamada, guardrails,
pedidos de aprovação e hooks de pós-chamada rodam todos contra o nome real da ferramenta — não
contra o tool_call. O feed de atividade da CLI e do gateway também desembrulha, então você vê a
ferramenta subjacente, não a ponte.
Quando ela ativa?
A Busca de Ferramentas usa divulgação em camadas: a presença de qualquer ferramenta adiável (de MCP ou de plugin) ativa a ponte; o que varia com o tamanho do catálogo é quanto dele continua visível, não se os schemas são adiados.
| Camada | Condição | O que o modelo vê |
|---|---|---|
| 0 | Nenhuma ferramenta de MCP ou de plugin | Toda ferramenta carregada de imediato, sem ponte. Passa direto. |
| 1 | A listagem do catálogo adiado cabe no orçamento | Ponte + um manifesto no estilo das skills com toda ferramenta adiada (nome + descrição curta, caindo para só os nomes quando estoura o orçamento). A degradação é por servidor: quando um servidor gigante (Cloudflare) está ligado ao lado de pequenos (Linear), os pequenos mantêm a listagem de cada ferramenta e só o gigante encolhe para uma linha de resumo. |
| 2 | A listagem por ferramenta estoura o orçamento mesmo só com os nomes de todo servidor (por exemplo, a superfície plana de API da Cloudflare sozinha: cerca de 3.300 ferramentas cujos nomes dão uns 32 mil tokens) | Ponte pelada + um resumo de uma linha por servidor (nome do servidor + quantidade de ferramentas), para que o modelo saiba quais domínios estão ao alcance; as ferramentas individuais só se descobrem pelo tool_search. |
O orçamento da listagem é min(threshold_pct% do contexto, listing_max_tokens). A decisão é
reavaliada toda vez que o array de ferramentas é montado, então acrescentar ou remover servidores
MCP no meio da sessão move a sessão de camada na montagem seguinte.
Configuração
tools:
tool_search:
enabled: auto # auto (padrão), on ou off
threshold_pct: 5 # orçamento da listagem como porcentagem do contexto
search_default_limit: 5
max_search_limit: 25
listing: auto # embute um manifesto agrupado de nome+descrição do catálogo
listing_max_tokens: 4000
| Chave | Padrão | Significado |
|---|---|---|
enabled | auto | auto/on ativam sempre que existe pelo menos uma ferramenta adiável; off desliga por completo (tudo fica carregado de imediato). Hoje o auto é um apelido de on — ele está reservado para um modo futuro que embute os schemas quando eles cabem no contexto e só adia quando não cabem. Fixe on ou off se quiser o comportamento de hoje garantido entre atualizações. |
threshold_pct | 5 | Orçamento da listagem como porcentagem do tamanho de contexto do modelo ativo. Faixa de 0 a 100. |
search_default_limit | 5 | Acertos devolvidos por consulta quando o modelo chama tool_search sem limit. |
max_search_limit | 25 | Teto rígido que o modelo pode pedir pelo limit (por consulta). Faixa de 1 a 50. |
listing | auto | Embute na descrição da ponte tool_search um manifesto no estilo das skills com toda ferramenta adiada (nome + primeira frase da descrição, com no máximo 60 caracteres, agrupado por servidor MCP). O auto inclui quando cabe no orçamento (caindo para só os nomes e depois para o resumo por servidor da camada 2); on/off forçam um dos dois. |
listing_max_tokens | 4000 | Teto absoluto da listagem embutida, seja qual for o tamanho do contexto. Faixa de 200 a 60000. Catálogos grandes degradam para só os nomes ou para resumos por servidor, mantendo os schemas completos disponíveis pela busca. |
Os tetos de array por chamada são limites internos de segurança, não configuração. Chamadas acima do teto devolvem um erro para o modelo tentar de novo com um lote menor.
Por que a listagem existe
Sem ela, as capacidades adiadas ficam invisíveis — a avaliação ao vivo mostrou modelos
substituindo por ferramentas de núcleo visíveis (rodando gh no terminal em vez de buscar a
ferramenta adiada do GitHub) ou declarando uma capacidade inexistente em vez de chamar o
tool_search. A listagem aplica às ferramentas o padrão das skills: toda capacidade continua
descobrível por nome o tempo todo, enquanto os schemas completos de parâmetro seguem adiados. Se o
modelo vê o nome exato da ferramenta na listagem, ele pode pular o tool_search e ir direto ao
tool_describe, economizando uma ida e volta.
Também dá para usar o formato booleano antigo:
tools:
tool_search: true # equivalente a {enabled: auto}
Quando NÃO usar
A Busca de Ferramentas troca um custo fixo de tokens por turno (os três schemas das ferramentas-ponte
mais a listagem do catálogo) e pelo menos uma ida e volta extra em ferramentas frias (descrever →
chamar) pela economia nos schemas adiados. Na camada 1 a listagem mantém toda capacidade visível,
então a ida e volta de descoberta em geral some — o modelo vai direto ao tool_describe. A
avaliação ao vivo mostrou o modo de listagem empatando com o carregamento imediato em sucesso de
tarefa, custando menos que a ponte pelada.
Se você quer o comportamento antigo, sempre imediato, para um conjunto pequeno de ferramentas,
defina enabled: off.
Trocas que não desaparecem
Elas vêm da invariante de integridade do cache de prompt — são inerentes a qualquer projeto de divulgação progressiva, não são específicas desta implementação:
- Uma ida e volta extra em ferramentas frias. Na primeira vez que o modelo precisa de uma ferramenta adiada, ele gasta uma ou duas chamadas de modelo a mais para achar e carregar o schema. A economia de tokens do lado estático é real, mas parte dela é devolvida em tempo de execução.
- Sem ganho de cache nos schemas adiados. Um resultado de
tool_describecarregado entra no histórico da conversa (então ele é sim cacheado nos turnos seguintes), mas nunca se beneficia do prefixo de cache do prompt de sistema. - Dependência da qualidade do modelo. A Busca de Ferramentas pressupõe que o modelo consegue escrever uma consulta razoável para a ferramenta que quer. Modelos menores fazem isso pior; os números publicados pela Anthropic (de 49% para 74% no Opus 4 com e sem busca de ferramentas) mostram o ganho, mas também que uns 26 pontos de acurácia ainda são falha de recuperação.
- Editar o conjunto de ferramentas invalida o cache. Acrescentar ou remover uma ferramenta no meio da sessão muda as descrições das ferramentas-ponte (que incluem a contagem de ferramentas adiadas) e o catálogo, então o cache de prompt é invalidado. É a mesma troca de qualquer edição de conjunto de ferramentas.
Detalhes de implementação
- Recuperação: BM25 sobre o nome tokenizado da ferramenta, o nome da fonte (o servidor MCP ou o
conjunto de ferramentas de plugin a que ela pertence, para que buscar
"linear"ache as ferramentas daquele servidor mesmo quando o nome de uma delas não carrega o serviço), a descrição e os nomes de parâmetro, com radicalização Snowball (em inglês) aplicada ao índice e à consulta, para que variantes morfológicas casem ("issues" achacreate_issue). Recai para um casamento literal de substring no nome da ferramenta quando nenhum token da consulta casa com documento nenhum (por exemplo, buscar"hub"onde o token égithub). - A execução em paralelo desembrulha a ponte. O planejador de lotes decide a simultaneidade pela
ferramenta subjacente de um
tool_call, e não pelo nome literal da ponte — então um servidor MCP que aderiu comsupports_parallel_tool_calls: truemantém a simultaneidade quando as ferramentas dele são chamadas pela ponte, e as consultas detool_search/tool_describesão agrupadas em paralelo como qualquer ferramenta somente leitura. - O catálogo não guarda estado entre turnos. Ele é remontado a partir da lista atual de
definições de ferramenta a cada montagem — sem
Mapindexado por sessão. Isso evita a classe de bug em que um catálogo guardado sai de sincronia com o registro vivo de ferramentas. - O catálogo é limitado aos conjuntos de ferramentas da sessão. O
tool_search, otool_describee otool_callsó enxergam e invocam ferramentas que a sessão de fato recebeu. Um subagente, um worker de kanban ou uma sessão de gateway restrita a um subconjunto de conjuntos de ferramentas não consegue usar a ponte para descobrir nem chamar uma ferramenta fora daquele subconjunto — o catálogo adiado é a fatia adiável dos conjuntos ligados e desligados da própria sessão, não o registro do processo inteiro. - Sem sandbox de JS. O Hermes usa o modo mais simples, de "ferramentas estruturadas" (buscar, descrever e chamar como funções comuns). O "modo de código" com sandbox de JS que algumas outras implementações oferecem é uma superfície enorme; nós pulamos.
Veja também
tools/tool_search.py— a implementaçãotests/tools/test_tool_search.py— a bateria de regressão- O PDF
openclaw-tool-search-report, no PR original da implementação, com a pesquisa que moldou o projeto