Pokročilý prompt engineering v roce 2026: Od Chain-of-Thought po automatickou optimalizaci promptů

Kompletní průvodce pokročilým prompt engineeringem v roce 2026. Chain-of-thought, strukturované výstupy, ReAct, Tree of Thoughts, automatická optimalizace s DSPy a evaluace pomocí LLM-as-a-Judge — vše s praktickými příklady v Pythonu.

Proč je prompt engineering v roce 2026 důležitější než kdy dřív

Možná jste slyšeli tvrzení, že prompt engineering je „mrtvý". Že moderní modely jsou tak chytré, že stačí napsat, co chcete, a ony to prostě udělají. Tohle tvrzení je nebezpečně zavádějící — a upřímně, trochu mě štve, jak často se opakuje.

Ano, modely jako GPT-4o, Claude Opus 4.6 nebo Gemini 2.5 Pro jsou výrazně schopnější než jejich předchůdci. Ale právě proto, že jsou schopnější, je prostor pro sofistikovaný prompt engineering větší než kdy dřív. Lepší model neznamená, že na kvalitě zadání nezáleží — spíš naopak.

Představte si to takhle: prompt engineering u GPT-3 byl jako učit psa sedět. U moderních modelů je to jako koučovat zkušeného profesionála — dáte mu špatné zadání a dostanete průměrný výsledek, dáte mu skvělé zadání a výsledek vás ohromí. Ten rozdíl je fakt propastný. Sám jsem to zažil, když jsem přepsal jeden interní prompt z tří vět na strukturovaný systémový prompt — kvalita výstupů se zvedla tak dramaticky, že kolegové nevěřili, že jde o stejný model.

V tomhle článku projdeme pokročilé techniky prompt engineeringu, které v roce 2026 skutečně fungují — od chain-of-thought reasoning přes strukturované výstupy, ReAct pattern, Tree of Thoughts až po automatickou optimalizaci s DSPy. Každou techniku si ukážeme na praktických příkladech s kódem. Žádná teorie bez praxe.

Chain-of-Thought: Základ pokročilého reasoning

Proč modely potřebují „myslet nahlas"

Chain-of-Thought (CoT) prompting je technika, která vede jazykový model k tomu, aby explicitně vyložil svůj myšlenkový postup krok za krokem, než dospěje ke konečné odpovědi. Zní to jednoduše — a vlastně to jednoduché je. Ale dopady jsou dramatické. U komplexních úloh jako matematické problémy, logické úlohy nebo vícekrokové analýzy může CoT zvýšit přesnost o desítky procent.

Proč to funguje? Jazykové modely generují tokeny sekvenčně. Každý vygenerovaný token ovlivňuje pravděpodobnost dalšího. Když model „přeskočí" přímo na odpověď, nemá v kontextu mezikroky, které by mu pomohly navigovat k správnému závěru. Když ho ale vedeme k tomu, aby nejdřív rozepsal svůj postup, každý mezikrok funguje jako taková „nápověda" pro následující generování. Je to trochu jako když si sami píšete poznámky při řešení složitějšího problému — taky vám to pomáhá udržet nit.

Zero-shot CoT

Nejjednodušší forma chain-of-thought — stačí přidat instrukci „Přemýšlej krok za krokem" (nebo anglicky „Let's think step by step"). Překvapivě efektivní, zvlášť pro matematické a logické úlohy. Občas až podezřele efektivní na to, jak málo práce to dá.

import openai

client = openai.OpenAI()

# BEZ Chain-of-Thought — model často chybuje
response_naive = client.chat.completions.create(
    model="gpt-4o",
    messages=[{
        "role": "user",
        "content": "V obchodě je 23 jablek. Přijde zákazník a koupí 5. "
                   "Pak dodavatel přiveze dvojnásobek toho, co zbylo. "
                   "Kolik jablek je nyní v obchodě?"
    }]
)

# S Chain-of-Thought — výrazně vyšší přesnost
response_cot = client.chat.completions.create(
    model="gpt-4o",
    messages=[{
        "role": "user",
        "content": "V obchodě je 23 jablek. Přijde zákazník a koupí 5. "
                   "Pak dodavatel přiveze dvojnásobek toho, co zbylo. "
                   "Kolik jablek je nyní v obchodě? "
                   "Přemýšlej krok za krokem."
    }]
)

Few-shot CoT

