主题
Trajectory 视图集成
在 LangSmith Trajectory 视图中呈现的框架和 SDK,以及每个框架设置的元数据。
Trajectory 视图将追踪(即线程的追踪)呈现为轨迹:用户提示、模型响应、工具调用和工具结果,按顺序排列。Trajectory 视图需要两条运行元数据来呈现轨迹:
- 线程分组:每个运行上的
thread_id告诉 LangSmith 一组运行属于同一对话。 - 运行分类:轮次顶层运行上的
ls_agent_type: "root"将该运行标记为主对话的一部分。标记为 subagent 的运行在线程中显示为子 agent 操作,而标记为 middleware 或 compaction 的运行目前会被过滤掉。
对于大多数 LangSmith 集成,这两者都会为你设置。当你需要手动设置元数据时,以下示例涵盖链式模式下的 OpenAI Responses API以及标记自定义中间件或护栏。
支持的集成
以下集成会自动设置 thread_id 和 ls_agent_type:
- Claude Code
- Claude Agent SDK
- OpenAI Codex
- Cursor
- Pi
- OpenCode
- GitHub Copilot
- Deep Agents
- LangChain
- LangGraph
- OpenAI Chat Completions(
wrap_openai) - OpenAI Responses API,单次调用(
wrap_openai)
链式模式下的 OpenAI Responses API(previous_response_id)会自动设置 ls_agent_type,但 thread_id 需要你自己设置。有关更多详细信息,请参阅带链式的 OpenAI Responses API示例。
有关完整的 ls_agent_type schema 以及官方集成在非根运行上设置的其他值(subagent、middleware、compaction),请参阅编码 agent 元数据契约。有关底层线程分组机制,请参阅配置线程。
带链式的 OpenAI Responses API
当你通过传递 previous_response_id 链式调用 OpenAI Responses API 时,OpenAI 会在服务器端存储对话状态,LangSmith 包装器没有用于将调用分组到线程的自然键。你需要自行设置 thread_id,可以按调用设置,也可以在包装器初始化时设置。
NOTE
为 thread_id 使用 UUID v7。LangSmith 的 SDK 导出了 uuid7 辅助函数,UUID v7 按创建时间排序,因此线程在列表视图中保持有序。
按调用设置元数据
在每次调用时设置 thread_id。当同一个被包装的客户端服务多个线程时(例如,每个进程一个客户端、多个并发对话)使用此方式。
python
import openai
from langsmith import uuid7
from langsmith.wrappers import wrap_openai
client = wrap_openai(openai.Client())
thread_id = str(uuid7())
res1 = client.responses.create(
model="gpt-5.6",
input="What is the capital of France?",
store=True,
langsmith_extra={"metadata": {"thread_id": thread_id}},
)
res2 = client.responses.create(
model="gpt-5.6",
input="And its population?",
previous_response_id=resp1.id,
store=True,
langsmith_extra={"metadata": {"thread_id": thread_id}},
)typescript
import OpenAI from "openai";
import { uuid7 } from "langsmith";
import { wrapOpenAI } from "langsmith/wrappers";
const client = wrapOpenAI(new OpenAI());
const threadId = uuid7();
const res1 = await client.responses.create({
model: "gpt-5.6",
input: "What is the capital of France?",
metadata: { thread_id: threadId },
store: true,
});
const res2 = await client.responses.create({
model: "gpt-5.6",
input: "And its population?",
previous_response_id: res1.id,
metadata: { thread_id: threadId },
store: true,
});初始化时设置元数据
在包装客户端时设置一次 thread_id。通过此包装器进行的每次调用都会标记为同一线程。当被包装的客户端在其生命周期内仅服务一个线程时(例如,每个对话一个 worker)使用此方式。
python
import openai
from langsmith import uuid7
from langsmith.wrappers import wrap_openai
thread_id = str(uuid7())
client = wrap_openai(
openai.Client(),
tracing_extra={"metadata": {"thread_id": thread_id}},
)
res1 = client.responses.create(
model="gpt-5.6",
input="What is the capital of France?",
store=True,
)
res2 = client.responses.create(
model="gpt-5.6",
input="And its population?",
previous_response_id=resp1.id,
store=True,
)typescript
import OpenAI from "openai";
import { uuid7 } from "langsmith";
import { wrapOpenAI } from "langsmith/wrappers";
const threadId = uuid7();
const client = wrapOpenAI(new OpenAI(), { metadata: { thread_id: threadId } });
const res1 = await client.responses.create({
model: "gpt-5.6",
input: "What is the capital of France?",
store: true,
});
const res2 = await client.responses.create({
model: "gpt-5.6",
input: "And its population?",
previous_response_id: res1.id,
store: true,
});隐藏自定义中间件或护栏
当你围绕 LLM 或工具调用编写自己的护栏、策略检查或中间件函数时,请用 @traceable 包装它,并在元数据上设置 ls_agent_type: "middleware"。Trajectory 视图会将这些运行从主对话中过滤掉。
python
from langsmith import traceable
@traceable(
run_type="llm",
metadata={"ls_agent_type": "middleware"},
)
def entry_guardrail(prompt: str) -> dict:
# Your guardrail logic
return {"decision": "allow"}typescript
import { traceable } from "langsmith/traceable";
const entryGuardrail = traceable(
async (prompt: string) => {
// Your guardrail logic
return { decision: "allow" };
},
{ run_type: "llm", metadata: { ls_agent_type: "middleware" } },
);从 Trajectory 视图中排除运行
在运行的元数据上设置 LS_MESSAGE_VIEW_EXCLUDE 会告诉 Trajectory 视图跳过该运行。重要的是键的存在,True 是常规值。该过滤器会在任何提取策略看到追踪之前运行,因此被排除的 LLM 或工具运行永远不会影响检测、消息提取或工具调用配对。
LS_MESSAGE_VIEW_EXCLUDE 是从 langsmith(Python 和 JS)导出的顶级常量,其值为字符串 "ls_message_view_exclude"。优先使用该常量以避免拼写错误;字面字符串仍然有效。
将其用于非对话轮次的 LLM 子 span,例如分类调用、嵌入查找、安全过滤器或路由/护栏决策,你仍然希望在 LangSmith 的其他位置看到它们,但不希望它们弄乱对话记录。
1. 在 @traceable 装饰器上:排除整个函数的运行。
python
from langsmith import LS_MESSAGE_VIEW_EXCLUDE, traceable
@traceable(run_type="llm", metadata={LS_MESSAGE_VIEW_EXCLUDE: True})
def classify_intent(query: str) -> str:
# This LLM call is internal routing, not part of the chat
return llm.predict(f"Classify the intent of: {query}")2. 通过 trace 上下文管理器:排除临时 span。
python
from langsmith import LS_MESSAGE_VIEW_EXCLUDE, trace
with trace(
"safety_check",
run_type="llm",
metadata={LS_MESSAGE_VIEW_EXCLUDE: True},
) as run:
result = safety_model.score(text)
run.end(outputs={"score": result})3. 在运行中的函数内部:在运行被打补丁之前的任意时刻,在当前运行树上设置该键。
python
from langsmith import LS_MESSAGE_VIEW_EXCLUDE, get_current_run_tree, traceable
@traceable(run_type="llm")
def maybe_internal(query: str) -> str:
result = llm.predict(query)
if _looks_like_routing(query):
rt = get_current_run_tree()
if rt is not None:
rt.add_metadata({LS_MESSAGE_VIEW_EXCLUDE: True})
return result4. 使用 wrap_openai / wrap_anthropic 时按调用设置:将 langsmith_extra 传递给被包装的客户端调用。
python
import openai
from langsmith import LS_MESSAGE_VIEW_EXCLUDE
from langsmith.wrappers import wrap_openai
client = wrap_openai(openai.Client())
resp = client.chat.completions.create(
model="gpt-5.6",
messages=[{"role": "user", "content": "Classify: ..."}],
langsmith_extra={"metadata": {LS_MESSAGE_VIEW_EXCLUDE: True}},
)5. LangChain RunnableConfig:排除链或聊天模型的单次调用。
python
from langchain_openai import ChatOpenAI
from langsmith import LS_MESSAGE_VIEW_EXCLUDE
llm = ChatOpenAI(model="gpt-5.6")
result = llm.invoke(
"Classify this query",
config={"metadata": {LS_MESSAGE_VIEW_EXCLUDE: True}},
)注
- 过滤器检查的是键是否存在,而不是真值。
{LS_MESSAGE_VIEW_EXCLUDE: false}仍会排除该运行。要包含该运行,请完全省略该键。 - 在
@traceable(Python)或traceable(JS)父级内执行的子运行会通过共享的追踪上下文继承排除设置:Python 的_METADATAContextVar和 JS 的AsyncLocalStorage。子级自身在装饰器时设置的元数据会叠加在继承值之上。 - 被排除的运行仍会出现在常规追踪视图、运行浏览器和指标中。只有 Trajectory 视图会将它们过滤掉。
手动插桩
如果你在没有使用支持的集成中某个包装器的情况下进行追踪(例如,通过 RunTree、REST API 或围绕提供程序 SDK 的自定义包装器发出运行),请在每个 LLM 运行的元数据上设置 ls_message_format,以将追踪路由到正确的提取器:
| 追踪形态 | 在元数据上设置 |
|---|---|
| LangChain 消息(构造函数封装) | ls_message_format: "langchain" |
| OpenAI Chat Completions | ls_message_format: "completions" |
| OpenAI Responses API | ls_message_format: "responses" |
| Anthropic Messages API | ls_message_format: "anthropic" |
相关
- 配置线程:
thread_id如何在 LangSmith 中分组运行。 - 编码 agent 元数据契约:完整的
ls_agent_typeschema。 - 查看追踪:Trajectory 视图显示的内容以及如何自定义。