AI funkce ve Snowflake prakticky

Doprovodný text pro lidi, kteří to SQL skutečně píší.

Jak zaznělo v AISQL není BI s AI — je to data science v hávu SQL: AI funkce vypadají jako SQL, ale přístup, kterou vyžadují, je vypůjčený z data science. Tato příručka popisuje praktické postupy pro stavbu AI analytických pipeline ve Snowflake (nebo jinde) s ohledem na náklady, výkon a spolehlivost.

Jan Šulc
8. července 2026

Většina z toho, co následuje, se vrací ke stejným třem tématům:

Nejdřív měř, potom řež (nebo spíš škáluj). Cena za to, mýlit se ve velkém měřítku u AI funkcí přestává být zanedbatelná.

Nástroj musí odpovídat úkolu. Snowflake pro jakýkoli úkol nabízí na výběr tucet funkcí a několik modelů, a rozdíl v ceně mezi nejlevnější a nejdražší použitelnou variantou bývá dva řády.

Za každou inferenci se platí přesně jednou. Architektonické vzory, které dávaly smysl v době, kdy byl compute levný, nutně neplatí pro AISQL.

Evaluační dataset jako první krok

Jedna věc s vysokou návratností je ručně oštítkovat pár set řádků skutečných dat ještě předtím, než se napíše první volání AISQL funkce. Tím vzniká evaluační dataset jakožto obdoba unit testů pro standartní deterministickou pipeline.

Vybírá se 200–500 řádků, které reprezentují to, jak dataset reálně vypadá. Dataset by měla obsahovat jasné případy, nejasný střed a hraniční případy — sarkasmus, vstupy s více tématy nebo komplexní scénáře — o kterých je známo, že jsou pro byznys kritické. Štítkují se samostatně nebo s doménovým expertem a ukládají se do běžné tabulky ve Snowflake:

CREATE TABLE eval_set_tickets (
    ticket_id        STRING,
    ticket_text      STRING,
    true_category    STRING,
    true_sentiment   STRING,
    notes            STRING  -- why this case is interesting
);

Tato tabulka je základním aktivem AI pipeline. Měla by být verzovaná, zálohovaná a rozšiřovaná pokaždé, když produkční data odhalí nový edge case.

Postup odtud je: spustit AI funkce na evaluační sadě, porovnat se skutečností a prozkoumat chyby. Škálovat na celý dataset až ve chvíli, kdy je na evaluační sadě dosažena byznysová prahová hodnota.

Jeden SELECT na 500 řádcích stojí pár korun. Stejná logika na pěti milionech řádků stojí reálné peníze. Tento rozdíl je hlavní důvod, proč se evaluační dataset staví jako první.

-- Spuštění funkce a porovnání
SELECT
    ticket_id,
    true_category,
    AI_CLASSIFY(ticket_text, ['bug', 'billing', 'feature_request', 'other']):labels[0]::STRING AS predicted_category,
    CASE WHEN true_category = predicted_category THEN 1 ELSE 0 END AS correct
FROM eval_set_tickets;


Přesnost jako spektrum

Dříve, než se bude pokračovat dál, stojí za to zastavit se u toho, co „přesnost“ vlastně znamená — instinkt, který si většina data engineeru nese z tradičního SQL, je totiž zavádějící. V deterministickém SQL je řádek buď správně, nebo špatně — test projde, nebo neprojde. V data science (a AI analytice) to ovšem neplatí. Dvě chyby se stejnou nominální cenou (jeden špatný řádek) mohou mít naprosto odlišný dopad na byznys. Některé chyby jsou jen nepříjemnost, jiné jsou promarněné byznysové příležitosti.

Vezměme klasifikátor, který řadí příchozí support tickety do kategorií Critical, High, Medium, Low. Po spuštění na evaluační sadě o 1 000 řádcích to vypadá skvěle: 87% celková přesnost. To vypadá dost dobře — ale pojďme se podívat na confusion matrix.

Model si dobře poradí s High, Medium i Low. Zvládne i většinu Critical ticketů. Ale ve zvýrazněné buňce je vidět: 23 Critical ticketů skončilo ve frontě Medium.

