为规则设置 Webhook 通知
当您在自动化操作中添加 Webhook URL 时,每当您定义的规则与任何新的运行匹配时,我们都会向您的 Webhook 端点发出 POST 请求。
Webhook payload
我们发送到您的 Webhook 端点的 payload 包含
"rule_id"
这是发送此 payload 的自动化的 ID"start_time"
和"end_time"
这些是我们找到匹配运行的时间边界"runs"
这是一个运行数组,其中每个运行都是一个字典。如果您需要关于每个运行的更多信息,我们建议在您的端点中使用我们的 SDK 从我们的 API 获取它。"feedback_stats"
这是一个包含运行反馈统计信息的字典。下面显示了此字段的示例 payload。
"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": {}
}
},
根据您的运行有多新,inputs_s3_urls
和 outputs_s3_urls
字段可能包含指向实际数据的 S3 URL,而不是数据本身。
inputs
和 outputs
可以分别通过 inputs_s3_urls
和 outputs_s3_urls
中提供的 ROOT.presigned_url
获取。
这是我们发送到您的 Webhook 端点的完整 payload 示例
{
"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
}
]
}
Webhook 安全性
我们强烈建议您在 Webhook URL 中添加一个密钥查询字符串参数,并在任何传入请求中验证它。这确保了如果有人发现您的 Webhook URL,您可以区分这些调用和真实的 Webhook 通知。
一个例子是
https://api.example.com/langsmith_webhook?secret=38ee77617c3a489ab6e871fbeb2ec87d
Webhook 自定义 HTTP 标头
如果您想随您的 webhook 发送任何特定的标头,可以为每个 URL 配置。要进行设置,请单击 URL 字段旁边的 Headers
选项并添加您的标头。
标头以加密格式存储。
Webhook 交付
在向您的 webhook 端点交付事件时,我们遵循以下准则
- 如果我们无法连接到您的端点,我们会在声明交付失败之前,最多重试传输连接 2 次。
- 如果您的端点回复时间超过 5 秒,我们将声明交付失败,并且不进行重试。
- 如果您的端点在 5 秒内返回 5xx 状态代码,我们将使用指数退避重试最多 2 次。
- 如果您的端点返回 4xx 状态代码,我们将声明交付失败,并且不进行重试。
- 您的端点在正文中返回的任何内容都将被忽略
使用 Modal 的示例
设置
有关如何设置此功能的示例,我们将使用 Modal。Modal 为推理和微调提供自动扩展 GPU,为代码 Agent 提供安全容器化,以及无服务器 Python Web 端点。我们将在此处重点关注 Web 端点。
首先,创建一个 Modal 帐户。然后,在本地安装 Modal SDK
pip install modal
要完成帐户设置,请运行命令
modal setup
并按照说明进行操作
密钥
接下来,您需要在 Modal 中设置一些密钥。
首先,LangSmith 将需要通过传入密钥来验证 Modal 的身份。最简单的方法是在查询参数中传入密钥。为了验证此密钥,我们需要在 Modal 中添加一个密钥来验证它。我们将通过创建一个 Modal 密钥来做到这一点。您可以在此处查看有关密钥的说明。为此,让我们将我们的密钥称为 ls-webhook
,并使其设置一个名为 LS_WEBHOOK
的环境变量。
我们还可以设置 LangSmith 密钥 - 幸运的是,已经有一个用于此的集成模板!
服务
之后,您可以创建一个 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 ...
轻松部署它(请参阅 此处 的文档)。
您现在应该得到类似以下的内容
✓ 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
要记住的重要事项是 https://hwchase17--auth-example-f.modal.run
- 我们创建的要运行的函数。注意:这不是最终的部署 URL,请确保不要意外使用它。
连接起来
我们现在可以获取上面创建的函数 URL 并将其添加为 webhook。我们必须记住也要将密钥作为查询参数传入。将它们放在一起,它应该看起来像这样
https://hwchase17--auth-example-f-dev.modal.run?secret={SECRET}
将 {SECRET}
替换为您创建的用于访问 Modal 服务的密钥。