mock 永远在线;其余每个真实
provider 只有在对应 API key 出现时才会注册,最后由 AI_PROVIDER 决定激活哪一个。这
样你可以离线开发、按环境切换,也不会上线时漏了配置。
前置条件
- 项目能跑(
pnpm dev起得来)。 - 至少一个真实 API key —— 如果只挑一个,OpenRouter 最省事 (openrouter.ai)。
- 先看一遍
src/ai/index.ts,80 行讲清楚整个故事。
六个 provider
| 名称 | 源文件 | 支持操作 | 说明 |
|---|---|---|---|
mock | providers/mock.ts | chat, chatStream, image | 默认。返回固定文本 + picsum 图片 URL。 |
openrouter | providers/openai-compat.ts | chat, chatStream | OpenAI 兼容形式,路由上百模型。 |
openai | providers/openai-compat.ts | chat, chatStream | 直连 OpenAI 端点。 |
anthropic | providers/anthropic.ts | chat, chatStream | 自有 Messages API + SSE 事件类型。 |
replicate | providers/replicate.ts | image | 轮询式预测 API。 |
fal | providers/fal.ts | image | 同步队列,FLUX schnell 大约 1 秒。 |
anthropic 调 image())会抛 AIUnsupportedError,
manager 会捕获并尝试 opts.fallback(如果传了的话)。
步骤:切换到真实 provider
-
选一个 provider,把 key 写进
.env.local: -
重启 dev server。条件注册在 import 时执行:
-
在 server action 或 route handler 里发起调用:
result类型是ChatResult | InsufficientCredits。读.text之前一定要先用isInsufficientCredits(result)收窄。
给价目表加新模型
src/ai/pricing.ts 是成本的唯一真相源。key 是 provider:model,数值是每 1k tokens
的 micro-cents(百分之一美分 —— $0.0001 = 100 micro-cents)。改完保存即生效:
getTokenPrice 会回退到 mock:any(很便宜),调用照样能跑但成本统计就
偏低了。在 可观测性 里搜「忘记价目表」可以看修复方法。
你需要捕获的错误
opts.fallback 是降级开关。AIProviderError 或 AIUnsupportedError 时 manager 会
用它再试一次 —— InsufficientCredits 不会触发降级(积分已经退过了)。开发环境用
mock 当 fallback,demo 永远不会挂。
验证生效
- 设
AI_PROVIDER=mock(默认)。打开/playground/chat,应该看到「(mock provider …)」 那段固定回复。 - 设上真实 key 和
AI_PROVIDER=<name>,重启。同样的 demo 现在应该流式回真实内容。 - 看 dev server 日志。
ai_call插入行里provider=<name>就是当前生效的选择。 psql进开发库跑SELECT provider, model, status FROM ai_call ORDER BY created_at DESC LIMIT 5;
常见坑
AI_PROVIDER配了但 key 没配。 Manager 会静默降级到mock。在getProvider里打印Object.keys(PROVIDERS),发现你的 provider 不在里面。- OpenRouter 的 model id 格式。 必须是
vendor/model(比如openai/gpt-4o-mini), 不是只写gpt-4o-mini。和直连 OpenAI 那条不一样。 - Anthropic 的 system 消息。 它在顶层,不在
messages里。Provider 会自动拆, 但你手搓请求时记住这一点。 - Replicate 要锁版本。
model字段是 version hash,不是友好名。用black-forest-labs/flux-schnell之前去 Replicate 查当前版本号。 - Anthropic 上的
AIUnsupportedError: image。 Anthropic 没有图像能力。设fallback: 'replicate'或'fal',或者在上层根据operation走分支。
官方文档
- OpenRouter:openrouter.ai/docs
- OpenAI:platform.openai.com/docs
- Anthropic:docs.anthropic.com
- Replicate:replicate.com/docs
- fal.ai:fal.ai/docs
- 源码:
src/ai/index.ts、src/ai/manager.ts、src/ai/types.ts