<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Apache SkyWalking – AI</title>
    <link>/tags/ai/</link>
    <description>Recent content in AI on Apache SkyWalking</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Sun, 05 Apr 2026 00:00:00 +0000</lastBuildDate>
    
	  <atom:link href="/tags/ai/feed.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Blog: Monitoring LLM Applications with SkyWalking 10.4: Insights into Performance and Cost</title>
      <link>/blog/2026-04-05-virtual-genai-monitoring/</link>
      <pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/blog/2026-04-05-virtual-genai-monitoring/</guid>
      <description>
        
        
        &lt;h1 id=&#34;the-problem-as-applications-consume-llms-monitoring-leaves-a-blind-spot&#34;&gt;The Problem: As Applications &amp;ldquo;Consume&amp;rdquo; LLMs, Monitoring Leaves a Blind Spot&lt;/h1&gt;
&lt;p&gt;With the deep penetration of Generative AI (GenAI) into enterprise workflows, developers face a challenging paradox: while powerful LLM capabilities are easily integrated via &lt;code&gt;Spring AI&lt;/code&gt; or &lt;code&gt;OpenAI SDKs&lt;/code&gt;, the actual performance and reliability of these calls remain largely invisible.&lt;/p&gt;
&lt;h3 id=&#34;1-the-black-box-of-cost-and-performance-is-the-expensive-model-worth-it&#34;&gt;1. The &amp;ldquo;Black Box&amp;rdquo; of Cost and Performance: Is the Expensive Model Worth It?&lt;/h3&gt;
&lt;p&gt;Facing high LLM bills, organizations often only see a total sum paid to a provider, but cannot calculate the &amp;ldquo;ROI&amp;rdquo; within the application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blind Upgrades:&lt;/strong&gt; You might switch to a premium flagship model for a better experience. But in your specific business scenario, does paying several times more per token actually yield lower latency or a faster &lt;strong&gt;TTFT (Time to First Token)&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of Real-World Benchmarks:&lt;/strong&gt; Official benchmarks mean little without your real-world business requests. You need to know which model achieves the perfect balance between &amp;ldquo;Token/Cost Consumption&amp;rdquo; and &amp;ldquo;Response Speed&amp;rdquo; under your actual prompt lengths and concurrency levels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-the-vanishing-golden-timeout&#34;&gt;2. The Vanishing &amp;ldquo;Golden Timeout&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;Many teams set timeouts for LLM calls arbitrarily (e.g., 30s or 60s).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Too Short:&lt;/strong&gt; During peak periods or long-text generation, requests are frequently interrupted, causing business failure rates to soar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Too Long:&lt;/strong&gt; If a provider hangs, requests pile up in memory, blocking execution threads and potentially leading to the collapse of the entire Java application or microservice cluster.
Only by mastering the &lt;strong&gt;P99/P95 Latency&lt;/strong&gt; can you set rational timeout policies based on data rather than intuition.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-the-overlooked-experience-killer-ttft&#34;&gt;3. The Overlooked Experience Killer: TTFT&lt;/h3&gt;
&lt;p&gt;In GenAI scenarios, a user&amp;rsquo;s perception of speed depends less on the total duration of the conversation and more on &lt;strong&gt;&amp;ldquo;when the first word appears.&amp;rdquo;&lt;/strong&gt; * A streaming response with a 10s total duration but a &lt;strong&gt;500ms TTFT&lt;/strong&gt; feels instantaneous.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A non-streaming response with a 5s total duration but a &lt;strong&gt;4s TTFT&lt;/strong&gt; feels &amp;ldquo;frozen.&amp;rdquo;
If your observability system only tracks total latency, you miss the core UX metric that explains why users complain about &amp;ldquo;AI slowness.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;SkyWalking 10.4: A &amp;ldquo;Digital Dashboard&amp;rdquo;&lt;/strong&gt;&lt;br&gt;
From the Application Perspective The &lt;strong&gt;Virtual GenAI&lt;/strong&gt; capability introduced in Apache SkyWalking 10.4 fills this &amp;ldquo;observability vacuum.&amp;rdquo; It avoids reliance on external gateways by using application-side probes (like the Java Agent) to collect the most authentic data from the client&amp;rsquo;s perspective.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Precise Latency Distribution:&lt;/strong&gt; Multi-dimensional metrics (P50, P90, P99) help visualize LLM fluctuations to inform dynamic timeout strategies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core UX Metric — TTFT Monitoring:&lt;/strong&gt; Native support for first-token latency in streaming calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-dimensional Model Profiling:&lt;/strong&gt; Aligns token usage, estimated cost, and performance across Providers and Models, helping you choose the most cost-effective solution for your specific needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&#34;virtual-genai-observability&#34;&gt;Virtual GenAI Observability&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Virtual GenAI&lt;/strong&gt; represents Generative AI service nodes detected by probe plugins. All performance metrics are based on the &lt;strong&gt;GenAI Client Perspective&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For instance, the &lt;strong&gt;Spring AI plugin&lt;/strong&gt; in the Java Agent detects the response latency of a Chat Completion request. SkyWalking then visualizes these in the dashboard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Traffic &amp;amp; Success Rate&lt;/strong&gt; (CPM &amp;amp; SLA)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Latency &amp;amp; TTFT&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token Usage&lt;/strong&gt; (Input/Output)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Estimated Cost&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Screenshots:&lt;/strong&gt;
&lt;img src=&#34;provider-dashboard-1.png&#34; alt=&#34;provider-dashboard-1.png&#34;&gt;
&lt;img src=&#34;provider-dashboard-2.png&#34; alt=&#34;provider-dashboard-2.png&#34;&gt;
&lt;img src=&#34;provider-dashboard-3.png&#34; alt=&#34;provider-dashboard-3.png&#34;&gt;
&lt;img src=&#34;model-dashboard-1.png&#34; alt=&#34;model-dashboard-1.png&#34;&gt;
&lt;img src=&#34;model-dashboard-2.png&#34; alt=&#34;model-dashboard-2.png&#34;&gt;
&lt;img src=&#34;model-dashboard-3.png&#34; alt=&#34;model-dashboard-3.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;how-it-works&#34;&gt;How It Works&lt;/h1&gt;
&lt;p&gt;When the SkyWalking Java Agent or OTLP probes intercept calls to mainstream AI frameworks (e.g., Spring AI, OpenAI SDK), they report Trace data to the SkyWalking OAP.
The OAP aggregates and computes this data to generate performance metrics for both &lt;strong&gt;Providers&lt;/strong&gt; and &lt;strong&gt;Models&lt;/strong&gt;, which are then rendered in the built-in Virtual-GenAI dashboards.&lt;/p&gt;
&lt;h1 id=&#34;installation--configuration&#34;&gt;Installation &amp;amp; Configuration&lt;/h1&gt;
&lt;h2 id=&#34;requirements&#34;&gt;Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SkyWalking Java Agent:&lt;/strong&gt; &amp;gt;= 9.7&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SkyWalking OAP:&lt;/strong&gt; &amp;gt;= 10.4&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;semantic-conventions--compatibility&#34;&gt;Semantic Conventions &amp;amp; Compatibility&lt;/h2&gt;
&lt;p&gt;SkyWalking Virtual GenAI follows &lt;strong&gt;OpenTelemetry GenAI Semantic Conventions&lt;/strong&gt;. OAP identifies GenAI-related Spans based on:&lt;/p&gt;
&lt;h3 id=&#34;skywalking-java-agent&#34;&gt;SkyWalking Java Agent&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Spans must be of type Exit, have the SpanLayer attribute set to GENAI, and contain the gen_ai.response.model tag.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;otlp--zipkin-probes&#34;&gt;OTLP / Zipkin Probes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Spans must contain the &lt;code&gt;gen_ai.response.model&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For details, refer to the E2E configurations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/test/e2e-v2/cases/virtual-genai/docker-compose.yml&#34;&gt;SkyWalking Java Agent Reporting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/test/e2e-v2/cases/otlp-virtual-genai/docker-compose.yml&#34;&gt;Probe Reporting OTLP Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/test/e2e-v2/cases/zipkin-virtual-genai/docker-compose.yml&#34;&gt;Probe Reporting Zipkin Data&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&#34;genai-estimated-cost-configuration&#34;&gt;GenAI Estimated Cost Configuration&lt;/h1&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;SkyWalking provides a built-in &lt;a href=&#34;https://github.com/apache/skywalking/blob/master/oap-server/server-starter/src/main/resources/gen-ai-config.yml&#34;&gt;GenAI Billing Configuration File&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This file defines how SkyWalking maps model names from Trace data to their corresponding providers and estimates the token cost for each LLM call. The estimated cost is displayed in the SkyWalking UI alongside trace and metric data, helping users intuitively understand the financial impact of their GenAI usage.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The pricing in this file is intended for cost estimation only and must not be treated as actual billing or invoice amounts. Users are advised to regularly verify the latest rates on the providers&amp;rsquo; official pricing pages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;configuration-structure&#34;&gt;Configuration Structure&lt;/h2&gt;
&lt;h3 id=&#34;top-level-fields&#34;&gt;Top-level Fields&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Field&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Type&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Description&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;last-updated&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;date&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;The last update date of the pricing data. All prices are based on public billing standards announced by providers prior to this date.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;providers&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;List of GenAI provider definitions. Each entry contains matching rules and specific model pricing information.&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;provider-definition&#34;&gt;Provider Definition&lt;/h3&gt;
&lt;p&gt;Each entry under &lt;code&gt;providers&lt;/code&gt; defines a GenAI provider:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;providers&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;provider-name&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &amp;lt;prefix-1&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &amp;lt;prefix-2&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;models&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;model-name&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;aliases&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&amp;lt;alias-1&amp;gt;, &amp;lt;alias-2&amp;gt;]&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;cost&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;cost&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Field&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Type&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Required&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Description&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Yes&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;The provider identifier (e.g., &lt;code&gt;openai&lt;/code&gt;, &lt;code&gt;anthropic&lt;/code&gt;, &lt;code&gt;gemini&lt;/code&gt;). It is displayed as the Virtual GenAI service name in SkyWalking.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;prefix-match&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list[string]&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Yes&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;A list of prefixes used to match model names to this provider. If a model name in the Trace data starts with any of these prefixes, it will be mapped to this provider.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;models&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list[model]&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;No&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;A list of model definitions containing pricing information. If omitted, the system can still identify the provider but will not perform cost estimation.&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;model-definition&#34;&gt;Model Definition&lt;/h3&gt;
&lt;p&gt;Each entry under &lt;code&gt;models&lt;/code&gt; defines the pricing for a specific model:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Field&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Type&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Required&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Description&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Yes&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;The standard model name used for matching.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;aliases&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list[string]&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;No&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Alternative names that should resolve to the same billing entry. This is useful when providers use different naming conventions (see the &amp;ldquo;Model Aliases&amp;rdquo; section).&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;input-estimated-cost-per-m&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;No&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated cost per 1,000,000 (one million) input (Prompt) tokens. The default unit is USD.&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;output-estimated-cost-per-m&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;No&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated cost per 1,000,000 (one million) output (Completion) tokens. The default unit is USD.&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;model-matching-mechanism&#34;&gt;Model Matching Mechanism&lt;/h2&gt;
&lt;h3 id=&#34;provider-level-prefix-matching&#34;&gt;Provider-Level Prefix Matching&lt;/h3&gt;
&lt;p&gt;When SkyWalking receives a Trace containing a GenAI call, it determines the &lt;strong&gt;Provider&lt;/strong&gt; based on the following priority order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;gen_ai.provider.name&lt;/code&gt; tag&lt;/strong&gt;: This tag is retrieved first. It follows the latest &lt;code&gt;OpenTelemetry&lt;/code&gt; GenAI semantic conventions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;gen_ai.system&lt;/code&gt; tag&lt;/strong&gt;: If the above tag is missing, the system falls back to this legacy tag. Note: This tag is only parsed when processing OTLP or Zipkin format data, primarily for compatibility with older versions of libraries like the Python auto-instrumentation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefix Matching&lt;/strong&gt;: If neither of the above tags exists, &lt;code&gt;SkyWalking&lt;/code&gt; reads the &lt;code&gt;prefix-match&lt;/code&gt; rules defined in &lt;code&gt;gen-ai-config.yml&lt;/code&gt; and attempts to identify the provider by matching the &lt;strong&gt;Model Name&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;openai&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- gpt&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Any model name starting with &lt;strong&gt;gpt&lt;/strong&gt; (such as &lt;strong&gt;gpt-4o&lt;/strong&gt;, &lt;strong&gt;gpt-4.1-mini&lt;/strong&gt;, or &lt;strong&gt;gpt-5-nano&lt;/strong&gt;) will be mapped to the &lt;strong&gt;openai&lt;/strong&gt; provider.
A single provider can have multiple prefixes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;tencent&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- hunyuan&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- Tencent&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;model-level-longest-prefix-matching&#34;&gt;Model-level Longest-Prefix Matching&lt;/h3&gt;
&lt;p&gt;Once the provider is determined, SkyWalking uses a Trie-based longest-prefix matching algorithm to find the best billing entry. This is crucial because model names returned in provider API responses often include version numbers or timestamps, differing from the base model name in the config.
Example OpenAI config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;models&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;gpt-4o&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;2.5&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;10.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;gpt-4o-mini&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.15&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.6&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Matching behavior:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Model Name in Trace&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Matched Configuration Entry&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Reason&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Exact match&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-2024-08-06&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Longest prefix is &lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Exact match (Longer prefix &lt;code&gt;gpt-4o-mini&lt;/code&gt; takes priority over &lt;code&gt;gpt-4o&lt;/code&gt;)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini-2024-07-18&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Longest prefix is &lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This mechanism ensures versioned API model names map to the correct pricing tier without requiring exact full names in the configuration file.&lt;/p&gt;
&lt;h3 id=&#34;model-aliases&#34;&gt;Model Aliases&lt;/h3&gt;
&lt;p&gt;Some providers use different naming conventions across API responses and documentation. For example, Anthropic&amp;rsquo;s model might appear as &lt;code&gt;claude-4-sonnet&lt;/code&gt; or &lt;code&gt;claude-sonnet-4&lt;/code&gt;. The aliases field supports both formats under a single billing entry:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;claude-4-sonnet&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;aliases&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;claude-sonnet-4]&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;3.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;15.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Under this configuration, &lt;code&gt;claude-4-sonnet&lt;/code&gt; and &lt;code&gt;claude-sonnet-4&lt;/code&gt; (as well as any versioned variants, such as &lt;code&gt;claude-sonnet-4-20250514&lt;/code&gt;) will resolve to the same &lt;strong&gt;billing entry&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Aliases also participate in &lt;strong&gt;longest prefix matching&lt;/strong&gt;. Therefore, &lt;code&gt;claude-sonnet-4-20250514&lt;/code&gt; will match the alias &lt;code&gt;claude-sonnet-4&lt;/code&gt;, which in turn resolves to the pricing information for &lt;code&gt;claude-4-sonnet&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;custom-configuration&#34;&gt;Custom Configuration&lt;/h2&gt;
&lt;h3 id=&#34;adding-a-new-provider&#34;&gt;Adding a New Provider&lt;/h3&gt;
&lt;p&gt;To add a provider that is not included in the default configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;providers&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# ... Existing providers ...&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;ollama&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- mymodel&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;models&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;mymodel-large&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;1.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;5.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;mymodel-small&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.5&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For OTLP/Zipkin data, a dedicated estimated tag has been added. You can now view the cost of each GenAI call directly on the UI.
&lt;img src=&#34;otlp-estimated-tag.png&#34; alt=&#34;otlp-estimated-tag&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;main-metrics&#34;&gt;Main Metrics&lt;/h1&gt;
&lt;h2 id=&#34;1provider-level&#34;&gt;1.Provider Level&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Metric ID&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Description&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Meaning&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_cpm&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Calls Per Minute&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Requests per minute (Throughput)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_sla&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Success Rate&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Request success rate&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_resp_time&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Avg Response Time&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Average response time&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_latency_percentile&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Latency Percentiles&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Response time percentiles (P50, P75, P90, P95, P99)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_input_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Input Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Total and average input token usage&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_output_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Output Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Total and average output token usage&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_total_estimated_cost/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated Cost&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Total estimated cost and average cost per call&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;2-model-level&#34;&gt;2. Model Level&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Metric ID&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Description&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Meaning&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_call_cpm&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Calls Per Minute&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Requests per minute for this specific model&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_sla&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Success Rate&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Model-specific request success rate&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_latency_avg/percentile&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Latency&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Average and percentiles of model response duration&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_ttft_avg/percentile&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;TTFT&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Time to First Token (Streaming only)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_input_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Input Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Detailed input token consumption for the model&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_output_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Output Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Detailed output token consumption for the model&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_total_estimated_cost/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated Cost&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated total cost and average cost for the model&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;recommended-usage-scenarios&#34;&gt;Recommended Usage Scenarios&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Performance Evaluation: Use Latency and Time to First Token (TTFT) metrics to analyze model inference efficiency and the end-user interaction experience.&lt;/li&gt;
&lt;li&gt;Token Monitoring: Real-time monitoring of Input and Output token consumption to analyze resource utilization across different business scenarios.&lt;/li&gt;
&lt;li&gt;Cost Alerting: Set alert thresholds based on Estimated Cost or token consumption to promptly detect abnormal calls and prevent budget overruns.&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Zh: 基于 SkyWalking 10.4 的大模型应用监控：洞察 LLM 的性能与成本</title>
      <link>/zh/2026-04-05-virtual-genai-monitoring/</link>
      <pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/zh/2026-04-05-virtual-genai-monitoring/</guid>
      <description>
        
        
        &lt;h1 id=&#34;问题当应用开始吞噬大模型监控却留下了盲区&#34;&gt;问题：当应用开始“吞噬”大模型，监控却留下了盲区&lt;/h1&gt;
