Ga naar inhoud

Een trace lezen

Het concept achter verbruik, audit en traces staat in Inzicht.

Een trace laat zien welk verzoek Core naar een modelleverancier stuurde en welk antwoord terugkwam. Core voegt daar een leesbare interpretatie aan toe. Gebruik traces om een onverwacht antwoord of een ontbrekende toolaanroep te onderzoeken.

Core kan meerdere modelaanroepen doen voor één beurt, bijvoorbeeld tijdens toolrondes. Elke modelaanroep krijgt een eigen trace. Dat geldt ook voor verzoeken met store: false.

Je sleutel heeft hiervoor geen aparte capability nodig. De opslag van traces moet wel zijn ingeschakeld voor de installatie en de organisatie. Een trace kan de volledige invoer en uitvoer bevatten; houd daarmee rekening bij het instellen van opslag en bewaartermijnen.

De twee routes

Route Wat die beantwoordt
GET /responses/{response_id}/trace de aanroepen van één beurt, oudste eerst, met een fallover-poging als eigen regel
GET /traces/{call_id} één aanroep, met het document erachter

De lijst is een pagina zoals elke andere lijst in deze API: ?limit= en ?cursor= erin, {items, next_cursor} eruit (Verzoeken). Er wordt geen opgeslagen byte gelezen en geen auditregel geschreven.

curl -s https://<jouw-core>/api/v1/responses/resp_01J.../trace \
  -H "Authorization: Bearer $ARTIFIC_API_KEY"

Elke regel draagt het id van de aanroep, de soort, het model dat je vroeg en het model dat antwoordde, hoe het afliep, wanneer het begon en klaar was, de tokens die de leverancier meldde, de omvang van het document, en of dat document is afgekapt.

En de gereedschapsuitvoeringen waar het antwoord van die aanroep om vroeg, als tool_calls op de regel zelf. Eén pagina van een beurt is daarmee de hele boom — beurt, ronde, en wat elke ronde uitvoerde — zonder tweede verzoek. Elke uitvoering noemt het gereedschap, waar het vandaan kwam, hoe het afliep (ok, error, denied of cancelled), de vaste code achter een mislukking, de status die de bestemming van het gereedschap antwoordde als die er was, wanneer het liep, en welke modelaanroep het resultaat ontving. Een aanroep waarvan het antwoord om geen gereedschap vroeg draagt een lege lijst. Gereedschap dat je eigen toepassing uitvoert — een function-gereedschap — heeft hier geen regel: Core heeft het nooit uitgevoerd. Een tool die het model via de toolrouter bereikte, staat onder zijn eigen naam met routed: true, en elke zoekopdracht van de router draagt in refs hoeveel tools hij rangschikte (candidates), zijn hits met hun score, en keyword_only als hij alleen op trefwoord rangschikte.

Wat een document bevat

GET /traces/{call_id} antwoordt met dezelfde aanroep én een document ernaast, in drie delen.

request is de body die de leverancier kreeg, in de vorm van die leverancier zelf — een OpenAI chat.completions-body, een Anthropic messages-body — en niet Core's kijk daarop. observed zegt of dit de bytes zijn die op de lijn stonden of de payload die de client klaarzette, voor de twee families waarvan Core de verbinding niet kan meekijken. headers_omitted is altijd true: er wordt geen enkele request-header vastgelegd, en daarom kan geen sleutel van jou of van Core hierin staan.

response is het rauwe antwoord van de leverancier: de uiteindelijke body, of — bij een gestreamde aanroep — de fragmenten op volgorde en geen samengestelde body, want het samenstellen van een event-stream is het protocol van de leverancier en niet haar antwoord. Een mislukte aanroep draagt de eigen foutbody van de leverancier, waar Core die kan lezen.

