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

部署Azure Function加载.pkl模型时遇typing._ClassVar属性错误

问题:Azure Function部署后加载Azure ML训练的.pkl模型失败

在Windows本地VS Code中使用Python 3.8.6部署带有Azure ML训练的.pkl模型的Azure Function时,本地运行正常,但部署后调用joblib.load('model.pkl')加载模型失败,报错AttributeError: module 'typing' has no attribute '_ClassVar'。已尝试更换不同库、用pickle替代joblib加载模型,错误依旧。


1. requirements.txt

azure-functions
joblib==0.14.1
numpyencoder==0.3.0
numpy==1.19.0
azureml-automl-runtime==1.49.0

2. 函数代码

import logging
import azure.functions as func
import os
import json
import pandas as pd
from numpyencoder import NumpyEncoder

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Predict business classification')

    max_prediction_count = 3
    logging.info('Predict business classification - before')

    model = joblib.load('model.pkl')

    logging.info('Predict business classification - after')

    company_name = req.params.get('name')
    limit =  req.params.get('limit')
    max_predictions = max_prediction_count
    if limit:
        try:
            max_predictions = int(limit)
        except ValueError:
            max_predictions = max_prediction_count
    
    predictions = get_predictions(model, company_name)
    
    labels = model.classes_
    
    res = predictions[0].tolist()
    res = [{'id': labels[i], 'confidence': x * 100} for i, x in enumerate(res)]
    res.sort(key=lambda d: d['confidence'], reverse=True)
    result = res[:max_predictions]
    return  func.HttpResponse(body=json.dumps(result, cls=NumpyEncoder) , mimetype="application/json",  status_code=200)

def get_predictions(model, company_name):
    input_sample = pd.DataFrame(data=[{
        "IN_CompanyNameClean": company_name,
    }])

    predictions = model.predict_proba(input_sample)
    return predictions

3. 完整报错栈

