Skip to main content
LangSmith 支持基于 OpenTelemetry 的追踪,允许您从任何兼容 OpenTelemetry 的应用程序发送追踪信息。本指南涵盖了针对 LangChain 应用的自动埋点和其他框架的手动埋点。 了解如何使用 OpenTelemetry 结合 LangSmith 来追踪您的 LLM 应用程序。
在以下请求中,请根据自托管安装或位于欧盟地区的组织,适当更新 LangSmith URL。对于欧盟地区,请使用 eu.api.smith.langchain.com

追踪 LangChain 应用程序

如果您使用 LangChain 或 LangGraph,请使用内置集成来追踪您的应用程序:
  1. 安装支持 OpenTelemetry 的 LangSmith 包:
    pip install "langsmith[otel]"
    pip install langchain
    
    需要 Python SDK 版本 langsmith>=0.3.18。我们建议使用 langsmith>=0.4.25 以受益于重要的 OpenTelemetry 修复。
  2. 在您的 LangChain/LangGraph 应用中,通过设置 LANGSMITH_OTEL_ENABLED 环境变量来启用 OpenTelemetry 集成:
    LANGSMITH_OTEL_ENABLED=true
    LANGSMITH_TRACING=true
    LANGSMITH_ENDPOINT=https://api.smith.langchain.com
    LANGSMITH_API_KEY=<your_langsmith_api_key>
    # 对于关联了多个工作区的 LangSmith API 密钥,请设置 LANGSMITH_WORKSPACE_ID 环境变量以指定要使用的工作区。
    
  3. 创建一个启用追踪的 LangChain 应用程序。例如:
    import os
    from langchain_openai import ChatOpenAI
    from langchain_core.prompts import ChatPromptTemplate
    
    # 创建一个链
    prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
    model = ChatOpenAI()
    chain = prompt | model
    
    # 运行链
    result = chain.invoke({"topic": "programming"})
    print(result.content)
    
  4. 应用程序运行后,在您的 LangSmith 仪表板(示例)中查看追踪信息。

追踪非 LangChain 应用程序

对于非 LangChain 应用程序或自定义埋点,您可以使用标准的 OpenTelemetry 客户端在 LangSmith 中追踪您的应用程序。(我们推荐使用 langsmith >= 0.4.25。)
  1. 安装 OpenTelemetry SDK、OpenTelemetry 导出器包以及 OpenAI 包:
    pip install openai
    pip install opentelemetry-sdk
    pip install opentelemetry-exporter-otlp
    
  2. 设置端点环境变量,替换为您自己的值:
    OTEL_EXPORTER_OTLP_ENDPOINT=https://api.smith.langchain.com/otel
    OTEL_EXPORTER_OTLP_HEADERS="x-api-key=<your langsmith api key>"
    
    根据您的 otel 导出器配置方式,如果您仅发送追踪信息,可能需要在端点后追加 /v1/traces
    如果您是自托管 LangSmith,请将基础端点替换为您的 LangSmith API 端点,并追加 /api/v1。例如:OTEL_EXPORTER_OTLP_ENDPOINT=https://ai-company.com/api/v1/otel
    可选:指定一个非 “default” 的自定义项目名称:
    OTEL_EXPORTER_OTLP_ENDPOINT=https://api.smith.langchain.com/otel
    OTEL_EXPORTER_OTLP_HEADERS="x-api-key=<your langsmith api key>,Langsmith-Project=<project name>"
    
  3. 记录一个追踪。 此代码设置了一个 OTEL 追踪器和导出器,用于将追踪信息发送到 LangSmith。然后它调用 OpenAI 并发送所需的 OpenTelemetry 属性。
    from openai import OpenAI
    from opentelemetry import trace
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import (
        BatchSpanProcessor,
    )
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
    
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
    
    otlp_exporter = OTLPSpanExporter(
        timeout=10,
    )
    
    trace.set_tracer_provider(TracerProvider())
    trace.get_tracer_provider().add_span_processor(
        BatchSpanProcessor(otlp_exporter)
    )
    
    tracer = trace.get_tracer(__name__)
    
    def call_openai():
        model = "gpt-4.1-mini"
        with tracer.start_as_current_span("call_open_ai") as span:
            span.set_attribute("langsmith.span.kind", "LLM")
            span.set_attribute("langsmith.metadata.user_id", "user_123")
            span.set_attribute("gen_ai.system", "OpenAI")
            span.set_attribute("gen_ai.request.model", model)
            span.set_attribute("llm.request.type", "chat")
    
            messages = [
                {"role": "system", "content": "You are a helpful assistant."},
                {
                    "role": "user",
                    "content": "Write a haiku about recursion in programming."
                }
            ]
    
            for i, message in enumerate(messages):
                span.set_attribute(f"gen_ai.prompt.{i}.content", str(message["content"]))
                span.set_attribute(f"gen_ai.prompt.{i}.role", str(message["role"]))
    
            completion = client.chat.completions.create(
                model=model,
                messages=messages
            )
    
            span.set_attribute("gen_ai.response.model", completion.model)
            span.set_attribute("gen_ai.completion.0.content", str(completion.choices[0].message.content))
            span.set_attribute("gen_ai.completion.0.role", "assistant")
            span.set_attribute("gen_ai.usage.prompt_tokens", completion.usage.prompt_tokens)
            span.set_attribute("gen_ai.usage.completion_tokens", completion.usage.completion_tokens)
            span.set_attribute("gen_ai.usage.total_tokens", completion.usage.total_tokens)
    
            return completion.choices[0].message
    
    if __name__ == "__main__":
        call_openai()
    
  4. 在您的 LangSmith 仪表板(示例)中查看追踪信息。

