火山引擎Seedream文生图API部署笔记

火山引擎 Seedream 文生图 API 部署笔记
最近在公司尝试接入火山引擎的 Seedream 文生图能力。从 Seedream 3.0 到 4.0,从异步任务到同步 API,从 V4 签名到 POST 直调,踩了不少坑,也学到了很多。这篇笔记把完整过程记录下来,希望能帮到后来人。
一、背景:为什么要用 Seedream
Seedream 是火山引擎(字节跳动旗下)推出的文生图模型系列。我们业务需要高质量的商品场景图生成,对比了 Midjourney、DALL·E 3、Stable Diffusion 等方案后,Seedream 在国内部署延迟更低、中文理解更好、内容审核也更合规。最终选择了 Seedream 3.0 V30L,随后升级到了 4.0 同步 API。
二、Seedream 3.0 V30L:V4 签名算法
接入 Seedream 3.0 的第一步就是签名。火山引擎的 API 使用自研的 V4 签名算法(类似 AWS Signature V4 但细节完全不同),手动实现非常复杂。官方提供了 Python 工具库 volcengine_sign.py,强烈建议直接用。
安装
pip install volcengine-python-sdk
签名示例代码
import hashlib
import hmac
import datetime
import requests
from urllib.parse import urlparse, quote
# V4 签名核心函数
def sign_v4(access_key, secret_key, method, url, headers, body, region="cn-north-1", service="cv"):
# 1. 创建规范请求
parsed = urlparse(url)
canonical_uri = parsed.path
canonical_querystring = parsed.query
payload_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
signed_headers = ";".join(sorted([k.lower() for k in headers.keys()]))
canonical_headers = "".join([f"{k.lower()}:{v.strip()}\n" for k, v in sorted(headers.items())])
canonical_request = f"{method}\n{canonical_uri}\n{canonical_querystring}\n{canonical_headers}\n{signed_headers}\n{payload_hash}"
# 2. 创建待签字符串
t = datetime.datetime.utcnow()
date_stamp = t.strftime("%Y%m%d")
amz_date = t.strftime("%Y%m%dT%H%M%SZ")
credential_scope = f"{date_stamp}/{region}/{service}/request"
string_to_sign = f"AWS4-HMAC-SHA256\n{amz_date}\n{credential_scope}\n{hashlib.sha256(canonical_request.encode()).hexdigest()}"
# 3. 计算签名
k_date = hmac.new(f"AWS4{secret_key}".encode(), date_stamp.encode(), hashlib.sha256).digest()
k_region = hmac.new(k_date, region.encode(), hashlib.sha256).digest()
k_service = hmac.new(k_region, service.encode(), hashlib.sha256).digest()
k_signing = hmac.new(k_service, b"request", hashlib.sha256).digest()
signature = hmac.new(k_signing, string_to_sign.encode(), hashlib.sha256).hexdigest()
authorization = (
f"AWS4-HMAC-SHA256 "
f"Credential={access_key}/{credential_scope}, "
f"SignedHeaders={signed_headers}, "
f"Signature={signature}"
)
return authorization, amz_date
# 使用示例
access_key = "你的 AK"
secret_key = "你的 SK"
headers = {
"Host": "open.volcengineapi.com",
"Content-Type": "application/json",
"X-Date": "",
}
body = json.dumps({"req_key": "high_aes_general_v30l_zt2i", ...})
auth, date_str = sign_v4(access_key, secret_key, "POST", url, headers, body)
headers["Authorization"] = auth
headers["X-Date"] = date_str
YYYYMMDDTHHMMSSZ,请求头排序要与签名时一致,body hash 不能有任何多余空格。我一开始自己手写签名,花了整整半天 debug,最后还是换回了官方 SDK。如果你不是有特殊需求,千万别自己手写,直接用 volcengine_sign 就好。
三、异步任务模式:CVSync2AsyncSubmitTask + 轮询
Seedream 3.0 V30L 采用异步任务模式。调用流程分两步:
Step 1:提交任务
import json
import requests
url = "https://open.volcengineapi.com/"
action = "CVSync2AsyncSubmitTask"
version = "2023-08-01"
payload = {
"req_key": "high_aes_general_v30l_zt2i",
"prompt": "一只橘猫坐在窗台上,午后阳光洒落,写实风格",
"seed": -1,
"scale": 3.5,
"ddim_steps": 25,
"width": 1024,
"height": 1024,
"strength": 1.0,
"return_attachment": False,
"logo_permission": "never",
}
# 这里带上 V4 签名后的 headers
resp = requests.post(url + f"?Action={action}&Version={version}",
headers=signed_headers, json=payload)
result = resp.json()
task_id = result["result"]["task_id"]
print(f"Task ID: {task_id}")
Step 2:轮询结果
import time
query_action = "CVSync2AsyncQueryTask"
max_retries = 60
interval = 5
for i in range(max_retries):
query_payload = {
"req_key": "high_aes_general_v30l_zt2i",
"task_id": task_id
}
resp = requests.post(url + f"?Action={query_action}&Version={version}",
headers=signed_headers, json=query_payload)
data = resp.json()
status = data["result"]["status"]
if status == "success":
image_url = data["result"]["image_url"]
print(f"生成成功: {image_url}")
break
elif status == "failed":
print(f"生成失败: {data['result'].get('error_msg', '未知错误')}")
break
print(f"轮询第 {i+1} 次,状态: {status}")
time.sleep(interval)
- 提交任务的
req_key为high_aes_general_v30l_zt2i——这个是 V30L 模型专用的 key,写错会返回参数错误。 - 轮询间隔建议 3-5 秒,太快会被限流(返回 429)。
- 任务最长可能运行 2-3 分钟,建议设置合理的超时重试次数(60 次 × 5 秒 = 5 分钟)。
- 查询任务也需要 V4 签名,不能复用提交时的签名(因为 X-Date 不一样)。
四、req_key 的含义与选择
req_key 字段是火山引擎 API 用来区分不同模型和风格的标识符。Seedream 系列常见的有:
| req_key | 模型 | 说明 |
|---|---|---|
high_aes_general_v30l_zt2i |
Seedream 3.0 V30L | 通用文生图,异步模式 |
high_aes_general_v42_zt2i |
Seedream 3.5 | 改进版,异步模式 |
seedream_4_0_zt2i_sync |
Seedream 4.0 | 最新同步模式,推荐 |
注意 V30L 的 req_key 全小写、下划线分隔,拼写容易出错,建议直接复制官方文档的值。
五、踩坑记:Access Denied 与服务开通
{"code": "AccessDenied", "message": "You are not authorized to access this resource"}
这个错是我花时间最久的。一开始以为是 AK/SK 写错了,或者签名算法出了问题。反复检查签名逻辑、IAM 权限、甚至换了三个不同版本的 SDK,结果还是一模一样的 Access Denied。
后来才发现原因:这个模型需要先在火山引擎控制台开通服务。
开通步骤
- 登录 火山引擎控制台
- 进入「视觉智能」(Visual Intelligence)产品页
- 找到「Seedream 文生图」服务,点击「开通服务」
- 如果是企业用户,可能需要先提交工单申请白名单
- 开通后等待约 5-10 分钟权限生效
- 控制台是否已开通对应服务
- API 是否在白名单中(部分新模型需要工单申请)
- AK/SK 是否属于有权限的子账号(IAM 策略是否绑定)
- Region 是否正确(大部分用
cn-north-1)
六、升级到 Seedream 4.0:同步 API 真香
在 V30L 上线稳定运行两周后,火山引擎推出了 Seedream 4.0,最大的变化是:支持同步 API 了!
为什么切换到 4.0?
- 不需要异步轮询,一次请求直接返回图片 URL
- 不需要 V4 签名,使用标准的 API Token 认证
- 生成质量大幅提升,尤其是光影和细节
- 延迟更低:同步模式平均 3-8 秒出图
Seedream 4.0 同步 API 调用示例
import requests
url = "https://api.volcengine.com/ai/seedream/v1/text2img"
api_token = "你的 API Token" # 从控制台获取
payload = {
"prompt": "一只橘猫坐在窗台上,午后阳光洒落,写实风格,8K超清",
"style": "photorealistic",
"size": "1024x1024",
"n": 1,
"seed": -1,
"cfg_scale": 7.0,
}
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
resp = requests.post(url, headers=headers, json=payload)
result = resp.json()
if result.get("code") == 0:
image_url = result["data"]["images"][0]["url"]
print(f"生成成功: {image_url}")
else:
print(f"错误: {result.get('message')}")
对比之前 V30L 的异步模式 + V4 签名,4.0 的代码量直接减少了一半以上,而且出图更快更稳定。
Seedream 3.0 vs 4.0 对比
| 特性 | Seedream 3.0 V30L | Seedream 4.0 |
|---|---|---|
| 认证方式 | V4 签名(HMAC-SHA256) | Bearer Token |
| 调用模式 | 异步:提交 → 轮询 → 获取 | 同步:直接 POST 返回 |
| req_key | 需要指定(如 high_aes_general_v30l_zt2i) |
不需要 |
| 出图质量 | 良好 | 优秀(细节、光影大幅提升) |
| 延迟 | 30秒-3分钟(含轮询) | 3-8秒 |
| 代码复杂度 | ⭐⭐⭐⭐⭐ | ⭐ |
七、总结与建议
从 Seedream 3.0 V30L 到 4.0,这一路走得不算轻松,但收获也很实在。最终给团队的建议是:
- 能用同步就别用异步。 4.0 的同步 API 让整个流程简单了一个数量级,开发成本和维护成本都大幅降低。
- 别手写 V4 签名。 官方 SDK 成熟稳定,自己实现容易在细节上踩坑(时间格式、Header 排序、body hash 等等)。
- 先检查服务开通状态。 遇到 Access Denied 别急着 debug 代码,先去控制台看看服务开了没。
- req_key 一定要对。 不同模型对应不同的 key,写错不会给提示,只会返回奇怪的参数错误。
- 考虑成本与速度的平衡。 4.0 质量更高但价格也略贵,如果批量场景对质量要求不高,3.0 异步模式配合并发提交也能接受。
以上就是火山引擎 Seedream 文生图 API 的完整部署记录了。从 V4 签名的折磨到异步轮询的等待,再到终于用上 4.0 同步 API 的畅快,每个阶段都有值得记录的经验。希望能帮到正在接入或者即将接入的小伙伴们!