10 min čteníJohnny UnarJohnny Unar

Ne shipujte agent chainy SMB zákazníkům

Agentic orchestraci nástrojů to sluší v demu, v produkci je z toho rychle průšvih. Místo toho použijte typed function calls, deterministické proxy vrstvy a explicitní fallbacky.

agenti selhávají tam, kde se fakturuje

Agentic tool chainům v SMB produktech nevěřím. Ne proto, že by LLM byla k ničemu, právě naopak, jsou extrémně užitečné. Jakmile ale ve hře tečou peníze, potřebujete chování, které umíte vysvětlit, přehrát, omezit a supportovat ve dvě ráno, aniž byste četli transcript spekulativního planneru, který se zatoulal přes pět nástrojů, dva z nich retrynul a nakonec vrátil napůl správnou odpověď bez jasného vlastníka chyby.

Většina agent setupů padá na stejných místech. Planner si vymyslí sekvenci, která technicky splní prompt, ale poruší business pravidlo, které nikdo nezakódoval. Retrieval krok timeoutne, model stejně pokračuje a pak sebevědomě sesmolí odpověď ze zastaralého kontextu. Tool jednou za pár set volání vrátí rozbitý JSON, parser to spolkne, aplikace zapíše success a support dostane ticket o tři dny později. Každý problém můžete zalepit zvlášť, a lidi to tak dělají. Za šest týdnů z toho ale máte prompt glue, retry glue, tracing glue, policy glue a obří skrytý state machine, o kterém nikdo nechce přiznat, že existuje.

SMB nepotřebují tenhle bordel. Potřebují „vytáhni položky z faktury“, „navrhni odpověď z těchto schválených faktů“, „zařaď tenhle ticket do jedné fronty“, „vyplň tohle CRM pole, pokud confidence přesáhne 0.9“. To jsou ohraničené operace s reálnými side effecty, a ohraničené operace si zaslouží deterministický software kolem model callu. Efektní agent loop je falešná úspora, protože ušetří začátek implementace a pak vám ten účet vrátí v operations, zátěži supportu, compliance problémech a času stráveném debuggingem.

Ve steezr jsme stavěli AI-heavy interní systémy a dokumentové pipelines pro týmy, které nemají luxus vlastní ML platform squad. V produkci přežívá ten nejméně sexy pattern, a to je dobře: typed function calls z modelu, tenká tool-proxy služba, která vlastní auth a validaci, explicitní state transitions a fallback cesta, kterou člověk pochopí na jedné obrazovce logů.

function calls porazí plannery

Jestli váš model umí structured outputs nebo function calling, začněte tím a držte surface area co nejmenší. Dejte modelu úzké menu akcí s typovanými argumenty, každou akci popište normálním jazykem, vynuťte striktní validaci proti JSON Schema a cokoliv mimo kontrakt rovnou odmítněte. Žádný reflection loop, žádná self-critique fáze, žádný rekurzivní planner, který usoudí, že asi potřebuje sáhnout do Slacku, HubSpotu a billing API jen proto, že se uživatel zeptal vágně.

Jednoduchý příklad, triage na customer supportu. Model dostane text e-mailu, metadata účtu a seznam toolů, dejme tomu tři funkce: classify_ticket, draft_reply, request_human_review. classify_ticket bere enum pro kategorii a omezený float pro confidence. draft_reply bere omezený markdown string plus seznam citovaných source ID. request_human_review bere jeden reason code. Hotovo. Z vágního promptu jste udělali typované rozhraní.

V praxi to znamená schémata třeba takhle:

json
1{
2 "name": "classify_ticket",
3 "strict": true,
4 "parameters": {
5 "type": "object",
6 "additionalProperties": false,
7 "properties": {
8 "category": {
9 "type": "string",
10 "enum": ["billing_dispute", "refund", "bug_report", "sales", "other"]
11 },
12 "confidence": {
13 "type": "number",
14 "minimum": 0,
15 "maximum": 1
16 }
17 },
18 "required": ["category", "confidence"]
19 }
20}

Pak udělá dospělou práci vaše aplikace. Když confidence < 0.86, pošle to do review. Když je stav účtu delinquent, zakáže sliby refundu. Když je zákazník v EU, před generováním draftu zaredukuje citlivá pole. Nic z toho nepatří do planner promptu. Nic z toho nemá záviset na tom, jestli se model zrovna probudil v poetické náladě.

Lidi si stěžují, že typed calls působí svazujícím dojmem. Přesně tak. Omezení je to, co z LLM feature udělá produktové chování, za které si můžete říct o peníze.

postavte si tool proxy