发送追踪到其他提供商

虽然 LangSmith 是 OpenTelemetry 追踪的默认目标,但您也可以配置 OpenTelemetry 将追踪发送到其他可观测性平台。
在 LangSmith Python SDK >= 0.4.1 版本中可用。我们建议使用 >= 0.4.25 版本以获得改进 OTEL 导出和混合扇出稳定性的修复。

使用环境变量进行全局配置

默认情况下,LangSmith OpenTelemetry 导出器会将数据发送到 LangSmith API 的 OTEL 端点,但可以通过设置标准的 OTEL 环境变量来自定义:
OTEL_EXPORTER_OTLP_ENDPOINT: 覆盖端点 URL
OTEL_EXPORTER_OTLP_HEADERS: 添加自定义头部(LangSmith API 密钥和项目将自动添加)
OTEL_SERVICE_NAME: 设置自定义服务名称(默认为 "langsmith")
LangSmith 默认使用 HTTP 追踪导出器。如果您想使用自己的追踪提供者,可以:
  1. 如上所示设置 OTEL 环境变量,或者
  2. 在初始化 LangChain 组件之前设置一个全局追踪提供者,LangSmith 将检测并使用它,而不是创建自己的提供者。

配置备用的 OTLP 端点

要将追踪发送到不同的提供商,请使用您提供商的端点配置 OTLP 导出器:
import os

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# 为 LangChain 设置环境变量
os.environ["LANGSMITH_OTEL_ENABLED"] = "true"
os.environ["LANGSMITH_TRACING"] = "true"

# 为您的自定义端点配置 OTLP 导出器
provider = TracerProvider()
otlp_exporter = OTLPSpanExporter(
    # 更改为您提供商的端点
    endpoint="https://otel.your-provider.com/v1/traces",
    # 添加身份验证所需的任何头部
    headers={"api-key": "your-api-key"},
)
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# 创建并运行一个 LangChain 应用程序
prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
model = ChatOpenAI()
chain = prompt | model
result = chain.invoke({"topic": "programming"})
print(result.content)
混合追踪在版本 >= 0.4.1 中可用。要将追踪发送到您的 OTEL 端点,请设置:LANGSMITH_OTEL_ONLY="true" (建议使用 langsmith >= 0.4.25。)

支持的 OpenTelemetry 属性和事件映射

通过 OpenTelemetry 向 LangSmith 发送追踪时,以下属性会映射到 LangSmith 字段:

核心 LangSmith 属性

OpenTelemetry 属性LangSmith 字段说明
langsmith.trace.nameRun name覆盖运行项的跨度名称
langsmith.span.kindRun type取值:llm, chain, tool, retriever, embedding, prompt, parser
langsmith.trace.session_idSession ID关联追踪的会话标识符
langsmith.trace.session_nameSession name会话名称
langsmith.span.tagsTags附加到跨度的自定义标签(逗号分隔)
langsmith.metadata.{key}metadata.{key}带有 langsmith 前缀的自定义元数据

GenAI 标准属性

