Skip to content
LangSmith 文档版本 跟随上游 源快照 94fd9fb6 更新于 2026-10-18

为规则配置 webhook 通知

配置 webhook 通知,以便在自动化规则匹配 LangSmith 中新的运行或线程时接收 POST 请求。

NOTE

本页介绍 LangSmith 自动化 webhooks,即当自动化规则匹配运行或线程时触发的 POST 通知。如果你在寻找 LangGraph API webhooks(创建或流式运行传递的一个回调参数),参阅使用 webhooks。

当你在一个自动化动作上添加一个 webhook URL 时,只要所定义的规则匹配任何新的运行或线程,LangSmith 就会向你的 webhook 端点发起一次 POST 请求。

Webhook

Webhook payload

LangSmith 发送到你 webhook 端点的负载包含:

  • "rule_id":这是发送此负载的自动化 ID。
  • "start_time" 和 "end_time":这些是 LangSmith 找到匹配项的时间边界。
  • "runs":这是一个运行数组,其中每个运行是一个字典。如果你需要关于每个运行的更多信息,在你的端点中使用 SDK 从 API 获取它。每个运行字典包括:
    • "feedback_stats":一个带有该运行反馈统计信息的字典。此字段的一个示例见下方代码块。
  • "threads":这是一个线程数组,当规则的项目类型为 Threads 时代替 "runs" 发送。一个负载携带其中一个数组或另一个,从不同时携带两者。更多信息,参阅读取线程规则负载。
json
"feedback_stats": {
    "about_langchain": {
        "n": 1,
        "avg": 0.0,
        "show_feedback_arrow": true,
        "values": {}
    },
    "category": {
        "n": 0,
        "avg": null,
        "show_feedback_arrow": true,
        "values": {
            "CONCEPTUAL": 1
        }
    },
    "user_score": {
        "n": 2,
        "avg": 0.0,
        "show_feedback_arrow": false,
        "values": {}
    },
    "vagueness": {
        "n": 1,
        "avg": 0.0,
        "show_feedback_arrow": true,
        "values": {}
    }
}

NOTE

从 S3 URL 获取

根据你的运行有多新,inputs_s3_urls 和 outputs_s3_urls 字段可能包含指向实际数据的 S3 URL,而非数据本身。

inputs 和 outputs 可分别通过 inputs_s3_urls 和 outputs_s3_urls 中提供的 ROOT.presigned_url 获取。

以下是 LangSmith 发送到你 webhook 端点的整个负载的一个示例:

json
{
  "rule_id": "d75d7417-0c57-4655-88fe-1db3cda3a47a",
  "start_time": "2024-04-05T01:28:54.734491+00:00",
  "end_time": "2024-04-05T01:28:56.492563+00:00",
  "runs": [
    {
      "status": "success",
      "is_root": true,
      "trace_id": "6ab80f10-d79c-4fa2-b441-922ed6feb630",
      "dotted_order": "20230505T051324571809Z6ab80f10-d79c-4fa2-b441-922ed6feb630",
      "run_type": "tool",
      "modified_at": "2024-04-05T01:28:54.145062",
      "tenant_id": "2ebda79f-2946-4491-a9ad-d642f49e0815",
      "end_time": "2024-04-05T01:28:54.085649",
      "name": "Search",
      "start_time": "2024-04-05T01:28:54.085646",
      "id": "6ab80f10-d79c-4fa2-b441-922ed6feb630",
      "session_id": "6a3be6a2-9a8c-4fc8-b4c6-a8983b286cc5",
      "parent_run_ids": [],
      "child_run_ids": null,
      "direct_child_run_ids": null,
      "total_tokens": 0,
      "completion_tokens": 0,
      "prompt_tokens": 0,
      "total_cost": null,
      "completion_cost": null,
      "prompt_cost": null,
      "first_token_time": null,
      "app_path": "/o/2ebda79f-2946-4491-a9ad-d642f49e0815/projects/p/6a3be6a2-9a8c-4fc8-b4c6-a8983b286cc5/r/6ab80f10-d79c-4fa2-b441-922ed6feb630?trace_id=6ab80f10-d79c-4fa2-b441-922ed6feb630&start_time=2023-05-05T05:13:24.571809",
      "in_dataset": false,
      "last_queued_at": null,
      "inputs": null,
      "inputs_s3_urls": null,
      "outputs": null,
      "outputs_s3_urls": null,
      "extra": null,
      "events": null,
      "feedback_stats": null,
      "serialized": null,
      "share_token": null
    }
  ]
}