Přímý přístup modelu k toolům je místo, kde se spousta AI produktů potichu stane neudržitelnou. Model nemá vědět, jak mluvit se Stripe, Jira, Salesforce, vaší Postgres read replikou ani s náhodným SOAP endpointem, který ještě pořád používá nějaký distributor. Dejte doprostřed deterministickou proxy vrstvu a udělejte ji co nejnudnější.

Ta proxy má mít na starost pět věcí. Authentication, authorization, validaci vstupu, rate limiting a normalizaci upstream chyb do malého interního slovníku. Jeden endpoint pro každou tool operaci, silná schémata na requestu i response, idempotency keys pro volání se side effecty a logy, ve kterých uvidíte request_id, customer_id, model_decision, tool_name, validated_args, upstream_status a final_outcome. Jakmile tohle máte, audit přestane být interpretační umění.

Go service se na to hodí dobře, protože ji snadno udržíte striktní a rychlou. HTTP handler s generovanou validací proti JSON Schema, context deadline třeba 1500 ms pro read operace a tvrdý allowlist outbound targetů odstraní půlku nesmyslů, které lidi házejí na modely. Nástřel:

go
1type CreateRefundRequest struct {
2 InvoiceID string `json:"invoice_id" validate:"required,uuid4"`
3 Amount float64 `json:"amount" validate:"gt=0"`
4 Reason string `json:"reason" validate:"oneof=duplicate chargeback goodwill"`
5}
6
7func (h *Handler) CreateRefund(w http.ResponseWriter, r *http.Request) {
8 ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
9 defer cancel()
10
11 var req CreateRefundRequest
12 if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
13 writeErr(w, 400, "invalid_json")
14 return
15 }
16 if err := h.validate.Struct(req); err != nil {
17 writeErr(w, 422, "schema_validation_failed")
18 return
19 }
20 if !h.policy.CanRefund(r.Context(), req.InvoiceID) {
21 writeErr(w, 403, "policy_denied")
22 return
23 }
24
25 res, err := h.billing.CreateRefund(ctx, req)
26 if err != nil {
27 writeMappedUpstreamErr(w, err)
28 return
29 }
30 writeJSON(w, 200, res)
31}

Z téhle proxy se stane vaše control plane. Můžete přidat rate capy po zákaznících, zmrazit nebezpečné tooly pro jeden tenant, shadowovat nové chování a přesně zaznamenat, který validátor odmítl který payload. Jestli jste někdy museli vysvětlovat špatný side effect majiteli SMB firmy, který osobně zná všech svých dvanáct zaměstnanců, víte, jak moc na tom záleží.

nejdřív kontrakty, pak prompty

Na pořadí záleží. Začněte kontraktem a teprve potom pište prompt tak, aby ten kontrakt plnil, ne obráceně. Týmy často prototypují s obřím system promptem, sledují, že to tak nějak funguje, a pak na něj vrství další instrukce, až se z promptu stane nezdokumentovaný policy engine. Takhle vzniká křehké chování a nulová jistota při upgradech.

Kontrakty na úrovni schémat vás donutí udělat užitečná rozhodnutí hned na začátku. Která pole jsou optional. Které enumy odpovídají reálným business stavům. Jaká maximální délka je přijatelná pro volný text. Jestli jsou citace povinné. Jaký confidence threshold pouští věci do automatu. Jakmile je tohle explicitní, výměna modelu není tak dramatická, protože většinu turbulence pohltí kontrakt. Můžete přejít z jednoho providera na druhého nebo mezi model families a logika aplikace pořád bere stejný validovaný shape.

Pro Python služby je Pydantic pořád jasná volba. Pro TypeScript v Next.js appce funguje dobře Zod, a když to provider chce, vyexportujete z něj JSON Schema. Jednoduchý příklad v TypeScriptu:

ts
1import { z } from "zod";
2
3export const DraftReply = z.object({
4 tone: z.enum(["neutral", "warm", "firm"]),
5 body_md: z.string().min(40).max(4000),
6 citations: z.array(z.string().uuid()).min(1),
7 safe_to_send: z.boolean(),
8});
9
10export type DraftReply = z.infer<typeof DraftReply>;

Pak fail closed:

ts
1const parsed = DraftReply.safeParse(modelOutput);
2if (!parsed.success) {
3 logger.warn({ err: parsed.error }, "draft_reply_schema_failed");
4 return { action: "human_review", reason: "invalid_model_output" };
5}

