在 AWS 上部署智能体
Flue 的 Node 目标是一个长期运行的 HTTP 服务器,而非函数。它在进程中持有智能体会话,并通过长连接提供流式响应,因此在 AWS 上你需要将它作为持续运行的容器服务来运行 — Flue 负责服务器,AWS 负责周围的平台。
这里的每个选项都运行来自使用 Docker 部署智能体的相同镜像。构建它,推送到 Amazon ECR 中的私有仓库,然后将下面的某个计算选项指向该镜像:
aws ecr create-repository --repository-name flue-agents
docker build -t flue-agents .
docker tag flue-agents:latest <account>.dkr.ecr.<region>.amazonaws.com/flue-agents:latest
aws ecr get-login-password --region <region> \
| docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
docker push <account>.dkr.ecr.<region>.amazonaws.com/flue-agents:latest
镜像绑定 PORT(Docker 指南设置为 8080);无论你选择什么,平台的端口和健康检查必须与之匹配。构建后的服务器只读取启动时提供的环境变量 — 它不会加载 .env — 因此 provider key(ANTHROPIC_API_KEY / OPENAI_API_KEY,可选的 MODEL_SPECIFIER)和 DATABASE_URL 来自平台的密钥存储,而不是镜像。
下面是三种计算选项,按照 AWS 为你管理的程度排序。
ECS Express Mode(推荐)
Amazon ECS Express Mode 是托管路径:一次 API 调用接受一个容器镜像和两个 IAM 角色,并在你的账户中配置完整的栈 — Fargate 上的 ECS 服务、带健康检查的应用负载均衡器、基于 CPU 的自动扩缩容、安全组和服务 URL。没有额外费用;你只需为底层资源付费。
aws ecs create-express-gateway-service \
--service-name flue-agents \
--execution-role-arn arn:aws:iam::<account>:role/ecsTaskExecutionRole \
--infrastructure-role-arn arn:aws:iam::<account>:role/ecsInfrastructureRoleForExpressServices \
--primary-container '{
"image": "<account>.dkr.ecr.<region>.amazonaws.com/flue-agents:latest",
"containerPort": 8080,
"environment": [{ "name": "MODEL_SPECIFIER", "value": "anthropic/claude-sonnet-4-6" }]
}' \
--health-check-path /health \
--scaling-target '{"minTaskCount":1,"maxTaskCount":4}' \
--monitor-resources
| 关注点 | Express Mode |
|---|---|
| 镜像 | --primary-container image 指向 ECR 仓库;execution role 拉取它。 |
| 环境变量和密钥 | 明文变量放在 environment 中。通过任务 secrets 引用注入密钥,由 execution role 从 Secrets Manager 或 SSM Parameter Store 解析 — 将 provider key 和 DATABASE_URL 保持在镜像之外。 |
| 健康检查 | --health-check-path 是 ALB 目标组的路径。Flue 不会自动生成 — 在 app.ts 中定义 /health。 |
| 扩缩容 | --scaling-target 设置 minTaskCount / maxTaskCount;扩缩容跟踪 CPU。保持 minTaskCount ≥ 1 以便始终有一个进程持有会话。 |
ALB 位于长期对话 GET 读取(长轮询/SSE)的前端。提升目标组的空闲超时,并保留准入的 streamUrl 和 offset,以便客户端可以重新连接并恢复对话流。多个任务需要共享 Postgres 来实现持久化状态,但每个智能体实例仍必须路由到一个活动任务;不要对同一实例进行轮询。参见流式协议。
EC2(最简单,完全控制)
单个实例是最直接的”你自己的机器”,也是你承担最多运维工作的方式。使用 Docker 运行镜像:
docker run -d --restart unless-stopped -p 80:8080 \
-e ANTHROPIC_API_KEY=sk-... \
-e MODEL_SPECIFIER=anthropic/claude-sonnet-4-6 \
<account>.dkr.ecr.<region>.amazonaws.com/flue-agents:latest
或者跳过容器,直接在 systemd 下运行 Node 构建 — 使用 npx vite build(vite.config.ts 中的 flue() 插件)构建到 dist/server.mjs,然后用 node dist/server.mjs 启动:
# /etc/systemd/system/flue.service
[Service]
WorkingDirectory=/opt/flue-agents
ExecStart=/usr/bin/node dist/server.mjs
Environment=PORT=8080
EnvironmentFile=/etc/flue-agents.env
Restart=always
[Install]
WantedBy=multi-user.target
| 关注点 | EC2 |
|---|---|
| 环境变量和密钥 | systemd EnvironmentFile(权限 600)或 docker run -e。在启动时从 SSM Parameter Store 获取 provider key 和 DATABASE_URL,而不是提交到实例中。 |
| 健康检查 | 没有进程为你检查。如果你在前面放了 ALB 或运行了监控器,将其指向 /health(在 app.ts 中定义路由)。 |
| 端口和 TLS | 实例的安全组必须打开监听端口。在机器上的反向代理(nginx / Caddy)或 ALB 后面终止 TLS;Node 服务器使用纯 HTTP。 |
没有第二个实例可以故障转移,也没有自动扩缩容 — 一个进程持有所有会话。长期对话流直接工作;如果前面有 ALB,提升其空闲超时。当进程重启时,内存中的状态会丢失;在扩展到一台机器之前添加共享 Postgres。
ECS on Fargate(编排)
当你需要明确控制网络和扩缩容时,自己定义任务和服务,而不是让 Express Mode 为你生成。任务定义引用 ECR 镜像并注入配置;ECS 服务在你的 VPC 中的 ALB 后面的 Fargate 上运行它。
在容器定义中,environment 携带明文变量,secrets(每个 { "name", "valueFrom" })通过任务 execution role 解析 Secrets Manager ARN 或 SSM 参数 — 这就是 provider key 和 DATABASE_URL 应该存放的地方。服务的 loadBalancers 块将容器端口映射到 ALB 目标组;因为 Fargate 使用 awsvpc 网络,目标组必须使用 IP 目标类型,其健康检查路径应该是 /health(在 app.ts 中定义)。打开任务安全组允许 ALB 访问容器端口,并设置 healthCheckGracePeriodSeconds 长于服务器启动时间,以免慢启动被中途终止。
Application Auto Scaling 调整期望的任务数量;为流式对话提升 ALB 空闲超时,使用共享 Postgres 实现持久化状态,并将每个智能体实例路由到一个活动任务。这与 Express Mode 自动构建的 Fargate-plus-ALB 栈相同 — 当你需要自己掌控各部分时使用它。
持久化
没有 db.ts 适配器时,Flue 将规范对话、附件和已接受的提交保存在进程本地内存中 — 在重启或重新部署时丢失,且对替换任务不可用。为了实现持久化状态,使用 Amazon RDS for PostgreSQL 从服务的 VPC 可达。共享存储支持替换恢复;它不会启用单个智能体实例的多活所有权。
添加适配器和一个包装你配置的 pg 连接池并读取 DATABASE_URL 的 db.ts — 参见 Postgres 了解完整的自带驱动运行器:
import { postgres } from '@flue/postgres';
import { Pool } from 'pg';
// 使用 DATABASE_URL 连接字符串创建连接池
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export default postgres({
query: async (text, params) => (await pool.query(text, params)).rows,
transaction: async (fn) => {
/* 每个事务一个检出的客户端;参见 Postgres 指南 */
},
close: () => pool.end(),
});将 RDS 连接字符串存储在 Secrets Manager 中,并作为 DATABASE_URL 注入 — 在 Express Mode 和 Fargate 上作为任务 secrets 引用,在 EC2 上从 SSM 获取。Flue 在构建时发现 db.ts 并将其连接到生成的服务器中;适配器处理模式创建、规范对话流、不可变附件和持久化提交状态。
不支持 AWS Lambda
Flue 不以 Lambda 为目标。Node 服务器是长期运行且有状态的 — 它持有智能体会话和进程内协调器,并通过长期对话 GET 连接提供流式响应。Lambda 的无状态、短期调用模型不适合这些:没有持久化进程在调用之间持有会话,执行窗口也不适合开放流。在那里运行 Flue 需要一个将所有协调外部化的适配器,这超出了范围 — 与 Vercel 和 Netlify 等函数平台被排除在外的原因相同。使用上面的某个容器服务。
参考资料
- Amazon ECS Express Mode 概述和
create-express-gateway-serviceCLI 参考 — 推荐路径及其确切参数。 - 从 App Runner 迁移到 ECS Express Mode — AWS 在 App Runner 对新客户关闭后(2026-04-30)的官方指南。
- 在 Amazon ECS 服务上使用负载均衡 — Fargate
awsvpc→ IP 目标组、loadBalancers和健康检查宽限期。 - 推送镜像到 Amazon ECR和 Amazon RDS for PostgreSQL — 镜像仓库和用于
DATABASE_URL的托管 Postgres。