OpenTelemetry 属性LangSmith 字段说明
gen_ai.systemmetadata.ls_providerGenAI 系统(例如 “openai”, “anthropic”)
gen_ai.operation.nameRun type将 “chat”/“completion” 映射到 “llm”,“embedding” 映射到 “embedding”
gen_ai.promptinputs发送给模型的输入提示
gen_ai.completionoutputs模型生成的输出
gen_ai.prompt.{n}.roleinputs.messages[n].role第 n 条输入消息的角色
gen_ai.prompt.{n}.contentinputs.messages[n].content第 n 条输入消息的内容
gen_ai.prompt.{n}.message.roleinputs.messages[n].role角色的替代格式
gen_ai.prompt.{n}.message.contentinputs.messages[n].content内容的替代格式
gen_ai.completion.{n}.roleoutputs.messages[n].role第 n 条输出消息的角色
gen_ai.completion.{n}.contentoutputs.messages[n].content第 n 条输出消息的内容
gen_ai.completion.{n}.message.roleoutputs.messages[n].role角色的替代格式
gen_ai.completion.{n}.message.contentoutputs.messages[n].content内容的替代格式
gen_ai.input.messagesinputs.messages输入消息数组
gen_ai.output.messagesoutputs.messages输出消息数组
gen_ai.tool.nameinvocation_params.tool_name工具名称,同时将运行类型设置为 “tool”

GenAI 请求参数

OpenTelemetry 属性LangSmith 字段说明
gen_ai.request.modelinvocation_params.model请求使用的模型名称
gen_ai.response.modelinvocation_params.model响应中返回的模型名称
gen_ai.request.temperatureinvocation_params.temperature温度设置
gen_ai.request.top_pinvocation_params.top_pTop-p 采样设置
gen_ai.request.max_tokensinvocation_params.max_tokens最大令牌数设置
gen_ai.request.frequency_penaltyinvocation_params.frequency_penalty频率惩罚设置
gen_ai.request.presence_penaltyinvocation_params.presence_penalty存在惩罚设置
gen_ai.request.seedinvocation_params.seed用于生成的随机种子
gen_ai.request.stop_sequencesinvocation_params.stop停止生成的序列
gen_ai.request.top_kinvocation_params.top_kTop-k 采样参数
gen_ai.request.encoding_formatsinvocation_params.encoding_formats输出编码格式

GenAI 用量指标

OpenTelemetry 属性LangSmith 字段说明
gen_ai.usage.input_tokensusage_metadata.input_tokens使用的输入令牌数
gen_ai.usage.output_tokensusage_metadata.output_tokens使用的输出令牌数
gen_ai.usage.total_tokensusage_metadata.total_tokens使用的总令牌数
gen_ai.usage.prompt_tokensusage_metadata.input_tokens使用的输入令牌数(已弃用)
gen_ai.usage.completion_tokensusage_metadata.output_tokens使用的输出令牌数(已弃用)
gen_ai.usage.details.reasoning_tokensusage_metadata.reasoning_tokens使用的推理令牌数

TraceLoop 属性

OpenTelemetry 属性LangSmith 字段说明
traceloop.entity.inputinputs来自 TraceLoop 的完整输入值
traceloop.entity.outputoutputs来自 TraceLoop 的完整输出值
traceloop.entity.nameRun name来自 TraceLoop 的实体名称
traceloop.span.kindRun type映射到 LangSmith 运行类型
traceloop.llm.request.typeRun type”embedding” 映射到 “embedding”,其他映射到 “llm”
traceloop.association.properties.{key}metadata.{key}带有 traceloop 前缀的自定义元数据

OpenInference 属性

OpenTelemetry 属性LangSmith 字段说明
input.valueinputs完整输入值,可以是字符串或 JSON
output.valueoutputs完整输出值,可以是字符串或 JSON
openinference.span.kindRun type将各种类型映射到 LangSmith 运行类型
llm.systemmetadata.ls_providerLLM 系统提供商
llm.model_namemetadata.ls_model_name来自 OpenInference 的模型名称
tool.nameRun name当跨度类型为 “TOOL” 时的工具名称
metadatametadata.*要合并的 JSON 格式元数据字符串

LLM 属性