interpretation is de lezing van Core van diezelfde aanroep:

  • elements — elk contextelement in de volgorde waarin het is verstuurd, met authority (core, developer, delegate, user, model), trust (trusted of untrusted), waar het vandaan kwam, de rijen erachter in source_ids, en een JSON-pointer naar de tekst ervan in request.body. Volg text_ref de body in en je leest de woorden van het element uit precies de bytes die de leverancier kreeg; de pointer wijst in de vorm van die leverancier, dus in een Anthropic-body leidt hij naar system of naar een blok van messages en in een Gemini-body naar contents. Een lege text_ref betekent dat Core het element niet kon plaatsen — nooit een gok. authority en trust zijn wat Core over het element wist, niet wat het model te horen kreeg: de lijst begint alleen met een inleidingselement als de sleutel van de beurt trust_envelope heeft, en zonder die capability is een untrusted-element als gewone tekst verstuurd.
  • elements[].tool_calls — wat een ronde aanvroeg, als zij iets aanvroeg: de naam van het gereedschap, het aanroep-id van het model zelf, en arguments_ref, een pointer naar de argumenten zoals de leverancier ze kreeg. Een ronde die alleen gereedschap aanriep heeft geen eigen tekst, dus characters is 0 en text_ref is leeg — de aanroepen zijn wat die ronde was.
  • pseudonyms — elke plaatshouder die in die elementen staat, met het soort gegeven en de posities (Persoonsgegevens verbergen).
  • tools — elke tool waar deze aanroep over besliste, met offered, denied_by_policy, withheld_by_capability, withheld_for_subject (bedoeld voor een ander subject, zoals de eigen mailbox van een serviceaccount), hidden_arguments of routed (achter de toolrouter) en de vaste reden erbij. Juist de tools die niet zijn aangeboden beantwoorden meestal "waarom gebruikte het model die tool niet".
  • blocks — de geheugen- en samenvattingsblokken die naast je eigen berichten zijn ingevoegd, met de rijen waar elk blok van gemaakt is. Bij geheugen is dropped_by_count het aantal passende records dat een aantal wegliet (de limiet van de sleutel, van een opslag of het plafond van de installatie), dropped_by_budget het aantal dat niet in het tokenbudget paste of in wat het plafond van de beurt overliet, en estimated_tokens wat het blok kost. Een skills-regel, zonder tekst, noemt de skills die op inhoud zijn toegevoegd: de dropped_by_count ervan is het aantal passende skills dat retrieval_top_k wegliet, en estimated_tokens wat de toegevoegde teksten kosten. Een tools-regel, zonder tekst, noemt in record_ids de tools die de router vooraf voor deze beurt koos, met dezelfde drie aantallen.
  • routing — de keten waarlangs deze beurt mocht terugvallen, welk model is geprobeerd en welk model antwoordde (Terugvallen).
  • answer — wat het model antwoordde: de tekst, een weigering, de samenvatting van de redenering en de tool-aanroepen die het vroeg, met hun argumenten. Alleen geschreven als de aanroep ok eindigde en alleen voor een chataanroep, dus een mislukte aanroep, een embedding of een afbeelding heeft er geen.
  • recovery — bij een aanroep die het model opnieuw vroeg om een antwoord waarvoor een live check faalde: attempt, de poging waarvoor de tekst van deze aanroep wordt gecontroleerd (vanaf 2), en check, de eerste check waarvoor het eerdere antwoord faalde. Het afgewezen antwoord blijft in de trace van de eerdere aanroep en komt nooit in het gesprek. Null bij elke andere aanroep.

Een transcriptie

Een opname die een audiomodel transcribeerde, is een aanroep van de soort transcription. Maakte de transcriptietool haar, dan hoort ze bij de beurt die de tool aanriep. Gemaakt op POST /audio/transcriptions of voor een input_audio-deel is ze een eigen taak (job), van de soort audio.transcription, met het request-id als id. Haar document verschilt op één punt van dat van een modelaanroep: geen van de secties bevat wat de leverancier ontving of antwoordde. request bevat Core's eigen samenvatting van wat er werd verstuurd (het model, het mediatype en de grootte in bytes van de opname, de taal, de prompt en de temperatuur), en response bevat de lengte van het transcript in tekens en de seconden audio. De opname en de woorden erin staan nooit in een trace. Zie Audio transcriberen.

