doubao2api
逆向豆包(Doubao)客户端 API,为 AI 智能体提供免费的多模态能力。通过 OpenAI 兼容接口,让任何纯文本模型也能识图、读文件、生成图片/音乐/视频。
起初只是想给自己的 Hermes Agent(基于 DeepSeek V4 Flash)补上识图能力,结果越写越多,索性做成了完整的逆向客户端和 API 服务。
目录
这个项目能做什么
本项目适合为通用 AI 智能体(如 OpenClaw、Hermes 等对话/任务型 Agent)补全多模态能力。
举个实际例子:我的 Hermes Agent 接入的是 DeepSeek V4 Flash——一个纯文本模型,看不了图、读不了文件、更不能生成多媒体内容。接入 doubao2api 之后,相当于给它装上了"眼睛"和"手":
-
多模态对话:多轮对话、深度思考(思维链)、联网搜索,完整的 ChatCompletion 能力
-
多模态理解:识图、读 PDF/Word/Excel/代码等 60+ 种文件格式,纯文本模型也能"看懂"图片和文档
-
多媒体生成:免费生成图片(文生图、图生图)、音乐、视频,Agent 的输出不再局限于文字
-
文件中转站(奇淫技巧):通过
/v1/files可上传任意文件(最大 1GB)获得一个永久 TOS URI,之后随时凭这个 URI 调用/v1/files/download换取 7 天有效的下载链接,过期了再换一个就行。这意味着你可以把它当作免费的跨机器文件传输通道——Agent A 在服务器 A 上传文件拿到 URI,把 URI 传给 Agent B,Agent B 在另一台服务器上凭 URI 获取下载链接直接拉取文件。无需自建 OSS,无需打通内网,单文件最大 1GB,存储不过期。有兴趣的兄弟可以基于这个开做个文件中转,感觉会很不错
⚠️ 不适合编程智能体:豆包客户端模型不支持 Function Calling / Tool Use(无法调用外部工具如文件读写、终端命令、代码搜索等),因此不适合作为编程智能体(Claude Code、Codex、OpenCode 等)的后端模型。如果你需要的是能操作代码仓库的 coding agent,请选择原生支持工具调用的模型 API。
原理
通过 QR 扫码登录(全平台)获取 sessionid 等认证 Cookie,然后调用豆包内部 SSE 流式端点实现对话、图片/视频/音乐生成。
端点 协议 思考链 状态
POST /samantha/chat/completion
JSON 明文 sentEvent
有 — block_type=10040 + 10000
✅ 推荐主用
POST /alice/message/stream_call_bot
base64 编码 payload
无
旧端点,已废弃
-
认证: Cookie (
sessionid,ttwid,passport_csrf_token) -
响应: Server-Sent Events 流
快速开始
安装
# 方式一:pip 安装(推荐)
pip install git+https://github.com/wangchuxiaoji-oss/doubao2api.git
# 方式二:从源码
git clone https://github.com/wangchuxiaoji-oss/doubao2api.git
cd doubao2api
pip install -e .
Docker 部署(可选)
docker build -t doubao2api .
docker run -d -p 9090:9090 -v ./. doubao_session.json:/app/.doubao_session.json doubao2api
前置条件
-
Python 3.10+
-
已安装依赖(pip install 会自动处理)
QR 扫码登录(推荐,跨平台)
不需要安装豆包桌面客户端:
from doubao2api.qr_login import QRLogin
result = QRLogin.login_and_save(".doubao_session.json")
从 Session 文件创建客户端
import asyncio
from doubao2api import DoubaoChatClient
async def main():
client = DoubaoChatClient.from_session()
async with client:
result = await client.chat("你好,请介绍一下你自己")
print(result.text)
asyncio.run(main())
流式输出
async with DoubaoChatClient.from_session() as client:
async for msg in client.chat_stream("讲个笑话"):
if msg.is_text_chunk:
print(msg.text, end="", flush=True)
三模式对话(快速/思考/专家)
from doubao2api import DoubaoChatClient, EXTENSION_BOT_ID
async with DoubaoChatClient.from_session(bot_id=EXTENSION_BOT_ID) as client:
# 快速模式 (need_deep_think=0)
result = await client.chat_completion("1+1=?")
# 思考模式 (need_deep_think=1) — 带思维链
result = await client.chat_completion("解释量子纠缠", need_deep_think=1)
print(f"思考: {result.thinking_text}")
print(f"回答: {result.text}")
# 专家模式 (need_deep_think=3) — 深度推理
result = await client.chat_completion("证明勾股定理", need_deep_think=3)
图片上传 + 多模态对话
from doubao2api import DoubaoChatClient, EXTENSION_BOT_ID
async with DoubaoChatClient.from_session(bot_id=EXTENSION_BOT_ID) as client:
image_bytes = open("photo.png", "rb").read()
att = await client.upload_image(image_bytes, "photo.png")
result = await client.chat_completion(
text="描述这张图片的内容",
image_attachments=[att],
need_deep_think=0,
)
注意: 图片功能需要使用 EXTENSION_BOT_ID(7338286299411103781)。
通过 REST API 上传大图片(推荐,无需 base64):
# 先上传图片,获取 CDN URL
curl -F "file=@photo.jpg" http://localhost:9090/v1/images/upload
# -> {"url": "https://...", "key": "tos-cn-i-.../xxx.png", ...}
# 然后在聊天中直接引用 URL
curl http://localhost:9090/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"doubao-expert","messages":[{"role":"user","content":[
{"type":"text","text":"这是什么?"},
{"type":"image_url","image_url":{"url":"上一步返回的url"}}
]}],"stream":true}'
文件上传 + 文档对话
支持 PDF、TXT、DOCX、XLSX、PPTX、CSV、Markdown、代码文件等 60+ 种格式。
from doubao2api import DoubaoChatClient, UploadedFile, EXTENSION_BOT_ID
async with DoubaoChatClient.from_session(bot_id=EXTENSION_BOT_ID) as client:
# 上传文件
file_bytes = open("report.pdf", "rb").read()
uploaded = await client.upload_file(file_bytes, "report.pdf")
# uploaded: UploadedFile(uri='tos-cn-i-ik7evvg4ik/xxx.pdf', name='report.pdf', size=102400, file_type='pdf')
# 带文件引用的对话
result = await client.chat_completion(
text="总结这份文档的要点",
file_attachments=[uploaded],
)
print(result.text)
多文件上传
async with DoubaoChatClient.from_session(bot_id=EXTENSION_BOT_ID) as client:
# 同时上传多个文件
files = []
for path in ["data.csv", "readme.md", "config.json"]:
data = open(path, "rb").read()
uploaded = await client.upload_file(data, path)
files.append(uploaded)
# 一次对话引用多个文件
result = await client.chat_completion(
text="对比这三个文件的内容,找出关键差异",
file_attachments=files,
)
文件 + 图片混合
async with DoubaoChatClient.from_session(bot_id=EXTENSION_BOT_ID) as client:
# 同时附带文件和图片
img_att = await client.upload_image(open("chart.png", "rb").read(), "chart.png")
file_att = await client.upload_file(open("data.csv", "rb").read(), "data.csv")
result = await client.chat_completion(
text="图表和数据是否一致?",
image_attachments=[img_att],
file_attachments=[file_att],
)
流式输出 + 文件
async with DoubaoChatClient.from_session(bot_id=EXTENSION_BOT_ID) as client:
uploaded = await client.upload_file(open("paper.pdf", "rb").read(), "paper.pdf")
async for chunk in client.chat_stream_completion(
text="逐段翻译这篇论文",
file_attachments=[uploaded],
need_deep_think=1, # 思考模式
):
if chunk.thinking:
print(f"[思考] {chunk.thinking}", end="")
if chunk.text:
print(chunk.text, end="", flush=True)
UploadedFile 数据结构
@dataclass
class UploadedFile:
uri: str = "" # TOS 存储路径,如 "tos-cn-i-ik7evvg4ik/xxx.pdf"
name: str = "" # 原始文件名
size: int = 0 # 文件大小(字节)
file_type: str = "" # 文件扩展名(不含点号)
上传流程详解
upload_file() 内部自动完成以下 4 步:
┌─────────────────────────────────────────────────────────────────────┐
│ Step 1: POST /alice/resource/prepare_upload │
│ 请求: {"tenant_id":"5","scene_id":"5","resource_type":1} │
│ 响应: service_id, upload_auth_token (AK/SK/SessionToken) │
├─────────────────────────────────────────────────────────────────────┤
│ Step 2: GET /top/v1?Action=ApplyImageUpload&ServiceId=xxx │
│ 签名: AWS Signature V4 (使用 Step 1 的 STS 凭证) │
│ 响应: StoreUri, UploadHosts, Auth (TOS token), SessionKey │
├─────────────────────────────────────────────────────────────────────┤
│ Step 3: POST https://{tos_host}/upload/v1/{store_uri} │
│ Headers: Authorization={TOS Auth}, Content-CRC32={crc32_hex} │
│ Body: 文件二进制内容 │
│ 响应: {"code":2000,"message":"Success","data":{"crc32":"xxx"}} │
├──────────────────────────────────────────────────────