继承Langchain类时super().__init__及自定义属性添加异常问题
问题:LangChain继承Pydantic模型时添加自定义属性触发ValueError
初始可运行代码
以下代码可以正常运行:
from langchain_openai import ChatOpenAI class LLM: def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name class OpenAILLM(LLM, ChatOpenAI): def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name
添加自定义属性后报错
当在OpenAILLM的__init__中添加自定义属性var时,创建对象失败:
from langchain_openai import ChatOpenAI class LLM: def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name class OpenAILLM(LLM, ChatOpenAI): def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name self.var = 'var'
报错信息:
ValueError: "OpenAILLM" object has no field "var"
尝试类变量后的问题
将var声明为LLM的类变量后,get_var方法可以正常工作,但set_var方法触发相同错误:
from langchain_openai import ChatOpenAI class LLM(): var = 1 def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name class OpenAILLM(LLM, ChatOpenAI): def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name def get_var(self): return self.var def set_var(self, var): print('self var', self.var) self.var = var return True
方法解析顺序(MRO)
OpenAILLM的MRO如下:
(__main__.OpenAILLM, __main__.LLM, langchain_openai.chat_models.base.ChatOpenAI, langchain_core.language_models.chat_models.BaseChatModel, langchain_core.language_models.base.BaseLanguageModel, langchain_core.runnables.base.RunnableSerializable, langchain_core.load.serializable.Serializable, pydantic.v1.main.BaseModel, pydantic.v1.utils.Representation, langchain_core.runnables.base.Runnable, typing.Generic, abc.ABC, object)
原因分析
从MRO可以看到,OpenAILLM间接继承了Pydantic v1的BaseModel。Pydantic v1的BaseModel默认会严格校验实例属性,不允许添加未在类中声明的字段。直接赋值self.var时,Pydantic会拦截并报错,因为var不是模型定义的字段。
解决方案
方案1:在子类中声明自定义字段
在OpenAILLM类中显式声明var字段,符合Pydantic的规范:
from langchain_openai import ChatOpenAI from pydantic.v1 import Field class LLM: def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name class OpenAILLM(LLM, ChatOpenAI): var: str = Field(default='var') # 声明字段,可设置默认值 def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name
方案2:允许额外字段
通过设置Extra.allow,让Pydantic允许添加未声明的字段:
from langchain_openai import ChatOpenAI from pydantic.v1 import Extra class LLM: def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name class OpenAILLM(LLM, ChatOpenAI): class Config: extra = Extra.allow # 允许额外字段 def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name self.var = 'var'
方案3:使用对象的__dict__赋值(不推荐)
绕过Pydantic的属性校验,直接修改__dict__,但可能破坏Pydantic的模型一致性:
from langchain_openai import ChatOpenAI class LLM: def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name class OpenAILLM(LLM, ChatOpenAI): def __init__(self, model_name): super().__init__(model_name=model_name) self.model_name = model_name self.__dict__['var'] = 'var' # 直接修改__dict__
内容的提问来源于stack exchange,提问作者Yadnesh Salvi
相关产品推荐
相关产品推荐

