LangChain 1.0实战:多模态RAG系统开发(二)——图片分析与语音转写功能实现

本文基于LangChain 1.0实现了多模态RAG系统的图片分析与语音转写功能。通过引入Qwen3-Omni全模态大模型,实现了端到端的多模态处理能力,包括图像预处理、Base64编码、多模态消息构建和历史记录处理等核心模块。文章提供了完整的代码实现和接口设计,并进行了功能测试验证,展示了如何构建能够同时处理文本、图像和音频的智能问答系统。


前言

上篇分享[《LangChain1.0实战之多模态RAG系统(一)——多模态RAG系统核心架构及智能问答功能开发》]中笔者系统介绍了基于 LangChain 1.0 构建多模态 RAG 系统的整体架构设计,并完成了智能问答基础模块的开发,实现了对话历史管理、流式响应等核心功能。

本篇笔者将在此基础上,进一步实现多模态 RAG 系统的两个重要扩展功能:图片内容分析语音信息转写。通过引入对图像和语音数据的处理能力,让 RAG 系统真正具备理解和响应多种模态信息的能力。

学习前置要求:本文是系列的第二篇,强烈建议大家先掌握第一篇中介绍的项目架构、环境配置和基础代码实现,这将有助于大家更好地理解本文的内容。

一、图片分析功能实现

1.1 传统图片分析系统建设思路

在构建图片分析系统时,传统技术方案通常采用多阶段处理流程:

核心技术路径:

  • 图像预处理:使用 OpenCV、PIL 等 Python 库对原始图像进行尺寸调整、色彩校正、噪声过滤等预处理操作
  • 文字信息提取:通过 OCR 模型(如 MonkeyOCR、DeepSeek-OCR)识别并提取图像中的文本内容
  • 语义理解分析:借助多模态大模型(如 Qwen-VL 系列)对图像进行深度语义解析,理解图像场景、对象关系等高层语义信息

这种分层处理架构虽然技术成熟,但存在流程复杂、误差累积等问题。随着多模态大模型能力的提升,笔者这里采用更简洁高效的端到端解决方案。

1.2 多模态 RAG 图片分析实现

本系统得益于Qwen3-Omni在文本、图像、音频全模态任务中保持的顶尖性能,实现一体化的图片分析功能。

1.2.1 数据结构回顾与设计

首先回顾笔者在LangChain1.0实战之多模态RAG系统(一)——多模态RAG系统核心架构及智能问答功能开发中定义的核心数据结构,多模态RAG系统会将图片经过base64编码转化为字符串中存储在ContentBlock中,与文字内容同步送入Qwen3-Omni大模型处理,这里不需要变动数据结构:

class ContentBlock(BaseModel):
type: str = Field(description="内容类型: text, image, audio")
content: Optional[str] = Field(description="内容数据")
class MessageRequest(BaseModel):
content_blocks: List[ContentBlock] = Field(default=[], description="内容块")
history: List[Dict[str, Any]] = Field(default=[], description="对话历史")
class MessageResponse(BaseModel):
content: str
timestamp: str
role: str

1.2.2 图像编码处理工具

在项目根目录创建 utils.py 文件,实现图像编码工具类,图像编码工具类负责识别用户上传图片格式并将其编码为base64字符串:

import base64
from fastapi import UploadFile, HTTPException
class ImageProcessor:
"""图像处理工具类"""
@staticmethod
def image_to_base64(image_file: UploadFile) -> str:
try:
# 读取文件内容
contents = image_file.file.read()
# 进行base64编码
base64_encoded = base64.b64encode(contents).decode('utf-8')
return base64_encoded
except Exception as e:
raise HTTPException(status_code=500, detail=f"图像编码失败: {str(e)}")
@staticmethod
def get_image_mime_type(filename: str) -> str:
extension = filename.split('.')[-1].lower()
mime_types = {
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'bmp': 'image/bmp',
'webp': 'image/webp'
}
return mime_types.get(extension, 'image/jpeg')

1.2.3 多模态消息构建

修改多模态消息构建逻辑,支持图像数据的处理,识别图片后缀格式并将其处理为base64字符串,构造格式为{"type":"image_url", "image_url":{"url": 图片base64格式}}的多模态大模型访问请求

