# 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` | 安全策略拒绝 |
