以编程方式使用文档

将 LangSmith 检测到的代理问题转发到您的事件管理、寻呼或聊天工具中。 LangSmith Engine 在打开新问题或将新追踪链接到已打开的问题时,向您的端点发送 Webhook 事件。

要配置 Webhook 订阅,请打开 **Engine 设置** 面板,在 **Engine** 标签页。参见 配置 LangSmith Engine.

传递

LangSmith 发送一个 POST 请求,带有 JSON 正文,发送到您的 Webhook URL。该请求使用 Content-Type: application/json 并包含您附加到订阅的任何自定义标头。

属性
方法POST
正文JSON, 通用信封 见下文
方案http://https:// 均被接受。 https:// 强烈推荐
签名X-LangSmith-Signature 标头,使用订阅的签名密钥签名
超时每次尝试 20 秒
尝试次数最多 4 次尝试(1 次初始加 3 次指数退避重试),针对传输错误、HTTP 408, 425, 429和任何 HTTP 5xx。其他 4xx 响应被视为永久性的,不会重试
响应成功仅由状态码决定。响应正文被忽略。

自定义请求头

您可以为每个订阅附加任意请求头(例如, Authorization: Bearer …)用于在您的端点验证调用者身份。 Content-Type 由 LangSmith 设置,无法被覆盖。

签名密钥

每个订阅都有一个签名密钥。LangSmith 使用此密钥对原始 webhook 请求体进行签名,并将结果放在 X-LangSmith-Signature header.

请求头值的格式如下:

sha256=<hex-encoded HMAC-SHA256 digest>

在解析或处理负载之前验证签名。HMAC 输入是精确的原始请求体字节,HMAC 密钥是订阅的签名密钥。请勿在验证前解析并重新序列化 JSON 体。

from typing import Optional


def verify_langsmith_signature(
    *,
    body: bytes,
    signing_secret: str,
    signature_header: Optional[str],
) -> bool:
    if not signature_header or not signature_header.startswith("sha256="):
        return False

    expected = "sha256=" + hmac.new(
        signing_secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()

    return hmac.compare_digest(expected, signature_header)
  body,
  signingSecret,
  signatureHeader,
}: {
  body: Buffer;
  signingSecret: string;
  signatureHeader: string | undefined;
}) {
  if (!signatureHeader?.startsWith("sha256=")) {
    return false;
  }

  const expected = `sha256=${createHmac("sha256", signingSecret)
    .update(body)
    .digest("hex")}`;

  const expectedBytes = Buffer.from(expected);
  const actualBytes = Buffer.from(signatureHeader);

  return (
    expectedBytes.length === actualBytes.length &&
    timingSafeEqual(expectedBytes, actualBytes)
  );
}

轮换签名密钥

当签名密钥可能已泄露时,或当您组织的凭证轮换策略需要新密钥时,请轮换签名密钥。

要轮换密钥,请在 **引擎设置**中打开订阅行,然后点击 **轮换签名密钥**,然后确认。LangSmith 会生成新的签名密钥并立即用于后续 webhook 投递。前一个密钥在轮换完成后立即停止为投递进行签名。

轮换密钥后,更新每个验证 X-LangSmith-Signature 的消费者以使用新值。

严重程度过滤

每个订阅都有一个 severity_threshold 阈值。对于问题事件,只有当问题的 0 to 3小于或等于阈值时才会投递事件。数字越小越紧急。 severity | 严重程度 | 含义 |

紧急
0
1
2
3 例如,具有

的订阅仅接收 severity_threshold: 1 (0)和 URGENT (1)问题的相关事件。 HIGH 严重程度阈值不适用于

,因为运行失败事件的作用域是引擎会话而非特定问题。 issue.agent_run.failed事件类型过滤

每个订阅都指定要接收的

事件类型 。未指定明确列表的订阅默认接收 事件包装 ["issue.created"].

投递到您端点的每个事件都使用相同的外层 JSON 结构。

| 字段 | 类型 | 描述 |

