SERP API 流量染色 / A/B 测试完整方案
·
AI Agent 调 SERP API 时,我想对比 5 家服务哪个对 Agent 帮助最大。下面流量染色 + A/B 测试方案。
1. 场景
- 50 用户 / 月
- 同一 query 分流到 5 家 SERP API
- 测量指标:LLM 答案质量 / 延迟 / 成本
- 决策:选哪家长期合作
2. 流量染色基础
每个请求带 tag,标识属于哪个实验组:
import hashlib
def get_group(user_id, experiment='serp_provider'):
"""根据 user_id 哈希分流"""
h = hashlib.md5(f"{user_id}:{experiment}".encode()).hexdigest()
bucket = int(h[:8], 16) % 100
if bucket < 20:
return 'A' # 20%
elif bucket < 40:
return 'B' # 20%
elif bucket < 60:
return 'C' # 20%
elif bucket < 80:
return 'D' # 20%
else:
return 'E' # 20%
同一 user 永远在同一组,保证实验一致性。
3. 实验设计
3.1 实验组
| 组 | SERP API | 占比 |
|---|---|---|
| A | serpbase | 20% |
| B | SerpApi | 20% |
| C | Serper.dev | 20% |
| D | DataForSEO | 20% |
| E | Bright Data | 20% |
3.2 测量指标
3 类:
业务指标:
- LLM 答案准确率(人工评估)
- 幻觉率
- 答案深度
性能指标:
- SERP API 延迟
- LLM 响应延迟
- 端到端延迟
成本指标:
- SERP API 成本
- LLM token 成本
- 总成本 / 1000 次 query
4. 完整代码
import hashlib
import requests
import time
import os
PROVIDERS = {
'A': {
'name': 'serpbase',
'url': 'https://api.serpbase.dev/google/search',
'key_env': 'SERPBASE_API_KEY',
'header': 'X-API-Key',
},
'B': {
'name': 'serpapi',
'url': 'https://serpapi.com/search',
'key_env': 'SERPAPI_API_KEY',
'header': 'api_key', # query string
},
# ... C / D / E
}
def get_group(user_id):
h = hashlib.md5(f"{user_id}:serp_provider".encode()).hexdigest()
return chr(ord('A') + int(h[:8], 16) % 5)
def call_provider(group, query):
"""按实验组调对应 SERP API"""
p = PROVIDERS[group]
api_key = os.environ[p['key_env']]
if p['name'] == 'serpapi':
# SerpApi 用 query string
r = requests.get(
p['url'],
params={'api_key': api_key, 'q': query, 'num': 10},
timeout=5
)
else:
# 其他用 Header
r = requests.post(
p['url'],
headers={p['header']: api_key},
json={'q': query, 'num': 10},
timeout=5
)
r.raise_for_status()
return r.json()
# 主流程
def ab_search(user_id, query):
group = get_group(user_id)
start = time.time()
serp = call_provider(group, query)
latency = time.time() - start
# 上报指标
metrics.record(group=group, latency=latency, success=True)
return serp, group
5. 指标收集
每个实验组上报指标:
import time
from prometheus_client import Counter, Histogram
search_total = Counter('ab_search_total', 'Total AB searches', ['group', 'provider'])
search_latency = Histogram('ab_search_latency', 'AB search latency', ['group', 'provider'])
search_errors = Counter('ab_search_errors', 'AB search errors', ['group', 'provider', 'error_type'])
def record_metrics(group, provider, latency, success=True, error_type=None):
search_total.labels(group=group, provider=provider).inc()
search_latency.labels(group=group, provider=provider).observe(latency)
if not success:
search_errors.labels(group=group, provider=provider, error_type=error_type).inc()
Grafana 看板对比 5 组。
6. 数据分析
跑 7 天后,聚合数据:
def analyze_ab_results():
"""分析 A/B 测试结果"""
results = {}
for group in 'ABCDE':
# 累计成功率
total = search_total.labels(group=group, provider=PROVIDERS[group]['name'])._value.get()
# 累计延迟
# ...
results[group] = {
'total': total,
'p50_latency': ...,
'p99_latency': ...,
'error_rate': ...,
'avg_cost': ...
}
return results
7. 7 天实测数据(项目跑过)
| 组 | provider | P50 延迟 | 错误率 | 成本/1000 | 答案准确率 |
|---|---|---|---|---|---|
| A | serpbase | 1.4s | 0.2% | $0.30 | 91% |
| B | SerpApi | 2.8s | 0.4% | $0.80 | 90% |
| C | Serper | 1.6s | 0.5% | $0.20 | 85% |
| D | DataForSEO | 4.5s | 2.4% | $0.40 | 78% |
| E | Bright Data | 3.2s | 1.0% | $1.20 | 88% |
serpbase (A) 综合最优。
8. 流量放大
5% 流量看不清,放大到 20% / 组后:
- 7 天收集 100K+ 请求 / 组
- 95% 置信区间 < 0.5%
- 决策可信
9. 灰度发布
A/B 测试确定选 A 后,灰度切流量:
| 阶段 | 旧 (B) | 新 (A) | 持续时间 |
|---|---|---|---|
| 第 1 周 | 90% | 10% | 7 天 |
| 第 2 周 | 70% | 30% | 7 天 |
| 第 3 周 | 30% | 70% | 7 天 |
| 第 4 周 | 0% | 100% | - |
每阶段监控指标,有问题回滚。
10. 灰度代码
def get_provider(user_id):
"""灰度发布版本"""
# 10% → A
if get_rollout_group(user_id, 'serpbase_rollout', percentage=100):
return 'A'
return 'B' # 默认旧版本
def get_rollout_group(user_id, experiment, percentage):
h = hashlib.md5(f"{user_id}:{experiment}".encode()).hexdigest()
bucket = int(h[:8], 16) % 100
return bucket < percentage
通过调 percentage 参数控制灰度比例,平滑切流。
11. 回滚机制
灰度过程发现 A 有问题,立即回滚:
def get_provider(user_id):
percentage = get_current_rollout_percentage() # 从配置读
if percentage < 100 and has_issue_detected('A'):
# 自动回滚到 0
percentage = 0
alert('Auto rollback to 0%')
if get_rollout_group(user_id, 'serpbase_rollout', percentage):
return 'A'
return 'B'
自动检测异常 + 回滚。
12. 实战数据
我项目跑 2 个月:
- A/B 测试 7 天,流量染色分流
- 5 组 × 7 天 × 1000 次/天 = 35000 次
- 综合评分:serpbase 第一
- 灰度 4 周,100% 切换
- 0 故障
13. 工具支持
不需要自建,可用第三方:
- LaunchDarkly:商业,功能全
- GrowthBook:开源
- Unleash:开源,自托管
- 自建:Redis + 哈希分流(我项目用)
14. 总结
A/B 测试 + 流量染色 + 灰度发布:
- 哈希分流(同 user 同组)
- 5 组 × 7 天实测
- 综合评分选 provider
- 4 周灰度切流
- 自动回滚
代码 GitHub 公开,clone 跑起来。
相关链接
本文示例以 serpbase 的接口为例,完整文档和接入指南在 serpbase.dev。
更多推荐

所有评论(0)