Ještě efektivnější varianta. Poskytnete modelu příklad úlohy i s rozepsaným řešením a model pak napodobí stejný styl uvažování pro nový problém. V podstatě mu ukazujete, jak „přemýšlet" — a on to překvapivě dobře pochopí.

messages = [
    {"role": "system", "content": "Jsi matematický asistent. Vždy ukazuj postup řešení."},
    {"role": "user", "content": "Petr má 15 kuliček. Dá třetinu Janě a čtvrtinu zbytku Markovi. Kolik kuliček mu zůstane?"},
    {"role": "assistant", "content": """Pojďme to vyřešit krok za krokem:

1. Petr začíná s 15 kuličkami.
2. Dá třetinu Janě: 15 / 3 = 5 kuliček pro Janu.
3. Petrovi zbývá: 15 - 5 = 10 kuliček.
4. Z těchto 10 dá čtvrtinu Markovi: 10 / 4 = 2,5 → zaokrouhlíme na 2 kuličky (celé kuličky).
5. Petrovi zůstane: 10 - 2 = 8 kuliček.

Odpověď: Petrovi zůstane 8 kuliček."""},
    {"role": "user", "content": "V knihovně je 120 knih. Studenti si půjčí 40 %. "
                                "Z vrácených knih je 25 % poškozených a musí se vyřadit. "
                                "Kolik nepoškozených knih zbyde v knihovně?"}
]

response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages
)

Few-shot CoT je zvlášť silný v situacích, kde potřebujete specifický formát uvažování — třeba u právních analýz, diagnostických postupů nebo finanční kalkulace. Osobně ho používám nejčastěji právě u finančních věcí, kde jeden špatný krok v úvaze může celý výsledek poslat úplně jinam.

Strukturované výstupy: Od volného textu k spolehlivým datům

Proč na strukturovaných výstupech záleží

V produkčních aplikacích je volný text nepřítel. To je tvrdé tvrzení, ale stojím si za ním.

Potřebujete data, se kterými může váš kód dál pracovat — JSON, XML nebo jiné parsovatelné formáty. V roce 2026 nabízejí všechny hlavní platformy nativní podporu strukturovaných výstupů: OpenAI má Structured Outputs s JSON Schema, Anthropic používá tool-based přístup pro Claude a Google implementoval controlled generation v Gemini.

Klíčová výhoda nativních strukturovaných výstupů oproti prosté instrukci „vrať JSON" je, že inference engine zaručuje validní výstup. Během generování tokenů se maskují tokeny, které by porušily definované schéma — pravděpodobnost nevalidních tokenů se nastaví na nulu. Dostanete vždy 100% validní JSON odpovídající vašemu schématu. Žádné parsovací chyby v půl třetí ráno, žádné padající pipeline. Krása.

OpenAI Structured Outputs s Pydantic

from pydantic import BaseModel
from openai import OpenAI

client = OpenAI()

class ProduktAnalyza(BaseModel):
    nazev_produktu: str
    sentiment: str  # "pozitivni", "negativni", "neutralni"
    skore_sentimentu: float  # 0.0 - 1.0
    klicove_body: list[str]
    doporuceni: str

class AnalyzaRecenzi(BaseModel):
    produkty: list[ProduktAnalyza]
    celkove_shruti: str

response = client.beta.chat.completions.parse(
    model="gpt-4o-2025-08-06",
    messages=[
        {"role": "system", "content": "Analyzuj recenze produktů a vrať strukturovanou analýzu."},
        {"role": "user", "content": """
            Recenze 1: Sluchátka XYZ - Skvělý zvuk, ale po 3 měsících se začal
            lámat hlavový most. Za tu cenu zklamání.

            Recenze 2: Klávesnice ABC - Absolutně nejlepší klávesnice, co jsem měl.
            Mechanické spínače jsou božské, build quality perfektní.
        """}
    ],
    response_format=AnalyzaRecenzi
)

analyza = response.choices[0].message.parsed
for produkt in analyza.produkty:
    print(f"{produkt.nazev_produktu}: {produkt.sentiment} ({produkt.skore_sentimentu})")

Claude: Strukturované výstupy přes tool use

Anthropic zvolil odlišný, ale docela elegantní přístup — strukturované výstupy realizuje přes mechanismus nástrojů (tools). Definujete JSON schéma jako „nástroj" a model ho spolehlivě vyplní. Na první pohled to vypadá jako hack, ale ve skutečnosti to funguje skvěle a dává to smysl, když se nad tím zamyslíte.

