Skip to content

ADR-006: AI Service 接口抽象设计

Status

Accepted

Date

2026-03-25

Context

前端需要调用后端 AI 能力(文本生成、图片生成、视频生成)和资源查询(模型列表)。需要决定如何组织 HTTP 调用代码,使其:

  1. 可测试 — 单元测试能隔离网络层
  2. 职责清晰 — 业务组件不直接操作 HTTP
  3. 可替换 — 未来如需切换 API 提供者,改动范围最小

Options Considered

方案 A:组件内直接调用 $fetch

  • 优点:简单直接
  • 缺点:HTTP 细节散布在组件中;无法统一错误处理;测试需要 mock 全局 $fetch

方案 B:两层抽象 — ApiClient + AiService 接口

  • 优点:ApiClient 统一处理 headers、错误转换;AiService 定义业务接口,实现可替换;测试只需 mock ApiClient
  • 缺点:多一层间接

方案 C:Nuxt useFetch / useAsyncData

  • 优点:Nuxt 原生、支持 SSR
  • 缺点:与 Nuxt 生命周期耦合;节点生成是用户触发的命令式操作,不适合声明式数据获取

Decision

选择 方案 B:两层抽象

组件 → AiService (业务接口) → ApiClient (HTTP 封装) → 后端 API
  • ApiClientservices/http/client.ts):封装 $fetch,统一 headers(App-IdPlatform)、响应解包(ApiResponse<T>T)、业务错误转换(ApiError
  • AiServiceservices/ai/types.ts):定义 generateTextgenerateImagegenerateVideo 三个方法签名
  • createRealAiServiceservices/ai/real.ts):工厂函数,接收 ApiClient,返回 AiService 实现
  • useApiClientservices/http/index.ts):Nuxt composable,从运行时配置读取 apiBase 创建单例

Consequences

正面影响:

  • 业务组件只依赖 AiService 接口,不感知 HTTP 细节
  • 单元测试 mock ApiClient 即可,无需 mock 全局 $fetch
  • 新增 AI 能力只需在 AiService 接口添加方法,real.ts 添加实现

负面影响 / 已知风险:

  • ApiClientApp-IdPlatform 硬编码在 client.ts 中,如需动态配置需要修改工厂函数

替代此决策的条件

若引入 GraphQL 或 WebSocket 实时推送(如流式生成),需要重新评估 ApiClient 的 HTTP-only 假设。