09.1 没加鉴权,被人刷了
去年一个项目,Agent 直接暴露在公网,没加鉴权。一周被刷掉 200 刀 API 费。
Agent 写好了,不能谁都能调。这章讲怎么把它接进你的服务,并守好门。
09.2 app.ts:你的 Hono 应用
src/app.ts 是可选的入口。它本质是个 Hono 应用。你把自己的路由、中间件和 Flue 拼一起。
// src/app.ts
import { flue } from '@flue/runtime/routing';
import { Hono, type MiddlewareHandler } from 'hono';
import { authenticate } from './auth.ts';
// 这行是关键:先验证用户
const requireUser: MiddlewareHandler = async (c, next) => {
const user = await authenticate(c.req.raw);
if (!user) return c.json({ error: 'Unauthorized' }, 401);
await next();
};
const app = new Hono();
app.get('/health', (c) => c.json({ ok: true }));
app.use('/agents/*', requireUser); // 给 Agent 路由加锁
app.use('/workflows/*', requireUser);
app.route('/', flue()); // 挂载 Flue
export default app;
09.3 暴露哪种传输,你自己定
每个 Agent 文件用导出决定"怎么被访问":
| 导出 | 暴露方式 |
|---|---|
route |
POST /agents/名/:id 的 HTTP |
websocket |
GET /agents/名/:id 的 WebSocket |
| 都不导 | 只通过 dispatch() 内部调用 |
只接 webhook、不对外暴露的 Agent,两个都不用导。安全。
09.4 异步事件用 dispatch
聊天平台、队列消息,用 dispatch 异步喂给 Agent:
app.post('/webhooks/support-comments', async (c) => {
const event = await verifySupportWebhook(c.req.raw);
// 这行是关键:异步投递,不等回复
const receipt = await dispatch(supportAssistant, {
id: event.ticketId,
session: 'customer-follow-up',
input: { type: 'support.comment.created', text: event.text },
});
return c.json(receipt, 202);
});
注意:provider 注册只在
app.ts有效。这是 §07 提过的坑,在路由里再强调一次:
registerProvider放 Agent 文件里会被丢弃。所有顶层副作用,都进app.ts。标叔的经验:鉴权别只挂在 Agent 上。
我吃过亏,只在 Agent 的
route里校验,结果工作流路由漏了。现在统一在app.ts用中间件锁/agents/*和/workflows/*,一处管全站,省心。
门守住了。下一章,让 Agent 的运行"看得见"。