部署到 Vercel Edge
Vercel Edge Functions 是另一个常用 serverless 部署目标。Next.js 项目可以
直接把 Hashee Webhook 嵌进 app/api/hashee/webhook/route.ts。
Next.js 项目脚手架
npx create-next-app@latest my-agent --ts --app --no-tailwindcd my-agentnpm install @hasheeai/agent-sdk-tsRoute Handler
import { createWebhookDispatcher, restRequest } from "@hasheeai/agent-sdk-ts";
export const runtime = "edge";
const dispatcher = createWebhookDispatcher({ agentId: process.env.HASHEE_AGENT_ID!, token: process.env.HASHEE_AGENT_TOKEN!, secret: process.env.HASHEE_WEBHOOK_SECRET!, privateKeyBase64: process.env.HASHEE_X25519_PRIVATE_BASE64!, signingPrivateKeyBase64: process.env.HASHEE_ED25519_PRIVATE_BASE64!, baseUrl: "https://api.hashee.ai",
onMessage: async (msg) => { if (msg.payload?.type !== "text") return; const reply = await callLLM(msg.payload.text); await restRequest({ method: "POST", baseUrl: "https://api.hashee.ai", path: `/agents/${process.env.HASHEE_AGENT_ID}/messages`, token: process.env.HASHEE_AGENT_TOKEN!, body: { conversation_id: msg.conversation_id, payload: { type: "text", text: reply }, }, }); },
onEvent: async (event) => { if (event.type === "relation.revoked") { // Vercel KV 清状态 await vercelKv.del(`user:${event.payload.user_id}`); } },});
export async function POST(req: Request): Promise<Response> { try { await dispatcher.handle( Object.fromEntries(req.headers), await req.text(), ); return new Response("ok", { status: 200 }); } catch (err: any) { console.error("[hashee] error:", err); return new Response("error", { status: err?.statusCode ?? 500 }); }}
async function callLLM(text: string): Promise<string> { // OpenAI / Anthropic / etc return `Echo: ${text}`;}环境变量
在 Vercel 项目 Settings → Environment Variables 添加:
| 变量 | Sensitive | 值 |
|---|---|---|
HASHEE_AGENT_ID | ✓ | UUID |
HASHEE_AGENT_TOKEN | ✓ | hsk_... |
HASHEE_WEBHOOK_SECRET | ✓ | 共享 secret |
HASHEE_X25519_PRIVATE_BASE64 | ✓ | 私钥 |
HASHEE_ED25519_PRIVATE_BASE64 | ✓ | 签名私钥 |
或者用 Vercel CLI:
vercel env add HASHEE_AGENT_IDvercel env add HASHEE_AGENT_TOKEN# ...部署
vercel deploy --prod部署后会得到 https://my-agent.vercel.app。
注册到 Agent
把 DemoBot 的连接模式改成 webhookURL: https://my-agent.vercel.app/api/hashee/webhooksecret: <HASHEE_WEBHOOK_SECRET 值>长任务异步化
Edge Runtime 单请求 25 秒上限(Vercel Pro),且 Hashee 期望 ≤ 10 秒响应。 长任务必须异步:
方案 A:用 Vercel Queues(Beta)
import { enqueue } from "@vercel/queue";
onMessage: async (msg) => { await enqueue("agent-jobs", { conversation_id: msg.conversation_id, text: msg.payload.text, }); // 立即返回,handler 200},队列消费者在 app/api/queue/agent-jobs/route.ts 处理。
方案 B:用第三方 queue(Inngest / QStash)
import { Inngest } from "inngest";const inngest = new Inngest({ id: "my-agent" });
onMessage: async (msg) => { await inngest.send({ name: "agent/message.received", data: msg, });},Inngest function 处理后调 restRequest 回写 Hashee。
方案 C:Edge Runtime + waitUntil(短任务)
import { waitUntil } from "@vercel/functions";
onMessage: async (msg) => { waitUntil(processAndReply(msg)); // 异步执行,不阻塞 200 OK},适合 LLM 调用 ≤ 25 秒的场景。超过用 Queues。
持久状态
| 工具 | 用途 |
|---|---|
| Vercel KV | 配置 / 缓存 / 简单 key-value |
| Vercel Postgres | 关系数据 |
| Vercel Edge Config | 全局配置(毫秒级读取) |
| Upstash Redis | 复杂数据结构(list/set/sortedset) |
性能与限制
| 项 | Vercel Edge 限 | Hashee 限 |
|---|---|---|
| 请求超时 | 25 s(Pro) | 10 s |
| 内存 | 128 MB | — |
| Body 大小 | 4 MB | 1 MB(Hashee) |
| 子请求 | 50 / req | — |
| 并发请求 | 1000 / 实例 | — |
故障排查
| 症状 | 排查 |
|---|---|
vercel logs 看不到调用 | 检查 Hashee Agent webhook URL 是否对 |
401 invalid signature | secret 错;redeploy 时 env 变了 |
| edge runtime crash | 检查 cold start log;可能依赖不兼容 edge |
| Cron timeout | 长任务必须 enqueue |