Po investigaci vyjde najevo, že jde téměř výhradně o tickety spojené s platbami — selhané platby, vyúčtování, problémy s předplatným. Model je bral jako běžné fakturační tickety, protože na povrchu vypadají jako běžné fakturační tickety. Fronta Medium má SLA 72 hodin. Než se k těm ticketům někdo dostane, zákazníka jsme už možná ztratili.

Ostatní chyby v matici jsou většinou šum — High ticket, který skončí v Critical, Low ticket, který skončí v Medium, věci, které člověk přesměruje během pár vteřin. Ale 23 chyb v té jedné buňce jsou reálné peníze odcházející ze dveří.

Model s 87% přesností, který selhává konkrétně u naléhavosti plateb, je horší než model se 78% přesností, který chybuje rovnoměrně napříč celou maticí.

Řešením zřídkakdy je „udělat model přesnějším“. Řešením je přidat byznysovou logiku, kterou model sám nedokáže odvodit. Spor o platbu od self-serve free uživatele může být opravdu Medium. Stejný spor od enterprise účtu za 200 tisíc dolarů ročně je Critical, pokaždé. Text modelu tohle neřekne. Data ano.

Jednoduchá úprava — předání příznaku úrovně zákazníka do promptu, nebo aplikace deterministického pravidla nad výstupem modelu — by zachytila většinu z těch 23 případů:

SELECT
    ticket_id,
    -- Encode the business rule alongside the model
    CASE
        WHEN customer_tier = 'enterprise'
             AND AI_CLASSIFY(ticket_text, ['payment','other']):labels[0]::STRING = 'payment'
            THEN 'Critical'
        ELSE AI_COMPLETE('claude-haiku-4-5',
                'Classify priority as Critical/High/Medium/Low. Return only the classification, nothing else.: ' || ticket_text)
    END AS priority
FROM tickets;

To není žádný chytrý prompt. Je to CASE statement nad AISQL funkcí. Ale je to přesně ten typ věci, na který se snadno zapomíná — model je zdánlivě tak schopný, že přestaneme přemýšlet o deterministických byznysových pravidlech, která můžeme použít.

Confusion matrix poskytuje zásadní realitní check: model nemá žádné vrozené povědomí o konkrétních úrovních zákazníků, produktových liniích kritických pro tržby ani indikátorech naléhavosti, jako jsou opakované support požadavky. Tento doménový kontext dokáže dodat jen byznys sám.

Obecný princip: „je model dost dobrý?“ skoro nikdy není otázka ano/ne. Správná otázka zní: „je model dost dobrý na případech, na kterých záleží, a jsou byznysová pravidla, která model sám neumí odvodit, zakódovaná do promptu?“ Bez matice na ani jednu z nich nelze odpovědět.

Zpracování každého řádku jednou

Tradiční ELT reflex, hlavně s příchodem dbt, je plný reload — truncate, znovu spustit, znovu materializovat každou noc. To je v pořádku, pokud je compute levný. S AI funkcemi se to ale může prodražit. Noční plný reload milionové tabulky přes AI_CLASSIFY přefakturuje stejné inference donekonečna, i když se 95 % řádků vůbec nezmění.

Pravidlo je jednoduché: každý řádek se zpracovává přesně jednou, na stabilních datech, výsledek se ukládá a nikdy se nepočítá znovu. S výstupem AI funkce se zachází stejně, jako by se zacházelo s výstupem drahého externího API — protože přesně to vlastně je.

Několik vzorů to zkonkrétní.

Zpracovávají se jen uzavřené, neměnné záznamy. AI se nespouští na datech, která jsou ještě v pohybu. Otevřené tickety, čekající objednávky, rozpracované dokumenty — ty se ještě změní, a každá změna znamená přepočet. Čeká se, až budou stabilní.

INSERT INTO ticket_ai_enriched
SELECT
    ticket_id,
    AI_CLASSIFY(ticket_text, ['bug','billing','feature','other']) AS category,
    AI_SENTIMENT(ticket_text) AS sentiment
FROM raw_tickets r
WHERE status = 'closed'
  AND closed_at < DATEADD('hour', -24, CURRENT_TIMESTAMP())
  AND NOT EXISTS (
      SELECT 1 FROM ticket_ai_enriched e WHERE e.ticket_id = r.ticket_id
  	);