&lt;p&gt;随着生成式 AI（GenAI）在企业业务中的深度渗透，开发者正面临一个尴尬的局面：我们在应用中通过&lt;code&gt;Spring AI&lt;/code&gt;或&lt;code&gt;OpenAI SDK&lt;/code&gt;快速集成了强大的大模型能力，但对于这些调用的实际表现却几乎一无所知。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;成本与性能的“黑盒”：昂贵的模型真的更具性价比吗？&lt;/strong&gt;&lt;br&gt;
面对高昂的大模型账单，我们往往只知道把钱交给了某个&lt;code&gt;Provider&lt;/code&gt;，却算不清这笔账在应用内部的“投入产出比”。
盲目的选型升级：为了追求更好的体验，你可能将业务默认切换到了成本更高的旗舰模型。但在具体的业务场景下，花费数倍的 Token 成本，它真的能在真实请求中带来更低的延迟和更快的 TTFT(Time to First Token) 吗？
缺乏真实的评估基准：脱离了真实的业务请求，单纯看官网的 Benchmark 意义不大，你需要知道在实际的 Prompt 长度和并发压力下，同一&lt;code&gt;Provider&lt;/code&gt;下的哪个模型能在“Token/Cost 消耗”与“响应速度”之间达到完美的平衡。如果没有应用侧的数据支撑，你根本无从判断哪款模型才是当前业务的最优解。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;消失的“黄金超时时间”&lt;/strong&gt;&lt;br&gt;
很多团队在代码里给 LLM 调用设置超时（Timeout）时，往往是拍脑袋决定（比如 30s 或 60s）。&lt;br&gt;
设太短：长文本生成或模型高峰期时，请求会被频繁强行中断，导致业务失败率飙升。&lt;br&gt;
设太长：如果下游供应商出现故障（卡死），大量的请求会堆积在应用内存中，阻塞执行线程，最终导致整个 Java 应用甚至微服务集群的瘫痪。
只有真正掌握了预估的整体调用延迟（P99/P95 Latency），你才能基于数据而非直觉，为不同模型设置最合理的超时策略。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;被忽视的体验杀手：TTFT&lt;/strong&gt;&lt;br&gt;
在 GenAI 场景下，用户对“快”的感知并不完全取决于整个对话结束的总耗时，而取决于**“第一行字什么时候跳出来”**。
一个总耗时 10 秒但 TTFT 仅 500ms 的流式响应，给用户的观感是“秒回”。
一个总耗时 5 秒但 TTFT 需要 4s 的非流式响应，给用户的观感却是“卡死”。
如果你的观测系统只能看到总耗时，你就会漏掉最核心的 UX 指标，无法解释为什么用户反馈“AI 很慢”即便总耗时看起来还行。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;SkyWalking 10.4：应用视角的“数字仪表盘”&lt;/strong&gt;&lt;br&gt;
Apache SkyWalking 自 10.4 版本引入的 Virtual GenAI 能力，正是为了解决应用层侧的这种“观测真空”。它不依赖任何外部网关，直接通过应用侧探针（如 Java Agent）在客户端视角采集最真实的数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;精准的延迟分布（Latency Percentiles）：通过 P50、P90、P99 等多维指标，帮你勾勒出 LLM 调用的真实波动曲线，为设置“动态超时时间”提供科学依据。&lt;/li&gt;
&lt;li&gt;核心 UX 指标——TTFT 监控：原生支持流式（Streaming）调用的首字延迟统计。通过对比不同 Provider 或不同模型的 TTFT，你可以优化提示词（Prompt）策略或切换更快的模型，确保用户体验始终在线。&lt;/li&gt;
&lt;li&gt;多维度的模型“画像”分析：在 Provider 和 Model 两个维度上，将 Token 消耗、预估成本与性能指标深度对齐。这让你不再看供应商全网的“理想平均数”，而是看清你的应用在调用特定模型时的真实表现，从而在复杂的模型生态中选出最具性价比的选型方案。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;虚拟-genai-观测&#34;&gt;虚拟 GenAI 观测&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;虚拟 GenAI&lt;/strong&gt; 代表了由探针插件检测到的生成式 AI 服务节点。GenAI 操作的性能指标均基于 &lt;strong&gt;GenAI 客户端视角&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如，Java 探针中的 &lt;strong&gt;Spring AI 插件&lt;/strong&gt;可以检测一次对话补全（Chat Completion）请求的响应延迟。随后，SkyWalking 将在仪表盘中展示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;流量与成功率&lt;/strong&gt; (CPM &amp;amp; SLA)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;响应延迟&lt;/strong&gt; (Latency &amp;amp; TTFT)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token 消耗&lt;/strong&gt; (Input/Output)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预估成本&lt;/strong&gt; (Estimated Cost)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如图：
&lt;img src=&#34;provider-dashboard-1.png&#34; alt=&#34;provider-dashboard-1.png&#34;&gt;
&lt;img src=&#34;provider-dashboard-2.png&#34; alt=&#34;provider-dashboard-2.png&#34;&gt;
&lt;img src=&#34;provider-dashboard-3.png&#34; alt=&#34;provider-dashboard-3.png&#34;&gt;
&lt;img src=&#34;model-dashboard-1.png&#34; alt=&#34;model-dashboard-1.png&#34;&gt;
&lt;img src=&#34;model-dashboard-2.png&#34; alt=&#34;model-dashboard-2.png&#34;&gt;
&lt;img src=&#34;model-dashboard-3.png&#34; alt=&#34;model-dashboard-3.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;原理&#34;&gt;原理&lt;/h1&gt;
&lt;p&gt;当 SkyWalking Java Agent 或 OTLP 探针拦截到主流 AI 框架（如 Spring AI、OpenAI SDK 等）的调用时，将Trace 数据上报至 SkyWalking OAP。
OAP会基于这些 Trace 自动完成数据的聚合与计算。最终会生成 Provider（服务商）与 Model（模型）两个维度的各类性能指标，并直接渲染填充至内置的 Virtual-GenAI 仪表盘中。&lt;/p&gt;
&lt;h1 id=&#34;安装配置&#34;&gt;安装配置&lt;/h1&gt;
&lt;h2 id=&#34;要求&#34;&gt;要求&lt;/h2&gt;
&lt;h3 id=&#34;版本要求&#34;&gt;版本要求&lt;/h3&gt;
&lt;p&gt;● SkyWalking Java Agent: &amp;gt;= 9.7
● SkyWalking Oap: &amp;gt;= 10.4&lt;/p&gt;
&lt;h3 id=&#34;语义规范与兼容性&#34;&gt;语义规范与兼容性&lt;/h3&gt;
&lt;p&gt;SkyWalking 虚拟 GenAI 遵循&lt;code&gt; OpenTelemetry GenAI&lt;/code&gt; 语义规范。OAP 将根据以下标准识别 GenAI 相关 Span：&lt;/p&gt;
&lt;h4 id=&#34;skywalking-java-agent&#34;&gt;SkyWalking Java Agent&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;上报的 Span 必须为 Exit 类型，其 SpanLayer 属性需设定为 GENAI,包含&lt;code&gt;gen_ai.response.model&lt;/code&gt; 标签。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;输出otlp--zipkin格式数据的探针&#34;&gt;输出OTLP / Zipkin格式数据的探针&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;上报的 Span 中包含 &lt;code&gt;gen_ai.response.model&lt;/code&gt; 标签。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体可以参考e2e配置&lt;br&gt;
&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/test/e2e-v2/cases/virtual-genai/docker-compose.yml&#34;&gt;SkyWalking Java Agent上报数据&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/test/e2e-v2/cases/otlp-virtual-genai/docker-compose.yml&#34;&gt;探针上报OTLP格式数据&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/test/e2e-v2/cases/zipkin-virtual-genai/docker-compose.yml&#34;&gt;探针上报Zipkin格式数据&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;genai-预估成本配置&#34;&gt;GenAI 预估成本配置&lt;/h1&gt;
&lt;h2 id=&#34;概览&#34;&gt;概览&lt;/h2&gt;
&lt;p&gt;SkyWalking 提供了一个内置的&lt;a href=&#34;https://github.com/apache/skywalking/blob/master/oap-server/server-starter/src/main/resources/gen-ai-config.yml&#34;&gt;GenAI计费配置文件&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;该配置定义了SkyWalking 如何将 Trace 数据中的模型名称映射到对应的供应商，并估算每次 LLM 调用的 Token 成本。估算成本将与 Trace 和指标数据一起显示在 SkyWalking UI 中，帮助用户直观了解 GenAI 使用带来的 预估费用影响。
重要提示: 此文件中的定价仅用于成本估算，不得视为实际账单或发票金额。建议用户定期从供应商官方定价页面核实最新费率。&lt;/p&gt;
&lt;h2 id=&#34;配置结构&#34;&gt;配置结构&lt;/h2&gt;
&lt;h3 id=&#34;top-字段&#34;&gt;Top 字段&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;字段&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;类型&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;描述&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;last-updated&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;date&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;定价数据的最后更新日期。所有价格均基于该日期前各厂商官网公布的公开计费标准。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;providers&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;GenAI 厂商定义列表。每个厂商条目下包含匹配规则（matching rules）以及具体的模型计费信息（model pricing）。&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;provider-定义&#34;&gt;provider 定义&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;providers&lt;/code&gt; 下的每个条目定义一个 GenAI 供应商：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;providers&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;provider-name&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &amp;lt;prefix-1&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &amp;lt;prefix-2&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;models&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;model-name&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;aliases&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&amp;lt;alias-1&amp;gt;, &amp;lt;alias-2&amp;gt;]&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;cost&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&amp;lt;cost&amp;gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;字段 (Field)&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;类型 (Type)&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;必填 (Required)&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;描述 (Description)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;是&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;供应商标识（如 &lt;code&gt;openai&lt;/code&gt;, &lt;code&gt;anthropic&lt;/code&gt;, &lt;code&gt;gemini&lt;/code&gt;）。在 SkyWalking 中作为虚拟 GenAI 服务名显示。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;prefix-match&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list[string]&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;是&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;用于将模型名称匹配到该供应商的前缀列表。如果 Trace 数据中的模型名以其中任一前缀开头，则会被映射到该供应商。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;models&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list[model]&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;否&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;包含定价信息的模型定义列表。如果省略，系统仍能识别供应商，但不会进行成本估算。&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;model-定义&#34;&gt;model 定义&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;models&lt;/code&gt; 下的每个条目定义特定模型的定价：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;字段 (Field)&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;类型 (Type)&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;必填 (Required)&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;描述 (Description)&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;是&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;用于匹配的标准模型名称。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;aliases&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;list[string]&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;否&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;应解析为同一计费条目的备选名称。当供应商使用不同的命名习惯时非常有用（参见“模型别名”部分）。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;input-estimated-cost-per-m&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;否&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;每 1,000,000（一百万）输入（Prompt）Token 的预估成本。默认单位为 USD。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;output-estimated-cost-per-m&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;否&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;每 1,000,000（一百万）输出（Completion）Token 的预估成本。默认单位为 USD。&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;模型匹配机制&#34;&gt;模型匹配机制&lt;/h2&gt;
&lt;h3 id=&#34;供应商级前缀匹配&#34;&gt;供应商级前缀匹配&lt;/h3&gt;
&lt;p&gt;当 SkyWalking 接收到包含 GenAI 调用的 Trace 时，会按照以下优先级顺序来确定供应商（Provider）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gen_ai.provider.name&lt;/code&gt; 标签：首先检索此标签。它是&lt;code&gt;OpenTelemetry&lt;/code&gt;最新的语义规范。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gen_ai.system&lt;/code&gt; 标签：如果缺少上述标签，系统将回退到此旧版（Legacy）标签。注意：此标签仅在处理 OTLP 或 Zipkin 协议的数据时会被解析，主要用于兼容旧版的 Python 自动仪表化等库。&lt;/li&gt;
&lt;li&gt;前缀匹配 (Prefix Matching)：若上述两个标签均不存在，&lt;code&gt;SkyWalking&lt;/code&gt; 会读取 &lt;code&gt;gen-ai-config.yml&lt;/code&gt; 中定义的 prefix-match 规则，通过匹配 模型名称 (Model Name) 来尝试识别供应商。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;openai&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- gpt&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;任何以 gpt 开头的模型名称（如 gpt-4o, gpt-4.1-mini, gpt-5-nano）都会被映射到 openai 供应商。
一个供应商可以拥有多个前缀：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;tencent&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- hunyuan&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- Tencent&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;模型级最长前缀匹配-model-level-longest-prefix-matching&#34;&gt;模型级最长前缀匹配 (Model-Level Longest-Prefix Matching)&lt;/h3&gt;
&lt;p&gt;一旦确定了供应商，SkyWalking 会使用基于前缀树 (Trie) 的最长前缀匹配算法来查找最佳的模型计费条目。这至关重要，因为 LLM 供应商在 API 响应中返回的模型名称通常包含版本号或时间戳，与配置中的基础模型名称有所不同。
示例： 假设 OpenAI 的配置条目如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;models&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;gpt-4o&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;2.5&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;10.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;gpt-4o-mini&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.15&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.6&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其匹配行为如下表所示：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Trace 中的模型名称&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;匹配的配置条目&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;原因&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;完全匹配&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-2024-08-06&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;最长前缀为 &lt;code&gt;gpt-4o&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;完全匹配（比 &lt;code&gt;gpt-4o&lt;/code&gt; 更长的前缀优先）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini-2024-07-18&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;最长前缀为 &lt;code&gt;gpt-4o-mini&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这种机制确保了 API 返回的带有版本的模型名称能够被正确映射到相应的价格档位，而无需在配置文件中维护精确的全名。&lt;/p&gt;
&lt;h3 id=&#34;模型别名-model-aliases&#34;&gt;模型别名 (Model Aliases)&lt;/h3&gt;
&lt;p&gt;部分供应商在 API 响应和官方文档中会使用不同的命名规范。例如，Anthropic 的模型在 Trace 中可能显示为 claude-4-sonnet 或 claude-sonnet-4。通过 aliases 字段，可以让单个计费条目同时支持这两种配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;claude-4-sonnet&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;aliases&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;claude-sonnet-4]&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;3.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;15.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这种配置下，&lt;code&gt;claude-4-sonnet&lt;/code&gt; 和 &lt;code&gt;claude-sonnet-4&lt;/code&gt;（以及任何带有版本的变体，如 &lt;code&gt;claude-sonnet-4-20250514&lt;/code&gt;）都会解析为同一个计费条目。&lt;br&gt;
&lt;strong&gt;注意&lt;/strong&gt;： 别名同样参与最长前缀匹配。因此，&lt;code&gt;claude-sonnet-4-20250514&lt;/code&gt; 会匹配到别名 &lt;code&gt;claude-sonnet-4&lt;/code&gt;，进而解析到 &lt;code&gt;claude-4-sonnet&lt;/code&gt; 的定价信息。&lt;/p&gt;
&lt;h2 id=&#34;自定义配置&#34;&gt;自定义配置&lt;/h2&gt;
&lt;p&gt;添加新供应商 (Adding a New Provider)
要添加默认配置中未包含的供应商：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;providers&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# ... 现有供应商 ...&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;provider&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;ollama&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;prefix-match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- mymodel&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;models&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;mymodel-large&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;1.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;5.0&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;- &lt;span style=&#34;color:#0550ae&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;mymodel-small&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;input-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;output-estimated-cost-per-m&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0.5&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;针对OTLP/zipkin的数据，新增了单独的estimated tag, 可以在UI上看到这次GenAI调用消耗的cost。&lt;br&gt;
&lt;img src=&#34;otlp-estimated-tag.png&#34; alt=&#34;otlp-estimated-tag&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;主要指标&#34;&gt;主要指标&lt;/h1&gt;
&lt;h2 id=&#34;1-provider-level-服务商维度&#34;&gt;1. Provider Level (服务商维度)&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;指标 ID&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;描述&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;含义&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_cpm&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Calls Per Minute&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;每分钟请求数 (吞吐量)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_sla&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Success Rate&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;请求成功率&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_resp_time&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Avg Response Time&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;平均响应耗时&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_latency_percentile&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Latency Percentiles&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;响应耗时百分位数 (P50, P75, P90, P95, P99)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_input_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Input Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;输入 Token 的总和及平均值&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_output_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Output Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;输出 Token 的总和及平均值&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_provider_total_estimated_cost/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated Cost&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;预估总成本及次均成本&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;2-model-level-模型维度&#34;&gt;2. Model Level (模型维度)&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;指标 ID&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;描述&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;含义&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_call_cpm&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Calls Per Minute&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;该特定模型的每分钟请求数&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_sla&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Success Rate&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;模型请求成功率&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_latency_avg/percentile&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Latency&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;模型响应耗时的平均值及百分位数&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_ttft_avg/percentile&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;TTFT&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;首个token响应时间 (仅限流式传输 Streaming)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_input_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Input Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;该模型的输入 Token 消耗详情&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_output_tokens_sum/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Output Token Usage&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;该模型的输出 Token 消耗详情&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;gen_ai_model_total_estimated_cost/avg&lt;/code&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Estimated Cost&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;该模型的预估总成本及次均成本&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;建议使用场景&#34;&gt;建议使用场景&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;性能评估：利用 响应延迟（Latency） 和 首字响应时间（TTFT） 指标，分析模型推理效率及终端用户交互体验。&lt;/li&gt;
&lt;li&gt;Token 监控：实时监控 输入（Input）与输出（Output）Token 的消耗，用于分析不同业务场景下的资源占用情况。&lt;/li&gt;
&lt;li&gt;成本预警：支持基于 预估成本（Cost） 或 Token 消耗量 配置告警阈值，及时发现异常调用，防止成本超支。&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Blog: Monitoring Envoy AI Gateway with Apache SkyWalking</title>
      <link>/blog/2026-04-02-envoy-ai-gateway-monitoring/</link>
      <pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/blog/2026-04-02-envoy-ai-gateway-monitoring/</guid>
      <description>
        
        
        &lt;h2 id=&#34;the-problem-flying-blind-with-llm-traffic&#34;&gt;The Problem: Flying Blind with LLM Traffic&lt;/h2&gt;
