Přeskočit na obsah

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 promptuStrukturovaný výstup v API
Platný JSONVětšinouZaručeně (až na výjimky níže)
Správné názvy polí a typyVětšinouZaručeně
Povinná pole nechybíVětšinouZaručeně
Hodnoty jsou pravdivéNezaručeněNezaručeně
Kde to fungujeKdekoli, i v chatuJen 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.

KrokKdoCo se děje
1ZákazníkNapíše: „Kde je moje objednávka 48213?“
2Tvůj systém → APIPoš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.
3Model → tvůj systémNeodpoví 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).
4Tvůj systémZkontroluje žá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.
5Databáze → tvůj systémVrátí: odesláno 4. 11., dopravce PPL, doručení očekáváno 6. 11.
6Tvůj systém → APIPošle modelu celou konverzaci znovu (pamatuješ, model je bezstavový): původní dotaz, žádost o nástroj a nově i výsledek nástroje.
7Model → tvůj systémTeď 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.“
8Tvůj systém → zákazníkZobrazí 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: true zaručí, ž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:

  1. 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á.
  2. Oprávnění odvozuj od přihlášeného uživatele, ne od modelu. Nástroj get_order_status musí 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á.
  3. 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.
  4. 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í.
  5. 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í

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?