大模型推理部署架构:从单卡到分布式全方案

部署架构的重要性 模型再好,部署不好也白搭。推理部署架构决定了服务的延迟、吞吐、可用性和成本。从单卡到大规模集群,每个规模都有不同的最优架构。 部署规模分层 Tier 1:单卡部署 适用场景: 小规模应用、开发测试、边缘计算 硬件配置: GPU: RTX 3090/4090 (24GB) 或 A10G (24GB) 模型: 7B Q4量化 并发: 5-10 QPS 延迟: 50-200ms/token 架构: [用户] → [Nginx] → [vLLM/Ollama] → [GPU] 优化要点: INT4量化减小模型大小 使用vLLM的PagedAttention 设置合理的max_batch_size 启用prefix caching Tier 2:多卡部署 适用场景: 中等规模生产环境 硬件配置: GPU: 2-8张 A100/H100 (80GB) 模型: 70B Q4 或 7B FP16 并发: 50-100 QPS 延迟: 30-100ms/token 架构选择: 方案A:Tensor Parallel(张量并行) 单模型分布在多GPU上: GPU1: 模型层1-40 (矩阵上半部分) GPU2: 模型层1-40 (矩阵下半部分) 每次forward需要GPU间通信 适合: 单模型多GPU场景 # vLLM张量并行 python -m vllm.entrypoints.openai.api_server \ --model meta-llama/Llama-3-70B \ --tensor-parallel-size 4 方案B:Pipeline Parallel(流水线并行) 模型按层切分: GPU1: 层1-20 GPU2: 层21-40 GPU3: 层41-60 GPU4: 层61-80 流水线处理多个请求 适合: 超大模型 方案C:数据并行(多副本) 4张GPU各运行一个完整模型副本: GPU1: 完整7B模型 ←→ 请求1-100 GPU2: 完整7B模型 ←→ 请求101-200 GPU3: 完整7B模型 ←→ 请求201-300 GPU4: 完整7B模型 ←→ 请求301-400 负载均衡分发请求 适合: 7B级别的多副本部署 Tier 3:集群部署 适用场景: 大规模生产环境 ...

2026-07-16 · 2 min · 367 words · 硅基 AGI 探索者
LLM负载均衡

LLM负载均衡策略

LLM负载均衡的特殊性 传统Web服务的负载均衡(轮询、加权轮询)在LLM场景下效果不佳——LLM请求的长度差异巨大(10 token vs 10000 token),处理时间差异可达100倍。简单的轮询会导致某些节点被长请求占满,而短请求也被迫排队。 策略一:最小连接数 class LeastConnectionsBalancer: def __init__(self, backends): self.backends = {b: 0 for b in backends} # backend -> active_connections self.lock = asyncio.Lock() async def get_backend(self): async with self.lock: backend = min(self.backends, key=self.backends.get) self.backends[backend] += 1 return backend async def release(self, backend): async with self.lock: self.backends[backend] -= 1 策略二:基于队列长度 class QueueAwareBalancer: def __init__(self, backends): self.queues = {b: asyncio.Queue() for b in backends} async def route(self, request): # 选择队列最短的节点 backend = min(self.queues, key=lambda b: self.queues[b].qsize()) await self.queues[backend].put(request) return backend 策略三:延迟感知 class LatencyAwareBalancer: def __init__(self, backends): self.backends = backends self.latency_stats = {b: deque(maxlen=100) for b in backends} def record_latency(self, backend, latency): self.latency_stats[backend].append(latency) def get_backend(self): # 选择平均延迟最低的节点 avg_latencies = { b: sum(lats) / len(lats) if lats else 0 for b, lats in self.latency_stats.items() } return min(avg_latencies, key=avg_latencies.get) 策略四:请求长度路由 class LengthAwareRouter: def __init__(self, short_backends, long_backends, threshold=500): self.short_backends = short_backends # 小模型,处理短请求 self.long_backends = long_backends # 大模型,处理长请求 self.threshold = threshold def route(self, request): input_length = len(request["messages"][-1]["content"]) // 4 if input_length > self.threshold: return self.select_least_loaded(self.long_backends) else: return self.select_least_loaded(self.short_backends) 健康检查 class HealthChecker: def __init__(self, backends, check_interval=10): self.backends = {b: {"healthy": True, "last_check": 0} for b in backends} self.check_interval = check_interval async def check_backend(self, backend): try: async with httpx.AsyncClient() as client: resp = await client.get(f"{backend}/health", timeout=5) return resp.status_code == 200 except: return False async def run(self): while True: for backend in self.backends: healthy = await self.check_backend(backend) self.backends[backend]["healthy"] = healthy if not healthy: logger.warning(f"Backend {backend} unhealthy") await asyncio.sleep(self.check_interval) 结语 LLM负载均衡需要考虑请求长度差异、节点异构性和KV Cache状态。最小连接数+延迟感知的组合策略在大多数场景下表现最佳。配合健康检查和自动故障转移,可以构建高可用的LLM推理服务。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。 ...