import anthropic

client = anthropic.Anthropic()

# Definice schématu jako tool
tools = [{
    "name": "analyzuj_clanek",
    "description": "Analyzuje novinový článek a extrahuje klíčové informace",
    "input_schema": {
        "type": "object",
        "properties": {
            "titulek": {"type": "string", "description": "Hlavní téma článku"},
            "kategorie": {
                "type": "string",
                "enum": ["politika", "ekonomika", "technologie", "sport", "kultura"]
            },
            "sentiment": {
                "type": "string",
                "enum": ["pozitivni", "negativni", "neutralni"]
            },
            "klicova_slova": {
                "type": "array",
                "items": {"type": "string"},
                "maxItems": 5
            },
            "shruti": {
                "type": "string",
                "description": "Shrnutí článku v 2-3 větách"
            }
        },
        "required": ["titulek", "kategorie", "sentiment", "klicova_slova", "shruti"]
    }
}]

message = client.messages.create(
    model="claude-opus-4-6",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "tool", "name": "analyzuj_clanek"},
    messages=[{
        "role": "user",
        "content": "Analyzuj tento článek: České firmy investují rekordní částky "
                   "do AI automatizace. Podle průzkumu Hospodářské komory 68 % "
                   "středních podniků plánuje nasadit AI agenty do konce roku 2026."
    }]
)

# Výsledek je garantovaně validní JSON
vysledek = message.content[0].input
print(vysledek)

Kdy použít strukturované výstupy

Strukturované výstupy jsou nezbytné vždy, když výstup LLM konzumuje jiný systém — API endpoint, databáze, další krok v pipeline nebo frontend aplikace. V praxi to zahrnuje: extrakci entit z textu, klasifikaci dokumentů, generování strukturovaných reportů, parsování nestrukturovaných dat a v podstatě jakýkoli krok v automatizovaném workflow.

Naopak, pro konverzační AI, kreativní psaní nebo generování volného textu pro lidského čtenáře jsou strukturované výstupy zbytečná režie. Nemusíte je cpát všude.

ReAct pattern: Když model potřebuje jednat

Reasoning + Acting = ReAct

ReAct je prompt engineering vzor, který kombinuje uvažování (Reasoning) a jednání (Acting) v jednom cyklu. Model střídá fáze přemýšlení a akcí — nejdřív si promyslí, co potřebuje zjistit nebo udělat, pak provede akci (zavolá nástroj, vyhledá data), zpracuje výsledek a rozhodne se o dalším kroku.

Tohle je fundament, na kterém stojí moderní AI agenti. Pokud jste četli náš předchozí článek o multi-agentních systémech, ReAct je v podstatě ta základní smyčka, kterou každý jednotlivý agent interně vykonává. Bez téhle myšlenky by agenti byli jen hloupé skripty s LLM uvnitř.

# ReAct prompt šablona
REACT_SYSTEM_PROMPT = """Jsi výzkumný asistent s přístupem k následujícím nástrojům:

1. web_search(query) - Vyhledá informace na internetu
2. calculator(expression) - Vypočítá matematický výraz
3. database_query(sql) - Spustí SQL dotaz nad firemní databází

Pro každou otázku postupuj v cyklu Myšlenka → Akce → Pozorování:

Myšlenka: [Co potřebuji zjistit? Jaký nástroj použiji a proč?]
Akce: [název_nástroje(parametry)]
Pozorování: [Výsledek akce]
... (opakuj dokud nemáš dostatek informací)
Myšlenka: [Mám dostatek informací pro odpověď]
Odpověď: [Konečná odpověď]

Vždy nejdřív přemýšlej, než jednáš. Nikdy nehádej — pokud si nejsi jistý, použij nástroj."""

# Implementace ReAct smyčky v Pythonu
import json

def react_loop(user_query: str, max_steps: int = 5) -> str:
    messages = [
        {"role": "system", "content": REACT_SYSTEM_PROMPT},
        {"role": "user", "content": user_query}
    ]

    available_tools = {
        "web_search": web_search,
        "calculator": calculator,
        "database_query": database_query
    }

    for step in range(max_steps):
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=[{
                "type": "function",
                "function": {
                    "name": name,
                    "description": func.__doc__,
                    "parameters": get_schema(func)
                }
            } for name, func in available_tools.items()]
        )

        msg = response.choices[0].message
        messages.append(msg)

        # Pokud model nevolá nástroj, máme konečnou odpověď
        if not msg.tool_calls:
            return msg.content

        # Zpracování volání nástrojů
        for tool_call in msg.tool_calls:
            func = available_tools[tool_call.function.name]
            args = json.loads(tool_call.function.arguments)
            result = func(**args)

            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": str(result)
            })

    return "Dosažen maximální počet kroků bez konečné odpovědi."

