前言
写 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 项目直接遵守)
- 生产代码、向量检索问答链,统一使用
.content,这是 LangChain 官方标准写法,兼容性最强。 - 只有确定模型只会返回纯文本、快速调试打印的时候,才偶尔用
.text。 - 写答辩代码,尽量用 content。答辩时如果被问到,就可以讲清楚二者区别,加分。
📖答辩口述小抄(直接背)
问:LangChain 中 invoke 返回结果,content 和 text 有什么区别? 答:content 是 AIMessage 消息对象原生存储字段,是官方标准,支持字符串和多模态的数组格式。text 是一个 property 装饰器的只读属性,它底层读取 content,但是会强制校验 content 必须是字符串。如果是多模态场景,访问 text 就会抛出异常。所以项目开发中优先使用 content,兼容性更好。
总结
简单一句话记住:content是原件,text是加了校验的复印件。内容看起来一样,但复印件有使用限制。开发 RAG 项目,尽量用.content,少用.text,避免后续切换模型出现意想不到的报错。