处理批量负载

一个负载涵盖的是一个轮询窗口而非单个匹配。LangSmith 收集在 "start_time" 和 "end_time" 之间该规则匹配到的每个条目,并在一个 POST 中投递它们,而不是为每个条目发送一个 POST。

编写你的端点以遍历该数组,而不是只读取第一个元素。一条线程规则每次执行最多投递 500 个线程。

读取线程规则负载

一条项目类型为 Threads 的规则,会用一个 "threads" 数组替换顶层的 "runs" 数组。该数组中的每个条目包含:

  • "thread_id":变为空闲并匹配该规则的线程 ID。
  • "session_id":该线程所属的追踪项目 ID。
  • "runs":该线程根运行的数组,每条追踪一个,各自带被追踪的输入和输出。工具调用和模型调用等子运行不包含在内。这些运行字典也会省略 "feedback_stats",它仅存在于 "runs" 负载的运行上。

这个示例经过删节,展示了一个带单个根运行的线程:

json
{
  "rule_id": "7f3e9c21-5b48-4a6d-8e12-9f0a1b2c3d4e",
  "start_time": "2026-08-14T09:00:00.000000+00:00",
  "end_time": "2026-08-14T09:01:00.000000+00:00",
  "threads": [
    {
      "thread_id": "019a1b2c-3d4e-7f80-9a1b-2c3d4e5f6071",
      "session_id": "2a9d6e4b-1c37-4f58-b0e9-6d5c4a3b2f10",
      "runs": [
        {
          "trace_id": "019a1b2c-3d4e-7f80-9a1b-2c3d4e5f6072",
          "start_time": "2026-08-14T08:57:12.412000",
          "inputs": {
            "messages": [
              {
                "type": "human",
                "id": "019a1b2c-3d4e-7f80-9a1b-2c3d4e5f6073",
                "content": "How do I group traces into a thread?",
                "additional_kwargs": {},
                "response_metadata": {}
              }
            ]
          }
        }
      ]
    }
  ]
}

安全性

给 webhook URL 添加一个秘密查询字符串参数,并在每个传入请求上验证它。这确保如果有人发现了你的 webhook URL,你也能区分那些调用与真实的 webhook 通知。

一个例子会是

https://api.example.com/langsmith_webhook?secret=38ee77617c3a489ab6e871fbeb2ec87d

Webhook 自定义 HTTP 标头

如果你想随你的 webhook 发送任何特定的标头,这可以按 URL 配置。要设置这一点,点击 URL 字段旁边的 Headers 选项并添加你的标头。

NOTE

标头以加密格式存储。

Webhook headers

Webhook 投递

在向你的 webhook 端点投递事件时,LangSmith 遵循以下准则:

  • 如果 LangSmith 无法连接到你的端点,LangSmith 会重试传输连接最多 2 次,然后宣告投递失败。
  • 如果你的端点回复耗时超过 5 秒,LangSmith 宣告投递失败且不重试。
  • 如果你的端点在不到 5 秒内返回一个 5xx 状态码,LangSmith 会重试最多 2 次并进行指数退避。
  • 如果你的端点返回一个 4xx 状态码,LangSmith 宣告投递失败且不重试。
  • 你的端点在请求体中返回的任何内容都会被忽略。

确保评估在 webhook 触发前完成

默认情况下,自动化规则在独立的时间表上运行。一条 webhook 规则和一条在线评估器规则扫描同一个项目时,可能会在不同时间拾取同一个运行,因此 webhook 可能在评估器还没来得及为该运行打分之前触发。

推荐的解决方案是给你的 webhook 规则添加一个反馈过滤器。这告诉 LangSmith 只在某个运行已经携带预期分数之后,才将其发送到你的 webhook,无论它何时被评估。

例如,你有一个产生 answer_usefulness 分数的在线评估器,以及一条只应在该分数出现后触发的 webhook 规则。

  1. 在你的追踪项目的 Automations 标签中打开该 webhook 自动化规则。

  2. 编辑该规则的过滤器以要求该反馈键。在过滤器构建器中添加一个条件:

    has(feedback_key, "answer_usefulness")
  3. 保存该规则。

