将 AI 功能集成到现有产品中
将 AI 集成到已有用户的产品中的实战手册——从选择合适的模型到生产环境部署模式。

给一个已经有用户的产品添加 AI 与从零开始构建一个 AI 优先的创业项目有着本质的不同。你有现有的基础设施、已建立的用户体验模式、真实的用户期望,以及——最重要的——可能会崩溃的东西。这篇文章涵盖了我在多个生产应用中交付 AI 功能后发现的可靠模式。
选择模型提供商
模型提供商的决策不是永久性的,也不应该被当作永久性决策来对待。每个提供商在生产中都有独特的优势。
OpenAI(GPT-4o、GPT-4.1) 仍然是通用文本生成最经实战检验的选择。API 稳定,文档详尽,围绕它的工具生态成熟。如果你需要函数调用、结构化 JSON 输出或广泛的多语言支持,OpenAI 是安全的默认选择。
Anthropic(Claude) 在细致的指令遵循和长上下文任务上表现出色。当你的功能涉及处理大型文档、维护复杂的系统提示词或处理模型需要说"我不知道"而非编造答案的任务时,Claude 往往表现更好。Claude 模型的思维/推理能力在多步分析任务中也很强。
Google Gemini 在你的功能涉及多模态输入时值得考虑——特别是当你需要在同一请求中同时处理图像、视频或音频和文本时。Gemini 的原生多模态架构避免了文本优先模型中视觉功能的拼凑感。高吞吐量用例的定价也很有竞争力。
实际答案是:从你的团队最熟悉的提供商开始,但要让你的系统架构支持切换。提供商锁定才是真正的风险,而不是在第一天选了"错误的"模型。
API 封装模式
每个 AI 集成都应该放在一个抽象层后面。不是因为你一定会切换提供商,而是因为你一定需要添加日志、缓存、速率限制和回退逻辑——你不想在 40 个不同的地方做这些。
interface AIProvider {
generateText(prompt: string, options?: GenerateOptions): Promise<AIResponse>;
generateStream(prompt: string, options?: GenerateOptions): AsyncGenerator<string>;
generateStructured<T>(prompt: string, schema: z.ZodSchema<T>, options?: GenerateOptions): Promise<T>;
}
interface GenerateOptions {
model?: string;
temperature?: number;
maxTokens?: number;
systemPrompt?: string;
}
interface AIResponse {
content: string;
usage: { promptTokens: number; completionTokens: number };
model: string;
latencyMs: number;
}
给定提供商的具体实现保持精简:
class AnthropicProvider implements AIProvider {
private client: Anthropic;
constructor(apiKey: string) {
this.client = new Anthropic({ apiKey });
}
async generateText(prompt: string, options?: GenerateOptions): Promise<AIResponse> {
const start = Date.now();
const response = await this.client.messages.create({
model: options?.model ?? "claude-sonnet-4-20250514",
max_tokens: options?.maxTokens ?? 1024,
temperature: options?.temperature ?? 0.7,
system: options?.systemPrompt,
messages: [{ role: "user", content: prompt }],
});
const textBlock = response.content.find((b) => b.type === "text");
return {
content: textBlock?.text ?? "",
usage: {
promptTokens: response.usage.input_tokens,
completionTokens: response.usage.output_tokens,
},
model: response.model,
latencyMs: Date.now() - start,
};
}
// ... generateStream, generateStructured
}
然后一个服务层处理横切关注点:
class AIService {
constructor(
private provider: AIProvider,
private cache: CacheStore,
private logger: Logger,
private fallbackProvider?: AIProvider
) {}
async generate(prompt: string, options?: GenerateOptions): Promise<AIResponse> {
const cacheKey = this.buildCacheKey(prompt, options);
const cached = await this.cache.get<AIResponse>(cacheKey);
if (cached) return cached;
try {
const response = await this.provider.generateText(prompt, options);
this.logger.info("ai_generation", {
model: response.model,
tokens: response.usage,
latencyMs: response.latencyMs,
});
await this.cache.set(cacheKey, response, { ttl: 3600 });
return response;
} catch (error) {
if (this.fallbackProvider) {
this.logger.warn("ai_fallback_triggered", { error: String(error) });
return this.fallbackProvider.generateText(prompt, options);
}
throw error;
}
}
}
这个模式在第一周内就能回本。当 OpenAI 出现故障时(这是会发生的),你切换到回退提供商。当你需要调试生产环境中的提示词问题时,日志已经在那里了。
生产环境中的提示词工程
生产环境中的提示词不是源代码中的字符串。它们是一个需要版本控制、测试和可观测性的独立关注点。
我使用的模板系统很简单:
interface PromptTemplate {
id: string;
version: number;
system: string;
user: string;
variables: string[];
}
const LISTING_DESCRIPTION: PromptTemplate = {
id: "listing-description",
version: 3,
system: `You are a professional copywriter for a restaurant platform.
Write compelling menu item descriptions.
Rules:
- Max 2 sentences
- Mention key ingredients
- Never use the word "delicious" or "mouth-watering"
- Match the restaurant's tone: {{tone}}`,
user: `Write a description for: {{itemName}}
Category: {{category}}
Ingredients: {{ingredients}}`,
variables: ["tone", "itemName", "category", "ingredients"],
};
function renderPrompt(
template: PromptTemplate,
vars: Record<string, string>
): { system: string; user: string } {
let system = template.system;
let user = template.user;
for (const key of template.variables) {
const value = vars[key];
if (!value) throw new Error(`Missing variable: ${key}`);
system = system.replaceAll(`{{${key}}}`, value);
user = user.replaceAll(`{{${key}}}`, value);
}
return { system, user };
}
版本号很重要。当你更改提示词时,增加版本号并将其与每个请求一起记录。当用户报告 AI 输出发生变化时,你可以追溯到确切的提示词版本。将提示词模板存储在数据库或配置文件中——而不是硬编码——这样你可以在不重新部署的情况下更新它们。
像测试代码一样测试你的提示词。 维护一组输入/输出的测试固件。当你更改提示词时,通过固件运行并人工审查差异。自动化评估在变好,但对提示词变更的人工审查仍然能捕获指标遗漏的问题。
流式响应改善用户体验
用户会容忍等待 3 秒获得完整响应。他们不会容忍盯着转圈 15 秒。流式传输解决了这个问题。
async function* streamAIResponse(
provider: AIProvider,
prompt: string,
options?: GenerateOptions
): AsyncGenerator<string> {
const stream = provider.generateStream(prompt, options);
for await (const chunk of stream) {
yield chunk;
}
}
// In your API route (Next.js example)
export async function POST(request: Request) {
const { prompt, options } = await request.json();
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
try {
for await (const chunk of streamAIResponse(aiProvider, prompt, options)) {
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ text: chunk })}\n\n`));
}
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
controller.close();
} catch (error) {
controller.enqueue(
encoder.encode(`data: ${JSON.stringify({ error: "Generation failed" })}\n\n`)
);
controller.close();
}
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
}
在客户端消费流并渐进式更新 UI。感知性能差异是巨大的——用户在 200-400ms 内就看到内容出现,而不是等待完整生成。
一个重要的实现细节:在客户端缓冲不完整的单词。 一些提供商发送的 token 会在单词中间断开。累积一个小缓冲区,只渲染完整的单词以避免视觉抖动。
成本控制和缓存策略
AI API 成本可能出乎你的意料。一个在预发布环境中每天花费 $2 的功能,如果你没有考虑缓存,在生产环境中可能每天花费 $2,000。
语义缓存是最高杠杆的优化。如果两个用户提出了功能上相同的问题,返回缓存的响应。你不需要向量数据库来做这个——从标准化输入的精确匹配缓存开始。哈希提示词(注入变量后)并将响应存储在带有 TTL 的缓存中。
分层模型路由在不降低质量的情况下节省成本。不是每个请求都需要你最贵的模型。将简单的分类任务路由到较小的模型,将大模型留给复杂生成:
function selectModel(task: AITask): string {
switch (task.complexity) {
case "classification":
case "extraction":
return "gpt-4o-mini"; // fast, cheap
case "generation":
return "claude-sonnet-4-20250514"; // balanced
case "reasoning":
return "claude-opus-4-20250514"; // maximum quality
}
}
设置硬性预算限制。 大多数提供商在 API 密钥级别支持用量限制。使用它们。同时在应用层面为每个用户实现速率限制——一个滥用的用户不应该在一个下午就烧完你的月度预算。
按功能追踪成本,而不仅仅是总支出。 给每个 API 调用标记触发它的功能。当账单到达时,你需要知道"自动生成 SEO 描述"功能占了你支出的 60%,而不仅仅是你总共花了 $X。
优雅降级
AI 功能会出故障。提供商宕机会发生。速率限制会被触达。网络请求会超时。你的产品需要继续工作。
原则:AI 功能应该增强体验,而不是阻断体验。 如果 AI 搜索不可用,回退到关键词搜索。如果 AI 内容生成失败,给用户显示手动输入表单。永远不要把 AI 放在没有绕过方式的关键路径上。
实际实现:
- 超时。 对 AI 调用设置激进的超时(最多 10-15 秒)。对大多数用户体验流程来说,慢响应比没有响应更糟。
- 断路器。 连续 N 次失败后,在冷却期内停止调用提供商。这防止了级联失败并避免在注定会失败的请求上浪费钱。
- 预生成的回退。 对于产品描述或推荐等功能,维护一组不需要 AI 的基于模板的回退方案。它们不会那么好,但至少有东西。
- UI 沟通。 告诉用户发生了什么。"AI 建议暂时不可用"远比通用错误或无限转圈好。
真实案例
AI 内容生成是最常见的集成点。对于一个营销平台,这意味着构建一个管道,接收产品简介,生成广告文案变体,根据品牌指南评分(使用第二次 AI 调用),并将排名靠前的候选方案呈现给人工审核者。关键洞察:AI 生成,人类策展。让用户编辑和优化 AI 输出的功能与生成本身同样重要。
室内设计的计算机视觉需要不同的架构。处理房间照片进行风格分析和家具检测涉及将图片发送到视觉模型、解析结构化输出、并将结果与产品目录匹配。延迟更高,所以用户体验模式转向异步处理加推送通知,而非同步等待显示。
智能搜索用语义理解替代传统的关键词匹配。对于一个餐饮平台,这意味着用嵌入向量索引菜单项,这样搜索"辛辣的素食"可以返回相关结果,即使这些确切的词不出现在任何菜单中。嵌入生成在写入时发生(当菜单更新时),而不是在查询时——这让搜索保持快速,不受 AI 提供商延迟的影响。
在每种情况下,同样的原则适用:封装提供商、版本化提示词、积极缓存,并且始终有回退方案。
负责任地交付 AI 功能
AI 演示和生产级 AI 功能之间的差距是巨大的。演示不需要缓存、错误处理、成本控制或优雅降级。生产环境需要。这篇文章中的模式不是理论性的——它们来自交付真实用户每天依赖的 AI 功能。
从 AI 驱动的房间重新设计到自动化内容工作室,我在移动 App、SaaS 平台和后端系统中交付过 AI 功能。技术确实强大,但围绕它的工程纪律决定了用户是喜爱这个功能还是学会避开它。
从封装模式开始,从第一天就添加可观测性,缓存一切可以缓存的东西,并且在 AI 不可用时始终给用户一条前进的路径。模型会持续变好。你的工作是确保集成足够可靠以利用这些改进。