OpenTelemetry 属性LangSmith 字段说明
llm.input_messagesinputs.messages输入消息
llm.output_messagesoutputs.messages输出消息
llm.token_count.promptusage_metadata.input_tokens提示令牌数
llm.token_count.completionusage_metadata.output_tokens完成令牌数
llm.token_count.totalusage_metadata.total_tokens总令牌数
llm.usage.total_tokensusage_metadata.total_tokens总令牌数的替代表示
llm.invocation_parametersinvocation_params.*JSON 格式的调用参数字符串
llm.presence_penaltyinvocation_params.presence_penalty存在惩罚
llm.frequency_penaltyinvocation_params.frequency_penalty频率惩罚
llm.request.functionsinvocation_params.functions函数定义

提示模板属性

OpenTelemetry 属性LangSmith 字段说明
llm.prompt_template.variablesRun type将运行类型设置为 “prompt”,与 input.value 一起使用

检索器属性

OpenTelemetry 属性LangSmith 字段说明
retrieval.documents.{n}.document.contentoutputs.documents[n].page_content第 n 个检索到文档的内容
retrieval.documents.{n}.document.metadataoutputs.documents[n].metadata第 n 个检索到文档的元数据 (JSON)

工具属性

OpenTelemetry 属性LangSmith 字段说明
toolsinvocation_params.tools工具定义数组
tool_argumentsinvocation_params.tool_argumentsJSON 或键值对形式的工具参数

Logfire 属性

OpenTelemetry 属性LangSmith 字段说明
promptinputsLogfire 提示输入
all_messages_eventsoutputsLogfire 消息事件输出
eventsinputs/outputsLogfire 事件数组,分割输入/选择事件

OpenTelemetry 事件映射

事件名称LangSmith 字段说明
gen_ai.content.promptinputs从事件属性中提取提示内容
gen_ai.content.completionoutputs从事件属性中提取完成内容
gen_ai.system.messageinputs.messages[]对话中的系统消息
gen_ai.user.messageinputs.messages[]对话中的用户消息
gen_ai.assistant.messageoutputs.messages[]对话中的助手消息
gen_ai.tool.messageoutputs.messages[]工具响应消息
gen_ai.choiceoutputs带有结束原因的模型选择/响应
exceptionstatus, error将状态设置为 “error”,并提取异常消息/堆栈跟踪

事件属性提取

对于消息事件,会提取以下属性:
  • content → 消息内容
  • role → 消息角色
  • id → tool_call_id(对于工具消息)
  • gen_ai.event.content → 完整的消息 JSON
对于选择事件:
  • finish_reason → 选择结束原因
  • message.content → 选择消息内容
  • message.role → 选择消息角色
  • tool_calls.{n}.id → 工具调用 ID
  • tool_calls.{n}.function.name → 工具函数名称
  • tool_calls.{n}.function.arguments → 工具函数参数
  • tool_calls.{n}.type → 工具调用类型
对于异常事件:
  • exception.message → 错误消息
  • exception.stacktrace → 错误堆栈跟踪(附加到消息后)

实现示例

使用 LangSmith SDK 进行追踪

使用 LangSmith SDK 的 OpenTelemetry 辅助函数来配置导出。以下示例追踪了一个 Google ADK 代理
import asyncio
from langsmith.integrations.otel import configure
from google.adk import Runner
from google.adk.agents import LlmAgent
from google.adk.sessions import InMemorySessionService
from google.genai import types

# 配置 LangSmith OpenTelemetry 导出(无需 OTEL 环境变量或头部)
configure(project_name="adk-otel-demo")


async def main():
    agent = LlmAgent(
        name="travel_assistant",
        model="gemini-2.5-flash-lite",
        instruction="You are a helpful travel assistant.",
    )

    session_service = InMemorySessionService()
    runner = Runner(app_name="travel_app", agent=agent, session_service=session_service)

    user_id = "user_123"
    session_id = "session_abc"
    await session_service.create_session(app_name="travel_app", user_id=user_id, session_id=session_id)

    new_message = types.Content(parts=[types.Part(text="Hi! Recommend a weekend trip to Paris.")], role="user")

    for event in runner.run(user_id=user_id, session_id=session_id, new_message=new_message):
        print(event)


if __name__ == "__main__":
    asyncio.run(main())
您不需要设置 OTEL 环境变量或导出器。configure() 会自动为 LangSmith 配置它们;埋点工具(如 GoogleADKInstrumentor)会创建跨度。
这是 LangSmith 中生成的追踪的示例

向追踪添加附件

