You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenAI与FastAPI兼容性问题求助:类型注解报错解决方案

问题:FastAPI中使用OpenAI的CompletionCreateParams作为请求参数类型注解报错

环境版本

  • Python:3.12.3(3.8、3.10版本也存在该问题)
  • FastAPI:0.111.0
  • OpenAI:1.30.4

问题场景

尝试在FastAPI接口中使用OpenAI的CompletionCreateParams作为请求参数的类型注解时,触发以下报错:

(3.12venv) Delphi:dispatcher LarryMartell$ python
Python 3.12.3 (v3.12.3:f6650f9ad7, Apr  9 2024, 08:18:48) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from fastapi import FastAPI
>>> from openai.types.chat import CompletionCreateParams
>>> app = FastAPI()
>>> @app.post("/v1/chat/completions")
... def chat_completions(r: CompletionCreateParams):
...  pass
... 
Traceback (most recent call last):
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/type_adapter.py", line 210, in __init__
    core_schema = _getattr_no_parents(type, '__pydantic_core_schema__')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/type_adapter.py", line 98, in _getattr_no_parents
    raise AttributeError(attribute)
AttributeError: __pydantic_core_schema__

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/routing.py", line 944, in decorator
    self.add_api_route(
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/routing.py", line 883, in add_api_route
    route = route_class(
            ^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/routing.py", line 513, in __init__
    self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py", line 261, in get_dependant
    type_annotation, depends, param_field = analyze_param(
                                            ^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py", line 444, in analyze_param
    field = create_response_field(
            ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/utils.py", line 99, in create_response_field
    return ModelField(**kwargs)  # type: ignore[arg-type]
           ^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 6, in __init__
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/fastapi/_compat.py", line 109, in __post_init__
    self._type_adapter: TypeAdapter[Any] = TypeAdapter(
                                           ^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/type_adapter.py", line 212, in __init__
    core_schema = _get_schema(type, config_wrapper, parent_depth=_parent_depth + 1)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/type_adapter.py", line 81, in _get_schema
    schema = gen.generate_schema(type_)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 502, in generate_schema
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 737, in _generate_schema_inner
    return self._annotated_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1757, in _annotated_schema
    schema = self._apply_annotations(source_type, annotations)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1825, in _apply_annotations
    schema = get_inner_schema(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_schema_generation_shared.py", line 82, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1907, in new_handler
    schema = metadata_get_schema(source, get_inner_schema)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1903, in <lambda>
    lambda source, handler: handler(source)
                            ^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_schema_generation_shared.py", line 82, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1806, in inner_handler
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 758, in _generate_schema_inner
    return self.match_type(obj)
           ^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 840, in match_type
    return self._match_generic_type(obj, origin)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 864, in _match_generic_type
    return self._union_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1152, in _union_schema
    choices.append(self.generate_schema(arg))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 502, in generate_schema
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 758, in _generate_schema_inner
    return self.match_type(obj)
           ^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 806, in match_type
    return self._typed_dict_schema(obj, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1254, in _typed_dict_schema
    for field_name, annotation in get_type_hints_infer_globalns(
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/LarryMartell/dispatcher/3.12venv/lib/python3.12/site-packages/pydantic/_internal/_fields.py", line 56, in get_type_hints_infer_globalns
    return get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 2244, in get_type_hints
    value = _eval_type(value, base_globals, base_locals)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 414, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 924, in _evaluate
    eval(self.__forward_code__, globalns, localns),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1, in <module>
TypeError: 'pydantic_core._pydantic_core.PydanticUndefinedType' object is not subscriptable

解决方法

原因

CompletionCreateParams是OpenAI SDK定义的TypedDict类型,并非Pydantic模型。FastAPI依赖Pydantic处理请求参数的解析和Schema生成,直接使用TypedDict会因类型系统不兼容触发报错。

方案1:转换为Pydantic模型

手动创建对应Pydantic模型,或者用Pydantic的create_model自动转换:

from fastapi import FastAPI
from openai.types.chat import CompletionCreateParams
from pydantic import create_model, Undefined

# 遍历TypedDict的注解,转换为Pydantic模型字段
fields = {}
for name, type_annotation in CompletionCreateParams.__annotations__.items():
    # 处理Optional等泛型类型,提取实际类型;默认值设为Undefined表示必填
    if hasattr(type_annotation, '__origin__') and type_annotation.__origin__ is Union:
        actual_type = next(t for t in type_annotation.__args__ if t is not type(None))
        fields[name] = (actual_type, Undefined)
    else:
        fields[name] = (type_annotation, Undefined)

ChatCompletionRequest = create_model("ChatCompletionRequest", **fields)

app = FastAPI()

@app.post("/v1/chat/completions")
def chat_completions(r: ChatCompletionRequest):
    # 后续业务逻辑
    pass

方案2:用Pydantic TypeAdapter适配

通过TypeAdapter手动解析请求体,绕过FastAPI的自动参数解析:

from fastapi import FastAPI, Request
from openai.types.chat import CompletionCreateParams
from pydantic import TypeAdapter

app = FastAPI()
# 创建TypedDict的适配器
adapter = TypeAdapter(CompletionCreateParams)

@app.post("/v1/chat/completions")
async def chat_completions(request: Request):
    # 读取原始请求体
    raw_body = await request.json()
    # 用适配器验证并转换为TypedDict结构
    validated_params = adapter.validate_python(raw_body)
    # 后续业务逻辑
    pass

方案3:直接使用字典转发请求

如果只是需要把请求转发给OpenAI API,可以直接接收字典类型,再传递给OpenAI客户端:

from fastapi import FastAPI
from openai import OpenAI

app = FastAPI()
client = OpenAI(api_key="你的API密钥")

@app.post("/v1/chat/completions")
def chat_completions(r: dict):
    # 直接将请求参数传递给OpenAI客户端
    return client.chat.completions.create(**r)

内容的提问来源于stack exchange,提问作者Larry Martell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:37:02