&lt;p&gt;LLM traffic is becoming a first-class citizen in production infrastructure. Teams are calling OpenAI, Anthropic,
AWS Bedrock, Azure OpenAI, Google Gemini — often multiple providers at once. But most organizations have
no unified visibility into this traffic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Token costs spiral&lt;/strong&gt; without knowing which teams, models, or providers drive the spend.
A single misconfigured prompt template can burn through thousands of dollars before anyone notices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provider outages cause cascading failures.&lt;/strong&gt; When OpenAI has a bad hour, your application goes down
with it — and you have no failover visibility to understand what happened or switch providers automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No unified metrics&lt;/strong&gt; across heterogeneous LLM calls. Latency, Time to First Token (TTFT),
Time Per Output Token (TPOT), token usage, error rates — each provider reports these differently,
if at all. There is no single dashboard to compare them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the same observability gap that microservices faced a decade ago. The solution then was
service meshes and API gateways with built-in telemetry. For AI workloads, the answer is an AI gateway.&lt;/p&gt;
&lt;h2 id=&#34;why-an-ai-gateway&#34;&gt;Why an AI Gateway&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://aigateway.envoyproxy.io/&#34;&gt;Envoy AI Gateway&lt;/a&gt; is an open-source AI gateway built on top of
&lt;a href=&#34;https://www.envoyproxy.io/&#34;&gt;Envoy Proxy&lt;/a&gt; and &lt;a href=&#34;https://gateway.envoyproxy.io/&#34;&gt;Envoy Gateway&lt;/a&gt;.
It is not a standalone SaaS product or a Python proxy — it is infrastructure-grade software built on
the same Envoy that already handles traffic for a large portion of cloud-native deployments.&lt;/p&gt;
&lt;p&gt;Key capabilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-provider routing&lt;/strong&gt; — supports 16+ AI providers (OpenAI, Anthropic, AWS Bedrock, Azure OpenAI,
Google Gemini, Mistral, Cohere, DeepSeek, and more) behind a unified API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token-based rate limiting&lt;/strong&gt; — rate limit by token consumption, not just request count.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provider fallback&lt;/strong&gt; — automatic failover when a provider is down or slow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model virtualization&lt;/strong&gt; — abstract model names so applications are decoupled from specific providers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two-tier architecture&lt;/strong&gt; — a reference architecture with a centralized entry gateway (Tier 1) for
auth and global routing, and per-cluster gateways (Tier 2) for inference optimization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CNCF ecosystem native&lt;/strong&gt; — runs on Kubernetes, composes with existing Envoy filters, WASM plugins,
and standard Kubernetes Gateway API resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because Envoy AI Gateway natively emits GenAI metrics and access logs via OTLP following
&lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/&#34;&gt;OpenTelemetry GenAI Semantic Conventions&lt;/a&gt;,
it plugs directly into any OpenTelemetry-compatible backend.&lt;/p&gt;
&lt;p&gt;Starting from SkyWalking 10.4.0, the OAP server natively receives and analyzes Envoy AI Gateway&amp;rsquo;s
OTLP metrics and access logs — no OpenTelemetry Collector needed in between.&lt;/p&gt;
&lt;h2 id=&#34;data-flow&#34;&gt;Data Flow&lt;/h2&gt;
&lt;p&gt;The AI Gateway pushes telemetry directly to SkyWalking via OTLP gRPC:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;workflow.jpg&#34; alt=&#34;Data flow&#34;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Application&lt;/strong&gt; sends LLM API requests through the Envoy AI Gateway.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Envoy AI Gateway&lt;/strong&gt; routes requests to AI providers (or local models like Ollama)
and records GenAI metrics (token usage, latency, TTFT, TPOT) and access logs.&lt;/li&gt;
&lt;li&gt;The gateway pushes metrics and logs via &lt;strong&gt;OTLP gRPC&lt;/strong&gt; directly to &lt;strong&gt;SkyWalking OAP&lt;/strong&gt; on port 11800.&lt;/li&gt;
&lt;li&gt;SkyWalking OAP parses metrics with MAL rules and access logs with LAL rules,
then stores everything in &lt;strong&gt;BanyanDB&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No OpenTelemetry Collector is needed. SkyWalking OAP&amp;rsquo;s built-in OTLP receiver handles everything.&lt;/p&gt;
&lt;h2 id=&#34;try-it-locally&#34;&gt;Try It Locally&lt;/h2&gt;
&lt;p&gt;This demo uses &lt;a href=&#34;https://ollama.com/&#34;&gt;Ollama&lt;/a&gt; as a local LLM backend so you can try
everything without an API key. The &lt;a href=&#34;https://github.com/envoyproxy/ai-gateway/tree/main/cmd/aigw&#34;&gt;Envoy AI Gateway CLI&lt;/a&gt;
(&lt;code&gt;aigw&lt;/code&gt;) provides a standalone mode that runs outside Kubernetes — perfect for local testing.&lt;/p&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Docker and Docker Compose&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ollama.com/&#34;&gt;Ollama&lt;/a&gt; installed on your host&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;step-1-start-ollama&#34;&gt;Step 1: Start Ollama&lt;/h3&gt;
&lt;p&gt;Start Ollama on all interfaces so Docker containers can reach it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#953800&#34;&gt;OLLAMA_HOST&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;0.0.0.0 ollama serve
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pull a small model for testing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ollama pull llama3.2:1b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step-2-start-the-stack&#34;&gt;Step 2: Start the Stack&lt;/h3&gt;
&lt;p&gt;Create a &lt;code&gt;docker-compose.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;banyandb&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;apache/skywalking-banyandb:0.10.0&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;banyandb&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;17912:17912&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;standalone --stream-root-path /tmp/stream-data --measure-root-path /tmp/measure-data&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;healthcheck&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;wget -qO- http://localhost:17913/api/healthz || exit 1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;interval&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;5s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;timeout&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;3s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;retries&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;oap&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;apache/skywalking-oap-server:10.4.0&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;oap&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;banyandb&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;condition&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service_healthy&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;11800:11800&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;12800:12800&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;SW_STORAGE&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;banyandb&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;SW_STORAGE_BANYANDB_TARGETS&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;banyandb:17912&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;healthcheck&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;bash -c &amp;#39;echo &amp;gt; /dev/tcp/localhost/12800&amp;#39; || exit 1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;interval&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;10s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;timeout&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;5s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;retries&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;start_period&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;60s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ui&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;apache/skywalking-ui:10.4.0&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;ui&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;oap&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;condition&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service_healthy&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;SW_OAP_ADDRESS&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;http://oap:12800&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;aigw&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;envoyproxy/ai-gateway-cli:latest&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;aigw&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;oap&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;condition&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service_healthy&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OPENAI_BASE_URL=http://host.docker.internal:11434/v1&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OPENAI_API_KEY=unused&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_SERVICE_NAME=my-ai-gateway&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_EXPORTER_OTLP_ENDPOINT=http://oap:11800&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_EXPORTER_OTLP_PROTOCOL=grpc&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_METRICS_EXPORTER=otlp&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_LOGS_EXPORTER=otlp&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_METRIC_EXPORT_INTERVAL=5000&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_RESOURCE_ATTRIBUTES=job_name=envoy-ai-gateway,service.instance.id=aigw-1,service.layer=ENVOY_AI_GATEWAY&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1975:1975&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;extra_hosts&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;host.docker.internal:host-gateway&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;run&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start everything:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait for all services to become healthy (BanyanDB starts first, then OAP, then UI and AI Gateway):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose ps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The key OTLP configuration on the &lt;code&gt;aigw&lt;/code&gt; service:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Env Var&lt;/th&gt;
          &lt;th&gt;Value&lt;/th&gt;
          &lt;th&gt;Purpose&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_SERVICE_NAME&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;my-ai-gateway&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Service name in SkyWalking&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;http://oap:11800&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;SkyWalking OAP gRPC endpoint&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;grpc&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;OTLP transport&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_METRICS_EXPORTER&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;otlp&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Enable metrics push&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_LOGS_EXPORTER&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;otlp&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;Enable access log push&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;OTEL_RESOURCE_ATTRIBUTES&lt;/code&gt; must include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;job_name=envoy-ai-gateway&lt;/code&gt; — routing tag for MAL/LAL rules&lt;/li&gt;
