📚 本文属于《AI开发实战》系列第7篇

  • ✅ 已完成:系列一第1-6篇
  • 🔄 进行中:系列一第7篇 ← 当前
  • 📋 待开始:系列一第8篇

📌 前置知识:建议先阅读 第1篇第2篇第3篇第4篇第5篇第6篇


一、前言:为什么多模态是AI的下一站

你有没有遇到过这些场景:

  • 截图了一段报错信息,想让AI帮你分析,但只能手动把错误信息打出来
  • 拍了一张产品图,想让AI生成描述文案,但只能文字描述图片内容
  • 想让AI听一段录音并总结要点,但没有合适的工具

多模态AI 解决的就是这些问题——让AI同时理解文本、图片、语音,不再局限于"文字进、文字出"。

模态 能力 代表API
文本 理解+生成 GPT-4o、Claude 3.5
图片 看图说话、图生文 GPT-4o、Claude 3.5
语音 识别+合成 Whisper、TTS

本文会讲什么:

  • 图片理解:让AI"看懂"图片
  • 语音识别:把音频转成文字
  • 语音合成:把文字转成语音
  • 综合实战:打造一个多模态AI助手

二、环境准备

2.1 依赖安装

pip install openai>=1.12.0 anthropic>=0.21.0 python-multipart aiofiles

2.2 API说明

服务 API 说明
OpenAI GPT-4o 支持图片输入
Anthropic Claude 3.5 支持图片输入
OpenAI Whisper 语音转文字
OpenAI TTS 文字转语音

三、图片理解:让AI看懂图片

3.1 GPT-4o 图片理解

GPT-4o 支持直接传入图片,可以是URL或base64编码。

3.1.1 从URL读取图片
import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def describe_image_from_url(image_url: str, prompt: str = "描述这张图片") -> str:
    """根据URL分析图片"""
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt},
                    {
                        "type": "image_url",
                        "image_url": {"url": image_url}
                    }
                ]
            }
        ]
    )
    return response.choices[0].message.content

# 示例:分析一张技术架构图
result = describe_image_from_url(
    "https://example.com/architecture.png",
    "这是一个系统架构图,帮我分析优缺点"
)
print(result)
3.1.2 从本地文件读取(base64)
import base64
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def describe_image_from_file(image_path: str, prompt: str = "描述这张图片") -> str:
    """分析本地图片文件"""
    
    # 读取图片并转为base64
    with open(image_path, "rb") as f:
        image_data = base64.b64encode(f.read()).decode("utf-8")
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt},
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": f"data:image/jpeg;base64,{image_data}"
                        }
                    }
                ]
            }
        ]
    )
    return response.choices[0].message.content

# 分析本地截图
result = describe_image_from_file(
    "screenshot.png",
    "这是一个错误截图,帮我分析可能的原因"
)
print(result)
3.1.3 同时分析多张图片
def compare_images(image_urls: list, prompt: str = "比较这些图片的异同") -> str:
    """同时分析多张图片"""
    
    content = [{"type": "text", "text": prompt}]
    
    for url in image_urls:
        content.append({
            "type": "image_url",
            "image_url": {"url": url}
        })
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": content}]
    )
    return response.choices[0].message.content

# 比较两张设计稿
result = compare_images([
    "https://example.com/design-v1.png",
    "https://example.com/design-v2.png"
], "比较这两个UI设计稿的布局差异")

3.2 Claude 图片理解

Claude 3.5 Sonnet 也支持图片理解,语法略有不同。

from anthropic import Anthropic

client = Anthropic()

def describe_image_claude(image_path: str, prompt: str = "描述这张图片") -> str:
    """用Claude分析本地图片"""
    
    with open(image_path, "rb") as f:
        image_data = base64.b64encode(f.read()).decode("utf-8")
    
    message = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/png",
                            "data": image_data
                        }
                    },
                    {
                        "type": "text",
                        "text": prompt
                    }
                ]
            }
        ]
    )
    return message.content[0].text

# 分析截图
result = describe_image_claude("error_screen.png", "这是一个bug截图,帮我定位问题")

3.3 实际应用:AI代码截图审查