def create_multimodal_message(request: MessageRequest, image_file: UploadFile) -> HumanMessage:
"""创建多模态消息"""
message_content = []
# 如果有图片
if image_file:
processor = ImageProcessor()
mime_type = processor.get_image_mime_type(image_file.filename)
base64_image = processor.image_to_base64(image_file)
message_content.append({
"type": "image_url",
"image_url": {
"url": f"data:{mime_type};base64,{base64_image}"
},
})
# 处理内容块
for i, block in enumerate(request.content_blocks):
if block.type == "text":
message_content.append({
"type": "text",
"text": block.content
})
elif block.type == "image":
# 只有base64格式的消息才会被接入
if block.content.startswith("data:image"):
message_content.append({
"type": "image_url",
"image_url": {
"url": block.content
},
})
return HumanMessage(content=message_content)

1.2.4 历史记录多模态支持

增强历史记录处理函数,添加图像分析的系统提示和多模态内容支持:

def convert_history_to_messages(history: List[Dict[str, Any]]) -> List[BaseMessage]:
"""将历史记录转换为 LangChain 消息格式,支持多模态内容"""
messages = []
# 添加系统消息
system_prompt = """
你是一个专业的多模态 RAG 助手,具备如下能:
1. 与用户对话的能力。
2. 图像内容识别和分析能力(OCR, 对象检测, 场景理解)
重要指导原则:
- 当用户上传图片并提出问题时,请结合图片内容和用户的具体问题来回答
- 仔细分析图片中的文字、图表、对象、场景等所有可见信息
- 根据用户的问题重点,有针对性地分析图片相关部分
- 如果图片包含文字,请准确识别并在回答中引用
- 如果用户只上传图片没有问题,则提供图片的全面分析
请以专业、准确、友好的方式回答
"""
messages.append(SystemMessage(content=system_prompt))
# 转换历史消息
for i, msg in enumerate(history):
content = msg.get("content", "")
content_blocks = msg.get("content_blocks", [])
message_content = []
if msg["role"] == "user":
for block in content_blocks:
if block.get("type") == "text":
message_content.append({
"type": "text",
"text": block.get("content", "")
})
elif block.get("type") == "image":
image_data = block.get("content", "")
if image_data.startswith("data:image"):
message_content.append({
"type": "image_url",
"image_url" : {
"url": image_data
}
})
messages.append(HumanMessage(content=message_content))
elif msg["role"] == "assistant":
messages.append(AIMessage(content=content))
return messages

1.2.5 接口格式调整

由于现在需要同时支持 JSON 数据和文件上传,将接口调整为 multipart/form-data 格式,修改chat_stream接口如下:

@app.post("/api/chat/stream")
async def chat_stream(
image_file: UploadFile = File(...),
content_blocks: str = Form(default="[]"),
history: str = Form(default="[]")
):
"""流式聊天接口(支持多模态)"""
try:
# 解析 JSON 字符串
try:
content_blocks_data = json.loads(content_blocks)
history_data = json.loads(history)
except json.JSONDecodeError as e:
raise HTTPException(status_code=400, detail=f"JSON 解析错误: {str(e)}")
# 创建请求对象(用于传递给其他函数)
request_data = MessageRequest(content_blocks=content_blocks_data, history=history_data)
# 转换消息历史
messages = convert_history_to_messages(request_data.history)
# 添加当前用户消息(支持多模态)
current_message = create_multimodal_message(request_data, image_file)
messages.append(current_message)
# 返回流式响应
return StreamingResponse(
generate_streaming_response(messages),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "text/event-stream",
}
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

完成以上五个核心模块的修改后,系统就具备了完整的图片分析能力,可以处理用户上传的图像并进行智能问答~

1.3 图片分析功能测试

完成代码开发后,我们通过 Postman 对图片分析功能进行完整测试。

测试配置步骤

1. 请求头设置
在 Postman 的 Headers 选项卡中配置:

  • Content-Type: multipart/form-data

2. 请求体配置
在 Body 选项卡中选择 form-data 格式,添加以下参数:

字段名类型
image_fileFile选择 Gemini 3.0 Logo 图片文件
content_blocksText[{"type": "text", "content": "请分析这张图片"}]
historyText[]

3. 测试执行
/api/chat/stream 端点发送 POST 请求,系统返回流式响应。

测试结果验证

从响应结果可见,系统成功识别并分析了测试图片:

  • 准确识别出图片包含 Gemini 3.0 的 Logo
  • 详细描述了 Logo 的设计元素和视觉特征
  • 提供了完整的图片内容分析

测试结果表明,图片分析功能已正常集成到多模态 RAG 系统中,能够正确处理用户上传的图片并结合问题进行智能分析。

二、音频分析功能实现

2.1 多模态RAG音频处理的实现

音频分析功能的实现思路与图片分析类似,主要通过 Base64 编码和格式转换实现音频数据的处理与传输。

2.1.1 数据结构设计

音频数据采用与图片相同的存储方式,通过 Base64 编码存储在 content 字段中:

class ContentBlock(BaseModel):
type: str = Field(description="内容类型: text, image, audio")
content: Optional[str] = Field(description="内容数据")
class MessageRequest(BaseModel):
content_blocks: List[ContentBlock] = Field(default=[], description="内容块")
history: List[Dict[str, Any]] = Field(default=[], description="对话历史")
class MessageResponse(BaseModel):
content: str
timestamp: str
role: str

2.1.2 音频处理工具类

utils.py 中添加音频处理工具类,支持多种音频格式,针对音频格式的处理笔者额外添加了上传文件大小的相关限制:

class AudioProcessor:
"""音频处理工具类"""
@staticmethod
def audio_to_base64(audio_file: UploadFile) -> str:
try:
# 验证文件类型
if not AudioProcessor.is_valid_audio_type(audio_file.content_type, audio_file.filename):
raise HTTPException(
status_code=400,
detail="不支持的音频格式,支持的格式有: MP3, WAV, OGG, M4A, FLAC"
)
# 读取文件内容
contents = audio_file.file.read()
# 验证文件大小(可选:限制为10MB)
max_size = 10 * 1024 * 1024  # 10MB
if len(contents) > max_size:
raise HTTPException(
status_code=400,
detail=f"音频文件过大,最大支持 {max_size // 1024 // 1024}MB"
)
base64_encoded = base64.b64encode(contents).decode('utf-8')
return base64_encoded
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"音频编码失败: {str(e)}")
@staticmethod
def get_audio_mime_type(filename: str) -> str:
extension = filename.split('.')[-1].lower()
mime_types = {
'mp3': 'audio/mpeg',
'wav': 'audio/wav',
'm4a': 'audio/mp4',
}
return mime_types.get(extension, 'audio/mpeg')  # 默认为MP3
@staticmethod
def is_valid_audio_type(content_type: str, filename: str) -> bool:
# 获取支持的MIME类型列表
supported_mimes = {
'audio/mpeg', 'audio/wav', 'audio/mp4'
}
# 检查content_type
if content_type and content_type in supported_mimes:
return True
# 检查文件扩展名
file_extension = filename.split('.')[-1].lower()
supported_extensions = {'mp3', 'wav', 'm4a'}
return file_extension in supported_extensions

2.1.3 多模态消息构建增强

扩展 create_multimodal_message 函数,支持音频数据的处理, 首先提取音频文件后缀并将其处理为base64格式,同时构造格式为{"type":"audio_url", "audio_url":{"url": 音频base64格式}}多模态大模型访问请求:

