Ga naar inhoud

Een agent met veel tools

Het concept achter deze pagina staat in De toolrouter.

Op deze pagina zet je de toolrouter aan voor een sleutel, kies je hem voor een agent of één verzoek, en controleer je in de trace en met een evaluatie of het model zijn tools nog vindt. Gebruik de router wanneer een agent meer tools krijgt dan zijn model in één aanroep aankan, of zo veel dat het model slecht kiest.

Je hebt nodig:

  • een sleutel met de capability tooling;
  • een organisatie die tool search toestaat. Doet ze dat niet, dan zet alleen de organisatie erboven of de operator het aan, op Instellingen, tabblad Toegang & policy, kaart Tools laten zoeken (Instellingen van een organisatie);
  • een embeddingmodel dat de sleutel mag gebruiken. Zonder dat werkt de router ook, maar zoekt hij alleen op trefwoord.

De router aanzetten op een sleutel

De router hoort bij de configuratie van tooling op de sleutel:

{
  "capabilities": {
    "tooling": {
      "system_tools": ["web_fetch"],
      "tool_search": {
        "enabled": true,
        "default_mode": "direct",
        "top_k": 5,
        "budget_tokens": 4000
      }
    }
  }
}

Stuur dit met PATCH /keys/{key_id}. capabilities vervangt de hele set van de sleutel, dus lees hem eerst met GET /keys/{key_id} en stuur alle capabilities terug met je wijziging erin.

Veld Wat het doet
enabled maakt de router beschikbaar voor de beurten van deze sleutel. Standaard uit
default_mode direct of router: de modus als agent en verzoek niets zeggen. Standaard direct
top_k hoeveel tools één zoekopdracht teruggeeft als het model zelf geen top_k noemt, van 1 tot 20. Standaard 5. Het model mag zelf om 1 tot 20 vragen
budget_tokens hoe groot één zoekresultaat mag zijn, van 100 tot 32.000 tokens, welke top_k het model ook vraagt. Standaard 4.000
preload tools vooraf kiezen, zie hieronder

Met enabled alleen verandert er nog niets: een beurt gebruikt de router pas als het verzoek, de agent of default_mode om router vraagt.

In de console staat hetzelfde op de pagina van de sleutel, onder de systeemtools van tooling: de schakelaar Tool zoeken, daaronder Standaard met Direct of Via zoeken, en de getallen Resultaten per zoekopdracht en Ruimte voor een resultaat (tokens). Een leeg getal betekent de standaard van Core. Staat tool search voor de organisatie uit, dan is de schakelaar vergrendeld en staat erbij waarom (Sleutels).

De router kiezen voor een agent

Een agentversie kiest de modus voor elke beurt die de agent draait. Maak een nieuwe versie met tool_search:

curl -s -X POST "$CORE_URL/agents/agt_5Nj2.../versions" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"model": "<een model-id>",
         "tools": [{"type": "toolset", "name": "orders"}],
         "tool_search": {"mode": "router"}}'

top_k en budget_tokens mag je ernaast zetten; laat je ze weg, dan gelden die van de sleutel. null laat de keuze aan de sleutel. In de console heet dit Tools aanbieden, bij de modelinstellingen van de versie, met Standaard van de sleutel, Direct of Via zoeken.

Noemt de versie router terwijl de sleutel die het verzoek doet tool search niet aan heeft, dan weigert Core elk verzoek met deze agent op tool_search.mode ("Tool search is not enabled for this key."). Een agent die als tool in een andere beurt draait, volgt zijn eigen modus.

De router kiezen voor één verzoek

tool_search op een verzoek gaat boven de agent en de sleutel:

curl -s -X POST "$CORE_URL/responses" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"agent": {"id": "support"},
         "input": "Zet de bestelling van klant 4411 op pauze.",
         "tool_search": {"mode": "router", "top_k": 8}}'

{"mode": "direct"} biedt voor deze beurt elke tool weer direct aan, ook als de agent router kiest. Op /messages werkt hetzelfde veld. Een geweigerde router krijgt een 400: op /responses met tool_search.mode in error.param, op /messages met een error.message dat begint met tool_search.mode:.

Een client die de velden van de leverancier stuurt, krijgt dezelfde router zonder dat je iets aanpast: defer_loading: true op een tool, het item {"type": "tool_search"} van OpenAI op /responses of tool_search_tool_bm25 of tool_search_tool_regex van Anthropic op /messages. Elk daarvan vraagt om router voor het hele verzoek, nooit voor één tool. Een tool_search die het verzoek zelf meestuurt, gaat boven die velden (Een codeeragent aansluiten).

De router via MCP

Een MCP-client buiten Core, zoals Claude Code of Cursor, kiest de router met ?tool_search=router op het sleuteladres of het adres van een toolset:

https://<jouw Core-adres>/api/v1/mcp?tool_search=router
https://<jouw Core-adres>/api/v1/mcp/toolsets/<naam>?tool_search=router

De server toont dan alleen builtin__tool_search en builtin__tool_run, met de top_k en budget_tokens van de sleutel. default_mode van de sleutel geldt hier niet: zonder de parameter krijgt de client alle tools (Core gebruiken vanuit een MCP-client).