def review_code_screenshot(image_path: str) -> dict:
    """分析代码截图,返回审查结果"""
    
    prompt = """请审查这张代码截图,完成以下任务:
    1. 识别代码语言
    2. 找出潜在的bug或问题
    3. 给出改进建议
    
    以JSON格式返回结果,包含 keys: language, issues[], suggestions[]"""
    
    with open(image_path, "rb") as f:
        image_data = base64.b64encode(f.read()).decode("utf-8")
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt},
                    {
                        "type": "image_url",
                        "image_url": {"url": f"data:image/png;base64,{image_data}"}
                    }
                ]
            }
        ],
        response_format={"type": "json_object"}
    )
    
    import json
    return json.loads(response.choices[0].message.content)

# 审查代码截图
result = review_code_screenshot("code_review.png")
print(f"语言: {result['language']}")
print(f"问题: {result['issues']}")

四、语音识别:让AI听懂音频

4.1 Whisper 语音转文字

OpenAI的Whisper是当前最好的开源语音识别模型之一。

4.1.1 基础用法:音频文件转文字
import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def transcribe_audio(audio_path: str) -> str:
    """将音频文件转录为文字"""
    
    with open(audio_path, "rb") as f:
        transcript = client.audio.transcriptions.create(
            model="whisper-1",
            file=f,
            response_format="text"  # 可选: text, json, srt, verbose_json, vtt
        )
    
    return transcript

# 转录会议录音
result = transcribe_audio("meeting.mp3")
print(result)
4.1.2 带说话人分离(后处理)
def transcribe_with_timestamps(audio_path: str) -> list:
    """转录并保留时间戳"""
    
    with open(audio_path, "rb") as f:
        result = client.audio.transcriptions.create(
            model="whisper-1",
            file=f,
            response_format="verbose_json",
            timestamp_granularities=["segment"]
        )
    
    segments = []
    for seg in result.segments:
        segments.append({
            "start": seg.start,
            "end": seg.end,
            "text": seg.text.strip()
        })
    
    return segments

# 打印带时间戳的转录
segments = transcribe_with_timestamps("lecture.mp3")
for seg in segments:
    print(f"[{seg['start']:.1f}s - {seg['end']:.1f}s] {seg['text']}")
4.1.3 指定语言 + 翻译
def transcribe_with_prompt(audio_path: str, prompt: str = "") -> str:
    """使用提示词改善转录质量
    
    prompt可以指定:
    - 音频语言
    - 专有名词
    - 上下文信息
    """
    
    with open(audio_path, "rb") as f:
        transcript = client.audio.transcriptions.create(
            model="whisper-1",
            file=f,
            language="zh",  # 指定语言,空白则自动检测
            prompt=prompt,   # 可选,帮助模型理解上下文
            response_format="text"
        )
    
    return transcript

# 转录中文音频,提示专有名词
result = transcribe_with_prompt(
    "tech_talk.mp3",
    prompt="涉及以下技术名词:LangChain、OpenAI、Claude、Vector Database"
)

4.2 实际应用:会议纪要生成

def meeting_minutes_generator(audio_path: str) -> dict:
    """从会议录音生成会议纪要"""
    
    # 第一步:转录
    transcript = transcribe_audio(audio_path)
    
    # 第二步:让AI总结
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": "你是一个会议纪要助手。请根据会议记录,生成结构化的会议纪要,包括:参会人员、讨论要点、决议事项、下一步行动。"
            },
            {
                "role": "user",
                "content": f"请为以下会议记录生成纪要:\n\n{transcript}"
            }
        ],
        response_format={"type": "json_object"}
    )
    
    import json
    return json.loads(response.choices[0].message.content)

# 生成会议纪要
minutes = meeting_minutes_generator("weekly_meeting.mp3")
print(f"参会人员: {minutes['participants']}")
print(f"讨论要点: {minutes['discussion_points']}")
print(f"决议: {minutes['decisions']}")
print(f"下一步: {minutes['action_items']}")

五、语音合成:让AI开口说话

5.1 TTS 文字转语音

import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def text_to_speech(
    text: str,
    output_path: str = "output.mp3",
    voice: str = "alloy",  # alloy, echo, fable, onyx, nova, shimmer
    model: str = "tts-1"   # tts-1 或 tts-1-hd(高清)
) -> str:
    """将文字转为语音"""
    
    response = client.audio.speech.create(
        model=model,
        voice=voice,
        input=text
    )
    
    response.write_to_file(output_path)  # 注意:新版本SDK用 write_to_file
    return output_path

# 基础用法
text_to_speech("你好,这是一个语音合成的测试。")

