<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Agentsight on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/agentsight/</link><description>Recent content in Agentsight on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 19 May 2026 18:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/agentsight/index.xml" rel="self" type="application/rss+xml"/><item><title>AgentSight and the new LLM tracing: zero-instrumentation with eBPF against Langfuse, LangSmith, Phoenix and company</title><link>https://blog.lo0.es/en/posts/agentsight-llm-tracing-ebpf-zero-instrumentation/</link><pubDate>Tue, 19 May 2026 18:00:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/agentsight-llm-tracing-ebpf-zero-instrumentation/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Observing an LLM agent in production in 2026 splits into two approaches with opposite philosophies. The &lt;strong>instrumented&lt;/strong> one, dominant until 2025, lives in tools such as &lt;a href="https://langfuse.com/">Langfuse&lt;/a>, &lt;a href="https://www.langchain.com/langsmith">LangSmith&lt;/a>, &lt;a href="https://phoenix.arize.com/">Arize Phoenix&lt;/a>, &lt;a href="https://www.helicone.ai/">Helicone&lt;/a>, &lt;a href="https://www.traceloop.com/openllmetry">OpenLLMetry/Traceloop&lt;/a> or &lt;a href="https://pydantic.dev/logfire">Pydantic Logfire&lt;/a>: you install an SDK, decorate your calls, emit spans with the &lt;strong>OpenTelemetry GenAI&lt;/strong> convention (&lt;code>gen_ai.request.model&lt;/code>, &lt;code>gen_ai.usage.input_tokens&lt;/code>, and so on) and export them to a backend. Enormous depth when you control the code; zero visibility when the agent is an opaque binary you run without instrumenting. The &lt;strong>zero-instrumentation&lt;/strong> one, which &lt;a href="https://github.com/eunomia-bpf/agentsight">AgentSight&lt;/a> popularised in the second half of 2025, turns the perspective 180º: it puts &lt;strong>eBPF hooks on the uprobes of the SSL/TLS libraries&lt;/strong> and captures the plaintext of every HTTPS request before encryption, &lt;strong>without touching the app&amp;rsquo;s code&lt;/strong>, with less than &lt;strong>3% overhead&lt;/strong> and the guarantee of being &lt;strong>tamper-proof&lt;/strong> (the agent cannot falsify what is seen in the kernel). Combined with BPF capture of stdio for local MCP servers, AgentSight gives you complete observability of any agent, including closed binaries such as Claude Code, Gemini CLI or Cursor, on a Kubernetes cluster. The two families are not enemies: the 2026 reference stack combines both (instrumented for your own apps with LangChain, eBPF for opaque binaries and tamper-proof compliance) over &lt;strong>OpenTelemetry GenAI semantic conventions&lt;/strong> as the common vocabulary the ecosystem is stabilising this year.&lt;/p>
&lt;blockquote>
&lt;p>This is the &lt;strong>fourth and last post of the eBPF series&lt;/strong>. Part 1: &lt;a href="https://blog.lo0.es/en/posts/ebpf-zero-to-cilium-kernel-tcp-ip-bypass/">eBPF from zero to Cilium&lt;/a>. Part 2: &lt;a href="https://blog.lo0.es/en/posts/tetragon-cilium-security-syscalls-kernel/">Tetragon: runtime security&lt;/a>. Part 3: &lt;a href="https://blog.lo0.es/en/posts/hubble-ebpf-network-observability-ai-agents/">Hubble: network observability&lt;/a>. Here we close the circle with the &lt;strong>semantic&lt;/strong> dimension: what an AI agent does, not only what network it opens or what syscalls it emits.&lt;/p>
&lt;/blockquote>
&lt;h2 id="the-analogy-traditional-apm-vs-network-sniffer">The analogy: traditional APM vs network sniffer&lt;/h2>
&lt;p>Anyone who has operated enterprise applications knows the two tribes of monitoring. The &lt;strong>APM&lt;/strong> tribe (New Relic, AppDynamics, Datadog APM): you install an agent or an SDK in each application, mark spans, collect traces with enormous depth inside each process, down to lines of code, SQL queries, Java methods. The &lt;strong>wire-level&lt;/strong> tribe (network sniffers, SolarWinds NPM-style tools, NetFlow): it does not touch the application; it observes the cable, sees protocols, latencies, retransmissions, identifies problems the app does not know it has.&lt;/p>
&lt;p>Each one sees different things and both are useful. Anyone who has lived through a serious incident where APM said &amp;ldquo;all green&amp;rdquo; while users suffered knows that wire-level would have caught the problem (a saturated middlebox, a badly configured MTU, a TCP timeout). Anyone who has tried to debug a memory leak with sniffers knows it was impossible without APM.&lt;/p>
&lt;p>LLM agent observability in 2026 is exactly at this point. The &lt;strong>APM-style&lt;/strong> has been in place for a couple of years: Langfuse, LangSmith, Phoenix, OpenLLMetry. Enormous depth, requires instrumenting the app. The &lt;strong>wire-level with eBPF&lt;/strong> has just arrived: AgentSight is the first project to take it to production. Less depth inside the agent, but it sees any agent without touching anything and it is &lt;strong>tamper-proof&lt;/strong>. Both are useful. The industry is in full coexistence.&lt;/p>
&lt;h2 id="why-observing-llm-agents-is-different">Why observing LLM agents is different&lt;/h2>
&lt;p>Before getting into tools, it is worth pausing on what makes LLM agents specific as subjects of observability:&lt;/p>
&lt;p>&lt;strong>Non-determinism.&lt;/strong> The same input can produce different outputs. Reproducing an incident requires capturing &lt;strong>exactly&lt;/strong> the conversation, the model, the parameters and, ideally, the seed. An aggregate &amp;ldquo;p95 latency&amp;rdquo; metric falls short; what you need is replay of the individual trace.&lt;/p>
&lt;p>&lt;strong>A chain of external invocations.&lt;/strong> A typical agent calls LLM → tools (tool calling) → MCP servers → other APIs → back to the LLM. A chat session can generate &lt;strong>dozens of chained calls&lt;/strong> that have to be correlated by trace_id to understand the decision.&lt;/p>
&lt;p>&lt;strong>Cost linear in tokens.&lt;/strong> Every call is paid for in tokens. Without tracing input/output tokens per request, you cannot assign cost to a tenant or a team, nor detect loops that eat your budget in an hour.&lt;/p>
&lt;p>&lt;strong>Semantic risk.&lt;/strong> Prompt injection (a user input containing instructions to manipulate the model), jailbreaks, secret leakage through tool calls. It is a class of problem that does not appear in traditional applications, and observability must see it.&lt;/p>
&lt;p>&lt;strong>Opaque binaries.&lt;/strong> In 2026, many teams deploy &lt;strong>third-party agents&lt;/strong> such as Claude Code, the Cursor agent, Aider, Gemini CLI or Codex CLI as internal tools. They are not your own applications; they are closed binaries that call the vendor&amp;rsquo;s API. Instrumenting them is impossible. Observing them requires something else.&lt;/p>
&lt;p>&lt;strong>Multi-agent and orchestration.&lt;/strong> More and more architectures have agents that invoke other agents (planner → executor → critic). Observability must understand the topology, not just the individual span.&lt;/p>
&lt;p>With these five points in mind, the tools we are about to see differ mainly in &lt;strong>which parts&lt;/strong> of the problem they cover well and &lt;strong>which parts&lt;/strong> they leave blind.&lt;/p>
&lt;h2 id="the-instrumented-approach-how-it-works">The instrumented approach: how it works&lt;/h2>
&lt;p>The model is direct and familiar:&lt;/p>
&lt;ol>
&lt;li>Your code calls the LLM or the tools using an official library: &lt;code>openai&lt;/code>, &lt;code>anthropic&lt;/code>, &lt;code>langchain&lt;/code>, &lt;code>llama_index&lt;/code>, &lt;code>dspy&lt;/code>.&lt;/li>
&lt;li>You install a tracer SDK (Langfuse, LangSmith, OpenLLMetry, Logfire) that &lt;strong>wraps&lt;/strong> or &lt;strong>monkey-patches&lt;/strong> those libraries.&lt;/li>
&lt;li>Each call emits an &lt;strong>OpenTelemetry span&lt;/strong> with standardised attributes: model used, input/output tokens, latency, parameters, messages, tool invoked, result.&lt;/li>
&lt;li>The spans are exported over OTLP to a backend that shows them as a tree of traces.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Typical example with OpenLLMetry + any SDK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">traceloop.sdk&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Traceloop&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">openai&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OpenAI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Traceloop&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">app_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;my-agent&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_endpoint&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;https://otel-collector:4318&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpenAI&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># this call automatically emits a span with&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># gen_ai.request.model, gen_ai.usage.input_tokens, etc.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">resp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;gpt-4.1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;...&amp;#34;&lt;/span>&lt;span class="p">}]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>What you see afterwards: a dashboard with each conversation as a trace, each call as a span, the complete prompts and completions (if you opt in), the computed cost, latencies per span, errors flagged.&lt;/p>
&lt;h3 id="opentelemetry-genai-semantic-conventions-the-common-vocabulary">OpenTelemetry GenAI semantic conventions: the common vocabulary&lt;/h3>
&lt;p>The fragmentation of the field is being mitigated with &lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/">&lt;strong>OpenTelemetry GenAI Semantic Conventions&lt;/strong>&lt;/a>. It is the CNCF&amp;rsquo;s effort to get &lt;strong>all&lt;/strong> tools to emit spans with the same attribute names:&lt;/p>
&lt;ul>
&lt;li>&lt;code>gen_ai.system&lt;/code> — the provider (openai, anthropic, vertex_ai, and so on).&lt;/li>
&lt;li>&lt;code>gen_ai.request.model&lt;/code> — the model requested (&lt;code>gpt-4.1&lt;/code>, &lt;code>claude-3-5-sonnet&lt;/code>).&lt;/li>
&lt;li>&lt;code>gen_ai.response.model&lt;/code> — the model actually used (sometimes it differs, e.g. fallbacks).&lt;/li>
&lt;li>&lt;code>gen_ai.usage.input_tokens&lt;/code> and &lt;code>gen_ai.usage.output_tokens&lt;/code> — counters.&lt;/li>
&lt;li>&lt;code>gen_ai.request.temperature&lt;/code>, &lt;code>gen_ai.request.top_p&lt;/code>, and so on — parameters.&lt;/li>
&lt;li>&lt;code>gen_ai.response.finish_reasons&lt;/code> — why it ended (stop, length, content_filter).&lt;/li>
&lt;li>&lt;code>gen_ai.operation.name&lt;/code> — the type of operation (chat, embedding, completion).&lt;/li>
&lt;/ul>
&lt;p>In early 2026, the &lt;strong>client spans&lt;/strong> moved from experimental to stable. The rest (server spans, multi-agent events) is still in development. The operational meaning: if your SDK emits these attributes, &lt;strong>any backend that understands OTel GenAI&lt;/strong> can consume them. Moving from Langfuse to Phoenix to Helicone does not imply re-instrumenting, only changing the exporter.&lt;/p>
&lt;p>The SIG is actively developing &lt;strong>conventions for multi-agent systems&lt;/strong>: agent teams, tasks, actions, memory, artifact tracking. This is what is missing for complex agent architectures to have a common vocabulary. In 2026 it is experimental; stabilisation is expected at the end of the year or the start of 2027.&lt;/p>
&lt;h3 id="instrumented-tools-the-2026-landscape">Instrumented tools: the 2026 landscape&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Tool&lt;/th>
&lt;th>Licence&lt;/th>
&lt;th>Self-host&lt;/th>
&lt;th>Focus&lt;/th>
&lt;th>Where it shines&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Langfuse&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>&lt;strong>Yes&lt;/strong>&lt;/td>
&lt;td>LLM observability + evals + prompt mgmt&lt;/td>
&lt;td>Best OSS balance, complete suite&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>LangSmith&lt;/strong>&lt;/td>
&lt;td>Commercial&lt;/td>
&lt;td>No&lt;/td>
&lt;td>Native LangChain/LangGraph&lt;/td>
&lt;td>If you use LangChain, zero-config integration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Arize Phoenix&lt;/strong>&lt;/td>
&lt;td>ELv2 (OSS)&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>OTel-native, strong RAG&lt;/td>
&lt;td>Vector DBs, retrieval, embeddings&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Helicone&lt;/strong>&lt;/td>
&lt;td>Commercial + OSS lite&lt;/td>
&lt;td>Yes (lite)&lt;/td>
&lt;td>Simple proxy&lt;/td>
&lt;td>Setup in minutes, OpenAI-only&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenLLMetry / Traceloop&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>OTel SDK for LLMs&lt;/td>
&lt;td>Vendor-neutral, exports to any OTel backend&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Pydantic Logfire&lt;/strong>&lt;/td>
&lt;td>Commercial&lt;/td>
&lt;td>No&lt;/td>
&lt;td>App + LLM unified&lt;/td>
&lt;td>If you use Pydantic AI, native integration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Weights &amp;amp; Biases Weave&lt;/strong>&lt;/td>
&lt;td>Commercial&lt;/td>
&lt;td>Limited&lt;/td>
&lt;td>Experimentation + production&lt;/td>
&lt;td>If you already use W&amp;amp;B for training&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Laminar / Braintrust&lt;/strong>&lt;/td>
&lt;td>Commercial&lt;/td>
&lt;td>No / Yes&lt;/td>
&lt;td>Evals + tracing&lt;/td>
&lt;td>More recent, focused on evaluation&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="deep-dive-langfuse">Deep dive: Langfuse&lt;/h3>
&lt;p>It is worth pausing on &lt;a href="https://langfuse.com/">Langfuse&lt;/a> because in 2026 it is &lt;strong>the default choice among the open-source options&lt;/strong> and the one most teams have adopted this year. It is a &lt;a href="https://github.com/langfuse/langfuse">YC W23&lt;/a> project, &lt;strong>MIT&lt;/strong> licence, and keeps a sustained release cadence with serious architectural changes between versions.&lt;/p>
&lt;p>&lt;strong>Four declared pillars&lt;/strong>: observability (tracing), evaluations, prompt management, playground/datasets. Each one separately has complete commercial products behind it; Langfuse integrates them into a single platform with a single backend.&lt;/p>
&lt;h4 id="sdk-v4-otel-native-not-a-replacement">SDK v4: OTEL-native, not a replacement&lt;/h4>
&lt;p>The big recent operational change is the &lt;strong>SDK v4&lt;/strong>, a thin layer over the official OpenTelemetry client. The choice is deliberate: instead of maintaining a client of its own that would fall behind the OTel primitives, Langfuse uses the standard SDK and &lt;strong>enriches&lt;/strong> the spans with LLM-specific attributes and helpers. The consequence: any code already instrumented with vanilla OpenTelemetry (&lt;code>@opentelemetry/sdk-node&lt;/code>, &lt;code>opentelemetry-sdk&lt;/code> in Python) &lt;strong>can export to Langfuse without major changes&lt;/strong>, and the other way round, if tomorrow you want to migrate from Langfuse to another OTel backend, the spans are portable.&lt;/p>
&lt;p>In Python the idiomatic decorator is &lt;code>@observe&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langfuse&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">observe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_client&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">langfuse&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_client&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@observe&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">buscar_documentos&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># any internal call is traced as well&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">vector_store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">similarity_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@observe&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">as_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;generation&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">llamar_llm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># marked as &amp;#34;generation&amp;#34; so it appears with LLM metadata&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">openai_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@observe&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">pipeline_rag&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pregunta&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">docs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">buscar_documentos&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pregunta&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">llamar_llm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">build_prompt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pregunta&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">docs&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The call tree is captured automatically: the trace shows &lt;code>pipeline_rag&lt;/code> as the root span, with &lt;code>buscar_documentos&lt;/code> and &lt;code>llamar_llm&lt;/code> as children, nested. Without writing a single &lt;code>with tracer.start_as_current_span(...)&lt;/code> by hand.&lt;/p>
&lt;p>In TypeScript the equivalent is modular: you install &lt;code>@langfuse/tracing&lt;/code>, &lt;code>@langfuse/otel&lt;/code> and &lt;code>@opentelemetry/sdk-node&lt;/code>, and you can use TS decorators, context managers or manual spans, the three models interoperate. The consequence: third-party libraries that emit OTel spans (&lt;code>openai&lt;/code>, &lt;code>@anthropic-ai/sdk&lt;/code>, Vercel AI SDK instrumentations) show up in Langfuse with no extra work.&lt;/p>
&lt;h4 id="self-host-architecture-designed-for-serious-production">Self-host architecture: designed for serious production&lt;/h4>
&lt;p>The Langfuse backend architecture has &lt;strong>two explicit decisions&lt;/strong> that set its self-host deployment apart:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Persistence in S3/Blob Storage first&lt;/strong>. When a tracing event arrives, &lt;strong>it is persisted in object storage before touching the database&lt;/strong>. Only when the later processing confirms OK is it inserted into Postgres/Clickhouse. If the DB goes down temporarily, the events &lt;strong>are not lost&lt;/strong>; they stay in S3 waiting to be reprocessed. For production where losing the traces of an incident is equivalent to losing evidence, this is load-bearing.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Long migrations as background jobs&lt;/strong>. Schema upgrades that on other platforms mean a downtime window run in the background on Langfuse while the application keeps serving. Upgrade downtime drops drastically.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>The officially supported deployment modes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Docker Compose&lt;/strong>: for development and POCs. One command, everything up.&lt;/li>
&lt;li>&lt;strong>VM&lt;/strong>: a single node, containers, no orchestration. For small environments.&lt;/li>
&lt;li>&lt;strong>Kubernetes with Helm&lt;/strong>: the recommended mode for production. Official chart maintained. Supports external Postgres, external Clickhouse, external S3, HPA.&lt;/li>
&lt;/ul>
&lt;p>The external dependencies in a typical production setup: &lt;strong>Postgres&lt;/strong> (metadata, prompts, configuration), &lt;strong>Clickhouse&lt;/strong> (tracing events, high-cardinality queries), &lt;strong>S3 or a compatible blob store&lt;/strong> (pending events), &lt;strong>Redis&lt;/strong> (the queue between components). Yes, that is several pieces; it is what holds up the durability and the scale.&lt;/p>
&lt;h4 id="prompt-management-as-a-first-class-citizen">Prompt management as a first-class citizen&lt;/h4>
&lt;p>What sets Langfuse apart from platforms focused only on tracing is that &lt;strong>the prompts live in Langfuse&lt;/strong>, not in the application repo or in spreadsheets. Each prompt has:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Name and version&lt;/strong> (v1, v2, v3&amp;hellip;). Changing the prompt does not require redeploying the app: the app asks the SDK for the prompt, and the SDK caches it and refreshes when there is a new version.&lt;/li>
&lt;li>&lt;strong>Typed variables&lt;/strong>: &lt;code>{{user_input}}&lt;/code>, &lt;code>{{context}}&lt;/code>. Rendering with validation.&lt;/li>
&lt;li>&lt;strong>Tags and labels&lt;/strong>: by environment (&lt;code>production&lt;/code>, &lt;code>staging&lt;/code>), by team, by experiment.&lt;/li>
&lt;li>&lt;strong>Client and server cache&lt;/strong>: the SDK caches locally with a configurable TTL, avoiding a roundtrip to Langfuse on every call.&lt;/li>
&lt;li>&lt;strong>Linkage with traces&lt;/strong>: each trace records which exact version of which prompt was used. Investigating &amp;ldquo;this answer came out wrong&amp;rdquo; leads to prompt version Y, not to &amp;ldquo;some version of the prompt at some point&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langfuse&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">get_client&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">langfuse&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_client&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">langfuse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_prompt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;rag-system-prompt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># or by label: langfuse.get_prompt(&amp;#34;rag-system-prompt&amp;#34;, label=&amp;#34;production&amp;#34;)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">compiled&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">compile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">docs_text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user_input&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">question&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;#39;compiled&amp;#39; is the final string, ready to send to the LLM&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For teams iterating on prompts daily, this is what avoids the chaos of &amp;ldquo;which version of the prompt is actually running in production right now&amp;rdquo;.&lt;/p>
&lt;h4 id="evaluations-four-combinable-evaluation-models">Evaluations: four combinable evaluation models&lt;/h4>
&lt;p>Langfuse covers the four patterns of answer evaluation:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LLM-as-a-judge&lt;/strong>: you configure a model (typically GPT-4 or Claude) with a rubric and it evaluates each answer. Result: a numeric score (0-1) and a justification. Applicable to automatic tracing (all answers) or batch (a dataset selection).&lt;/li>
&lt;li>&lt;strong>User feedback&lt;/strong>: the app lets the user mark an answer as good/bad. The feedback is associated with the trace and the prompt version, which lets you see which versions have a worse rate.&lt;/li>
&lt;li>&lt;strong>Manual labeling&lt;/strong>: a UI where human labelers score answers. Useful for golden datasets and for evaluating the judge.&lt;/li>
&lt;li>&lt;strong>Custom evaluators through the API/SDK&lt;/strong>: your own evals (a unit test, a business metric) report a score through the API. They integrate with CI.&lt;/li>
&lt;/ul>
&lt;p>Combined, they give &lt;strong>regression testing&lt;/strong> of the prompt: you change from v3 to v4, evaluate the golden dataset with LLM-as-judge, compare; if v4 gets worse in any of the segments, the merge fails.&lt;/p>
&lt;h4 id="integrations">Integrations&lt;/h4>
&lt;p>Langfuse does not compete with OpenLLMetry, LangChain or LiteLLM: it &lt;strong>integrates&lt;/strong> them. The ones that are tested and documented:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenTelemetry&lt;/strong>: any OTel instrumentation emits to Langfuse over OTLP.&lt;/li>
&lt;li>&lt;strong>LangChain and LangGraph&lt;/strong>: a native callback that captures the whole chain.&lt;/li>
&lt;li>&lt;strong>LlamaIndex&lt;/strong>: native callback.&lt;/li>
&lt;li>&lt;strong>OpenAI SDK&lt;/strong> (Python and TS): a wrapper that adds tracing automatically.&lt;/li>
&lt;li>&lt;strong>LiteLLM&lt;/strong>: integration as a callback, which covers 100+ providers through LiteLLM.&lt;/li>
&lt;li>&lt;strong>OpenLLMetry / Traceloop&lt;/strong>: they emit to Langfuse like any OTel backend.&lt;/li>
&lt;li>&lt;strong>MLflow&lt;/strong>: through an OTel exporter from MLflow to Langfuse.&lt;/li>
&lt;li>&lt;strong>Vercel AI SDK&lt;/strong>: native instrumentation.&lt;/li>
&lt;/ul>
&lt;p>The strategy is clear: &lt;strong>Langfuse is a backend, not an SDK&lt;/strong>. Your team chooses how it instruments; Langfuse accepts any path. The operational consequence: moving from Langfuse to another OTel backend tomorrow is viable.&lt;/p>
&lt;h4 id="when-langfuse-is-not-the-answer">When Langfuse is not the answer&lt;/h4>
&lt;p>So as not to present it as a silver bullet:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>If you only use LangChain and have no resources to self-host&lt;/strong>: LangSmith will give you a smoother integration (it is the same team).&lt;/li>
&lt;li>&lt;strong>If your only need is a proxy with cost tracking and no evals&lt;/strong>: Helicone is simpler.&lt;/li>
&lt;li>&lt;strong>If you want an integrated commercial vendor solution&lt;/strong>: Datadog LLM Observability, New Relic AI Monitoring or Dynatrace AI are Enterprise alternatives with 24/7 support.&lt;/li>
&lt;li>&lt;strong>If your load is pure batch massive inference with no agents&lt;/strong>: you probably do not need semantic tracing; Prometheus + Grafana with OTel metrics is enough.&lt;/li>
&lt;/ul>
&lt;p>For everything else, your own apps with serious tracing, multi-tenant with quotas, teams iterating on prompts daily, RAG with continuous evaluation, Langfuse is the safe bet.&lt;/p>
&lt;p>&lt;strong>Quick choice summary&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LangChain → LangSmith&lt;/strong> (zero effort, automatic instrumentation).&lt;/li>
&lt;li>&lt;strong>Your own multi-framework applications with OSS → Langfuse&lt;/strong> (MIT, self-host, complete).&lt;/li>
&lt;li>&lt;strong>RAG with vector stores → Arize Phoenix&lt;/strong> (better retrieval visibility).&lt;/li>
&lt;li>&lt;strong>Simple proxy, low budget → Helicone&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Strict vendor neutrality → OpenLLMetry/Traceloop&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Pydantic AI → Logfire&lt;/strong> (same team).&lt;/li>
&lt;/ul>
&lt;h3 id="strengths-and-weaknesses-of-the-instrumented-model">Strengths and weaknesses of the instrumented model&lt;/h3>
&lt;p>&lt;strong>Strengths&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Enormous depth&lt;/strong>: nested spans with all the context (chain steps, retrieval, embeddings, tool calls).&lt;/li>
&lt;li>&lt;strong>Semantic vocabulary&lt;/strong>: the SDK knows the domain (LLM, vector store, agent).&lt;/li>
&lt;li>&lt;strong>Maturity&lt;/strong>: three years of evolution, a rich ecosystem, ready-made dashboards.&lt;/li>
&lt;li>&lt;strong>Built-in evals&lt;/strong>: the top platforms combine tracing with evaluation (judge LLM, datasets, regression).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Weaknesses&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Requires control of the code&lt;/strong>: if you cannot instrument, it does not work.&lt;/li>
&lt;li>&lt;strong>Trust in the app&lt;/strong>: if the app reports badly or has a bug, so does the trace. It is not tamper-proof.&lt;/li>
&lt;li>&lt;strong>Coupling to the SDK&lt;/strong>: version changes in a library can break the instrumentation.&lt;/li>
&lt;li>&lt;strong>Uneven coverage&lt;/strong>: Python SDKs are mature; Go, Rust and JS are younger.&lt;/li>
&lt;/ul>
&lt;h2 id="the-zero-instrumentation-approach-agentsight">The zero-instrumentation approach: AgentSight&lt;/h2>
&lt;p>&lt;a href="https://github.com/eunomia-bpf/agentsight">AgentSight&lt;/a> is the project from the &lt;code>eunomia-bpf&lt;/code> group that champions the opposite approach. Its &lt;a href="https://arxiv.org/abs/2508.02736">paper on arxiv (2508.02736)&lt;/a>, presented at the &lt;em>Workshop on Practical Adoption Challenges of ML for Systems&lt;/em>, formalises the proposal. The premise is direct:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Instead of instrumenting the agent, observe it at the system boundary.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>And &amp;ldquo;system boundary&amp;rdquo; means &lt;strong>the kernel boundary&lt;/strong>: the last point before a piece of data leaves the process towards the network or the filesystem. There, with eBPF, things are seen as they are, without the application being able to cooperate in hiding them.&lt;/p>
&lt;h3 id="architecture-three-planes">Architecture: three planes&lt;/h3>
&lt;p>AgentSight assembles three layers:&lt;/p>
&lt;p>&lt;strong>Plane 1 — SSL/TLS uprobes&lt;/strong>. eBPF can attach programs to functions in &lt;strong>userspace libraries&lt;/strong> (uprobes). The target functions are the encryption ones: &lt;code>SSL_write&lt;/code>, &lt;code>SSL_read&lt;/code> from OpenSSL/BoringSSL, and their equivalents in Rustls. AgentSight puts hooks on them that &lt;strong>capture the arguments&lt;/strong>: the &lt;strong>plaintext&lt;/strong> buffer the app passes to be encrypted, just before TLS processes it. On reception it does the symmetric thing: a hook after &lt;code>SSL_read&lt;/code> with the freshly decrypted plaintext. Result: AgentSight sees the complete content of any HTTPS request the app makes &lt;strong>without needing a man-in-the-middle, certificates or traffic decryption&lt;/strong>. The payload is plaintext because it was captured &lt;strong>before&lt;/strong> being encrypted.&lt;/p>
&lt;p>This works because uprobes are cheap (around 100 ns per invocation) and because apps use common TLS libraries. The few apps that implement their own TLS (rare in production) escape this hook; for those you need a different kprobe or manual instrumentation.&lt;/p>
&lt;p>&lt;strong>Plane 2 — Kernel events&lt;/strong>. In parallel, AgentSight observes relevant syscalls through tracepoints: &lt;code>execve&lt;/code> (which processes start), &lt;code>connect&lt;/code>/&lt;code>accept&lt;/code> (network), &lt;code>read&lt;/code>/&lt;code>write&lt;/code> with file descriptors (filesystem and stdio), &lt;code>unlink&lt;/code>, &lt;code>clone&lt;/code>. Any action by the agent that has an effect outside the process passes through here. This covers, among other things, &lt;strong>shell commands executed by the agent&lt;/strong>: if a Claude Code agent decides to run &lt;code>rm -rf&lt;/code> to &amp;ldquo;clean up the project&amp;rdquo;, the &lt;code>execve&lt;/code> is seen even if the LLM API does not report it.&lt;/p>
&lt;p>&lt;strong>Plane 3 — Correlation engine&lt;/strong>. The two previous planes produce streams of asynchronous events. AgentSight has a userspace component that &lt;strong>correlates them causally cross-process&lt;/strong>: an outgoing HTTP request with &lt;code>bash -c rm -rf&lt;/code> can be correlated with the previous LLM response that suggested it, through PIDs, timings and heuristics. The paper mentions the optional use of &lt;strong>a secondary LLM&lt;/strong> (Anthropic Claude, for instance) that analyses the sequence of events and produces semantic alerts: &amp;ldquo;the agent responded with a tool call that was not in the whitelist&amp;rdquo;, &amp;ldquo;the reasoning chain has gone 47 iterations without converging&amp;rdquo;.&lt;/p>
&lt;h3 id="stdiocap-capturing-the-stdio-of-local-mcp-servers">&lt;code>stdiocap&lt;/code>: capturing the stdio of local MCP servers&lt;/h3>
&lt;p>One specific piece that deserves its own mention is &lt;code>stdiocap&lt;/code>, a separate BPF tool included in the repo. The &lt;strong>Model Context Protocol (MCP)&lt;/strong>, popularised by Anthropic in 2024 and mainstream in 2025-2026, has two transport modes: HTTP/SSE (network) and &lt;strong>stdio&lt;/strong> (between the client and the server it starts as a subprocess). Local MCP servers, the ones that run on the same machine and are started by the client as children over pipes, communicate through stdin/stdout/stderr with JSON-RPC.&lt;/p>
&lt;p>&lt;code>stdiocap&lt;/code> hooks &lt;code>read&lt;/code>/&lt;code>write&lt;/code>/&lt;code>dup&lt;/code> on the stdin/stdout/stderr file descriptors of a target process and &lt;strong>records all the JSON-RPC traffic&lt;/strong> between the MCP client and server. It is the same idea as the SSL capture but for stdio: you observe the conversation without either the client or the server knowing. Typical use case: seeing which tools of the &lt;code>filesystem-mcp&lt;/code> MCP server a Claude Code agent has invoked in the last hour, what arguments it passed, what errors it received. Impossible with classic instrumentation (MCP servers are usually third-party binaries).&lt;/p>
&lt;h3 id="guarantees-tamper-proof-kernel-safety-3-overhead">Guarantees: tamper-proof, kernel safety, &amp;lt;3% overhead&lt;/h3>
&lt;p>Three properties make AgentSight interesting for production:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Tamper-proof&lt;/strong>: the observation happens in the kernel (uprobes, syscalls). A malicious or compromised application cannot falsify what is seen. Compare with instrumentation: if the agent decides not to emit the span for its action, it does not appear in Langfuse. Here it has no choice.&lt;/li>
&lt;li>&lt;strong>Kernel safety&lt;/strong>: eBPF formally verifies that programs terminate and respect bounds checks. It cannot crash the kernel. The same as in the rest of the eBPF series.&lt;/li>
&lt;li>&lt;strong>&amp;lt;3% CPU overhead&lt;/strong> measured on real agent workloads (per the paper). The number compares favourably with SDK instrumentation, which typically adds 5-10% in intensive applications.&lt;/li>
&lt;/ul>
&lt;h3 id="what-it-detects-out-of-the-box">What it detects out of the box&lt;/h3>
&lt;p>The paper and the documentation highlight three classes of detection:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Real-time prompt injection&lt;/strong>: the correlation engine can apply rules or a detection model over the plaintext captured by the SSL uprobes. If the prompt contains suspicious patterns, &amp;ldquo;ignore all previous instructions&amp;rdquo;, a system prompt embedded in a user input, instructions to exfiltrate data, it raises an alert.&lt;/li>
&lt;li>&lt;strong>Reasoning loops that burn resources&lt;/strong>: agents that enter infinite loops calling tools without progressing. Detectable because the causal chain does not converge to a &amp;ldquo;final answer&amp;rdquo; and the tokens pile up. The correlation engine flags them.&lt;/li>
&lt;li>&lt;strong>Bottlenecks in multi-agent setups&lt;/strong>: when several agents coordinate, AgentSight sees the communication matrix between all of them and can detect agents that block while waiting, deadlocks, excessive fan-out.&lt;/li>
&lt;/ul>
&lt;h2 id="the-clash-and-the-coexistence">The clash and the coexistence&lt;/h2>
&lt;p>The two families look like competitors, but in reality they see different things and complement each other in production.&lt;/p>
&lt;h3 id="what-only-the-instrumented-one-sees">What only the instrumented one sees&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Internal agent variables&lt;/strong> that never reach the wire: the intermediate state of a LangChain chain, the values before passing them to a tool, how a prompt is built from a template with internal vars.&lt;/li>
&lt;li>&lt;strong>Deep semantic spans&lt;/strong>: &lt;code>retrieval &amp;gt; embed &amp;gt; vector_search &amp;gt; rerank &amp;gt; format_context &amp;gt; prompt_template &amp;gt; llm&lt;/code>. AgentSight sees only the final call to the LLM; the path taken to build it is invisible.&lt;/li>
&lt;li>&lt;strong>Evaluations&lt;/strong>: scoring of answers, judge LLMs, quality regression. This lives only in instrumented platforms.&lt;/li>
&lt;/ul>
&lt;h3 id="what-only-ebpf-sees">What only eBPF sees&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Opaque binaries&lt;/strong>: Claude Code, Cursor, Gemini CLI, third-party agents. You do not have the code; you cannot instrument them. Only eBPF sees them.&lt;/li>
&lt;li>&lt;strong>System-level actions&lt;/strong>: the agent decides to run &lt;code>git push --force&lt;/code> or &lt;code>kubectl delete&lt;/code>. The action is seen in the &lt;code>execve&lt;/code>. The agent&amp;rsquo;s instrumentation may not report it (especially if it was a command the agent generated as output without going through an explicit &amp;ldquo;tool&amp;rdquo;).&lt;/li>
&lt;li>&lt;strong>Tamper-proof audit&lt;/strong>: for regulatory compliance (HIPAA, SOC2, NIS2), having observation the app cannot dodge has formal value. eBPF provides it.&lt;/li>
&lt;li>&lt;strong>Local MCP servers over stdio&lt;/strong>: invisible to classic instrumentation unless each server emits its own spans (rare).&lt;/li>
&lt;/ul>
&lt;h3 id="what-both-see-complementarily">What both see, complementarily&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Prompts and completions&lt;/strong>: the instrumented approach emits them with rich metadata; eBPF captures them off the wire. A perfect cross-check for spotting discrepancies.&lt;/li>
&lt;li>&lt;strong>Calls to external APIs&lt;/strong>: APM flags it; eBPF confirms it at kernel level.&lt;/li>
&lt;li>&lt;strong>Latency&lt;/strong>: APM per span; eBPF measures RTT at TCP level and network connectivity.&lt;/li>
&lt;/ul>
&lt;h3 id="decision-matrix">Decision matrix&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Case&lt;/th>
&lt;th>Instrumented&lt;/th>
&lt;th>eBPF (AgentSight)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Your own app with LangChain&lt;/td>
&lt;td>&lt;strong>Yes, first&lt;/strong>&lt;/td>
&lt;td>Optional&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Your own multi-framework app&lt;/td>
&lt;td>&lt;strong>Yes&lt;/strong>&lt;/td>
&lt;td>Optional&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Third-party binary (Claude Code, Cursor)&lt;/td>
&lt;td>&lt;strong>Does not work&lt;/strong>&lt;/td>
&lt;td>&lt;strong>Yes, the only path&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tamper-proof regulatory compliance&lt;/td>
&lt;td>Insufficient&lt;/td>
&lt;td>&lt;strong>Yes, required&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Zero-trust multi-tenant&lt;/td>
&lt;td>Insufficient&lt;/td>
&lt;td>&lt;strong>Yes, required&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Local MCP servers (stdio)&lt;/td>
&lt;td>Difficult&lt;/td>
&lt;td>&lt;strong>Yes, with stdiocap&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Answer quality evaluation&lt;/td>
&lt;td>&lt;strong>Yes, required&lt;/strong>&lt;/td>
&lt;td>No (out of scope)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Depth of the internal chain&lt;/td>
&lt;td>&lt;strong>Yes, required&lt;/strong>&lt;/td>
&lt;td>No (a black box for AgentSight)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reasoning loop detection&lt;/td>
&lt;td>Possible with plumbing&lt;/td>
&lt;td>&lt;strong>Yes, built in&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Real-time prompt injection&lt;/td>
&lt;td>Possible (post-processed)&lt;/td>
&lt;td>&lt;strong>Yes, in stream&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The natural conclusion: &lt;strong>for your own apps, instrumented; for opaque binaries or compliance, eBPF; for everything that matters, both&lt;/strong>.&lt;/p>
&lt;h2 id="2026-reference-architecture">2026 reference architecture&lt;/h2>
&lt;p>Four recipes that cover the bulk of real cases:&lt;/p>
&lt;h3 id="setup-a--your-own-application-with-langchain-or-similar">Setup A — Your own application with LangChain or similar&lt;/h3>
&lt;p>Needs: depth, evals, a team comfortable with SDKs.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Langfuse self-host&lt;/strong> or &lt;strong>LangSmith cloud&lt;/strong> as the backend.&lt;/li>
&lt;li>&lt;strong>OpenLLMetry SDK&lt;/strong> or &lt;strong>LangSmith SDK&lt;/strong> instrumenting the code.&lt;/li>
&lt;li>&lt;strong>OpenTelemetry Collector&lt;/strong> between the app and the backend for routing flexibility (to Langfuse + Tempo + Loki, for instance).&lt;/li>
&lt;li>&lt;strong>Hubble&lt;/strong> for the network layer in the cluster (inter-pod latency, drop attribution).&lt;/li>
&lt;/ul>
&lt;h3 id="setup-b--productionising-an-opaque-binary-claude-code-gemini-cli">Setup B — Productionising an opaque binary (Claude Code, Gemini CLI)&lt;/h3>
&lt;p>Needs: observe without touching, audit, control cost.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>AgentSight&lt;/strong> deployed as a DaemonSet over the cluster (or standalone on the node).&lt;/li>
&lt;li>&lt;strong>Grafana with dashboards&lt;/strong> fed by AgentSight&amp;rsquo;s metrics.&lt;/li>
&lt;li>&lt;strong>An OTLP exporter&lt;/strong> from AgentSight to an OTel backend (Tempo, Jaeger). The spans will use the GenAI semantic conventions once they are fully standardised.&lt;/li>
&lt;li>&lt;strong>Tetragon&lt;/strong> optionally for policy over what the agent is allowed to run (Sigkill if it tries &lt;code>rm -rf&lt;/code> or similar).&lt;/li>
&lt;/ul>
&lt;h3 id="setup-c--zero-trust-multi-tenant-platform">Setup C — Zero-trust multi-tenant platform&lt;/h3>
&lt;p>Needs: agents from different clients running on the same cluster, mandatory audit, nobody trusts anybody.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>AgentSight&lt;/strong> as the tamper-proof audit layer. Compliance requires it.&lt;/li>
&lt;li>&lt;strong>Langfuse multi-tenant&lt;/strong> for the clients that do instrument.&lt;/li>
&lt;li>&lt;strong>Tetragon&lt;/strong> with &lt;code>TracingPolicyNamespaced&lt;/code> per tenant (different policies per namespace).&lt;/li>
&lt;li>&lt;strong>Hubble&lt;/strong> with persistent flow logs for forensics.&lt;/li>
&lt;li>&lt;strong>Cilium NetworkPolicy&lt;/strong> to isolate tenants from each other on the network.&lt;/li>
&lt;/ul>
&lt;h3 id="setup-d--a-local-mcp-server-on-a-workstation">Setup D — A local MCP server on a workstation&lt;/h3>
&lt;p>Needs: seeing what an agent does with a stdio MCP server.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>AgentSight stdiocap&lt;/strong> pointed at the PID of the client or the server.&lt;/li>
&lt;li>Complete JSON-RPC capture to a file or to an OTLP endpoint.&lt;/li>
&lt;li>Visualisation: Grafana, or simply &lt;code>jq&lt;/code> over the log.&lt;/li>
&lt;/ul>
&lt;p>A real use case: if you are integrating an MCP server of your own and want to see what tool calls a Claude Code or Cursor agent makes to your server, &lt;code>stdiocap&lt;/code> is the cleanest way. You need to modify neither client nor server.&lt;/p>
&lt;h2 id="operational-traps">Operational traps&lt;/h2>
&lt;h3 id="sensitive-data-in-prompts-instrumented">Sensitive data in prompts (instrumented)&lt;/h3>
&lt;p>By default, Langfuse, LangSmith and similar tools capture &lt;strong>the complete content&lt;/strong> of prompts and completions. If your app processes PII, secrets or medical data, &lt;strong>that goes to your observability backend&lt;/strong>. Configuring &lt;strong>redaction&lt;/strong> or &lt;strong>content opt-out&lt;/strong> before going to production is mandatory. OTel GenAI has specific flags (&lt;code>OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=false&lt;/code>) to avoid it.&lt;/p>
&lt;h3 id="sensitive-data-in-prompts-agentsight">Sensitive data in prompts (AgentSight)&lt;/h3>
&lt;p>The same problem, worse: AgentSight captures &lt;strong>literally what goes to the wire&lt;/strong>, in plaintext. If the agent talked to &lt;code>api.openai.com&lt;/code> with a prompt containing sensitive data, AgentSight has that plaintext. You have to encrypt or redact before storing.&lt;/p>
&lt;h3 id="pinned-certificates-or-non-standard-tls">Pinned certificates or non-standard TLS&lt;/h3>
&lt;p>Some high-security apps do certificate pinning or use unconventional TLS implementations (Go&amp;rsquo;s &lt;code>crypto/tls&lt;/code>, custom BoringSSL). In those cases, the uprobes on &lt;code>libssl&lt;/code> do not cover them. AgentSight detects when it cannot observe and reports the gap; you still have to add specific hooks for the alternative SDK.&lt;/p>
&lt;h3 id="token-volume-and-storage">Token volume and storage&lt;/h3>
&lt;p>An application with medium traffic can generate &lt;strong>millions of tokens a day&lt;/strong>. If you store them all in Langfuse or Phoenix with long retention, the database grows fast. Strategies: aggressive sampling, short retention for normal sessions and long retention only for errors/anomalies, content redaction and keeping only metadata.&lt;/p>
&lt;h3 id="tracing-with-sampling-and-consistency">Tracing with sampling and consistency&lt;/h3>
&lt;p>To cut cost, many installations sample: only 1 in every N traces is persisted. &lt;strong>Be careful with inconsistent sampling&lt;/strong>: a trace can carry several spans across multiple services, and if the sampling decision is taken per span, you end up with incomplete traces. OTel has &lt;strong>head sampling&lt;/strong> (in the SDK, at the start), which is consistent, and &lt;strong>tail sampling&lt;/strong> (in the collector, at the end), which allows finer rules. For LLM, tail sampling is ideal: sample everything, discard only the &amp;ldquo;normal&amp;rdquo; traces and keep the ones with errors, high latency or high cost.&lt;/p>
&lt;h3 id="multi-agent-and-trace-propagation">Multi-agent and trace propagation&lt;/h3>
&lt;p>When agent A calls agent B, you have to &lt;strong>propagate the trace context&lt;/strong> (W3C Trace Context headers) so it shows up as a single tree. If you do not, you see two disconnected traces. Modern platforms do it automatically with &lt;code>inject&lt;/code>/&lt;code>extract&lt;/code>, but if your transport between agents is custom (over Redis pub/sub, over a DB), you have to propagate by hand.&lt;/p>
&lt;h3 id="the-cost-of-uprobes-on-critical-libraries">The cost of uprobes on critical libraries&lt;/h3>
&lt;p>Hooking &lt;code>libssl&lt;/code> adds around 100 ns per invocation. On extreme TLS traffic loads (tens of thousands of connections/s per core), that adds up. AgentSight keeps it under 3% on typical agent workloads (which are chatty but not networking-intensive). If your use were sniffing all the HTTPS on the node, it could hurt more.&lt;/p>
&lt;h2 id="what-we-have-not-covered-next-series">What we have not covered (next series)&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Evals&lt;/strong>: the next layer after tracing. Phoenix, Langfuse, LangSmith and company offer answer evaluation (judge LLM, datasets, regression). It is a world of its own.&lt;/li>
&lt;li>&lt;strong>Guardrails and safety&lt;/strong>: NeMo Guardrails, Llama Guard, Llama Prompt Guard, evaluators specific to prompt injection and jailbreaks.&lt;/li>
&lt;li>&lt;strong>Deep MCP server observability&lt;/strong>: how the OpenTelemetry GenAI conventions are being extended to MCP servers for trace-aware tools.&lt;/li>
&lt;li>&lt;strong>eBPF + on-device inference&lt;/strong>: when the LLM runs locally through vLLM or llama.cpp, the uprobes can see the output token queue BEFORE it goes to the client. New territory.&lt;/li>
&lt;li>&lt;strong>Statistical analysis of agent flows&lt;/strong>: detecting drift, outliers, patterns that indicate degradation.&lt;/li>
&lt;/ul>
&lt;h2 id="closing-the-ebpf-series">Closing the eBPF series&lt;/h2>
&lt;p>This series of four articles has travelled eBPF from first principles to the 2026 frontier:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/ebpf-zero-to-cilium-kernel-tcp-ip-bypass/">eBPF from zero to Cilium&lt;/a> — what eBPF is, networking hooks, how Cilium skips the TCP/IP stack, BGP Control Plane v2.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/tetragon-cilium-security-syscalls-kernel/">Tetragon: runtime security&lt;/a> — observability and enforcement of processes in the kernel.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/hubble-ebpf-network-observability-ai-agents/">Hubble: network observability&lt;/a> — L3-L7 flow logs and the frontier with AI agents.&lt;/li>
&lt;li>&lt;strong>This one&lt;/strong> — AgentSight, LLM tracing, instrumented vs zero-instrumentation.&lt;/li>
&lt;/ol>
&lt;p>If you have got this far you have the map to sit down with a platform, security or AI team in 2026 and recognise what each piece does, what problem it solves and where to start. That whole stack, Cilium for CNI and BGP, Tetragon for runtime security, Hubble for network observability, AgentSight for AI agents, sharing eBPF as a common substrate, Cloud Native governance and OpenTelemetry vocabulary. It is the clean architecture the industry asked for a decade ago and that finally exists.&lt;/p>
&lt;h2 id="references">References&lt;/h2>
&lt;p>AgentSight:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/eunomia-bpf/agentsight">AgentSight GitHub (eunomia-bpf)&lt;/a> — the project.&lt;/li>
&lt;li>&lt;a href="https://arxiv.org/abs/2508.02736">AgentSight: System-Level Observability for AI Agents Using eBPF (arxiv 2508.02736)&lt;/a> — the formal paper.&lt;/li>
&lt;li>&lt;a href="https://dl.acm.org/doi/10.1145/3766882.3767169">AgentSight ACM workshop publication&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://eunomia.dev/blog/2025/08/26/agentsight-keeping-your-ai-agents-under-control-with-ebpf-powered-system-observability/">AgentSight blog post (eunomia.dev)&lt;/a> — accessible description.&lt;/li>
&lt;/ul>
&lt;p>OpenTelemetry GenAI semantic conventions:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/">OpenTelemetry — Semantic conventions for generative AI systems&lt;/a> — official reference.&lt;/li>
&lt;li>&lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/">Semantic conventions for generative client AI spans&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-metrics/">Semantic conventions for generative AI metrics&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://opentelemetry.io/blog/2026/genai-observability/">Inside the LLM Call: GenAI Observability with OpenTelemetry (OTel blog 2026)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://github.com/open-telemetry/semantic-conventions/issues/2664">Multi-agent Semantic Conventions (GitHub issue #2664)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Instrumented platforms:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://langfuse.com/">Langfuse&lt;/a> — MIT, self-host + cloud.&lt;/li>
&lt;li>&lt;a href="https://www.langchain.com/langsmith">LangSmith&lt;/a> — LangChain team.&lt;/li>
&lt;li>&lt;a href="https://phoenix.arize.com/">Arize Phoenix&lt;/a> — OSS, OTel-native.&lt;/li>
&lt;li>&lt;a href="https://www.helicone.ai/">Helicone&lt;/a> — simple proxy.&lt;/li>
&lt;li>&lt;a href="https://github.com/traceloop/openllmetry">OpenLLMetry (Traceloop)&lt;/a> — Apache 2.0, OTel SDK.&lt;/li>
&lt;li>&lt;a href="https://pydantic.dev/docs/logfire/get-started/ai-observability/">Pydantic Logfire — AI observability&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>2026 comparisons:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.braintrust.dev/articles/langfuse-alternatives-2026">Langfuse alternatives 2026 (Braintrust)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.braintrust.dev/articles/best-llm-tracing-tools-2026">7 best LLM tracing tools for multi-agent AI systems (2026)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://medium.com/@kanerika/llmops-observability-langsmith-vs-arize-vs-langfuse-vs-w-b-f1baeabd1bbf">LLMOps Observability: LangSmith vs Arize vs Langfuse vs W&amp;amp;B&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.firecrawl.dev/blog/best-llm-observability-tools">Best LLM Observability Tools in 2026 (Firecrawl)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.spheron.network/blog/llm-observability-gpu-cloud-langfuse-arize-phoenix-helicone/">LLM Observability on GPU Cloud (Spheron 2026 guide)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Cross-references from the series:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/ebpf-zero-to-cilium-kernel-tcp-ip-bypass/">eBPF from zero to Cilium&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/tetragon-cilium-security-syscalls-kernel/">Tetragon: runtime security&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/hubble-ebpf-network-observability-ai-agents/">Hubble: network observability&lt;/a>.&lt;/li>
&lt;li>LLM inference series: &lt;a href="https://blog.lo0.es/en/posts/kv-cache-working-memory-llm-inference/">KV cache&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/vllm-kubernetes-llm-inference-that-scales/">vLLM on Kubernetes&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/pagedattention-vllm-block-manager/">PagedAttention&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/llm-inference-operators-kubernetes/">LLM Operators on K8s&lt;/a>.&lt;/li>
&lt;/ul></description></item></channel></rss>