前言
写 RAG、大模型问答项目的时候,我们都会调用llm.invoke()拿到模型返回结果。 很多新手直接复制网上代码,一会写res.content,一会写res.text,跑起来好像都能拿到文字,以为这两个是等价的,随便写哪个都行。 但是!某些场景下代码会突然报错,或者拿到的内容为空,排查半天找不到原因。
今天就把 content 和 text 的底层区别一次性讲清楚。
说明:基于 LangChain 新版本(langchain-core >=0.1)讲解。
先看示例代码
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-3.5-turbo",
api_key="xxx",
base_url="xxx"
)
res = llm.invoke("简单介绍RAG是什么")
print("==== res.content ====")
print(res.content)
print(type(res.content))
print("\\n==== res.text ====")
print(res.text)
print(type(res.text))
运行之后,看起来两个打印出来的字符串一模一样,这就是迷惑新手的地方。
1. res.content ——【标准官方属性,核心字段】
content 是 BaseMessage(AIMessage、HumanMessage 等消息对象)原生定义的标准属性。
- 保存大模型返回的主体内容;
- 类型:字符串 str(普通文本输出);
- 如果是多模态,content 也可以是列表,包含文本、图片块;
- LangChain 所有官方 API、链式调用、RetrievalQA、RAG 链,全部读取.content。
✅特点: 属于消息模型的原生字段,稳定,版本之间不会随意移除,生产环境、毕设项目优先使用 content。
重点:当模型返回空回答,content为空字符串"";流式返回拼接后的结果也是放到 content。
2. res.text ——【便捷只读属性 property,是个别名】
.text并不是 AIMessage 类里独立存储的数据,它是一个属性装饰器 @property,本质是读取 content,做简单校验之后返回。
源码逻辑简化理解:
@property
def text(self) -> str:
if not isinstance(self.content, str):
raise ValueError("content不是纯文本,无法使用.text")
return self.content
也就是说: res.text 本质 = 校验 content 是字符串,然后返回self.content。
✅正常场景:content 是普通字符串,text 和 content 输出完全一样。 ❌限制场景:一旦 content 不是简单字符串(多模态,content 为 list),访问.text直接抛异常!
核心差异对比表
表格
| content | 实例成员变量 | 原始存储内容 | ✅支持,可以是 str/list | ⭐⭐⭐⭐⭐ 官方推荐 |
| text | @property 只读属性 | 读取 content + 类型校验 | ❌不支持,非字符串直接报错 | ⭐⭐ 仅简单文本临时用 |
新手高频踩坑点
❌坑 1:所有地方无脑用 .text 普通文本问答没问题。一旦切换多模态模型,或者模型返回的 content 是数组格式,res.text直接抛出ValueError。本地单测正常,上线直接崩,属于隐性 BUG。
❌坑 2:误以为 text 是模型单独返回的另一块数据 text 没有单独存储任何内容,不是大模型返回两个字段!它只是 content 的一层包装,没有额外信息。
✅坑 3:把 text 用来赋值
res.text = "abc"
会报错,因为这是 @property,只读,不能写。而res.content可以手动赋值。
实战开发规范(RAG 项目直接遵守)
📖答辩口述小抄(直接背)
问:LangChain 中 invoke 返回结果,content 和 text 有什么区别? 答:content 是 AIMessage 消息对象原生存储字段,是官方标准,支持字符串和多模态的数组格式。text 是一个 property 装饰器的只读属性,它底层读取 content,但是会强制校验 content 必须是字符串。如果是多模态场景,访问 text 就会抛出异常。所以项目开发中优先使用 content,兼容性更好。
总结
简单一句话记住: content是原件,text是加了校验的复印件。内容看起来一样,但复印件有使用限制。 开发 RAG 项目,尽量用.content,少用.text,避免后续切换模型出现意想不到的报错。


