Skip to main content
许多 LLM 应用具备类似聊天机器人的界面,用户与 LLM 应用之间会进行多轮对话。为了追踪这些对话,你可以在 LangSmith 中使用 线程

将追踪记录分组到线程中

线程 是代表单次对话的一系列追踪记录。每次响应都表示为独立的追踪记录,但这些追踪记录通过属于同一线程而相互关联。 要将追踪记录关联在一起,你需要传入一个特殊的 metadata 键,其值为该线程的唯一标识符。键名应为以下之一:
  • session_id
  • thread_id
  • conversation_id
值可以是任意字符串,但我们建议使用 UUID,例如 f47ac10b-58cc-4372-a567-0e02b2c3d479。查看 向追踪记录添加元数据和标签 获取操作指南。
重要: 为确保跨整个线程的筛选和令牌计数正常工作,你必须在 所有运行(包括追踪记录内的子运行)上设置线程元数据(session_idthread_idconversation_id)。如果子运行没有 thread_id 元数据,则在以下情况下它们将不会被包含:
  • 按线程筛选运行。
  • 计算线程的令牌使用量。
  • 跨线程聚合成本。
创建子运行时(例如,对嵌套函数使用 @traceable 或创建子跨度),请确保将线程元数据传播到所有子运行。

示例

此示例演示了如何使用结构化的消息格式来记录和检索对话历史,以维护长期运行的聊天。
import os
import json
from dotenv import load_dotenv

# 从 .env 文件加载环境变量
load_dotenv()

import openai
from langsmith import traceable, Client
from langsmith.wrappers import wrap_openai

# 初始化客户端
langsmith_client = Client()
client = wrap_openai(openai.Client())

# 配置
THREAD_ID = "thread-id-1"

# 使用本地目录存储线程历史。生产环境中请使用持久化存储方案。
THREADS_DIR = os.path.join(os.path.dirname(__file__), "threads")

# 获取线程中所有 LLM 调用的历史以构建对话历史
def get_thread_history(thread_id: str) -> list:
    path = os.path.join(THREADS_DIR, f"{thread_id}.json")
    if not os.path.exists(path):
        return []
    with open(path, "r") as f:
        return json.load(f)

def save_thread_history(thread_id: str, messages: list):
    os.makedirs(THREADS_DIR, exist_ok=True)
    with open(os.path.join(THREADS_DIR, f"{thread_id}.json"), "w") as f:
        json.dump(messages, f, indent=2, default=str)


@traceable(name="Chat Bot", metadata={"thread_id": THREAD_ID})
def chat_pipeline(messages: list, get_chat_history: bool = False):
    # 是继续现有线程还是开始新线程
    if get_chat_history:
        history_messages = get_thread_history(THREAD_ID)
        # 获取现有对话历史并追加新消息
        all_messages = history_messages + messages
    else:
        all_messages = messages

    # 调用模型
    chat_completion = client.chat.completions.create(
        model="gpt-4.1-mini", messages=all_messages
    )

    response_message = chat_completion.choices[0].message
    print("模型响应:", response_message)

    full_conversation = all_messages + [{"role": response_message.role, "content": response_message.content}]
    save_thread_history(THREAD_ID, full_conversation)

    return {"messages": full_conversation}


# 格式化消息
messages = [
    {
        "content": "你好,我叫 Sally",
        "role": "user"
    }
]

# 调用聊天流程
result = chat_pipeline(messages, get_chat_history=False)
进行以下调用来继续对话。通过传递 get_chat_history=True/getChatHistory: true,你可以从上次中断的地方继续对话。这意味着 LLM 将接收整个消息历史并据此响应,而不仅仅是响应最新消息。
# 格式化消息
messages = [
    {
        "content": "我叫什么名字",
        "role": "user"
    }
]

# 调用聊天流程
result = chat_pipeline(messages, get_chat_history=True)
继续对话。由于包含了过往消息,LLM 会记住对话内容。
# 继续对话。
messages = [
    {
        "content": "我发给你的第一条消息是什么?",
        "role": "user"
    }
]

chat_pipeline(messages, get_chat_history=True)

查看线程

你可以在任何项目详情页中点击 Threads 标签页来查看线程。然后你将看到所有线程的列表,按最近活动排序。
LangSmith UI 显示线程表格。
在线程视图中使用 Polly 来分析对话线程、理解用户情绪、识别痛点并跟踪问题是否得到解决。

查看单个线程

你可以点击进入特定线程。这将打开该特定线程的历史记录。
LangSmith UI 显示线程表格。
线程可以通过两种不同方式查看: 你可以使用页面顶部的按钮在两种视图之间切换,或使用键盘快捷键 T 在两种视图之间切换。

线程概览

线程概览页面显示类似聊天机器人的界面,你可以看到对话每一轮的输入和输出。你可以配置在概览中显示输入和输出的哪些字段,或通过点击 Configure 按钮显示多个字段。 输入和输出的 JSON 路径支持负索引,因此你可以使用 -1 来访问数组的最后一个元素。例如,inputs.messages[-1].content 将访问 messages 数组中的最后一条消息。

追踪视图

这里的追踪视图类似于查看单个运行时的追踪视图,不同之处在于你可以轻松访问线程中每一轮的所有运行。

查看反馈

查看线程时,在页面顶部你会看到一个名为 Feedback 的部分。在这里你可以看到构成线程的每个运行的反馈。这些反馈是聚合的,因此如果你对线程的每个运行评估相同的标准,你将看到所有运行的平均分数。你也可以在这里看到留下的 线程级别反馈

保存线程级别筛选器

线程筛选器会检查所有运行,如果至少有一个运行匹配筛选条件,就会显示该线程。
与在项目级别保存筛选器类似,你也可以在线程级别保存常用筛选器。要在 Threads 表格上保存筛选器,请使用 Add filter 按钮 设置筛选器,然后点击 Save view 按钮。 你可以通过分别点击 AnnotateOpen trace,在侧面板中打开追踪记录或对其进行标注。