ChatCompletion object is not subscriptable:请求成功了,取结果的代码还停在旧版
Chat Completions 完整响应是模型对象时,用属性读取替代旧式字典下标;下游必须接收字典时再用 model_dump() 转换,并分别处理文本、拒绝和工具调用。
ChatCompletion object is not subscriptable:请求成功了,取结果的代码还停在旧版
如果异常落在下面这种表达式上:
text = response["choices"][0]["message"]["content"]
并提示:
'ChatCompletion' object is not subscriptable
先检查 type(response)。OpenAI Python 1.x 及其后续客户端通常返回 ChatCompletion 模型对象,旧式字典下标读取不再适用。官方讨论 #1150 记录了同类取值问题。原始讨论
一行修正,然后处理没有文本的情况
直接读取文本可以改为:
text = response.choices[0].message.content
但如果下一行立刻 text.strip(),工具调用场景可能继续报 NoneType 的错误。实际业务最好把“文本”“拒绝”“工具调用”作为不同分支处理。下列分支代码以 openai 1.109.1 为基线,较早的 1.x 版本不能据此假定存在相同字段:
def classify_first_message(response):
if not response.choices:
return "empty", None
message = response.choices[0].message
if message.refusal:
return "refusal", message.refusal
if message.tool_calls:
return "tool_calls", message.tool_calls
if message.content is None:
return "empty", None
return "text", message.content
这个函数只是一个示例分流策略:有工具调用时优先交给工具处理。如果你的产品允许同一消息同时展示文本并处理工具,应按业务调整,不要无意丢弃其中一部分。收到工具调用也不等于获得了执行外部操作的授权。
如果明确只接受普通文本,可以在调用方检查类别,再决定是否去掉首尾空白。不能用 str(None) 把缺失内容变成字面量 "None" 塞给用户。
下游确实只收字典时,在边界转换
payload = response.model_dump()
text = payload["choices"][0]["message"]["content"]
model_dump() 用于得到 Python 字典;model_dump_json() 返回 JSON 字符串,二者不要混用。Pydantic 的序列化文档明确区分了 Python 对象形式和 JSON 形式。Pydantic 序列化说明
只在需要交给旧组件、序列化器或消息队列的边界转换即可。若一个函数里一会儿按属性读取、一会儿按字典读取,后续排查会变得更困难。可以统一函数的输入约定,让类型检查更容易发现遗漏。
用本地对象检查,不用再扣一次 API 额度
下面构造的是测试数据,不是模型真实返回。代码不会联网,可先验证“属性读取”和“转字典读取”是否一致:
from openai.types.chat import ChatCompletion
response = ChatCompletion(
id="local-fixture",
object="chat.completion",
created=0,
model="local-fixture",
choices=[{
"index": 0,
"finish_reason": "stop",
"message": {"role": "assistant", "content": "OK"},
}],
)
assert response.choices[0].message.content == "OK"
assert response.model_dump()["choices"][0]["message"]["content"] == "OK"
再把测试消息的 content 改为 None,检查自己的分支能否正常返回。给 tool_calls 和 refusal 各加一个测试,比只验证一条文本更容易发现下一处问题。
本文适用于 Chat Completions 的完整响应对象。流式调用拿到的分块、Responses API 的输出以及第三方网关自行包装的结果,结构可能不同。修复这类取值错误不需要改到 /completions 端点。SDK 响应模型与迁移说明