&lt;li&gt;&lt;code&gt;service.instance.id=&amp;lt;id&amp;gt;&lt;/code&gt; — instance identity&lt;/li&gt;
&lt;li&gt;&lt;code&gt;service.layer=ENVOY_AI_GATEWAY&lt;/code&gt; — routes logs to AI Gateway LAL rules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The MAL and LAL rules are enabled by default in SkyWalking OAP. No OAP-side configuration is needed.&lt;/p&gt;
&lt;h3 id=&#34;step-3-run-the-demo-app&#34;&gt;Step 3: Run the Demo App&lt;/h3&gt;
&lt;p&gt;Create a simple Python application that sends requests through the AI Gateway (&lt;code&gt;app.py&lt;/code&gt;).
It mixes normal requests, streaming requests (for TTFT/TPOT metrics), and error requests
(non-existent model → HTTP 404, always captured by the LAL sampling policy):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;time&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;random&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;requests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GATEWAY &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;http://localhost:1975&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEADERS &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Bearer unused&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;questions &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;What is Apache SkyWalking? Answer in one sentence.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;What is Envoy Proxy used for? Answer in one sentence.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;What are the benefits of an AI gateway? Answer in two sentences.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Explain observability in three sentences.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;chat&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;model&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; question&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; stream&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;False&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    resp &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;post&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;GATEWAY&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;/v1/chat/completions&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        json&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;model&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; model&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;messages&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; question&lt;span style=&#34;color:#1f2328&#34;&gt;}],&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;stream&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; stream&lt;span style=&#34;color:#1f2328&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        headers&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;HEADERS&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; timeout&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; stream&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;stream&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; stream&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        chunks &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;for&lt;/span&gt; line &lt;span style=&#34;color:#0550ae&#34;&gt;in&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;iter_lines&lt;span style=&#34;color:#1f2328&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; line&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                chunks&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;append&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;line&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;decode&lt;span style=&#34;color:#1f2328&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[streamed &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#6639ba&#34;&gt;len&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;chunks&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; chunks]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;json&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;True&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;random&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; r &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0.2&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;# Error request: non-existent model triggers 404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; chat&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;non-existent-model&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6639ba&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[error] model=non-existent-model status=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;status&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;elif&lt;/span&gt; r &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0.5&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;# Streaming request — generates TTFT and TPOT metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        q &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;choice&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;questions&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; info &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; chat&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;llama3.2:1b&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; q&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; stream&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;True&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6639ba&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[stream] status=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;status&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;info&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;else&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;# Normal non-streaming request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        q &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;choice&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;questions&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; chat&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;llama3.2:1b&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; q&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        answer &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; body&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;choices&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[{}])[&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{})&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)[:&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;80&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tokens &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; body&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;usage&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6639ba&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[ok] status=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;status&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; tokens=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;tokens&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; answer=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;answer&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    time&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;sleep&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;randint&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install requests
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python app.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The application talks to the AI Gateway on port 1975, which routes to Ollama.
Each request generates GenAI metrics (token usage, latency, TTFT, TPOT) and access logs
that the gateway pushes to SkyWalking via OTLP.&lt;/p&gt;
&lt;p&gt;The error requests (non-existent model → HTTP 404) are always captured by the access log
sampling policy, so you will see them in the SkyWalking log view.&lt;/p&gt;
&lt;h3 id=&#34;step-4-view-in-skywalking-ui&#34;&gt;Step 4: View in SkyWalking UI&lt;/h3&gt;
&lt;p&gt;Open &lt;a href=&#34;http://localhost:8080&#34;&gt;http://localhost:8080&lt;/a&gt; and select the &lt;strong&gt;GenAI &amp;gt; Envoy AI Gateway&lt;/strong&gt; menu.&lt;/p&gt;
&lt;p&gt;The service list shows &lt;code&gt;my-ai-gateway&lt;/code&gt; with CPM, latency, and token rates at a glance:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-1.png&#34; alt=&#34;Service list&#34;&gt;&lt;/p&gt;
&lt;p&gt;Click into the service to see the full dashboard — Request CPM, Latency (average + percentiles),
Input/Output Token Rates, TTFT, and TPOT:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-2.png&#34; alt=&#34;Service dashboard&#34;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Providers&lt;/strong&gt; tab breaks down metrics by AI provider:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-3.png&#34; alt=&#34;Provider breakdown&#34;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Models&lt;/strong&gt; tab shows per-model metrics including TTFT and TPOT (streaming only).
Note the &lt;code&gt;unknown&lt;/code&gt; model entries — these are the error requests with non-existent models:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-4.png&#34; alt=&#34;Model breakdown&#34;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Log&lt;/strong&gt; tab shows access logs. The sampling policy drops normal successful responses
but always captures errors (HTTP 404) and high-token requests:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-5.png&#34; alt=&#34;Access logs&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;cleanup&#34;&gt;Cleanup&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;deploying-on-kubernetes&#34;&gt;Deploying on Kubernetes&lt;/h2&gt;
&lt;p&gt;For production deployments, Envoy AI Gateway runs as a full Kubernetes controller with
Envoy Gateway as the control plane. See the
&lt;a href=&#34;https://aigateway.envoyproxy.io/docs/getting-started/&#34;&gt;Envoy AI Gateway getting started guide&lt;/a&gt;
for Kubernetes installation.&lt;/p&gt;
&lt;p&gt;The OTLP configuration is the same — set the &lt;code&gt;OTEL_*&lt;/code&gt; environment variables on the
AI Gateway&amp;rsquo;s external processor to point at SkyWalking OAP&amp;rsquo;s gRPC port (11800).
See the &lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-envoy-ai-gateway-monitoring/&#34;&gt;SkyWalking Envoy AI Gateway Monitoring&lt;/a&gt;
documentation for details.&lt;/p&gt;
&lt;h2 id=&#34;genai-observability-without-an-ai-gateway&#34;&gt;GenAI Observability Without an AI Gateway&lt;/h2&gt;
&lt;p&gt;Not every deployment uses an AI gateway. If your applications call LLM providers directly,
SkyWalking 10.4.0 also provides GenAI observability through the
&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/service-agent/virtual-genai/&#34;&gt;Virtual GenAI&lt;/a&gt; layer.&lt;/p&gt;
&lt;p&gt;This works with any SkyWalking-instrumented, OpenTelemetry-instrumented, or Zipkin-instrumented application.
When traces carry &lt;code&gt;gen_ai.*&lt;/code&gt; tags (following
&lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/&#34;&gt;OpenTelemetry GenAI Semantic Conventions&lt;/a&gt;),
SkyWalking derives per-provider and per-model metrics from the client side:
latency, token usage, success rate, and estimated cost.&lt;/p&gt;
&lt;p&gt;For Java applications, the SkyWalking Java Agent (9.7+) includes a Spring AI plugin that automatically
instruments calls to 13+ providers (OpenAI, Anthropic, AWS Bedrock, Google GenAI, DeepSeek, Mistral, etc.)
with the correct &lt;code&gt;gen_ai.*&lt;/code&gt; span tags — no code changes needed.&lt;/p&gt;
&lt;p&gt;This is a different use case from the Envoy AI Gateway monitoring covered above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Envoy AI Gateway layer&lt;/strong&gt;: infrastructure-level observability — what the gateway sees across all traffic.
Best for platform teams managing centralized AI routing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual GenAI layer&lt;/strong&gt;: application-level observability — what each instrumented app sees for its own LLM calls.
Best for teams without a centralized gateway, or for per-application cost tracking.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://aigateway.envoyproxy.io/&#34;&gt;Envoy AI Gateway&lt;/a&gt; — project site and documentation&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/envoyproxy/ai-gateway/tree/main/cmd/aigw&#34;&gt;Envoy AI Gateway CLI&lt;/a&gt; — standalone mode for local development&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-envoy-ai-gateway-monitoring/&#34;&gt;SkyWalking Envoy AI Gateway Monitoring&lt;/a&gt; — OAP setup doc&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/service-agent/virtual-genai/&#34;&gt;SkyWalking Virtual GenAI&lt;/a&gt; — client-side GenAI observability&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/&#34;&gt;OpenTelemetry GenAI Semantic Conventions&lt;/a&gt; — the metric/attribute standard both projects follow&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Zh: 用 Apache SkyWalking 监控 Envoy AI Gateway</title>
      <link>/zh/2026-04-02-envoy-ai-gateway-monitoring/</link>
      <pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/zh/2026-04-02-envoy-ai-gateway-monitoring/</guid>
      <description>
        
        
        &lt;h2 id=&#34;问题llm-流量缺乏统一观测&#34;&gt;问题：LLM 流量缺乏统一观测&lt;/h2&gt;
&lt;p&gt;LLM 流量正在成为生产基础设施中不可忽视的一部分。团队同时在调用 OpenAI、Anthropic、AWS Bedrock、Azure OpenAI、Google Gemini——往往还不止一个提供商。但大多数组织对这些流量缺乏统一的可见性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Token 费用失控&lt;/strong&gt;，却不知道哪个团队、哪个模型、哪个提供商在烧钱。一个配置不当的 prompt 模板就可能在无人察觉的情况下烧掉几千美元。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提供商故障引发连锁反应。&lt;/strong&gt; OpenAI 出问题的那一小时，你的应用也跟着挂——而你既没有故障切换的可见性，也无法自动切换提供商。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺乏统一指标。&lt;/strong&gt; 延迟、首 Token 耗时（TTFT）、每 Token 输出耗时（TPOT）、Token 用量、错误率——每个提供商的报告方式都不一样，有些甚至不提供。没有一个统一的面板能做对比。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这和十年前微服务面临的可观测性困境如出一辙。当时的解法是服务网格和内置遥测的 API 网关。对 AI 工作负载来说，答案就是 AI 网关。&lt;/p&gt;
&lt;h2 id=&#34;为什么选择-ai-网关&#34;&gt;为什么选择 AI 网关&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://aigateway.envoyproxy.io/&#34;&gt;Envoy AI Gateway&lt;/a&gt; 是一个开源 AI 网关，构建在 &lt;a href=&#34;https://www.envoyproxy.io/&#34;&gt;Envoy Proxy&lt;/a&gt; 和 &lt;a href=&#34;https://gateway.envoyproxy.io/&#34;&gt;Envoy Gateway&lt;/a&gt; 之上。底层就是云原生世界里已经广泛部署的 Envoy，天然具备基础设施级的稳定性和性能。&lt;/p&gt;
&lt;p&gt;核心能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多提供商路由&lt;/strong&gt; —— 支持 16+ AI 提供商（OpenAI、Anthropic、AWS Bedrock、Azure OpenAI、Google Gemini、Mistral、Cohere、DeepSeek 等），统一 API 接入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基于 Token 的限流&lt;/strong&gt; —— 按 Token 消耗限流，而不只是按请求数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提供商故障切换&lt;/strong&gt; —— 某个提供商宕机或响应慢时自动切换。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型虚拟化&lt;/strong&gt; —— 抽象模型名称，让应用与具体提供商解耦。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;两层架构&lt;/strong&gt; —— 参考架构包含一个集中入口网关（Tier 1）负责认证和全局路由，以及每集群网关（Tier 2）负责推理优化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CNCF 生态原生&lt;/strong&gt; —— 运行在 Kubernetes 上，兼容现有的 Envoy Filter、WASM 插件和标准 Kubernetes Gateway API 资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Envoy AI Gateway 原生支持通过 OTLP 发送 GenAI 指标和访问日志，遵循 &lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/&#34;&gt;OpenTelemetry GenAI 语义约定&lt;/a&gt;，可以直接接入任何兼容 OpenTelemetry 的后端。&lt;/p&gt;
&lt;p&gt;从 SkyWalking 10.4.0 开始，OAP 原生接收和分析 Envoy AI Gateway 的 OTLP 指标和访问日志——中间不需要部署 OpenTelemetry Collector。&lt;/p&gt;
&lt;h2 id=&#34;数据流&#34;&gt;数据流&lt;/h2&gt;
&lt;p&gt;AI Gateway 通过 OTLP gRPC 直接将遥测数据推送到 SkyWalking：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;workflow.jpg&#34; alt=&#34;数据流&#34;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;应用&lt;/strong&gt; 通过 Envoy AI Gateway 发送 LLM API 请求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Envoy AI Gateway&lt;/strong&gt; 将请求路由到 AI 提供商（或 Ollama 这样的本地模型），同时记录 GenAI 指标（Token 用量、延迟、TTFT、TPOT）和访问日志。&lt;/li&gt;
&lt;li&gt;网关通过 &lt;strong&gt;OTLP gRPC&lt;/strong&gt; 直接将指标和日志推送到 &lt;strong&gt;SkyWalking OAP&lt;/strong&gt; 的 11800 端口。&lt;/li&gt;
&lt;li&gt;SkyWalking OAP 用 MAL 规则解析指标、用 LAL 规则解析访问日志，然后统一存储到 &lt;strong&gt;BanyanDB&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不需要 OpenTelemetry Collector。SkyWalking OAP 内置的 OTLP 接收器可以直接处理所有数据。&lt;/p&gt;
&lt;h2 id=&#34;本地体验&#34;&gt;本地体验&lt;/h2&gt;
&lt;p&gt;这个 Demo 使用 &lt;a href=&#34;https://ollama.com/&#34;&gt;Ollama&lt;/a&gt; 作为本地 LLM 后端，不需要任何 API Key 就能跑起来。&lt;a href=&#34;https://github.com/envoyproxy/ai-gateway/tree/main/cmd/aigw&#34;&gt;Envoy AI Gateway CLI&lt;/a&gt;（&lt;code&gt;aigw&lt;/code&gt;）提供独立运行模式，不依赖 Kubernetes，非常适合本地测试。&lt;/p&gt;
&lt;h3 id=&#34;前置条件&#34;&gt;前置条件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Docker 和 Docker Compose&lt;/li&gt;
&lt;li&gt;主机上已安装 &lt;a href=&#34;https://ollama.com/&#34;&gt;Ollama&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;第一步启动-ollama&#34;&gt;第一步：启动 Ollama&lt;/h3&gt;
&lt;p&gt;让 Ollama 监听所有网络接口，以便 Docker 容器能访问到：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#953800&#34;&gt;OLLAMA_HOST&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;0.0.0.0 ollama serve
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;拉取一个小模型用于测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ollama pull llama3.2:1b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;第二步启动服务栈&#34;&gt;第二步：启动服务栈&lt;/h3&gt;
&lt;p&gt;创建 &lt;code&gt;docker-compose.yaml&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;banyandb&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;apache/skywalking-banyandb:0.10.0&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;banyandb&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;17912:17912&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;standalone --stream-root-path /tmp/stream-data --measure-root-path /tmp/measure-data&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;healthcheck&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;wget -qO- http://localhost:17913/api/healthz || exit 1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;interval&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;5s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;timeout&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;3s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;retries&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;oap&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;apache/skywalking-oap-server:10.4.0&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;oap&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;banyandb&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;condition&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service_healthy&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;11800:11800&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;12800:12800&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;SW_STORAGE&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;banyandb&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;SW_STORAGE_BANYANDB_TARGETS&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;banyandb:17912&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;healthcheck&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;bash -c &amp;#39;echo &amp;gt; /dev/tcp/localhost/12800&amp;#39; || exit 1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;interval&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;10s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;timeout&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;5s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;retries&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;start_period&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;60s&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ui&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;apache/skywalking-ui:10.4.0&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;ui&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;oap&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;condition&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service_healthy&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;SW_OAP_ADDRESS&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;http://oap:12800&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;aigw&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;envoyproxy/ai-gateway-cli:latest&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;aigw&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;oap&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;condition&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;service_healthy&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OPENAI_BASE_URL=http://host.docker.internal:11434/v1&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OPENAI_API_KEY=unused&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_SERVICE_NAME=my-ai-gateway&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_EXPORTER_OTLP_ENDPOINT=http://oap:11800&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_EXPORTER_OTLP_PROTOCOL=grpc&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_METRICS_EXPORTER=otlp&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_LOGS_EXPORTER=otlp&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_METRIC_EXPORT_INTERVAL=5000&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- OTEL_RESOURCE_ATTRIBUTES=job_name=envoy-ai-gateway,service.instance.id=aigw-1,service.layer=ENVOY_AI_GATEWAY&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;1975:1975&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;extra_hosts&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;host.docker.internal:host-gateway&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;run&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动所有服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;等待所有服务变为健康状态（BanyanDB 先启动，然后是 OAP，最后是 UI 和 AI Gateway）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose ps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;aigw&lt;/code&gt; 服务的关键 OTLP 配置：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;环境变量&lt;/th&gt;
          &lt;th&gt;值&lt;/th&gt;
          &lt;th&gt;用途&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_SERVICE_NAME&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;my-ai-gateway&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;SkyWalking 中的服务名&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;http://oap:11800&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;SkyWalking OAP gRPC 端点&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;grpc&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;OTLP 传输协议&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_METRICS_EXPORTER&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;otlp&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;启用指标推送&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;OTEL_LOGS_EXPORTER&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;otlp&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;启用访问日志推送&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;OTEL_RESOURCE_ATTRIBUTES&lt;/code&gt; 必须包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;job_name=envoy-ai-gateway&lt;/code&gt; —— MAL/LAL 规则的路由标签&lt;/li&gt;
&lt;li&gt;&lt;code&gt;service.instance.id=&amp;lt;id&amp;gt;&lt;/code&gt; —— 实例标识&lt;/li&gt;
&lt;li&gt;&lt;code&gt;service.layer=ENVOY_AI_GATEWAY&lt;/code&gt; —— 将日志路由到 AI Gateway LAL 规则&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MAL 和 LAL 规则在 SkyWalking OAP 中默认启用，不需要额外配置。&lt;/p&gt;
&lt;h3 id=&#34;第三步运行-demo-应用&#34;&gt;第三步：运行 Demo 应用&lt;/h3&gt;
&lt;p&gt;创建一个简单的 Python 应用，通过 AI Gateway 发送请求（&lt;code&gt;app.py&lt;/code&gt;）。
它混合了普通请求、流式请求（用于产生 TTFT/TPOT 指标）和错误请求（不存在的模型 → HTTP 404，始终会被 LAL 采样策略捕获）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;time&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;random&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;requests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GATEWAY &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;http://localhost:1975&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HEADERS &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Bearer unused&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;questions &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;What is Apache SkyWalking? Answer in one sentence.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;What is Envoy Proxy used for? Answer in one sentence.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;What are the benefits of an AI gateway? Answer in two sentences.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Explain observability in three sentences.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;chat&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;model&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; question&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; stream&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;False&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    resp &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;post&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;GATEWAY&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;/v1/chat/completions&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        json&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;model&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; model&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;messages&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[{&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; question&lt;span style=&#34;color:#1f2328&#34;&gt;}],&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;stream&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; stream&lt;span style=&#34;color:#1f2328&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        headers&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;HEADERS&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; timeout&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; stream&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;stream&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; stream&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        chunks &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;for&lt;/span&gt; line &lt;span style=&#34;color:#0550ae&#34;&gt;in&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;iter_lines&lt;span style=&#34;color:#1f2328&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; line&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                chunks&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;append&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;line&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;decode&lt;span style=&#34;color:#1f2328&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[streamed &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#6639ba&#34;&gt;len&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;chunks&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; chunks]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; resp&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;json&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;True&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;random&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;if&lt;/span&gt; r &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0.2&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;# Error request: non-existent model triggers 404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; chat&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;non-existent-model&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6639ba&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[error] model=non-existent-model status=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;status&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;elif&lt;/span&gt; r &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0.5&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;# Streaming request — generates TTFT and TPOT metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        q &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;choice&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;questions&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; info &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; chat&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;llama3.2:1b&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; q&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; stream&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;True&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6639ba&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[stream] status=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;status&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;info&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;else&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;# Normal non-streaming request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        q &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;choice&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;questions&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        status&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; chat&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;llama3.2:1b&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; q&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        answer &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; body&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;choices&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[{}])[&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{})&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)[:&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;80&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tokens &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; body&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;usage&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#6639ba&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;[ok] status=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;status&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; tokens=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;tokens&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt; answer=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;answer&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    time&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;sleep&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;random&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;randint&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install requests
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python app.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用通过 1975 端口与 AI Gateway 通信，AI Gateway 再路由到 Ollama。每次请求都会产生 GenAI 指标（Token 用量、延迟、TTFT、TPOT）和访问日志，由网关通过 OTLP 推送到 SkyWalking。&lt;/p&gt;
&lt;p&gt;错误请求（不存在的模型 → HTTP 404）始终会被访问日志采样策略捕获，所以在 SkyWalking 的日志视图中一定能看到。&lt;/p&gt;
&lt;h3 id=&#34;第四步在-skywalking-ui-中查看&#34;&gt;第四步：在 SkyWalking UI 中查看&lt;/h3&gt;
&lt;p&gt;打开 &lt;a href=&#34;http://localhost:8080&#34;&gt;http://localhost:8080&lt;/a&gt;，选择 &lt;strong&gt;GenAI &amp;gt; Envoy AI Gateway&lt;/strong&gt; 菜单。&lt;/p&gt;
&lt;p&gt;服务列表显示 &lt;code&gt;my-ai-gateway&lt;/code&gt;，可以一览 CPM、延迟和 Token 速率：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-1.png&#34; alt=&#34;服务列表&#34;&gt;&lt;/p&gt;
&lt;p&gt;点击进入服务详情，查看完整仪表盘——请求 CPM、延迟（平均值 + 百分位数）、输入/输出 Token 速率、TTFT 和 TPOT：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-2.png&#34; alt=&#34;服务仪表盘&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Providers&lt;/strong&gt; 标签页按 AI 提供商维度展示指标：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-3.png&#34; alt=&#34;提供商维度&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Models&lt;/strong&gt; 标签页展示每个模型的指标，包括 TTFT 和 TPOT（仅流式请求）。注意 &lt;code&gt;unknown&lt;/code&gt; 模型条目——这些就是使用不存在模型的错误请求：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-4.png&#34; alt=&#34;模型维度&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Log&lt;/strong&gt; 标签页展示访问日志。采样策略会丢弃正常的成功响应，但始终保留错误（HTTP 404）和高 Token 消耗的请求：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen-5.png&#34; alt=&#34;访问日志&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;清理&#34;&gt;清理&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;kubernetes-生产部署&#34;&gt;Kubernetes 生产部署&lt;/h2&gt;
&lt;p&gt;生产环境中，Envoy AI Gateway 作为完整的 Kubernetes 控制器运行，以 Envoy Gateway 作为控制面。详见 &lt;a href=&#34;https://aigateway.envoyproxy.io/docs/getting-started/&#34;&gt;Envoy AI Gateway 入门指南&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;OTLP 配置方式相同——在 AI Gateway 的 External Processor 上设置 &lt;code&gt;OTEL_*&lt;/code&gt; 环境变量，指向 SkyWalking OAP 的 gRPC 端口（11800）。详见 &lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-envoy-ai-gateway-monitoring/&#34;&gt;SkyWalking Envoy AI Gateway 监控文档&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;不用-ai-网关也能做-genai-可观测&#34;&gt;不用 AI 网关也能做 GenAI 可观测&lt;/h2&gt;
&lt;p&gt;并非所有场景都需要 AI 网关。如果你的应用直接调用 LLM 提供商，SkyWalking 10.4.0 也提供了基于 &lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/service-agent/virtual-genai/&#34;&gt;Virtual GenAI&lt;/a&gt; 层的 GenAI 可观测方案。&lt;/p&gt;
&lt;p&gt;任何接入了 SkyWalking、OpenTelemetry 或 Zipkin 探针的应用都能使用这个功能。只要 Trace 中携带 &lt;code&gt;gen_ai.*&lt;/code&gt; 标签（遵循 &lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/&#34;&gt;OpenTelemetry GenAI 语义约定&lt;/a&gt;），SkyWalking 就能从客户端视角推导出每提供商、每模型的指标：延迟、Token 用量、成功率和预估费用。&lt;/p&gt;
&lt;p&gt;对于 Java 应用，SkyWalking Java Agent（9.7+）内置了 Spring AI 插件，自动为 13+ 提供商（OpenAI、Anthropic、AWS Bedrock、Google GenAI、DeepSeek、Mistral 等）的调用注入正确的 &lt;code&gt;gen_ai.*&lt;/code&gt; Span 标签——不需要改代码。&lt;/p&gt;
&lt;p&gt;这与上面介绍的 Envoy AI Gateway 监控是不同的使用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Envoy AI Gateway 层&lt;/strong&gt;：基础设施级可观测——网关视角，覆盖所有流量。适合负责集中 AI 路由的平台团队。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual GenAI 层&lt;/strong&gt;：应用级可观测——每个应用自己看到的 LLM 调用情况。适合没有集中网关的团队，或者需要按应用维度跟踪费用的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://aigateway.envoyproxy.io/&#34;&gt;Envoy AI Gateway&lt;/a&gt; —— 项目官网和文档&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/envoyproxy/ai-gateway/tree/main/cmd/aigw&#34;&gt;Envoy AI Gateway CLI&lt;/a&gt; —— 本地开发用的独立运行模式&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-envoy-ai-gateway-monitoring/&#34;&gt;SkyWalking Envoy AI Gateway 监控&lt;/a&gt; —— OAP 配置文档&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skywalking.apache.org/docs/main/next/en/setup/service-agent/virtual-genai/&#34;&gt;SkyWalking Virtual GenAI&lt;/a&gt; —— 客户端侧 GenAI 可观测&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://opentelemetry.io/docs/specs/semconv/gen-ai/&#34;&gt;OpenTelemetry GenAI 语义约定&lt;/a&gt; —— 两个项目共同遵循的指标/属性标准&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Zh: AI Coding 如何重塑软件架构师的工作方式</title>
      <link>/zh/2026-03-13-how-ai-changed-the-economics-of-architecture/</link>
      <pubDate>Sun, 15 Mar 2026 00:00:00 +0000</pubDate>
      <guid>/zh/2026-03-13-how-ai-changed-the-economics-of-architecture/</guid>
      <description>
        
        
        &lt;p&gt;&lt;em&gt;以 SkyWalking GraalVM Distro 为例，看 AI Coding 如何把一批探索性 PoC 打磨成一条可重复的迁移流水线。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./graph.jpg&#34; alt=&#34;graph.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;这个项目给我最大的启发，不是 AI 能写多少代码，而是 AI Coding 改变了架构设计的试错成本。当一个想法可以很快做成 PoC、跑起来验证、不行就推翻重来时，架构师就更有机会逼近自己真正想要的设计，而不是过早停在“团队现在做得出来”的折中方案上。&lt;/p&gt;
&lt;p&gt;这种变化在成熟开源系统里尤其重要。Apache SkyWalking OAP 长期以来一直是一个功能强大且经过生产验证的可观测性后端，但大型 Java 平台该有的问题它一个不少：运行时字节码生成、重反射初始化、classpath 扫描、基于 SPI 的模块装配，以及动态 DSL 执行——这些机制方便扩展，但做 GraalVM Native Image 时全是障碍。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SkyWalking GraalVM Distro&lt;/strong&gt; 的出现，源于我们把这个挑战当成一个架构设计问题来处理，而不是一次性的移植工程。目标不仅是让 OAP 能以原生二进制运行，更是把 GraalVM 迁移本身做成一条可重复执行、能够持续跟上上游演进的自动化流水线。&lt;/p&gt;
&lt;p&gt;如果你想看完整的技术设计、基准数据和上手方式，请阅读配套文章：&lt;a href=&#34;/zh/2026-03-13-skywalking-graalvm-distro-design-and-benchmarks/&#34;&gt;SkyWalking GraalVM Distro：设计与基准测试&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;从停滞的想法到可运行的系统&#34;&gt;从停滞的想法到可运行的系统&lt;/h2&gt;
&lt;p&gt;这件事其实很多年前就开始了。在这个仓库创建不久之后，&lt;a href=&#34;https://github.com/yswdqz&#34;&gt;yswdqz&lt;/a&gt; 曾花了数个月探索迁移方案。真正做下来才发现，这个项目远比 GraalVM 文档里列出的那些单点限制复杂得多，这项工作最终也因此搁置了很多年。&lt;/p&gt;
&lt;p&gt;这段停滞很重要。缺少的并不是想法。成熟维护者通常从来不缺想法，真正稀缺的，是把这些想法真正做出来的时间、人力和精力。即使架构师已经看到了几条很有前景的路线，有限的开发资源也会迫使大家更早做出权衡：优先选择实现成本最低的方案，而不是那个更干净、更可复用、更经得起未来变化的方案。&lt;/p&gt;
&lt;p&gt;这种情况非常普遍，并不特殊。在开源社区里，很多工作依赖志愿者或有限的企业赞助；在商业产品里，约束的形式不同，但本质仍然一样：路线图承诺、团队规模和交付压力都会让工程资源始终紧张。在这两种环境里，很多好想法被放弃，并不是因为它们错了，而是因为要把它们真正验证清楚、实现完整，成本太高。&lt;/p&gt;
&lt;p&gt;还有一个同样重要的约束：架构师通常同时也是非常资深的工程师，而不是一个可以全职扑在实现细节上的人。问题在于个人编码精力有限、时间高度碎片化，同时还要在代码尚未出现之前，不断向其他资深工程师解释自己的设计意图。传统上，这种解释主要通过图、文档和沟通完成。它很慢、信息损失大，而且充满不确定性。我们都体验过“传话游戏”：哪怕是很简单的意思，也很容易被误解，而等误解真正暴露出来时，时间已经过去很多了。&lt;/p&gt;
&lt;p&gt;到了 2025 年末，AI Coding 让”同时尝试多条路线”这件事终于变得现实。我们不必再因为实现能力稀缺而过早接受折中，而是可以在多个设计之间来回切换，用代码验证，快速淘汰弱方案，持续迭代，直到架构本身变得足够稳固、足够实用、足够高效。&lt;/p&gt;
&lt;p&gt;这种设计自由度至关重要。GraalVM 文档对单个限制讲得很清楚，但成熟 OSS 平台遇到的是一整套彼此牵连的系统性问题。只修补一个动态机制远远不够。要让 native image 真正落地，我们必须把整类运行时行为改造成构建期产物和自动生成的元数据。&lt;/p&gt;
&lt;p&gt;在这条路的早期历史中，还有一座非常具体的大山。那时上游 SkyWalking 仍然大量依赖 Groovy 来处理 LAL、MAL 和 Hierarchy 脚本。理论上，这只不过是另一个“不支持运行时动态行为”的例子；但在实践中，Groovy 是整条路径上最大的障碍。它不仅意味着脚本执行，还意味着一整套在 JVM 里极其便利、在 native image 里却极其不友好的动态模型。&lt;/p&gt;
&lt;p&gt;为了跨过这道坎，我们围绕 AOT-first 模式重新设计了 OAP 的核心引擎。早期实验必须直接面对 Groovy 时代的运行时行为，并尝试不同的脚本编译方案来绕过去。最终方案走得更远：对齐上游编译器流水线，把动态生成前移到构建期，并引入自动化机制，让这条迁移路径在上游持续演进时依然保持可控。具体来说，就是把 OAL、MAL、LAL 和 Hierarchy 的生成过程变成构建期预编译器的输出，而不是继续保留为启动期的动态行为。&lt;/p&gt;
&lt;h2 id=&#34;ai-coding-如何改写架构迭代&#34;&gt;AI Coding 如何改写架构迭代&lt;/h2&gt;
&lt;p&gt;这次转变的关键，并不只是“写代码更快了”。AI 真正改变的，是想法、原型、验证和重设计之间来回迭代的速度。围绕同一个问题，我们可以很快做出几个可运行的 PoC，迅速淘汰不成立的方向，再把值得保留的抽象慢慢沉淀成一套连贯的迁移系统。&lt;/p&gt;
&lt;p&gt;这并不会削弱人的架构价值，反而会放大它。哪些行为应该前移到构建期，哪些地方应该保留可配置性，哪里应该引入 same-FQCN 替换，如何让上游同步保持可控，以及哪些抽象值得不惜代价保留下来，这些判断仍然只能由人来做。不同的是，AI 的速度让我们终于有机会把这些更好的设计真正做出来，而不是过早退回到更简单、也更差的折中方案。&lt;/p&gt;
&lt;p&gt;这才是软件架构师工作方式真正发生变化的地方。过去，架构师往往已经知道更干净的方向在哪里，但有限的工程产能会逼着那个愿景退回到一个更便宜的妥协方案。现在，架构师在某种意义上又重新变回了“能快速动手的人”：可以直接用代码把思路搭出来，把高层抽象落成接口，再用真实运行的实现去证明设计。&lt;/p&gt;
&lt;p&gt;这不仅改变了实现，也改变了沟通方式。在开源里，我们常说：&lt;code&gt;talk is cheap, show me the code&lt;/code&gt;。在 AI Coding 时代，“把代码拿出来”这件事变得容易多了。设计不再那么依赖一个缓慢的、自上而下的翻译过程：从想法到文档，再到解释，再到实现。代码可以更早出现，也可以更早跑起来。&lt;/p&gt;
&lt;p&gt;这也让其他资深工程师受益。他们不必只靠图、会议或长篇解释来还原整个设计，而是可以直接审查抽象、阅读真实代码、运行它、质疑它，并在具体实现上一起打磨。这让架构协作更快、更清晰，也少了很多沟通误差。&lt;/p&gt;
&lt;p&gt;也正因为如此，我总觉得今天很多 AI 讨论有点跑偏。很多项目确实很有趣、也很好玩，拿来体验当然没问题，但高级工程工作并不会因为“给代码库接了个 agent”就自然变好。真正重要的，不是哪个 demo 看起来最炫，而是哪些工程能力真的被放大了，同时软件开发本身的纪律有没有被保留下来。&lt;/p&gt;
&lt;p&gt;对于架构师和资深工程师来说，这里真正重要的能力包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;快速做对比式原型验证&lt;/strong&gt;：不是只用 slides 和文档去论证某个想法，而是直接把多个方案做成可运行代码来比较。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大规模代码理解能力&lt;/strong&gt;：能在大量模块之间快速阅读，同时保持对整个系统的全局认识。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统性的重构能力&lt;/strong&gt;：把基于反射、依赖运行时动态行为的路径，系统性地改造成适配 AOT 约束的设计。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;搭建自动化的能力&lt;/strong&gt;：当一个迁移步骤在每次上游同步时都必须重做一次，靠手工处理本身就很费时费力，而且越往后只会越累。AI 让我们真正有条件去投资生成器、清单、一致性检查和漂移检测，把重复的人力劳动变成可重复的自动化流程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大范围审查能力&lt;/strong&gt;：在很大的代码面上检查边界条件、兼容性约束，以及方案是否经得起反复执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些能力也都体现在最终的设计结果里。same-FQCN 替换为 GraalVM 特定行为建立了清晰、受控的边界；反射元数据不再依赖手工维护的猜测清单，而是直接从构建产物中生成；各种清单机制和漂移检测，则把原本模糊的“上游同步风险”变成了显式的工程工作流。&lt;/p&gt;
&lt;p&gt;对于初级工程师，我觉得这里的启发同样重要。AI 不会让架构设计、系统约束、接口设计、测试和可维护性这些基本功变得不重要。恰恰相反，这些能力只会变得更重要，因为它们决定了“被加速的实现”最终产出的是一个可持续演进的系统，还是只是更快地制造出更多代码。真正的杠杆来自工程判断力，而不是新鲜感。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; 和 &lt;strong&gt;Gemini AI&lt;/strong&gt; 在整个过程中都扮演了工程加速器的角色。在 GraalVM Distro 这个项目里，它们具体帮我们做了几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;把迁移思路直接做成可运行代码&lt;/strong&gt;：不是争论哪个方向可能行得通，而是把多个真实原型做出来、跑起来、比较掉，把不成立的方向淘汰掉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重构重反射、重动态的代码路径&lt;/strong&gt;：把不适合运行时的模式系统性替换成 AOT 友好的实现方式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;让上游同步真正可持续&lt;/strong&gt;：每次 distro 从上游 SkyWalking 拉取变更后，元数据扫描、配置再生成和重新编译都必须再来一次。AI 帮助我们把这些过程做成流水线，使每次同步都变成一个可控、且大部分自动化的过程，而不是一次比一次更长的手工重复劳动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在大范围内审查逻辑和边界情况&lt;/strong&gt;：特别是在功能对等性比纯实现速度更重要的地方。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终产出的，不只是一次大重写，而是一套可重复的系统：预编译器、manifest 驱动的加载、反射配置生成、替换边界，以及让上游迁移可审查、可自动化的漂移检测机制。&lt;/p&gt;
&lt;p&gt;如果你想看这种开发方法背后的更广泛背景，可以读这篇文章：&lt;a href=&#34;/zh/2026-03-08-agentic-vibe-coding/&#34;&gt;在成熟开源大型项目中实践 Agentic Vibe Coding：软件工程与工程控制论还在延续&lt;/a&gt;。这篇文章则是这个故事的下一步：不仅是在一个成熟代码库里增强功能，而是重新激活一项曾经停滞的工作，并把它真正做成可运行系统。&lt;/p&gt;
&lt;h2 id=&#34;真正改变的到底是什么&#34;&gt;真正改变的到底是什么&lt;/h2&gt;
&lt;p&gt;这个项目最重要的结果，并不是一张 benchmark 表。基准数据当然属于 distro 本身，而且它们很重要，因为它们证明这套系统是真实可运行的。但对这篇文章来说，更深层的变化发生在方法论层面：AI Coding 改变了我们探索、验证和打磨架构方案的方式。&lt;/p&gt;
&lt;p&gt;过去，架构往往更像一项以文档为主、后面拖着漫长而昂贵实现过程的活动。现在，我们可以更快地在想法、原型、比较和重设计之间切换。这让我们真正有机会去追求更高抽象层次的方案，保留更干净的边界，并建设那些让迁移过程可持续维护的自动化机制。&lt;/p&gt;
&lt;p&gt;这项工作的技术证据，就是 SkyWalking GraalVM Distro 本身：它不仅是一个可运行的系统，更是一条由预编译器、自动生成的反射元数据、受控替换边界和漂移检查组成的迁移流水线。基准数据之所以重要，是因为它们证明这套系统在实践里是成立的；但从架构角度看，真正的结果是：这次迁移不再是一场一次性的移植，而是变成了一套可重复执行的系统工程。关于完整测试方法、原始数据和技术设计，请阅读配套文章：&lt;a href=&#34;/zh/2026-03-13-skywalking-graalvm-distro-design-and-benchmarks/&#34;&gt;SkyWalking GraalVM Distro：设计与基准测试&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;项目仓库位于 &lt;a href=&#34;https://github.com/apache/skywalking-graalvm-distro&#34;&gt;apache/skywalking-graalvm-distro&lt;/a&gt;。我们欢迎社区成员测试这个新发行版、提交 issue，并帮助它逐步走向生产可用。&lt;/p&gt;
&lt;p&gt;对我来说，更深层的启发并不止于这个发行版。AI Coding 不会让架构变得不重要，反而会让架构更值得被认真追求。当实现速度提升到一定程度时，我们终于有机会在真实代码里验证更多想法，保留那些真正好的抽象，并把那些过去常常因为投入太大而半途妥协的系统真正做出来。&lt;/p&gt;
&lt;p&gt;对于资深工程师来说，瓶颈正在从单纯的代码实现速度，转向品味、系统判断力，以及定义稳定边界的能力。对于初级工程师来说，真正该走的路不是追逐每一种看上去都很刺激的 AI 工作流，而是把基础能力练得更扎实，让加速真正产生复利：理解需求、阅读陌生系统、质疑假设，并识别出在系统快速变化时仍然必须保持正确的那些部分。AI Coding 降低了验证好设计的代价，但并没有降低工程判断本身的门槛。&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Blog: How AI Changed the Economics of Architecture</title>
      <link>/blog/2026-03-13-how-ai-changed-the-economics-of-architecture/</link>
      <pubDate>Fri, 13 Mar 2026 00:00:00 +0000</pubDate>
      <guid>/blog/2026-03-13-how-ai-changed-the-economics-of-architecture/</guid>
      <description>
        
        
        &lt;p&gt;&lt;em&gt;SkyWalking GraalVM Distro: A case study in turning runnable PoCs into a repeatable migration pipeline.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./graph.jpg&#34; alt=&#34;graph.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;The most important lesson from this project is not that AI can generate a large amount of code. It is that AI changes the economics of architecture. When runnable PoCs become cheap to build, compare, discard, and rebuild, architects can push further toward the design they actually want instead of stopping early at a compromise they can afford to implement.&lt;/p&gt;
&lt;p&gt;That shift matters a lot in mature open source systems. Apache SkyWalking OAP has long been a powerful and production-proven observability backend, but it also carries all the realities of a large Java platform: runtime bytecode generation, reflection-heavy initialization, classpath scanning, SPI-based module wiring, and dynamic DSL execution that are friendly to extensibility but hostile to GraalVM native image.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SkyWalking GraalVM Distro&lt;/strong&gt; is the result of treating that challenge as a design-system problem instead of a one-off porting exercise. The goal was not only to make OAP run as a native binary, but to turn GraalVM migration itself into a repeatable automation pipeline that can stay aligned with upstream evolution.&lt;/p&gt;
&lt;p&gt;For the full technical design, benchmark data, and getting-started guide, see the companion post: &lt;a href=&#34;../2026-03-13-skywalking-graalvm-distro-design-and-benchmarks/index.md&#34;&gt;SkyWalking GraalVM Distro: Design and Benchmarks&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;from-paused-idea-to-runnable-system&#34;&gt;From Paused Idea to Runnable System&lt;/h2&gt;
&lt;p&gt;This journey actually began years ago. Shortly after this repository was created, &lt;a href=&#34;https://github.com/yswdqz&#34;&gt;yswdqz&lt;/a&gt; spent several months exploring the transition. The project proved much harder in practice than the individual GraalVM limitations sounded on paper, and the work eventually paused for years.&lt;/p&gt;
&lt;p&gt;That pause is important. The missing ingredient was not ideas. Mature maintainers usually have more ideas than time. The real constraint was implementation economics. Even when the architect can see several promising directions, limited developer resources force an earlier trade-off: choose the path that is cheapest to implement, not necessarily the path that is cleanest, most reusable, or most future-proof.&lt;/p&gt;
&lt;p&gt;This is a very common reality, not an exceptional one. In open source communities, much of the work depends on volunteers or limited company sponsorship. In commercial products, the pressure is different but the constraint is still real: roadmap commitments, staffing limits, and delivery deadlines keep engineering resources tight. In both worlds, good ideas are often abandoned not because they are wrong, but because they are too expensive to validate and implement thoroughly.&lt;/p&gt;
&lt;p&gt;There is another constraint that matters just as much: the architect is usually also a very senior engineer, not a full-time implementation machine. That means limited personal coding energy, fragmented time, and a constant need to explain ideas to other senior engineers before the code exists. Traditionally, that explanation happens through diagrams, documents, and conversations. It is slow, lossy, and unpredictable. We all know some version of the Telephone Game: even simple words are easy to misunderstand, and by the time the misunderstanding becomes visible, a lot of time has already passed.&lt;/p&gt;
&lt;p&gt;What changed in late 2025 was that AI engineering made multiple runnable ideas affordable. Instead of picking an early compromise because implementation capacity was scarce, we could switch repeatedly between designs, validate them with code, discard weak directions quickly, and keep iterating until the architecture became solid, practical, and efficient enough to hold.&lt;/p&gt;
&lt;p&gt;That design freedom was critical. GraalVM documentation gives clear guidance on isolated limitations, but a mature OSS platform hits them as a connected system. Fixing only one dynamic mechanism is not enough. To make native image practical, we had to turn whole categories of runtime behavior into build-time artifacts and automated metadata generation.&lt;/p&gt;
&lt;p&gt;There was also a very concrete mountain in front of us in the early history of this distro. In the first several commits of the repository, upstream SkyWalking still relied heavily on Groovy for LAL, MAL, and Hierarchy scripts. In theory, that was just one more unsupported runtime-heavy component. In practice, Groovy was the biggest obstacle in the whole path. It represented not only script execution, but a whole dynamic model that was deeply convenient on the JVM side and deeply unfriendly to native image.&lt;/p&gt;
&lt;p&gt;To bridge the gap, we re-architected the core engines of OAP around an AOT-first model. Earlier experiments had to confront Groovy-era runtime behavior directly and explore alternative script-compilation approaches to get around it. The finalized direction went further: align with the upstream compiler pipeline, move dynamic generation to build time, and add automation so the migration stays controllable as upstream keeps moving. Concretely, that meant turning OAL, MAL, LAL, and Hierarchy generation into build-time precompiler outputs instead of leaving them as startup-time dynamic behavior.&lt;/p&gt;
&lt;h2 id=&#34;ai-speed-changed-the-design-loop&#34;&gt;AI Speed Changed the Design Loop&lt;/h2&gt;
&lt;p&gt;The scale of this transformation was not only about coding faster. AI changed the loop between idea, prototype, validation, and redesign. We could build runnable PoCs for different approaches, throw away weak ones quickly, and preserve the promising abstractions until they formed a coherent migration system.&lt;/p&gt;
&lt;p&gt;That does not reduce the role of human architecture. It raises the value of it. Human judgment was still required to decide what should become build-time, what should stay configurable, where to introduce same-FQCN replacements, how to keep upstream sync controllable, and which abstractions were worth preserving. But AI speed made it realistic to pursue those better designs instead of settling for a simpler compromise too early.&lt;/p&gt;
&lt;p&gt;This is the real change in the economics of architecture. In the past, an architect might already know the cleaner direction, but limited engineering capacity often forced that vision back toward a cheaper compromise. Now the architect can return much closer to being a fast developer again: building code, shaping high-abstraction interfaces, and using design patterns to prove the vision directly in the real world.&lt;/p&gt;
&lt;p&gt;That changes communication as much as implementation. In open source, we often say, &lt;code&gt;talk is cheap, show me the code&lt;/code&gt;. With AI engineering, showing the code becomes much more straightforward. The design no longer depends so heavily on a slow top-down translation from idea to documents to interpretation to implementation. The code can appear earlier, and it can run earlier.&lt;/p&gt;
&lt;p&gt;Other senior engineers benefit from this too. They do not need to reconstruct the whole design only from diagrams, meetings, or long explanations. They can review the actual abstraction, see the behavior in code, run it, challenge it, and refine it from something concrete. That makes architectural collaboration faster, clearer, and less lossy.&lt;/p&gt;
&lt;p&gt;This is also where I think the current AI discussion is often noisy. Many projects are fun, surprising, and worth exploring, but advanced engineering work is not improved merely by attaching an agent to a codebase. The important question is not which demo looks most magical. The important question is which engineering capabilities are actually being accelerated without losing the discipline of software development itself.&lt;/p&gt;
&lt;p&gt;For architects and senior engineers, the capabilities that mattered most here were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fast comparative prototyping:&lt;/strong&gt; Building several runnable approaches in code instead of defending one idea with slides and documents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large-scale code comprehension:&lt;/strong&gt; Reading across many modules quickly enough to keep the whole system in view.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Systematic refactoring:&lt;/strong&gt; Converting reflection-heavy or runtime-dynamic paths into designs that fit AOT constraints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation construction:&lt;/strong&gt; When a migration step must be repeated every upstream sync, doing it manually once is already expensive. Doing it manually again next time is even more expensive. AI made it practical to invest in generators, inventories, consistency checks, and drift detectors that turn repeated manual work into repeatable automation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review at breadth:&lt;/strong&gt; Checking edge cases, compatibility boundaries, and repeatability across a large surface area.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those capabilities were visible in the resulting design. Same-FQCN replacements created a controlled boundary for GraalVM-specific behavior. Reflection metadata was generated from build outputs instead of maintained as a hand-written guess list. Inventories and drift detectors turned upstream sync from a vague maintenance risk into an explicit engineering workflow.&lt;/p&gt;
&lt;p&gt;For junior engineers, I think the lesson is equally important. AI does not remove the need to learn architecture, invariants, interfaces, testing, or maintenance. It makes those skills more valuable, because they determine whether accelerated implementation produces a durable system or just more code faster. The leverage comes from engineering judgment, not from novelty.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; and &lt;strong&gt;Gemini AI&lt;/strong&gt; acted as engineering accelerators throughout this process. In the GraalVM Distro specifically, they helped us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explore migration strategies as running code:&lt;/strong&gt; Instead of debating which approach might work, we built and compared multiple real prototypes, discarded the weak ones, and kept what held up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refactor reflection-heavy and dynamic code paths:&lt;/strong&gt; Replace runtime-hostile patterns with AOT-friendly alternatives across the codebase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make upstream sync sustainable:&lt;/strong&gt; Every time the distro pulls from upstream SkyWalking, metadata scanning, config regeneration, and recompilation must happen again. AI helped build the pipeline so that each sync is a controlled, largely automated process rather than a fresh manual effort that grows longer each time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review logic and edge cases at scale:&lt;/strong&gt; Especially in places where feature parity mattered more than raw implementation speed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result was not just a large rewrite. It was a repeatable system: precompilers, manifest-driven loading, reflection-config generation, replacement boundaries, and drift detectors that make upstream migration reviewable and automatable.&lt;/p&gt;
&lt;p&gt;For the broader methodology behind this style of development, see &lt;a href=&#34;https://builder.aws.com/content/3AgtzlikuD9bSUJrWDCjGW5Q5nW/agentic-vibe-coding-in-a-mature-oss-project-what-worked-what-didnt&#34;&gt;Agentic Vibe Coding in a Mature OSS Project&lt;/a&gt;. This post is the next step in that story: not only enhancing an active mature codebase, but reviving a paused effort and making it actually runnable.&lt;/p&gt;
&lt;h2 id=&#34;what-actually-changed&#34;&gt;What Actually Changed&lt;/h2&gt;
&lt;p&gt;The most important outcome of this project is not a benchmark table. The benchmark results belong to the distro itself, and they matter because they prove the system is real. But for this post, the deeper result is methodological: AI engineering changed how architecture could be explored, validated, and refined.&lt;/p&gt;
&lt;p&gt;Instead of treating architecture as a mostly document-driven activity followed by a long and expensive implementation phase, we were able to move much faster between idea, prototype, comparison, and redesign. That made it realistic to pursue higher-abstraction solutions, preserve cleaner boundaries, and build the automation needed to keep the migration maintainable over time.&lt;/p&gt;
&lt;p&gt;The technical evidence for that work is the SkyWalking GraalVM Distro itself: not only a runnable system, but a migration pipeline expressed as precompilers, generated reflection metadata, controlled replacement boundaries, and drift checks. The benchmark data matter because they prove the system works in practice, but the architectural result is that the migration became a repeatable system rather than a one-time port. For detailed benchmark methodology, per-pod data, and the full technical design, see &lt;a href=&#34;https://skywalking.apache.org/blog/2026-03-13-how-ai-changed-the-economics-of-architecture/&#34;&gt;SkyWalking GraalVM Distro: Design and Benchmarks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The project is hosted at &lt;a href=&#34;https://github.com/apache/skywalking-graalvm-distro&#34;&gt;apache/skywalking-graalvm-distro&lt;/a&gt;. We invite the community to test it, report issues, and help move it toward production readiness.&lt;/p&gt;
&lt;p&gt;For me, the deeper takeaway is broader than this distro. AI engineering does not make architecture less important. It makes architecture more worth pursuing. When implementation speed rises enough, we can afford to test more ideas in code, keep the good abstractions, and build systems that would previously have been judged too expensive to finish well.&lt;/p&gt;
&lt;p&gt;For senior engineers, that means the bottleneck shifts away from raw typing speed and toward taste, system judgment, and the ability to define stable boundaries. For junior engineers, it means the path forward is not to chase every exciting AI workflow, but to become stronger at the fundamentals that let acceleration compound: understanding requirements, reading unfamiliar systems, questioning assumptions, and recognizing what must remain correct as everything around it changes. AI changed the economics of architecture because it lowered the cost of validating better designs without lowering the bar for engineering judgment.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Blog: Agentic Vibe Coding in a Mature OSS Project: What Worked, What Didn&#39;t</title>
      <link>/blog/2026-03-08-agentic-vibe-coding/</link>
      <pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate>
      <guid>/blog/2026-03-08-agentic-vibe-coding/</guid>
      <description>
        
        
        &lt;p&gt;Most &amp;ldquo;vibe coding&amp;rdquo; stories start with a greenfield project. This one doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Apache SkyWalking is a 9-year-old observability platform with hundreds of production deployments, a complex DSL stack, and an external API surface that users have built dashboards, alerting rules, and automation scripts against. When I decided to replace the core scripting engine — purging the Groovy runtime from four DSL compilers — the constraint wasn&amp;rsquo;t &amp;ldquo;can AI write the code?&amp;rdquo; It was: &amp;ldquo;can AI write the code without breaking anything for existing users?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The answer turned out to be yes — &lt;strong&gt;~77,000 lines changed across 10 major PRs in about 5 weeks&lt;/strong&gt; — but only because the AI was tightly guided by a human who understood the project&amp;rsquo;s architecture, its compatibility contracts, and its users. This post is about the methodology: what worked, what didn&amp;rsquo;t, and what mature open-source maintainers should know before handing their codebase to AI agents.&lt;/p&gt;
&lt;h2 id=&#34;the-project-in-brief&#34;&gt;The Project in Brief&lt;/h2&gt;
&lt;p&gt;The task was to replace SkyWalking&amp;rsquo;s Groovy-based scripting engines (MAL, LAL, Hierarchy) with a unified ANTLR4 + Javassist bytecode compilation pipeline, matching the architecture already proven by the OAL compiler. The internal tech stack was completely overhauled; the external interface had to remain identical.&lt;/p&gt;
&lt;p&gt;Beyond the compiler rewrites, the scope included a new queue infrastructure (threads dropped from 36 to 15), virtual thread support for JDK 25+, and E2E test modernization. By conventional estimates, this was 5-8 months of senior engineer work.&lt;/p&gt;
&lt;p&gt;For the full technical details on the compiler architecture, see the &lt;a href=&#34;https://github.com/apache/skywalking/discussions/13716&#34;&gt;Groovy elimination discussion&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;what-is-agentic-vibe-coding&#34;&gt;What is Agentic Vibe Coding?&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Vibe coding&amp;rdquo; — a term coined by Andrej Karpathy — describes a style of programming where you describe intent and let AI write the code. It&amp;rsquo;s powerful for prototyping, but on its own, it&amp;rsquo;s risky for production systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agentic vibe coding&lt;/strong&gt; takes this further: instead of a single AI autocomplete, you orchestrate multiple AI agents — each with different strengths — under your architectural direction, with automated tests as the safety net. In my workflow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Claude Code (plan mode)&lt;/strong&gt;: Primary coding agent. Plan mode lets me review the approach before any code is generated. This is critical for architectural decisions — I steer the design, Claude handles the implementation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gemini&lt;/strong&gt;: Code review, concurrency analysis, and verification reports. Gemini reviewed every major PR for thread-safety, feature parity, and edge cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Codex&lt;/strong&gt;: Autonomous task execution for well-defined, bounded work items.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key insight: &lt;strong&gt;AI writes the code, but the architect owns the design.&lt;/strong&gt; Without deep domain knowledge of SkyWalking&amp;rsquo;s internals, no AI could have planned these changes. Without AI, I couldn&amp;rsquo;t have executed them in 5 weeks.&lt;/p&gt;
&lt;h2 id=&#34;how-tdd-made-ai-coding-safe&#34;&gt;How TDD Made AI Coding Safe&lt;/h2&gt;
&lt;p&gt;The reason I could move this fast without breaking things comes down to one principle: &lt;strong&gt;never let AI code without a test harness.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My workflow for each major change:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Plan mode first&lt;/strong&gt;: Describe the goal to Claude, review the plan, iterate on architecture before any code is written.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write the test contract&lt;/strong&gt;: Define what &amp;ldquo;correct&amp;rdquo; means — for the compiler rewrites, this meant cross-version comparison tests that run every expression through both the old and new engines, asserting identical results across 1,290+ expressions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Let AI implement&lt;/strong&gt;: With the test contract in place, Claude can write thousands of lines of implementation code. If it&amp;rsquo;s wrong, the tests catch it immediately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E2E as the final gate&lt;/strong&gt;: Every PR must pass the full E2E test suite — Docker-based integration tests that boot the entire server with real storage backends.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI code review&lt;/strong&gt;: Gemini reviewed each PR for concurrency issues, thread-safety, and feature parity — catching things that unit tests alone wouldn&amp;rsquo;t find.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the opposite of &amp;ldquo;hope it works&amp;rdquo; vibe coding. The AI writes fast, the tests verify fast, and I steer the architecture. The feedback loop is tight enough that I can iterate on complex compiler code in minutes instead of days.&lt;/p&gt;
&lt;h2 id=&#34;lessons-learned&#34;&gt;Lessons Learned&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AI is a force multiplier, not a replacement.&lt;/strong&gt; Before any AI agent wrote a single line, a human had to define the replacement solution: &lt;em&gt;what&lt;/em&gt; gets replaced, &lt;em&gt;how&lt;/em&gt; it gets replaced, and — critically — &lt;em&gt;where the boundaries are&lt;/em&gt;. Which APIs could break? The internal compilation pipeline was fair game for a complete overhaul. Which APIs must stay aligned? Every external-facing DSL syntax, every YAML configuration key, every metrics name and tag structure had to remain byte-for-byte identical — because hundreds of deployed dashboards, alerting rules, and user scripts depend on them. Drawing these boundaries required deep knowledge of the codebase and its users. AI executed the plan at extraordinary speed, but the plan itself — the scope, the invariants, the compatibility contract — had to come from a human who understood the blast radius of every change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plan mode is non-negotiable for architectural work.&lt;/strong&gt; Letting AI jump straight to code on a compiler rewrite would be a disaster. Plan mode&amp;rsquo;s strength is that it collects code context — scanning imports, tracing call chains, mapping class hierarchies — and uses that context to help me fill in implementation details I&amp;rsquo;d otherwise have to look up manually. But it can&amp;rsquo;t tell you the design principles. That direction had to come from me, stated clearly upfront, so the AI&amp;rsquo;s planning stayed on the right track instead of optimizing toward a locally reasonable but architecturally wrong solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Know when to hit ESC.&lt;/strong&gt; Claude has a clear tendency to dive deep into solution code writing once it starts — and it won&amp;rsquo;t stop on its own when it encounters something that conflicts with the original plan&amp;rsquo;s concept. Instead of pausing to flag the conflict, it will push forward, improvising around the obstacle in ways that silently violate the design intent. I had to learn to watch for this: when Claude&amp;rsquo;s output started drifting from the plan, I&amp;rsquo;d manually cancel the task (ESC), call it off, identify where the plan and reality diverged, adjust the plan, and restart. This interrupt-replan cycle was a regular part of the workflow, not an exception. The architect has to stay in the loop — not just at planning time, but during execution — because AI agents don&amp;rsquo;t yet know when to stop and ask.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spec-driven testing is necessary but not sufficient — the logic workflow matters more.&lt;/strong&gt; It&amp;rsquo;s tempting to think that if you define the input/output spec clearly enough, AI can fill in the implementation and tests will catch any mistakes. I tried this. It doesn&amp;rsquo;t work for anything non-trivial. During the expression compiler rewrite, Claude would sometimes change code in unreasonable ways just to make the spec tests pass — the inputs went in, the expected outputs came out, and everything looked green. But the internal logic was wrong: inconsistent with the design patterns the rest of the codebase relied on, impossible to extend, or solving the specific test case through a hack rather than a general mechanism. A spec only checks &lt;em&gt;what&lt;/em&gt; the code produces; it says nothing about &lt;em&gt;how&lt;/em&gt; the code produces it. For a mature project, the &amp;ldquo;how&amp;rdquo; matters enormously — the solution needs to be consistent with the existing architecture, widely adoptable by contributors, and maintainable long-term. That&amp;rsquo;s why I needed cross-version testing &lt;em&gt;and&lt;/em&gt; human review of the implementation path, not just the results.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testing at two levels kept the rewrite honest.&lt;/strong&gt; Cross-version testing was part of my design plan from the start — I architected the dual-path comparison framework so that every production DSL expression runs through both the old and new engines, asserting identical results across 1,290+ expressions. This gave me confidence no human review could match, and it was a deliberate planning decision: I knew AI-generated compiler code needed a mechanical proof of behavioral equivalence, not just eyeball review. On top of that, E2E tests served as the project&amp;rsquo;s existing infrastructure safety net — Docker-based integration tests that boot the entire server with real storage backends. Unit tests and cross-version tests verify logic in isolation; E2E tests verify the system actually works end-to-end. For infrastructure-level changes like queue replacement and thread model changes, E2E is the only gate that truly matters. Together, the two layers — designed-for-this-rewrite cross-version tests and pre-existing E2E infrastructure — caught different classes of bugs and made shipping with confidence possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple AIs have different strengths.&lt;/strong&gt; Claude excels at large-scale code generation with plan mode. Gemini is exceptional at logic review — it can mentally trace code branches with given input data, simulating execution without actually running the code. This is significant for reviewing AI-generated code: Gemini would walk through a generated compiler method step by step, flagging where a null check was missing or where a branch would produce wrong output for a specific edge case. Codex proved most valuable as a test reviewer and honesty checker. AI-generated code has a subtle failure mode: the coding agent can make wrong assumptions and then write tests that pass by setting expected values to match the wrong behavior — effectively bypassing the test safety net. Codex caught cases where Claude had set unreasonable expected values that happened to make tests green, masking logic errors that would have surfaced in production. Using all three as checks on each other was far more effective than relying on any single one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Mythical Man-Month still applies — and so does the Mythical Token-Month.&lt;/strong&gt; Brooks taught us that a task requiring 12 person-months does not mean 12 people can finish it in one month. The same law applies to AI: you cannot simply throw more tokens, more agents, or more parallel sessions at a problem and expect it to converge faster. Communication costs, coordination overhead, requirements analysis, and conceptual integrity — these software engineering fundamentals do not disappear just because your workforce is artificial. Worse, when the direction is wrong — when there&amp;rsquo;s a conceptual error in the design or an unreasonable architectural choice — AI will not recognize it. It will charge down the wrong path at extraordinary speed, burning tokens furiously while trapped in a vortex of self-justification: patching code to make failing tests pass, adjusting expected values to match wrong behavior, adding workarounds on top of workarounds — each iteration making the codebase look more &amp;ldquo;complete&amp;rdquo; while drifting further from correctness. AI vibe coding cannot break out of this spiral on its own. Only a human who understands the domain can recognize &amp;ldquo;this is fundamentally wrong, stop,&amp;rdquo; discard the work, and redirect. Speed without direction is just expensive chaos.&lt;/p&gt;
&lt;h2 id=&#34;the-bigger-picture&#34;&gt;The Bigger Picture&lt;/h2&gt;
&lt;p&gt;The agentic vibe coding approach worked because it combined AI&amp;rsquo;s speed with human architectural judgment and automated test discipline. It&amp;rsquo;s not magic — it&amp;rsquo;s engineering, accelerated.&lt;/p&gt;
&lt;p&gt;Brooks also gave us &amp;ldquo;No Silver Bullet,&amp;rdquo; and its core distinction matters more than ever: software complexity comes in two kinds. &lt;strong&gt;Essential complexity&lt;/strong&gt; comes from the problem itself — the domain semantics, the behavioral contracts, the concurrency invariants. No tool can eliminate this; it must be understood, modeled, and reasoned about by someone who knows the domain. &lt;strong&gt;Accidental complexity&lt;/strong&gt; comes from the tools and implementation — boilerplate code, manual refactoring across hundreds of files, the mechanical work of translating a design into compilable source. This is exactly where AI excels. What made this project work was recognizing which complexity was which: I owned the essential complexity (architecture, API boundaries, correctness invariants), and AI demolished the accidental complexity (generating 77K lines of implementation, scaffolding test harnesses, rewriting repetitive patterns across dozens of config files). Confuse the two — let AI make essential decisions, or waste human time on accidental work — and you get the worst of both worlds.&lt;/p&gt;
&lt;p&gt;Qian Xuesen(Tsien Hsue-shen)&amp;rsquo;s &lt;em&gt;Engineering Cybernetics&lt;/em&gt; offers another lens that proved surprisingly relevant. His core framework — &lt;strong&gt;feedback&lt;/strong&gt;, &lt;strong&gt;control&lt;/strong&gt;, &lt;strong&gt;optimization&lt;/strong&gt; — describes how to keep complex systems running toward their target. AI vibe coding at full speed is like a hypersonic missile: extraordinarily fast, but without a guidance system it just creates a bigger crater in the wrong place. The feedback loop in my workflow was the test harness — cross-version tests and E2E tests providing continuous signal on whether the system was still on course. Control was the human architect deciding when to intervene: reviewing plans before execution, hitting ESC when the direction drifted, choosing which AI to trust for which task. Optimization was iterative: each interrupt-replan cycle refined the approach, each Gemini review tightened the logic, each Codex audit caught assumptions the coding agent had smuggled past the tests. Without all three — feedback to detect deviation, control to correct course, optimization to converge — the speed of AI coding would be not an advantage but a liability. The faster the missile, the more precise the guidance must be.&lt;/p&gt;
&lt;p&gt;For more details or to share your own experience with agentic coding on production systems, feel free to reach me on &lt;a href=&#34;https://github.com/wu-sheng&#34;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Zh: 在成熟开源大型项目中实践 Agentic Vibe Coding：软件工程与工程控制论还在延续</title>
      <link>/zh/2026-03-08-agentic-vibe-coding/</link>
      <pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate>
      <guid>/zh/2026-03-08-agentic-vibe-coding/</guid>
      <description>
        
        
        &lt;p&gt;大多数&amp;quot;vibe coding&amp;quot;的故事都从一个全新项目开始，讲述一个快速构建原型或者可运行项目的过程，但这篇不是。&lt;/p&gt;
&lt;p&gt;Apache SkyWalking 是一个有 9 年历史的Apache顶级项目，线上数以千计的集群部署，内部有一套复杂的 DSL 编译栈，对外暴露的 API 上承载着用户构建的仪表盘、告警规则和自动化脚本。当我决定替换核心脚本引擎——从四个 DSL 编译器中彻底移除 Groovy 运行时——面临的问题不是&amp;quot;AI 能不能写出代码&amp;quot;，而是&amp;quot;也许只有AI能完成如此大规模的一致性迭代&amp;quot;，以及&amp;quot;AI 能不能在不破坏系统的前提下写出完整且高效的代码&amp;quot;。&lt;/p&gt;
&lt;p&gt;答案是可以——&lt;strong&gt;约 7.7 万行代码变更，10 个主要 PR，历时约 5 周&lt;/strong&gt;——但前提是 AI 始终在一个深刻理解项目架构、兼容性要求和用户场景的人的引导下工作。这篇文章分享了我在过去几个月的实践体验，以及成熟开源项目的维护者在把代码库交给 AI 智能体之前应该知道什么。&lt;/p&gt;
&lt;h2 id=&#34;项目概况&#34;&gt;项目概况&lt;/h2&gt;
&lt;p&gt;这次的任务是将 SkyWalking 基于 Groovy 的脚本引擎（MAL、LAL、Hierarchy）替换为统一的 ANTLR4 + Javassist 字节码编译管线，对齐 OAL 编译器已经验证过的架构。内部技术栈彻底重构，但对外接口必须保持完全一致。&lt;/p&gt;
&lt;p&gt;除了编译器重写，范围还包括新的线程管理策略（线程数从 36 降到 15）、JDK 25+ 虚拟线程支持，以及端到端测试的现代化改造。按传统估算，这是 5-8 个月的资深工程师（以我自己为例）工作量。&lt;/p&gt;
&lt;p&gt;编译器架构的完整技术细节，参见 &lt;a href=&#34;https://github.com/apache/skywalking/discussions/13716&#34;&gt;Groovy 移除讨论&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;什么是-agentic-vibe-coding&#34;&gt;什么是 Agentic Vibe Coding？&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;Vibe coding&amp;rdquo;——Andrej Karpathy 提出的概念——描述的是一种你表达意图、让 AI 来写代码的编程风格。整个AI编程过程，一直以来都是用来做原型，效果强大且速度迅猛，但单独用于生产系统是有风险的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agentic vibe coding&lt;/strong&gt; 更进一步：不是单一的 AI 自动补全，而是在你的架构指导下编排多个 AI 智能体——各有所长——以自动化测试作为安全网。我的工作流是这样的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Claude Code（plan 模式）&lt;/strong&gt;：主力编码智能体。Plan 模式让我在生成任何代码之前先审查方案。这对架构决策至关重要——我把控设计方向，Claude 负责实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gemini&lt;/strong&gt;：代码审查、并发分析和验证报告。每个主要 PR 都经过 Gemini 审查线程安全性、功能对等性和边界情况。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Codex&lt;/strong&gt;：对定义明确、边界清晰的工作项进行自主任务执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;核心洞察：&lt;strong&gt;AI 写代码，但架构师掌控设计。&lt;/strong&gt; 没有对 SkyWalking 内部机制的深入领域知识，任何 AI 都无法规划这些变更。没有 AI，我也不可能在 5 周内完成执行。&lt;/p&gt;
&lt;h2 id=&#34;tdd-如何让-ai-编程变得安全&#34;&gt;TDD 如何让 AI 编程变得安全&lt;/h2&gt;
&lt;p&gt;我能以这样的速度推进而不搞砸，归结为一个原则：&lt;strong&gt;绝不让 AI 在没有测试保护的情况下写代码。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;每次重大变更的工作流：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先进 plan 模式&lt;/strong&gt;：向 Claude 描述目标，审查方案，在写任何代码之前先在架构层面迭代。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编写测试契约&lt;/strong&gt;：定义&amp;quot;正确&amp;quot;意味着什么——对于编译器重写，这意味着交叉版本对比测试，让每个表达式同时通过新旧两个引擎运行，在 1290+ 个表达式上断言结果完全一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;让 AI 实现&lt;/strong&gt;：有了测试契约，Claude 可以写出数千行实现代码。如果写错了，测试会立即捕获。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;端到端测试作为最终关卡&lt;/strong&gt;：每个 PR 都必须通过完整的端到端测试套件——基于 Docker 的集成测试，启动整个服务器并连接真实存储后端。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 代码审查&lt;/strong&gt;：Gemini 审查每个 PR 的并发问题、线程安全性和功能对等性——捕获单元测试无法发现的问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这和&amp;quot;写完祈祷能跑&amp;quot;的 vibe coding 完全相反。AI 写得快，测试验证得快，我把控架构方向。反馈循环足够紧凑，让我能在几分钟而不是几天内迭代复杂的编译器代码。&lt;/p&gt;
&lt;h2 id=&#34;经验教训&#34;&gt;经验教训&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AI 是力量倍增器，不是替代品。&lt;/strong&gt; 在任何 AI 智能体写下第一行代码之前，必须由人来定义替换方案：&lt;em&gt;替换什么&lt;/em&gt;、&lt;em&gt;怎么替换&lt;/em&gt;，以及——至关重要的——&lt;em&gt;边界在哪里&lt;/em&gt;。哪些 API 可以破坏性变更？内部编译管线可以彻底重构。哪些 API 必须保持对齐？每一个对外的 DSL 语法、每一个 YAML 配置键、每一个指标名称和标签结构都必须逐字节保持一致——因为数百个已部署的仪表盘、告警规则和用户脚本依赖于它们。划定这些边界需要对代码库及其用户的深入了解。AI 以惊人的速度执行了计划，但计划本身——范围、不变量、兼容性契约——必须来自一个理解每次变更影响半径的人。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;架构级工作，plan 模式不可妥协。&lt;/strong&gt; 让 AI 在编译器重写上直接跳到写代码，那是灾难。Plan 模式的价值在于它会收集代码上下文——扫描 import、追踪调用链、映射类继承关系——并利用这些上下文帮我补全那些我本来需要手动查找的实现细节。但它无法告诉你设计原则。方向必须由我在前期明确给出，这样 AI 的规划才能沿着正确的轨道走，而不是朝着一个局部合理但架构上错误的方案去优化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要知道什么时候该按 ESC。&lt;/strong&gt; Claude 有一个明显的倾向：一旦开始写解决方案代码就会一头扎进去——当遇到与原始计划概念冲突的东西时，它不会自己停下来。它不会暂停来标记冲突，而是会继续推进，用即兴的方式绕过障碍，悄无声息地违背设计意图。我必须学会观察这个信号：当 Claude 的输出开始偏离计划时，我会手动取消任务（ESC），叫停它，找出计划和现实的分歧点，调整计划，然后重新开始。这种中断-重新规划的循环是工作流的常态，而非例外。架构师必须始终在环路中——不仅是在规划阶段，执行阶段也是——因为 AI 智能体还不知道什么时候该停下来问一句。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spec-Driven 更多的运用于测试，而非开发。它只是一个必要的但不充分条件，而逻辑工作流更重要。&lt;/strong&gt; 很容易产生一种想法：只要把输入/输出规格定义得足够清楚，AI 就能填充实现，测试会捕获任何错误。我试过。对于任何复杂的生产场景，这行不通。在表达式编译器重写过程中，Claude 有时会以不合理的方式修改代码，仅仅为了让规格测试通过——输入进去了，预期输出出来了，一切看起来都是正常的。但内部逻辑是错的：与代码库其他部分依赖的设计模式不一致，无法扩展，或者通过 hack （代码反射、字段名称静态比较等不可接受的工程方法）而非通用机制来解决特定测试用例。规格只检查代码&lt;em&gt;产出了什么&lt;/em&gt;；它对代码&lt;em&gt;如何产出&lt;/em&gt;一无所知。对于成熟项目，&amp;ldquo;如何&amp;quot;极其重要——解决方案需要与现有架构一致，能被贡献者广泛采用，并且长期可维护可扩展。这就是为什么我需要交叉版本测试&lt;em&gt;加上&lt;/em&gt;对实现路径的人工审查，而不仅仅是审查结果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;两个层次的测试让重写的代码验证更有保障。&lt;/strong&gt; 交叉版本测试从一开始就是我设计方案的一部分——我架构了双路径对比框架，让每个生产环境的 DSL 表达式同时通过新旧两个引擎运行，在 1290+ 个表达式上断言结果完全一致。这给了我任何人工审查都无法匹敌的信心，而且这是一个刻意的规划决策：我知道 AI 生成的编译器代码需要行为等价性的机械证明，而不仅仅是肉眼审查。在此之上，端到端测试作为项目已有的基础设施安全网——基于 Docker/K8s 的集成测试，启动整个服务器并连接真实存储后端。单元测试和交叉版本测试在隔离环境中验证逻辑；端到端测试验证系统真正能端到端地工作。对于队列替换和线程模型变更这样的基础设施级变更，端到端测试是唯一真正重要的关卡。两个层次——为本次重写专门设计的交叉版本测试和预先存在的端到端基础设施——捕获了不同类别的 bug，使得有信心地发布成为可能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多个 AI 各有所长。&lt;/strong&gt; Claude 擅长配合 plan 模式进行大规模代码生成。Gemini 在逻辑审查方面表现出色——它能在给定输入数据的情况下在脑中追踪代码分支，模拟执行而无需实际运行代码。这对审查 AI 生成的代码意义重大：Gemini 会逐步走查一个编译器生成的方法，标记出哪里缺少空值检查，或者哪个分支在特定边界情况下会产生错误输出。Codex 作为测试审查者和诚实性检查者最有价值。AI 生成的代码有一种微妙的失败模式：编码智能体可能做出错误假设，然后编写测试时将期望值设置为匹配错误行为——实际上绕过了测试安全网。Codex 捕获了 Claude 设置不合理期望值使测试变绿的情况，掩盖了本会在生产环境中暴露的逻辑错误。将三者互相校验，远比依赖其中任何一个更有效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;人月神话依然适用——基于Token的AI月神话同样如此。&lt;/strong&gt; Brooks 告诉我们，一个需要 12 人月的任务不意味着 12 个人能在一个月内完成。同样的定律适用于 AI：你不能简单地投入更多 token、更多智能体或更多并行会话，就指望问题更快收敛。沟通成本、协调开销、需求分析和概念完整性——这些软件工程的基本规律不会因为你的劳动力是人工智能就消失。更糟糕的是，当方向错误时——当设计中存在概念性错误或不合理的架构选择时——AI 不会识别出来。它会以惊人的速度冲向错误的方向，疯狂消耗 token，同时陷入自我辩护的漩涡：修补代码让失败的测试通过，调整期望值去匹配错误行为，在变通方案上叠加变通方案——每次迭代都让代码库看起来更&amp;quot;完整&amp;rdquo;，实际上却离正确越来越远。AI vibe coding 无法自行跳出这个螺旋。只有理解领域的人才能认识到&amp;quot;这从根本上就是错的，停下来&amp;quot;，丢弃这些工作，重新引导方向。没有方向的速度，只是昂贵的混乱。&lt;/p&gt;
&lt;h2 id=&#34;更大的图景&#34;&gt;更大的图景&lt;/h2&gt;
&lt;p&gt;Agentic vibe coding 之所以有效，是因为它将 AI 的速度与人的架构判断力和自动化测试纪律结合在了一起。这不是魔法——这是被加速的工程。&lt;/p&gt;
&lt;p&gt;Brooks 还给了我们《没有银弹》，其核心区分在今天比以往任何时候都更重要：软件复杂性分为两种。&lt;strong&gt;本质复杂性&lt;/strong&gt;来自问题本身——领域语义、行为契约、并发不变量。没有任何工具能消除它；它必须由理解领域的人去理解、建模和推理。&lt;strong&gt;偶然复杂性&lt;/strong&gt;来自工具和实现——样板代码、跨数百个文件的手动重构、将设计翻译成可编译源码的机械工作。这恰恰是 AI 擅长的地方。这个项目之所以成功，在于认清了哪种复杂性是哪种：我掌控本质复杂性（架构、API 边界、正确性不变量），AI 消灭偶然复杂性（生成 7.7 万行实现代码、搭建测试框架、跨数十个配置文件重写重复模式）。搞混这两者——让 AI 做本质决策，或者让人浪费时间在偶然工作上——你会得到两个世界中最差的结果。&lt;/p&gt;
&lt;p&gt;钱学森的《工程控制论》提供了另一个视角，在实践中出人意料地切题。他的核心框架——&lt;strong&gt;反馈&lt;/strong&gt;、&lt;strong&gt;控制&lt;/strong&gt;、&lt;strong&gt;优化&lt;/strong&gt;——描述的是如何让复杂系统持续朝目标运行。全速运转的 AI vibe coding 就像一枚高超音速导弹：速度惊人，但没有制导系统只会在错误的地方炸出一个更大的坑。我工作流中的反馈回路是测试体系——交叉版本测试和端到端测试持续提供系统是否仍在航线上的信号。控制是人类架构师决定何时介入：在执行前审查方案，在方向偏移时按 ESC，选择哪个 AI 负责哪项任务。优化是迭代式的：每次中断-重新规划的循环都在精炼方法，每次 Gemini 审查都在收紧逻辑，每次 Codex 审计都在捕获编码智能体偷偷绕过测试的假设。缺少其中任何一个——检测偏差的反馈、纠正航向的控制、趋向收敛的优化——AI 编程的速度就不是优势而是负债。导弹越快，制导就必须越精确。&lt;/p&gt;
&lt;p&gt;AI Vibe Coding以及它的迭代，正在快速地走进每一个开发者，也正在广泛地融入开源和商业软件。我们都在见证这种新的开发模式，以及AI Vibe Coding和软件工程理论的融合。如果你想和我探讨更多的AI + OSS话题，欢迎在 &lt;a href=&#34;https://github.com/wu-sheng&#34;&gt;GitHub&lt;/a&gt; 上联系我。&lt;/p&gt;

      </description>
    </item>
    
  </channel>
</rss>