2026-07-02 · 2 min · 252 words · 硅基 AGI 探索者
ring attention long context

Ring Attention:突破百万 Token 上下文的分布式注意力

长上下文的显存困境 大模型上下文窗口从 4K 扩展到 1M,最大的障碍不是计算量,而是 KV Cache 的显存。 以 Llama-3-70B 为例,fp16 精度下: 上下文长度 KV Cache (单序列) 单卡 80GB 够吗? 8K ~1.5 GB 是 32K ~6 GB 是 128K ~24 GB 勉强 1M ~192 GB 需要多卡 如果 batch_size > 1,显存需求成倍增长。单卡无法装下百万 token 的 KV Cache,必须将注意力计算分布到多张卡上。 分布式注意力的三种方案 1. Megatron 张量并行 将 Q、K、V 矩阵按头切分到不同 GPU: GPU 0: 计算 Head 0-19 的注意力 GPU 1: 计算 Head 20-39 的注意力 优点:通信量小(只需 AllReduce 输出) 缺点:KV Cache 仍按头切分,单序列长度受限于 单卡显存 × 总头数 ...

2026-06-25 · 6 min · 1112 words · 硅基 AGI 探索者
ring attention explained

Ring Attention 解析:百万 Token 上下文的秘密

朴素 Attention 的显存墙 标准自注意力的计算: $$\text{Attn}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V$$ 对于序列长度 $n$,中间矩阵 $QK^T$ 的形状为 $n \times n$。当 $n = 1\text{M}$ 时: FP16 显存:$10^6 \times 10^6 \times 2 \text{ bytes} = 2 \text{ TB}$ 即使分块计算,单 GPU 的 HBM(80 GB)也远远不够 朴素方案是序列并行——将序列切分到多个 GPU,但 Softmax 需要全局归约,通信量巨大。 Ring Attention 核心思想 Liu et al. (2023) 提出 Ring Attention:将序列分块分布在多个 GPU 上,以环形拓扑传递 KV 块,与计算重叠。 关键洞察 注意力可以分解为分块计算: $$\text{softmax}(QK^T)V = \frac{\sum_{j} e^{s_j} V_j}{\sum_{j} e^{s_j}}, \quad s_j = QK_j^T$$ 每个 GPU 只需要:本地 Q + 当前 KV 块 → 计算部分 score → 更新 running max 和 running sum。 ...

2026-06-25 · 4 min · 826 words · 硅基 AGI 探索者
agent scalability

Agent 系统可扩展性设计:从单机到分布式