Result: Failure Exception: AttributeError: module 'typing' has no attribute '_ClassVar' 
Stack: 
File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 452, in _handle__invocation_request 
call_result = await self._loop.run_in_executor( 
File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run 
result = self.fn(*self.args, **self.kwargs) 
File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 718, in _run_sync_func 
return ExtensionManager.get_sync_invocation_wrapper(context, 
File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/extension.py", line 215, in _raw_invocation_wrapper 
result = function(**args) 
File "/home/site/wwwroot/predictBusinessClassification/__init__.py", line 34, in main 
model = joblib.load('model.pkl') 
File "/home/site/wwwroot/.python_packages/lib/site-packages/joblib/numpy_pickle.py", line 605, in load 
obj = _unpickle(fobj, filename, mmap_mode) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/joblib/numpy_pickle.py", line 529, in _unpickle 
obj = unpickler.load() 
File "/usr/local/lib/python3.8/pickle.py", line 1212, in load 
dispatch[key[0]](self) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/joblib/numpy_pickle.py", line 342, in load_build 
Unpickler.load_build(self) 
File "/usr/local/lib/python3.8/pickle.py", line 1705, in load_build 
setstate(state) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/featurization/data_transformer.py", line 998, in __setstate__ 
new_data_transformer = DataTransformer() 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/featurization/data_transformer.py", line 198, in __init__ 
from azureml.automl.runtime.sweeping.meta_sweeper import MetaSweeper 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/sweeping/meta_sweeper.py", line 36, in <module> 
from ..scoring import Scorers, AbstractScorer 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/scoring/__init__.py", line 5, in <module> 
from .abstract_scorer import AbstractScorer 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/scoring/abstract_scorer.py", line 12, in <module> 
from azureml.automl.runtime.shared.metrics import is_better 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/shared/metrics.py", line 18, in <module> 
from azureml.automl.runtime import _ml_engine 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/__init__.py", line 6, in <module> 
from .ml_engine import convert_to_onnx, featurize, validate, run_ensemble_selection 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/ml_engine.py", line 52, in <module> 
from azureml.automl.runtime._ml_engine.validation import AbstractRawExperimentDataValidator, \ 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/validation/__init__.py", line 7, in <module> 
from .featurization_config_data_validator import FeaturizationConfigDataValidator 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/validation/featurization_config_data_validator.py", line 19, in <module> 
from azureml.automl.runtime import _data_transformation_utilities 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_data_transformation_utilities.py", line 41, in <module> 
from azureml.core import Run 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/core/__init__.py", line 16, in <module> 
from .workspace import Workspace 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/core/workspace.py", line 22, in <module> 
from azureml._project import _commands 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/_commands.py", line 23, in <module> 
from azureml._project.project_engine import ProjectEngineClient 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/project_engine.py", line 12, in <module> 
import azureml._project.project_manager as project_manager 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/project_manager.py", line 9, in <module> 
from azureml._project.ignore_file import AmlIgnoreFile 
File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/ignore_file.py", line 6, in <module> 
import pathspec 
File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/__init__.py", line 32, in <module> 
from .gitignore import ( 
File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/gitignore.py", line 15, in <module> 
from .pathspec import ( 
File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/pathspec.py", line 23, in <module> 
from . import util 
File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/util.py", line 30, in <module> 
from .pattern import ( 
File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/pattern.py", line 192, in <module> 
class RegexMatchResult(object): 
File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 950, in wrap 
return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 800, in _process_class 
cls_fields = [_get_field(cls, name, type) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 800, in <listcomp> 
cls_fields = [_get_field(cls, name, type) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 659, in _get_field 
if (_is_classvar(a_type, typing) 
File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 550, in _is_classvar 
return type(a_type) is typing._ClassVar

解决方案

该错误根源是Python 3.8环境中安装了第三方dataclasses库,而Python 3.7+已内置dataclasses模块,第三方版本与内置版本冲突,导致typing._ClassVar的查找逻辑出错。

解决步骤

  1. 修正requirements.txt
    修改依赖文件,强制排除第三方dataclasses(仅为Python 3.6及以下版本安装):

    azure-functions
    joblib==0.14.1
    numpyencoder==0.3.0
    numpy==1.19.0
    azureml-automl-runtime==1.49.0
    # 仅为Python 3.6及以下版本安装第三方dataclasses,3.8使用内置版本
    dataclasses==0.6; python_version < "3.7"
    
  2. 清理并重新部署

    • 本地删除.python_packages文件夹,清理旧依赖缓存
    • 使用远程构建命令重新部署,确保环境安装正确依赖:
      func azure functionapp publish <你的函数应用名称> --build remote
      
  3. 额外优化

    • 补上代码中缺失的import joblib语句,避免运行时导入错误
    • 将模型加载移到全局作用域,仅在函数启动时加载一次,提升请求响应速度:
      import logging
      import azure.functions as func
      import os
      import json
      import pandas as pd
      from numpyencoder import NumpyEncoder
      import joblib  # 补上缺失的导入
      
      # 全局加载模型,仅启动时执行一次
      model = joblib.load('model.pkl')
      max_prediction_count = 3
      
      def main(req: func.HttpRequest) -> func.HttpResponse:
          logging.info('Predict business classification')
      
          company_name = req.params.get('name')
          limit =  req.params.get('limit')
          max_predictions = max_prediction_count
          if limit:
              try:
                  max_predictions = int(limit)
              except ValueError:
                  max_predictions = max_prediction_count
          
          predictions = get_predictions(model, company_name)
          
          labels = model.classes_
          
          res = predictions[0].tolist()
          res = [{'id': labels[i], 'confidence': x * 100} for i, x in enumerate(res)]
          res.sort(key=lambda d: d['confidence'], reverse=True)
          result = res[:max_predictions]
          return  func.HttpResponse(body=json.dumps(result, cls=NumpyEncoder) , mimetype="application/json",  status_code=200)
      
      def get_predictions(model, company_name):
          input_sample = pd.DataFrame(data=[{
              "IN_CompanyNameClean": company_name,
          }])
      
          predictions = model.predict_proba(input_sample)
          return predictions
      
    • 通过Azure门户的Kudu工具,确认model.pkl已正确上传到函数应用的wwwroot目录

内容的提问来源于stack exchange,提问作者Ewa Łyko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:05:45