def create_multimodal_message(request: MessageRequest, image_file: UploadFile | None, audio_file:UploadFile | None) -> HumanMessage:
"""创建多模态消息"""
message_content = []
# 如果有图片
if image_file:
processor = ImageProcessor()
mime_type = processor.get_image_mime_type(image_file.filename)
base64_image = processor.image_to_base64(image_file)
message_content.append({
"type": "image_url",
"image_url": {
"url": f"data:{mime_type};base64,{base64_image}"
},
})
if audio_file:
processor = AudioProcessor()
mime_type = processor.get_audio_mime_type(audio_file.filename)
base64_audio = processor.audio_to_base64(audio_file)
message_content.append({
"type": "audio_url",
"audio_url": {
"url": f"data:{mime_type};base64,{base64_audio}"
},
})
# 处理内容块
for i, block in enumerate(request.content_blocks):
if block.type == "text":
message_content.append({
"type": "text",
"text": block.content
})
elif block.type == "image":
# 只有base64格式的消息才会被接入
if block.content.startswith("data:image"):
message_content.append({
"type": "image_url",
"image_url": {
"url": block.content
},
})
elif block.type == "audio":
if block.content.startswith("data:audio"):
message_content.append({
"type": "audio_url",
"audio_url": {
"url": block.content
},
})
return HumanMessage(content=message_content)

2.1.4 历史记录处理增强

更新系统提示词,添加音频处理能力,并增强历史记录处理逻辑:

def convert_history_to_messages(history: List[Dict[str, Any]]) -> List[BaseMessage]:
"""将历史记录转换为 LangChain 消息格式,支持多模态内容"""
messages = []
# 添加系统消息
system_prompt = """
你是一个专业的多模态 RAG 助手,具备如下能:
1. 与用户对话的能力。
2. 图像内容识别和分析能力(OCR, 对象检测, 场景理解)
3. 音频转写与分析
重要指导原则:
- 当用户上传图片并提出问题时,请结合图片内容和用户的具体问题来回答
- 仔细分析图片中的文字、图表、对象、场景等所有可见信息
- 根据用户的问题重点,有针对性地分析图片相关部分
- 如果图片包含文字,请准确识别并在回答中引用
- 如果用户只上传图片没有问题,则提供图片的全面分析
请以专业、准确、友好的方式回答
"""
messages.append(SystemMessage(content=system_prompt))
# 转换历史消息
for i, msg in enumerate(history):
content = msg.get("content", "")
content_blocks = msg.get("content_blocks", [])
message_content = []
if msg["role"] == "user":
for block in content_blocks:
if block.get("type") == "text":
message_content.append({
"type": "text",
"text": block.get("content", "")
})
elif block.get("type") == "image":
image_data = block.get("content", "")
if image_data.startswith("data:image"):
message_content.append({
"type": "image_url",
"image_url" : {
"url": image_data
}
})
elif block.get("type") == "audio":
audio_data = block.get("content", "")
if audio_data.startswith("data:audio"):
message_content.append({
"type": "audio_url",
"image_url": {
"url": audio_data
}
})
messages.append(HumanMessage(content=message_content))
elif msg["role"] == "assistant":
messages.append(AIMessage(content=content))
return messages

2.1.5 接口完整实现

更新聊天接口,同时支持图片和音频文件上传:

@app.post("/api/chat/stream")
async def chat_stream(
image_file: UploadFile | None = File(None),
content_blocks: str = Form(default="[]"),
history: str = Form(default="[]"),
audio_file: UploadFile | None = File(None)
):
"""流式聊天接口(支持多模态)"""
try:
# 解析 JSON 字符串
try:
content_blocks_data = json.loads(content_blocks)
history_data = json.loads(history)
except json.JSONDecodeError as e:
raise HTTPException(status_code=400, detail=f"JSON 解析错误: {str(e)}")
# 创建请求对象(用于传递给其他函数)
request_data = MessageRequest(content_blocks=content_blocks_data, history=history_data)
# 转换消息历史
messages = convert_history_to_messages(request_data.history)
# 添加当前用户消息(支持多模态)
current_message = create_multimodal_message(request_data, image_file=image_file, audio_file=audio_file)
messages.append(current_message)
# 返回流式响应
return StreamingResponse(
generate_streaming_response(messages),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "text/event-stream",
}
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

2.2 功能测试

完成代码开发后,通过 Postman 对音频分析功能进行测试。

测试配置:

  • 请求头:Content-Type: multipart/form-data
  • 请求体(form-data格式)
字段名类型
audio_fileFile选择测试音频文件(包含"你好"的录音)
content_blocksText[{"type": "text", "content": "请解析音频内容"}]
historyText[]

