使用 OpenTelemetry 追踪
LangSmith 可以接受来自基于 OpenTelemetry 的客户端的追踪。本指南将通过示例介绍如何实现这一点。
对于自托管安装或欧盟区域的组织,请在以下请求中相应更新 LangSmith URL。对于欧盟区域,请使用 eu.api.smith.langchain.com
。
使用基本的 OpenTelemetry 客户端记录追踪
本节首先介绍如何使用标准 OpenTelemetry 客户端将追踪记录到 LangSmith。
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>"
可选:指定一个非“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()
您应该在 LangSmith 仪表盘中看到一个追踪,就像这个一样。
支持的 OpenTelemetry 属性和事件映射
通过 OpenTelemetry 将追踪发送到 LangSmith 时,以下属性会映射到 LangSmith 字段。
核心 LangSmith 属性
确定运行层级的以下属性(langsmith.span.id
、langsmith.trace.id
、langsmith.span.dotted_order
、langsmith.span.parent_id
)在使用 OpenTelemetry 时通常不应手动设置。这些属性主要由 LangSmith SDK 在使用 OpenTelemetry 进行追踪时内部使用。虽然设置这些属性可以提高性能,但对于大多数用例不建议这样做,因为它们可能会干扰正确的运行树构建。有关这些属性如何工作的更多详细信息,请参阅运行数据格式文档。
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
langsmith.trace.name | 运行名称 | 覆盖运行的 span 名称 |
langsmith.span.kind | 运行类型 | 值:llm , chain , tool , retriever , embedding , prompt , parser |
langsmith.span.id | 运行 ID | span 的唯一标识符 |
langsmith.trace.id | 追踪 ID | 追踪的唯一标识符 |
langsmith.span.dotted_order | 点序 | 在执行树中的位置 |
langsmith.span.parent_id | 父运行 ID | 父 span 的 ID |
langsmith.trace.session_id | 会话 ID | 相关追踪的会话标识符 |
langsmith.trace.session_name | 会话名称 | 会话名称 |
langsmith.span.tags | 标签 | 附加到 span 的自定义标签(逗号分隔) |
langsmith.metadata.{key} | metadata.{key} | 带有 langsmith 前缀的自定义元数据 |
GenAI 标准属性
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
gen_ai.system | metadata.ls_provider | GenAI 系统(例如,“openai”、“anthropic”) |
gen_ai.operation.name | 运行类型 | 将“chat”/“completion”映射到“llm”,“embedding”映射到“embedding” |
gen_ai.prompt | 输入 | 发送到模型的输入提示 |
gen_ai.completion | 输出 | 模型生成的输出 |
gen_ai.prompt.{n}.role | inputs.messages[n].role | 第 n 条输入消息的角色 |
gen_ai.prompt.{n}.content | inputs.messages[n].content | 第 n 条输入消息的内容 |
gen_ai.prompt.{n}.message.role | inputs.messages[n].role | 角色的备用格式 |
gen_ai.prompt.{n}.message.content | inputs.messages[n].content | 内容的备用格式 |
gen_ai.completion.{n}.role | outputs.messages[n].role | 第 n 条输出消息的角色 |
gen_ai.completion.{n}.content | outputs.messages[n].content | 第 n 条输出消息的内容 |
gen_ai.completion.{n}.message.role | outputs.messages[n].role | 角色的备用格式 |
gen_ai.completion.{n}.message.content | outputs.messages[n].content | 内容的备用格式 |
gen_ai.tool.name | invocation_params.tool_name | 工具名称,同时将运行类型设置为“tool” |
GenAI 请求参数
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
gen_ai.request.model | invocation_params.model | 请求使用的模型名称 |
gen_ai.response.model | invocation_params.model | 响应中返回的模型名称 |
gen_ai.request.temperature | invocation_params.temperature | 温度设置 |
gen_ai.request.top_p | invocation_params.top_p | Top-p 采样设置 |
gen_ai.request.max_tokens | invocation_params.max_tokens | 最大令牌设置 |
gen_ai.request.frequency_penalty | invocation_params.frequency_penalty | 频率惩罚设置 |
gen_ai.request.presence_penalty | invocation_params.presence_penalty | 存在惩罚设置 |
gen_ai.request.seed | invocation_params.seed | 用于生成的随机种子 |
gen_ai.request.stop_sequences | invocation_params.stop | 停止生成的序列 |
gen_ai.request.top_k | invocation_params.top_k | Top-k 采样参数 |
gen_ai.request.encoding_formats | invocation_params.encoding_formats | 输出编码格式 |
GenAI 使用指标
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
gen_ai.usage.input_tokens | usage_metadata.input_tokens | 使用的输入令牌数量 |
gen_ai.usage.output_tokens | usage_metadata.output_tokens | 使用的输出令牌数量 |
gen_ai.usage.total_tokens | usage_metadata.total_tokens | 使用的总令牌数量 |
gen_ai.usage.prompt_tokens | usage_metadata.input_tokens | 使用的输入令牌数量(已弃用) |
gen_ai.usage.completion_tokens | usage_metadata.output_tokens | 使用的输出令牌数量(已弃用) |
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.system | metadata.ls_provider | LLM 系统提供商 |
llm.model_name | metadata.ls_model_name | 来自 OpenInference 的模型名称 |
tool.name | 运行名称 | 当 span 类型为“TOOL”时的工具名称 |
metadata | metadata.* | 要合并的元数据的 JSON 字符串 |
LLM 属性
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
llm.input_messages | inputs.messages | 输入消息 |
llm.output_messages | outputs.messages | 输出消息 |
llm.token_count.prompt | usage_metadata.input_tokens | 提示令牌计数 |
llm.token_count.completion | usage_metadata.output_tokens | 完成令牌计数 |
llm.token_count.total | usage_metadata.total_tokens | 总令牌计数 |
llm.usage.total_tokens | usage_metadata.total_tokens | 备用总令牌计数 |
llm.invocation_parameters | invocation_params.* | 调用参数的 JSON 字符串 |
llm.presence_penalty | invocation_params.presence_penalty | 存在惩罚 |
llm.frequency_penalty | invocation_params.frequency_penalty | 频率惩罚 |
llm.request.functions | invocation_params.functions | 函数定义 |
提示模板属性
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
llm.prompt_template.variables | 运行类型 | 将运行类型设置为“prompt”,与 input.value 一起使用 |
检索器属性
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
retrieval.documents.{n}.document.content | outputs.documents[n].page_content | 第 n 个检索文档的内容 |
retrieval.documents.{n}.document.metadata | outputs.documents[n].metadata | 第 n 个检索文档的元数据 (JSON) |
工具属性
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
tools | invocation_params.tools | 工具定义数组 |
tool_arguments | invocation_params.tool_arguments | 工具参数,以 JSON 或键值对形式 |
Logfire 属性
OpenTelemetry 属性 | LangSmith 字段 | 备注 |
---|---|---|
prompt | 输入 | Logfire 提示输入 |
all_messages_events | 输出 | Logfire 消息事件输出 |
events | inputs /outputs | Logfire 事件数组,拆分输入/选择事件 |
OpenTelemetry 事件映射
事件名称 | LangSmith 字段 | 备注 |
---|---|---|
gen_ai.content.prompt | 输入 | 从事件属性中提取提示内容 |
gen_ai.content.completion | 输出 | 从事件属性中提取完成内容 |
gen_ai.system.message | inputs.messages[] | 对话中的系统消息 |
gen_ai.user.message | inputs.messages[] | 对话中的用户消息 |
gen_ai.assistant.message | outputs.messages[] | 对话中的助手消息 |
gen_ai.tool.message | outputs.messages[] | 工具响应消息 |
gen_ai.choice | 输出 | 带有结束原因的模型选择/响应 |
exception | status , error | 将状态设置为“error”并提取异常消息/堆栈追踪 |
事件属性提取
对于消息事件,提取以下属性
content
→ 消息内容role
→ 消息角色id
→ tool_call_id(用于工具消息)gen_ai.event.content
→ 完整消息 JSON
对于选择事件
finish_reason
→ 选择结束原因message.content
→ 选择消息内容message.role
→ 选择消息角色tool_calls.{n}.id
→ 工具调用 IDtool_calls.{n}.function.name
→ 工具函数名称tool_calls.{n}.function.arguments
→ 工具函数参数tool_calls.{n}.type
→ 工具调用类型
对于异常事件
exception.message
→ 错误消息exception.stacktrace
→ 错误堆栈追踪(附加到消息)
使用 Traceloop SDK 记录追踪
Traceloop SDK 是一个兼容 OpenTelemetry 的 SDK,涵盖了一系列模型、向量数据库和框架。如果您有兴趣集成此 SDK 支持的工具,可以使用此 SDK 与 OpenTelemetry 一起将追踪记录到 LangSmith。
要查看 Traceloop SDK 支持的集成,请参阅Traceloop SDK 文档。
要开始使用,请按照以下步骤操作
1. 安装
pip install traceloop-sdk
pip install openai
2. 配置您的环境
设置环境变量
TRACELOOP_BASE_URL=https://api.smith.langchain.com/otel
TRACELOOP_HEADERS=x-api-key=<your_langsmith_api_key>
可选:指定一个非“default”的自定义项目名称
TRACELOOP_HEADERS=x-api-key=<your_langsmith_api_key>,Langsmith-Project=<langsmith_project_name>
3. 初始化 SDK
要使用 SDK,您需要在记录追踪之前对其进行初始化
from traceloop.sdk import Traceloop
Traceloop.init()
4. 记录追踪
这是一个使用 OpenAI 聊天完成的完整示例
import os
from openai import OpenAI
from traceloop.sdk import Traceloop
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
Traceloop.init()
completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{
"role": "user",
"content": "Write a haiku about recursion in programming."
}
]
)
print(completion.choices[0].message)
您应该在 LangSmith 仪表盘中看到一个追踪,就像这个一样。
使用 Arize SDK 进行追踪
通过 Arize SDK 和 OpenTelemetry,您可以将来自其他多个框架的追踪记录到 LangSmith。下面是追踪 CrewAI 到 LangSmith 的示例,您可以在此处找到支持的框架的完整列表。要使此示例适用于其他框架,您只需更改 instrumentor 以匹配该框架。
1. 安装
首先,安装所需的包
pip install -qU arize-phoenix-otel openinference-instrumentation-crewai crewai crewai-tools
2. 配置您的环境
接下来,设置以下环境变量
OPENAI_API_KEY=<your_openai_api_key>
SERPER_API_KEY=<your_serper_api_key>
3. 设置 instrumentor
在运行任何应用程序代码之前,让我们设置 instrumentor(您可以将其替换为此处支持的任何框架)
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
# Add LangSmith API Key for tracing
LANGSMITH_API_KEY = "YOUR_API_KEY"
# Set the endpoint for OTEL collection
ENDPOINT = "https://api.smith.langchain.com/otel/v1/traces"
# Select the project to trace to
LANGSMITH_PROJECT = "YOUR_PROJECT_NAME"
# Create the OTLP exporter
otlp_exporter = OTLPSpanExporter(
endpoint=ENDPOINT,
headers={"x-api-key": LANGSMITH_API_KEY, "Langsmith-Project": LANGSMITH_PROJECT}
)
# Set up the trace provider
provider = TracerProvider()
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)
# Now instrument CrewAI
from openinference.instrumentation.crewai import CrewAIInstrumentor
CrewAIInstrumentor().instrument(tracer_provider=provider)
4. 记录追踪
现在,您可以运行 CrewAI 工作流,追踪将自动记录到 LangSmith
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool
search_tool = SerperDevTool()
# Define your agents with roles and goals
researcher = Agent(
role='Senior Research Analyst',
goal='Uncover cutting-edge developments in AI and data science',
backstory="""You work at a leading tech think tank.
Your expertise lies in identifying emerging trends.
You have a knack for dissecting complex data and presenting actionable insights.""",
verbose=True,
allow_delegation=False,
# You can pass an optional llm attribute specifying what model you wanna use.
# llm=ChatOpenAI(model_name="gpt-3.5", temperature=0.7),
tools=[search_tool]
)
writer = Agent(
role='Tech Content Strategist',
goal='Craft compelling content on tech advancements',
backstory="""You are a renowned Content Strategist, known for your insightful and engaging articles.
You transform complex concepts into compelling narratives.""",
verbose=True,
allow_delegation=True
)
# Create tasks for your agents
task1 = Task(
description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
Identify key trends, breakthrough technologies, and potential industry impacts.""",
expected_output="Full analysis report in bullet points",
agent=researcher
)
task2 = Task(
description="""Using the insights provided, develop an engaging blog
post that highlights the most significant AI advancements.
Your post should be informative yet accessible, catering to a tech-savvy audience.
Make it sound cool, avoid complex words so it doesn't sound like AI.""",
expected_output="Full blog post of at least 4 paragraphs",
agent=writer
)
# Instantiate your crew with a sequential process
crew = Crew(
agents=[researcher, writer],
tasks=[task1, task2],
verbose= False,
process = Process.sequential
)
# Get your crew to work!
result = crew.kickoff()
print("######################")
print(result)
您应该在您的 LangSmith 项目中看到一个像这样的追踪