最近在帮团队做 LLM 选型,发现一个挺有意思的现象:大家讨论时最常问的是“哪个模型效果最好”,但真正用起来,最先遇到的瓶颈往往是“为什么这么慢”“为什么并发一高就报错”“为什么半夜调用总失败”。
这其实反映了一个问题:我们对 LLM 的评估,太容易停留在“效果”这个单一维度上。效果当然重要,但延迟、吞吐量、稳定性这些工程指标,往往才是决定一个模型能不能真正进入生产环境的关键。
举个例子,有个团队选型时看中了某个模型在特定任务上的准确率,结果上线后发现平均响应时间超过 5 秒,用户根本等不及。另一个团队测试时单次调用很快,但并发超过 10 就频繁超时,最后只能临时降级。还有团队发现模型提供商在特定时段经常维护,导致业务高峰期调用失败。
这些都不是“效果”问题,但每一个都可能让再好的模型也无法落地。
所以,今天我想系统聊聊怎么评估不同 LLM 提供商在延迟、吞吐量和正常运行时间上的表现。这不是一个简单的性能测试指南,而是一套从单次验证到批量测试,再到长期监控的完整评估框架。
1. 为什么不能只看准确率:延迟、吞吐量和稳定性才是生产环境的生死线
在实验室环境里,我们更关心模型在测试集上的表现。但在真实业务中,用户不会等你慢慢推理,系统不会因为你用了最先进的模型就自动扩容,业务也不会因为提供商维护就暂停运营。
1.1 延迟:用户能等多长时间,决定了模型能不能用
延迟是用户最直接的体验。一般来说:
- 对话场景:响应时间最好在 1-2 秒内,超过 3 秒用户就会明显感知到卡顿
- 内容生成:根据生成长度,5-10 秒可能是可接受的上限
- 后台任务:如果没有实时交互需求,可以适当放宽,但也要考虑任务队列的堆积问题
但延迟不是一个固定值。你需要关注几个关键指标:
- P50 延迟:中位数,代表大多数请求的体验
- P95/P99 延迟:长尾延迟,代表最慢的那部分请求
- 冷启动延迟:第一次调用或长时间未调用后的延迟,可能比正常情况慢数倍
测试时不能只测几次,而要在不同时间段、不同负载下多次测试,才能得到有代表性的数据。
1.2 吞吐量:系统能承受多大压力,决定了模型能撑多大业务
吞吐量决定了你的系统能同时服务多少用户。这里有几个关键概念:
- QPS(Queries Per Second):每秒能处理的请求数
- 并发用户数:同时在线并发送请求的用户数量
- 最大吞吐量:系统在可接受延迟范围内的最大处理能力
测试吞吐量时要注意,单纯提高并发数可能没有意义,因为很多提供商会对单个账户或 API Key 进行限流。你需要了解提供商的限流策略,比如:
- 每秒最大请求数
- 每分钟/每小时最大 token 数
- 并发连接数限制
- 突发流量的处理方式
1.3 正常运行时间:服务能不能持续可用,决定了业务敢不敢依赖
正常运行时间通常用 SLA(Service Level Agreement)来衡量,比如 99.9% 的可用性意味着每月最多有 43.2 分钟的不可用时间。
但 SLA 数字背后还有几个需要关注的点:
- 维护窗口:提供商是否定期维护,维护时间是否在你的业务高峰期
- 故障恢复时间:出现问题时,平均需要多长时间恢复
- 地域可用性:不同地域的服务质量是否一致
- 降级策略:提供商是否提供备选方案或自动故障转移
2. 搭建测试环境:从单次调用到压力测试的完整路径
评估性能不能靠感觉,需要有一套可重复的测试方法。下面是我在实践中总结的测试流程。
2.1 环境准备:确保测试结果可比性
测试环境要尽可能接近生产环境:
# 示例:设置测试环境变量 export API_KEY="your_api_key" export ENDPOINT="https://api.provider.com/v1/chat/completions" export MODEL_NAME="gpt-4" # 根据测试的模型调整测试机器要保证网络稳定,最好使用与生产环境相同的网络配置。如果测试国内外的提供商,还要考虑网络延迟的影响。
2.2 单次调用测试:建立性能基线
先进行单次调用测试,了解最基本的性能表现:
import time import requests import json def test_single_request(api_key, endpoint, model, prompt): headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } data = { "model": model, "messages": [{"role": "user", "content": prompt}], "max_tokens": 100 } start_time = time.time() response = requests.post(endpoint, headers=headers, json=data) end_time = time.time() latency = end_time - start_time return latency, response.status_code, response.json() # 测试不同长度的输入 test_prompts = [ "你好", # 短文本 "请用300字左右介绍人工智能的发展历史", # 中等长度 "详细分析当前大语言模型的技术架构、应用场景和未来发展趋势" # 长文本 ] for prompt in test_prompts: latency, status, result = test_single_request(api_key, endpoint, MODEL_NAME, prompt) print(f"Prompt length: {len(prompt)}, Latency: {latency:.2f}s, Status: {status}")这个阶段要测试不同输入长度、不同参数配置下的延迟表现,建立性能基线。
2.3 并发测试:了解系统的处理能力
单次调用没问题不代表能承受并发压力。使用并发测试工具模拟真实场景:
import concurrent.futures import statistics def concurrent_test(api_key, endpoint, model, prompt, concurrent_users=10, requests_per_user=10): latencies = [] def single_user_requests(user_id): user_latencies = [] for i in range(requests_per_user): latency, status, result = test_single_request(api_key, endpoint, model, prompt) if status == 200: user_latencies.append(latency) time.sleep(0.1) # 模拟用户思考间隔 return user_latencies with concurrent.futures.ThreadPoolExecutor(max_workers=concurrent_users) as executor: futures = [executor.submit(single_user_requests, i) for i in range(concurrent_users)] for future in concurrent.futures.as_completed(futures): latencies.extend(future.result()) return latencies # 测试不同并发数下的表现 concurrency_levels = [1, 5, 10, 20, 50] results = {} for concurrency in concurrency_levels: print(f"Testing with {concurrency} concurrent users...") latencies = concurrent_test(api_key, endpoint, MODEL_NAME, "测试请求", concurrency, 10) if latencies: results[concurrency] = { 'p50': statistics.median(latencies), 'p95': statistics.quantiles(latencies, n=20)[18], # 95th percentile 'success_rate': len(latencies) / (concurrency * 10) }通过这个测试,你可以看到随着并发数增加,系统的响应时间和成功率如何变化。
2.4 长时间运行测试:检测稳定性问题
有些问题不会在短时间测试中暴露,需要长时间运行来发现:
- 内存泄漏问题
- 连接池耗尽
- 令牌刷新问题
- 提供商端的性能衰减
建议至少进行 4-8 小时的持续测试,观察性能指标的变化趋势。
3. 关键性能指标解读:什么才是“好”的性能
拿到测试数据后,怎么判断性能是否达标?这需要结合业务需求来定。
3.1 延迟指标的业务含义
| 延迟范围 | 用户体验 | 适用场景 |
|---|---|---|
| < 1秒 | 几乎无感知 | 实时对话、快速问答 |
| 1-3秒 | 可接受 | 大多数交互场景 |
| 3-5秒 | 明显等待 | 内容生成、复杂推理 |
| > 5秒 | 不可接受 | 仅限后台异步任务 |
但要注意,延迟的一致性也很重要。如果 P99 延迟是 P50 的 10 倍以上,说明系统存在严重的长尾问题。
3.2 吞吐量的合理预期
吞吐量需求完全取决于业务规模:
- 小型应用:10-50 QPS
- 中型应用:50-500 QPS
- 大型应用:500+ QPS
测试时要关注吞吐量的增长曲线。理想的系统应该在达到最大吞吐量之前,延迟保持相对稳定。
3.3 正常运行时间的实际影响
99.9% 的可用性听起来很高,但具体到业务影响:
| 可用性 | 每月宕机时间 | 业务影响 |
|---|---|---|
| 99% | 7.2小时 | 可能影响用户体验 |
| 99.9% | 43.2分钟 | 大多数业务可接受 |
| 99.99% | 4.32分钟 | 关键业务要求 |
| 99.999% | 25.9秒 | 金融级要求 |
4. 不同提供商的性能特点分析
基于公开数据和测试经验,不同提供商在性能上各有特点:
4.1 国际主流提供商
OpenAI GPT 系列
- 优势:模型成熟,文档完善,生态系统完整
- 延迟:通常 1-3 秒,受网络影响较大
- 吞吐量:限流相对严格,需要合理设计重试机制
- 稳定性:SLA 明确,但国内访问可能不稳定
Anthropic Claude
- 优势:上下文长度支持好,推理能力强
- 延迟:相对稳定,长文本处理有优势
- 吞吐量:并发限制较为宽松
- 稳定性:北美地区表现较好
4.2 国内提供商
百度文心一言
- 优势:国内网络优化好,中文理解强
- 延迟:国内访问快,通常 0.5-2 秒
- 吞吐量:企业版支持较高并发
- 稳定性:符合国内监管要求
阿里通义千问
- 优势:与阿里云生态集成好
- 延迟:云服务内网调用延迟低
- 吞吐量:可根据业务需求灵活调整
- 稳定性:阿里云基础设施支持
4.3 开源模型自部署
Llama 系列
- 优势:完全可控,成本固定
- 延迟:取决于部署硬件和优化程度
- 吞吐量:硬件决定上限,需要自行优化
- 稳定性:自己维护,责任自负
5. 性能优化实践:从调用方式到系统架构
测试发现问题后,如何优化?这里有几个层次的解决方案。
5.1 调用层面的优化
批量处理多个请求合并为一个批量请求,减少网络开销:
def batch_requests(api_key, endpoint, model, prompts): headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } # 将多个prompt合并为一个批量请求 messages_list = [[{"role": "user", "content": prompt}] for prompt in prompts] data = { "model": model, "messages": messages_list, # 支持批量处理的API "max_tokens": 100 } start_time = time.time() response = requests.post(endpoint, headers=headers, json=data) end_time = time.time() return end_time - start_time, response.json()连接复用使用 HTTP 连接池,避免重复建立连接的开销:
import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() retry_strategy = Retry( total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504], ) adapter = HTTPAdapter(max_retries=retry_strategy, pool_connections=10, pool_maxsize=10) session.mount("http://", adapter) session.mount("https://", adapter)5.2 系统架构优化
缓存策略对相同或相似的请求结果进行缓存:
import redis import hashlib import json class LLMCache: def __init__(self): self.redis_client = redis.Redis(host='localhost', port=6379, db=0) def get_cache_key(self, model, prompt, parameters): content = f"{model}_{prompt}_{json.dumps(parameters, sort_keys=True)}" return hashlib.md5(content.encode()).hexdigest() def get(self, key): result = self.redis_client.get(key) return json.loads(result) if result else None def set(self, key, value, expire=3600): # 默认缓存1小时 self.redis_client.setex(key, expire, json.dumps(value))异步处理对于非实时需求,使用消息队列进行异步处理:
import asyncio import aiohttp async def async_llm_request(session, api_key, endpoint, model, prompt): headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } data = { "model": model, "messages": [{"role": "user", "content": prompt}], "max_tokens": 100 } async with session.post(endpoint, headers=headers, json=data) as response: return await response.json() async def batch_async_requests(api_key, endpoint, model, prompts): async with aiohttp.ClientSession() as session: tasks = [] for prompt in prompts: task = async_llm_request(session, api_key, endpoint, model, prompt) tasks.append(task) results = await asyncio.gather(*tasks) return results5.3 降级和容错机制
多提供商备份不要把所有鸡蛋放在一个篮子里:
class MultiProviderLLM: def __init__(self, providers): self.providers = providers # 多个提供商配置 self.current_provider = 0 def call_with_fallback(self, prompt): for i in range(len(self.providers)): try: provider = self.providers[(self.current_provider + i) % len(self.providers)] result = self._call_provider(provider, prompt) self.current_provider = (self.current_provider + i) % len(self.providers) return result except Exception as e: print(f"Provider {i} failed: {e}") continue raise Exception("All providers failed")6. 长期监控和持续优化
性能评估不是一次性的工作,需要建立持续的监控体系。
6.1 关键监控指标
建立监控看板,跟踪以下指标:
- 实时延迟分布(P50/P95/P99)
- 每分钟请求数和错误数
- 提供商可用性状态
- Token 使用量和成本趋势
6.2 告警机制设置
根据业务需求设置合理的告警阈值:
- 延迟超过 3 秒的请求比例 > 5%
- 错误率连续 5 分钟 > 1%
- 提供商状态异常
6.3 定期性能回归测试
每月或每季度重新运行性能测试,比较与之前的差异,及时发现性能衰减问题。
7. 选型决策框架:如何平衡性能、成本和效果
最后,提供一个实用的选型决策框架。不要追求完美的提供商,而要找到最适合当前业务阶段的方案。
7.1 评估矩阵
为每个候选提供商在以下维度打分(1-5 分):
| 维度 | 权重 | 提供商A | 提供商B | 提供商C |
|---|---|---|---|---|
| 延迟性能 | 30% | |||
| 吞吐能力 | 25% | |||
| 稳定性 | 20% | |||
| 成本 | 15% | |||
| 模型效果 | 10% |
7.2 阶段化策略
根据业务发展阶段选择不同策略:
初创期:优先考虑开发速度和稳定性,选择文档完善、生态系统成熟的提供商成长期:平衡性能和成本,可能需要在多个提供商间分配流量成熟期:构建多提供商架构,实现自动故障转移和负载均衡
7.3 风险控制清单
在最终决策前,检查以下风险点:
- [ ] 是否测试过业务高峰期的性能表现
- [ ] 是否了解提供商的限流和配额政策
- [ ] 是否有降级方案和备用提供商
- [ ] 是否设置了足够的监控和告警
- [ ] 团队是否熟悉该提供商的问题排查方法
评估 LLM 提供商的性能是一个需要持续投入的工作,但这份投入是值得的。一个好的性能基础,能让你的 AI 应用在用户体验、系统稳定性和业务扩展性上都获得显著优势。
最关键的是,要把性能评估当作一个系统工程,而不是一次性的测试任务。从单次验证到压力测试,从即时监控到长期优化,每个环节都需要精心设计和执行。
在实际落地时,我建议先从最重要的 2-3 个场景开始,建立完整的性能评估流程,然后再逐步扩展到其他场景。这样既能快速获得价值,又能在过程中不断完善你的评估体系。