Nooit in een trace

  • Geen enkele sleutel. Jouw API-sleutel, een leverancierssleutel, een credential-header van een tool: dat zijn allemaal headers, en er wordt geen header gelezen.
  • Niet waar een plaatshouder voor staat. Een pseudoniem draagt de plaatshouder, het soort gegeven en twee posities. Wil je de waarden, vraag dan de pseudoniemen van het gesprek zelf op (Persoonsgegevens verbergen); die route bestaat daarvoor en legt het lezen vast. Een beurt waarvan de gebeurtenis pseudonymisation.applied een renumbered boven nul heeft, is de uitzondering: de plaatshouders daarvan zijn daar niet op te zoeken.
  • Niets van een andere organisatie.

Traces zijn jouw inhoud

Een trace valt onder de bewaartermijn van je organisatie, net als al het andere dat je aanroepers stuurden, en je beheerder mag traces een kortere eigen termijn geven — nooit een langere, want Core ruimt een trace op bij de termijn die het eerst komt. Het wissen van één persoon neemt de traces van die persoon mee (Bouwen voor mensen); het verwijderen van de organisatie neemt ze allemaal mee.

Hun omvang wordt los van je bestanden gemeld, als trace_bytes op GET /usage/summary (Gebruik en audit via de API): een maand gesprekken is klein en een maand aan de bodies erachter niet, dus die twee getallen worden nooit bij elkaar opgeteld.

Een document lezen is een gebeurtenis

Zien dát een aanroep bestaat is gratis. Het document lezen niet: elke GET /traces/{call_id} schrijft één trace.read-auditgebeurtenis met de lezer en het id van de aanroep, of die lezer nu een sleutel is, iemand die is ingelogd in de console, of een operator. Het is de eerste gebeurtenis in het spoor van Core die vastlegt wat er gezien is in plaats van wat er gedaan is, en je vindt hem terug in je eigen auditspoor (Gebruik en audit via de API).

Een gesprek openen in de console is dezelfde daad, meerdere keren: daarbij wordt het document van elke aanroep van de beurten op die pagina gelezen, dus schrijft het één trace.read-gebeurtenis per aanroep in plaats van één voor de pagina.

Wat een sleutel mag lezen

Een sleutel leest de traces van de aanroepen die zij deed. Noemt je applicatie een persoon op haar aanroepen (Bouwen voor mensen), dan leest een credential dat aan één persoon vastzit de traces van die persoon, en -- waar je deployment groepsgesprekken op basis van regels aanzet (threads_group_reach_by_rule, standaard uit) -- de traces van elke beurt in een gesprek dat een regel die de persoon noemt haar laat zien: in een gesprek waarin meerdere mensen schrijven leest ieder ook de traces van de beurten van de anderen. De lijst met aanroepen van een beurt toont nooit een aanroep waarvan het document lezen geweigerd zou worden. Een aanroep voor niemand blijft van je sleutel: die van een indexeerrun overal, en in een gesprek dat een persoon mag lezen een samenvatting van een lang gesprek of een beurt die je backend deed zonder een persoon te noemen. Dat geldt ook voor elke aanroep in een gedeeld gesprek waarop geen regel de persoon noemt. Elke keer dat een document wordt gelezen, wordt vastgelegd wie het las.

Heeft je organisatie het vastleggen uitgezet, dan worden nieuwe aanroepen niet vastgelegd; wat al vastligt blijft leesbaar tot een bewaartermijn het opruimt.

Dezelfde aanroepen in de console

Wie je organisatie beheert leest alles ervan in het onderdeel Traces van de organisatie, met filters en de drie weergaven van één document (Instellingen van een organisatie).

Het onderdeel Traces op Gesprekken: de periode in de paginabalk, de schakelaar Gesprekken en Aanroepen met filters voor soort, afloop en model en Meer filters, de filters die gelden als chips naast hoeveel gesprekken er geladen zijn, en een tabel met de kolommen Laatste activiteit, Soort, Persoon, Beurten en aanroepen, Tools en Modellen.

