- 新增 ConversionEngine 核心引擎,支持 OpenAI 和 Anthropic 协议转换 - 添加 stream decoder/encoder 实现 - 更新 provider client 支持新引擎 - 补充单元测试和集成测试 - 更新 specs 文档
1716 lines
38 KiB
Markdown
1716 lines
38 KiB
Markdown
# Anthropic Messages API 端到端测试用例与 Mock 设计
|
||
|
||
本文档针对 `POST /v1/messages` 接口,设计端到端测试用例及对应的 Mock 返回值结构。
|
||
|
||
---
|
||
|
||
## 一、测试场景总览
|
||
|
||
| 分类 | 测试用例 | 优先级 |
|
||
|------|----------|--------|
|
||
| 基础对话 | 1. 单轮纯文本对话 | P0 |
|
||
| 基础对话 | 2. 多轮对话(user + assistant + user) | P0 |
|
||
| 系统消息 | 3. 字符串 system prompt | P0 |
|
||
| 系统消息 | 4. 数组 system prompt(多文本块) | P1 |
|
||
| 消息内容 | 5. 用户消息含图片(base64 source) | P1 |
|
||
| 消息内容 | 6. 用户消息含图片(URL source) | P1 |
|
||
| 消息内容 | 7. 用户消息含 tool_result 内容块 | P0 |
|
||
| 工具调用 | 8. 单工具调用 | P0 |
|
||
| 工具调用 | 9. 并行多工具调用 | P1 |
|
||
| 工具调用 | 10. tool_choice 为 "none" | P2 |
|
||
| 工具调用 | 11. tool_choice 指定具体工具名 | P2 |
|
||
| 工具调用 | 12. tool_choice 为 "any"(强制调用) | P2 |
|
||
| 参数控制 | 13. temperature + top_p + top_k | P1 |
|
||
| 参数控制 | 14. max_tokens 截断 | P1 |
|
||
| 参数控制 | 15. stop_sequences 截断 | P2 |
|
||
| 扩展思考 | 16. thinking enabled(extended thinking) | P1 |
|
||
| 扩展思考 | 17. thinking adaptive | P2 |
|
||
| 输出格式 | 18. output_config 为 json_object | P1 |
|
||
| 输出格式 | 19. output_config 为 json_schema(structured output) | P1 |
|
||
| 流式响应 | 20. 流式文本响应(SSE) | P0 |
|
||
| 流式响应 | 21. 流式工具调用 | P1 |
|
||
| 流式响应 | 22. 流式 + thinking 内容 | P1 |
|
||
| 缓存控制 | 23. system prompt cache_control(ephemeral) | P2 |
|
||
| 元数据 | 24. metadata.user_id | P2 |
|
||
| 错误处理 | 25. 无效 model 返回 400 | P1 |
|
||
| 错误处理 | 26. 缺少 max_tokens 返回 400 | P1 |
|
||
| 错误处理 | 27. 缺少 messages 返回 400 | P1 |
|
||
| 错误处理 | 28. 内容安全策略拒绝(refusal) | P2 |
|
||
| 其他 | 29. disable_parallel_tool_use | P2 |
|
||
| 其他 | 30. container 复用 | P2 |
|
||
|
||
---
|
||
|
||
## 二、测试用例详情
|
||
|
||
### 用例 1:单轮纯文本对话
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "你好,请介绍一下你自己"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test001",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "你好!我是 Claude,由 Anthropic 开发的 AI 助手。我可以帮你回答问题、写作、编程、数学推理、数据分析等多种任务。我的知识截止到 2025 年 1 月。请问有什么我可以帮你的?"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 15,
|
||
"output_tokens": 68
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `content[0].type` == `"text"`
|
||
- `stop_reason` == `"end_turn"`
|
||
- `usage` 字段完整
|
||
|
||
---
|
||
|
||
### 用例 2:多轮对话
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "什么是 Go 语言的 interface?"
|
||
},
|
||
{
|
||
"role": "assistant",
|
||
"content": "Go 语言的 interface 是一种类型,它定义了一组方法签名。任何实现了这些方法的类型都自动实现了该 interface,无需显式声明。这是 Go 语言"隐式接口"设计的核心特点。"
|
||
},
|
||
{
|
||
"role": "user",
|
||
"content": "能举个例子吗?"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test002",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "当然。例如定义一个 `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,无需显式声明 `implements Reader`。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 120,
|
||
"output_tokens": 85
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 3:字符串 system prompt
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"system": "你是一个专业的编程助手,请用简洁的语言回答问题。",
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "什么是递归?"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test003",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "递归是一种函数调用自身来解决问题的方法。它包含两个关键部分:\n\n1. **基准情况**:直接返回结果的终止条件\n2. **递归情况**:将问题分解为更小的子问题,调用自身解决\n\n例如计算阶乘:`n! = n × (n-1)!`,基准情况是 `0! = 1`。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 45,
|
||
"output_tokens": 72
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 4:数组 system prompt(多文本块)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"system": [
|
||
{
|
||
"type": "text",
|
||
"text": "你是一个专业的编程助手。"
|
||
},
|
||
{
|
||
"type": "text",
|
||
"text": "请用简洁的语言回答问题,并尽量提供代码示例。"
|
||
}
|
||
],
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "什么是闭包?"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test004",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "闭包是指函数可以访问并"记住"其定义时所在作用域中的变量,即使在该作用域已经执行完毕后仍然可以访问。\n\n```javascript\nfunction makeCounter() {\n let count = 0;\n return function() {\n count++;\n return count;\n };\n}\nconst counter = makeCounter();\nconsole.log(counter()); // 1\nconsole.log(counter()); // 2\n```\n\n`count` 变量被内部函数"捕获",形成了闭包。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 85,
|
||
"output_tokens": 95
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 5:用户消息含图片(base64 source)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "这张图片里有什么?"
|
||
},
|
||
{
|
||
"type": "image",
|
||
"source": {
|
||
"type": "base64",
|
||
"media_type": "image/jpeg",
|
||
"data": "/9j/4AAQSkZJRgABAQEAYABgAAD..."
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test005",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "图片中有一只橘色的猫,它正躺在棕色的沙发上晒太阳。猫的毛色是橘白相间的,眼睛是绿色的,看起来非常放松和满足。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 1280,
|
||
"output_tokens": 45
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 6:用户消息含图片(URL source)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "请描述这张图片"
|
||
},
|
||
{
|
||
"type": "image",
|
||
"source": {
|
||
"type": "url",
|
||
"url": "https://example.com/images/landscape.jpg"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test006",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "这是一幅美丽的自然风景图。前景是一片翠绿的草地,点缀着野花。中景有一条蜿蜒的小河,河水清澈见底。远处是连绵起伏的青山,山顶覆盖着白雪。天空湛蓝,飘着几朵白云。整体画面给人一种宁静祥和的感觉。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 1520,
|
||
"output_tokens": 82
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 7:用户消息含 tool_result 内容块
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "北京天气怎么样?"
|
||
},
|
||
{
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test001",
|
||
"name": "get_weather",
|
||
"input": {"city": "北京"}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"role": "user",
|
||
"content": [
|
||
{
|
||
"type": "tool_result",
|
||
"tool_use_id": "toolu_01test001",
|
||
"content": "北京今天晴,气温 25°C,东南风 2 级。"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取指定城市的天气信息",
|
||
"input_schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"city": {
|
||
"type": "string",
|
||
"description": "城市名称"
|
||
}
|
||
},
|
||
"required": ["city"]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test007",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "北京今天天气很好,晴天,气温 25°C,东南风 2 级,非常适合外出活动。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 250,
|
||
"output_tokens": 35
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- 能正确理解 tool_result 内容
|
||
- 基于工具返回结果生成自然语言回复
|
||
|
||
---
|
||
|
||
### 用例 8:单工具调用
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "北京天气怎么样?"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取指定城市的天气信息",
|
||
"input_schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"city": {
|
||
"type": "string",
|
||
"description": "城市名称"
|
||
}
|
||
},
|
||
"required": ["city"]
|
||
}
|
||
}
|
||
],
|
||
"tool_choice": {
|
||
"type": "auto"
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test008",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test008",
|
||
"name": "get_weather",
|
||
"input": {
|
||
"city": "北京"
|
||
}
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "tool_use",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 180,
|
||
"output_tokens": 42
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `stop_reason` == `"tool_use"`
|
||
- `content[0].type` == `"tool_use"`
|
||
- `input` 包含正确的参数
|
||
|
||
---
|
||
|
||
### 用例 9:并行多工具调用
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "帮我查一下北京、上海、广州三个城市的天气"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取指定城市的天气信息",
|
||
"input_schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"city": {"type": "string"}
|
||
},
|
||
"required": ["city"]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test009",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test009a",
|
||
"name": "get_weather",
|
||
"input": {"city": "北京"}
|
||
},
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test009b",
|
||
"name": "get_weather",
|
||
"input": {"city": "上海"}
|
||
},
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test009c",
|
||
"name": "get_weather",
|
||
"input": {"city": "广州"}
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "tool_use",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 200,
|
||
"output_tokens": 120
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `content` 数组包含 3 个 tool_use 块
|
||
- 每个 tool_use 有不同的 ID
|
||
|
||
---
|
||
|
||
### 用例 10:tool_choice 为 "none"
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "随便聊聊"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取天气",
|
||
"input_schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"city": {"type": "string"}
|
||
}
|
||
}
|
||
}
|
||
],
|
||
"tool_choice": {
|
||
"type": "none"
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test010",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "好的!今天天气不错,很适合聊天。你想聊些什么话题呢?可以是技术、生活、娱乐等任何你感兴趣的内容。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 150,
|
||
"output_tokens": 42
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- 尽管定义了 tools,响应中不包含 tool_use 块
|
||
- 纯文本回复
|
||
|
||
---
|
||
|
||
### 用例 11:tool_choice 指定具体工具名
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "查天气"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取天气",
|
||
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}
|
||
},
|
||
{
|
||
"name": "get_news",
|
||
"description": "获取新闻",
|
||
"input_schema": {"type": "object", "properties": {"topic": {"type": "string"}}}
|
||
}
|
||
],
|
||
"tool_choice": {
|
||
"type": "tool",
|
||
"name": "get_weather"
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test011",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test011",
|
||
"name": "get_weather",
|
||
"input": {}
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "tool_use",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 200,
|
||
"output_tokens": 35
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- 强制使用了 `get_weather` 而非 `get_news`
|
||
|
||
---
|
||
|
||
### 用例 12:tool_choice 为 "any"(强制调用)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "帮我做点什么"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取天气",
|
||
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}
|
||
}
|
||
],
|
||
"tool_choice": {
|
||
"type": "any"
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test012",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test012",
|
||
"name": "get_weather",
|
||
"input": {}
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "tool_use",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 150,
|
||
"output_tokens": 30
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- 模型必须调用至少一个工具
|
||
|
||
---
|
||
|
||
### 用例 13:temperature + top_p + top_k
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "写一首关于春天的短诗"
|
||
}
|
||
],
|
||
"temperature": 0.9,
|
||
"top_p": 0.95,
|
||
"top_k": 50
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test013",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "春风拂面花自开,\n柳絮飞舞满园香。\n燕归巢中呢喃语,\n万物复苏迎朝阳。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 25,
|
||
"output_tokens": 32
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 14:max_tokens 截断
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 20,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "请详细介绍一下人工智能的发展历史"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test014",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "人工智能起源于1950年代,图灵提出了机器能否思考的问题。1956年达特茅斯会议正式确立了AI领域。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "max_tokens",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 22,
|
||
"output_tokens": 20
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `stop_reason` == `"max_tokens"`
|
||
- `output_tokens` == 20(等于 max_tokens)
|
||
- 内容被截断
|
||
|
||
---
|
||
|
||
### 用例 15:stop_sequences 截断
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "从1数到10,每行一个数字"
|
||
}
|
||
],
|
||
"stop_sequences": ["5"]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test015",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "1\n2\n3\n4\n"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "stop_sequence",
|
||
"stop_sequence": "5",
|
||
"usage": {
|
||
"input_tokens": 22,
|
||
"output_tokens": 10
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `stop_reason` == `"stop_sequence"`
|
||
- `stop_sequence` 字段包含触发截断的序列
|
||
|
||
---
|
||
|
||
### 用例 16:thinking enabled(extended thinking)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 4096,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "一个房间里有3个灯泡,房间外有3个开关,每个开关控制一个灯泡。你只能进房间一次,如何确定哪个开关控制哪个灯泡?"
|
||
}
|
||
],
|
||
"thinking": {
|
||
"type": "enabled",
|
||
"budget_tokens": 2048
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test016",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "thinking",
|
||
"thinking": "这是一个经典的逻辑推理问题。我需要找到一种方法,通过一次观察来区分三个开关。关键是灯泡有两种可观察的状态:亮或灭。但如果只用亮灭,我只能区分一个开关(开的那个)。我需要找到另一种可观察的属性...温度!灯泡开着会发热。所以我可以:先开一个开关等一会儿,然后关掉,再开另一个开关,然后进房间。亮着的是第二个开关,热的是第一个开关,冷且灭的是第三个开关。"
|
||
},
|
||
{
|
||
"type": "text",
|
||
"text": "解决方案如下:\n\n1. **打开第一个开关**,等待几分钟\n2. **关闭第一个开关**,**打开第二个开关**\n3. **立即进入房间**\n\n此时观察:\n- **亮着的灯** → 由第二个开关控制\n- **摸起来发热的灯** → 由第一个开关控制(因为开过几分钟)\n- **既不亮也不热的灯** → 由第三个开关控制"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 95,
|
||
"output_tokens": 280
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `content` 包含 `thinking` 块和 `text` 块
|
||
- `output_tokens` 包含 thinking tokens
|
||
|
||
---
|
||
|
||
### 用例 17:thinking adaptive
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 4096,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "请帮我分析一下这个算法问题"
|
||
}
|
||
],
|
||
"thinking": {
|
||
"type": "adaptive",
|
||
"budget_tokens": 1024
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test017",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "thinking",
|
||
"thinking": "用户提到了一个算法问题,但没有具体说明是什么问题。我需要请用户提供更多细节。"
|
||
},
|
||
{
|
||
"type": "text",
|
||
"text": "我很乐意帮你分析算法问题!不过你没有具体说明是什么问题。请详细描述一下:\n\n1. 问题的具体要求是什么?\n2. 输入输出的格式是怎样的?\n3. 有没有什么约束条件?\n\n有了这些信息后,我可以帮你分析解题思路和最优解法。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 35,
|
||
"output_tokens": 95
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 18:output_config 为 json_object
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "提取以下信息的姓名和年龄:张三,今年25岁,是一名工程师"
|
||
}
|
||
],
|
||
"output_config": {
|
||
"format": {
|
||
"type": "json_object"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test018",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "{\"name\": \"张三\", \"age\": 25, \"occupation\": \"工程师\"}"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 45,
|
||
"output_tokens": 28
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `content[0].text` 是合法的 JSON 字符串
|
||
|
||
---
|
||
|
||
### 用例 19:output_config 为 json_schema(structured output)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "创建一个用户信息记录,姓名李四,年龄30岁"
|
||
}
|
||
],
|
||
"output_config": {
|
||
"format": {
|
||
"type": "json_schema",
|
||
"schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {"type": "string"},
|
||
"age": {"type": "integer"},
|
||
"email": {"type": "string"}
|
||
},
|
||
"required": ["name", "age"]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test019",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "{\"name\": \"李四\", \"age\": 30}"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 120,
|
||
"output_tokens": 22
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- 输出严格符合 JSON schema 定义
|
||
- 不包含 schema 未定义的字段
|
||
|
||
---
|
||
|
||
### 用例 20:流式文本响应(SSE)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "你好"
|
||
}
|
||
],
|
||
"stream": true
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK, Content-Type: text/event-stream):**
|
||
|
||
```
|
||
event: message_start
|
||
data: {"type":"message","id":"msg_01stream001","role":"assistant","content":[],"model":"claude-opus-4-7","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":10,"output_tokens":0}}
|
||
|
||
event: content_block_start
|
||
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"你"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"好"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"!"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"我"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"是"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Claude"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"很高兴"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"为你"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"服务"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"。"}}
|
||
|
||
event: content_block_stop
|
||
data: {"type":"content_block_stop","index":0}
|
||
|
||
event: message_delta
|
||
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":8}}
|
||
|
||
event: message_stop
|
||
data: {"type":"message_stop"}
|
||
```
|
||
|
||
**验证点:**
|
||
- 事件顺序:message_start → content_block_start → content_block_delta* → content_block_stop → message_delta → message_stop
|
||
- `message_start` 包含完整的 message 对象
|
||
- 每个 `content_block_delta` 包含增量文本
|
||
- `message_delta` 包含 stop_reason 和最终 usage
|
||
- 以 `message_stop` 结束
|
||
|
||
---
|
||
|
||
### 用例 21:流式工具调用
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "北京天气怎么样?"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取天气",
|
||
"input_schema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"city": {"type": "string"}
|
||
},
|
||
"required": ["city"]
|
||
}
|
||
}
|
||
],
|
||
"stream": true
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK, Content-Type: text/event-stream):**
|
||
|
||
```
|
||
event: message_start
|
||
data: {"type":"message","id":"msg_01stream003","role":"assistant","content":[],"model":"claude-opus-4-7","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":180,"output_tokens":0}}
|
||
|
||
event: content_block_start
|
||
data: {"type":"content_block_start","index":0,"content_block":{"type":"tool_use","id":"toolu_01stream003","name":"get_weather"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":""}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\""}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"city"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"\":\""}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"北京"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"}\""}}
|
||
|
||
event: content_block_stop
|
||
data: {"type":"content_block_stop","index":0}
|
||
|
||
event: message_delta
|
||
data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":42}}
|
||
|
||
event: message_stop
|
||
data: {"type":"message_stop"}
|
||
```
|
||
|
||
**验证点:**
|
||
- `content_block_start` 包含 tool_use 类型和工具名
|
||
- `input_json_delta` 逐步拼接完整的 JSON 输入
|
||
- `stop_reason` == `"tool_use"`
|
||
|
||
---
|
||
|
||
### 用例 22:流式 + thinking 内容
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 4096,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "1+1=?"
|
||
}
|
||
],
|
||
"thinking": {
|
||
"type": "enabled",
|
||
"budget_tokens": 1024
|
||
},
|
||
"stream": true
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK, Content-Type: text/event-stream):**
|
||
|
||
```
|
||
event: message_start
|
||
data: {"type":"message","id":"msg_01stream004","role":"assistant","content":[],"model":"claude-opus-4-7","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":30,"output_tokens":0}}
|
||
|
||
event: content_block_start
|
||
data: {"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":""}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"这是一个简单的"}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"数学问题。"}}
|
||
|
||
event: content_block_stop
|
||
data: {"type":"content_block_stop","index":0}
|
||
|
||
event: content_block_start
|
||
data: {"type":"content_block_start","index":1,"content_block":{"type":"text","text":""}}
|
||
|
||
event: content_block_delta
|
||
data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"1+1=2"}}
|
||
|
||
event: content_block_stop
|
||
data: {"type":"content_block_stop","index":1}
|
||
|
||
event: message_delta
|
||
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":25}}
|
||
|
||
event: message_stop
|
||
data: {"type":"message_stop"}
|
||
```
|
||
|
||
**验证点:**
|
||
- 先有 thinking 块,再有 text 块
|
||
- `thinking_delta` 类型正确
|
||
- 两个内容块有不同的 index
|
||
|
||
---
|
||
|
||
### 用例 23:system prompt cache_control(ephemeral)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"system": [
|
||
{
|
||
"type": "text",
|
||
"text": "你是一个专业的编程助手。",
|
||
"cache_control": {
|
||
"type": "ephemeral"
|
||
}
|
||
}
|
||
],
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "你好"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test023",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "你好!我是 Claude,很高兴为你服务。我是由 Anthropic 开发的 AI 助手,可以帮你解答问题、写作、编程等各种任务。请问有什么我可以帮你的?"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 25,
|
||
"output_tokens": 52,
|
||
"cache_creation_input_tokens": 15,
|
||
"cache_read_input_tokens": 0
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `cache_creation_input_tokens` 反映缓存创建的 token 数
|
||
|
||
---
|
||
|
||
### 用例 24:metadata.user_id
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "你好"
|
||
}
|
||
],
|
||
"metadata": {
|
||
"user_id": "user_12345"
|
||
}
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test024",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "你好!我是 Claude,很高兴为你服务。请问有什么我可以帮你的?"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "end_turn",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 12,
|
||
"output_tokens": 18
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 25:无效 model 返回 400
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "nonexistent-model-xyz",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "你好"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(400 Bad Request):**
|
||
```json
|
||
{
|
||
"type": "error",
|
||
"error": {
|
||
"type": "invalid_request_error",
|
||
"message": "The model 'nonexistent-model-xyz' does not exist or is not available."
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 26:缺少 max_tokens 返回 400
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "你好"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(400 Bad Request):**
|
||
```json
|
||
{
|
||
"type": "error",
|
||
"error": {
|
||
"type": "invalid_request_error",
|
||
"message": "'max_tokens' is a required parameter for the Messages API."
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 27:缺少 messages 返回 400
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(400 Bad Request):**
|
||
```json
|
||
{
|
||
"type": "error",
|
||
"error": {
|
||
"type": "invalid_request_error",
|
||
"message": "'messages' is a required parameter and must be a non-empty array."
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 用例 28:内容安全策略拒绝(refusal)
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "生成违法内容..."
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test028",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "抱歉,我无法协助生成此类内容。我的设计原则是提供有益、安全和负责任的帮助。如果你有其他问题或需要帮助的地方,我很乐意为你服务。"
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "refusal",
|
||
"stop_sequence": null,
|
||
"stop_details": {
|
||
"type": "refusal",
|
||
"category": "cyber",
|
||
"explanation": "请求内容违反了使用政策。"
|
||
},
|
||
"usage": {
|
||
"input_tokens": 18,
|
||
"output_tokens": 42
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- `stop_reason` == `"refusal"`
|
||
- `stop_details` 包含 refusal 详情
|
||
|
||
---
|
||
|
||
### 用例 29:disable_parallel_tool_use
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "帮我查北京和上海的天气"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"name": "get_weather",
|
||
"description": "获取天气",
|
||
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}
|
||
}
|
||
],
|
||
"disable_parallel_tool_use": true
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test029",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "tool_use",
|
||
"id": "toolu_01test029",
|
||
"name": "get_weather",
|
||
"input": {"city": "北京"}
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "tool_use",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 120,
|
||
"output_tokens": 35
|
||
}
|
||
}
|
||
```
|
||
|
||
**验证点:**
|
||
- 只调用了一个工具(而非并行调用两个)
|
||
|
||
---
|
||
|
||
### 用例 30:container 复用
|
||
|
||
**请求:**
|
||
```json
|
||
{
|
||
"model": "claude-opus-4-7",
|
||
"max_tokens": 1024,
|
||
"messages": [
|
||
{
|
||
"role": "user",
|
||
"content": "运行一段 Python 代码"
|
||
}
|
||
],
|
||
"tools": [
|
||
{
|
||
"type": "code_execution_20250825",
|
||
"name": "code_execution",
|
||
"container": {
|
||
"type": "python",
|
||
"version": "3.11"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**期望 Mock 响应(200 OK):**
|
||
```json
|
||
{
|
||
"id": "msg_01test030",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "server_tool_use",
|
||
"id": "toolu_01test030",
|
||
"name": "code_execution",
|
||
"input": {
|
||
"code": "print('Hello, World!')",
|
||
"language": "python"
|
||
},
|
||
"caller": {
|
||
"type": "direct"
|
||
}
|
||
}
|
||
],
|
||
"model": "claude-opus-4-7",
|
||
"stop_reason": "tool_use",
|
||
"stop_sequence": null,
|
||
"usage": {
|
||
"input_tokens": 150,
|
||
"output_tokens": 55
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 三、Mock 响应通用结构规范
|
||
|
||
### 非流式响应通用结构
|
||
|
||
```json
|
||
{
|
||
"id": "msg_<unique_id>",
|
||
"type": "message",
|
||
"role": "assistant",
|
||
"content": [
|
||
{
|
||
"type": "text" | "tool_use" | "thinking" | "redacted_thinking" | "server_tool_use" | "web_search_tool_result" | "web_fetch_tool_result" | "code_execution_tool_result" | "bash_code_execution_tool_result" | "text_editor_code_execution_tool_result" | "tool_search_tool_result",
|
||
"text": "<text_content>" | null,
|
||
"id": "toolu_<id>" | null,
|
||
"name": "<tool_name>" | null,
|
||
"input": { /* tool input */ } | null,
|
||
"thinking": "<thinking_content>" | null,
|
||
"data": "<redacted_data>" | null
|
||
}
|
||
],
|
||
"model": "<model_name>",
|
||
"stop_reason": "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | "pause_turn" | "refusal",
|
||
"stop_sequence": "<sequence>" | null,
|
||
"stop_details": {
|
||
"type": "refusal",
|
||
"category": "cyber" | "bio",
|
||
"explanation": "<explanation>"
|
||
} | null,
|
||
"usage": {
|
||
"input_tokens": <int>,
|
||
"output_tokens": <int>,
|
||
"cache_read_input_tokens": <int> | null,
|
||
"cache_creation_input_tokens": <int> | null
|
||
}
|
||
}
|
||
```
|
||
|
||
### 流式 Event 通用结构
|
||
|
||
| Event Type | Key Fields |
|
||
|------------|-----------|
|
||
| `message_start` | `type: "message"`, `id`, `role`, `content: []`, `model`, `stop_reason: null`, `usage` |
|
||
| `content_block_start` | `type: "content_block_start"`, `index`, `content_block: {type, ...}` |
|
||
| `content_block_delta` | `type: "content_block_delta"`, `index`, `delta: {type, text/partial_json/thinking}` |
|
||
| `content_block_stop` | `type: "content_block_stop"`, `index` |
|
||
| `message_delta` | `type: "message_delta"`, `delta: {stop_reason, stop_sequence}`, `usage: {output_tokens}` |
|
||
| `message_stop` | `type: "message_stop"` |
|
||
|
||
### 错误响应通用结构
|
||
|
||
```json
|
||
{
|
||
"type": "error",
|
||
"error": {
|
||
"type": "invalid_request_error" | "authentication_error" | "permission_error" | "not_found_error" | "rate_limit_error" | "api_error",
|
||
"message": "<human_readable_message>"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 请求必需参数
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `model` | string | 模型标识符(如 `claude-opus-4-7`) |
|
||
| `max_tokens` | integer | 最大生成 token 数(必需) |
|
||
| `messages` | array | 消息数组,至少包含一条(必需) |
|
||
|
||
### 请求可选参数
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `system` | string/array | - | 系统 prompt |
|
||
| `temperature` | number | 1.0 | 采样温度(0.0-1.0) |
|
||
| `top_p` | number | - | 核采样阈值 |
|
||
| `top_k` | number | - | 从 top K 采样 |
|
||
| `stop_sequences` | array | - | 停止序列 |
|
||
| `tools` | array | - | 工具定义 |
|
||
| `tool_choice` | object | auto | 工具选择策略 |
|
||
| `thinking` | object | - | 扩展思考配置 |
|
||
| `output_config` | object | - | 输出格式配置 |
|
||
| `stream` | boolean | false | 是否流式 |
|
||
| `metadata` | object | - | 请求元数据 |
|
||
| `disable_parallel_tool_use` | boolean | false | 禁用并行工具调用 |
|
||
| `container` | any | - | 容器标识符 |
|
||
|
||
### Stop Reason 枚举
|
||
|
||
| 值 | 含义 |
|
||
|----|------|
|
||
| `end_turn` | 自然结束 |
|
||
| `max_tokens` | 达到 max_tokens 限制 |
|
||
| `stop_sequence` | 遇到自定义停止序列 |
|
||
| `tool_use` | 模型调用了工具 |
|
||
| `pause_turn` | 长运行 turn 暂停 |
|
||
| `refusal` | 安全策略拒绝 |
|