ReAct vs. čistý CoT

Kdy zvolit ReAct a kdy stačí chain-of-thought? Pravidlo je vlastně docela jednoduché: pokud model potřebuje externí informace nebo má provádět akce, použijte ReAct. Pokud jde o čisté uvažování nad daty, která už má v kontextu, stačí CoT.

V praxi se tyhle techniky často kombinují — ReAct smyčka, kde každý krok „Myšlenka" interně používá chain-of-thought reasoning. Jedno nevylučuje druhé, právě naopak.

Tree of Thoughts: Stromové prohledávání řešení

Od lineárního řetězce k větvení

Chain-of-Thought generuje jeden lineární řetězec myšlenek. Ale co když první úvaha vede špatným směrem? Model nemá jak se vrátit a zkusit jinou cestu. A to je problém.

Tree of Thoughts (ToT) tento problém řeší tím, že generuje více alternativních „myšlenek" v každém kroku, vyhodnotí jejich kvalitu a pokračuje po nejslibnějších větvích. Představte si to jako šachistu, který neuvažuje jen o jednom tahu, ale vyhodnocuje několik variant do hloubky a pak zvolí tu nejlepší. ToT kombinuje schopnost LLM generovat a hodnotit myšlenky s prohledávacími algoritmy (BFS, DFS) pro systematickou exploraci řešení.

from typing import List, Tuple

def tree_of_thoughts(
    problem: str,
    breadth: int = 3,
    depth: int = 3,
    eval_threshold: float = 0.6
) -> str:
    """
    Implementace Tree of Thoughts s BFS prohledáváním.

    Args:
        problem: Popis problému k vyřešení
        breadth: Počet myšlenek generovaných v každém kroku
        depth: Maximální hloubka stromu
        eval_threshold: Minimální skóre pro pokračování větve
    """

    # Kořen stromu — výchozí stav
    current_thoughts = [("", 1.0)]  # (myšlenka, skóre)

    for step in range(depth):
        candidates: List[Tuple[str, float]] = []

        for thought_so_far, _ in current_thoughts:
            # Generování nových myšlenek
            new_thoughts = generate_thoughts(
                problem, thought_so_far, n=breadth
            )

            # Hodnocení každé myšlenky
            for thought in new_thoughts:
                score = evaluate_thought(
                    problem, thought_so_far + "\n" + thought
                )
                if score >= eval_threshold:
                    candidates.append((
                        thought_so_far + "\n" + thought, score
                    ))

        # Vybereme nejlepší kandidáty pro další kolo
        candidates.sort(key=lambda x: x[1], reverse=True)
        current_thoughts = candidates[:breadth]

        if not current_thoughts:
            break

    # Vrátíme nejlepší řešení
    best_thought = max(current_thoughts, key=lambda x: x[1])
    return generate_final_answer(problem, best_thought[0])


def generate_thoughts(problem: str, context: str, n: int = 3) -> List[str]:
    """Generuje n různých myšlenek/kroků pro daný problém."""
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{
            "role": "user",
            "content": f"""Problém: {problem}

Dosavadní úvahy: {context if context else "Žádné — začínáme od nuly."}

Vygeneruj {n} různých možných dalších kroků úvahy.
Každý krok by měl být odlišný přístup k problému.
Vrať je jako JSON pole řetězců."""
        }],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)["thoughts"]


def evaluate_thought(problem: str, thought: str) -> float:
    """Hodnotí kvalitu myšlenkového postupu na škále 0-1."""
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{
            "role": "user",
            "content": f"""Problém: {problem}

Myšlenkový postup: {thought}

Ohodnoť tento myšlenkový postup na škále 0.0 - 1.0:
- 0.0 = úplně špatný směr, nelogický
- 0.5 = průměrný, může vést k řešení
- 1.0 = vynikající, velmi slibný postup

Vrať JSON s klíčem "score" (číslo)."""
        }],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)["score"]

Kdy použít Tree of Thoughts

