无状态 AI 应用背后的架构
Source: Dev.to
项目一开始就做了一个看似冒险的决定:没有后端数据库。
当时并不需要持久化用户数据——获取用户的响应是首要任务。大多数教程假设你会把账户、会话和数据存储在 PostgreSQL、MongoDB、DynamoDB 等数据库中,但这个应用根本不需要在设备之间持久化任何内容。
三层拆分

- 前端 – 负责所有用户交互、UI 状态、图像压缩、多步骤向导流程、本地历史记录以及结果渲染。
- 后端 – 唯一职责:将图像数据转化为诊断数据。它接收请求、构建提示词、调用 LLM、解析响应并返回结构化 JSON。没有状态、会话或数据库。
- AI 层 – Claude Vision 接收带有精心构造的提示词的图像,并返回详细的诊断信息。
每一层只做一件事。混合职责(例如在后端存储历史记录或直接在前端调用 LLM)会增加不必要的复杂度。
数据交互

- 历史记录和设置永远不会离开用户的设备。
- API 密钥会通过服务器传递,但永不存储。
多步骤向导:为何使用状态机
扫描流程可能包含五个潜在步骤:
- 植物部位选择
- 作物类型选择
- 媒体上传
- 分析模式(单图 vs. 多图)
- 上下文输入
传统的编号步骤会变得模糊,因为第 4 步的出现取决于运行时条件(单图还是多图)。
解决方案: 使用带有有意义状态名称的状态机(part、crop、media、mode、context、analyzing)。UI 根据当前状态渲染,进度指示器动态计算,保持用户体验的准确性,而无需硬编码步骤编号。

存储架构:三层

| 层级 | 目的 | 常见内容 |
|---|---|---|
| 会话存储 | 保存浏览器关闭时失效的同意标志。 | 与健康相关数据的同意选择。 |
| 本地存储 | 跨会话持久化数据。 | 扫描历史、可访问性设置(字体大小、语音偏好)、API 密钥。 |
| 嵌入式深度缓存 | 为每个历史条目存储完整诊断(全部 25+ 字段)。 | 治疗方案、预防建议、完整结果负载。 |
深度缓存会增加存储体积,但实现了真正的离线访问——这对农村用户至关重要。一次典型扫描约 20–30 KB;最多约 50 次扫描总计约 1.5 MB,远低于浏览器 5 MB 的配额。旧的扫描会自动轮换出去。
单一端点哲学
后端仅暴露一个 API 端点:
POST /api/v1/analyze

所有分析模式(单图、批量、视频)都通过 mode 参数来处理,该参数会调整提示词构造和响应处理。这避免了:
- 重复的验证逻辑
- 复杂的客户端路由
- 多端点的版本管理烦恼
- 额外的文档维护负担
单一、文档完善的端点更易于测试和维护。
用户提供的 API 密钥

- 费用透明:用户清楚自己在付费,没有隐藏加价。
- 无需密钥管理:不需要数据库来存储或轮换密钥,降低运维复杂度。
- 可扩展性:每位用户拥有自己的 Anthropic 配额,消除共享速率限制。
- 信任:用户自行掌控凭证,开发者无法产生意外费用。
权衡在于摩擦——用户必须先创建 Anthropic 账户并生成 API 密钥才能使用应用。这对技术受众来说可以接受,但若面向大众市场则需要重新考虑。
批量 vs. 单图模式:同一植物问题
当上传多张图像时,系统必须判断它们是 不同植物(分别分析)还是 同一植物的不同角度(一起分析)。
(关于此决策逻辑实现的更多细节请参见原文。)