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

38 KiB
Raw Permalink Blame History

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单轮纯文本对话

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "你好,请介绍一下你自己"
    }
  ]
}

期望 Mock 响应200 OK

{
  "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多轮对话

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "你是一个专业的编程助手,请用简洁的语言回答问题。"
    },
    {
      "role": "user",
      "content": "什么是 Go 语言的 interface"
    },
    {
      "role": "assistant",
      "content": "Go 语言的 interface 是一种类型,它定义了一组方法签名。任何实现了这些方法的类型都自动实现了该 interface无需显式声明。"
    },
    {
      "role": "user",
      "content": "能举个例子吗?"
    }
  ]
}

期望 Mock 响应200 OK

{
  "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+ 模型)

请求:

{
  "model": "o1",
  "messages": [
    {
      "role": "developer",
      "content": "你是一名数学专家。请逐步推理后再给出答案。"
    },
    {
      "role": "user",
      "content": "15 + 23 * 2 等于多少?"
    }
  ]
}

期望 Mock 响应200 OK

{
  "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工具调用 + 工具结果

请求(第一轮 - 模型调用工具):

{
  "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第一轮

{
  "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
  }
}

请求(第二轮 - 提交工具结果):

{
  "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第二轮

{
  "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

请求:

{
  "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

{
  "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

请求:

{
  "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

{
  "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

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "如何制作危险物品?"
    }
  ]
}

期望 Mock 响应200 OK

{
  "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并行多工具调用

请求:

{
  "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

{
  "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"

请求:

{
  "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

{
  "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 指定具体工具名

请求:

{
  "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

{
  "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 格式(向后兼容)

请求:

{
  "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

{
  "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 参数

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "写一首关于春天的短诗"
    }
  ],
  "temperature": 0.9,
  "top_p": 0.95
}

期望 Mock 响应200 OK

{
  "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 截断

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "请详细介绍一下人工智能的发展历史"
    }
  ],
  "max_tokens": 30
}

期望 Mock 响应200 OK

{
  "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 序列截断

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "从1数到10每行一个数字"
    }
  ],
  "stop": ["5"]
}

期望 Mock 响应200 OK

{
  "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

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "用不同的词汇描述'好'"
    }
  ],
  "frequency_penalty": 0.5,
  "presence_penalty": 0.3
}

期望 Mock 响应200 OK

{
  "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

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "提取以下信息的姓名和年龄张三今年25岁是一名工程师"
    }
  ],
  "response_format": {
    "type": "json_object"
  }
}

期望 Mock 响应200 OK

{
  "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

请求:

{
  "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

{
  "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

请求:

{
  "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

请求:

{
  "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流式工具调用

请求:

{
  "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 模型)

请求:

{
  "model": "o3",
  "messages": [
    {
      "role": "user",
      "content": "一个房间里有3个灯泡房间外有3个开关每个开关控制一个灯泡。你只能进房间一次如何确定哪个开关控制哪个灯泡"
    }
  ],
  "reasoning_effort": "high"
}

期望 Mock 响应200 OK

{
  "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

请求:

{
  "model": "nonexistent-model-xyz",
  "messages": [
    {
      "role": "user",
      "content": "你好"
    }
  ]
}

期望 Mock 响应404 Not Found

{
  "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

请求:

{
  "model": "gpt-4o"
}

期望 Mock 响应400 Bad Request

{
  "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内容安全策略拒绝

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "生成违法内容..."
    }
  ]
}

期望 Mock 响应400 Bad Request

{
  "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"

{
  "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 参数多选择

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "用一句话描述春天"
    }
  ],
  "n": 3
}

期望 Mock 响应200 OK

{
  "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 参数可复现

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "随机生成一个5位数字"
    }
  ],
  "seed": 42,
  "temperature": 0
}

期望 Mock 响应200 OK

{
  "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

请求:

{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "1+1="
    }
  ],
  "logprobs": true,
  "top_logprobs": 3
}

期望 Mock 响应200 OK

{
  "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 响应通用结构规范

非流式响应通用结构

{
  "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 通用结构

{
  "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
}

错误响应通用结构

{
  "error": {
    "message": "<human_readable_message>",
    "type": "invalid_request_error" | "authentication_error" | "api_error" | "rate_limit_error",
    "param": null | "<parameter_name>",
    "code": "<error_code>"
  }
}