為什麼 LLM 追蹤需要標準化?

過去幾年,每個 LLM 工具都發明了自己的追蹤格式。Langfuse 有獨特的結構,Helicone 也有自己的格式, Arize 也不例外。這種碎片化導致一個嚴重問題:當你想更換供應商或同時使用多個工具時,必須重新實作整個追蹤系統。

OpenTelemetry(OTel)近日宣布標準化 LLM 追蹤,為這個混亂的局面帶來解決方案。採用統一標準後,開發者可以在不同工具之間無縫遷移,同時保有完整的可觀測性。

OpenTelemetry LLM 追蹤的基礎語意

OTel 定義了專門的語意約定來描述 LLM 請求。這些屬性讓不同工具能夠解讀相同的追蹤資料:

  • llm.system:使用的模型名稱(如 gpt-4、claude-3)
  • llm.prompt:傳送給模型的提示詞
  • llm.completion:模型生成的回應
  • llm.token_count.promptllm.token_count.completion:輸入輸出代幣數
  • llm.streaming:是否為串流回應

這些標準化屬性確保任何相容 OTel 的後端都能正確解析你的 LLM 呼叫紀錄。

Python 實作:使用 OpenTelemetry 追蹤 OpenAI 呼叫

以下是完整的程式碼範例,展示如何在 Python 中使用 OpenTelemetry 追蹤 LLM 請求:

from opentelemetry import trace
from opentelemetry.trace import SpanKind
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource

# 初始化追蹤供應商
resource = Resource(attributes={"service.name": "my-llm-app"})
provider = TracerProvider(resource=resource)
trace.set_tracer_provider(provider)

# 設定 OTLP 匯出至任何相容後端
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:4317"))
provider.add_span_processor(processor)

tracer = trace.get_tracer(__name__)

# 追蹤 LLM 呼叫
def call_openai(prompt: str):
    with tracer.start_as_current_span("llm.request", kind=SpanKind.CLIENT) as span:
        span.set_attribute("llm.system", "gpt-4")
        span.set_attribute("llm.prompt", prompt)
        span.set_attribute("llm.operation_name", "chat")
        
        response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[{"role": "user", "content": prompt}]
        )
        
        span.set_attribute("llm.completion", response.choices[0].message.content)
        span.set_attribute("llm.token_count.prompt", response.usage.prompt_tokens)
        span.set_attribute("llm.token_count.completion", response.usage.completion_tokens)
        
        return response

result = call_openai("用 Python 解釋什麼是閉包")

這段程式碼建立了一個完整的追蹤上下文,自動記錄模型名稱、提示詞、回應內容以及代幣使用量。你可以將資料匯出至 Jaeger、Zipkin 或任何支援 OTLP 的後端。

進階功能:自訂屬性與串流追蹤

除了基本追蹤,OTel 還支援更進階的場景。你可以為每次請求加入自訂元資料:

# 加入自訂屬性追蹤用戶與對話
span.set_attribute("user.id", user_id)
span.set_attribute("conversation.id", conversation_id)
span.set_attribute("request.metadata", json.dumps(metadata))

# 追蹤串流回應
with tracer.start_as_current_span("llm.stream") as stream_span:
    stream_span.set_attribute("llm.streaming", True)
    
    for chunk in openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        stream=True
    ):
        # 記錄每個串流區塊
        stream_span.add_event("chunk_received", {
            "content": chunk.choices[0].delta.content
        })

這些功能讓你能完整掌握 LLM 應用的行為,包括用戶互動、對話歷史以及即時回應處理。

如何開始:快速整合步驟

要在現有專案中加入 OTel LLM 追蹤,只需以下步驟:

  1. 安裝依賴:執行 pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
  2. 初始化供應商:在應用啟動時設定 TracerProvider
  3. 包裝 LLM 呼叫:使用 with tracer.start_as_current_span() 包覆你的 API 呼叫
  4. 設定匯出器:選擇 Jaeger、Zipkin 或自訂 OTLP 端點
  5. 驗證資料:打開追蹤介面確認資料正確傳送

標準化帶來的最大價值是靈活性:未來無論你想切換到 Langfuse、Helicone 或其他工具,只需更換匯出器設定,追蹤資料結構完全相容。