Dat onderdeel opent op Gesprekken in plaats van op de aanroepen: de aanroepen van de organisatie, gegroepeerd naar het gesprek, de losse beurt of de klus waar ze bij horen, met de laatste activiteit eerst, en per groep de beurten, aanroepen en gereedschappen met de mislukkingen daaronder gemarkeerd. Een gesprek opent als de pagina hieronder; een losse beurt en een klus openen de weergave Aanroepen, teruggeknipt tot precies hun eigen aanroepen, want geen van beide heeft een eigen pagina. Beide weergaven nemen dezelfde filters, dus ze gaan altijd over dezelfde aanroepen: de periode staat in de paginabalk, soort, afloop en model in de rij boven de lijst, en Meer filters opent de persoon, het gereedschap, de uitkomst daarvan, de klus en de response. Elk filter dat geldt is een chip die je los weghaalt, en Wis filters haalt ze allemaal weg. Op een telefoon opent Filters in de balk alle filters tegelijk.

Zoek in de berichten met het vak boven Gesprekken: typ woorden en kies Zoeken, en de lijst toont de berichten waarin ze staan in plaats van de groepen, nieuwste eerst, elk met wie het schreef, de woorden rond de overeenkomst gemarkeerd, de persoon en een link naar het gesprek. De periode, de persoon en de response beperken de zoekopdracht; soort, afloop, model en tool gaan over aanroepen en tellen niet mee zolang je zoekt. Een pagina leest een vast deel van de geschiedenis, dus als ze nog niets vond zegt ze hoe ver terug ze keek en biedt ze Zoek verder terug aan. Elke zoekopdracht komt in het auditlog met de gevonden berichten, nooit met de woorden die je typte.

De pagina van één gesprek: links de lijst Wat er gebeurde, een groep per beurt met het bericht van de persoon, het werk van het model ingesprongen eronder en elk gereedschap als één blok van wat er gevraagd werd en wat terugkwam, met chips om alleen de toolaanroepen of wat mislukte te tonen; rechts de gekozen kaart voluit, met boven de titel wat voor kaart het is en de gegevens als tegels.

Op de pagina van een gesprek toont de kaart van een gereedschap onder Variabelen bij de aanroep de namen van de aanroepvariabelen die het gereedschap uit de tool_variables van het verzoek kreeg, de geheime gemarkeerd, en nooit een waarde: geen enkele trace bewaart er een (Een waarde van je klant aan een tool meegeven).

De pagina van één aanroep toont daar hetzelfde document, maar dan om te lezen. De kop noemt het model dat antwoordde en hoe de aanroep afliep, dan de gegevens van de aanroep als tegels — leverancier, keten, tokens, duur, time to first token en tokensnelheid, de grootte van het document, de ronde, de fout en de klus — en het request-id en trace-id om te kopiëren; elke aanroep van dezelfde beurt is één klik weg. Op de weergave Context staan een lang element en elk gereedschapsresultaat ingeklapt met een knop en hun eerste regels, de gereedschapsaanroepen van een ronde staan er mét hun argumenten, en naast de elementen staan de gereedschappen die deze aanroep kreeg of niet kreeg, de blokken die Core invoegde en de placeholders die de aanroep droeg. De <untrusted source="…">-omslag waarin Core onvertrouwde tekst verpakt voor een sleutel met trust_envelope is daar in de labels gevouwen — de weergave Verzoek houdt de bytes precies zoals ze verstuurd zijn. Een beurt waarvan de sleutel de capability niet heeft, kreeg geen omslag mee: daar wordt niets gevouwen en staat elk element er als de tekst die het is, onder dezelfde labels voor autoriteit en vertrouwen. Een melding boven de elementen, en op de pagina van het gesprek bij het bericht van die beurt, zegt dat de aanroep zonder omslag ging, en elk label Onvertrouwd luidt daar Onvertrouwd · niet ingepakt: de tekst kwam van buiten, maar het model kreeg dat niet te horen. De weergave Antwoord toont interpretation.answer — wat het model zei, een weigering, de samenvatting van de redenering en de aanroepen waar het antwoord om vroeg, het enige deel van een gestreamde aanroep dat nergens anders bestaat — naast de bytes die terugkwamen. Kwamen de eerste en de laatste byte minder dan 100 ms na elkaar, dan staat bij Tokens per seconde niet gestreamd: een snelheid over zo'n kort venster heeft niemand gemeten. De time to first token staat er wel.