LangSmith 支持向追踪附加文件。这在构建具有多模态输入或输出的代理时非常有用。使用 OpenTelemetry 进行追踪时也支持附件。 下面的示例追踪了一个 Google ADK 代理并向追踪添加了一个附件。它结合使用了 LangSmith 的 OtelSpanProcessor 和一个自定义的 AttachmentSpanProcessor,后者使用 on_end() 向父跨度添加一个图像附件。
import asyncio
import base64
import json
from pathlib import Path
from dotenv import load_dotenv
from google.adk import Runner
from google.adk.agents import LlmAgent
from google.adk.sessions import InMemorySessionService
from google.genai import types
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider, SpanProcessor
from langsmith.integrations.otel import OtelSpanProcessor


class AttachmentSpanProcessor(SpanProcessor):
    """自定义 SpanProcessor,用于向调用跨度添加附件。"""

    def __init__(self):
        self.attachment_data = None

    def set_attachment(self, attachment_data):
        self.attachment_data = attachment_data

    def on_end(self, span):
        if span.name == "invocation" and self.attachment_data:
            attachments_json = json.dumps([self.attachment_data])
            span._attributes["langsmith.attachments"] = attachments_json

load_dotenv()

# 手动设置 TracerProvider
provider = TracerProvider()
trace.set_tracer_provider(provider)

# 首先添加附件处理器(在 LangSmith 处理器之前运行)
attachment_processor = AttachmentSpanProcessor()
provider.add_span_processor(attachment_processor)

# 其次添加 LangSmith 处理器(接收已修改的跨度)
langsmith_processor = OtelSpanProcessor(project="travel-assistant")
provider.add_span_processor(langsmith_processor)

def get_flight_info(destination: str, departure_date: str) -> dict:
    """获取目的地的航班信息。"""
    return {
        "destination": destination,
        "departure_date": departure_date,
        "price": "$450",
        "duration": "5h 30m",
        "airline": "Example Airways"
    }

def get_hotel_recommendations(city: str, check_in: str) -> dict:
    """获取城市的酒店推荐。"""
    return {
        "city": city,
        "check_in": check_in,
        "hotels": [
            {"name": "Grand Plaza Hotel", "rating": 4.5, "price": "$120/night"},
            {"name": "City Center Inn", "rating": 4.2, "price": "$95/night"}
        ]
    }

async def main():
    # 准备附件
    receipt_path = Path("receipt-template-example.png")
    with open(receipt_path, "rb") as img_file:
        image_bytes = img_file.read()
        image_base64 = base64.b64encode(image_bytes).decode("ascii")

    attachment_data = {
        "name": "receipt-template-example",
        "content": image_base64,
        "mime_type": "image/jpeg",
    }

    attachment_processor.set_attachment(attachment_data)

    # 创建 ADK 代理
    agent = LlmAgent(
        name="travel_assistant",
        tools=[get_flight_info, get_hotel_recommendations],
        model="gemini-2.0-flash-exp",
        instruction="You are a helpful travel assistant that can help with flights and hotels.",
    )

    # 设置会话和运行器
    session_service = InMemorySessionService()
    runner = Runner(
        app_name="travel_app",
        agent=agent,
        session_service=session_service
    )

    await session_service.create_session(
        app_name="travel_app",
        user_id="traveler_456",
        session_id="session_789"
    )

    # 向代理发送消息
    new_message = types.Content(
        parts=[types.Part(text="I need to book a flight to Paris for March 15th and find a good hotel.")],
        role="user",
    )

    # 运行代理并处理事件
    events = runner.run(
        user_id="traveler_456",
        session_id="session_789",
        new_message=new_message,
    )

    for event in events:
        print(event)

if __name__ == "__main__":
    asyncio.run(main())
这是 LangSmith 中生成的追踪的示例

高级配置

使用 OpenTelemetry Collector 进行扇出

