OpenAI 多模态 API 实践记录

本文最后更新于 2026-08-14

OpenAI 的模型和接口迭代很快,与其记住一组很快过时的模型名,不如掌握一套稳定的调用和测试方法。本文使用 Python SDK,记录文本生成、向量嵌入、图片、视频、语音合成和语音转写的最小可运行示例。

本文最后核对时间:2026 年 8 月 14 日。模型是否可用与账号权限、地区和 API 用量等级有关,运行前应以 OpenAI 模型目录 为准。

阅读路线

能力 本文示例 主要接口 适合解决的问题
文本生成 gpt-5.6 Responses API 问答、总结、结构化生成
向量嵌入 text-embedding-3-small Embeddings API 语义检索、聚类、RAG
图片生成 gpt-image-2 Images API 文生图、图片编辑
视频生成 sora-2 Videos API 文生视频、图生视频
语音合成 tts-1 Audio Speech API 旁白、播报、无障碍阅读
语音转写 gpt-4o-transcribe Audio Transcriptions API 字幕、会议记录、语音输入

这些模型名只代表本文核对时采用的示例。实际项目中建议通过环境变量配置模型,不把模型名散落在业务代码里。

运行环境

安装依赖

1
2
3
python -m venv .venv
source .venv/bin/activate
pip install -U openai python-dotenv

Windows PowerShell 激活虚拟环境时使用:

1
.venv\Scripts\Activate.ps1

配置 API Key

在项目根目录创建 .env

1
2
3
4
5
6
7
8
9
OPENAI_API_KEY=your_api_key_here

# 可选:方便在不改代码的情况下切换模型
OPENAI_TEXT_MODEL=gpt-5.6
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
OPENAI_IMAGE_MODEL=gpt-image-2
OPENAI_VIDEO_MODEL=sora-2
OPENAI_TTS_MODEL=tts-1
OPENAI_TRANSCRIBE_MODEL=gpt-4o-transcribe

同时把 .env 加入 .gitignore,不要将 API Key 写进代码、博客或提交记录:

1
.env

初始化客户端时无需重复读取和传递 Key,SDK 会从环境变量中获取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
from time import perf_counter

from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()
client = OpenAI()


def timed_call(name, request):
"""执行一次请求并输出端到端耗时。"""
started_at = perf_counter()
result = request()
elapsed = perf_counter() - started_at
print(f"{name}: {elapsed:.2f}s")
return result

这里直接连接 OpenAI 官方 API。若项目必须使用代理或兼容服务,应将 base_url 放入独立环境变量,并确认数据处理、日志留存和密钥安全策略。

文本生成:Responses API

Responses API 是当前文本生成示例的主入口。下面用同一个问题测试模型,并记录响应耗时和 token 用量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
text_model = os.getenv("OPENAI_TEXT_MODEL", "gpt-5.6")

response = timed_call(
"text generation",
lambda: client.responses.create(
model=text_model,
input="用三句话解释向量嵌入,并给出一个实际使用场景。",
),
)

print(response.output_text)
print(
"tokens:",
response.usage.input_tokens,
"input /",
response.usage.output_tokens,
"output",
)

比较多个文本模型时,应固定输入、输出要求和运行环境,至少重复三次。单次回答更适合验证接口是否跑通,不能代表模型的稳定质量。

向量嵌入:Embedding

Embedding 将文本映射为向量。含义相近的文本,其向量通常也更接近,因此可以用于语义检索、推荐、聚类和 RAG 召回。

下面同时生成两段文本的向量,并计算余弦相似度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from math import sqrt

embedding_model = os.getenv(
"OPENAI_EMBEDDING_MODEL",
"text-embedding-3-small",
)

texts = [
"如何用向量数据库构建语义检索?",
"怎样根据文本含义搜索相似内容?",
]

embedding_response = timed_call(
"embeddings",
lambda: client.embeddings.create(
model=embedding_model,
input=texts,
encoding_format="float",
),
)

vector_a = embedding_response.data[0].embedding
vector_b = embedding_response.data[1].embedding


def cosine_similarity(a, b):
dot_product = sum(x * y for x, y in zip(a, b))
norm_a = sqrt(sum(x * x for x in a))
norm_b = sqrt(sum(y * y for y in b))
return dot_product / (norm_a * norm_b)


print("dimensions:", len(vector_a))
print("similarity:", cosine_similarity(vector_a, vector_b))

生产环境中还需要统一文本清洗、切分粒度和模型版本。若更换 Embedding 模型,通常要重新生成并写入已有向量,不能直接混用不同模型产生的向量。

图片生成:Images API

图片接口返回 Base64 编码的图片数据,可以直接解码并保存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import base64
from pathlib import Path