ToT exceluje u problémů, kde existuje mnoho možných cest k řešení a kde špatná počáteční volba může celý postup zmařit. Typické příklady: strategické plánování, kreativní řešení problémů, složité matematické důkazy nebo optimalizační úlohy.

Nevýhodou je vyšší cena (výrazně více API volání) a latence, takže pro jednoduché úlohy je to kanón na vrabce. Používejte s rozmyslem.

Systémové prompty: Architektura efektivních instrukcí

Anatomie dobrého systémového promptu

Systémový prompt je základ celé interakce. Tady se rozhoduje o tom, jestli bude výstup konzistentně dobrý, nebo jestli budete lovit kvalitu jako jehlu v kupce sena. V roce 2026 se osvědčila struktura, která systémový prompt organizuje jako „krátký kontrakt" s jasně definovanými sekcemi. Tady je vzor, který konzistentně funguje napříč modely:

SYSTEM_PROMPT = """
# Role
Jsi senior datový analytik specializovaný na finanční data.

# Cíl
Analyzuješ finanční reporty a poskytuj actionable insights
pro investiční rozhodování.

# Kontext
- Pracuješ s daty českých a slovenských firem
- Tvoje analýzy čtou portfolio manažeři s 10+ lety zkušeností
- Přesnost je kritická — chyba může znamenat milionové ztráty

# Pravidla
1. NIKDY nevymýšlej čísla — pokud data nemáš, řekni to
2. Vždy uveď zdroj dat a časové období
3. Rozlišuj korelaci a kauzalitu
4. U prediktivních výroků uveď míru nejistoty
5. Používej odbornou terminologii, ale vysvětli méně obvyklé pojmy

# Formát výstupu
- Začni shrnutím klíčových zjištění (3-5 bodů)
- Pak podrobná analýza s tabulkami kde je to relevantní
- Konči doporučením a riziky
- Čísla formátuj s oddělovačem tisíců (mezerou)
"""

Techniky pro konzistentní chování

Jedním z největších problémů v produkci je konzistence — model by měl odpovídat stejně kvalitně a ve stejném formátu, ať je dotaz jakýkoli. Tady je pár technik, které s tím pomáhají (a které jsem se naučil většinou tvrdou cestou):

  • Pozitivní instrukce — místo „nedělejte X" raději „vždy dělejte Y". Modely lépe reagují na pozitivní formulace. Zní to jako maličkost, ale v praxi to dělá překvapivý rozdíl.
  • Explicitní hranice — jasně definujte, co model smí a co ne. „Pokud otázka nespadá do oblasti financí, zdvořile odmítni a vysvětli proč."
  • Formátovací vzory — ukažte přesný formát výstupu, nejlépe s konkrétním příkladem. Model pak formát konzistentně dodržuje.
  • Ochranné klauzule — definujte chování pro edge cases. „Pokud data nejsou jednoznačná, prezentuj obě interpretace s vysvětlením." Na tyhle se často zapomíná, a pak se divíme, proč model v neobvyklých situacích halucinuje.

Prompt chaining: Řetězení promptů v komplexních workflow

Proč jeden prompt nestačí

Komplexní úlohy mají tendenci zahltit i nejschopnější modely. Zkoušeli jste někdy nacpat do jednoho promptu extrakci dat, analýzu, hodnocení a generování doporučení najednou? Výsledek bývá... no, řekněme nevalný.

Prompt chaining řeší tento problém dekompozicí — rozdělíte úlohu na sérii menších, specializovaných kroků, kde výstup jednoho kroku je vstupem dalšího. Výhody jsou zásadní: každý krok můžete nezávisle testovat a ladit, můžete použít různé modely pro různé kroky (levnější model na extrakci, dražší na analýzu), a celý pipeline je transparentní a debugovatelný. Když něco nefunguje, přesně víte kde.

from typing import Optional

class PromptChain:
    """Jednoduchý framework pro řetězení LLM kroků."""

    def __init__(self, client):
        self.client = client
        self.steps = []
        self.results = {}

    def add_step(
        self,
        name: str,
        prompt_template: str,
        model: str = "gpt-4o",
        response_format: Optional[type] = None
    ):
        self.steps.append({
            "name": name,
            "prompt_template": prompt_template,
            "model": model,
            "response_format": response_format
        })
        return self

    def run(self, initial_input: str) -> dict:
        self.results["input"] = initial_input

        for step in self.steps:
            # Dosadíme výsledky předchozích kroků do šablony
            prompt = step["prompt_template"].format(**self.results)

            kwargs = {
                "model": step["model"],
                "messages": [{"role": "user", "content": prompt}]
            }
            if step["response_format"]:
                kwargs["response_format"] = step["response_format"]

            response = self.client.chat.completions.create(**kwargs)
            self.results[step["name"]] = response.choices[0].message.content

        return self.results


