Skip to main content

Webhook 自动化

在记忆变化时触发外部系统 — 同步、通知、自动化。


Webhook 自动化

Webhook 让你在 Synapse 事件触发时启动外部系统。本指南涵盖常见自动化模式。

常见模式

模式 1:关键记忆通知

当存储关键记忆时发送 Slack 消息:

# Webhook 处理程序(你的服务器)
@app.post("/webhook")
async def handle(request):
    payload = await request.json()
    
    # 验证签名
    if not verify_signature(payload, request.headers):
        return 401
    
    if payload["event"] == "memory.store":
        memory = payload["data"]
        if memory.get("priority") == "critical":
            # 发送 Slack 通知
            await slack.post(
                f"🚨 Critical memory stored: {memory['key']}\n{memory['content'][:200]}"
            )
    
    return 200

注册 Webhook:

curl -X POST https://synapse.schaefer.zone/webhooks \
  -H "Authorization: Bearer YOUR_MIND_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://my-app.com/webhook",
    "events": "memory.store",
    "secret": "my-hmac-secret"
  }'

模式 2:同步到外部系统

把记忆同步到 Notion、Obsidian 或任何外部知识库:

@app.post("/webhook")
async def sync_to_notion(request):
    payload = await request.json()
    
    if payload["event"] == "memory.store":
        memory = payload["data"]
        # 创建 Notion 页面
        await notion.create_page(
            title=memory["key"],
            content=memory["content"],
            tags=memory.get("tags", [])
        )
    
    elif payload["event"] == "memory.delete":
        # 从 Notion 删除
        await notion.delete_page(memory_id=payload["data"]["id"])
    
    return 200

模式 3:触发 CI/CD

当存储 “release” 记忆时触发部署:

@app.post("/webhook")
async def trigger_deploy(request):
    payload = await request.json()
    
    if payload["event"] == "memory.store":
        memory = payload["data"]
        if memory.get("key", "").startswith("release_"):
            # 触发 GitLab pipeline
            await gitlab.trigger_pipeline(
                project="synapse",
                ref="main",
                variables={"RELEASE_MEMORY_ID": memory["id"]}
            )
    
    return 200

模式 4:人类消息唤醒 Agent

当人类发送聊天消息时触发 LLM Agent 运行:

@app.post("/webhook")
async def wake_agent(request):
    payload = await request.json()
    
    if payload["event"] == "chat.message_received":
        message = payload["data"]
        # 排队 Agent 处理任务
        await job_queue.enqueue(
            "process_message",
            message_id=message["id"],
            content=message["content"]
        )
    
    return 200

模式 5:聚合指标

跟踪记忆增长、聊天活动、任务完成:

@app.post("/webhook")
async def track_metrics(request):
    payload = await request.json()
    event = payload["event"]
    
    metrics = {
        "memory.store": "memories_stored_total",
        "memory.delete": "memories_deleted_total",
        "chat.message_received": "messages_received_total",
        "task.created": "tasks_created_total",
        "task.completed": "tasks_completed_total",
    }
    
    if event in metrics:
        await prometheus.increment(metrics[event])
    
    return 200

签名验证

始终验证 Webhook 签名以防伪造:

import hmac
import hashlib

def verify_signature(payload_body: bytes, headers, secret: str) -> bool:
    signature = headers.get("X-Synapse-Signature", "")
    if not signature.startswith("sha256="):
        return False
    
    expected = hmac.new(
        secret.encode(),
        payload_body,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(f"sha256={expected}", signature)

重试逻辑

Synapse 会以指数退避重试失败的 Webhook。你的处理程序应该:

  1. 快速返回 200 — 不要同步做重活
  2. 排队处理 — 使用后台作业系统
  3. 保持幂等 — 同一事件可能被投递多次
@app.post("/webhook")
async def handle(request):
    payload = await request.json()
    # 排队异步处理
    await job_queue.enqueue("process_webhook", payload)
    # 立即返回
    return 200

调试 Webhook

检查投递历史

Webhook 投递会被记录。查看你的 Webhook 最近的投递:

# 获取 Webhook 详情,包含最近投递
curl -H "Authorization: Bearer YOUR_MIND_KEY" \
     https://synapse.schaefer.zone/webhooks/wh_001

手动测试 Webhook

# 触发测试事件
curl -X POST https://synapse.schaefer.zone/webhooks/wh_001/test \
  -H "Authorization: Bearer YOUR_MIND_KEY"

常见问题

问题 修复
4xx 响应 检查处理程序是否返回 200
5xx 响应 服务器错误 — 查看你的应用日志
超时 快速返回 200,异步排队处理
重复投递 让处理程序幂等
签名不匹配 确认 secret 正确

最佳实践

下一步