扩展性挑战:为什么单机 Agent 走不远 单个 Agent 进程能处理的并发请求受限于 CPU、内存和网络连接数。一个典型的 LLM Agent 单次推理消耗 2-8GB 显存,单卡 GPU 同时只能服务少数几个请求。当 QPS 从个位数涨到百级、千级时,单机方案必然崩溃。 扩展 Agent 系统的核心挑战不是简单的"加机器",而是: 挑战 描述 影响 状态管理 Agent 会话上下文在哪台机器? 直接影响会话连续性 GPU 资源 LLM 推理是计算密集型 扩展瓶颈在 GPU 而非 CPU 长连接 流式输出需要持久连接 连接亲和性限制负载均衡 一致性 多 Agent 实例的内存状态同步 分布式共识开销 尾延迟 少数慢请求拖垮整体 P99 需要超时和降级机制 水平扩展策略 1. 无状态 Agent:将状态外部化 扩展的第一原则:Agent 进程本身不持有任何会话状态。所有状态存储在外部系统。 from dataclasses import dataclass, field from typing import Optional, Any import json # ❌ 错误做法:状态在内存中 class StatefulAgent: def __init__(self): self.conversations: dict[str, list] = {} # 内存中的会话状态 def chat(self, session_id: str, message: str) -> str: history = self.conversations[session_id] # 只在本机有效 history.append({"role": "user", "content": message}) # ...处理... return "response" # ✅ 正确做法:状态外部化 class StatelessAgent: """无状态 Agent,所有会话状态存入 Redis""" def __init__(self, state_store: 'SessionStore'): self.store = state_store def chat(self, session_id: str, message: str) -> str: # 每次从外部存储加载会话状态 history = self.store.get_history(session_id) history.append({"role": "user", "content": message}) # 处理逻辑 response = self._generate(history) history.append({"role": "assistant", "content": response}) # 持久化回外部存储 self.store.save_history(session_id, history) return response class SessionStore: """基于 Redis 的会话存储""" def __init__(self, redis_client): self.redis = redis_client self.ttl = 3600 # 会话过期时间 1 小时 def get_history(self, session_id: str) -> list[dict]: data = self.redis.get(f"session:{session_id}") return json.loads(data) if data else [] def save_history(self, session_id: str, history: list[dict]): self.redis.setex( f"session:{session_id}", self.ttl, json.dumps(history, ensure_ascii=False) ) def extend_ttl(self, session_id: str): self.redis.expire(f"session:{session_id}", self.ttl) 2. 分层架构:接入层 + 推理层 + 知识层 """ 三层架构设计: - 接入层:处理 HTTP/WebSocket 连接,会话路由 - 推理层:LLM 推理,可水平扩展 - 知识层:向量数据库、知识图谱 """ from abc import ABC, abstractmethod class GatewayLayer: """接入层:路由请求到推理节点""" def __init__(self, inference_pool: 'InferencePool'): self.pool = inference_pool async def handle_request(self, session_id: str, message: str): # 根据会话亲和性选择节点 node = self.pool.select_node(session_id) return await node.process(session_id, message) class InferenceNode: """推理层:单个推理节点""" def __init__(self, node_id: str, model_path: str): self.node_id = node_id self.model = self._load_model(model_path) self.active_sessions = 0 self.max_sessions = 10 async def process(self, session_id: str, message: str) -> str: self.active_sessions += 1 try: # 推理逻辑 result = await self._infer(message) return result finally: self.active_sessions -= 1 @property def available(self) -> bool: return self.active_sessions < self.max_sessions class InferencePool: """推理节点池""" def __init__(self): self.nodes: list[InferenceNode] = [] def add_node(self, node: InferenceNode): self.nodes.append(node) def select_node(self, session_id: str = None) -> InferenceNode: # 优先选择可用且负载最低的节点 available = [n for n in self.nodes if n.available] if not available: raise RuntimeError("No available inference nodes") return min(available, key=lambda n: n.active_sessions) 3. 推理与工具调用分离 LLM 推理和工具执行有不同的资源特征:推理需要 GPU,工具调用主要消耗 CPU 和网络 I/O。将它们分离到不同服务。 ...

2026-06-24 · 7 min · 1286 words · 硅基 AGI 探索者
鲁ICP备2026018361号