跳到主要内容
LangSmith 支持基于 OpenTelemetry 的追踪,允许您从任何兼容 OpenTelemetry 的应用程序发送追踪。本指南涵盖 LangChain 应用程序的自动仪表以及其他框架的手动仪表。 了解如何使用 LangSmith 和 OpenTelemetry 追踪您的 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>
    # For LangSmith API keys linked to multiple workspaces, set the LANGSMITH_WORKSPACE_ID environment variable to specify which workspace to use.
    
  3. 创建一个带有追踪功能的 LangChain 应用程序。例如
    import os
    from langchain_openai import ChatOpenAI
    from langchain_core.prompts import ChatPromptTemplate
    
    # Create a chain
    prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
    model = ChatOpenAI()
    chain = prompt | model
    
    # Run the chain
    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-4o-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: Override the endpoint URL
OTEL_EXPORTER_OTLP_HEADERS: Add custom headers (LangSmith API keys and Project are added automatically)
OTEL_SERVICE_NAME: Set a custom service name (defaults to "langsmith")
LangSmith 默认使用 HTTP 追踪导出器。如果您想使用自己的追踪提供商,您可以
  1. 如上所示设置 OTEL 环境变量,或
  2. 在初始化 LangChain 组件之前设置一个全局追踪提供商,LangSmith 将检测并使用它而不是创建自己的。

配置备用 OTLP 端点

要将追踪发送到不同的提供商,请使用您的提供商的端点配置 OTLP 导出器
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

# Set environment variables for LangChain
os.environ["LANGSMITH_OTEL_ENABLED"] = "true"
os.environ["LANGSMITH_TRACING"] = "true"

# Configure the OTLP exporter for your custom endpoint
provider = TracerProvider()
otlp_exporter = OTLPSpanExporter(
    # Change to your provider's endpoint
    endpoint="https://otel.your-provider.com/v1/traces",
    # Add any required headers for authentication
    headers={"api-key": "your-api-key"}
)
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# Create and run a LangChain application
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.name运行名称覆盖运行的 span 名称
langsmith.span.kind运行类型值:llmchaintoolretrieverembeddingpromptparser
langsmith.trace.session_id会话 ID相关追踪的会话标识符
langsmith.trace.session_name会话名称会话的名称
langsmith.span.tags标签附加到 span 的自定义标签(逗号分隔)
langsmith.metadata.{key}metadata.{key}带有 langsmith 前缀的自定义元数据

GenAI 标准属性

OpenTelemetry 属性LangSmith 字段备注
gen_ai.systemmetadata.ls_providerGenAI 系统(例如,“openai”,“anthropic”)
gen_ai.operation.name运行类型将“chat”/“completion”映射到“llm”,将“embedding”映射到“embedding”
gen_ai.prompt输入发送到模型的输入提示
gen_ai.completion输出模型生成的输出
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最大 token 设置
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使用的输入 token 数量
gen_ai.usage.output_tokensusage_metadata.output_tokens使用的输出 token 数量
gen_ai.usage.total_tokensusage_metadata.total_tokens使用的总 token 数量
gen_ai.usage.prompt_tokensusage_metadata.input_tokens使用的输入 token 数量(已弃用)
gen_ai.usage.completion_tokensusage_metadata.output_tokens使用的输出 token 数量(已弃用)
gen_ai.usage.details.reasoning_tokensusage_metadata.reasoning_tokens使用的推理 token 数量

TraceLoop 属性

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

OpenInference 属性

OpenTelemetry 属性LangSmith 字段备注
input.value输入完整的输入值,可以是字符串或 JSON
output.value输出完整的输出值,可以是字符串或 JSON
openinference.span.kind运行类型将各种类型映射到 LangSmith 运行类型
llm.systemmetadata.ls_providerLLM 系统提供商
llm.model_namemetadata.ls_model_nameOpenInference 的模型名称
tool.name运行名称当 span 种类为“TOOL”时,表示工具名称
metadatametadata.*要合并的元数据的 JSON 字符串

LLM 属性

OpenTelemetry 属性LangSmith 字段备注
llm.input_messagesinputs.messages输入消息
llm.output_messagesoutputs.messages输出消息
llm.token_count.promptusage_metadata.input_tokens提示 token 计数
llm.token_count.completionusage_metadata.output_tokens完成 token 计数
llm.token_count.totalusage_metadata.total_tokens总 token 计数
llm.usage.total_tokensusage_metadata.total_tokens替代的总 token 计数
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.variables运行类型将运行类型设置为“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_arguments作为 JSON 或键值对的工具参数

Logfire 属性

OpenTelemetry 属性LangSmith 字段备注
prompt输入Logfire 提示输入
all_messages_events输出Logfire 消息事件输出
eventsinputs/outputsLogfire 事件数组,拆分输入/选择事件

OpenTelemetry 事件映射

事件名称LangSmith 字段备注
gen_ai.content.prompt输入从事件属性中提取提示内容
gen_ai.content.completion输出从事件属性中提取完成内容
gen_ai.system.messageinputs.messages[]对话中的系统消息
gen_ai.user.messageinputs.messages[]对话中的用户消息
gen_ai.assistant.messageoutputs.messages[]对话中的助手消息
gen_ai.tool.messageoutputs.messages[]工具响应消息
gen_ai.choice输出模型选择/响应,带结束原因
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 帮助器配置导出
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

# Configure LangSmith OpenTelemetry export (no OTEL env vars or headers needed)
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)会创建 span。
  1. 在您的 LangSmith 仪表板中查看追踪(示例)。

高级配置

使用 OpenTelemetry Collector 进行扇出

对于更高级的场景,您可以使用 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. 配置您的应用程序以发送到 Collector
    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
    
    # Point to your local OpenTelemetry Collector
    otlp_exporter = OTLPSpanExporter(
        endpoint="https://:4318/v1/traces"
    )
    provider = TracerProvider()
    processor = BatchSpanProcessor(otlp_exporter)
    provider.add_span_processor(processor)
    trace.set_tracer_provider(provider)
    
    # Set environment variables for LangChain
    os.environ["LANGSMITH_OTEL_ENABLED"] = "true"
    os.environ["LANGSMITH_TRACING"] = "true"
    
    # Create and run a LangChain application
    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 的上下文传播功能确保追踪在服务边界之间保持连接。

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

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

使用 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

# Set up OpenTelemetry trace provider
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__)

# Service A: Create a span and propagate context to Service B
def service_a():
    with tracer.start_as_current_span("service_a_operation") as span:
        # Create a chain
        prompt = ChatPromptTemplate.from_template("Summarize: {text}")
        model = ChatOpenAI()
        chain = prompt | model

        # Run the chain
        result = chain.invoke({"text": "OpenTelemetry is an observability framework"})

        # Propagate context to Service B
        headers = {}
        inject(headers)  # Inject trace context into headers

        # Call Service B with the trace context
        response = requests.post(
            "http://service-b.example.com/process",
            headers=headers,
            json={"summary": result.content}
        )
        return response.json()

# Service B: Extract the context and continue the trace
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/process", methods=["POST"])
def service_b_endpoint():
    # Extract the trace context from the request headers
    context = extract(request.headers)
    with tracer.start_as_current_span("service_b_operation", context=context) as span:
        data = request.json
        summary = data.get("summary", "")

        # Process the summary with another LLM chain
        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)

以编程方式连接这些文档到 Claude、VSCode 等,通过 MCP 获取实时答案。
© . This site is unofficial and not affiliated with LangChain, Inc.