Tenhle styl navíc umožní regression testy. Uložíte reálné vstupy, očekávané schema outputs a policy decisions. Pustíte je v CI proti změnám modelu. Když se kvalita výstupu pohne, uvidíte to dřív než zákazník. Čistě promptové systémy se k téhle disciplíně skoro nikdy nedostanou, protože proti čemu vlastně testovat, když nemáte stabilní rozhraní.

fallbacky jsou součást produktu

Fallback není smutná větev. Je to základní produktové chování a týmy, které ho řeší až nakonec, končí s AI features, které působí náhodně. Každá operace má mít před releasem definovaný deterministický fallback. Když je confidence extrakce nízká, zařaďte to do manuálního review. Když je upstream CRM rate limited, uložte návrh a dejte uživateli vědět, že sync čeká. Když generovaná odpověď nemá citace, neposílejte ji. Když selže validace toolu, vraťte recoverable stav, kterému UI rozumí.

Všimněte si toho patternu: fallback je explicitní a konečný. Ne „zkus jiný chain“ nebo „řekni modelu, ať přemýšlí víc“. Retry model callu může dávat smysl u dočasných transportních chyb. Retry samotné sémantiky jen proto, že model vrátil kaši, bývá spíš sebeklam navěšený na další tokeny.

Potřebujete taky user-facing stavy, které se mapují jedna ku jedné na backend stavy. ready, needs_review, deferred, blocked_by_policy, upstream_unavailable. Skutečné názvy. Support je přečte. Product kolem nich navrhne UX. Analytics je spočítají. Srovnejte si to s volným agent tracem, kde model rozhodl, že krok 7 je volitelný a krok 8 popřel krok 3.

Jeden praktický trik: uložte model input bundle, validované tool argumenty, snapshot policy a zvolený fallback do jednoho immutable event řádku. PostgreSQL to pro většinu SMB objemů zvládne úplně v pohodě. Přidejte JSONB sloupec na raw response od providera, pokud potřebujete forenzní data, při vyšších objemech partitioning, a máte replayable execution bez toho, abyste kupovali drahý observability příběh, který stejně skoro nevyužijete.

Predikovatelnost vyhrává dvakrát, jednou pro engineering, podruhé pro důvěru zákazníka. „Zařazeno do review“ zákazníci odpustí. Tiché špatné akce ne.

stack, který bych opravdu shipnul

Pro greenfield SMB SaaS feature v roce 2026 bych architekturu držel agresivně malou. Next.js pro app surface, pokud v něm už jste, Python nebo Go service pro AI orchestraci, když mají workflows aspoň trochu složitost, PostgreSQL na eventy a auditní stav, Redis jen pokud opravdu potřebujete krátké fronty nebo rate countery, a jednu abstrakci nad providerem, která umí structured output a function calling. U interních backoffice nástrojů bych klidně nechal ve hře HTMX, když je důležitější rychlost než frontendové divadlo. Tohle fakt nemusí být katedrála.

Request flow je přímočaré. UI pošle action request. Backend sestaví ohraničený context packet, zákaznická data už přefiltrovaná policy vrstvou. Model dostane zadání na jedno typované rozhodnutí nebo jeden typovaný content object. Výstup projde validací proti schématu. Když výstup požaduje tool, jde request přes proxy. Proxy aplikuje policy, auth, rate capy, idempotenci a mapování upstream chyb. Finální stav se uloží s dostatkem metadat na replay. UI renderuje konečný stav, ne vibe.

Logoval bych i ty ošklivé věci napřímo. Reálné status codes, reálné provider chyby, počty tokenů, latency percentily po toolech, schema failure rates podle verze modelu. Chci dashboardy, které po rolloutu modelu řeknou draft_reply_schema_failed=1.7%, ne abstraktní nesmysly typu „agent quality dipped“. Chci alerty na spike v policy_denied, protože často odhalí prompt drift nebo bug v tenant konfiguraci. Konkrétní metriky vynucují konkrétní opravy.

Ještě jeden názor: nenechte se vendory natlačit do jejich plného agent frameworku, pokud nemáte prokázané, že ho opravdu potřebujete. Spousta těch stacků jsou wrappers on wrappers, s tracing formáty, které nikdo nestandardizuje, s execution sémantikou, kterou nikdo neumí srozumitelně vysvětlit, a s dostatkem magie na to, aby incident response bylo utrpení. Obyčejné function calling plus deterministický software kolem vás dostane překvapivě daleko. Pro SMB produkty je to většinou víc než dost.

Johnny Unar

Napsal/a

Johnny Unar

Chcete s námi spolupracovat?

Agentic orchestraci nástrojů to sluší v demu, v produkci je z toho rychle průšvih. Místo toho použijte typed function calls, deterministické proxy vrstvy a explicitní fallbacky.