Hoppa till innehåll

Justera en agents verktygskontext

Den här guiden tar upp det praktiska arbetet kring verktygsytan i två nivåer: att se vad en körning skickar, att ändra det och att diagnostisera en agent som grep efter fel verktyg. Läs Verktygskontext och promptcache om du vill veta varför det fungerar så här.

Öppna ett samtal och tryck på indikatorn för kontextanvändning i samtalets rubrik. Den bygger upp den exakta yta som nästa dispatch skulle skicka, utan att köra något. Visa mer (eller kommandot /context) öppnar den fullständiga kontextutforskaren, där du kan granska varje verktyg.

Två segment spelar roll här:

  • Verktygsdefinitioner och MCP och dynamiska verktyg — den residenta uppsättningen, med varje verktygs verkliga tokenkostnad.
  • Verktyg som läses in vid behov — det uppskjutna indexet. Varje post kostar bara sitt namn, eftersom ett namn är allt förfrågan bär med sig; att öppna en post visar fortfarande hela beskrivningen och schemat, så du ser vad den skulle kosta om körningen läste in den.

Om det uppskjutna segmentet är tomt är uppskjutning avstängd för den här servern. Kontrollera --tool-deferral i CLI-referensen för cc_server.

Den residenta uppsättningen är policy, inte konfiguration — den finns i ModeToolPolicy (packages/cc_domain/lib/features/mcp/domain/value_objects/mode_tool_policy.dart) och gäller för varje körning:

  • residentBuiltins — ordförrådet för filer och skal.
  • residentDiscovery — search_tools och list_my_tools. Ta inte bort dem; det är så en agent når allt annat.
  • residentMcpTools — den handfull Control Center-verktyg som är värda sitt schema vid varje förfrågan.
  • Ett block per läge, för de verktyg som ett givet läge använder nästan varje tur.

Två regler när du redigerar den:

Lägg bara till ett verktyg om de flesta körningar använder det. Varje namn kostar sitt schema vid varje förfrågan i varje körning, för alltid. Ett verktyg som är viktigt när det används men sällsynt i stort hör hemma i den uppskjutna halvan — agenten hittar det ändå.

Använd verktygets verkliga namn. Ett resident namn som inte matchar något verktyg är inert: inget fel, ingen varning, verktyget skjuts helt enkelt upp. test/tooling/resident_tool_names_test.dart fångar detta och håller dessutom varje läge under 40 residenta verktyg, vilket är hela poängen med övningen — bortom det intervallet försämras verktygsvalet mätbart.

Ett läges obligatoriska och fästa verb läggs till automatiskt, så du behöver aldrig lista ett läges eget utdataverb.

När en agent använde fel verktyg eller påstod att den inte kunde göra något, ta reda på vilket av tre saker som hände.

Varje körning registrerar vilka uppskjutna verktyg den läste in och vad som utlöste det — ett direkt anrop med namn, eller en search_tools-fråga. Öppna körningens händelseström (Inställningar → Arbetsyta → Agenter → agenten → Loggar → Visa) och leta efter [harness] loaded N deferred tool(s).

  • Inget loggat, och agenten sade att förmågan saknades — den tittade aldrig. Det är ett promptproblem, inte ett hämtningsproblem: det uppskjutna indexet finns i dess systemprompt med en instruktion att inte förklara en förmåga saknad förrän en sökning har kommit tillbaka tom.
  • En sökning loggad, men inget inläst — en äkta hämtningsmiss. Gå till steg 2.
  • Verktyg inlästa, men fel användes — verktygen den hittade är för lika. Gå till steg 3.

search_tools matchar namn, beskrivningar och argumentnamn. En miss betyder nästan alltid att beskrivningen inte innehåller orden som agenten använde.

Lägg till dem. Beskrivningar är hämtningsindexet, så förläng dem i stället för att trimma — skriv det ordförråd en operatör faktiskt skulle skriva (”assign”, ”hand off”, ”give to”), inte bara det interna substantivet. Att trimma en beskrivning för att spara tokens kostar dig både sökträffen och träffsäkerheten i valet, och sparar nästan ingenting jämfört med schemat.

Om rätt verktyg finns men rangordnas lågt är det vad argumentet limit är till för; verktygets egen beskrivning uppmanar agenten att bredda en sökning som verkar nära men missar.

Om två verktyg har beskrivningar som skulle läsas likadant av någon som inte redan känner till skillnaden gissar modellen. Slå ihop dem till ett verktyg med ett särskiljande argument.

ticket_relation och ticket_pr_link följer det här mönstret: båda hanterar länkning och avlänkning genom ett särskiljande argument. Ett val som görs inuti ett anrop, med förfrågans fulla kontext, är mer tillförlitligt än ett val mellan två snarlika beskrivningar.

Håll verktyg åtskilda när de behöver olika godkännandegrindar, olika granskning eller olika rendering — det är skäl till att en sammanslagning skulle kosta dig något verkligt.

Cacheträffrekvensen visas i Observability → Insikter som Cachefrekvens. Ett friskt långkörande samtal ligger högt; om det är ihållande lågt skriver något om prefixet varje tur.

Vanliga orsaker, i sannolikhetsordning:

  • Vad som helst icke-deterministiskt tidigt i prompten. En tidsstämpel, ett request-id eller en mängd som itereras i varierande ordning räcker.
  • Ett byte av modell eller effort under samtalet. Båda ändrar prefixet. Subagenter är särskilt lätta att få fel här: att köra barn på lägre effort för att spara pengar kan kosta mer i förlorad cache-delning än det sparar.
  • Tät komprimering. Komprimering skriver om historiken av design, så dess kostnad är verklig; lösningen är att komprimera sällan och djupt i stället för ofta och grunt.

Att stänga av uppskjutningen med --tool-deferral=off är ett giltigt A/B-test för att isolera om en beteendeändring kom från ytan i två nivåer. Det återskapar förfrågan exakt som före uppskjutningen, så om beteendet kvarstår med den avstängd är ytan inte orsaken.