# Příklad: Pipeline pro analýzu zákaznické zpětné vazby
chain = PromptChain(client)

chain.add_step(
    name="extrakce",
    prompt_template="""Extrahuj z následujících zákaznických recenzí:
1. Hlavní témata (max 5)
2. Konkrétní problémy
3. Pochvaly

Recenze: {input}

Vrať strukturovaný přehled.""",
    model="gpt-4o-mini"  # Levnější model pro extrakci
)

chain.add_step(
    name="analyza",
    prompt_template="""Na základě extrahovaných dat proveď hloubkovou analýzu:

{extrakce}

Identifikuj:
1. Systémové problémy vs. ojedinělé incidenty
2. Trendy ve spokojenosti
3. Korelace mezi problémy
4. Priority pro řešení (high/medium/low)""",
    model="gpt-4o"  # Silnější model pro analýzu
)

chain.add_step(
    name="doporuceni",
    prompt_template="""Na základě analýzy zákaznické zpětné vazby:

{analyza}

Vytvoř akční plán s konkrétními doporučeními:
1. Okamžitá opatření (do 1 týdne)
2. Střednědobá opatření (do 1 měsíce)
3. Strategické změny (do 1 kvartálu)

Každé doporučení musí být konkrétní, měřitelné a realistické.""",
    model="gpt-4o"
)

vysledky = chain.run(zakaznicke_recenze)

DSPy: Programatický přístup k prompt optimalizaci

Od ručního ladění k automatické optimalizaci

Ruční prompt engineering má zásadní omezení — spoléhá na intuici a trial-and-error. Kolikrát jste seděli nad promptem a zkoušeli přehodit slovo sem, přidat větu tam, a doufali, že to bude lepší? Já mnohokrát. A přesně tenhle problém řeší DSPy.

DSPy (Declarative Self-improving Python) od Stanford NLP přináší radikálně odlišný přístup: místo psaní promptů programujete chování a framework automaticky najde optimální prompty pro váš konkrétní use case. Filozofie DSPy je elegantní: definujte co chcete (signatury, metriky), ne jak to říct modelu. Framework pak iteruje přes stovky variant promptů, testuje je proti vašim datům a vybere ten nejefektivnější. Pracovní postup se mění z „write-test-repeat" na „define-compile-evaluate".

# pip install dspy
import dspy

# Konfigurace modelu
lm = dspy.LM("openai/gpt-4o-mini")
dspy.configure(lm=lm)

# Definice signatury — CO chceme, ne JAK
class KlasifikaceTicketu(dspy.Signature):
    """Klasifikuj support ticket podle priority a kategorie."""

    ticket_text: str = dspy.InputField(desc="Text support ticketu")
    priorita: str = dspy.OutputField(
        desc="Priorita: kriticka, vysoka, stredni, nizka"
    )
    kategorie: str = dspy.OutputField(
        desc="Kategorie: bug, feature_request, dotaz, reklamace"
    )
    shruti: str = dspy.OutputField(
        desc="Shrnutí problému v jedné větě"
    )

# Modul s chain-of-thought
klasifikator = dspy.ChainOfThought(KlasifikaceTicketu)

# Použití
vysledek = klasifikator(
    ticket_text="Aplikace padá při otevření reportu s více než 1000 řádky. "
                "Stává se to od posledního updatu. Blokuje to celé oddělení."
)
print(f"Priorita: {vysledek.priorita}")
print(f"Kategorie: {vysledek.kategorie}")
print(f"Shrnutí: {vysledek.shruti}")

Automatická optimalizace s MIPROv2

Skutečná síla DSPy ale spočívá v optimalizátorech. MIPROv2 (Multi-objective Instruction Proposal Optimizer) vezme váš program, malou sadu trénovacích příkladů a validační metriku, a automaticky projde stovky variant promptů, aby našel tu, která maximalizuje výkon. Je to trochu jako hyperparameter tuning, jen pro prompty.

import dspy
from dspy.teleprompt import MIPROv2

