1. 为什么需要单独选择后端框架
上一篇文章确定了边缘部署的方向,并选择 CloudFlare Workers 作为基础设施。接下来还要解决一个具体问题:使用什么框架组织 API、中间件和服务调用。
我们曾经在两个候选框架之间做过比较,一个是 Python 生态的 FastAPI,另一个是 TypeScript 生态的 Hono.js。它们都很轻量,也都重视性能和开发体验,但在运行时、部署方式和生态定位上有明显差异。
当部署平台确定为 CloudFlare Workers 后,框架选择的范围其实已经很小。不过,仍然有必要把判断过程说明清楚:FastAPI 的优势是否足以让我们放弃边缘部署,以及 Hono.js 为什么更符合当前项目的约束。
2. 两个框架的定位
我们先通过最简单的接口看看两者的代码风格。
FastAPI:Python 生态的 API 框架
01from fastapi import FastAPI02from pydantic import BaseModel0304app = FastAPI()0506class Message(BaseModel):07content: str08user_id: str0910@app.post("/chat")11async def chat(msg: Message):12# 调用 LLM、检索记忆、组装回复...13return {"reply": f"收到: {msg.content}"}
Hono.js:TypeScript 生态的轻量级 Web 框架
01import { Hono } from 'hono'0203const app = new Hono()0405app.post('/chat', async (c) => {06const { content, user_id } = await c.req.json()07// 调用 LLM、检索记忆、组装回复...08return c.json({ reply: `收到: ${content}` })09})1011export default app
单看接口定义,两者都足够简洁。真正影响选型的不是语法差异,而是它们依赖的运行时、能够使用的部署平台,以及各自擅长的应用场景。
| 维度 | FastAPI | Hono.js |
|---|---|---|
| 语言 | Python | TypeScript / JavaScript |
| 运行时 | CPython / uvicorn | 任意 JS 运行时(Node、Deno、Bun、Workers) |
| 定位 | 全功能 API 框架 | 超轻量 Web 框架 |
| 包体积 | ~30MB(含依赖) | ~14KB(无依赖) |
| 首个 stable 版本 | 2018 年 | 2022 年 |
3. 从五个维度进行比较
3.1 边缘运行时兼容性
运行时兼容性是这次选型中最先考虑的条件,因为它会直接限制部署平台。
FastAPI 需要完整的 Python 运行时。除了 CPython 解释器,它通常还会依赖 uvicorn ASGI 服务器,以及 pydantic v2 的 Rust 编译后端等扩展。这套运行方式适合 AWS EC2、Docker 和 Lambda 等传统服务器或容器环境,却无法直接迁移到 CloudFlare Workers。
Workers 已经通过 Pyodide,也就是编译为 WASM 的 CPython,提供了实验性的 Python 支持,但目前仍处于早期阶段。FastAPI 依赖的 ASGI 服务器和 C 扩展生态,包括 uvicorn、pydantic v2 的 Rust 后端等,仍然无法完整运行。因此,在当前条件下,FastAPI 不能直接部署到边缘运行时。
Hono.js 在设计时就考虑了不同 JavaScript 运行时之间的兼容性:
01// CloudFlare Workers02export default app0304// Node.js05import { serve } from '@hono/node-server'06serve(app)0708// Deno09Deno.serve(app.fetch)1011// Bun12export default app
同一套应用代码不需要修改业务逻辑,就可以运行在 CloudFlare Workers、Node.js、Deno 和 Bun 上。它带来的不只是迁移方便,更重要的是保留了部署方式的选择空间。
结合上一篇文章的结论,如果选择 FastAPI,就要同时放弃 CloudFlare Workers 提供的边缘部署能力。而实时对话需要尽可能缩短网络延迟,因此这个限制会直接影响 AI 伴侣的响应体验。
3.2 冷启动与运行时开销
即使暂时不考虑全球边缘部署,只比较 AWS Lambda、Vercel Functions 等 Serverless 场景,两套运行时的冷启动开销也有明显差异。
| 指标 | FastAPI(Lambda) | Hono.js(Workers) |
|---|---|---|
| 冷启动时间 | 300-3000ms | < 5ms |
| 运行时开销 | ~50MB 内存起步 | < 1MB |
| 并发模型 | 单进程异步(GIL 限制 CPU 密集任务) | V8 Isolate(轻量隔离) |
这里的冷启动差距主要来自 Lambda 和 Workers 的运行时平台,不能完全归因于框架本身。不过,框架与运行时并不是彼此独立的选择:FastAPI 对应 Python 运行时,而 Hono.js 可以直接使用 Workers 的 V8 Isolate。
FastAPI 冷启动时需要加载 Python 解释器、依赖包以及所有被导入的模块。如果 Lambda 函数还依赖 numpy、pydantic v2 的 Rust 编译模块等库,冷启动时间很容易超过 2 秒。
Hono.js 在 Workers 上没有这部分开销。V8 Isolate 的启动成本很低,框架本身约为 14KB,也没有额外依赖需要逐项加载,因此冷启动通常可以忽略。
这个差异会直接出现在对话过程中。用户沉默几分钟后,Lambda 实例可能已经被回收;下一次发送消息时,首字节时间需要同时包含冷启动、请求处理和 LLM 推理。仅冷启动就占用 2 秒,会明显拖慢这次回复。
3.3 前后端技术栈统一
AI 伴侣的前端使用 React、Next.js 和 TypeScript。如果服务端继续使用 TypeScript,前后端可以共享类型定义,也能沿用同一套工具链。
最直接的收益是共享接口类型。请求和响应不需要分别维护,也不必先生成 OpenAPI schema,再根据 schema 生成客户端代码。
01// 这个类型定义,前端和后端直接 import 同一份文件02export interface ChatRequest {03content: string04user_id: string05session_id: string06}0708export interface ChatResponse {09reply: string10emotion: string11memories_used: number12}
项目的工具链也可以保持一致,包括 ESLint、Prettier / Biome、tsconfig 和包管理器 yarn。团队不需要同时维护 Python 与 TypeScript 两套开发、检查和构建配置。
对于以 API 编排为主的服务端,统一语言还能减少上下文切换。AI 伴侣后端的大部分工作是调用 LLM、查询数据库和组装 Prompt,并不依赖 Python 在数据科学领域的能力,前端开发者也不必为了这些工作额外切换语言。
Hono.js 还提供 RPC 客户端,可以根据服务端路由自动推断请求参数和响应类型。
01// 后端:定义路由02const route = app.post('/chat',03zValidator('json', chatSchema),04async (c) => {05const body = c.req.valid('json')06return c.json({ reply: '...', emotion: 'happy' })07}08)0910export type AppType = typeof route
1// 前端:自动推断请求和响应类型,无需任何手动定义2import { hc } from 'hono/client'3import type { AppType } from '../server'45const client = hc<AppType>('/api')67// res 的类型自动推断为 { reply: string, emotion: string }8const res = await client.chat.$post({ json: { content: '你好' } })
这样一来,前端调用接口时能够获得与本地函数相近的类型检查体验。请求参数写错后,TypeScript 编译器会直接报错,不需要再手动维护一组完全对应的 interface。
FastAPI 本身同样具有完善的类型和校验能力,但 Python 类型无法直接与 TypeScript 互通。项目需要额外维护 Python 运行时、pip 或 poetry 依赖、类型生成流程,以及一套独立的部署流水线。
3.4 CloudFlare 生态集成
确定使用 CloudFlare Workers 后,框架能否直接使用平台提供的服务,会影响后续接口实现的复杂度。
Hono.js 原生支持 Workers Bindings:
01import { Hono } from 'hono'0203type Bindings = {04KV: KVNamespace // 键值存储05DB: D1Database // SQL 数据库06VECTORIZE: VectorizeIndex // 向量数据库07AI: Ai // Workers AI 推理08}0910const app = new Hono<{ Bindings: Bindings }>()1112app.post('/chat', async (c) => {13// 直接通过 c.env 访问所有 CloudFlare 服务,完整的类型提示14const emotion = await c.env.KV.get(`emotion:${userId}`, 'json')15const memories = await c.env.DB.prepare('SELECT ...').all()16const embedding = await c.env.AI.run('@cf/baai/bge-base-en-v1.5', { text: query })17const similar = await c.env.VECTORIZE.query(embedding.data[0], { topK: 5 })1819return c.json({ /* ... */ })20})
前面几篇文章使用的 KV、D1、Vectorize 和 Workers AI,都可以通过 c.env 直接访问,并且保留完整的 TypeScript 类型提示。
FastAPI 无法直接使用这些 Bindings。如果仍然希望从外部 Python 服务访问 CloudFlare 的相关能力,就需要改为调用 REST API,这会增加网络请求和集成代码。
3.5 中间件与 API 编排
AI 伴侣后端不以复杂的业务逻辑为主,但请求处理过程仍然需要精细编排。一条消息通常要依次经过安全检查、身份验证、记忆检索、Prompt 组装、LLM 调用、记忆写回和响应返回。
Hono.js 的中间件模型可以把这些步骤拆成清晰的处理层:
01import { Hono } from 'hono'02import { cors } from 'hono/cors'03import { logger } from 'hono/logger'04import { timing } from 'hono/timing'0506const app = new Hono()0708// 内置中间件09app.use('*', cors())10app.use('*', logger())11app.use('*', timing())1213// 自定义中间件:安全检查14app.use('/chat/*', async (c, next) => {15const content = await c.req.text()16if (containsUnsafeContent(content)) {17return c.json({ error: '内容不合规' }, 403)18}19await next()20})2122// 自定义中间件:身份验证23app.use('/chat/*', async (c, next) => {24const token = c.req.header('Authorization')25const user = await verifyToken(token)26c.set('user', user)27await next()28})2930// 路由处理31app.post('/chat/message', async (c) => {32const user = c.get('user')33// 已经通过了安全检查和身份验证34// ...35})
FastAPI 同样提供中间件和依赖注入,而且它的依赖注入系统在复杂场景中更强。对于当前这种以顺序编排为主的接口,Hono.js 的洋葱模型已经可以清楚地组织处理过程,代码也更容易沿着请求路径阅读。
4. FastAPI 更适合哪些场景
这次选择 Hono.js,并不意味着 FastAPI 的能力不足。下面这些场景中,FastAPI 仍然可能是更合适的框架。
数据科学与机器学习。 如果服务端需要使用 pandas、numpy 处理数据,或者通过 PyTorch、transformers 完成模型训练与推理,Python 生态仍然很难替代。当前 AI 伴侣的服务端只负责编排,不直接执行这些任务。
自动生成 API 文档。 FastAPI 可以基于 OpenAPI 规范自动生成 Swagger UI 和 ReDoc 交互式文档。API 需要提供给第三方开发者时,这项能力很有价值。Hono.js 也可以通过 zod-openapi 支持 OpenAPI,但成熟度不如 FastAPI。
复杂的依赖注入。 FastAPI 的 Depends() 可以构建依赖树,并自动完成解析和注入。大型单体应用需要组织复杂依赖关系时,这套机制会更有优势。
以 Python 为主的团队。 如果团队成员都熟悉 Python,强行改用 TypeScript 开发后端反而会增加沟通和维护成本。框架选择还要结合团队已有的工程能力,不能只比较框架功能。
5. 总结
把 AI 伴侣当前的需求放在一起,可以得到下面这张选型表:
| 需求 | FastAPI 能否满足 | Hono.js 能否满足 |
|---|---|---|
| 部署在 CloudFlare Workers | 不能 | 原生支持 |
| 冷启动 < 10ms | 不能 | < 5ms |
| 前后端 TypeScript 类型共享 | 不能 | 天然支持 |
| 直接访问 KV / D1 / Vectorize | 需要外部 API 调用 | 通过 Bindings 原生访问 |
| 流式 SSE 响应(LLM 输出) | 支持(需配置) | 原生支持 |
| 轻量级 API 编排 | 支持(偏重) | 完美匹配 |
| 数据科学 / ML 推理 | 强项 | 不适用 |
| 自动 API 文档 | 内置(强) | 社区方案(中) |
FastAPI 是一个成熟且能力完整的 API 框架,只是它不符合这个项目已经确定的部署条件。当前后端不负责模型推理和数据处理,因此用不到 Python 生态最有优势的部分。项目真正需要的是边缘运行能力、较低的冷启动开销、CloudFlare 服务的直接集成,以及与前端共享 TypeScript 类型。
按照这些硬性条件逐项判断,Hono.js 是两个候选中唯一能够全部满足要求的框架。这个结论来自部署平台和业务需求,而不是对框架本身做简单的优劣排序。
后续文章会基于 Hono.js 和 CloudFlare Workers 搭建服务端,从路由设计、中间件编排到与 LLM 的流式通信,逐步实现完整的对话处理管线。