Model přes API · lekce 2 z 7 · 14 min čtení
Strukturovaný výstup a volání nástrojů
Jak API zaručí, že model vrátí data v přesném tvaru, a jak model „používá“ nástroje: popíšeš je, model požádá o volání, tvůj kód ho provede a vrátí výsledek. Krok za krokem na dotazu na stav objednávky, včetně toho, co to umožňuje a kde to může selhat.
V minulé lekci jsi viděl, jak program pošle modelu text a dostane zpátky text. Pro chatbota to stačí. Jenže většina firemních aplikací potřebuje dvě věci navíc. Zaprvé, výstup má zpracovat další program, a ten potřebuje data v přesném tvaru, ne volné věty. Zadruhé, model má pracovat se skutečnými údaji: se stavem objednávky, s volnými termíny v kalendáři, se záznamem v CRM. Ty v jeho tréninkových datech nejsou a být nemůžou.
Obě potřeby řeší API funkcemi, které se jmenují strukturované výstupy a volání nástrojů. Stojí na stejném principu: popíšeš přesný tvar dat a model se ho drží. A obě jsou základem všeho, co přijde dál v kurzu, od agentů po MCP.
Strukturované výstupy: tvar, na který se dá spolehnout
V lekci Strukturovaný výstup: tabulky, seznamy a JSON ses naučil říct si o JSON v promptu: „Odpověz POUZE JSONem v tomto tvaru…“. Viděl jsi i typické chyby: text navíc před daty, chybějící závorka, "ano" místo true, jiný název pole. V chatu to opravíš rukou. V systému, který zpracuje deset tisíc e-mailů za noc, jedna rozbitá odpověď z tisíce znamená deset zaseknutých záznamů každou noc.
Proto API nabízí víc než prosbu v promptu.
- JSON schéma(JSON Schema)
- Formální popis, jak mají data vypadat: jaká pole musí obsahovat, jakého typu jsou (text, číslo, ano/ne, seznam), která jsou povinná a jaké hodnoty jsou povolené. Je to jako formulář s předtištěnými kolonkami, jen čitelný pro programy.
Když v požadavku pošleš JSON schéma a zapneš strukturované výstupy, API zaručí, že odpověď schématu odpovídá. Nefunguje to tak, že by model „víc poslouchal“. Při generování se mu jednoduše nedovolí vybrat token, který by tvar porušil. Z lekce o strukturovaném výstupu víš, že se tomu odborně říká omezené dekódování. Model pořád předpovídá token po tokenu, jen ze zúženého výběru.
| JSON vyžádaný v promptu | Strukturovaný výstup v API | |
|---|---|---|
| Platný JSON | Většinou | Zaručeně (až na výjimky níže) |
| Správné názvy polí a typy | Většinou | Zaručeně |
| Povinná pole nechybí | Většinou | Zaručeně |
| Hodnoty jsou pravdivé | Nezaručeně | Nezaručeně |
| Kde to funguje | Kdekoli, i v chatu | Jen přes API, u podporovaných modelů |
Poslední dva řádky jsou to nejdůležitější. Schéma zaručuje tvar, ne pravdu. Pole castka_kc bude vždycky číslo, ale může to být špatné číslo. Když v e-mailu údaj chybí a schéma ho vyžaduje jako povinný, model ho musí nějak vyplnit, a může si ho domyslet. Proto se do schématu vyplatí dávat možnost „údaj chybí“ (prázdnou hodnotu) všude, kde údaj chybět může.
Dokumentace Anthropicu uvádí i výjimky ze záruky tvaru: když model odpověď odmítne, nebo když dojde limit tokenů (odpověď je useknutá), výstup schématu odpovídat nemusí. Tady se vrací důvod zastavení z minulé lekce: systém ho musí kontrolovat vždycky. A schémata mají omezení: některé složitější konstrukce API nepodporuje a vrátí chybu, takže se schéma musí navrhnout jednodušeji a zbytek ohlídat kódem.
Do hloubkyPro ty, kdo programují: strukturovaný výstup v požadavku
U Anthropicu se schéma posílá v poli output_config.format (v době psaní, ověř v dokumentaci):
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"messages": [
{ "role": "user", "content": "Vytáhni údaje z e-mailu: Dobrý den, za firmu Novák Stav objednáváme 12 židlí Ergo. Petr Novák" }
],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"zakaznik": { "type": "string" },
"produkt": { "type": "string" },
"pocet": { "type": "integer" },
"pozadovany_termin": { "type": ["string", "null"] }
},
"required": ["zakaznik", "produkt", "pocet", "pozadovany_termin"],
"additionalProperties": false
}
}
}
}'
Odpověď pak v textovém bloku obsahuje JSON přesně v tomto tvaru. Všimni si pole pozadovany_termin: povolený typ je text, nebo null. Model tak má legální způsob, jak říct „v e-mailu to není“, a nemusí si termín vymýšlet.
OpenAI má obdobnou funkci (Structured Outputs) a ve své dokumentaci ji výslovně odlišuje od staršího „JSON režimu“: ten zaručuje jen platný JSON, ne dodržení schématu.
Volání nástrojů: model, který si řekne o data
Teď druhá potřeba. Zákazník napíše do chatu na webu: „Kde je moje objednávka 48213?“ Model stav objednávky znát nemůže. Ten je v databázi e-shopu a mění se každou hodinu. Kdyby odpověděl „z hlavy“, odpověď by byla čistá halucinace, jen velmi přesvědčivá.
Princip volání nástrojů jsi poprvé potkal v lekci Když nestačí chat: model místo odpovědi napíše strukturovanou žádost o akci a aplikace ji provede. Tam ses na to díval jako uživatel hotového asistenta. Teď jsi na druhé straně: ty rozhoduješ, jaké nástroje model dostane, a tvůj kód je provádí.
- Nástroj(tool, function)
- Funkce tvého systému, kterou modelu popíšeš jménem, slovním popisem a JSON schématem vstupů. Model ji nemůže spustit. Může jen požádat, aby ji spustil tvůj program, a navrhnout, s jakými údaji (argumenty).
Nejdůležitější věta celé lekce: model nikdy nic sám nespouští. Nemá přístup k tvé databázi, ke kalendáři ani k internetu. Umí jen jedno: vygenerovat text. Při volání nástrojů ten text jen má přesně daný tvar, který tvůj program pozná jako žádost. Jestli se žádost provede, s jakými oprávněními a co se vrátí, rozhoduje vždy kód kolem modelu. (I nástroje, které „běží u výrobce“, jako hledání na webu u některých API, spouští infrastruktura výrobce, ne model.)
Krok za krokem: dotaz na stav objednávky
Podívejme se, co se doopravdy děje, když se zákazník zeptá na objednávku. Aplikace má jeden nástroj, get_order_status (zjisti stav objednávky), který přijímá číslo objednávky.
| Krok | Kdo | Co se děje |
|---|---|---|
| 1 | Zákazník | Napíše: „Kde je moje objednávka 48213?“ |
| 2 | Tvůj systém → API | Pošle modelu systémový prompt, zprávu zákazníka a popis nástroje get_order_status: co dělá a že potřebuje číslo objednávky. |
| 3 | Model → tvůj systém | Neodpoví textem. Vrátí žádost o volání nástroje: název get_order_status, argument order_id: "48213". Důvod zastavení je „chci použít nástroj“ (u Anthropicu tool_use). |
| 4 | Tvůj systém | Zkontroluje žádost: existuje takový nástroj, je číslo ve správném tvaru, patří objednávka přihlášenému zákazníkovi? Pak se zeptá databáze. |
| 5 | Databáze → tvůj systém | Vrátí: odesláno 4. 11., dopravce PPL, doručení očekáváno 6. 11. |
| 6 | Tvůj systém → API | Pošle modelu celou konverzaci znovu (pamatuješ, model je bezstavový): původní dotaz, žádost o nástroj a nově i výsledek nástroje. |
| 7 | Model → tvůj systém | Teď má údaje v kontextu a napíše odpověď: „Vaše objednávka 48213 odešla 4. listopadu přes PPL, doručení čekejte ve čtvrtek 6. listopadu.“ |
| 8 | Tvůj systém → zákazník | Zobrazí odpověď. |
Pár věcí, které z tabulky nejsou vidět na první pohled:
- Model rozhodl, že nástroj potřebuje. Nikdo mu neřekl „teď zavolej databázi“. Podle dotazu a popisu nástroje usoudil, že odpověď v kontextu nemá a nástroj ji dodá. Kdyby se zákazník zeptal „Jak dlouho trvá doručení?“ a odpověď byla v systémovém promptu, model by nástroj nejspíš nevolal.
- Jedna otázka znamenala dvě volání API. A při druhém se platí znovu za celý vstup, včetně popisů nástrojů a výsledku. Nástroje tak zvyšují spotřebu tokenů i čas odpovědi.
- Kroky 3–6 se mohou opakovat. Model může po prvním výsledku požádat o další nástroj, nebo o několik naráz. Tahle smyčka „požádej, proveď, vrať, pokračuj“ je přesně to, z čeho se staví agenti.
- Popis nástroje je prompt. Model se podle něj rozhoduje, kdy nástroj použít a jak vyplnit argumenty. Vágní popis vede ke špatným voláním. Psaní popisů nástrojů je stejná řemeslná práce jako psaní systémového promptu.
Do hloubkyPro ty, kdo programují: nástroj v kódu
Popis nástroje u Anthropicu má jméno, popis a schéma vstupů (input_schema). Volitelně strict: true, které zaručí, že argumenty budou schématu odpovídat. Smyčka v TypeScriptu, zjednodušeně (bez ošetření chyb):
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const tools: Anthropic.Tool[] = [
{
name: "get_order_status",
description:
"Vrátí aktuální stav objednávky přihlášeného zákazníka podle čísla objednávky. " +
"Použij, když se zákazník ptá, kde je jeho zásilka nebo v jakém stavu je objednávka.",
input_schema: {
type: "object",
properties: {
order_id: { type: "string", description: "Číslo objednávky, např. 48213" },
},
required: ["order_id"],
additionalProperties: false,
},
strict: true,
},
];
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "Kde je moje objednávka 48213?" },
];
let response = await client.messages.create({
model: "claude-opus-5-5", max_tokens: 1024, tools, messages,
});
while (response.stop_reason === "tool_use") {
messages.push({ role: "assistant", content: response.content });
const results: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type !== "tool_use") continue;
// Tady rozhoduje TVŮJ kód: ověř nástroj, argumenty a oprávnění.
const output = await runTool(block.name, block.input, currentCustomer);
results.push({ type: "tool_result", tool_use_id: block.id, content: output });
}
messages.push({ role: "user", content: results });
response = await client.messages.create({
model: "claude-opus-5-5", max_tokens: 1024, tools, messages,
});
}
Funkce runTool je tvoje: zkontroluje, že objednávka patří currentCustomer, zeptá se databáze a vrátí text nebo JSON. Výsledky se vracejí v roli user jako bloky tool_result spárované s žádostí přes tool_use_id. Oficiální knihovny mají i pomocníka (tool runner), který smyčku obstará sám.
U OpenAI je postup stejný v pěti krocích, jak je popisuje jejich dokumentace: pošli požadavek s nástroji, dostaň žádost o volání, proveď kód u sebe, pošli druhý požadavek s výsledkem, dostaň odpověď (nebo další žádosti). Nástroj se popisuje polem "type": "function" se jménem, popisem, schématem v poli parameters a volitelně "strict": true.
Co to umožňuje
Volání nástrojů je most mezi jazykovým modelem a zbytkem firmy. Místo modelu, který jen mluví, máš model, který si umí říct o data a navrhnout akci:
- Čtení z databází a systémů: stav objednávek, skladové zásoby, historie zákazníka v CRM, data z účetnictví.
- Kalendáře a rezervace: najít volný termín, navrhnout schůzku, rezervovat zasedačku.
- Zápis a akce: vytvořit požadavek v helpdesku, založit kontakt v CRM, poslat e-mail, změnit adresu doručení.
- Výpočty a převody: místo počítání „z hlavy“ zavolat kalkulačku nebo tabulkový výpočet (proč je to lepší, víš z lekce Analýza dat a dokumentů).
- Hledání ve firemních dokumentech: nástroj, který vyhledá relevantní pasáže. Na tom stojí RAG, kterému se věnují lekce Embeddingy a RAG v praxi.
A navíc: nástroje jsou také elegantní způsob, jak dostat strukturovaná data. Formulář, který model vyplní jako argumenty nástroje, je JSON podle schématu, i když se pak žádná akce neprovede.
Kde to selhává a jak se bránit
Model, který může navrhovat akce, otevírá nový druh chyb. Nejde už jen o špatnou větu, ale o špatný čin. Typické problémy:
- Špatný nástroj. Model zavolá „zruš objednávku“, když se zákazník ptal, jestli ji může zrušit. Čím víc podobných nástrojů a čím vágnější popisy, tím častěji.
- Špatné nebo domyšlené argumenty. Zákazník napíše „ta moje poslední objednávka“ a model si číslo domyslí. Dokumentace Anthropicu sama upozorňuje, že když v dotazu chybí povinný údaj, některé modely (zvlášť ty méně schopné) se místo zeptání raději pokusí „rozumnou“ hodnotu odhadnout.
strict: truezaručí, že argument bude mít správný tvar, ne že bude správný. - Nástroj udělá víc, než měl. Když nástroj umí „spusť libovolný dotaz do databáze“, model ho může použít jinak, než sis představoval.
- Výsledek nástroje jako past. Text, který nástroj vrátí (e-mail od zákazníka, webová stránka, dokument), může obsahovat skryté pokyny, které se model pokusí splnit. Tomu se říká prompt injection a věnuje se mu lekce Prompt injection.
Obrana stojí na jednom principu: o tom, co se smí stát, rozhoduje kód, ne model. Prakticky:
- Kontroluj každou žádost. Existuje nástroj, odpovídají argumenty, dává smysl v tomto kontextu? Neplatnou žádost odmítni a vrať modelu chybu, ať se opraví nebo zeptá.
- Oprávnění odvozuj od přihlášeného uživatele, ne od modelu. Nástroj
get_order_statusmusí sám ověřit, že objednávka patří tomu, kdo je přihlášený. Když model požádá o cizí objednávku (třeba proto, že ho k tomu zákazník přemluvil), kód ji prostě nevydá. - Dávej nástrojům co nejmenší pravomoci. Raději úzký nástroj „zjisti stav objednávky“ než obecný „přečti cokoli z databáze“. Raději jen čtení, kde zápis není potřeba.
- U akcí, které nejdou vzít zpátky, chtěj potvrzení člověka. Odeslání e-mailu klientovi, vrácení peněz, smazání záznamu. Model navrhne, člověk potvrdí.
- Zapisuj, co se dělo. Které nástroje model volal, s jakými argumenty a co se vrátilo. Bez toho nezjistíš, proč se něco pokazilo.
Jak tyto zásady nastavit soustavně, kdo co smí a kde musí být člověk, rozebírá lekce Oprávnění a lidská kontrola.
Most k agentům a MCP
Když se smyčka z našeho příkladu nechá běžet víc kol (model zavolá nástroj, podívá se na výsledek, zavolá další, a tak dál, dokud úkol nesplní), máš agenta. Rozdíl mezi chatbotem s jedním nástrojem a agentem není v jiné technologii, ale v tom, kolik kroků a kolik samostatnosti model dostane. Kdy se to vyplatí a jak to uhlídat, je téma lekce Agenti.
A druhá otázka, která tě brzy napadne: když chci modelu dát nástroje pro kalendář, CRM a helpdesk, musí je každá firma psát znovu pro každou aplikaci? Právě tohle řeší MCP (Model Context Protocol), jednotný způsob, jak nástroje a data nabídnout různým AI aplikacím. Pod kapotou je to pořád volání nástrojů, jak jsi ho viděl tady. Víc v lekci MCP.
Co si odnést
- Strukturované výstupy v API zaručují tvar dat podle JSON schématu, protože model při generování nesmí zvolit token, který by tvar porušil. Nezaručují pravdivost a mají výjimky (odmítnutí, useknutá odpověď).
- Volání nástrojů: popíšeš nástroje, model požádá o volání s argumenty, tvůj kód ho provede a výsledek vrátí, model pak odpoví. Model sám nikdy nic nespouští.
- Jedna otázka s nástrojem znamená víc volání API a víc tokenů. Popis nástroje funguje jako prompt a jeho kvalita rozhoduje o tom, jestli model volá správně.
- Nástroje napojí AI na databáze, kalendáře, CRM a dokumenty. Zároveň přinášejí nové chyby: špatný nástroj, domyšlené argumenty, škodlivé pokyny ve výsledcích.
- O tom, co se smí stát, rozhoduje kód: kontrola každé žádosti, oprávnění podle přihlášeného uživatele, co nejužší nástroje a potvrzení člověkem u nevratných akcí.
- Smyčka volání nástrojů je základ agentů a MCP je standard, jak nástroje sdílet mezi aplikacemi.
Zdroje a další čtení
- Anthropic: Tool use with Claude – jak funguje volání nástrojů, kde nástroje běží a jak se účtují.
- Anthropic: Structured outputs – vynucení JSON schématu, strict tool use a výjimky ze záruky.
- OpenAI: Function calling – postup volání funkcí v pěti krocích a tvar popisu nástroje.
- OpenAI: Structured Outputs – rozdíl mezi strukturovanými výstupy a JSON režimem.
Kvíz k modulu
Model přes API
Otázka 1 z 6
Zákazník píše chatbotovi na webu už desátou zprávu. Co musí aplikace poslat modelu přes API, aby odpověď navazovala na rozhovor?