Tool Calling a strukturované výstupy: smlouva, která drží
24 volání, žádný rozbitý JSON a dvě použitelné datumové hodnoty. Pak stejný endpoint s lepším popisem — a co schema neopraví.
Na této stránce
Dejte modelu nástroj pro vyhledávání letů a požádejte ho, aby našel let z Madridu do Berlína. Vrátí se toto:
<tool_call>
{"name": "search_flights",
"arguments": {"from": "Madrid", "to": "Berlin", "date": "3rd October 2026"}}
</tool_call>JSON je validní. Název nástroje je správný. Všechna povinná pole jsou přítomná. A volání je k ničemu: žádné API pro lety nepřijme "Madrid" tam, kde chce kód letiště, ani "3rd October 2026" tam, kde chce datum.
Právě o téhle mezeře — syntakticky dokonalé, sémanticky nepoužitelné — je tato kapitola. A první věc, kterou je potřeba si ujasnit: není to problém JSON. Během dvaceti čtyř požadavků s tímto nástrojem model vytvořil 24 validních volání nástroje a nulový počet rozbitých JSON. Ani jednou neselhal v části, kterou všichni ladí.
Model nic nespouští
Odkaz na sekci: Model nic nespouštíNež přijdou mechaniky, věta, která zabrání největšímu zmatku: volání nástroje je žádost, ne akce.
Model vydá strukturovanou zprávu, která říká chtěl bych zavolat search_flights s těmito argumenty. Pak se zastaví. Váš kód tu zprávu přijme, rozhodne, zda ji splní, zavolá cokoli má zavolat a pošle výsledek zpět jako další zprávu. Model se nikdy nedotkl vaší databáze, nikdy neprovedl HTTP požadavek, nikdy neměl přihlašovací údaje.
Z tohoto rozdělení plyne všechno o zabezpečení agent v kapitole 30 i všechno o návrhu agent v kapitole 23: model navrhuje a váš kód rozhoduje, a právě v kódu žijí všechny záruky.
Nástroj, zbavený slovní zásoby, jsou tedy dvě věci:
Schema. JSON Schema popisující funkci: její název, co dělá a jaké argumenty bere, včetně jejich typů a omezení. To se dostává do prompt a je to jediná věc, kterou model kdy vidí.
Endpoint. Funkce ve vašem kódu, která tyto argumenty vezme a něco vrátí. Model ji nikdy nevidí, nikdy neví, v jakém je jazyce, a nedokáže rozeznat databázový dotaz od napevno zadaného řetězce.
Schémata posíláte s požadavkem
Odkaz na sekci: Schémata posíláte s požadavkemDefinice nástrojů jdou do prompt, serializované do formátu, na kterém byl model trénován. Stojí tokeny při každém jednotlivém volání — fakt, který se později v této kapitole vrátí s číslem.
Model odpoví voláním místo textu
Odkaz na sekci: Model odpoví voláním místo textuMísto prózy odpověď obsahuje strukturovanou žádost a API ohlásí odpovídající důvod ukončení. Na důvodu záleží: právě podle něj váš kód pozná, že má spustit nástroj, ne ukázat uživateli odpověď.
Váš kód ho spustí — nebo odmítne
Odkaz na sekci: Váš kód ho spustí — nebo odmítneTohle je krok, ve kterém model vůbec není. Ověřte argumenty proti schema, rozhodněte, zda tento volající smí udělat, o co žádá, a proveďte to.
Výsledek pošlete zpět jako zprávu
Odkaz na sekci: Výsledek pošlete zpět jako zprávuVýsledek se stane dalším tahem v konverzaci, v roli vyhrazené pro tento účel. Model ho čte jako jakýkoli jiný context.
Model odpoví, nebo požádá o další nástroj
Odkaz na sekci: Model odpoví, nebo požádá o další nástrojCož je smyčka z kapitoly 23 a důvod, proč se jeden požadavek může změnit v tucet obousměrných cest.
Nic z toho není emergentní. Jak ukázala kapitola 11, tool calling je natrénované chování:1 během post-training model viděl tisíce konverzací tvarovaných přesně takto. Proto je formát specifický pro model, proto se spolehlivost tak liší mezi modely podobné velikosti a proto model dokáže zavolat nástroj, který nikdy předtím neviděl — tvar byl natrénován, konkrétní nástroj pochází z vašeho prompt.
Kolik stojí špatné schema, změřeno
Odkaz na sekci: Kolik stojí špatné schema, změřenoTakhle nástroj napíše většina lidí poprvé. Všimněte si, že na něm není nic špatně; je jen řídký:
{
name: "search_flights",
description: "Search for flights.",
parameters: {
type: "object",
properties: {
from: { type: "string", description: "Airport." },
to: { type: "string", description: "Airport." },
date: { type: "string", description: "The date." },
},
required: ["from", "to", "date"],
},
}Dvacet čtyři požadavků, šest dvojic měst zkřížených se čtyřmi způsoby vyjádření data („třetího příští měsíc“, „příští pátek“, „15. prosince“, „zítra“), greedy decoding, aby šly výsledky reprodukovat:
| nástroj zavolán | rozbitý JSON | datum v ISO | letiště jako IATA | vše správně | |
|---|---|---|---|---|---|
| schema výše | 24/24 | 0 | 2/24 | 4/24 | 1/24 |
Přečtěte si první dva sloupce dřív než poslední tři. Model pokaždé zavolá správný nástroj a pokaždé vytvoří dobře utvořený JSON. Selhání je celé v hodnotách a hodnoty jsou nepoužitelné: "Madrid" místo MAD, "3rd October 2026" místo 2026-10-03.
Stojí za to na tom trvat, protože to určuje, kam se díváte, když se něco rozbije. Instinkt velí přidat JSON parser s retry, nebo požádat model důrazněji o validní JSON. Ani jedno neřeší nic z toho, co se stalo tady.
Teď změňte jen popis
Odkaz na sekci: Teď změňte jen popisStejný endpoint. Stejný kód za ním. Stejný model, stejné prompts, stejné dekódování. Jediná věc, která se mění, je text ve schema:
{
name: "search_flights",
description: "Search scheduled flights between two airports on a given day.",
parameters: {
type: "object",
properties: {
from: {
type: "string",
description: "Departure airport as a three-letter IATA code, e.g. MAD for Madrid. Never a city name.",
pattern: "^[A-Z]{3}$",
},
to: { /* same */ },
date: {
type: "string",
description: "Departure date as an ISO 8601 calendar date, YYYY-MM-DD. Resolve relative dates against today before calling.",
format: "date",
pattern: "^\\d{4}-\\d{2}-\\d{2}$",
},
},
required: ["from", "to", "date"],
},
}| FORMÁT data | HODNOTA data | FORMÁT letiště | HODNOTA letiště | |
|---|---|---|---|---|
| řídké schema | 2/24 | 1/24 | 4/24 | 4/24 |
| popsané schema | 24/24 | 12/24 | 16/24 | 8/24 |
Formát data se posune ze 2 z 24 na 24 z 24. Dokonalé, jen změnou textu, bez zásahu do kódu a bez logiky retry. Pokud si z této kapitoly odnesete jeden provozní návyk, pak tento: když je nástroj zavolán špatně, oprava je téměř vždy v popisu a je to nejlevnější oprava v systému.
Teď si přečtěte druhý sloupec, což je ta důležitější polovina.
Schema omezuje tvar. Nedodá znalosti.
Odkaz na sekci: Schema omezuje tvar. Nedodá znalosti.Datum je ve formátu ISO ve 24 případech z 24. Je to správný den ve 12 případech z 24.
Takže polovina volání teď nese dokonale zformátované datum, které je špatně. Popis řekl modelu, jaký tvar má vytvořit, a model ho vytvořil bezchybně — ale převést „příští pátek“ na 2026-09-11 vyžaduje znát dnešní datum a provést kalendářní aritmetiku, a to žádné množství popisu nedodá. Stejný příběh platí pro letiště: formát šel ze 4 na 16, ale hodnota jen ze 4 na 8, protože napsat MAD vyžaduje vědět, že madridské letiště je MAD.
Tohle rozlišení je nosná myšlenka kapitoly:
Schema je smlouva o formě. Dokáže udělat výstup modelu parsovatelný, typovaný a konzistentní. Nedokáže z něj udělat pravdu a každý režim selhání, který přežije dobré schema, je selhání znalostí, ne selhání formátu.
Ty dvě věci potřebují různé opravy a jejich zaměňování stojí týdny. Selhání formátu se opravují v popisu nebo pomocí constrained decoding, níže. Selhání znalostí se opravují tím, že znalosti vložíte do prompt — aktuální datum do systémové zprávy, vyhledání letiště jako druhý nástroj, který model zavolá jako první, enum ve schema, když je množina dost malá na vyjmenování. Všimněte si, co mají všechny tři společné: přesouvají problém z paměti modelu do jeho vstupu, což je celá kapitola 24.
Strukturované výstupy a co „constrained decoding“ ve skutečnosti je
Odkaz na sekci: Strukturované výstupy a co „constrained decoding“ ve skutečnosti jeVšechno výše pořád spoléhá na to, že se model rozhodne vytvořit správný tvar. Existuje silnější záruka a je to nejlepší výsledek kapitoly 17.
Připomeňme si, jak funguje generování: v každém kroku model vytvoří logit pro každý token ve slovníku a sampler jeden vybere. Constrained decoding mezi to vloží další krok. Na základě gramatiky — odvozené z vašeho JSON Schema — spočítá, které tokeny by legálně mohly následovat, nastaví logits všech ostatních na záporné nekonečno a nechá sampler vybrat ze zbytku.
Pokud schema říká, že další věc musí být {, pak každý token, který není {, má pravděpodobnost nula. Ne „nepravděpodobnou“: nula. Model nemůže vydat nevalidní JSON, protože nevalidní tokeny byly z distribuce odstraněny ještě před sampling.
To je to, co se skrývá pod „structured outputs“, „JSON mode“ a „guided generation“, a vysvětluje to jejich dvě vlastnosti. Záruka je úplná pro všechno, co gramatika umí vyjádřit — typy, povinná pole, enums, vnoření — protože je vynucena mechanicky, ne zdvořile vyžádána. A neříká nic o obsahu: gramatika může donutit "date", aby byl řetězec odpovídající vzoru data, ale nedokáže ho donutit být správným dnem. Což je stejná zeď jako v předchozí části, jen dosažená z druhé strany.
Dvě praktické poznámky. Není to zdarma: maska se musí počítat v každém kroku a složité gramatiky stojí měřitelnou latenci. A mění to, co model dělá — model odkloněný od preferovaného token může vytvářet horší obsah, zatímco produkuje dokonalou strukturu. Proto je „hezky se zeptat a validovat“ pořád rozumný výchozí stav pro jednoduché tvary a constrained decoding si svou cenu zaslouží, když je tvar složitý nebo je spotřebitel přísný.
Vedlejší efekty a jedna vlastnost, na které záleží
Odkaz na sekci: Vedlejší efekty a jedna vlastnost, na které záležíKapitola 14 změřila timeout následovaný retry, který naúčtoval dvě generace za jednu odpověď. S nástroji je stejné selhání horší, protože nástroj může něco udělat.
Pokud váš kód zavolá charge_card, vyprší mu čas a zkusí to znovu, máte dvě platby. Model nemá tušení, že se cokoli z toho stalo; vidí jeden výsledek nástroje. Oprava je stejná jako v jakémkoli distribuovaném systému a není to problém modelu: udělejte operaci idempotentní tím, že volání dáte klíč, aby druhé provedení rozpoznalo první a vrátilo jeho výsledek místo opakování práce.
Návrhové pravidlo, které z toho plyne, stojí za jasné vyslovení. Oddělte čtení od zápisů ve svém katalogu nástrojů. Čtení lze volně opakovat, spouštět paralelně a cachovat. Zápis ne, a měl by nést klíč, kontrolu oprávnění a — u všeho, o čem by uživatel chtěl vědět dřív, než se to stane — krok schválení, který vloží člověka mezi žádost a akci. Ten krok schválení není zdvořilost: je to jedna z mála věcí mezi prompt injection a skutečným následkem — a jak měří kapitola 30, jedna z nejslabších.
Kolik nástrojů, než se to zhorší?
Odkaz na sekci: Kolik nástrojů, než se to zhorší?Folklor říká, že načtení mnoha nástrojů vede model ke špatnému výběru. Stojí za to to změřit, ne jen opakovat. Tedy: stejných dvacet čtyři požadavků, s nástrojem pro lety plus rostoucí sadou dalších — včetně tří záměrně zaměnitelných (vlakové jízdní řády, trajektové spoje, autobusové trasy).
| načtených nástrojů | prompt tokens | zvolil search_flights | datum v ISO |
|---|---|---|---|
| 1 | 353 | 24/24 | 24/24 |
| 5 | 730 | 24/24 | 24/24 |
| 10 | 1,193 | 21/24 | 21/24 |
| 20 | 2,119 | 24/24 | 24/24 |
Výběr se nezhoršil. S dvaceti nástroji, z nichž tři byly věrohodně zaměnitelné, vybral model s půl miliardou parametrů správný nástroj ve dvaceti čtyřech případech z dvaceti čtyř. Propad u deseti jsou tři volání, která pojmenovala jiný nástroj, a při přechodu na dvacet nepřetrvá.
Je to negativní výsledek a měl by být takto uveden: u této úlohy, s těmito nástroji, nebylo problémem „příliš mnoho nástrojů“. Co rostlo, monotonně a šestinásobně, byl prompt: z 353 tokenů na 2,119, placených při každém požadavku v konverzaci, navždy, ať už se jakýkoli nástroj použije, nebo ne.
Poctivá verze folkloru je tedy o nákladech a context, ne o přesnosti. Dvacet nástrojů je trvalá daň z každé zprávy a kapitola 16 už ukázala, co trvalý prefix udělá s účtem během čtyřiceti tahů. Když lidé hlásí, že mnoho nástrojů zhoršuje kvalitu, mechanismus obvykle spočívá v tom, že definice vytlačily context, na kterém záleželo — což je problém kapitoly 24 v kostýmu kapitoly 18. Nástroje, které jsou skutečně téměř duplicitní, jsou také reálný problém a oprava pro ně není méně nástrojů, ale lepší popisy a namespaces: prefixujte je podle systému (crm.search_customer, billing.search_customer), aby se dva katalogy sloučené ze dvou týmů nesrazily a aby model měl podle čeho rozlišovat.
Tři druhy nástrojů a ten, který otevírá další část
Odkaz na sekci: Tři druhy nástrojů a ten, který otevírá další částPomáhá roztřídit nástroje podle toho, co dělají se světem, protože inženýrství je u každého jiné.
Datové nástroje čtou: hledají, načítají, dotazují se. Lze je opakovat, paralelizovat a cachovat. Selhávají tím, že nevrátí nic užitečného, a jejich hlavní riziko je, že přinášejí nedůvěryhodný text do context — což je celá plocha útoku kapitoly 30.
Akční nástroje zapisují: posílají, vytvářejí, účtují, mažou. Bez klíče je nelze bezpečně opakovat, nelze je bezpečně paralelizovat a právě kvůli nim existují schvalovací toky.
Orchestrační nástroje volají jiné modely. Nástroj, jehož implementací je jiný agent, s vlastním prompt, vlastními nástroji a vlastní smyčkou — a volajícímu modelu vypadá přesně jako předchozí dva, protože schema a endpoint jsou všechno, co kdy vidí.
Ten třetí druh není kuriozita. Je to mechanismus za polovinou „agent jako nástroj“ v kapitole 25 — druhá topologie, handoff, konverzaci předá pryč a nikdy ji nedostane zpět — a funguje přesně proto, že rozhraní v této kapitole je dost úzké na to, aby se za něj vešel celý agent.
Kam to vede dál
Odkaz na sekci: Kam to vede dálTeď máte model, který si umí o věci říct, a smlouvu, díky níž je to žádání parsovatelné. Co nemáte, je cokoli, na co by se mohl ptát, kromě toho, co se vejde do jeho prompt.
Nejběžnějším nástrojem v produkci, s velkým náskokem, je vyhledávání v korpusu textu, který model během trénování nikdy neviděl: vaše dokumentace, vaše tickety, vaše smlouvy. Zní to jako vyřešený problém — vytvořit embedding, najít nejbližší sousedy, vložit je do prompt — a nevyřešené části jsou právě ty, které rozhodují, zda je odpověď důvěryhodná: jak se text rozřeže před tím, než se vytvoří embedding, jaký práh podobnosti je dost nízký na to, aby znamenal nevím, a jak se citace připojí k tvrzení, aby si ji čtenář mohl ověřit.
Kapitola 19 je retrieval a je to kapitola, ve které špatná odpověď přestává být kuriozitou a začíná být závazkem.
Zdroje a metoda
Odkaz na sekci: Zdroje a metodaMěření v této kapitole pocházejí z Qwen/Qwen2.5-0.5B-Instruct s greedy decoding, přes 24 vygenerovaných požadavků křížících šest dvojic měst se čtyřmi formulacemi data, s použitím vlastního chat template modelu pro definice nástrojů. Reprodukují se přesně a jde o malý model: rozdělení formát/hodnota čtěte jako ukázku mechanismu, ne jako benchmark toho, co dělají současné modely. Frontier model vyřeší „příští pátek“ správně mnohem častěji — a pořád ho k tomu schema nedokáže přinutit, což je část, která se zobecňuje.
Slovník JSON Schema použitý výše (type, properties, required, pattern, format, enum) je specifikován v draftu JSON Schema, který uvádí dokumentace vašeho providera; užitečná podmnožina je malá a napříč providery stejná, a rozdíly, které existují — která klíčová slova jsou vynucena constrained decoding a která se modelu jen předávají — stojí za přečtení v průvodci structured-output vašeho providera, ne za předpokládání.
U constrained decoding jako techniky dokumentují knihovny typu guidance a projekt outlines konstrukci grammar-to-logit-mask způsobem, který přímo mapuje na sampler z kapitoly 17. A pro samotnou obousměrnou cestu není nejjasnější specifikací tutoriál, ale protokol: kapitola 26 ho čte řádek po řádku.
Reference
Odkaz na sekci: Reference-
Ouyang, L. et al. Training language models to follow instructions with human feedback. arXiv:2203.02155 (2022). Článek, který z receptu post-training udělal standard; tvar volání nástroje se tam učí z demonstrací, přesně jako tvar odpovědi. ↩