乐于分享
好东西不私藏

Day 4|AI应用架构设计:从单体Chat到多模型协同系统

Day 4|AI应用架构设计:从单体Chat到多模型协同系统

上周和一个做 SaaS 的朋友聊天,他说他们团队花了两周把 GPT-4 接进产品,上线第一个月用户反馈炸裂。第二个月开始,问题来了——高峰期 API 调用延迟飙到 8 秒,单月 API 账单六位数,某个第三方模型凌晨挂掉直接让核心功能瘫痪。他苦笑着说:”Chat wrapper 好写,生产级系统难搞。”

这就是今天要聊的主题:AI 应用的架构设计。从一个人、一个 Chat 包装器就能跑的 demo,到一个能扛流量、控成本、有容错的 production 系统,中间差了哪些东西?

第一阶段:单体 Chat 包装器

大多数团队起步都很像:Flask/FastAPI 起一个服务,调一次 OpenAI API,返回结果完事。

from openai import OpenAIfrom fastapi import FastAPIapp = FastAPI()client = OpenAI()@app.post("/chat")asyncdefchat(prompt: str):    resp = client.chat.completions.create(        model="gpt-4",        messages=[{"role""user""content": prompt}]    )return {"reply": resp.choices[0].message.content}

简单、直观、能用。但这个架构有三个致命缺陷:

  1. 单点故障:GPT-4 挂了,你的服务就挂了
  2. 成本失控:所有流量都走最贵的模型
  3. 性能不可控:没有缓存,同样的问题反复调用 API

第二阶段:模型路由与负载均衡

第一步改进是引入 Model Router。不同请求走不同模型,而不是把所有鸡蛋放在一个篮子里。

from openai import OpenAIimport jsonclassModelRouter:def__init__(self):self.clients = {"gpt4": OpenAI(),"gpt4o_mini": OpenAI(),"claude": OpenAI(base_url="...")  # 假设的 Anthropic 端点        }self.rules = [            ("简单问答",  self._is_simple_qa,     "gpt4o_mini"),            ("代码生成",  self._is_code_gen,      "gpt4"),            ("文档分析",  self._is_doc_analysis,   "claude"),        ]defroute(self, prompt: str) -> tuple:for name, detector, model inself.rules:if detector(prompt):return model, self.clients[model]return"gpt4o_mini"self.clients["gpt4o_mini"]def_is_simple_qa(self, prompt: str) -> bool:returnlen(prompt) < 100# 简化的启发式规则

核心思路:小模型干小活,大模型干大活。简单问候、FAQ 类请求走 gpt-4o-mini,成本降到 1/30;复杂推理、代码生成再升舱到 GPT-4 或 Claude。

配合 fallback 机制——主模型返回 429 或 5xx 时,自动降级到次优模型:

asyncdefchat_with_fallback(router, prompt: str, max_retries=2):    errors = []for attempt inrange(max_retries + 1):try:            model, client = router.route(prompt)            resp = client.chat.completions.create(                model=model,                messages=[{"role""user""content": prompt}],                timeout=15            )return resp.choices[0].message.contentexcept Exception as e:            errors.append(f"{model}{str(e)}")# 降级策略:下次尝试不同的模型            router.demote(model)raise Exception(f"All models failed: {errors}")

第三阶段:语义缓存——降本提速

你有没有想过,同一个问题被不同用户问了 100 遍,你付了 100 次 API 费用?语义缓存就是解决这个问题的。

普通的 key-value 缓存要求精确匹配,但用户的自然语言表述千变万化。”怎么注册?”和”注册流程是什么?”语义相同,但文本不同。语义缓存用 embedding 做检索,命中语义相近的历史结果就直接返回。

import numpy as npfrom openai import OpenAIclassSemanticCache:def__init__(self, threshold=0.92):self.client = OpenAI()self.cache = []          # [(embedding, response), ...]self.threshold = thresholddef_embed(self, text: str) -> list:        resp = self.client.embeddings.create(            model="text-embedding-3-small"input=text        )return resp.data[0].embeddingdef_cosine_sim(self, a, b) -> float:        a, b = np.array(a), np.array(b)return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))defget(self, query: str):        q_emb = self._embed(query)for emb, resp inself.cache:ifself._cosine_sim(q_emb, emb) >= self.threshold:return respreturnNonedefset(self, query: str, response: str):self.cache.append((self._embed(query), response))

实测数据:在常见的客服场景中,语义缓存能命中 30%~50% 的请求,延迟从 2~3 秒降到 50ms 以下,API 账单直接腰斩。

第四阶段:多模型协同——小模型预筛选 + 大模型精修

这是目前生产级 AI 系统最流行的范式:两条流水线协作

用户请求 → 小模型预筛选 → 结果分类 / 路由决策 → 大模型精修 → 最终输出                    ↕              语义缓存

小模型(如 GPT-4o-mini、Llama-3.1-8B)负责快速判断:这个请求是啥类型?需要调用工具吗?命中缓存了吗?大模型只在需要深度推理时才上场。

一个实际案例:某 AI 客服系统,每天 100 万请求。架构如下:

  • Layer 1(路由层):GPT-4o-mini + 语义缓存,处理 70% 的普通问答,P50 延迟 200ms
  • Layer 2(推理层):GPT-4o,处理 25% 的复杂查询(多轮对话、情感分析),P50 延迟 1.5s
  • Layer 3(深度推理层):Claude Opus 或 o1,处理 5% 的高难度请求(合同审查、代码审计),P50 延迟 5~10s

结果:综合成本降低了 60%,同时核心用户体验没有降级。

流式响应的工程实现

最后提一个常被忽视的工程细节:流式响应(Streaming)。用户对”一个字一个字往外蹦”的体验预期已经形成了标准,如果响应是整段返回的,用户会觉得”卡”。

from fastapi.responses import StreamingResponsefrom openai import OpenAIclient = OpenAI()asyncdefstream_chat(prompt: str):    stream = client.chat.completions.create(        model="gpt-4o-mini",        messages=[{"role""user""content": prompt}],        stream=True,    )for chunk in stream:        delta = chunk.choices[0].delta.contentif delta:yieldf"data: {delta}\n\n"@app.get("/chat/stream")asyncdefchat_stream(prompt: str):return StreamingResponse(        stream_chat(prompt),        media_type="text/event-stream"    )

注意:加上缓存的时候,如果命中缓存,需要模拟流式输出(把完整句子切成小段返回),前端才能统一处理 text/event-stream 协议。不然你缓存命中的时候会”静默”——前端等半天没收到流。

总结

今天我们从四个层面拆解了 AI 应用的架构演进:

阶段
核心能力
解决什么问题
单体 Chat
快速上线验证
从 0 到 1
模型路由 + Fallback
负载均衡与容错
单点故障 / 成本
语义缓存
降本提速
重复请求 / 延迟
多模型协同
性价比最优解
全场景覆盖 / 成本控制

明天(Day 5)我们将进入 RAG 的世界——让大模型拥有真正的”长期记忆”,不再受限于上下文窗口。敬请期待。

系列回顾

  • [第1篇] 大模型应用开发全景:从入门到实战路线图
  • [第2篇] 提示词工程(上):Prompt设计核心原则与实战技巧
  • [第3篇] 提示词工程(下):Chain-of-Thought、Few-shot与高级技巧
  • ← 你在这里
  • [第5篇] RAG从原理到实战:让大模型拥有「长期记忆」