14 KiB
14 KiB
兼容性检测脚本
概述
本目录包含一组用于检测 LLM API 网关对 OpenAI 和 Anthropic 协议兼容性的测试脚本。通过向目标服务发送一系列结构化请求,验证响应格式、字段类型、错误处理等是否符合协议规范。
脚本结构
scripts/
├── core.py # 公共基础设施
├── detect_openai.py # OpenAI 兼容协议测试
└── detect_anthropic.py # Anthropic 兼容协议测试
core.py — 公共模块
提供所有检测脚本共享的基础功能:
| 函数/类 | 说明 |
|---|---|
TestCase |
测试用例数据类(URL、方法、请求头、请求体、验证器) |
TestResult |
测试结果数据类(状态码、耗时、错误类型、响应内容) |
http_request() |
普通 HTTP 请求(支持重试、自动 JSON 序列化) |
http_stream_request() |
流式 HTTP 请求(SSE,支持重试) |
parse_sse_events() |
从 SSE 响应文本中提取 data: 事件列表 |
create_ssl_context() |
创建不验证证书的 SSL 上下文(测试环境用) |
run_test() |
执行单个用例并打印结构化输出 |
run_test_suite() |
执行完整测试套件并打印统计摘要 |
check_required_fields() |
检查必需字段(通用验证辅助) |
check_field_type() |
检查字段类型(通用验证辅助) |
check_enum_value() |
检查枚举值(通用验证辅助) |
check_array_items_type() |
检查数组元素类型(通用验证辅助) |
validate_response_structure() |
组合上述函数的通用验证器 |
注意:core.py 只包含协议无关的通用功能。每个协议独有的响应验证函数应定义在各自的检测脚本中(如 validate_openai_chat_completion_response 在 detect_openai.py 中)。
detect_openai.py — OpenAI 兼容测试
检测目标服务对 OpenAI Chat Completions API 的兼容程度。
覆盖的 API 端点:
GET /models— 模型列表GET /models/{model}— 模型详情POST /chat/completions— 对话补全
测试类别:
- 正面用例:基本对话、system/developer 角色、多轮对话、参数组合(temperature、top_p、seed、penalty、stop、n、max_tokens、max_completion_tokens、logit_bias、reasoning_effort、service_tier、verbosity、response_format)
- 扩展功能:
--vision(图片输入)、--stream(流式响应)、--tools(工具调用)、--logprobs(对数概率)、json_schema(结构化输出) - 负面用例:缺参数、空消息、无效认证、不存在的模型、畸形 JSON、max_tokens 负数/0、temperature 越界
响应验证:
- Models List:检查
object: "list"、data数组中每个模型的id、object、created、owned_by - Model Retrieve:检查
id、object: "model"、created、owned_by - Chat Completion:检查
id、object: "chat.completion"、created、model、choices数组结构、usage对象
detect_anthropic.py — Anthropic 兼容测试
检测目标服务对 Anthropic Messages API 的兼容程度。
覆盖的 API 端点:
GET /v1/models— 模型列表GET /v1/models/{model}— 模型详情POST /v1/messages— 消息对话POST /v1/messages/count_tokens— Token 计数
测试类别:
- 正面用例:基本对话、system prompt(字符串/数组格式)、多轮对话、assistant prefill、content 数组格式、参数组合(temperature、top_p、top_k、max_tokens、stop_sequences、metadata)
- 扩展功能:
--vision(图片输入)、--stream(流式响应)、--tools(工具调用)、--thinking(扩展思维) - 负面用例:缺 header、无效认证、缺参数、空消息、畸形 JSON、非法 role、max_tokens 负数/0、temperature 越界
响应验证:
- Models List:检查
data、has_more、每个模型的id、type: "model"、display_name、created_at - Model Retrieve:检查
id、type: "model"、display_name、created_at - Messages:检查
id、type: "message"、role: "assistant"、content数组、model、usage - Count Tokens:检查
input_tokens为数字
使用方式
基本用法
# OpenAI 兼容测试
python3 scripts/detect_openai.py --base_url http://localhost:9826/v1
# Anthropic 兼容测试
python3 scripts/detect_anthropic.py --base_url http://localhost:9826
带认证
python3 scripts/detect_openai.py --base_url http://localhost:9826/v1 --api_key sk-xxx --model gpt-4o
python3 scripts/detect_anthropic.py --base_url http://localhost:9826 --api_key sk-xxx --model claude-sonnet-4-5
扩展测试
# 开启所有扩展测试
python3 scripts/detect_openai.py --base_url http://localhost:9826/v1 --all
python3 scripts/detect_anthropic.py --base_url http://localhost:9826 --all
# 单独开启某项
python3 scripts/detect_openai.py --base_url http://localhost:9826/v1 --stream --tools
python3 scripts/detect_anthropic.py --base_url http://localhost:9826 --stream --tools --thinking
命令行参数
| 参数 | 说明 | 默认值 |
|---|---|---|
--base_url |
API 基础地址(必填) | — |
--api_key |
API 密钥 | 空 |
--model |
测试使用的模型名称 | gpt-4o / claude-sonnet-4-5 |
--vision |
执行视觉相关测试 | 关闭 |
--stream |
执行流式响应测试 | 关闭 |
--tools |
执行工具调用测试 | 关闭 |
--logprobs |
执行 logprobs 测试(仅 OpenAI) | 关闭 |
--json_schema |
执行 Structured Output 测试(仅 OpenAI) | 关闭 |
--thinking |
执行扩展思维测试(仅 Anthropic) | 关闭 |
--all |
开启所有扩展测试 | 关闭 |
输出示例
Anthropic 兼容性测试
目标: http://localhost:9826
模型: claude-sonnet-4-5
时间: 2026-04-21 10:30:00
用例: 35 个 | 扩展: stream, tools
[1/35] 获取模型列表 (GET /v1/models)
URL: GET http://localhost:9826/v1/models
Headers:
x-api-key: sk-xxx
anthropic-version: 2023-06-01
响应 (200, 0.12s):
{
"data": [...],
"has_more": false
}
✓ 响应验证通过
[5/35] 基本对话(仅 user)
URL: POST http://localhost:9826/v1/messages
Headers:
x-api-key: sk-xxx
Content-Type: application/json
入参:
{
"model": "claude-sonnet-4-5",
"max_tokens": 5,
"messages": [{"role": "user", "content": "Hi"}]
}
响应 (200, 0.23s):
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [...],
"model": "claude-sonnet-4-5",
"usage": {"input_tokens": 10, "output_tokens": 5}
}
✓ 响应验证通过
测试完成 | 总计: 35 | 成功: 33 | 客户端错误: 2 | 服务端错误: 0 | 网络错误: 0
测试设计原则
- 所有正面用例都启用响应验证器 — 任何响应结构偏差都会立即暴露,避免掩盖错误
- 负面用例覆盖常见错误场景 — 缺参数、类型错误、范围越界、认证失败
- 扩展功能通过 flag 按需开启 — 避免在基础测试中引入不必要的依赖
- 验证器基于协议规范编写 — 严格检查必需字段、类型、枚举值
- 流式与非流式覆盖一致 — 流式只是传输方式不同,功能覆盖范围应完全对应(见下文)
新增检测脚本开发流程
如需为新的协议(如 Google Gemini、Cohere 等)开发检测脚本,遵循以下流程:
1. 在新脚本中定义协议专用的验证函数
每个协议的响应结构是独特的,验证函数应定义在各自的脚本中,不要放入 core.py。例如:
# 在 detect_gemini.py 中
def validate_gemini_generate_content_response(response_text: str) -> Tuple[bool, List[str]]:
"""验证 Gemini GenerateContent 响应"""
errors = []
try:
data = json.loads(response_text)
except json.JSONDecodeError as e:
return False, [f"响应不是有效的JSON: {e}"]
# 检查 Gemini 特有的字段
required_fields = ["candidates", "usageMetadata"]
for field in required_fields:
if field not in data:
errors.append(f"缺少必需字段: {field}")
...
return len(errors) == 0, errors
2. 在 core.py 中只添加通用验证辅助
只有当多个协议都需要相同的验证逻辑时,才将函数提取到 core.py。目前已有的通用函数:
| 函数 | 说明 |
|---|---|
check_required_fields() |
检查必需字段是否存在 |
check_field_type() |
检查字段类型 |
check_enum_value() |
检查枚举值 |
check_array_items_type() |
检查数组元素类型 |
validate_response_structure() |
组合上述函数的通用验证器 |
parse_sse_events() |
从 SSE 响应文本中提取 data: 事件 |
3. 创建检测脚本模板
#!/usr/bin/env python3
"""新协议兼容性接口测试脚本"""
import json
import argparse
from typing import Dict, List, Tuple, Any
from core import (
create_ssl_context,
TestCase,
run_test_suite,
validate_response_structure,
)
def build_headers(api_key: str) -> Dict[str, str]:
"""构建请求头"""
...
def validate_xxx_response(response_text: str) -> Tuple[bool, List[str]]:
"""验证响应结构(协议专用)"""
...
def validate_xxx_streaming_response(response_text: str) -> Tuple[bool, List[str]]:
"""验证流式响应结构(协议专用)"""
from core import parse_sse_events
...
def main():
parser = argparse.ArgumentParser(...)
parser.add_argument("--base_url", required=True, ...)
parser.add_argument("--api_key", default="", ...)
parser.add_argument("--model", default="...", ...)
parser.add_argument("--stream", action="store_true", ...)
parser.add_argument("--all", action="store_true", ...)
args = parser.parse_args()
cases: List[TestCase] = []
# ---- 共享定义(供流式和非流式用例共同使用)----
# 将 tool、image_url 等定义放在所有功能块之前,
# 避免流式和非流式块中重复定义
tool_xxx = { ... }
image_url = "..."
# ==== 非流式正面用例(都添加 validator)====
cases.append(TestCase(
desc="...", method="...", url=..., headers=..., body=...,
validator=validate_xxx_response
))
# ==== 非流式负面用例(不添加 validator)====
cases.append(TestCase(desc="...", method="...", url=..., headers=..., body=...))
# ==== --stream ====
if args.stream:
# 核心对话流式用例:每个非流式正面用例都应有对应的流式版本
# 仅传输方式不同(stream=True, stream=True),
# 功能覆盖(参数、角色、多轮等)必须与非流式一致
cases.append(TestCase(
desc="流式...", method="POST", url=..., headers=headers,
body={ ..., "stream": True },
stream=True,
validator=validate_xxx_streaming_response
))
# 流式 + 其他 flag 组合(放在 --stream 块内部)
if args.vision:
cases.append(TestCase(
desc="流式图片输入 (--stream + --vision)",
...,
stream=True,
validator=validate_xxx_streaming_response
))
if args.tools:
cases.append(TestCase(
desc="流式工具调用 (--stream + --tools)",
...,
stream=True,
validator=validate_xxx_streaming_response
))
run_test_suite(cases=cases, ssl_ctx=ssl_ctx, title="...", base_url=..., model=..., flags=...)
if __name__ == "__main__":
main()
关键要点
- 协议专用验证函数放在各自的脚本中 — 不要污染
core.py - 只有多协议通用的验证逻辑才提取到
core.py— 遵循 DRY 原则但不过度抽象 - 所有正面用例必须添加 validator — 确保响应结构正确
- 负面用例不添加 validator — 预期返回错误响应
- 扩展功能用 flag 控制 — 保持基础测试轻量
- 遵循现有命名和代码风格 — 中文注释、类型注解、dataclass 使用
流式测试覆盖原则
流式(SSE)与非流式只是数据传输方式不同,服务端对请求参数的处理逻辑应完全一致。因此:
- 每个非流式正面用例都应有对应的流式版本 — 包括不同的消息角色组合、参数组合、工具调用等
- 共享定义提前声明 —
tool、image_url、json_schema等定义放在所有功能块之前,流式和非流式共用同一实例,避免重复定义 - flag 组合放在
--stream块内部 — 流式+工具、流式+视觉等组合用例放在if args.stream:内部的if args.tools:/if args.vision:子块中,不需要单独的组合 flag - 负面用例不需要流式版本 — 参数校验发生在请求处理之前,与传输方式无关
- Models API 等非 Chat 端点不需要流式测试 — 它们本身不支持流式传输
| 用例类别 | 非流式 | 流式 |
|---|---|---|
| 基本对话 / 多轮对话 | ✓ | ✓ |
| 消息角色组合(system, developer 等) | ✓ | ✓ |
| 参数组合(temperature, top_p, max_tokens 等) | ✓ | ✓ |
| 工具调用(tool_choice 各模式) | ✓ | ✓(在 --stream 块内检查 --tools) |
| 视觉(图片输入) | ✓ | ✓(在 --stream 块内检查 --vision) |
| 扩展思维 / Logprobs 等特性 | ✓ | ✓(在 --stream 块内检查对应 flag) |
| 高级参数(service_tier, reasoning_effort 等) | ✓ | ✓ |
| 负面用例(缺参数、越界、认证失败) | ✓ | ✗(参数校验与传输方式无关) |
| Models API(GET 端点) | ✓ | ✗(不支持流式) |
许可证
MIT