如何在LangChain的RunnableLambda中传入self以调用类内方法与属性?
看起来你在类里实现LangChain并行链的时候卡壳了,核心就是怎么让RunnableLambda能正确访问类实例(也就是self)的方法和属性对吧?我来给你捋几个实际能用的方案,都是踩过坑后总结的,应该能解决你的问题:
方案1:直接使用绑定了self的实例方法(最简洁)
你原来的demographics_review是类内的方法吧?如果是实例方法的话,它本身已经和self绑定了,根本不需要用lambda额外传self!
步骤:
- 先调整你的类方法参数,让它只接收链传递的输入参数(比如把
def demographics_review(self, input):改成def demographics_review(self, x):,参数名统一成x或者和链的输出匹配的名字); - 直接把实例方法传给
RunnableLambda,不用嵌套lambda:
# 修正后的demographics_review_chain demographics_review_chain = ( RunnableLambda(self.demographics_review) # 直接用绑定self的实例方法 | self.general_model | StrOutputParser() ) # 对应的management_plan_chain也可以这么写 management_plan_chain = ( RunnableLambda(self.management_plan) | self.management_plan_model | StrOutputParser() )
这样写的好处是完全避免了lambda的作用域问题,实例方法里的self就是当前类的实例,能直接访问self.general_model、self.rag_bot这些属性,不会出现“没法访问”的情况。
方案2:用functools.partial绑定self(适合不能修改方法参数的情况)
如果因为某些原因不能修改demographics_review的参数(比如必须保留input这个参数名),可以用functools.partial把self固定成方法的第一个参数,这样Runnable调用时只需要传输入参数就行:
from functools import partial demographics_review_chain = ( RunnableLambda(partial(demographics_review, self)) # 把self绑定成第一个固定参数 | self.general_model | StrOutputParser() )
这个方案相当于给原方法“预设”了self参数,lambda就不需要再显式传self了,能完美解决你原来代码里的作用域问题。
方案3:修正lambda的参数传递(适合临时调试)
如果非要用lambda的话,你原来的写法其实也能工作,但要注意不要把实例方法当成普通函数调用!比如你原来的:
RunnableLambda(lambda x: demographics_review(self, input=x))
如果demographics_review是类内的实例方法,正确的调用方式应该是self.demographics_review(input=x),而不是把self作为参数传进去(普通函数才需要这么做,实例方法已经绑定self了)。修正后是:
demographics_review_chain = ( RunnableLambda(lambda x: self.demographics_review(input=x)) | self.general_model | StrOutputParser() )
不过这个方案不推荐长期用,因为lambda的延迟绑定有时候会导致self的引用出问题(比如类实例状态变化后,lambda里的self可能不是你预期的那个),还是方案1或2更稳妥。
额外提醒:你的management_plan方法有个小坑
看你的management_plan代码,循环里的context和prompt是在if分支里赋值的,如果没有匹配到notes_template_item,这两个变量会未定义,执行到return的时候会报错!建议加个默认值或者处理无匹配的情况,比如:
def management_plan(self, input) -> str: print("PROCESSING write_notes coroutine: starting management_plan()") # 初始化默认值,避免无匹配时报错 context = self.personality['CONTEXT'] prompt = "" for notes_template_item in self.notes_template_item_list: if notes_template_item in self.similar_prompt_items['MANAGEMENT PLAN']: prompt = self.personality[notes_template_item].replace("{input_text}", input.messages[0].content) context = self.modify_context( self.personality['CONTEXT'], RAG_data=self.rag_bot.output+self.rag_bot.issues_list+self.rag_bot.differentials ) # 如果只需要第一个匹配项,这里可以加个break break return prompt_template.format_prompt(context=context, prompt=prompt)
最后修正你的并行链
用上面的方案调整后,你的主链写法就可以保持原来的结构,不会再出现访问不到self属性的问题了:
chain = ( input_template | RunnableParallel( branches={ "demographics_review": demographics_review_chain, "management_plan": management_plan_chain # 其他分支... } ) | RunnableLambda(lambda x: combine_all(self, x["branches"]["demographics_review"], x["branches"]["management_plan"])) )
备注:内容来源于stack exchange,提问作者Code Monkey