Klíčová je klauzule NOT EXISTS. Každý řádek je zpracován jednou, ve chvíli, kdy je stabilní. Pipeline škáluje s novými daty, ne s celkovým objemem.

Pro inkrementální zpracování se používají streams a tasks. Pipeline běžící nad streamem nových řádků stojí ve třetím roce stejně jako v prvním týdnu. Pipeline s nočními plnými reloady zdražuje každým dnem, navždy.

Materializace místo opakovaného počítání. Jakmile je jednou zaplaceno za inferenci, výsledek se ukládá. AI_COMPLETE se nikdy nedává do view, na které se dotazují navazující dashboardy — každé volání stojí peníze. Materializuje se do tabulky, refreshuje se podle schedule, dotazuje se na tabulku.

Oddělení AI obohacení od navazující transformace. AI volání se nemíchají do stejného dbt modelu jako zbytek byznysové logiky. Když se navazující logika změní — nový sloupec, přejmenované pole, opravený CASE statement — celý model se přestaví, což znovu spustí AI volání. Rozdělení vypadá takto:

raw_tickets

└─> ticket_ai_enriched     (inkrementální, AI volání zde, drahé)

        └─> ticket_marts   (plný refresh v pořádku, žádná AI volání, levné)

Exploraci stačí vzorek. Když chceme zkusit AI_SUMMARIZE na recenze, spouštíme ho na SAMPLE (1000 ROWS), ne na celé tabulce. Rozdíl v ceně mezi explorací na vzorku a explorací na produkci je rozdíl mezi 0,05 $ a 500 $. Stejný insight tak i tak.

Verzování výstupů. Na obohacených tabulkách se udržuje sloupec prompt_version nebo model_version. Při změně promptu nebo přepnutí modelu lze zpracovat jen inkrement a vědět, co odkud pochází. 

Specializované funkce vs. AI_COMPLETE

Snowflake dává dva způsoby, jak dělat mnohé z těchto úkolů:

  • Specializované funkce — AI_SENTIMENT, AI_CLASSIFY, AI_EXTRACT, AI_TRANSLATE, AI_SUMMARIZE, AI_FILTER. Pevně daný model pod kapotou, plochá sazba za token, žádné rozlišování vstup/výstup, o které by bylo třeba se starat. Optimalizované pro průměrný případ svého úkolu.
  • AI_COMPLETE — plný přístup k LLM. Model i prompt se volí ručně. Maximální flexibilita, guardrails, maximální rozptyl nákladů a jediný způsob, jak zakódovat konkrétní byznysovou logiku.

Pro rutinní, vysokoobjemovou práci, kde záleží na průměrném případu, jsou specializované funkce správnou výchozí volbou. Jsou levnější než volání AI_COMPLETE s prémiovým modelem, snáz se rozpočtují (plochá sazba, žádný rozptyl kvůli výběru modelu) a produkují předvídatelnější tvar výstupu, který se snáz integruje dál.

Specializované funkce ale mají strop. Jsou natrénované na průměrný případ obecného úkolu. Neznají konkrétní byznys.

AI_SENTIMENT kompetentně oklasifikuje „tenhle produkt je hrozný“ jako negativní. Problém nastává u „konečně faktura, která přišla se zpožděním jen tři týdny“ — sarkasmus, který obrací polaritu. Nedokáže vědět, že „ozveme se vám“ od klienta v daném odvětví skoro vždy znamená, že obchod je mrtvý.

AI_CLASSIFY dobře zvládá široké kategorie. Předvídatelně selhává na případech, na kterých nejvíc záleží: na nejednoznačných, na těch, které se rozkládají mezi dvě kategorie, na těch, kde správná odpověď závisí na kontextu, který obsahují data, ale funkce ne.

Přesně tady si AI_COMPLETE na sebe vydělá. Ne proto, že by byl model „chytřejší“ — ale protože prompt umožňuje zakódovat věci, které specializované funkce neznají:

Specializované: levné, rychlé, žádný byznysový kontext

AI_CLASSIFY(ticket_text,
    ['bug_report', 'feature_request', 'help_request',
     'positive_review', 'complaint', 'account_billing']):labels[0]::STRING

