1. 引言
在使用 LangChain 进行大模型应用开发时,content和content_block是两个经常出现但又容易混淆的概念。它们分别出现在不同的抽象层级中,承担着不同的职责。本文将从定义、使用场景、代码示例和常见问题几个方面,带你彻底搞懂这两个概念。
2. 什么是 content
content是 LangChain 中消息(Message)对象的核心字段,用于承载一条消息的实际文本内容。无论是用户输入、AI 回复还是系统提示,最终都会以content的形式存储在消息对象中。
2.1 基本用法
在 LangChain 中,构造一条消息非常简单:
fromlangchain_core.messagesimportHumanMessage,AIMessage# 构造用户消息user_msg=HumanMessage(content="你好,请介绍一下你自己")# 构造 AI 回复ai_msg=AIMessage(content="你好!我是基于大语言模型构建的 AI 助手。")2.2 content 的多种类型
content字段并不局限于纯文本,它还可以是其他类型:
# 纯文本msg1=HumanMessage(content="你好")# 多模态内容(图片 + 文本)msg2=HumanMessage(content=[{"type":"text","text":"请描述这张图片"},{"type":"image_url","image_url":{"url":"https://example.com/cat.jpg"}}])# 工具调用结果msg3=AIMessage(content="",tool_calls=[...])3. 什么是 content_block
content_block是 LangChain 中用于表示消息内容结构化组成部分的概念。当一条消息的content包含多个不同类型的片段时,每个片段就是一个content_block。
3.1 为什么需要 content_block
在实际应用中,一条消息往往不只是纯文本。例如:
- 一段文本 + 一张图片
- 一段文本 + 一个工具调用请求
- 多个文本片段组合
如果只用单一的字符串来表示content,就无法区分这些不同类型的片段。content_block正是为了解决这个问题而设计的。
3.2 常见的 content_block 类型
LangChain 提供了多种内置的 content block 类型:
fromlangchain_core.messagesimport(TextContentBlock,ImageContentBlock,ToolCallBlock,)# 文本块text_block=TextContentBlock(text="这是一段文本")# 图片块image_block=ImageContentBlock(url="https://example.com/image.png",detail="auto")# 工具调用块tool_block=ToolCallBlock(id="call_123",name="search",args={"query":"LangChain"})4. content 与 content_block 的关系
理解两者的关系是掌握它们的关键:
content是消息的顶层字段,是「容器」。content_block是content内部的结构化单元,是「内容」。
当content为字符串时,它等价于一个纯文本块;当content为列表时,列表中的每个元素就是一个content_block。
fromlangchain_core.messagesimportHumanMessage# 方式一:content 为字符串(隐式单个文本块)msg1=HumanMessage(content="你好")# 方式二:content 为列表(显式多个 content_block)msg2=HumanMessage(content=[{"type":"text","text":"你好"},{"type":"text","text":"请分析下面的数据"}])# 两种方式在底层都会被转换为 content_block 列表print(msg1.content)# 输出: 你好print(msg2.content)# 输出: [{'type': 'text', 'text': '你好'}, {'type': 'text', 'text': '请分析下面的数据'}]5. 实际应用场景
5.1 多模态对话
fromlangchain_core.messagesimportHumanMessage# 构造包含图片和文本的多模态消息message=HumanMessage(content=[{"type":"text","text":"这张图片里有什么?"},{"type":"image_url","image_url":{"url":"https://example.com/photo.jpg"}}])# 发送给支持多模态的模型response=llm.invoke([message])5.2 流式输出处理
fromlangchain_core.messagesimportAIMessageChunk# 流式输出时,每个 chunk 的 content 可能是部分内容forchunkinllm.stream("讲个笑话"):# 每个 chunk 都是一个 AIMessageChunk# 其 content 可能是字符串或 content_block 列表ifisinstance(chunk.content,list):forblockinchunk.content:ifblock.get("type")=="text":print(block["text"],end="")else:print(chunk.content,end="")5.3 工具调用场景
fromlangchain_core.messagesimportAIMessage# 模型返回工具调用时,content 可能为空,但 tool_calls 中有内容ai_message=AIMessage(content="",tool_calls=[{"name":"calculator","args":{"expression":"2 + 2"},"id":"call_001"}])# 此时可以通过 content_block 的方式访问fortool_callinai_message.tool_calls:print(f"调用工具:{tool_call['name']}, 参数:{tool_call['args']}")6. 常见问题与注意事项
6.1 content 为 None 的情况
某些消息(如纯工具调用消息)的content可能为None或空字符串,处理时需要注意判空:
ifmessage.content:# 处理 contentpasselse:# content 为空,可能是工具调用消息pass6.2 不同模型的兼容性
不同模型对content_block的支持程度不同。OpenAI 支持text和image_url类型,而 Anthropic 使用text和image类型。LangChain 会做自动转换,但自定义时需要注意:
# OpenAI 风格openai_content=[{"type":"text","text":"你好"},{"type":"image_url","image_url":{"url":"..."}}]# Anthropic 风格anthropic_content=[{"type":"text","text":"你好"},{"type":"image","source":{"type":"url","url":"..."}}]6.3 序列化与反序列化
content_block在存储和传输时会被序列化为 JSON,需要注意保持结构完整:
importjsonfromlangchain_core.messagesimportHumanMessage msg=HumanMessage(content=[{"type":"text","text":"你好"}])# 序列化serialized=msg.model_dump_json()print(serialized)# 反序列化fromlangchain_core.messagesimportmessage_to_dict,messages_from_dict restored=messages_from_dict([json.loads(serialized)])7. 总结
content是消息的顶层内容字段,可以是字符串或结构化列表。content_block是content的结构化组成单元,用于表达多模态、多类型内容。- 当
content为字符串时,LangChain 内部会将其视为单个文本块。 - 处理多模态输入、流式输出和工具调用时,理解
content_block至关重要。
掌握这两个概念,能帮助你更灵活地构建复杂的对话应用,充分发挥 LangChain 的能力。