Tools vooraf kiezen

Met preload begint een beurt in de modus router met de tools die het best bij het bericht passen, als zoekresultaat dat het model meteen kan gebruiken. Dat bespaart een zoekronde wanneer het bericht duidelijk zegt wat er moet gebeuren.

{
  "tool_search": {
    "enabled": true,
    "preload": { "enabled": true, "limit": 5, "budget_tokens": 1500 }
  }
}
Veld Wat het doet
preload.enabled zet het vooraf kiezen aan. Standaard uit
preload.limit hoeveel tools een beurt hoogstens vooraf krijgt, van 1 tot 20. Standaard 5
preload.budget_tokens hoe groot dat resultaat mag zijn, van 100 tot 8.000 tokens. Standaard 1.500

Het is een instelling van de sleutel alleen; een agentversie of verzoek kan het niet aan- of uitzetten. In de console staat het onder de schakelaar Tool zoeken, zolang die aan staat: Tools vooraf kiezen, met Tools per beurt en Ruimte voor de vooraf gekozen tools (tokens).

Controleren of het werkt

Lees de trace van een beurt met GET /responses/{response_id}/trace en open een aanroep met GET /traces/{call_id} (Een trace lezen):

  • In interpretation.tools staat elke tool die achter de router zat met de beslissing routed. Een tool die je mist en die daar denied_by_policy of withheld_by_capability heeft, kon het model ook niet vinden.
  • In tool_calls staat elke zoekopdracht als builtin__tool_search, met in refs hoeveel tools er doorzocht zijn (candidates), welke hij vond met hun score (hits) en of hij alleen op trefwoord rangschikte (keyword_only).
  • Een uitvoering staat in tool_calls onder de naam van de echte tool, met routed: true.
  • Vooraf gekozen tools staan in interpretation.blocks als blok met source: "tools": in record_ids de gekozen tools, in dropped_by_count en dropped_by_budget hoeveel tools de grenzen weglieten, en in estimated_tokens wat het resultaat kostte. In het gesprek zelf staan ze als een aanroep van builtin__tool_search met de argumenten {"preloaded": true} en het resultaat erbij.

In de console staat dezelfde informatie op de pagina van een aanroep onder Traces: in Welke tools zijn aangeboden hebben de tools achter de router Achter de router, en bij een zoekopdracht staat het blok Zoekopdracht van de router met Gezocht op en de gevonden tools. Een uitvoering is gemarkeerd met Via de router gevonden.

Vindt het model een tool niet die het wel had moeten vinden, verbeter dan de beschrijving van die tool: een zoekopdracht vergelijkt de vraag van het model met de naam, de beschrijving en de parameters van elke tool.

Meten met een evaluatie

Met een evaluatie zie je of de router je agent beter of slechter maakt. Daarvoor dienen twee checks:

Check Slaagt wanneer
tool_found een builtin__tool_search in de beurt, of de vooraf gekozen tools, expected onder de resultaten had
must_use_tool de beurt expected aanriep, direct of via de router

Dit is één stap in de steps van een scenario (Een scenario schrijven):

{"input": "Zet de bestelling van klant 4411 op pauze.",
 "checks": [{"kind": "tool_found", "expected": "api__orders_pause", "required": false},
            {"kind": "must_use_tool", "expected": "api__orders_pause"}]}

Samen vertellen ze waar het misgaat: faalt tool_found, dan vond de zoekopdracht de tool niet; slaagt tool_found en faalt must_use_tool, dan vond het model de tool maar gebruikte het hem niet. Een beurt zonder zoekopdracht faalt op tool_found, dus in de modus direct faalt elke stap erop en meet alleen must_use_tool iets. Daarom staat tool_found hierboven op "required": false: in een run in de modus direct geeft hij alleen een waarschuwing, en slaagt of faalt de stap op must_use_tool.

Om de router aan en uit te vergelijken:

  1. Start een run van de suite terwijl de laatste versie van de agent direct is.
  2. Maak een nieuwe versie met "tool_search": {"mode": "router"} en start nog een run.
  3. Vergelijk de twee runs op must_use_tool. Elke run legt de agentversie vast waarmee hij draaide.

Fouten

Antwoord Betekenis Wat je doet
400 op tool_search.mode (error.param op /responses, het begin van error.message op /messages), "Tool search is not enabled for this key." een verzoek of agent vraagt om router, maar de sleutel heeft tool_search.enabled niet of de organisatie staat tool search niet toe zet de schakelaar op de sleutel aan, of vraag de organisatie erboven om tool search toe te staan
422 op tool_search op een MCP-adres hetzelfde, voor ?tool_search=router idem
422 op tools (400 op /responses en /messages), "This request offers more than … tools; model '…' accepts at most …." de beurt biedt meer tools aan dan het model aankan zet de router aan, of bied minder tools aan
422 op tools, "This request offers more tools than a turn may carry." meer dan 128 tools direct, of meer dan 2.048 achter de router bied minder tools aan, of zet de router aan