image_model = os.getenv("OPENAI_IMAGE_MODEL", "gpt-image-2")
image_path = Path("otter.png")

image_response = timed_call(
"image generation",
lambda: client.images.generate(
model=image_model,
prompt=(
"A warm children's book illustration of a veterinarian "
"checking a baby otter with a stethoscope."
),
),
)

image_bytes = base64.b64decode(image_response.data[0].b64_json)
image_path.write_bytes(image_bytes)
print("saved to:", image_path.resolve())

生成图片时,优先从主体、场景、构图、光线和风格五个方面描述需求。尺寸、质量、透明背景和输出格式等参数会随模型不同而变化,应查看对应模型页面后再添加。

视频生成:Videos API

视频生成通常是异步任务:先创建任务,再轮询状态,完成后下载文件。视频模型并非所有账号都可用,正式运行前还需要确认模型权限和费用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time

video_model = os.getenv("OPENAI_VIDEO_MODEL", "sora-2")

video = client.videos.create(
model=video_model,
prompt=(
"A cinematic close-up of a small robot watering a plant "
"on a sunny windowsill, gentle camera movement."
),
)

while video.status in {"queued", "in_progress"}:
print("status:", video.status, "progress:", video.progress)
time.sleep(10)
video = client.videos.retrieve(video.id)

if video.status != "completed":
raise RuntimeError(f"video generation failed: {video.status}")

content = client.videos.download_content(video.id, variant="video")
content.write_to_file("video.mp4")
print("saved to: video.mp4")

视频测试不只要看画面清晰度,还应记录指令遵循、镜头稳定性、文字准确性、生成耗时和失败率。

语音合成:Text to Speech

语音合成需要指定模型、音色和输入文本。下面将输出以流式方式保存到文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
from pathlib import Path

tts_model = os.getenv("OPENAI_TTS_MODEL", "tts-1")
speech_path = Path("speech.mp3")

with client.audio.speech.with_streaming_response.create(
model=tts_model,
voice="coral",
input="今天是适合学习和创造的一天。",
) as response:
response.stream_to_file(speech_path)

print("saved to:", speech_path.resolve())

如果使用 AI 合成语音向最终用户提供服务,应清楚说明声音由 AI 生成,而不是真人录音。不同语音模型支持的音色、语速和风格控制参数可能不同。

语音转写:Speech to Text

转写会保留音频中的原语言;翻译则把音频内容转换为英文。一般字幕、会议纪要和资料归档使用转写即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pathlib import Path

audio_path = Path("voice/test1.mp3")
transcribe_model = os.getenv(
"OPENAI_TRANSCRIBE_MODEL",
"gpt-4o-transcribe",
)

with audio_path.open("rb") as audio_file:
transcription = timed_call(
"transcription",
lambda: client.audio.transcriptions.create(
model=transcribe_model,
file=audio_file,
),
)

print(transcription.text)

确实需要将非英文音频直接翻译成英文时,可以使用 Translation 接口。该接口支持的模型和输出参数少于转写接口,应单独检查:

1
2
3
4
5
6
7
with audio_path.open("rb") as audio_file:
translation = client.audio.translations.create(
model="whisper-1",
file=audio_file,
)

print(translation.text)

如何做一次可信的模型测试

调用成功不等于完成了模型比较。建议为每种能力准备固定样例,并保存以下信息:

记录项 说明
测试日期 模型和接口会变化,结果必须带时间
SDK 版本 使用 pip show openai 查询
模型 ID 记录实际请求使用的完整模型名
输入样例 保证不同模型使用相同输入
端到端耗时 包含网络、排队和生成时间
token 或媒体用量 用于结合官方价格估算费用
输出质量 按准确性、指令遵循和稳定性评分
异常情况 记录限流、超时、内容拒绝和失败重试

文本任务至少重复三次;图片、音频和视频任务还应保存输出文件,避免只凭一次主观印象下结论。费用不建议直接写死在代码里,应在测试当天根据 OpenAI API Pricing 计算。

常见问题

401 Unauthorized

通常是 API Key 缺失、无效或加载了错误的 .env 文件。先确认 OPENAI_API_KEY 已设置,不要在日志中打印完整 Key。

404model_not_found

模型名可能已调整,或者当前项目没有该模型权限。到模型目录确认状态,再通过环境变量切换,不要直接在多处修改代码。

429 Too Many Requests

可能触发请求速率或用量限制。生产代码应使用带随机抖动的指数退避,并设置最大重试次数,避免无上限循环。

示例能运行,但结果与预期不同

先固定模型、输入和测试条件,再检查提示词是否明确。模型输出具有非确定性,重要任务应准备小型评测集,而不是只测试一个问题。

参考资料