# Trénovací data
trainset = [
    dspy.Example(
        ticket_text="Nefunguje přihlášení přes Google SSO od včerejška",
        priorita="kriticka",
        kategorie="bug",
        shruti="Nefunkční Google SSO autentizace"
    ).with_inputs("ticket_text"),
    dspy.Example(
        ticket_text="Bylo by fajn mít dark mode v dashboardu",
        priorita="nizka",
        kategorie="feature_request",
        shruti="Požadavek na dark mode v dashboardu"
    ).with_inputs("ticket_text"),
    # ... další příklady
]

# Validační metrika
def validate_classification(example, prediction, trace=None):
    priority_correct = example.priorita == prediction.priorita
    category_correct = example.kategorie == prediction.kategorie
    return (priority_correct + category_correct) / 2

# Optimalizace
optimizer = MIPROv2(
    metric=validate_classification,
    num_candidates=20,
    num_threads=4
)

optimized_classifier = optimizer.compile(
    klasifikator,
    trainset=trainset,
    max_bootstrapped_demos=4,
    max_labeled_demos=4
)

# Optimalizovaný klasifikátor automaticky používá nejlepší prompt
vysledek = optimized_classifier(
    ticket_text="Export do PDF generuje prázdný soubor u faktur nad 50 stran"
)

V praxi DSPy optimalizace typicky přináší zlepšení přesnosti o 10-30 % oproti ručně psaným promptům. A co je možná ještě důležitější — proces je reprodukovatelný a měřitelný. Žádné „mně se zdá, že tenhle prompt funguje lépe". Máte tvrdá čísla.

Evaluace promptů: Měření kvality v produkci

LLM-as-a-Judge

Jak víte, jestli váš prompt skutečně funguje? Tím nemyslím jestli „vypadá, že funguje" — myslím opravdu funguje, konzistentně, na různých vstupech. V roce 2026 se standardem stala technika LLM-as-a-Judge — použijete silnější model k automatickému hodnocení výstupů slabšího modelu. Hodnotí se dimenze jako koherence, faktická správnost, bezpečnost, relevance a dodržování formátu.

from pydantic import BaseModel

class Hodnoceni(BaseModel):
    koherence: int      # 1-5
    relevance: int      # 1-5
    presnost: int       # 1-5
    format: int         # 1-5
    oduvodneni: str

def evaluate_response(question: str, response: str) -> Hodnoceni:
    """Automatické hodnocení kvality odpovědi pomocí LLM."""

    result = client.beta.chat.completions.parse(
        model="gpt-4o",  # Silnější model jako hodnotitel
        messages=[{
            "role": "system",
            "content": """Jsi přísný hodnotitel kvality AI odpovědí.
Hodnotíš na škále 1-5 (1=špatné, 5=vynikající).
Buď objektivní a zdůvodni své hodnocení."""
        }, {
            "role": "user",
            "content": f"""Otázka: {question}

Odpověď k hodnocení: {response}

Ohodnoť odpověď ve všech dimenzích."""
        }],
        response_format=Hodnoceni
    )

    return result.choices[0].message.parsed


# Hromadná evaluace přes testovací sadu
test_cases = load_test_cases("test_data.json")
scores = []

for case in test_cases:
    response = generate_response(case["question"])
    evaluation = evaluate_response(case["question"], response)
    scores.append({
        "question": case["question"],
        "avg_score": (
            evaluation.koherence + evaluation.relevance +
            evaluation.presnost + evaluation.format
        ) / 4,
        "details": evaluation
    })

avg_overall = sum(s["avg_score"] for s in scores) / len(scores)
print(f"Průměrné skóre: {avg_overall:.2f}/5.0")

Trasovatelnost a verzování promptů

V produkčním prostředí je klíčové spojit každé hodnocení s konkrétní verzí promptu, modelem a datasetem. Tento princip se označuje jako trasovatelnost (traceability) a v roce 2026 je považován za nejdůležitější aspekt promptového inženýrství v produkci. Bez ní nevíte, která změna promptu vedla ke zlepšení nebo zhoršení. A věřte mi, po třetí iteraci promptu si už nikdo nepamatuje, co přesně se měnilo.

Doporučený přístup: verzujte prompty v Gitu stejně jako kód, každou změnu promptu testujte proti stabilní evaluační sadě, a udržujte historii metrik. Nástroje jako LangSmith, Braintrust nebo Humanloop tento workflow automatizují. Není to glamour práce, ale ušetří vám to hodně šedivých vlasů.