# 使用不同音色
text_to_speech(
    "大家好,欢迎收听今天的AI技术播客",
    output_path="podcast_intro.mp3",
    voice="nova"  # 更温暖的音色
)

5.2 语音角色扮演

def ai_voice_assistant(text: str, style: str = "professional") -> str:
    """根据场景调整语音风格
    
    style选项:
    - professional: 专业正式
    - friendly: 友好轻松
    - calm: 冷静沉稳
    """
    
    voice_map = {
        "professional": "alloy",   # 中性专业
        "friendly": "onyx",       # 温暖友好
        "calm": "echo"            # 沉稳平和
    }
    
    voice = voice_map.get(style, "alloy")
    output_path = f"response_{style}.mp3"
    
    return text_to_speech(text, output_path, voice=voice)

# 专业播报
ai_voice_assistant(
    "今日股价上涨3.5%,成交量放大至500万股",
    style="professional"
)

# 轻松对话
ai_voice_assistant(
    "太好了!这个功能终于上线了!",
    style="friendly"
)

5.3 SSML 高级控制(可选)

TTS支持SSML标记,可以更精细地控制停顿、音调等:

def text_to_speech_with_ssml(text: str, output_path: str = "output.mp3") -> str:
    """使用SSML精细控制语音"""
    
    ssml = f"""<speak>
        <break time="500ms"/>
        {text}
        <break time="300ms"/>
        播报完毕。
    </speak>"""
    
    response = client.audio.speech.create(
        model="tts-1",
        voice="alloy",
        input=ssml,
        response_format="mp3"
    )
    
    response.write_to_file(output_path)
    return output_path

六、综合实战:打造多模态AI助手

6.1 项目需求

我们来实现一个多模态AI助手,支持:

  • 文本对话
  • 图片分析
  • 语音输入(语音转文字 → AI处理 → 语音回复)
  • 语音播报

6.2 核心代码

import os
import base64
from openai import OpenAI
from anthropic import Anthropic

client_openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
client_anthropic = Anthropic()

class MultimodalAssistant:
    def __init__(self):
        self.model = "gpt-4o"  # 支持多模态的主力模型
    
    def chat(self, message: str) -> str:
        """文本对话"""
        response = client_openai.chat.completions.create(
            model=self.model,
            messages=[{"role": "user", "content": message}]
        )
        return response.choices[0].message.content
    
    def analyze_image(self, image_path: str, question: str = "描述这张图片") -> str:
        """分析图片"""
        with open(image_path, "rb") as f:
            image_data = base64.b64encode(f.read()).decode("utf-8")
        
        response = client_openai.chat.completions.create(
            model=self.model,
            messages=[
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": question},
                        {
                            "type": "image_url",
                            "image_url": {"url": f"data:image/png;base64,{image_data}"}
                        }
                    ]
                }
            ]
        )
        return response.choices[0].message.content
    
    def speech_to_text(self, audio_path: str) -> str:
        """语音转文字"""
        with open(audio_path, "rb") as f:
            transcript = client_openai.audio.transcriptions.create(
                model="whisper-1",
                file=f,
                response_format="text"
            )
        return transcript
    
    def text_to_speech(self, text: str, output_path: str = "response.mp3") -> str:
        """文字转语音"""
        response = client_openai.audio.speech.create(
            model="tts-1",
            voice="alloy",
            input=text
        )
        response.write_to_file(output_path)
        return output_path
    
    def voice_interaction(self, audio_path: str) -> tuple[str, str]:
        """完整语音交互:语音输入 → AI处理 → 语音输出"""
        # 1. 语音转文字
        user_text = self.speech_to_text(audio_path)
        print(f"用户说: {user_text}")
        
        # 2. AI处理
        ai_response = self.chat(user_text)
        print(f"AI回复: {ai_response}")
        
        # 3. 文字转语音
        audio_output = self.text_to_speech(ai_response)
        
        return ai_response, audio_output


# 使用示例
assistant = MultimodalAssistant()

# 文本对话
response = assistant.chat("解释一下什么是RAG")
print(response)

# 图片分析
description = assistant.analyze_image(
    "architecture.png",
    "这个系统架构有什么优缺点?"
)
print(description)

# 语音交互
text_response, audio_file = assistant.voice_interaction("user_question.mp3")
print(f"文字回复: {text_response}")
print(f"语音文件: {audio_file}")

