25. 多模态应用开发
本章覆盖多模态大模型应用开发,包括图片理解、视频分析、OCR、多模态 RAG、多模态 Agent 等核心技术。2025-2026 年多模态是 LLM 应用最火热的方向之一。
多模态基础
Q: 多模态大模型的架构原理是什么?⭐⭐⭐
答: 多模态大模型的核心是将不同模态(文本、图片、音频、视频)统一到一个语义空间中。
主流架构对比:
| 架构 | 代表模型 | 原理 | 优点 | 缺点 |
|---|---|---|---|---|
| Vision Encoder + LLM | GPT-4o, Gemini | 图片通过 ViT/CLIP 编码后,映射到 LLM 的 token 空间 | 理解能力强 | 训练成本高 |
| 统一 Tokenizer | Chameleon, Emu | 所有模态统一 tokenize,同一个 Transformer 处理 | 架构简洁 | 技术难度大 |
| Cross-Attention | Flamingo, Qwen-VL | LLM 通过交叉注意力层注入视觉特征 | 可插拔 | 增加参数量 |
Vision Encoder + LLM 的典型流程:
图片 → Vision Encoder (ViT/CLIP/SigLIP) → 投影层 → Visual Tokens
↓
文本 → Tokenizer → Text Tokens → LLM Decoder → 输出python
# 简化版多模态推理流程
class MultimodalModel:
def __init__(self):
self.vision_encoder = ViTModel() # 提取视觉特征
self.projection = LinearLayer() # 对齐到文本空间
self.llm = LLMDecoder() # 统一生成
def forward(self, image, text):
# 1. 图片编码
visual_features = self.vision_encoder(image) # [B, N, D]
visual_tokens = self.projection(visual_features) # [B, N, D_llm]
# 2. 文本编码
text_tokens = self.llm.embed(text) # [B, T, D_llm]
# 3. 拼接后送入 LLM
combined = concat([visual_tokens, text_tokens], dim=1)
output = self.llm.generate(combined)
return outputQ: GPT-4o vs Gemini vs Claude 的多模态能力有什么区别?⭐⭐
答:
| 能力 | GPT-4o | Gemini 2.5 Pro | Claude 4 Sonnet |
|---|---|---|---|
| 图片理解 | ✅ 强 | ✅ 最强 | ✅ 强 |
| 多图对比 | ✅ | ✅ | ✅ |
| 视频理解 | ⚠️ 有限 | ✅ 原生支持 | ❌ |
| 音频理解 | ✅ 实时 | ✅ | ❌ |
| 图片生成 | ✅ 原生 | ✅ Imagen | ❌ |
| OCR 能力 | ✅ 强 | ✅ 最强 | ✅ 强 |
| 长文档 | 128K | 1M+ | 200K |
| 中文理解 | ✅ | ✅ | ⚠️ 一般 |
| 成本/千图 | ~$2.5 | ~$1.25 | ~$3 |
选型建议:
- 图片理解为主 → Gemini(精度最高、成本最低)
- 实时语音+视觉 → GPT-4o(原生多模态)
- 代码+截图分析 → Claude(代码理解强)
- 长视频分析 → Gemini(支持长上下文)
图片理解
Q: 如何用 LLM 分析图片内容?⭐⭐⭐
答: 两种方式:Base64 直传和 URL 传参。
python
import httpx
import base64
async def analyze_image_base64(image_path: str, question: str) -> str:
"""Base64 方式:适合本地图片"""
with open(image_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
"https://api.openai.com/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "gpt-4o",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": question},
{"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{b64}"
}}
]
}]
}
)
return resp.json()["choices"][0]["message"]["content"]
async def analyze_image_url(image_url: str, question: str) -> str:
"""URL 方式:适合在线图片"""
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
"https://api.openai.com/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "gpt-4o",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": question},
{"type": "image_url", "image_url": {"url": image_url}}
]
}]
}
)
return resp.json()["choices"][0]["message"]["content"]图片 Token 计算规则(GPT-4o):
- 低分辨率(low):固定 85 tokens
- 高分辨率(high):每个 512×512 块 170 tokens + 85 base
- 一张 1024×1024 图片 ≈ 85 + 4×170 = 765 tokens
Q: OCR 与 LLM 结合的最佳实践?⭐⭐
答:
| 方案 | 适用场景 | 精度 | 速度 |
|---|---|---|---|
| LLM 直接 OCR | 简单文档、截图 | ⭐⭐⭐ | ⭐⭐ |
| PaddleOCR + LLM | 复杂排版、表格 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 专业 OCR API + LLM | 手写体、低质量图片 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
python
class OCRAgent:
"""OCR + LLM 两阶段方案"""
def __init__(self):
self.ocr_engine = PaddleOCR(use_angle_cls=True, lang='ch')
self.llm_client = AsyncClient(timeout=60)
async def extract_and_analyze(self, image_path: str, question: str) -> str:
# 阶段 1:OCR 提取文字
ocr_result = self.ocr_engine.ocr(image_path, cls=True)
text_lines = [line[1][0] for line in ocr_result[0]]
extracted_text = "\n".join(text_lines)
# 阶段 2:LLM 理解和分析
prompt = f"""以下是图片中的文字内容:
{extracted_text}
问题:{question}"""
resp = await self.llm_client.post(
"https://api.deepseek.com/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"model": "deepseek-chat", "messages": [
{"role": "user", "content": prompt}
]}
)
return resp.json()["choices"][0]["message"]["content"]视频理解
Q: 视频理解的技术方案有哪些?⭐⭐⭐
答: 视频理解的核心挑战是 token 消耗巨大——1 分钟视频可能需要 10 万+ tokens。
| 方案 | 原理 | 适用场景 | 成本 |
|---|---|---|---|
| 关键帧提取 + 图片理解 | 均匀/场景切换抽帧,逐帧分析 | 长视频摘要 | 低 |
| 视频 Embedding + RAG | 视频片段向量化,检索相关片段 | 视频问答 | 中 |
| 原生视频模型 | Gemini 等直接处理视频 | 短视频分析 | 高 |
| ASR + LLM | 先转文字,再分析 | 教学/会议视频 | 低 |
python
import cv2
from PIL import Image
import base64
import io
class VideoAnalyzer:
"""关键帧提取 + 多模态分析"""
def extract_keyframes(self, video_path: str, max_frames: int = 10) -> list[str]:
"""均匀抽帧"""
cap = cv2.VideoCapture(video_path)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
interval = max(1, total_frames // max_frames)
frames_b64 = []
for i in range(0, total_frames, interval):
cap.set(cv2.CAP_PROP_POS_FRAMES, i)
ret, frame = cap.read()
if not ret:
break
# 转 base64
img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=85)
b64 = base64.b64encode(buf.getvalue()).decode()
frames_b64.append(b64)
if len(frames_b64) >= max_frames:
break
cap.release()
return frames_b64
async def analyze_video(self, video_path: str, question: str) -> str:
frames = self.extract_keyframes(video_path)
content = [{"type": "text", "text": f"请分析这段视频。{question}"}]
for i, b64 in enumerate(frames):
content.append({"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{b64}"
}})
resp = await client.post(
"https://api.openai.com/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"model": "gpt-4o", "messages": [
{"role": "user", "content": content}
]}
)
return resp.json()["choices"][0]["message"]["content"]多模态 RAG
Q: 多模态 RAG 如何实现?⭐⭐⭐
答: 传统 RAG 只处理文本,多模态 RAG 需要同时检索文本和图片。
架构对比:
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 图片描述化 | 图片先转文字描述,走文本 RAG | 简单 | 信息损失 |
| 统一 Embedding | 文本和图片用同一个模型编码 | 语义对齐 | 模型限制 |
| 双路检索 | 文本向量 + 图片向量分别检索再融合 | 灵活 | 复杂度高 |
python
class MultimodalRAG:
"""多模态 RAG:图片+文本混合检索"""
def __init__(self):
self.text_embedder = TextEmbedding("BAAI/bge-large-zh")
self.image_embedder = ImageEmbedding("openai/clip-vit-large")
self.vector_db = MilvusClient()
self.llm = AsyncClient(timeout=60)
async def index_document(self, doc_id: str, text: str, images: list[str]):
"""索引文档(文本+图片)"""
# 文本分块 + 向量化
chunks = split_text(text, chunk_size=500)
for i, chunk in enumerate(chunks):
embedding = self.text_embedder.encode(chunk)
self.vector_db.insert("text_collection", {
"id": f"{doc_id}_text_{i}",
"vector": embedding,
"text": chunk,
"doc_id": doc_id,
"type": "text"
})
# 图片向量化
for i, img_path in enumerate(images):
embedding = self.image_embedder.encode(img_path)
self.vector_db.insert("image_collection", {
"id": f"{doc_id}_img_{i}",
"vector": embedding,
"image_path": img_path,
"doc_id": doc_id,
"type": "image"
})
async def query(self, question: str) -> str:
"""混合检索 + 多模态生成"""
# 文本检索
text_emb = self.text_embedder.encode(question)
text_results = self.vector_db.search("text_collection", text_emb, top_k=3)
# 图片检索
img_emb = self.image_embedder.encode_text(question)
img_results = self.vector_db.search("image_collection", img_emb, top_k=2)
# 构建多模态 prompt
context = "相关文本:\n" + "\n---\n".join(r["text"] for r in text_results)
content = [{"type": "text", "text": f"{context}\n\n问题:{question}"}]
for r in img_results:
with open(r["image_path"], "rb") as f:
b64 = base64.b64encode(f.read()).decode()
content.append({"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{b64}"
}})
resp = await self.llm.post(
"https://api.openai.com/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"model": "gpt-4o", "messages": [
{"role": "user", "content": content}
]}
)
return resp.json()["choices"][0]["message"]["content"]多模态 Agent
Q: 多模态 Agent 的设计要点?⭐⭐⭐
答: 多模态 Agent 不仅能"看",还能根据视觉信息做出决策和行动。
核心能力:
- 视觉感知:截图分析、UI 理解、文档解析
- 视觉推理:根据图片内容推理和决策
- 视觉行动:操作 GUI、点击按钮、填写表单
python
class VisionAgent:
"""多模态视觉 Agent — 截图+决策+行动"""
def __init__(self):
self.llm = AsyncClient(timeout=60)
self.screenshot_tool = ScreenshotTool()
async def run(self, task: str, max_steps: int = 10):
for step in range(max_steps):
# 1. 截图获取当前状态
screenshot = self.screenshot_tool.take()
# 2. LLM 分析截图 + 决策
response = await self.llm.post(
"https://api.openai.com/v1/chat/completions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "gpt-4o",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": f"任务:{task}\n当前步骤:{step+1}\n请分析截图并决定下一步操作。"},
{"type": "image_url", "image_url": {
"url": f"data:image/png;base64,{screenshot}"
}}
]
}],
"tools": [{
"type": "function",
"function": {
"name": "click",
"description": "点击屏幕上的位置",
"parameters": {
"type": "object",
"properties": {
"x": {"type": "integer"},
"y": {"type": "integer"}
}
}
}
}, {
"type": "function",
"function": {
"name": "type_text",
"description": "输入文字",
"parameters": {
"type": "object",
"properties": {"text": {"type": "string"}}
}
}
}, {
"type": "function",
"function": {
"name": "done",
"description": "任务完成",
"parameters": {"type": "object", "properties": {
"result": {"type": "string"}
}}
}
}]
}
)
# 3. 执行工具调用
msg = response.json()["choices"][0]["message"]
if msg.get("tool_calls"):
tool = msg["tool_calls"][0]
if tool["function"]["name"] == "done":
return tool["function"]["arguments"]["result"]
await self._execute_tool(tool)性能优化
Q: 多模态应用的性能优化策略?⭐⭐
答:
| 优化手段 | 效果 | 实现方式 |
|---|---|---|
| 图片压缩 | 减少 50-80% token | 缩放到合理分辨率(如 768px) |
| 低分辨率模式 | 减少 70% token | API 参数 detail: "low" |
| 关键帧提取 | 减少 90% token | 场景变化检测抽帧 |
| 图片缓存 | 避免重复传输 | 语义缓存(相同图片哈希) |
| 异步并发 | 提升吞吐 | 多图并行分析 |
| 分批处理 | 避免超限 | 长视频分段分析 |
python
from PIL import Image
import hashlib
def optimize_image(image_path: str, max_size: int = 768) -> bytes:
"""压缩图片到合理大小,减少 token 消耗"""
img = Image.open(image_path)
# 等比缩放
ratio = min(max_size / img.width, max_size / img.height)
if ratio < 1:
new_size = (int(img.width * ratio), int(img.height * ratio))
img = img.resize(new_size, Image.LANCZOS)
# 转 JPEG 压缩
buf = io.BytesIO()
img.convert("RGB").save(buf, format="JPEG", quality=80)
return buf.getvalue()
def image_hash(image_bytes: bytes) -> str:
"""图片哈希,用于缓存"""
return hashlib.md5(image_bytes).hexdigest()面试速查
| 问题 | 关键点 |
|---|---|
| 多模态架构? | Vision Encoder + 投影层 + LLM,三种架构对比 |
| Token 计算? | 低分辨率 85 tokens,高分辨率按 512×512 块计算 |
| 视频怎么处理? | 关键帧提取 → 图片理解,或 ASR + 文本分析 |
| 多模态 RAG? | 双路检索(文本+图片),统一 Embedding 或融合排序 |
| 成本控制? | 压缩图片、低分辨率模式、缓存、异步并发 |