UUID本次投递的唯一标识符。在重试时保持稳定,用于去重。
idstring
typeinteger
createdUUID
request_id 批量合并 [object
data 。仅在 data.object时包含 data.trace 事件上。 issue.trace.added events.

问题 data.object

对于 issue.createdissue.trace.added, data.object 是问题的快照。请将其视为事件生成时问题的权威状态。

FieldTypeDescription
idUUID问题 ID。
namestring问题的简短标题。
descriptionstring人类可读的描述。
severityinteger0 (紧急) 到 3 (低)。参见 严重程度过滤.
tenant_idUUID问题所属的工作空间。
tenant_namestring工作空间显示名称。
session_idUUID问题所属的追踪项目。
session_namestring追踪项目名称。
urlstringLangSmith UI 中问题的深度链接。

运行失败 data.object

对于 issue.agent_run.failed, data.object 描述失败的 Engine 运行。

FieldTypeDescription
tenant_idUUID运行所属的工作空间。
tenant_namestring工作空间显示名称。
session_idUUID运行所属的追踪项目。
session_namestring追踪项目名称。
urlstringUI 中 LangSmith 项目的深度链接。
thread_idstringEngine 线程 ID。
run_idstringEngine 运行 ID。不可用时省略。
statusstring最终运行状态。
error_messagestring失败运行的错误文本。不可用时省略。
occurred_atstring失败发生时间的 RFC 3339 时间戳。

data.trace

data.trace 仅在 issue.trace.added events.

FieldTypeDescription
run_idUUID链接到问题的运行 ID。
trace_idUUID包含该运行的追踪 ID。
start_timestring运行开始时间的 RFC 3339 时间戳。
commentstring \null

批量合并

单个上游操作可以产生多个 webhook 事件。当 Engine 打开一个新问题并附加五个追踪到它时,您会收到一个 issue.created 事件和五个 issue.trace.added 事件,它们都共享相同的 request_id。使用 request_id 将这些分组为单个下游通知。

事件类型

以下事件类型是 LangSmith Engine 今天发送的完整集合。未来可能会添加新类型,因此处理程序应该忽略未知的 type 值而不是失败。

issue.created

当 LangSmith Engine 创建新问题时发送。 data.trace 被省略。

{
  "id": "b91c1f0e-7c4a-4f53-9d3e-9f1c8e7a2b10",
  "type": "issue.created",
  "created": 1747238400,
  "request_id": "0d2f4f6a-2a3a-4b6e-9b87-5d5b6e8c9a01",
  "data": {
    "object": {
      "id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
      "name": "Tool selection inconsistency",
      "description": "Agent repeatedly calls the search tool with identical arguments before terminating.",
      "severity": 1,
      "tenant_id": "11111111-2222-3333-4444-555555555555",
      "tenant_name": "Acme Workspace",
      "session_id": "66666666-7777-8888-9999-aaaaaaaaaaaa",
      "session_name": "prod-api",
      "url": "https://smith.langchain.com/o/11111111-2222-3333-4444-555555555555/projects/p/66666666-7777-8888-9999-aaaaaaaaaaaa?tab=5&issue=9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d"
    }
  }
}

issue.trace.added

当新追踪链接到现有问题时发送。 data.trace 描述链接的追踪。

{
  "id": "c02e3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
  "type": "issue.trace.added",
  "created": 1747238410,
  "request_id": "0d2f4f6a-2a3a-4b6e-9b87-5d5b6e8c9a01",
  "data": {
    "object": {
      "id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
      "name": "Tool selection inconsistency",
      "description": "Agent repeatedly calls the search tool with identical arguments before terminating.",
      "severity": 1,
      "tenant_id": "11111111-2222-3333-4444-555555555555",
      "tenant_name": "Acme Workspace",
      "session_id": "66666666-7777-8888-9999-aaaaaaaaaaaa",
      "session_name": "prod-api",
      "url": "https://smith.langchain.com/o/11111111-2222-3333-4444-555555555555/projects/p/66666666-7777-8888-9999-aaaaaaaaaaaa?tab=5&issue=9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d"
    },
    "trace": {
      "run_id": "f1e2d3c4-b5a6-9788-6655-44332211ffee",
      "trace_id": "abcdefab-1234-5678-9abc-def012345678",
      "start_time": "2026-05-14T12:30:00Z",
      "comment": "Reproduces the same tool-loop pattern."
    }
  }
}

issue.agent_run.failed

当 LangSmith Engine 运行失败时发送。此事件是会话范围的,因此不包含 data.trace 并且不使用严重性过滤。

{
  "id": "4d0e8db2-81e6-4491-b8e5-b13a8f5afc0d",
  "type": "issue.agent_run.failed",
  "created": 1747238500,
  "request_id": "f6bbd48a-0386-403d-9344-31051264b45f",
  "data": {
    "object": {
      "tenant_id": "11111111-2222-3333-4444-555555555555",
      "tenant_name": "Acme Workspace",
      "session_id": "66666666-7777-8888-9999-aaaaaaaaaaaa",
      "session_name": "prod-api",
      "url": "https://smith.langchain.com/o/11111111-2222-3333-4444-555555555555/projects/p/66666666-7777-8888-9999-aaaaaaaaaaaa",
      "thread_id": "thread-123",
      "run_id": "run-456",
      "status": "error",
      "error_message": "RuntimeError: missing API key",
      "occurred_at": "2026-05-14T12:45:00Z"
    }
  }
}

测试您的端点

在将真实订阅指向您的端点之前,发送示例负载以验证它在 20 秒超时内接受并确认:

curl -X POST https://your-endpoint.example.com/webhook \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $WEBHOOK_SECRET" \
  -d @sample-issue-created.json

使用来自的示例正文 issue.created as sample-issue-created.json。验证以下内容:

  • - 自定义 Authorization 标头到达并与您在订阅上配置的密钥匹配。
  • - 处理程序通过其键持久保存事件 id 以便重试被去重。
  • - 处理程序返回 2xx 在启动缓慢的下游工作之前。

安全

  • - Webhook URL 在订阅创建时和交付时都会被验证。私有和元数据 IP 范围在 SaaS 中被阻止。两者都 http://https:// 都被接受;使用 https:// 以便负载和任何自定义标头不会以明文形式发送。
  • - LangSmith 使用订阅的签名密钥对 webhook 正文进行签名。在处理负载之前验证 X-LangSmith-Signature
  • - 您还可以在订阅上设置自定义标头,例如 Authorization: Bearer …,用于在您的端点进行路由或额外身份验证。
  • - 根据事件进行去重 id 以便重试交付不会导致重复通知。

最佳实践

  • 快速确认。 在您已持久保存事件后立即响应 2xx 。将缓慢工作(扇出、分页、下游 API 调用)移至队列,以便您的处理程序保持在 20 秒超时范围内。
  • 容忍未知的事件类型。 忽略 type 您的处理程序无法识别的值。新事件类型可能会在未事先通知的情况下添加。
  • 容忍新字段。 使用宽松的模式解析负载。新字段可能会在未事先通知的情况下添加到现有事件类型中。