当您需要 OTEL 扇出时,使用 LANGSMITH_OTEL_ENABLED=true。配置您的应用程序仅发送一次 OTEL 跨度,然后使用 OpenTelemetry Collector 将它们路由到 LangSmith 和任何其他可观测性后端。 当您正在追踪应用程序并希望进行多目标路由时,请使用此方法。如果您正在操作 LangSmith 平台基础设施遥测(来自 Kubernetes 上自托管 LangSmith 服务的日志、指标、追踪),请改用为 LangSmith 遥测配置您的收集器指南。 对于更高级的场景,您可以使用 OpenTelemetry Collector 将您的遥测数据扇出到多个目标。这比在应用程序代码中配置多个导出器更具可扩展性。
  1. 为您的环境安装 OpenTelemetry Collector
  2. 创建一个配置文件(例如 otel-collector-config.yaml),导出到多个目标:
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
          http:
            endpoint: 0.0.0.0:4318
    
    processors:
      batch:
    
    exporters:
      otlphttp/langsmith:
        endpoint: https://api.smith.langchain.com/otel/v1/traces
        headers:
          x-api-key: ${env:LANGSMITH_API_KEY}
          Langsmith-Project: my_project
      otlphttp/other_provider:
        endpoint: https://otel.your-provider.com/v1/traces
        headers:
          api-key: ${env:OTHER_PROVIDER_API_KEY}
    
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch]
          exporters: [otlphttp/langsmith, otlphttp/other_provider]
    
  3. 配置您的应用程序以将数据发送到收集器:
    import os
    from opentelemetry import trace
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
    from langchain_openai import ChatOpenAI
    from langchain_core.prompts import ChatPromptTemplate
    
    # 指向您的本地 OpenTelemetry Collector
    otlp_exporter = OTLPSpanExporter(
        endpoint="http://localhost:4318/v1/traces"
    )
    provider = TracerProvider()
    processor = BatchSpanProcessor(otlp_exporter)
    provider.add_span_processor(processor)
    trace.set_tracer_provider(provider)
    
    # 为 LangChain 设置环境变量
    os.environ["LANGSMITH_OTEL_ENABLED"] = "true"
    os.environ["LANGSMITH_TRACING"] = "true"
    
    # 创建并运行一个 LangChain 应用程序
    prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
    model = ChatOpenAI()
    chain = prompt | model
    result = chain.invoke({"topic": "programming"})
    print(result.content)
    
这种方法有几个优点:
  • 所有遥测目标的集中配置
  • 减少应用程序代码的开销
  • 更好的可扩展性和弹性
  • 无需更改应用程序代码即可添加或移除目标

使用 LangChain 和 OpenTelemetry 进行分布式追踪

当您的 LLM 应用程序跨越多个服务或进程时,分布式追踪至关重要。OpenTelemetry 的上下文传播功能确保追踪在服务边界之间保持连接。

分布式追踪中的上下文传播

在分布式系统中,上下文传播在服务之间传递追踪元数据,以便相关的跨度链接到同一个追踪:
  • 追踪 ID:整个追踪的唯一标识符
  • 跨度 ID:当前跨度的唯一标识符
  • 采样决策:指示是否应对此追踪进行采样

使用 LangChain 设置分布式追踪

要跨多个服务启用分布式追踪:
import os
from opentelemetry import trace
from opentelemetry.propagate import inject, extract
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
import requests
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 设置 OpenTelemetry 追踪提供者
provider = TracerProvider()
otlp_exporter = OTLPSpanExporter(
    endpoint="https://api.smith.langchain.com/otel/v1/traces",
    headers={"x-api-key": os.getenv("LANGSMITH_API_KEY"), "Langsmith-Project": "my_project"}
)
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

# 服务 A:创建一个跨度并将上下文传播到服务 B
def service_a():
    with tracer.start_as_current_span("service_a_operation") as span:
        # 创建一个链
        prompt = ChatPromptTemplate.from_template("Summarize: {text}")
        model = ChatOpenAI()
        chain = prompt | model

        # 运行链
        result = chain.invoke({"text": "OpenTelemetry is an observability framework"})

        # 将上下文传播到服务 B
        headers = {}
        inject(headers)  # 将追踪上下文注入头部

        # 使用追踪上下文调用服务 B
        response = requests.post(
            "http://service-b.example.com/process",
            headers=headers,
            json={"summary": result.content}
        )
        return response.json()

# 服务 B:提取上下文并继续追踪
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/process", methods=["POST"])
def service_b_endpoint():
    # 从请求头中提取追踪上下文
    context = extract(request.headers)
    with tracer.start_as_current_span("service_b_operation", context=context) as span:
        data = request.json
        summary = data.get("summary", "")

        # 使用另一个 LLM 链处理摘要
        prompt = ChatPromptTemplate.from_template("Analyze the sentiment of: {text}")
        model = ChatOpenAI()
        chain = prompt | model
        result = chain.invoke({"text": summary})

        return jsonify({"analysis": result.content})

if __name__ == "__main__":
    app.run(port=5000)