测试结果:
系统成功识别并转写了音频内容,准确输出三个"你好",验证了音频分析功能的正确性。

三、总结

本期分享通过集成全模态大模型的能力,成功构建了支持图片和音频分析的多模态 RAG 系统。这种端到端的解决方案大大简化了传统多模态处理的复杂性,展现了未来大模型技术的发展趋势。下期分享笔者将和大家一起处理多模态PDF文档,也是我们多模态RAG系统的核心功能,大家敬请期待~

​最后

我在一线科技企业深耕十二载,见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事,早已在效率与薪资上形成代际优势,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。

我整理出这套 AI 大模型突围资料包:

  • ✅AI大模型学习路线图
  • ✅Agent行业报告
  • ✅100集大模型视频教程
  • ✅大模型书籍PDF
  • ✅DeepSeek教程
  • ✅AI产品经理入门资料

完整的大模型学习和面试资料已经上传带到优快云的官方了,有需要的朋友可以扫描下方二维码免费领取【保证100%免费】👇👇
​​
在这里插入图片描述

为什么说现在普通人就业/升职加薪的首选是AI大模型?

人工智能技术的爆发式增长,正以不可逆转之势重塑就业市场版图。从DeepSeek等国产大模型引发的科技圈热议,到全国两会关于AI产业发展的政策聚焦,再到招聘会上排起的长队,AI的热度已从技术领域渗透到就业市场的每一个角落。

img
智联招聘的最新数据给出了最直观的印证:2025年2月,AI领域求职人数同比增幅突破200% ,远超其他行业平均水平;整个人工智能行业的求职增速达到33.4%,位居各行业榜首,其中人工智能工程师岗位的求职热度更是飙升69.6%。

AI产业的快速扩张,也让人才供需矛盾愈发突出。麦肯锡报告明确预测,到2030年中国AI专业人才需求将达600万人,人才缺口可能高达400万人,这一缺口不仅存在于核心技术领域,更蔓延至产业应用的各个环节。

在这里插入图片描述

​​
在这里插入图片描述

资料包有什么?

①从入门到精通的全套视频教程⑤⑥

包含提示词工程、RAG、Agent等技术点
在这里插入图片描述

② AI大模型学习路线图(还有视频解说)

全过程AI大模型学习路线

在这里插入图片描述

③学习电子书籍和技术文档

市面上的大模型书籍确实太多了,这些是我精选出来的

在这里插入图片描述

④各大厂大模型面试题目详解

在这里插入图片描述

⑤ 这些资料真的有用吗?

这份资料由我和鲁为民博士共同整理,鲁为民博士先后获得了北京清华大学学士和美国加州理工学院博士学位,在包括IEEE Transactions等学术期刊和诸多国际会议上发表了超过50篇学术论文、取得了多项美国和中国发明专利,同时还斩获了吴文俊人工智能科学技术奖。目前我正在和鲁博士共同进行人工智能的研究。

所有的视频教程由智泊AI老师录制,且资料与智泊AI共享,相互补充。这份学习大礼包应该算是现在最全面的大模型学习资料了。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

在这里插入图片描述
在这里插入图片描述

智泊AI始终秉持着“让每个人平等享受到优质教育资源”的育人理念‌,通过动态追踪大模型开发、数据标注伦理等前沿技术趋势‌,构建起"前沿课程+智能实训+精准就业"的高效培养体系。

课堂上不光教理论,还带着学员做了十多个真实项目。学员要亲自上手搞数据清洗、模型调优这些硬核操作,把课本知识变成真本事‌!

​​​​在这里插入图片描述
在这里插入图片描述

如果说你是以下人群中的其中一类,都可以来智泊AI学习人工智能,找到高薪工作,一次小小的“投资”换来的是终身受益!

应届毕业生‌:无工作经验但想要系统学习AI大模型技术,期待通过实战项目掌握核心技术。

零基础转型‌:非技术背景但关注AI应用场景,计划通过低代码工具实现“AI+行业”跨界‌。

业务赋能 ‌突破瓶颈:传统开发者(Java/前端等)学习Transformer架构与LangChain框架,向AI全栈工程师转型‌。

👉获取方式:

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓**

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值