AI系统架构实战指南:从单体到混合架构的演进
前言:架构是业务和团队的映射
架构设计从来不是寻找"完美方案",而是在特定约束条件下做出最合理的取舍。
架构演进的本质: 每一步演进都解决了特定问题,也带来了新的复杂性。任何架构改进都要问自己:新增的复杂性是否带来了相应的价值?
一、架构演进的典型路径
| 阶段 | 解决的问题 | 引入的复杂性 |
|---|---|---|
| 单体 | 初期快速开发 | 耦合严重、部署麻烦 |
| 进程守护 | 进程崩溃恢复 | 资源监控 |
| 多机部署 | 单点故障 | 数据一致性、负载均衡 |
| 消息队列 | 流量削峰、异步处理 | 状态管理、监控难度 |
| 微服务 | 团队协作、独立部署 | 服务发现、分布式事务 |
| Serverless | 运维减负、按需付费 | 冷启动、调试复杂 |
| 混合架构 | 场景化最优 | 协调复杂度 |
二、单体架构:一切都很简单,直到出问题
2.1 单体的局限
// 单体应用的结构
/app
/controllers // 用户、订单、支付
/models // 用户、订单、支付
/services // 邮件、通知
/routes.js
问题:
- 代码耦合严重,改一处影响多处
- 部署麻烦,小改动要部署整个应用
- 团队协作困难,多人修改同一代码库
- 扩展性差,整体部署或不部署
2.2 什么时候需要拆分
评估标准:
| 维度 | 单体够用 | 考虑拆分 |
|---|---|---|
| 团队规模 | < 5 人 | 5-20 人(>20 人必须拆分) |
| 业务复杂度 | 简单 CRUD | 业务逻辑复杂 |
| 流量规模 | 小流量 | 高流量 |
| 部署频率 | 月级别 | 日级别 |
不是所有系统都需要拆分,有时候单体架构更简单。
三、AI 系统架构的特殊性
3.1 AI 组件不是"听话"的服务
做 AI 系统架构和传统系统最大的不同:你不能假设所有组件都是"听话"的。
LLM 调用有几个明显特点:
- 延迟不稳定:同样的请求,有时 500ms,有时 5 秒
- 并发限制严格:大多数提供商有严格的 rate limit
- 成本随用量线性增长:失败重试要真金白银
3.2 第一个坑:把 LLM 当成普通 HTTP 服务
# 错误做法:当成普通 HTTP 请求
async def query_llm(prompt: str) -> str:
async with httpx.AsyncClient() as client:
response = await client.post(
"https://api.openai.com/v1/chat/completions",
json={"model": "gpt-4", "messages": [...]}
)
return response.json()["choices"][0]["message"]["content"]
测试环境跑了几天挺好,直到某天并发量突然翻倍,系统疯狂报错(Timeout、Connection 错误)。
正确做法:加调用管理层
class LLMCaller:
def __init__(self, max_concurrent=5, timeout=30):
self.semaphore = asyncio.Semaphore(max_concurrent)
self.timeout = timeout
async def call(self, prompt: str, retry=3) -> str:
for attempt in range(retry):
async with self.semaphore:
try:
async with asyncio.timeout(self.timeout):
return await self._do_call(prompt)
except asyncio.TimeoutError:
if attempt == retry - 1:
raise
await asyncio.sleep(2 ** attempt) # 指数退避
except httpx.HTTPStatusError as e:
if e.response.status_code == 429: # Rate limit
wait_time = int(e.response.headers.get("Retry-After", 60))
await asyncio.sleep(wait_time)
continue
raise
3.3 第二个坑:检索和生成的边界
问题:
- 检索质量参差不齐
- 上下文长度爆炸
- 成本不可控
解决:加质量评估层
async def enhanced_query(query: str) -> str:
# 快速检索
docs = await vector_search(query, top_k=3)
# 评估检索质量
relevance = await assess_relevance(query, docs)
if relevance < 0.5:
# 质量不够,扩展检索
docs = await vector_search(query, top_k=10)
relevance = await assess_relevance(query, docs)
if relevance < 0.3:
# 还是差,走通用回答
return await generic_llm_response(query)
return await llm_summarize(query, docs)
核心认识:AI 系统里的组件之间不是简单的串联,而是需要有"中间层"来做质量评估和路由决策。
3.4 第三个坑:状态管理
用户反馈"为什么问同样的问题,答案每次都不一样"。
简单方案: 把对话历史存 Redis。结果 Redis 内存爆炸,上下文长度限制也很快到了。
正确做法:分级存储 + 对话摘要
async def chat_with_memory(user_id: str, message: str) -> str:
# 获取最近对话
recent_history = await redis.get(f"chat:recent:{user_id}")
messages = json.loads(recent_history) if recent_history else []
# 超过 10 轮,做摘要
if len(messages) > 10:
summary = await llm_summarize_history(messages[:5])
messages = messages[5:]
messages.insert(0, {"role": "system", "content": f"对话摘要:{summary}"})
messages.append({"role": "user", "content": message})
response = await llm_call(messages)
messages.append({"role": "assistant", "content": response})
# 只保留最近 10 轮
await redis.set(f"chat:recent:{user_id}", json.dumps(messages[-10:]))
return response
3.5 AI 系统架构的核心原则
- 不要把 AI 组件当成可靠服务:要做专门的适配层
- 组件之间需要"质量评估层":特别是在检索和生成之间
- 成本控制要内置到架构里:LLM 调用按次付费
- 状态管理要考虑上下文限制:做摘要和分级存储
- 监控和日志很重要:AI 的不确定性让问题定位更难
四、模型服务架构演进
4.1 单机时代
最初的模型服务架构:一台 8 卡 A100,部署 Flask 服务,Nginx 转发。
问题:
- 显存泄漏(3 小时从 65% 涨到 98%)
- 进程假死
- 单点故障
4.2 进程守护 + 监控
# Supervisor 配置
[program:model-service]
command=/opt/conda/bin/gunicorn -w 4 -b 0.0.0.0:5000 app:app
autorestart=true
stdout_logfile=/var/log/model-service.log
Prometheus 监控 GPU:
from prometheus_client import start_http_server, Gauge
import pynvml
gpu_memory_used = Gauge('model_gpu_memory_used_mb', 'GPU memory', ['gpu_id'])
gpu_utilization = Gauge('model_gpu_utilization_percent', 'GPU util', ['gpu_id'])
def update_gpu_metrics():
for i in range(gpu_count):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
util = pynvml.nvmlDeviceGetUtilizationRates(handle)
gpu_memory_used.labels(gpu_id=i).set(mem_info.used / 1024 / 1024)
gpu_utilization.labels(gpu_id=i).set(util.gpu)
4.3 多机部署
upstream model_backend {
server 10.0.1.10:5000 max_fails=3 fail_timeout=30s;
server 10.0.1.11:5000 max_fails=3 fail_timeout=30s;
least_conn; # 模型推理是长连接任务
}
多机的坑:
- 模型一致性:两台服务器模型版本必须完全一致
- 负载不均:least_conn 只考虑连接数
- 状态同步:复杂度大幅上升
4.4 消息队列:削峰填谷
异步架构的好处:
- 流量削峰
- 失败重试
- 资源充分利用
新挑战:
- 延迟增加(同步变异步)
- 任务状态管理复杂
- 监控难度上升
4.5 高可用架构
关键设计:
- 无状态设计:Web 和 Worker 都无状态
- 故障隔离:组件间网络隔离
- 自动恢复:K8s 健康检查 + Redis Cluster 故障转移
- 可观测性:全链路监控
4.6 模型服务的坑
坑一:冷启动问题
模型加载需要 3-5 分钟。解决:预热机制,新 Pod 先加载模型再接收流量。
坑二:显存碎片
频繁推理导致显存碎片化。解决:定期重启 Worker + 显存整理。
坑三:请求超时
长文本推理可能几分钟。解决:调整 proxy_read_timeout。
坑四:Redis key 没设 TTL
任务完成后 key 没过期,Redis 内存爆满。解决:所有 key 都要带 TTL。
五、Serverless 架构
5.1 什么时候选 Serverless
适合的场景:
- 不规律流量(波动大、偶发峰值)
- 事件驱动任务(文件上传、定时任务)
- 轻量级 API(逻辑简单、执行时间短)
- 快速验证想法
不适合的场景:
- 长运行任务(超过 15 分钟)
- 高性能需求(极低延迟)
- 复杂状态管理
- 合规要求严
5.2 冷启动:看不见的性能杀手
| 函数体量 | 首次冷启动 | 热调用 | 闲置 10 分钟后 |
|---|---|---|---|
| 简单(~1MB) | ~300ms | ~10ms | ~350ms |
| 中等(~10MB) | ~800ms | ~20ms | ~900ms |
| 复杂(~50MB) | ~1500ms | ~30ms | ~1800ms |
冷启动与热调用延迟差两个数量级。
优化策略:
- 保持热度:定时任务定期 ping 函数
- 预热:流量高峰前主动触发
- 优化代码:懒加载依赖
- 升级配置:增加内存(AWS Lambda 内存和 CPU 绑定)
5.3 连接池放在函数外部
import psycopg2
from psycopg2 import pool
# 全局连接池(关键!)
connection_pool = None
def get_connection():
global connection_pool
if connection_pool is None:
connection_pool = psycopg2.pool.SimpleConnectionPool(
minconn=1, maxconn=5,
host=db_host, database=db_name,
user=db_user, password=db_password
)
return connection_pool.getconn()
5.4 多云对比
| 指标 | AWS Lambda | 腾讯云函数 | 阿里云 FC |
|---|---|---|---|
| P50 延迟 | 45ms | 60ms | 50ms |
| P99 延迟 | 350ms | 480ms | 420ms |
| 错误率 | 0.01% | 0.03% | 0.02% |
| 冷启动频率 | 12% | 18% | 15% |
AWS 稳定性更好,但国内用户访问延迟会被网络抵消。
5.5 Serverless 的坑
坑一:本地与线上不一致
本地 Python 3.10,云函数 3.9,库的兼容性问题。解决:用 Dockerfile 确保环境统一。
坑二:超时设置太激进
设成 3 秒,第三方 API 慢就超时。解决:预留余量(10 秒),监控 P99.5。
坑三:忘了处理异步任务
第三方 API 卡 10 秒,函数超时但 API 请求还在继续。解决:明确超时和重试策略。
坑四:环境变量管理混乱
测试 API key 推到生产。解决:环境分离,不同配置文件。
六、AI 集成模式演进
6.1 模式一:简单调用
@app.post("/generate-summary")
async def generate_summary(content: str):
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": f"摘要:{content}"}]
)
return {"summary": response.choices[0].message.content}
问题:
- API 调用慢(10-20 秒)
- 成本不可控
- 错误处理不够
- Prompt 不稳定
6.2 模式二:异步调用
@app.post("/process-content")
async def process_content(content: str, background_tasks: BackgroundTasks):
task_id = f"task_{int(time.time())}"
redis.hset(f"task:{task_id}", mapping={"status": "pending"})
# 后台异步处理
background_tasks.add_task(process_with_ai, task_id, content)
return {"task_id": task_id, "status": "pending"}
好处: 用户不用干等。 新问题: 任务状态管理复杂、用户需要轮询、缓存没做好。
6.3 模式三:分级模型选择
class AIModelSelector:
def __init__(self):
self.model_mapping = {
"high_quality": {"model": "gpt-4", "max_tokens": 2000, "temperature": 0.3},
"general": {"model": "gpt-3.5-turbo", "max_tokens": 1000, "temperature": 0.7},
"fast": {"model": "gpt-3.5-turbo", "max_tokens": 500, "temperature": 0.5}
}
def select_model(self, task_type: str, priority: str = "normal"):
if priority == "high":
return self.model_mapping["high_quality"]
if task_type in ["content_creation", "code_review"]:
return self.model_mapping["high_quality"]
elif task_type in ["summarization", "tag_extraction"]:
return self.model_mapping["general"]
else:
return self.model_mapping["fast"]
效果: GPT-4 只占 10% 调用量,但处理最重要任务。成本下降 60%。
6.4 模式四:嵌入业务流程
AI 参与决策,不只吐一段生成内容:
class ContentAIWorkflow:
async def process_content(self, content_id: int, content: dict):
# AI 初步评估
ai_assessment = await self._ai_pre_assessment(content)
# 根据评估走不同流程
if ai_assessment["risk_level"] == "high":
await self._escalate_to_human(content_id, ai_assessment)
elif ai_assessment["risk_level"] == "medium":
additional_checks = await self._run_additional_checks(content)
if additional_checks["passed"]:
await self._approve_content(content_id)
else:
await self._escalate_to_human(content_id, additional_checks)
else:
await self._approve_content(content_id)
# 记录反馈,持续优化
await self._record_feedback(content_id, ai_assessment)
关键区别:
- AI 参与决策,不只生成内容
- 有反馈循环,定期分析准确率
- AI 是"专家"不是"工人"
6.5 模式五:混合架构
三层架构:
- 规则引擎:处理明确规则(快、准)
- AI:处理模糊判断(理解上下文)
- 人工:处理边界情况(复杂决策)
效果: 审核准确率从 75% 提到 92%,人工审核量减少 80%。
七、分布式系统的挑战
7.1 数据一致性问题
def process_order(user_id, amount):
inventory.reduce_stock(amount) # 1. 扣库存
order = order_service.create_order() # 2. 创建订单
payment_service.charge(user_id) # 3. 支付
# 问题:如果支付失败,库存已经扣了
解决:Saga 模式(带补偿)
class CreateOrderSaga:
def execute(self, user_id, amount):
try:
inventory_service.reduce_stock(amount)
order = order_service.create_order(user_id, amount)
payment_service.charge(user_id, amount)
return order
except Exception as e:
# 补偿操作
inventory_service.restore_stock(amount)
raise e
7.2 服务发现
const consul = require('consul')();
// 服务注册
await consul.agent.service.register({
name: serviceName,
address: serviceUrl,
check: {
http: `http://${serviceUrl}/health`,
interval: '10s'
}
});
// 服务发现
const services = await consul.agent.service.list();
7.3 分布式追踪
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
@tracer.start_as_current_span("process_order")
def process_order(order_id):
with tracer.start_as_span("get_order"):
order = get_order(order_id)
with tracer.start_as_span("process_payment"):
process_payment(order)
八、拆分策略
8.1 垂直拆分(按业务功能)
/user-service
- 用户管理
- 权限管理
/order-service
- 订单处理
- 订单查询
/payment-service
- 支付处理
- 退款管理
8.2 水平拆分(按流量)
/user-service-master
/user-service-slave-1
/user-service-slave-2
8.3 拆分的常见坑
坑一:过度拆分
把所有东西都拆成独立服务,管理复杂。解决:合并相关服务,减少服务数量。
坑二:数据拆分不清晰
导致数据访问复杂。解决:按业务域拆分数据,明确所有权。
坑三:监控困难
服务多了,监控变难。解决:分布式追踪 + 集中监控。
九、成本控制策略
9.1 成本控制要前置
不要等账单来了才发现成本爆了。从设计阶段就要考虑:
| 策略 | 效果 |
|---|---|
| 分级模型选择 | GPT-4 只用于关键任务 |
| 结果缓存 | 相似问题复用答案 |
| Prompt 优化 | 减少 token 消耗 |
| 本地预处理 | 过滤低质量请求 |
| 批处理 | 非实时场景合并请求 |
9.2 智能采样(影子部署)
SHADOW_RATES = {
"low": 1.0, # 低风险 100% 影子
"medium": 0.5, # 中风险 50%
"high": 0.2 # 高风险 20%
}
9.3 按场景分级
# 简单任务用便宜模型
def select_model(task_type):
if task_type == "simple_qa":
return "gpt-3.5-turbo"
elif task_type == "code_generation":
return "gpt-4"
else:
return "claude-3-5-sonnet"
十、监控与可观测性
10.1 全链路监控
# Prometheus 告警规则
groups:
- name: model_service_alerts
rules:
- alert: HighQueueLength
expr: redis_queue_length{queue="model_tasks"} > 1000
for: 5m
labels:
severity: warning
- alert: ModelServiceDown
expr: up{job="model-service"} == 0
for: 1m
labels:
severity: critical
- alert: HighGPUMemory
expr: model_gpu_memory_usage_percent > 90
for: 10m
labels:
severity: warning
10.2 关键监控指标
技术指标:
- 延迟(P50、P95、P99)
- 错误率
- 吞吐量
- GPU 利用率
- 显存使用率
业务指标:
- 准确率
- 用户满意度
- 任务完成率
成本指标:
- API 调用量
- Token 消耗
- 计算资源消耗
十一、架构原则总结
11.1 核心原则
- 简单可靠:复杂度是工程师的最大敌人
- 可观测:没有监控就没有真相
- 能恢复:故障必然发生,关键是快速恢复
- 无状态优先:有状态带来复杂度
- 故障隔离:一个组件问题不扩散
11.2 AI 系统的额外原则
- 不要把 AI 当万能药:用它擅长的(理解、生成、分类)
- 从简单开始:先 API 调用,遇到问题再优化
- 监控和日志要到位:AI 行为不可预测
- 要有降级方案:AI 出问题不能拖垮系统
- 成本控制要前置:设计阶段就考虑
- AI 需要持续调优:不要指望一次完美
11.3 技术选型建议
| 场景 | 推荐架构 |
|---|---|
| 快速原型 | 单体 + API 调用 |
| 中等规模 | 单机模型服务 + 监控 |
| 高可用需求 | 多机部署 + 消息队列 |
| 流量波动大 | Serverless |
| 复杂业务 | 混合架构(规则 + AI + 人工) |
| 隐私敏感 | 本地部署 |
十二、写在最后
架构是业务和团队的映射。技术选型从来不是非黑即白。
几个核心体会:
- 没有"完美架构",只有"适合当前阶段的架构"
- 演进比革命好:渐进式改进,不要推倒重来
- 监控比功能重要:没有可观测性,所有架构都是黑盒
- 简单比复杂好:能用单体解决就别上微服务
- 成本是硬约束:技术方案要算经济账
做 AI 系统架构最大的不同:你不能假设所有组件都是"听话"的。它们有自己的脾气、限制和成本模型。传统系统关注"高效协作",AI 系统还要考虑"让不确定的组件协作得尽量稳定"。
接好了,AI 是系统里的一环;接不好,就是个慢且贵的外挂。
本文整合了 11 篇系统架构设计相关文章,涵盖单体到分布式演进、AI 系统架构、模型服务高可用、Serverless 实践、AI 集成模式、混合架构等核心技术。
版权声明: 本文首发于 指尖魔法屋-AI系统架构实战指南:从单体到混合架构的演进(https://blog.thinkmoon.cn/post/ai-system-architecture-comprehensive-guide/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。