大模型冷知识: 大部分 LLM 的 API 响应中 choices 字段是干什么的?
choices。
·
为什么 API 响应中会有 choices 字段?
快速答案
choices 是 OpenAI API 标准格式的一部分,用于表示模型可能生成多个候选回复。
深入理解
1. OpenAI API 的设计
OpenAI 在设计 Chat Completion API 时,考虑了以下场景:
用户的一个请求 → 模型可能生成多个候选回复
因此,响应格式设计为:
{
"choices": [
{"message": {"content": "..."}},
{"message": {"content": "..."}},
{"message": {"content": "..."}}
]
}
参数:n 参数控制生成多少个候选
response = client.chat.completions.create(
model="gpt-4",
messages=[...],
n=3 # 生成 3 个候选回复
)
# 响应中会有 3 个 choices
2. 为什么需要多个候选?
场景 1:创意写作
# 生成多个故事开头
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "写一个故事开头"}],
n=3 # 生成 3 个不同的开头
)
# 用户可以选择最喜欢的
for i, choice in enumerate(response.choices):
print(f"选项 {i+1}: {choice.message.content}")
场景 2:多路径推理
# 生成多个解决方案
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "解决这个数学问题"}],
n=5 # 生成 5 个不同的解法
)
# 分析多个解法
for i, choice in enumerate(response.choices):
print(f"解法 {i+1}: {choice.message.content}")
场景 3:投票机制
# 生成多个回复,然后投票选择最好的
responses = []
for _ in range(5):
response = client.chat.completions.create(
model="gpt-4",
messages=[...],
n=1
)
responses.append(response.choices[0].message.content)
# 选择最佳回复
best_response = select_best(responses)
3. 标准结构详解
完整的 OpenAI 响应格式
{
"id": "chatcmpl-8Hs...",
"object": "chat.completion",
"created": 1699564200,
"model": "gpt-4",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The answer is..."
},
"finish_reason": "stop"
},
{
"index": 1,
"message": {
"role": "assistant",
"content": "Another answer..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
}
}
字段说明:
choices:候选回复数组index:候选的索引(0, 1, 2, …)message:实际的回复内容finish_reason:生成停止的原因(“stop”、“length”、"tool_calls"等)
4. 为什么 Deepseek 也用 choices?
Deepseek 兼容 OpenAI API,所以采用了相同的格式:
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.deepseek.com"
)
# 调用 Deepseek
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[{"role": "user", "content": "..."}],
n=2 # 也支持多个候选
)
# 响应格式完全相同
for choice in response.choices:
print(choice.message.content)
5. 其他厂商的格式对比
Gemini(Google)
{
"candidates": [
{
"content": {
"parts": [{"text": "..."}]
}
}
]
}
说明:用 candidates 代替 choices
Claude(Anthropic)
{
"content": [
{"type": "text", "text": "..."}
]
}
说明:直接返回内容,没有 choices
豆包(VolcEngine)
{
"choices": [
{
"message": {
"content": "...",
"thinking": "..."
}
}
]
}
说明:也用 choices,兼容 OpenAI 格式
6. 实际使用中的处理
方式 1:获取第一个候选(最常见)
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[...],
n=1 # 只生成 1 个候选
)
# 获取第一个(也是唯一的)候选
message = response.choices[0].message
print(message.content)
方式 2:获取所有候选
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[...],
n=3 # 生成 3 个候选
)
# 遍历所有候选
for i, choice in enumerate(response.choices):
print(f"候选 {i+1}: {choice.message.content}")
方式 3:处理 finish_reason
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[...],
)
choice = response.choices[0]
if choice.finish_reason == "stop":
print("正常完成")
elif choice.finish_reason == "length":
print("达到最大长度限制")
elif choice.finish_reason == "tool_calls":
print("调用了工具")
7. 为什么通常只用第一个?
在实际应用中,大多数情况下 n=1(默认值),所以只有一个候选:
# 默认 n=1
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[...],
# n 默认为 1
)
# 响应中只有一个 choice
print(len(response.choices)) # 输出: 1
print(response.choices[0].message.content)
8. 完整示例
示例 1:单个候选(常见)
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.deepseek.com"
)
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[
{"role": "user", "content": "What is 2+2?"}
],
n=1 # 默认值
)
# 访问响应
choice = response.choices[0]
print(f"Content: {choice.message.content}")
print(f"Finish reason: {choice.finish_reason}")
输出:
Content: The answer is 4
Finish reason: stop
示例 2:多个候选
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[
{"role": "user", "content": "给我 3 个创意想法"}
],
n=3 # 生成 3 个候选
)
# 处理多个候选
for i, choice in enumerate(response.choices):
print(f"想法 {i+1}:")
print(choice.message.content)
print("---")
输出:
想法 1:
使用 AI 生成个性化学习计划...
---
想法 2:
开发一个社区知识共享平台...
---
想法 3:
创建虚拟现实教学体验...
---
示例 3:处理 thinking 和 choices
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=[
{"role": "user", "content": "解决这个难题"}
],
n=2 # 生成 2 个候选
)
# 处理多个候选,每个都可能有 thinking
for i, choice in enumerate(response.choices):
message = choice.message
print(f"候选 {i+1}:")
# 访问 thinking(如果有)
if hasattr(message, 'reasoning_content'):
print(f" 思考: {message.reasoning_content[:100]}...")
# 访问答案
print(f" 答案: {message.content}")
print(f" 完成原因: {choice.finish_reason}")
print("---")
9. 成本影响
⚠️ 重要:生成多个候选会增加成本!
# n=1: 生成 1 个回复
response1 = client.chat.completions.create(
model="deepseek-reasoner",
messages=[...],
n=1
)
# 成本: 基础成本
# n=3: 生成 3 个回复
response3 = client.chat.completions.create(
model="deepseek-reasoner",
messages=[...],
n=3
)
# 成本: 基础成本 × 3
10. 最佳实践
✅ 推荐
- 默认使用
n=1 - 只在需要多个候选时设置
n > 1 - 检查
finish_reason了解生成状态 - 使用
response.choices[0]获取主要回复
❌ 避免
- 不必要地设置
n > 1(增加成本) - 忽略
finish_reason - 假设总是有多个候选
总结
为什么有 choices?
- OpenAI API 标准:设计用于支持多个候选回复
- 灵活性:允许生成多个不同的回复供选择
- 兼容性:Deepseek、豆包等兼容 OpenAI API 的厂商都采用这个格式
结构
请求 (n=1/2/3/...)
↓
模型生成 n 个候选
↓
响应中的 choices 数组包含所有候选
↓
通常只使用 choices[0]
访问方式
# 获取第一个候选
response.choices[0].message.content
# 获取所有候选
for choice in response.choices:
print(choice.message.content)
参考资源
更多推荐

所有评论(0)