Complete: dražší, ale ví, co každá kategorie skutečně znamená

AI_COMPLETE('claude-sonnet-4-5',
    'You are a support ticket classifier. Classify the following ticket into
     exactly one of these categories:

     1. bug_report - Something is broken, crashing, returning errors, or not
        working as expected. The user is reporting a malfunction.

     2. feature_request - The user is asking for new functionality, an
        improvement, or a capability that does not exist yet. No current
        issue, just a wish.

     3. help_request - The user needs guidance on how to do something.
        A how-to question, setup help, or configuration assistance. They
        are not reporting a problem with the product itself.

     4. positive_review - The user is expressing satisfaction, praise, or
        a positive experience. No issue or request, just good feedback.

     5. complaint - The user is frustrated or unhappy about service quality,
        performance, pricing, or broken promises. They are venting
        dissatisfaction, not reporting a specific technical bug.

     6. account_billing - The user is asking about invoices, licenses,
        pricing plans, payment methods, billing contacts, contracts,
        upgrades, downgrades, or any financial/account administration topic.
        If the ticket mentions money, invoices, subscriptions, user
        licenses, or plan changes, it belongs here.

     Return only the category name, nothing else.

     Ticket: ' || ticket_text)

Obě volání používají stejných šest kategorií. Na povrchu to vypadá, že by měly dát stejný výsledek. Nedávají.

AI_CLASSIFY vidí textové štítky a odvozuje jejich význam ze samotných slov — bug_report je „něco o chybách“, complaint je „něco negativního“. To stačí na jasné případy. Ale kam patří frustrovaný uživatel, který hlásí rozbitou funkci — do bug_report, nebo do complaint? Kam patří fakturační dotaz zabalený do naštvaného tónu — do complaint, nebo do account_billing? Specializovaná funkce nemá způsob, jak správnou odpověď znát.

Promptovaná verze definuje každou kategorii v byznysových pojmech. Modelu se říká, že complaint je venting bez konkrétní technické chyby — takže frustrovaný bug report jde do bug_report, ne do complaint. Modelu se říká, že cokoliv zmiňující faktury, předplatné nebo licence patří do account_billing bez ohledu na tón — takže naštvaný fakturační dotaz nesklouzne do complaint. Tato hraniční pravidla jsou pro AI_CLASSIFY neviditelná. Jsou tím jediným smyslem AI_COMPLETE.

Prompt engineering je nová byznys logika.

Tento prompt je kus byznysové logiky. Každá věta v něm je rozhodnutí o tom, jak má byznys tickety kategorizovat. „Pokud jde o peníze, faktury, předplatné, uživatelské licence nebo změny plánu, patří to sem“ — to je pravidlo. „Ventilují nespokojenost, nehlásí konkrétní technickou chybu“ — to je rozhodčí pravidlo pro nejasný střed. Změna jedné z těch vět mění navazující směrování. Když se jedna zapomene zakódovat, tickety končí ve špatné frontě.

To znamená, že prompt si zaslouží stejné zacházení jako komplexní CASE statement v dbt modelu: verzování, code review, dokumentaci, testování proti evaluační sadě před nasazením. Prompty patří do dbt repozitáře, ne do ad-hoc SQL souborů. Se změnami v nich se zachází jako se změnami byznysové logiky — protože to jsou.

AI nevyřeší všechny problémy, a spoléhat se na ni bez rozmyslu se nevyplácí. Kolem AI se používá tolik deterministické logiky, kolik jen jde. CASE statement, příznak úrovně zákazníka, regex na předmětu ticketu, vyhledávací tabulka známých názvů produktů — to všechno je levnější, rychlejší a přesnější než nechat LLM, aby si to sám vydedukoval. AI je správný nástroj na to, co umí jen AI; všechno ostatní má zůstat v SQL.

Výběr modelu — tady se vyhrává, nebo prohrává budget

Při použití AI_COMPLETE je volba modelu strategické architektonické rozhodnutí, ne stylistická preference. Rozdíly v ceně mezi modely pro identický úkol dosahují 30–60×. Na milionovém workloadu je to rozdíl mezi 300 a 15 000 dolary za identický výstup.

Defaultní volba — sáhnout po nejschopnějším modelu a považovat to za bezpečnou variantu — tady neplatí. Správně je nejlevnější model, který by úkol pravděpodobně zvládl, otestovaný proti evaluačnímu datasetu.

Kde skoro vždy stačí malý model:

  • Klasifikace do malé, dobře definované sady labelů
  • Analýza sentimentu (pozitivní / negativní / neutrální)
  • Extrakce entit s jasným schématem
  • Překlad mezi hlavními jazyky
  • Sumarizace na pevnou délku u známých typů obsahu
  • Booleovské filtrování („je tenhle email stížnost?“)

Kde si větší model začíná zasluhovat svou cenu:

  • Uvažování nad dlouhým kontextem (vytažení klauzule z 50stránkové smlouvy a uvažování o ní)
  • Doménový jazyk vyžadující skutečné porozumění — právo, medicína, technické specifikace
  • Vícekrokové úkoly, kde se chyby kumulují
  • Výstupy, které čtou lidé a které reprezentují značku
  • Případy, kde je cena za omyl vysoká v poměru k ceně inference

Osvědčený postup: Každý kandidátský model se spustí proti evaluační sadě jednou, predikce se uloží a analýza přesnosti se provádí z tohoto uloženého datasetu. Tento postup se řídí základním principem, kterým se řídí produkční pipeline: za každou inferenci se platí přesně jednou. Díky cachování predikcí lze analýzu přesnosti rozkrájet mnoha způsoby — podle kategorie, délky ticketu nebo zdroje — aniž by se znovu přefakturoval jediný token.

Navíc, pokud je potřeba znovu otestovat po aktualizaci štítků nebo přidání řádků do evaluační sady, stačí přehodnotit jen dotčené záznamy, čímž se vyhne zbytečným inferenčním voláním a minimalizují se náklady.

Krok 1: každý model se spustí jednou a predikce se uloží do cache

INSERT INTO eval_predictions
SELECT
    ticket_id,
    'llama3.1-8b' AS model,
    AI_COMPLETE('llama3.1-8b',
        'Classify as bug/billing/feature/other. Return only the classification, nothing else.: ' || ticket_text) AS predicted_category,
    CURRENT_TIMESTAMP() AS scored_at
FROM eval_set_tickets;

INSERT INTO eval_predictions
SELECT
    ticket_id,
    'claude-haiku-4-5' AS model,
    AI_COMPLETE('claude-haiku-4-5',
        'Classify as bug/billing/feature/other. Return only the classification, nothing else.: ' || ticket_text) AS predicted_category,
    CURRENT_TIMESTAMP() AS scored_at
FROM eval_set_tickets;

Krok 2: přesnost se spočítá z cache (levné, opakovatelné, bez AI)

SELECT
    p.model,
    AVG(CASE WHEN p.predicted_category = e.true_category THEN 1 ELSE 0 END) AS accuracy
FROM eval_predictions p
JOIN eval_set_tickets e USING (ticket_id)
GROUP BY p.model;

Pokud levný model splňuje byznysovou prahovou hodnotu, může se nasadit do produkce.

Tokeny se sčítají — návrh pro stručné výstupy

Ještě jedna věc, kterou stojí za to vědět: výstupní tokeny se obvykle účtují za několikanásobek sazby vstupních tokenů. Podle Snowflake Service Consumption Table pro nejpoužívanější modely (kredity na milion tokenů, stav k květnu 2026):

ModelVstupVýstupPoměr
claude-sonnet-4-51,658,255,0×
openai-gpt-5 (long context)5,5024,754,5×
snowflake-llama-3.3-70b0,290,291,0×

Praktický důsledek: délka výstupu je nákladová páka, kterou lze přímo řídit. Sumarizace zákaznických recenzí na claude-sonnet-4-5, kde typická recenze má ~200 vstupních tokenů:

  • Jednovětá sumarizace (~30 výstupních tokenů): ~580 mikrokreditů na recenzi
  • Sumarizace v odstavci (~150 výstupních tokenů): ~1 570 mikrokreditů na recenzi

Stejný model, stejný vstup, 2,7× rozdíl v ceně jen kvůli délce výstupu. Napříč milionem recenzí je to rozdíl mezi zhruba 500 a 1 500 kredity — a delší sumarizace zřídkakdy přináší 2,7× větší užitek.

Prompty se navrhují tak, aby produkovaly jen to, co je potřeba.

–Nehospodárné: otevřený výstup, žádné omezení délky

AI_COMPLETE('claude-sonnet-4-5',
    'Summarize this customer review.: ' || review_text)

Omezené: specifikuje délku, formát a co extrahovat

AI_COMPLETE('claude-sonnet-4-5',
    'In max 20 words, summarize the main complaint
     or praise in this review. Return only the sentence.
     Review: ' || review_text)

Stejný model, stejný úkol. Druhý prompt produkuje kratší, přesněji ohraničený výstup, což výrazně sníží cenu na řádek. Na milionu recenzí to mohou být stovky ušetřených kreditů — a jednovětá sumarizace bývá dál v pipeline užitečnější než rozvláčný odstavec.

Na co myslet při návrhu architektury

Neexistuje jeden správný tvar AI analytické pipeline — závisí na objemu, nárocích na latenci, toleranci k nákladům a tom, kolik byznysové logiky je potřeba zakódovat. Ale několik designových rozhodnutí se opakuje dostatečně často na to, aby stálo za zvážení u jakékoli produkční pipeline:

  • Vrstvený přístup obvykle poráží jednovrstvý. Levná cesta, která zvládne snadnou většinu, drahá cesta pro hraniční případy a lidská fronta pro to, co nezvládne ani jedna z nich. Jaký podíl objemu půjde přes kterou vrstvu, se rozhoduje než se začne stavět — na základě cílů pro cenu a kvalitu z evaluační sady.
  • Směrování podle jistoty se vyplatí navrhnout hned od začátku. Ať už jde o číselnou prahovou hodnotu, nebo explicitní štítky unknown/mixed, schopnost poslat případy s nízkou jistotou jinam než ty jisté je to, co dělá vrstvený přístup funkčním. Dodělávat to dodatečně je bolestivé.
  • Feedback se snadno vynechává a draze doplňuje později. Když lidský reviewer opraví model, je to nový cenný input. Zachycuje se a vrací zpátky do evaluační sady. Evaluační dataset je živý artefakt, ne jednorázový výstup.
  • Plánuje se revalidace, ne jen nasazení. Skutečný tichý drift modelu je ve Snowflake vzácný — verzované modely se chovají konzistentně — ale důvody pro nové spuštění evaluační sady jsou běžné. Vstupní data se posouvají (nová produktová řada, nový segment zákazníků). Byznysové definice se mění (kategorie je předefinována, přibude nová úroveň priority). Model, který se používá, je vyřazen a je potřeba přejít na jiný. Evaluační dataset se bere jako věc, na kterou se sahá, kdykoli nastane cokoliv z výše uvedeného — ne jako naplánovaný monitoring běžící na CRONu. Revaliduje se dle událostí, nejen dle času.
  • Na vlastnictví záleží víc než na architektuře. Ať pipeline vypadá jakkoli, někdo musí vlastnit evaluační sadu, prompt, volbu modelu a revalidaci — jmenovitě, ne na úrovni týmu. AI pipeline selhávají tiše, a tichá selhání potřebují člověka, ne proces.

Tvar se bude lišit. Přístup je stejný.

Příslib AI v SQL je reálný. Snowflake opravdu zmenšuje propast mezi „máme nápad“ a „běží to v produkci“. Ale přístup, která dělá rozdíl mezi demem a systémem přinášejícím byznysovou hodnotu, pořád vypadá jako data science — evaluační sady, inspekce chyb, volba modelu s ohledem na náklady, deterministická logika tam, kam patří. Nástroje usnadnily začátek. Řemeslo je v tom, umět je využít správně.

Jan Šulc


Business analytik ve společnosti Revolt BI se zkušenostmi se Snowflake a moderními datovými platformami. 



VYZKOUŠEJTE AI FUNKCE SNOWFLAKE PŘÍMO NA VAŠICH DATECH

Rezervujte si bezplatnou 30 minutovou konzultaci. Vybereme jeden use case z vašich dat a ukážeme vám, co to bude stát v kreditech.

Přečtěte si některý z našich dalších článků