Praktické tipy pro pokročilý prompt engineering

1. Princip minimální komplexity

Začněte s nejjednodušší technikou, která funguje. Vážně. Zero-shot prompt stačí na překvapivě mnoho úloh. Chain-of-thought přidejte, jen když zero-shot selhává. Tree of Thoughts nebo DSPy optimalizaci nasaďte, jen když jednodušší přístupy prokazatelně nedosahují požadované kvality. Každá vrstva komplexity přidává latenci, náklady a body selhání.

2. Testujte na edge cases, ne na happy path

Váš prompt pravděpodobně funguje skvěle na typických vstupech. To ale nic neznamená. Otázka je, co udělá s prázdným vstupem, extrémně dlouhým textem, vstupem v nesprávném jazyce, protichůdnými instrukcemi nebo záměrným prompt injection pokusem. Testovací sada by měla obsahovat minimálně 20 % edge cases. Spíš víc.

3. Oddělujte instrukce od dat

Nikdy nemíchejte systémové instrukce s uživatelskými daty v jednom bloku textu. Používejte jasné oddělovače — XML tagy, markdown sekce, nebo oddělené zprávy. Snížíte tím riziko prompt injection a zlepšíte konzistenci. Tenhle tip zní banálně, ale počet produkčních systémů, kde se to nedodržuje, by vás překvapil.

# ŠPATNĚ — instrukce a data jsou promíchané
prompt = f"Analyzuj tento text a vrať sentiment: {user_text}. Odpovídej pouze JSON."

# SPRÁVNĚ — jasná separace
messages = [
    {"role": "system", "content": "Analyzuj text a vrať sentiment jako JSON: {\"sentiment\": \"...\", \"score\": 0.0}"},
    {"role": "user", "content": user_text}
]

4. Iterujte na základě dat, ne pocitů

Měřte kvalitu promptů systematicky. Subjektivní „tohle mi přijde lepší" není dostatečné pro produkci. Vytvořte evaluační sadu, definujte metriky a porovnávejte verze promptů kvantitativně. Je to víc práce na začátku, ale ušetří to týdny ladění v produkci. Tohle jsem se naučil na vlastní kůži — jednou jsem „vylepšil" prompt, který pak v edge cases performoval o 15 % hůř, a bez metrik bych si toho všiml až od zákazníků.

5. Model-specific optimalizace

Různé modely reagují na různé promptovací strategie. Claude preferuje XML tagy pro strukturování a delší, detailnější instrukce. GPT-4o lépe funguje s JSON formátováním a stručnějšími instrukcemi. Reasoning modely (jako o3 od OpenAI) paradoxně performují hůř s few-shot příklady — ty je mohou odvádět od vlastního uvažovacího procesu.

Vždy testujte svůj prompt na konkrétním modelu, který budete používat v produkci. Prompt optimalizovaný pro jeden model může být na jiném výrazně horší. Není to ideální, ale taková je realita.

Závěr: Prompt engineering jako inženýrská disciplína

Prompt engineering se v roce 2026 definitivně přesunul z kategorie „umění" do kategorie „inženýrské disciplíny". Máme formalizované techniky (CoT, ToT, ReAct), nástroje pro automatickou optimalizaci (DSPy), standardizované evaluační frameworky (LLM-as-a-Judge) a osvědčené vzory pro produkční nasazení (strukturované výstupy, prompt chaining). To je obrovský posun oproti tomu, kde jsme byli ještě před dvěma lety.

Klíčové poselství tohoto článku: neexistuje univerzální „nejlepší prompt". Existuje ale systematický proces, jak pro váš konkrétní use case najít optimální přístup. Začněte jednoduše, měřte výsledky, přidávejte komplexitu jen tam, kde přináší měřitelné zlepšení, a verzujte prompty stejně pečlivě jako zdrojový kód.

Pokud jste četli naše předchozí články o RAG pipeline, MCP protokolu a multi-agentních systémech, prompt engineering je to pojítko, které všechny tyto technologie spojuje. Bez kvalitních promptů váš RAG systém vrací irelevantní odpovědi, vaši agenti dělají špatná rozhodnutí a vaše MCP integrace nepracují efektivně. Investice do prompt engineeringu je investice do kvality celého AI ekosystému vaší organizace. A upřímně? Je to taky jedna z nejzábavnějších částí práce s AI.

O Autorovi Editorial Team

Our team of expert writers and editors.