1
0
Files
nex/docs/api_reference/test_mock_openai.md
lanyuanxiaoyao bc1ee612d9 refactor: 实现 ConversionEngine 协议转换引擎,替代旧 protocol 包
- 新增 ConversionEngine 核心引擎,支持 OpenAI 和 Anthropic 协议转换
- 添加 stream decoder/encoder 实现
- 更新 provider client 支持新引擎
- 补充单元测试和集成测试
- 更新 specs 文档
2026-04-20 13:02:28 +08:00

1727 lines
38 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenAI Chat Completion API 端到端测试用例与 Mock 设计
本文档针对 `POST /chat/completions` 接口,设计端到端测试用例及对应的 Mock 返回值结构。
---
## 一、测试场景总览
| 分类 | 测试用例 | 优先级 |
|------|----------|--------|
| 基础对话 | 1. 单轮纯文本对话 | P0 |
| 基础对话 | 2. 多轮对话system + user + assistant + user | P0 |
| 消息类型 | 3. developer 消息o1+ 模型) | P1 |
| 消息类型 | 4. 带 tool_calls 的 assistant 消息 + tool 消息 | P0 |
| 消息内容 | 5. 用户消息含图片 URLvision | P1 |
| 消息内容 | 6. 用户消息含多模态内容text + image | P1 |
| 消息内容 | 7. assistant 消息含 refusal | P1 |
| 工具调用 | 8. 单工具调用function tool | P0 |
| 工具调用 | 9. 并行多工具调用parallel_tool_calls | P1 |
| 工具调用 | 10. tool_choice 为 "none" | P2 |
| 工具调用 | 11. tool_choice 指定具体工具名 | P2 |
| 工具调用 | 12. 废弃的 function_call 格式(向后兼容) | P2 |
| 参数控制 | 13. temperature + top_p | P1 |
| 参数控制 | 14. max_tokens 截断 | P1 |
| 参数控制 | 15. stop 序列截断 | P2 |
| 参数控制 | 16. frequency_penalty + presence_penalty | P2 |
| 响应格式 | 17. response_format 为 json_object | P1 |
| 响应格式 | 18. response_format 为 json_schemastructured output | P1 |
| 流式响应 | 19. 流式文本响应SSE | P0 |
| 流式响应 | 20. 流式 + stream_options include_usage | P1 |
| 流式响应 | 21. 流式工具调用 | P1 |
| 推理模型 | 22. reasoning_effort 参数o1/o3 模型) | P2 |
| 错误处理 | 23. 无效 model 返回 404 | P1 |
| 错误处理 | 24. 缺少 messages 返回 400 | P1 |
| 错误处理 | 25. 内容安全策略拒绝content_filter | P2 |
| 其他 | 26. n 参数多选择multiple choices | P2 |
| 其他 | 27. seed 参数可复现 | P2 |
| 其他 | 28. logprobs + top_logprobs | P2 |
---
## 二、测试用例详情
### 用例 1单轮纯文本对话
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "你好,请介绍一下你自己"
}
]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-001",
"object": "chat.completion",
"created": 1700000000,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你好!我是由 OpenAI 开发的 AI 助手 GPT-4。我可以帮你回答问题、写作、编程、数学推理等任务。请问有什么我可以帮你的"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 15,
"completion_tokens": 42,
"total_tokens": 57
},
"system_fingerprint": "fp_test123"
}
```
**验证点:**
- `choices[0].message.role` == `"assistant"`
- `choices[0].message.content` 非空
- `choices[0].finish_reason` == `"stop"`
- `usage` 字段完整
---
### 用例 2多轮对话
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "system",
"content": "你是一个专业的编程助手,请用简洁的语言回答问题。"
},
{
"role": "user",
"content": "什么是 Go 语言的 interface"
},
{
"role": "assistant",
"content": "Go 语言的 interface 是一种类型,它定义了一组方法签名。任何实现了这些方法的类型都自动实现了该 interface无需显式声明。"
},
{
"role": "user",
"content": "能举个例子吗?"
}
]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-002",
"object": "chat.completion",
"created": 1700000001,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "当然。例如定义一个 `Reader` interface\n\n```go\ntype Reader interface {\n Read(p []byte) (n int, err error)\n}\n```\n\n`os.File` 和 `bytes.Buffer` 都实现了 `Read` 方法,所以它们都自动实现了 `Reader` interface。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 120,
"completion_tokens": 65,
"total_tokens": 185
},
"system_fingerprint": "fp_test123"
}
```
**验证点:**
- 多轮上下文正确传递
- 响应与上下文连贯
---
### 用例 3developer 消息o1+ 模型)
**请求:**
```json
{
"model": "o1",
"messages": [
{
"role": "developer",
"content": "你是一名数学专家。请逐步推理后再给出答案。"
},
{
"role": "user",
"content": "15 + 23 * 2 等于多少?"
}
]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-003",
"object": "chat.completion",
"created": 1700000002,
"model": "o1",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "根据运算优先级先算乘法23 * 2 = 46再加 1546 + 15 = 61。答案是 61。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 35,
"completion_tokens": 48,
"total_tokens": 83,
"completion_tokens_details": {
"reasoning_tokens": 20
}
},
"system_fingerprint": "fp_test123"
}
```
**验证点:**
- developer 角色被正确处理
- reasoning_tokens 在详情中体现
---
### 用例 4工具调用 + 工具结果
**请求(第一轮 - 模型调用工具):**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "北京今天天气怎么样?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto"
}
```
**期望 Mock 响应200 OK第一轮**
```json
{
"id": "chatcmpl-test-004a",
"object": "chat.completion",
"created": 1700000003,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\"}"
}
}
]
},
"finish_reason": "tool_calls",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 80,
"completion_tokens": 18,
"total_tokens": 98
}
}
```
**请求(第二轮 - 提交工具结果):**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "北京今天天气怎么样?"
},
{
"role": "assistant",
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": "北京今天晴,气温 25°C东南风 2 级。"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
}
}
]
}
```
**期望 Mock 响应200 OK第二轮**
```json
{
"id": "chatcmpl-test-004b",
"object": "chat.completion",
"created": 1700000004,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "北京今天天气很好,晴天,气温 25°C东南风 2 级,适合外出活动。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 120,
"completion_tokens": 30,
"total_tokens": 150
}
}
```
**验证点:**
- 第一轮 `finish_reason` == `"tool_calls"`
- `tool_calls` 包含正确的 function name 和 arguments
- 第二轮能基于工具结果生成自然语言回复
---
### 用例 5用户消息含图片 URLvision
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "这张图片里有什么?"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/images/cat.jpg",
"detail": "high"
}
}
]
}
]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-005",
"object": "chat.completion",
"created": 1700000005,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "图片中有一只橘色的猫,它正躺在沙发上晒太阳。猫的毛色是橘白相间的,眼睛是绿色的,看起来非常放松。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 280,
"completion_tokens": 45,
"total_tokens": 325
}
}
```
**验证点:**
- 图片 URL 被正确传递
- 响应描述图片内容
---
### 用例 6用户消息含多模态内容text + image
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "请比较这两张图片有什么不同"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/images/before.jpg"
}
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/images/after.jpg"
}
}
]
}
]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-006",
"object": "chat.completion",
"created": 1700000006,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "两张图片的主要区别:\n1. 第一张是白天的场景,第二张是夜晚\n2. 灯光从自然光变成了暖黄色的室内灯光\n3. 桌上的物品摆放位置有所不同"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 520,
"completion_tokens": 55,
"total_tokens": 575
}
}
```
---
### 用例 7assistant 消息含 refusal
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "如何制作危险物品?"
}
]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-007",
"object": "chat.completion",
"created": 1700000007,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"refusal": "抱歉,我无法提供涉及危险活动的信息。我的设计目的是提供有益和安全的帮助。如果你有其他问题,我很乐意协助。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 35,
"total_tokens": 47
}
}
```
**验证点:**
- `refusal` 字段存在且非空
- `content` 为 null 或空
---
### 用例 8单工具调用function tool
同用例 4 第一轮。
---
### 用例 9并行多工具调用
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "帮我查一下北京、上海、广州三个城市的天气"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto"
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-009",
"object": "chat.completion",
"created": 1700000009,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_001",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\"}"
}
},
{
"id": "call_002",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"上海\"}"
}
},
{
"id": "call_003",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"广州\"}"
}
}
]
},
"finish_reason": "tool_calls",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 95,
"completion_tokens": 55,
"total_tokens": 150
}
}
```
**验证点:**
- `tool_calls` 数组长度 == 3
- 每个 call 有不同 ID 和参数
---
### 用例 10tool_choice 为 "none"
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "随便聊聊"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
}
}
}
}
],
"tool_choice": "none"
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-010",
"object": "chat.completion",
"created": 1700000010,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "好的!今天天气不错,很适合聊天。你想聊些什么话题呢?可以是技术、生活、娱乐等任何你感兴趣的内容。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 50,
"completion_tokens": 35,
"total_tokens": 85
}
}
```
**验证点:**
- 尽管定义了 tools响应中不包含 `tool_calls`
- 纯文本回复
---
### 用例 11tool_choice 指定具体工具名
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "查天气"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取天气",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}}
}
},
{
"type": "function",
"function": {
"name": "get_news",
"description": "获取新闻",
"parameters": {"type": "object", "properties": {"topic": {"type": "string"}}}
}
}
],
"tool_choice": {
"type": "function",
"function": {"name": "get_weather"}
}
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-011",
"object": "chat.completion",
"created": 1700000011,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_weather1",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{}"
}
}
]
},
"finish_reason": "tool_calls",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 80,
"completion_tokens": 15,
"total_tokens": 95
}
}
```
**验证点:**
- 强制使用了 `get_weather` 而非 `get_news`
---
### 用例 12废弃的 function_call 格式(向后兼容)
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "查天气"
}
],
"functions": [
{
"name": "get_weather",
"description": "获取天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}
],
"function_call": "auto"
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-012",
"object": "chat.completion",
"created": 1700000012,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"function_call": {
"name": "get_weather",
"arguments": "{\"city\": \"北京\"}"
}
},
"finish_reason": "function_call",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 60,
"completion_tokens": 20,
"total_tokens": 80
}
}
```
**验证点:**
- 废弃的 `functions`/`function_call` 格式仍能被正确处理
- `finish_reason` == `"function_call"`(而非 `"tool_calls"`
---
### 用例 13temperature + top_p 参数
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "写一首关于春天的短诗"
}
],
"temperature": 0.9,
"top_p": 0.95
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-013",
"object": "chat.completion",
"created": 1700000013,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "春风拂面花自开,\n柳絮飞舞满园香。\n燕归巢中呢喃语\n万物复苏迎朝阳。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 32,
"total_tokens": 50
}
}
```
---
### 用例 14max_tokens 截断
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "请详细介绍一下人工智能的发展历史"
}
],
"max_tokens": 30
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-014",
"object": "chat.completion",
"created": 1700000014,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "人工智能起源于1950年代图灵提出了机器能否思考的问题。1956年达特茅斯会议正式确立了AI领域。此后经历了多次起伏..."
},
"finish_reason": "length",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 20,
"completion_tokens": 30,
"total_tokens": 50
}
}
```
**验证点:**
- `finish_reason` == `"length"`
- `completion_tokens` == 30等于 max_tokens
- 内容被截断
---
### 用例 15stop 序列截断
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "从1数到10每行一个数字"
}
],
"stop": ["5"]
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-015",
"object": "chat.completion",
"created": 1700000015,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "1\n2\n3\n4\n"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 10,
"total_tokens": 28
}
}
```
**验证点:**
- `finish_reason` == `"stop"`
- 内容在遇到 stop 序列时截断
---
### 用例 16frequency_penalty + presence_penalty
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "用不同的词汇描述'好'"
}
],
"frequency_penalty": 0.5,
"presence_penalty": 0.3
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-016",
"object": "chat.completion",
"created": 1700000016,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "优秀、出色、精彩、卓越、非凡、完美、绝佳、美妙、精彩、杰出"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 15,
"total_tokens": 33
}
}
```
---
### 用例 17response_format 为 json_object
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "提取以下信息的姓名和年龄张三今年25岁是一名工程师"
}
],
"response_format": {
"type": "json_object"
}
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-017",
"object": "chat.completion",
"created": 1700000017,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\"name\": \"张三\", \"age\": 25, \"occupation\": \"工程师\"}"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 35,
"completion_tokens": 25,
"total_tokens": 60
}
}
```
**验证点:**
- `content` 是合法的 JSON 字符串
---
### 用例 18response_format 为 json_schemastructured output
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "创建一个用户信息记录姓名李四年龄30岁"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "user_info",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"email": {"type": "string"}
},
"required": ["name", "age"]
},
"strict": true
}
}
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-018",
"object": "chat.completion",
"created": 1700000018,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\"name\": \"李四\", \"age\": 30}"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 85,
"completion_tokens": 18,
"total_tokens": 103
}
}
```
**验证点:**
- 输出严格符合 JSON schema 定义
- 不包含 schema 未定义的字段
---
### 用例 19流式文本响应SSE
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "你好"
}
],
"stream": true
}
```
**期望 Mock 响应200 OK, Content-Type: text/event-stream**
```
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"你"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"好"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"!我"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"是"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"AI"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"助手"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"很高兴"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"为你"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"服务"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"。"},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-001","object":"chat.completion.chunk","created":1700000019,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
```
**验证点:**
- 每个 chunk 的 `id` 一致
- 第一个 chunk 的 `delta` 包含 `role`
- 中间 chunk 的 `delta` 只包含 `content`
- 最后一个 chunk 包含 `finish_reason`
-`[DONE]` 结束
---
### 用例 20流式 + stream_options include_usage
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "你好"
}
],
"stream": true,
"stream_options": {
"include_usage": true
}
}
```
**期望 Mock 响应200 OK, Content-Type: text/event-stream**
最后一个 chunk 之前增加一个 usage chunk
```
data: {"id":"chatcmpl-stream-020","object":"chat.completion.chunk","created":1700000020,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
... (中间内容 chunk) ...
data: {"id":"chatcmpl-stream-020","object":"chat.completion.chunk","created":1700000020,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-stream-020","object":"chat.completion.chunk","created":1700000020,"model":"gpt-4o","choices":[],"usage":{"prompt_tokens":10,"completion_tokens":25,"total_tokens":35}}
data: [DONE]
```
**验证点:**
- 倒数第二个 chunk 包含 `usage` 字段
- 该 chunk 的 `choices` 为空数组
---
### 用例 21流式工具调用
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "北京天气怎么样?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}
}
],
"stream": true
}
```
**期望 Mock 响应200 OK, Content-Type: text/event-stream**
```
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":null},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_stream1","type":"function","function":{"name":"get_weather","arguments":""}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"city"}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"北京"}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"}\"}"}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-stream-021","object":"chat.completion.chunk","created":1700000021,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
data: [DONE]
```
**验证点:**
- 第一个 chunk 包含 `role`
- tool_calls 通过增量 chunk 逐步拼接
- 最后一个 chunk 的 `finish_reason` == `"tool_calls"`
---
### 用例 22reasoning_effort 参数o1/o3 模型)
**请求:**
```json
{
"model": "o3",
"messages": [
{
"role": "user",
"content": "一个房间里有3个灯泡房间外有3个开关每个开关控制一个灯泡。你只能进房间一次如何确定哪个开关控制哪个灯泡"
}
],
"reasoning_effort": "high"
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-022",
"object": "chat.completion",
"created": 1700000022,
"model": "o3",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "解决方案:\n\n1. 打开第一个开关,等待几分钟\n2. 关闭第一个开关,打开第二个开关\n3. 立即进入房间\n\n此时\n- 亮着的灯由第二个开关控制\n- 摸起来发热的灯由第一个开关控制(因为开过几分钟)\n- 既不亮也不热的灯由第三个开关控制"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 85,
"completion_tokens": 120,
"total_tokens": 205,
"completion_tokens_details": {
"reasoning_tokens": 80
}
}
}
```
**验证点:**
- reasoning_tokens 显著增加
- 响应展示推理结果
---
### 用例 23无效 model 返回 404
**请求:**
```json
{
"model": "nonexistent-model-xyz",
"messages": [
{
"role": "user",
"content": "你好"
}
]
}
```
**期望 Mock 响应404 Not Found**
```json
{
"error": {
"message": "The model `nonexistent-model-xyz` does not exist or you do not have access to it.",
"type": "invalid_request_error",
"param": null,
"code": "model_not_found"
}
}
```
---
### 用例 24缺少 messages 返回 400
**请求:**
```json
{
"model": "gpt-4o"
}
```
**期望 Mock 响应400 Bad Request**
```json
{
"error": {
"message": "'messages' is a required property and must be a non-empty array.",
"type": "invalid_request_error",
"param": null,
"code": "missing_required_field"
}
}
```
---
### 用例 25内容安全策略拒绝
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "生成违法内容..."
}
]
}
```
**期望 Mock 响应400 Bad Request**
```json
{
"error": {
"message": "The content you submitted may violate our usage policies.",
"type": "invalid_request_error",
"param": null,
"code": "content_filter"
}
}
```
或者作为 completion 返回finish_reason = "content_filter"
```json
{
"id": "chatcmpl-test-025",
"object": "chat.completion",
"created": 1700000025,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"refusal": "我无法生成此类内容。"
},
"finish_reason": "content_filter",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 15,
"completion_tokens": 8,
"total_tokens": 23
}
}
```
---
### 用例 26n 参数多选择
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "用一句话描述春天"
}
],
"n": 3
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-026",
"object": "chat.completion",
"created": 1700000026,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "春天是万物复苏、百花盛开的季节。"
},
"finish_reason": "stop",
"logprobs": null
},
{
"index": 1,
"message": {
"role": "assistant",
"content": "春风拂面,绿意盎然,处处洋溢着生机与希望。"
},
"finish_reason": "stop",
"logprobs": null
},
{
"index": 2,
"message": {
"role": "assistant",
"content": "冬雪消融,嫩芽破土,春天带着温暖悄然而至。"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 60,
"total_tokens": 78
}
}
```
**验证点:**
- `choices` 数组长度为 3
- 每个 choice 有不同的 `index`
---
### 用例 27seed 参数可复现
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "随机生成一个5位数字"
}
],
"seed": 42,
"temperature": 0
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-027",
"object": "chat.completion",
"created": 1700000027,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "12345"
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 5,
"total_tokens": 23
},
"system_fingerprint": "fp_test_seed42"
}
```
**验证点:**
- 相同 seed + temperature=0 应产生相同输出
- `system_fingerprint` 可用于验证 backend 一致性
---
### 用例 28logprobs + top_logprobs
**请求:**
```json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": "1+1="
}
],
"logprobs": true,
"top_logprobs": 3
}
```
**期望 Mock 响应200 OK**
```json
{
"id": "chatcmpl-test-028",
"object": "chat.completion",
"created": 1700000028,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "2"
},
"finish_reason": "stop",
"logprobs": {
"content": [
{
"token": "2",
"logprob": -0.001,
"bytes": [50],
"top_logprobs": [
{"token": "2", "logprob": -0.001, "bytes": [50]},
{"token": "二", "logprob": -3.5, "bytes": [201, 147]},
{"token": " two", "logprob": -5.2, "bytes": [32, 116, 119, 111]}
]
}
],
"refusal": null
}
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 1,
"total_tokens": 11
}
}
```
**验证点:**
- `logprobs.content` 数组包含每个生成 token 的概率信息
- `top_logprobs` 包含前 K 个候选 token
---
## 三、Mock 响应通用结构规范
### 非流式响应通用结构
```json
{
"id": "chatcmpl-<unique_id>",
"object": "chat.completion",
"created": <unix_timestamp>,
"model": "<model_name>",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "<text>" | null,
"refusal": "<text>" | null,
"tool_calls": [
{
"id": "call_<id>",
"type": "function" | "custom",
"function": {"name": "<name>", "arguments": "<json_string>"} | null,
"custom": {"name": "<name>", "input": "<json_string>"} | null
}
]
},
"finish_reason": "stop" | "length" | "tool_calls" | "content_filter" | "function_call",
"logprobs": null | { "content": [...], "refusal": null }
}
],
"usage": {
"prompt_tokens": <int>,
"completion_tokens": <int>,
"total_tokens": <int>,
"prompt_tokens_details": {
"cached_tokens": <int> | null,
"audio_tokens": <int> | null
},
"completion_tokens_details": {
"reasoning_tokens": <int> | null,
"audio_tokens": <int> | null,
"accepted_prediction_tokens": <int> | null,
"rejected_prediction_tokens": <int> | null
}
},
"system_fingerprint": "<fingerprint>" | null,
"service_tier": "auto" | "default" | "flex" | null
}
```
### 流式 Chunk 通用结构
```json
{
"id": "chatcmpl-<unique_id>",
"object": "chat.completion.chunk",
"created": <unix_timestamp>,
"model": "<model_name>",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant" | null,
"content": "<text_chunk>" | null,
"refusal": "<text_chunk>" | null,
"tool_calls": [
{
"index": <int>,
"id": "call_<id>" | null,
"type": "function" | "custom" | null,
"function": {"name": "<name>" | null, "arguments": "<partial_json>"} | null,
"custom": {"name": "<name>" | null, "input": "<partial_json>"} | null
}
]
},
"finish_reason": "stop" | "length" | "tool_calls" | "content_filter" | null,
"logprobs": null | { ... }
}
],
"usage": { ... } | null,
"system_fingerprint": "<fingerprint>" | null
}
```
### 错误响应通用结构
```json
{
"error": {
"message": "<human_readable_message>",
"type": "invalid_request_error" | "authentication_error" | "api_error" | "rate_limit_error",
"param": null | "<parameter_name>",
"code": "<error_code>"
}
}
```