
Sessions, Traces a Spans v LLM observabilitě: Jedna z nich není strukturální úroveň
Stránka s pojmy od Datadogu, první výsledek na Googlu pro dotaz LLM observability sessions traces spans, definuje dvě z těchto tří slov. Ne tři. To chybějící se mapuje na gen_ai.conversation.id a důvod, proč chybí, je prostý: specifikace OpenTelemetry z něj nikdy strukturální úroveň neudělala. Pokud potřebujete zdůvodnění pro observabilitu jako takovou, začněte zde. Tento článek navazuje tam, kde ten předchozí končí: datovým modelem.
Klíčové body
- Spans se vnořují do traces, traces se seskupují do sessions. Vnořování běží zevnitř ven: span, pak trace, pak session.
- Span je jedna měřená operace. Trace je jeden end-to-end request. Session je jedna konverzace s více koly.
- Konvence OpenTelemetry GenAI definují spans a atribut
gen_ai.conversation.id. Úroveň session nedefinují. - ID trace a spanu se propagují automaticky skrze kontext. ID session ne. To nastavujete vy, v každém kole.
Sessions vs. Traces vs. Spans na první pohled
V LLM observabilitě je span jedna časově měřená operace (volání modelu, krok retrievalu), trace je strom spans, který jeden request vyprodukuje, a session seskupuje mnoho traces ze stejné konverzace. Vnořování směřuje dovnitř: spans uvnitř traces, traces uvnitř sessions. Třetí seskupení je přesně to, které není tím, čím se zdá být.
| Úroveň | Co obaluje | Jak dlouho žije | Kdo nastavuje ID | Co odpovídá | Typický počet na konverzaci |
|---|---|---|---|---|---|
| Session | Mnoho traces z jedné uživatelské konverzace | Minuty až dny; končí timeoutem neaktivity nebo explicitním zavřením (definuje vendor) | Vy, ručně, v každém kole | Byla celá tato konverzace úspěšná? | 1 |
| Trace | Jeden end-to-end request nebo jedno kolo | Milisekundy až sekundy | Automaticky (SDK / OTel) | Co se stalo v tomto kole? | Obvykle 5–20 |
| Span | Jedna operace: retrieval, volání modelu, volání nástroje | Submilisekundy až sekundy | Automaticky (SDK / OTel) | Který krok byl pomalý, chybný nebo drahý? | Zhruba 3–30 na trace |
Uvedené počty a doby životnosti jsou typické rozsahy, které můžete čekat u RAG chatbota nebo agentské smyčky, ne měření z kontrolovaného testu. Vaše čísla se budou lišit. Co se lišit nebude: řádek Session je ten, který není strukturální úrovní ve specifikaci, a sekce „Sessions: Úroveň, kterou si váš nástroj pravděpodobně vymyslel" to dokazuje.
Co je span a co je druh spanu?
Span je jedna časově měřená operace s názvem, počátečním timestampem, koncovým timestampem, stavovým kódem a sadou atributů typu klíč-hodnota. V LLM tracingu jsou užitečná data právě v atributech: gen_ai.usage.input_tokens, gen_ai.usage.output_tokens a gen_ai.request.model vám řeknou, co operace stála a který model ji provedl.
Span je jedna operace, ne jedno volání funkce
Každý span nese ukazatel na ID nadřazeného spanu (u kořenového spanu prázdný), který buduje strom. Sada atributů je otevřená: připojíte si jakýkoli kontext, který potřebujete. Konvence OpenTelemetry GenAI pro spans (stav: Development) vyžadují u každého GenAI spanu gen_ai.operation.name a gen_ai.provider.name a doporučují výše uvedené atributy spotřeby tokenů.
Jedno praktické pravidlo ze stránky pojmů Datadogu: spans LLM, Workflow a Agent mohou sloužit jako kořenový span; spans Tool, Task, Embedding a Retrieval ne. To je pravidlo Datadogu, ne univerzální, ale je to jediný vendor, který ho vyslovuje, a ušetří vás trace, která začíná voláním nástroje bez rodiče.
Druhy spans: stejná myšlenka, pět slovníků
Každý nástroj potřebuje nějak říct „tento span je volání modelu" oproti „tento span je retrieval". Jen se neshodnou na slově:
| Nástroj | Jeho výraz pro „druh operace" | Hodnoty |
|---|---|---|
| OpenTelemetry GenAI | atribut gen_ai.operation.name | 15 dobře známých hodnot (chat, embeddings, execute_tool, invoke_agent, retrieval a 10 dalších); pokud některá platí, MUSÍ se použít, vlastní hodnoty jsou povoleny, když neplatí žádná |
| Datadog | Span kind | LLM, Workflow, Agent, Tool, Task, Embedding, Retrieval |
| OpenInference / Phoenix | Span kind | CHAIN, LLM, TOOL, RETRIEVER, RERANKER, EMBEDDING, AGENT, GUARDRAIL, EVALUATOR, PROMPT |
| Langfuse | Observation type | generation, span, event |
| LangSmith | Run type | LLM, chain, tool, retriever |
Specifikace OpenInference uvádí deset druhů. Datadog uvádí sedm. OTel jde třetí cestou: jeho registr atributů GenAI publikuje 15 dobře známých hodnot pro gen_ai.operation.name (chat, create_agent, create_memory, create_memory_store, delete_memory, delete_memory_store, embeddings, execute_tool, generate_content, invoke_agent, invoke_workflow, plan, retrieval, search_memory, text_completion) a stanovuje, že pokud některá z nich platí, MUSÍ se použít; vlastní hodnota smí být použita jen tehdy, když nevyhovuje žádná. Jde tedy o polouzavřený výčet, ne o jeho absenci. Tři seznamy, tři délky a žádné sladění mezi nimi. Pokud vybíráte nástroj, tato mezera ve slovníku znamená víc než seznam funkcí, protože právě na něm budou klíčovat vaše dashboardy a filtry alertů.
Co je trace a proč záleží na tvaru stromu?
Trace je strom spans vyprodukovaný jedním requestem. Nahoře sedí jeden kořenový span; každý další span visí pod ním přes hrany ID nadřazeného spanu. Tvar stromu je to celé: plochý log vám řekne, že něco bylo pomalé, ale strom vám řekne, který krok byl pomalý a který krok vyprodukoval špatný výstup.
chat_request (root) 2,340ms
├── retrieval 410ms
│ └── rerank 85ms
├── chat gpt-4o 1,720ms
└── tool_call: search_calendar 190msPřečtěte si ten strom a diagnóza je okamžitá: 74 % latence sedělo ve volání modelu, ne v retrievalu. Plochý log s pěti timestampy vám dá stejný součet, ale žádné připsání.
Agentská smyčka dělá tento strom hlubším a širším než prostý RAG request. Každé volání nástroje zplodí vlastní podstrom; pětikrokové kolo agenta snadno vyprodukuje přes 30 spans pod jedním kořenem. To je normální a je to důvod, proč existuje otázka granularity spans níže.
Rozdíl mezi tracingem a loggingem tu také hraje roli: logging zaznamenává události, tracing zaznamenává kauzalitu. Pokud ještě zvažujete, co logovat a co tracovat, náš článek o osvědčených postupech LLM loggingu tu hranici vede.
Sessions: Úroveň, kterou si váš nástroj pravděpodobně vymyslel
Ne. Session není strukturální úrovní v konvencích OpenTelemetry GenAI. Specifikace definuje spans a atribut gen_ai.conversation.id (podmíněně vyžadovaný, „když je dostupný", stav: Development), popsaný jako jedinečný identifikátor konverzace nebo vlákna používaný ke korelaci zpráv. Vendoři nad tímto atributem staví vlastní objekt session. Nikdo jiný na této stránce výsledků vyhledávání stav specifikace neříká otevřeně, takže tady je.
Důsledek je věta, kvůli které celý tento článek existuje:
Session je seskupovací klíč, ne nadřazený span. Nepropaguje se jako ID trace; nastavujete ji sami v každém kole.
Vynechte jedno kolo a toto kolo ze session vypadne. Žádná automatická propagace kontextu pro ni neexistuje.
Kdy session začíná a končí?
Definuje vendor. Některé nástroje otevírají session u první trace s novým ID konverzace a zavírají ji timeoutem neaktivity (Langfuse má výchozí konfigurovatelné okno). Jiné vyžadují explicitní volání pro zavření. Specifikace o životním cyklu neříká nic, protože session nemodeluje jako objekt.
Co se přenáší mezi koly a co ne?
Kontextové okno modelu není session. Session je seskupovací klíč nad nezávislými traces. Každé kolo dostane vlastní trace, vlastní kořenový span, vlastní počty tokenů. Co se přenáší, je atribut ID konverzace, který jste orazítkovali na každý kořenový span. Co se nepřenáší: latence, spotřeba tokenů, struktura spans. Ty jsou pro každou trace zvlášť.
Co měří metrika na úrovni session?
Věci, které jedna trace nedokáže: míru vyřešení (vyřešila konverzace uživatelův problém?), počet kol do odpovědi (kolik traces proběhlo, než uživatel dostal, co potřeboval?) a opuštěné konverzace (sessions bez uzavíracího signálu). Spouštění evaluací na živých traces na úrovni session je způsob, jak zachytit selhání napříč koly, která při pohledu kolo po kole vypadají v pořádku.
Kód, neutrální vůči vendorům
Tento úryvek používá jen stabilní primitiva OTel. Žádné SDK vendorů. Vytvoří kořenový span pro jedno kolo, potomka pro retrieval, potomka pro volání modelu a nastaví gen_ai.conversation.id, takže tři kola skončí v jedné session:
from opentelemetry import trace
tracer = trace.get_tracer("my-llm-app")
SESSION_ID = "conv-8f3a2c" # same value on every turn
def handle_turn(user_message: str):
with tracer.start_as_current_span("chat_request") as root:
# You set this. It does not propagate automatically.
root.set_attribute("gen_ai.conversation.id", SESSION_ID)
with tracer.start_as_current_span("retrieval") as ret:
ret.set_attribute("gen_ai.operation.name", "retrieval")
docs = retrieve(user_message)
with tracer.start_as_current_span("chat gpt-4o") as llm:
llm.set_attribute("gen_ai.operation.name", "chat")
llm.set_attribute("gen_ai.provider.name", "openai")
llm.set_attribute("gen_ai.request.model", "gpt-4o")
response = call_model(user_message, docs)
llm.set_attribute("gen_ai.usage.input_tokens", 1_204)
llm.set_attribute("gen_ai.usage.output_tokens", 312)
return responseZavolejte handle_turn třikrát se stejným SESSION_ID a všechny tři traces se v jakémkoli backendu, který atribut čte, seskupí pod jednu session. Změňte ID a založili jste novou session. To je celý mechanismus.
Přečetli jsme dokumentaci pěti vendorů vedle sebe. Neshodují se.
-
- 2026 jsme vedle sebe přečetli aktuální dokumentaci datového modelu pro Langfuse, LangSmith, OpenInference / Phoenix a Datadog a navíc specifikaci spans OpenTelemetry GenAI. Čtyři z pěti nazývají stejný objekt jinak. Jen jeden zachází se session jako s plnohodnotným objektem, ne jako s atributem. Stránka pojmů Datadogu, první výsledek Googlu pro tento dotaz, session nedefinuje vůbec.
| Koncept | Sémantické konvence OTel GenAI | Langfuse | LangSmith | OpenInference / Phoenix | Datadog |
|---|---|---|---|---|---|
| Celá konverzace | atribut gen_ai.conversation.id | Session (volitelné seskupení traces) | Thread (přes metadata session_id / thread_id) | atribut spanu session.id | Na stránce pojmů nedefinováno |
| Jeden request | Trace | Trace | Trace („sbírka runs") | Trace | Trace |
| Jedna operace | Span | Observation (span / generation / event) | Run („span představující jednu jednotku práce") | Span s druhem spanu | Span s druhem spanu |
Jedna poznámka ke zdrojům u prvního řádku: session.id od OpenInference není ve výše odkazované specifikaci traces, která pokrývá deset druhů spans. Je definován v sesterském souboru sémantických konvencí OpenInference jako jedinečný identifikátor session. Dva soubory, jedna specifikace.
Srovnání napříč vendory jsme nevymysleli; FutureAGI publikuje tabulku OTel vs. vendoři také. Naše dva přídavky jsou řádek session (FutureAGI ho přeskakuje) a past stejného slova s jiným významem: „observation" u Langfuse a „run" u LangSmith jsou stejný objekt jako span, zatímco druhy spans u Datadogu a OpenInference jsou různé slovníky pro stejnou myšlenku.
Langfuse tomu říká observation, LangSmith tomu říká run, Datadog tomu říká span. Stejný objekt, tři dashboardy, které se rozbijí, když migrujete.
To je náš odhad nákladů na migraci, ne tvrzení vendorů. Ale je to důvod, proč uložené filtry, konfigurace evaluací a pravidla alertů klíčovaná na „observation" nebo „run" přestanou fungovat v den, kdy nástroje vyměníte. Nepřejmenováváte pole. Přejmenováváte úroveň. Pokud zvažujete právě tyto dva nástroje, naše srovnání Langfuse vs. LangSmith jde v rozdílech hlouběji.
Čtenáři možná už mají ve svém stacku Opik, PostHog, Sentry nebo Weights & Biases; Google všechny čtyři spojuje s llm tracing a každý mapuje tyto koncepty trochu jinak. Vybíráte ten pravý? Náš přehled observability platforem pokrývá celé pole.
Jedna poznámka k aktuálnosti: konvence GenAI se přestěhovaly do vlastního repozitáře, pryč z hlavního repozitáře semantic-conventions. Stará cesta opentelemetry.io/docs/specs/semconv/gen-ai/ teď nese jen odkaz.
Které ID patří kam?
ID trace identifikuje jeden request a propaguje se kontextem automaticky. ID spanu identifikuje jednu operaci uvnitř této trace, také automaticky. Korelační ID (neboli ID requestu) přichází z vaší webové vrstvy ještě před začátkem tracingu a právě to si lidé nejčastěji pletou s ID trace. ID session je výjimka: nastavujete ho vy, ručně, v každém kole.
| ID | Nastavuje | Rozsah | Plete se s |
|---|---|---|---|
| ID trace | Automaticky | Jeden request; propaguje se kontextem | Korelační ID z vaší webové vrstvy |
| ID spanu | Automaticky | Jedna operace | , |
| ID nadřazeného spanu | Automaticky | Buduje strom; u kořenového spanu prázdné | , |
| ID session / konverzace | Vy, ručně, v každém kole | Mnoho traces | Předpokladem, že se propaguje. Nepropaguje. |
| ID uživatele | Vy, ručně | Mnoho sessions | ID session |
| ID requestu / korelační ID | Vaše webová vrstva, před začátkem tracingu | Jeden HTTP request | ID trace (to je ten velký omyl) |
Praktické pravidlo: připojte gen_ai.conversation.id jako atribut spanu na kořenový span každého kola a vedle něj orazítkujte ID uživatele. Přeskočte jedno kolo a vaše metriky na úrovni session o toto kolo tiše přijdou.
Jedno varování ke kardinalitě: ID uživatelů a ID sessions jsou hodnoty s vysokou kardinalitou. To se projeví na účtu za indexaci vašeho backendu, což je problém další sekce.
Jak granulární má span být?
Dva způsoby selhání, oba běžné:
Příliš mnoho spans. Span pro každé volání funkce vám dá trace se 400 spans, kterou nikdo nepřečte, a účet za spany, který nikdo neschválil. Hostované backendy (Datadog, Langfuse Cloud) účtují podle objemu spans. Upovídaná agentská smyčka, která instrumentuje každé zřetězení řetězců, spálí free tier za jedno odpoledne.
Příliš málo spans. Jeden span pro „celý řetězec" vám řekne, že to bylo pomalé, ale ne kde. Skončíte u zpětného přidávání printů, což je přesně to, co měl tracing nahradit.
Pravidlo palce (a je to pravidlo palce, ne měření): spanujte hranice, kde probíhá rozhodnutí nebo externí volání.
- Krok retrievalu: spanujte.
- Volání reranku: spanujte.
- Každé volání modelu: spanujte.
- Každé volání nástroje: spanujte.
- Každá kontrola guardrailu: spanujte.
- Čisté vnitroprocesové transformace (formátování řetězců, parsování JSON, skládání promptu): atributy na nadřazeném spanu, ne vlastní spans.
Ke kardinalitě, vzorkování a retenci:
- Atributy s vysokou kardinalitou (ID uživatelů, celé prompty) nafukují náklady na úložiště. Vzorkujte je nebo ořezávejte.
- Většina backendů umožňuje vzorkování na úrovni trace. Ponechte 100 % chybových traces; vzorkujte šťastnou cestu.
- Retenční okna se liší: 7 dní u free tierů, 30–90 dní u placených. Rozhodněte se, než data budete potřebovat.
Pro skutečný nákladový model za objemem spans a cenou za span se podívejte do našeho průvodce monitorováním nákladů LLM. Nebudeme ho tu stavět znovu.
Jak k tomu přistupuje Techsy
Pro klientské agentské projekty jsme si standardizovali tři pravidla:
- Jedna trace na kolo. Nikdy nespojujte dvě uživatelská kola do jedné trace, i když agent uvnitř smyčkuje.
- ID session orazítkované na každém kořenovém spanu, nastavené v aplikačním kódu, nikdy se nepředpokládá propagace.
- Druhy spans držíme v malé pevné sadě (retrieval, inference, tool, guardrail), aby dashboardy přežily změnu vendora.
Třetí pravidlo je to, které týmy přeskakují, a přitom právě ono zachraňuje migraci. Pokud je váš slovník spans svázaný s výčtem jednoho vendora, každý alert a uložený pohled se rozbije v den, kdy přejdete.
Pokud stavíte agentský systém a chcete druhý názor na architekturu tracingu, získejte bezplatnou konzultaci.
O autorovi
Mert Batur je spoluzakladatel Techsy.io, kde tým dodává AI agenty, automatizační systémy a hlasové/SDR pipeline pro B2B klienty. Píše o stacku nástrojů LLM, který tým Techsy skutečně používá v produkci. Spojte se na LinkedInu.
Často kladené otázky
Co je span v distribuovaném tracingu?
Span je jedna časově měřená jednotka práce: má název, čas začátku, čas konce, stav a sadu atributů. Spans se navzájem propojují odkazy na ID nadřazeného spanu a tvoří strom. V LLM aplikacích span typicky obaluje jedno volání modelu, jeden retrieval nebo jedno vyvolání nástroje.
Co je span v Datadogu?
V LLM Observability Datadogu je span tatáž měřená operace, ale Datadog přidává taxonomii druhů spanu: LLM, Workflow, Agent, Tool, Task, Embedding a Retrieval. Jen druhy LLM, Workflow a Agent mohou sloužit jako kořenový span. Taxonomie je specifická pro Datadog; není součástí standardu OpenTelemetry.
Jaké jsou čtyři pilíře observability?
Čtyři pilíře jsou logy, metriky, traces a (podle toho, čí rámec zvolíte) profily nebo události. Traces jsou pilíř, ve kterém žije tento článek. Případ LLM přidává záhyb: spotřeba tokenů a identita modelu jsou atributy na spans trace, ne samostatné proudy metrik, což sráží to, co by byly dva pilíře, do jednoho dotazu.
Jaké jsou čtyři zlaté signály observability?
Latence, provoz, chyby a saturace. U LLM systémů latence znamená time-to-first-token a celkovou dobu generování; provoz znamená requesty za sekundu na model; chyby znamenají selhané spans (stavový kód ERROR); saturace znamená vyčerpání rozpočtu tokenů nebo hloubku fronty. Signály jsou stejné; jednotky se liší.
Je session součástí specifikace OpenTelemetry?
Ne jako strukturální úroveň. Konvence OTel GenAI pro spans definují gen_ai.conversation.id jako podmíněně vyžadovaný atribut („když je dostupný") pro korelaci zpráv v konverzaci nebo vláknu. Sedí na spans. Vendoři jako Langfuse a LangSmith nad ním staví vlastní objekty session nebo thread.
Jaký je rozdíl mezi ID trace, ID spanu a korelačním ID?
ID trace identifikuje jeden request a propaguje se automaticky všemi navazujícími službami. ID spanu identifikuje jednu operaci uvnitř této trace. Korelační ID (neboli ID requestu) generuje vaše webová vrstva před začátkem tracingu a je to hodnota, kterou si lidé nejčastěji pletou s ID trace. Rozsahem se překrývají, ale vznikají jinak.
Kolik spans má mít jedna trace?
Pevná odpověď neexistuje, ale typické rozsahy jsou 3–30 pro RAG request a 10–50+ pro agentskou smyčku s více voláními nástrojů. Pravidlo palce: spanujte externí volání a rozhodovací body, ne vnitroprocesové transformace. Pokud vaše trace přesáhne 100 spans, pravděpodobně instrumentujete příliš.
Jsou „observations" v Langfuse totéž co spans?
Ano. Observation v Langfuse je stejný objekt jako span OTel: jedna měřená operace s atributy. Langfuse dělí observations na tři typy (generation, span, event), zatímco OTel používá gen_ai.operation.name. Pokud hodnotíte nástroje, které čtou vaše traces, náš přehled evaluačních nástrojů LLM pokrývá, které z nich přijímají oba slovníky.
Jak seskupíte konverzaci chatbota s více koly do jedné session?
Nastavte stejný identifikátor konverzace na kořenovém spanu každého kola. V terminologii OTel je to gen_ai.conversation.id. V Langfuse předáváte session_id při vytváření traces. V LangSmith nastavujete metadata session_id nebo thread_id. Vynechte jedno kolo a toto kolo ze seskupení vypadne.
Potřebuji sessions, pokud zpracovávám jen jednokolové requesty?
Pravděpodobně ne. Sessions existují proto, aby korelovaly více traces do jedné konverzace. Pokud je každý request nezávislý (klasifikační API, jednorázový sumarizér), stačí metriky na úrovni trace. Sessions přidejte, když potřebujete metriky napříč koly: míru vyřešení, počet kol do odpovědi nebo náklady na konverzaci. Náš průvodce evaluací LLM pokrývá, kdy se evaluace na úrovni session vyplatí.
Krátká verze
Spans se vnořují do traces; traces se seskupují do sessions. Vnořování je skutečné, ale specifikace strukturuje jen dvě ze tří úrovní. gen_ai.conversation.id je atribut, který nastavujete sami, ne nadřazený span, který se propaguje. A vendor, kterého vyberete dnes, nazývá tyto objekty jinak než vendor, ke kterému přejdete za 18 měsíců, takže držte svůj slovník spans malý a přenositelný.
Pokud vybíráte platformu, začněte naším srovnáním observability platforem. Pokud stavíte evaluace nad svými traces, průvodce evaluací LLM navazuje přesně tady.