6.3 进阶:流式语音合成

import io
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def stream_text_to_speech(text: str) -> bytes:
    """流式语音合成,边生成边返回"""
    
    stream = client.audio.speech.create(
        model="tts-1",
        voice="alloy",
        input=text,
        stream=True
    )
    
    audio_buffer = io.BytesIO()
    for chunk in stream.iter_bytes():
        audio_buffer.write(chunk)
    
    audio_buffer.seek(0)
    return audio_buffer.getvalue()

# 获取流式音频数据
audio_data = stream_text_to_speech("这是一段流式合成的语音测试。")
print(f"生成音频大小: {len(audio_data)} bytes")

七、常见问题与处理

7.1 图片上传失败

问题:图片太大导致API报错

解决:控制图片大小,建议不超过5MB

from PIL import Image

def resize_image_if_needed(image_path: str, max_size_mb: int = 5) -> str:
    """如果图片太大就压缩"""
    
    img = Image.open(image_path)
    
    # 检查文件大小
    file_size = os.path.getsize(image_path) / (1024 * 1024)
    
    if file_size > max_size_mb:
        # 按比例缩放
        scale = (max_size_mb / file_size) ** 0.5
        new_size = (int(img.width * scale), int(img.height * scale))
        img = img.resize(new_size, Image.LANCZOS)
        
        output_path = image_path.replace(".png", "_compressed.png")
        img.save(output_path, optimize=True)
        return output_path
    
    return image_path

7.2 Whisper转录中文不准确

问题:中文专有名词识别错误

解决:使用prompt提供上下文

def transcribe_tech_content(audio_path: str) -> str:
    """转录技术类音频,使用上下文提示"""
    
    with open(audio_path, "rb") as f:
        result = client.audio.transcriptions.create(
            model="whisper-1",
            file=f,
            language="zh",
            prompt="以下内容涉及AI技术:LangChain、Vector Database、RAG、Embedding、Claude、GPT、Token、Prompt Engineering、Function Calling、Agent"
        )
    
    return result

7.3 TTS生成语音太长被截断

问题:文本太长时可能被截断

解决:分段处理

def long_text_to_speech(text: str, max_chars: int = 4000) -> str:
    """处理长文本,分段合成"""
    
    # 按句子拆分
    sentences = text.replace("。", "。|").replace("!", "!|").replace("?", "?|").split("|")
    sentences = [s.strip() for s in sentences if s.strip()]
    
    output_files = []
    
    for i, sentence in enumerate(sentences):
        # 如果单句仍然太长,进一步拆分
        if len(sentence) > max_chars:
            # 按段落拆分
            chunks = [sentence[i:i+max_chars] for i in range(0, len(sentence), max_chars)]
            for chunk in chunks:
                output_file = f"temp_chunk_{i}.mp3"
                text_to_speech(chunk, output_file)
                output_files.append(output_file)
        else:
            output_file = f"temp_chunk_{i}.mp3"
            text_to_speech(sentence, output_file)
            output_files.append(output_file)
    
    # 合并音频文件(略,需要pydub)
    return f"合并了{len(output_files)}个片段"

7.4 多模态API成本参考

功能 模型 费用(参考)
图片理解 GPT-4o $0.021/图(1024x1024)
图片理解 Claude 3.5 按token计费
语音识别 Whisper-1 $0.006/分钟
语音合成 TTS-1 $0.015/1000字符

八、总结

技能 关键代码 说明
图片URL分析 image_url: {"url": url} GPT-4o直接分析网络图片
图片Base64分析 data:image/png;base64,{data} 本地图片转base64后分析
Claude图片分析 {"type": "image", "source": {...}} Claude格式略有不同
语音转文字 audio.transcriptions.create(model="whisper-1") 支持多语言
文字转语音 audio.speech.create(model="tts-1") 6种音色可选
多模态助手 MultimodalAssistant类 综合实战项目

多模态让AI更接近人类:看图、听话、说话——这些能力组合起来,已经能实现很多实用的AI应用了。


更多内容

如果你对AI开发、Agent实战感兴趣,欢迎关注我的公众号【码头码农】:

  • 每日AI热点解读
  • 实战项目复盘
  • 技术成长心得

扫码关注,一起进步👇

前一篇《流式响应实现:打造丝滑的AI对话体验》

本文为《AI开发实战》系列课程 · 系列一:大模型应用开发入门 · 第7篇

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