TypeScript 生态里做 Agent,过去要么自己拼 SDK,要么接受一套静态配置式的框架。2026 年 9 月,Astro 团队开源了 Flue 2.0:一个用 React 风格 Hooks 写 Agent 的 TypeScript 框架,主张把 Agent 写成函数、把能力写成 Hook,并默认带上「崩溃可恢复」的持久化。这篇教程带你从空目录跑通一个能记状态、能挂 MCP 工具、能部署上线的 Agent。
先理解:Agent Hooks 是什么思路
传统 Agent SDK 把 Agent 当成一个静态对象:一次性声明模型、工具、系统提示,运行期间不再变化。Flue 2.0 反过来,把 Agent 写成一个函数,函数体里调用 Hook 来组合能力:
export function Assistant() {
const [count, setCount] = usePersistentState('count', 0);
useAgentStart(() => setCount((n) => n + 1));
useModel('moonshot/kimi-k2');
return `You are a helpful assistant. This conversation has ${count} messages.`;
}
这个写法带来四种传统框架不好表达的模式:动态升级能力(任务变难时换更大的模型)、有状态流程(用持久状态记录多步进度)、条件工具(按运行时条件挂不同工具)、自定义 Hook(把可复用能力打包成可分享单元)。框架内置 16 个 Hook,常用的有 useModel()、useTool()、useSkill()、useSandbox()。
| Hook | 作用 |
|---|---|
useModel() | 指定本阶段使用的模型与提供方 |
useTool() | 注册一个可被模型调用的工具 |
useSkill() | 挂载一份可复用的技能说明或流程 |
useSandbox() | 给 Agent 一个能跑命令、改文件的安全环境 |
usePersistentState() | 崩溃、重启、重新部署后依然存在的状态 |
Step 1:初始化项目与安装依赖
# 新建目录并初始化
mkdir my-flue-agent && cd my-flue-agent
npm init -y
# 装运行时与 CLI
npm install @flue/runtime @flue/cli
# 确认 CLI 可用
npx flue --help
Flue 2.0 属于较新的开源项目,版本迭代较快。安装后请记录 package.json 里两个包的实际版本号,并在官方文档确认 Hook 名称与参数签名。本教程示例来自官方公开说明,若与最新文档不一致,以官方文档为准。
Step 2:写一个最小 Agent
新建 src/agents/assistant.ts。文件开头的 'use agent' 是框架指令,用来标记这个模块是一个 Agent 定义:
'use agent';
import { useModel } from '@flue/runtime';
export function Assistant() {
useModel('anthropic/claude-haiku-4-5');
return 'You are a helpful assistant. Keep replies short.';
}
函数返回的字符串就是系统提示。注意它可以直接引用外部变量,这让「提示词随状态变化」变成了很自然的事,而不是拼字符串的苦力活。
提供方/模型名 的形式,底层由 Pi 提供多模型接入(覆盖 Anthropic、OpenAI、Moonshot 等)。具体可用标识请查官方文档的模型列表,不要凭记忆写。Step 3:本地跑起来
npx flue run src/agents/assistant.ts --message "Say hello"
看到模型回复就算跑通了。这一步的价值在于:它把「框架是否装对」「模型 Key 是否可用」「Agent 定义是否合法」三件事一次性验证完,后面再出问题就不用怀疑环境。
API Key 只放环境变量。不要把 Key 写进 .ts 文件或提交到 Git。本地用 .env 并加进 .gitignore,部署时用平台的环境变量配置项注入。
Step 4:加持久状态,让流程跨重启不丢
这是 Flue 2.0 和多数轻量框架拉开差距的地方:会话被记录在持久流里,运行时重启后会自动恢复,不需要你自己写恢复逻辑。下面这个「GitHub Issue 分诊」Agent 用持久状态记住走到哪一步:
export function IssueTriageAgent({ id }) {
useSandbox(local());
const [step, setStep] = usePersistentState('step', 'reproduce');
if (step === 'reproduce') {
useModel('anthropic/sonnet-5-0');
useSkill(reproChecklist);
useTool({ name: 'submit_repro', run: () => setStep('diagnose') });
}
if (step === 'diagnose') {
useModel('anthropic/fable-5-0');
useSkill(debuggingGuide);
useTool({ name: 'submit_diagnosis', run: () => setStep('report') });
}
if (step === 'report') {
useModel('anthropic/sonnet-5-0');
useTool(postGitHubComment);
}
return `Follow the workflow to triage GitHub issue ${id}.`;
}
这段代码里有三个值得借鉴的设计:按阶段换模型(复现阶段用推理更强的模型,报告阶段换更快的)、按阶段换技能(每一步只加载当下需要的说明,控制上下文长度)、用工具推进状态(submit_repro 的副作用就是把状态推到下一步)。
Step 5:挂 MCP 工具与沙箱
Flue 支持从任意 Model Context Protocol 服务器挂载工具,也支持给 Agent 一个沙箱来执行命令、编辑文件。这意味着你在别处已经写好的 MCP Server 可以直接复用,不必为框架重写一遍。
export function OpsAssistant() {
useModel('anthropic/claude-haiku-4-5');
// 从 MCP 服务器挂载工具(具体 API 以官方文档为准)
useMcp('filesystem', { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', './data'] });
useSandbox(local()); // 给 Agent 一个可执行命令的环境
return 'You are an ops assistant. Use the filesystem tools to inspect ./data before answering.';
}
沙箱 + 文件系统工具是高风险组合。给 Agent 的命令执行能力必须限制在专用目录,生产环境建议跑在容器或独立主机里,并明确网络出口策略。不要把它指向你的代码仓库根目录或家目录。
Step 6:构建与部署
Flue 用 Vite 做构建、Hono 做路由,接进现有工程只需要加一个插件:
// vite.config.ts
import { flue } from '@flue/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [flue()],
});
部署目标覆盖 Cloudflare Workers、Node.js、Docker、AWS、Vercel、Railway;渠道侧可接 Slack、Discord、GitHub、Telegram、WhatsApp、Microsoft Teams 等 20 多个平台;存储侧支持 PostgreSQL、Redis、MongoDB、MySQL、Supabase;可观测性对接 OpenTelemetry、Braintrust、Sentry。
常见问题 FAQ
Q1:Flue 和其他 TypeScript Agent 框架怎么选?
判断标准可以简化为三条:是否需要崩溃恢复(长流程、关键任务)、是否需要运行期动态换能力(按阶段换模型或工具)、是否希望用熟悉的 React 心智模型写 Agent。三条里中两条以上,Flue 的写法会明显省事;如果只是一次性问答,用更轻的 SDK 就够了。
Q2:必须用 Astro 吗?
不需要。Flue 与 Astro 同源但独立,构建走 Vite,路由走 Hono,可以接进任意前端工程或纯 Node 服务。
Q3:Hooks 在函数体里调用,会不会有 React 那套调用顺序限制?
写法上确实借鉴了 Hooks 的组合方式,但 Agent 的执行模型与 React 渲染不同。建议保持「同一阶段内 Hook 调用顺序稳定」的习惯,避免在条件分支里随机增删 Hook,这样行为最可预测。框架的精确语义请以官方文档为准。
Q4:能接本地模型吗?
可以走 OpenAI 兼容端点或 Ollama 这类本地推理服务。目前官方及行业暂未披露更多细节,后续将持续跟进迭代动态。