一、快速解决 AttributeError: 'AIMessage' object has no attribute 'strip'
博主在学习LangChain实战课第4课:Langchain的输出解析部分时直接复制了课程提供的代码,并将模型换成了国内可以使用的ChatGLM后,遇到了AttributeError: 'AIMessage' object has no attribute 'strip' 的错误,意思是我们传递给 output_parser.parse 的对象 output 是一个 AIMessage 对象,而不是预期的str字符串对象。如图所示。
下面是替换的代码,将原代码中的
# 获取模型的输出
output = model.invoke(input)
# 解析模型的输出
parsed_output = output_parser.parse(output)
替换成
# 获取模型的输出
output = model.invoke(input)
output_content = output.content
# 解析模型的输出(这是一个字典结构)
parsed_output = output_parser.parse(output_content)
就能实现正常的运行了,结果如下,非常的nice
二、原理解析
下面根据大模型的回答,结合控制台的输出给大家详细阐述一下原因。
您好!很高兴听到您已经取得了一些进展,并且发现了关键步骤 output_content = output.content 的重要性。让我详细分析一下为什么这一步骤能够解决您的问题,以及背后的原因和机制。
问题背景回顾
在您的原始代码中,您试图通过以下方式解析模型的输出:
parsed_output = output_parser.parse(output)
然而,这导致了以下错误:
AttributeError: 'AIMessage' object has no attribute 'strip'
这个错误表明,您传递给 output_parser.parse 的对象 output 是一个 AIMessage 对象,而不是预期的字符串。
为什么 output.content 是关键
1. 理解 model.invoke(input) 的返回值(即output)
在使用 LangChain 或类似的库调用语言模型时,model.invoke(input) 方法通常会返回一个包含模型响应的对象。这些响应对象不仅包含生成的文本,还可能包含其他元数据,例如生成时间、使用的模型版本等。
具体到您的情况,ChatZhipuAI 模型的 invoke 方法返回的是一个 AIMessage 对象。这个对象的结构可能如下:
class AIMessage:
def __init__(self, content, other_metadata):
self.content = content
# 其他属性
content属性:包含模型生成的实际文本内容,这是您需要解析的部分。- 其他属性:可能包括模型生成时间、token 使用量等。
- 实际下,output输出如下:
content='json\n{\n\t"description": "50元,玫瑰的浪漫,爱情的物语。珍爱每一份深情,让这束玫瑰为您诉说无尽爱意。",\n\t"reason": "这个文案强调了玫瑰作为爱情象征的重要性,同时突出了价格优势,以吸引消费者的注意力。通过使用\'浪漫\'和\'爱意\'这样的词汇,增强了文案的情感吸引力,使得潜在顾客感受到购买这束玫瑰的价值不仅仅是花朵本身,更是一份深厚的情感表达。"\n}\n' response_metadata={'token_usage': {'completion_tokens': 103, 'prompt_tokens': 97, 'total_tokens': 200}, 'model_name': 'glm-4', 'finish_reason': 'stop'} id='run-1443ed20-ce5f-4c94-bbf4-bce50506084c-0'
content='json\n{\n\t"description": "清新脱俗,30元即可拥抱高雅百合,为生活添一抹纯美诗意。",\n\t"reason": "这个文案强调了百合花的高雅和价格的亲民,同时传达了购买鲜花能带来的生活品质提升,‘清新脱俗’和‘纯美诗意’两个词组旨在唤起人们对美好生活的向往。"\n}\n' response_metadata={'token_usage': {'completion_tokens': 83, 'prompt_tokens': 95, 'total_tokens': 178}, 'model_name': 'glm-4', 'finish_reason': 'stop'} id='run-3c01ef0a-1334-46c6-98c5-0d6b337f394d-0'
content='json\n{\n\t"description": "仅需20元,将爱与敬意融入一束温馨的康乃馨,为特殊之人送上不凡之情。",\n\t"reason": "这个文案突出了康乃馨的价格优势,同时强调了它作为表达爱与敬意的载体,能够传递深厚的情感,吸引顾客为之买单。"\n}\n' response_metadata={'token_usage': {'completion_tokens': 72, 'prompt_tokens': 96, 'total_tokens': 168}, 'model_name': 'glm-4', 'finish_reason': 'stop'} id='run-e7fca1c4-74fc-4241-8a2c-f128048001a2-0'
发现除了我们需要的content外,还存在大量的其它参数,而在output这里,实际上我们只需要处理content这部分内容就能完成输出的解析,其它信息是冗余的,所以这就是为什么只需要取出content的原因。
2. StructuredOutputParser.parse 的预期输入
StructuredOutputParser.parse 方法设计用于接收一个 字符串 作为输入,并将其解析为结构化的数据(例如字典或特定的格式)。它依赖于输入文本的格式来提取所需的信息。
当您将一个 AIMessage 对象直接传递给 parse 方法时,Python 尝试在该对象上调用 strip 方法(这是字符串对象的一个常用方法),但 AIMessage 对象本身并没有 strip 方法,这就导致了 AttributeError。
3. 提取 content 属性解决问题
通过访问 output.content,您从 AIMessage 对象中提取出了模型生成的实际文本字符串:
output_content = output.content
然后,将这个字符串传递给 parse 方法:
parsed_output = output_parser.parse(output_content)
这样,parse 方法接收到的是预期的字符串输入,能够正常工作,并按照定义的 ResponseSchema 解析出所需的结构化数据。