现在该 webhook 规则会跳过任何尚未具有 answer_usefulness 分数的运行。当评估器规则运行并附加该分数时,webhook 规则的下一次轮询周期会拾取那些运行并将它们发送到你的端点。

TIP

你也可以按分数值本身(而非仅其存在与否)进行过滤。例如,要将只有低有用性分数的运行发送到你的端点:

has(feedback_key, "answer_usefulness") and feedback_score < 0.5

有关完整的过滤语法,参阅过滤追踪 (ClickHouse)。

NOTE

在单条自动化规则内,动作按固定顺序执行:标注队列 → 数据集 → webhook → 评估。这意味着如果你的 webhook 和评估器配置在同一条规则上,webhook 总会在那条规则的运行上评估完成之前触发。为确保 webhook 接收到评估分数,请将 webhook 和评估器保持为分开的规则,并按示例所述在 webhook 规则上使用一个反馈过滤器。

使用 Modal 的示例

准备

有关如何设置这一点的示例,本指南使用 Modal。Modal 为推理和微调提供自动扩缩的 GPU、为代码 agent 提供安全的容器化,以及无服务器的 Python web 端点。本指南聚焦于 web 端点。

首先,创建一个 Modal 账户。然后在本地安装 Modal SDK:

bash
pip install modal
bash
uv add modal

为了完成账户设置,运行命令:

shell
modal setup

按照说明完成账户设置。

Secrets

接下来,你需要在 Modal 中设置一些 secrets。

首先,LangSmith 需要通过传入一个 secret 来向 Modal 进行身份验证。 最简单的方式是在查询参数中传入一个 secret。 要验证此 secret,在 Modal 中添加一个 secret 来验证它。 通过创建一个 Modal secret来做到这一点。 将该 secret 命名为 ls-webhook 并设置一个名为 LS_WEBHOOK 的环境变量。

你也可以设置一个 LangSmith secret——幸运地,已经有一个用于此的集成模板!

LangSmith Modal Template

服务

之后,你可以创建一个将作为你端点的 Python 文件。 下方代码块中给出了一个示例,并附有解释其运作的注释:

python
from fastapi import HTTPException, status, Request, Query
from modal import Secret, Stub, web_endpoint, Image

stub = Stub("auth-example", image=Image.debian_slim().pip_install("langsmith"))

@stub.function(
    secrets=[Secret.from_name("ls-webhook"), Secret.from_name("my-langsmith-secret")]
)
# We want this to be a `POST` endpoint since we will post data here
@web_endpoint(method="POST")
# We set up a `secret` query parameter
def f(data: dict, secret: str = Query(...)):
    # You can import dependencies you don't have locally inside Modal functions
    from langsmith import Client

    # First, we validate the secret key we pass
    import os

    if secret != os.environ["LS_WEBHOOK"]:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect bearer token",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # This is where we put the logic for what should happen inside this webhook
    ls_client = Client()
    runs = data["runs"]
    ids = [r["id"] for r in runs]
    feedback = list(ls_client.list_feedback(run_ids=ids))
    for r, f in zip(runs, feedback):
        try:
            ls_client.create_example(
                inputs=r["inputs"],
                outputs={"output": f.correction},
                dataset_name="classifier-github-issues",
            )
        except Exception:
            raise ValueError(f"{r} and {f}")
    # Function body
    return "success!"

用 modal deploy ... 部署它(参阅管理 Modal 部署)。

你现在应该会看到类似这样的东西:

✓ Created objects.
├── 🔨 Created mount /Users/harrisonchase/workplace/langsmith-docs/example-webhook.py
├── 🔨 Created mount PythonPackage:langsmith
└── 🔨 Created f => https://hwchase17--auth-example-f.modal.run
✓ App deployed! 🎉

View Deployment: https://modal.com/apps/hwchase17/auth-example

注意函数 URL:https://hwchase17--auth-example-f.modal.run。 注意:这不是最终部署 URL,确保不要误用它。

连接起来

取你先前创建的函数 URL 并将其添加为一个 webhook。 记得也将 secret 密钥作为一个查询参数传入。 把它组合起来,它看起来应类似于:

https://hwchase17--auth-example-f-dev.modal.run?secret={SECRET}

将 {SECRET} 替换为你创建的用于访问 Modal 服务的 secret 密钥。


BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。