Skip to content

25. 多模态应用开发

本章覆盖多模态大模型应用开发,包括图片理解、视频分析、OCR、多模态 RAG、多模态 Agent 等核心技术。2025-2026 年多模态是 LLM 应用最火热的方向之一。


多模态基础

Q: 多模态大模型的架构原理是什么?⭐⭐⭐

答: 多模态大模型的核心是将不同模态(文本、图片、音频、视频)统一到一个语义空间中。

主流架构对比:

架构代表模型原理优点缺点
Vision Encoder + LLMGPT-4o, Gemini图片通过 ViT/CLIP 编码后,映射到 LLM 的 token 空间理解能力强训练成本高
统一 TokenizerChameleon, Emu所有模态统一 tokenize,同一个 Transformer 处理架构简洁技术难度大
Cross-AttentionFlamingo, Qwen-VLLLM 通过交叉注意力层注入视觉特征可插拔增加参数量

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 output

Q: GPT-4o vs Gemini vs Claude 的多模态能力有什么区别?⭐⭐

答:

能力GPT-4oGemini 2.5 ProClaude 4 Sonnet
图片理解✅ 强✅ 最强✅ 强
多图对比
视频理解⚠️ 有限✅ 原生支持
音频理解✅ 实时
图片生成✅ 原生✅ Imagen
OCR 能力✅ 强✅ 最强✅ 强
长文档128K1M+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 不仅能"看",还能根据视觉信息做出决策和行动。

核心能力:

  1. 视觉感知:截图分析、UI 理解、文档解析
  2. 视觉推理:根据图片内容推理和决策
  3. 视觉行动:操作 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% tokenAPI 参数 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 或融合排序
成本控制?压缩图片、低分辨率模式、缓存、异步并发

LLM 应用 & Agent 开发面试准备