En een gesprek lees je als gesprek. Het gesprek op een rij opent een eigen pagina, in twee kolommen. Links staat het gesprek zelf, de oudste bovenaan en de nieuwste onderaan, en de pagina opent onderaan: de instructies die het gesprek meekreeg, dan een groep per beurt — het bericht van de persoon, en daaronder wat het model deed: het denkwerk, elk gereedschap dat het draaide als één blok van wat er gevraagd werd en wat terugkwam, en het antwoord dat terugging. Een compaction-run die Core zelf startte is een eigen groep, op de plek waar hij gebeurde. Klap een groep in tot zijn kop, of toon met de chips boven de lijst alleen de asynchrone tools, de toolaanroepen, de kenniszoekacties, de geheugengereedschappen, de compactionstappen of wat mislukte. Rechts staat de kaart die je aanklikt, helemaal uitgeschreven en alleen die kaart: een bericht toont wat de persoon stuurde en niet het antwoord, en het denkwerk van de aanroep die antwoordde houdt op vóór het antwoord, want het antwoord is een eigen kaart. De kaart staat in de link, en op een telefoon opent hij op een eigen scherm. Elke kaart zegt van wie de woorden zijn en of Core ervoor kon instaan, en precies daarom draagt het blok van een gereedschap twee sets labels: het model schreef de argumenten, en voor wat een gereedschap teruggeeft staat niemand in. Een gereedschap dat het niet deed zegt waarom in de vaste woorden van Core, naast de status die de bestemming zelf antwoordde, en elke pseudoniem-placeholder is gemarkeerd waar hij staat — nooit waar hij voor staat. Een modelaanroep leidt naar haar eigen pagina, en een gereedschap leidt naar de aanroep wiens antwoord erom vroeg. Eerdere beurten laad je bovenaan, waar ze horen.

Gereedschap dat je eigen toepassing uitvoert, staat er ook in. Core voert een function-gereedschap nooit uit, dus het heeft geen uitvoering, maar het gesprek tekent de aanroep waar het model erom vroeg, als een blok met Uitgevoerd door je app: de argumenten die het model schreef, en als resultaat wat je toepassing als function_call_output terugstuurde, zoals de volgende aanroep het kreeg. Zolang je toepassing niets terugstuurde, of als de aanroep die het ontving niet op de pagina staat, zegt het resultaat dat. De kaart van het bericht van een beurt noemt ook de Aangeboden tools: elke tool waar de eerste aanroep over besliste, met waar hij vandaan kwam — system, http, mcp, retrieval of client — zoals de pagina van een aanroep ze noemt. Beantwoordt je toepassing zo'n aanroep door de response voort te zetten met alleen haar function_call_output, dan heeft de beurt die volgt geen eigen bericht: de kop zegt Je app gaf het resultaat van show_chart terug. in plaats van te herhalen wat de persoon de beurt ervoor zei.

Een gereedschap dat op de achtergrond loopt, staat er van start tot resultaat. Startte een beurt een asynchrone tool, dan zegt het blok daarvan Asynchroon met het job-id, en een regel Later eronder zegt hoeveel later het resultaat binnenkwam en of dezelfde beurt of een latere het las, dat nog geen beurt het las, dat de taak zonder resultaat eindigde, of dat het nog loopt, wat een melding boven het gesprek dan ook zegt. De beurt die het resultaat las, toont waar het landde, met de weg terug naar de start, en een beurt die Core zelf startte om een resultaat te beantwoorden staat er met een bel en Gewekt door een asynchroon resultaat, en de kaart leidt terug met Naar de beurt die het startte. Hoe een tool zo gaat draaien, staat op Een tool op de achtergrond draaien.

Deze pagina leest de documenten, en dat wordt vastgelegd. De lijst van Traces leest alleen rijen en schrijft niets; een gesprek openen leest per aanroep van de pagina één document, en elk daarvan is een regel trace.read in het audittrail met de naam van de lezer erbij. De pagina zegt dat boven de kolommen.

Publiceert jouw omgeving een telemetrieconsole, dan is het trace-id van een aanroep ook een link rechtstreeks naar de spans van die trace; publiceert ze er geen, dan is het id tekst die je kopieert naar de console die je wél gebruikt.