在 LangSmith 里,"回滚"不是一键按钮,而是通过三种机制组合实现

  1. 把更早的 commit 重新 Promote 到目标环境(最常用)
  2. 把环境标签(tag)移回 旧的 commit
  3. 在代码里直接 指定旧 commit hash 拉取
    另外,如果你是在 LangGraph Studio / Agent Server 里做"运行时回滚",还可以用 Time Travel(检查点分叉)
    下面逐一讲清楚。

一、最常用的方式:重新 Promote 一个旧 commit

场景

你在 Production 上跑了 commit abc123,今天又 Promote 了 def456,发现线上效果变差,想回到 abc123

步骤(全部在 UI 完成)

  1. 打开该 Prompt 的详情页(左侧 Prompts → 点击目标 Prompt)。
  2. 左侧会看到完整的 commit 历史,以及 Staging / Production 两个环境。
  3. 找到你想回滚到的那个旧 commit(比如 abc123),悬停 → 点击 Promote
  4. 在弹窗中选择目标环境(例如 Production),确认。

这样 Production 的标签就指向了旧的 abc123,等效于"回滚"。
def456 仍然保留在 commit 历史里,不会丢失。

要点

  • 回滚本身 = 把某个旧 commit 重新 Promote 到目标环境
  • 不影响 Staging;如果 Staging 也在新版本上,可以单独再 Promote 旧版到 Staging。
  • 可以随时在任意两个环境之间来回 Promote,没有"只能向前"的限制。

二、用标签(Tag)回滚:把 Tag 移回旧 commit

场景

你不用 Staging/Production 预置环境,而是自己打了 v1.0v2.0 等标签;现在想把 v2.0 移回旧的 commit。

步骤

  1. 打开 Prompt 详情页,在 commit 列表中找到旧 commit。
  2. 悬停 → 选择 “Add tag”“Move tag”(如果标签已存在于另一个 commit 上)。
  1. 选择要移动的标签(例如 v2.0),确认。

之后代码里 client.pull_prompt("my-prompt:v2.0") 拿到的就是旧版本。

与 Promote 的区别

Promote 移动 Tag
操作对象 Staging / Production 预置标签 任意自定义标签
谁能用 需要 Owner/编辑权限 需要 Owner/编辑权限
典型用途 环境级别的发布/回滚 自定义版本号管理

三、在代码里直接指定旧 commit hash(最灵活)

场景

不想改 UI 上的环境/标签配置,临时在代码里回退到已知的好版本。

做法

from langsmith import Client
client = Client()
# 正常:用 tag 拉取(跟环境/标签绑定)
prompt = client.pull_prompt("joke-generator:production")
# 回滚:直接指定某个 commit hash
prompt = client.pull_prompt("joke-generator:abc12345")
# 回滚到 staging
prompt = client.pull_prompt("joke-generator:staging")

适用情况:

  • 紧急回滚,来不及改 UI。
  • A/B 测试:不同请求拉不同 commit。
  • 调试:对比两个 commit 的效果。

四、LangGraph Studio / Agent Server 里的"运行时回滚"(Time Travel)

如果你用的是 LangGraph + Agent Server,回滚还有一个维度:从某个历史检查点重新执行

1) 在 Studio 中 Time Travel

  • 打开一个 Thread(对话线程),右侧可以看到完整的 状态时间线
  • 点击任意一个历史检查点(状态快照),可以:
    • Fork:从该点分叉出新线程继续执行。
    • Re-run:从该点重新执行后续节点。
  • 这等效于"回滚到某个中间状态再重新走一遍"。

2) 在 SDK 中用检查点回滚

from langgraph_sdk import get_client
client = get_client(url="http://localhost:8123")
# 获取某个 thread 的历史状态
history = await client.threads.get_history(thread_id="xxx")
# 拿到某个旧状态的 checkpoint_id
old_checkpoint = history[5].checkpoint_id
# 从该检查点重新执行(或 fork 一个新线程)
await client.runs.create(
    thread_id="xxx",
    assistant_id="my-agent",
    input={"messages": [{"role": "user", "content": "继续"}]},
    checkpoint_id=old_checkpoint,  # 从这个检查点开始
)

与 Prompt 回滚的关系

回滚维度 回滚对象 粒度
Prompt 回滚(上面三种) Prompt 模板内容 整个 Prompt 的版本
Time Travel Agent 运行状态 某次执行的某个节点
两者可以组合:先 Prompt 回滚到旧版模板,再对受影响的 Thread 做 Time Travel 重新执行。

五、最佳实践:建议的回滚流程

┌──────────────────────────────────────────────────┐
│               Prompt 发布流程                     │
│                                                  │
│  Playground 编辑 ──保存──> commit_1               │
│       │                                          │
│       ├── Promote commit_1 ──> Staging           │
│       │       │                                  │
│       │   测试通过?                               │
│       │       │                                  │
│       │    是 ├── Promote commit_1 ──> Production│
│       │       │                                  │
│       │    否 └── 继续编辑 ──保存──> commit_2    │
│       │               │                          │
│       │               └── Promote commit_2 ──>   │
│       │                   Staging(覆盖)         │
│       │                                          │
│  ─── 线上发现异常,需要回滚 ────┐                 │
│                                │                  │
│  方式1: Promote commit_1 ──> Production(覆盖)  │
│  方式2: 把 production tag 移回 commit_1          │
│  方式3: 代码里临时指定 commit_1 的 hash          │
└──────────────────────────────────────────────────┘

几个关键建议

  1. 每个 commit 都有唯一 hash,永远不会丢——即使你 Promote 了新版本,旧版本随时可以再 Promote 回来。
  2. 用 tag 而不是 hash 做代码引用——代码里写 "my-prompt:production" 而不是 "my-prompt:abc123",回滚时只需改 tag 指向,不需要改代码。
  3. 重大变更前先打一个自定义 tag 做快照(比如 v1.0-golden),方便随时回退。
  4. 回滚后记得跑一次 Eval——用 LangSmith 的离线评测对比新旧版本,确认回滚确实修复了问题。

Logo

更多推荐