AI Agent 生图总要配商业 Key 还带水印?开源豆包网页版原生生图工具插件实战

本文介绍一款开源的AI Agent原生工具插件,实现无需商业API Key、自动绕过豆包网页版水印与风控限制,直接提取2730×1536无水印超清原图。核心涵盖DOM图像矩阵解析、哈希去重与三级质量评分算法、Node.js直连下载规避bdms-sdk拦截、以及自动切换极速对话模式等关键技术,支持DeepSeek Harness平台原生集成。

玄同 765

AI Engineer


  中国传媒大学 | 数字媒体技术(游戏设计技术方向)

  ▍深耕领域  AI Agent 架构设计 Agent Harness 工程 Context Engineering 多智能体协同 & RAG
  ▍技术底座  Python TypeScript · LangChain MCP & Skills · FastAPI Milvus Docker
  ▍工程能力  专注 Agent 运行时架构、长上下文与 Prompt Cache 优化、LLM 全链路评测与工程化落地

     

「 让 AI 交互更智能,让技术落地更高效 」   |   欢迎技术探讨 / 项目合作,关注解锁大模型与智能交互的无限可能!

AI Agent 生图总要配商业 Key 还带水印?开源豆包网页版原生生图工具插件实战

📚 《DeepSeek Harness (DSH) 插件工程与 Agent 运行时实战》连载专栏

在日常使用 AI Coding Agent 开发前端落地页、撰写技术文档、制作产品原型或生成多媒体素材时,我们经常希望直接对 Agent 说一句:“帮我生成一张 16:9 电影级 CG 风格的产品 Banner 配图并插入页面”。然而在实际工程落地中,传统的 AI 生图接入方式往往让开发者陷入三难境地:要么去申请按张计费的商业生图 API Key 并配置复杂的火山引擎/OpenAI 账单鉴权;要么切出 IDE 手动打开豆包网页版(doubao.com)输入提示词、等待生成、右键另存为带「豆包 AI 生成」水印的图片再拖回项目;要么写一段简单的爬虫脚本,结果被页面前端风控拦截(bdms-sdk 篡改页面内 fetch 抛出 TypeError: Failed to fetch)或抓回一堆模糊的渐进式缩略图(-cthumb)。

为了彻底打通「自然语言指令 → Agent 原生工具调用 → 真实浏览器豆包网页版自动化 → 2730×1536(2.7K)无水印原图落盘与多模态回传」的端到端闭环,我正式开源发布了 dsh-doubao-image v0.1.0(豆包网页版 AI 生图 Agent 原生工具插件)。安装后无需配置任何付费 API Key,也不用在输入框上方堆砌繁琐的手动面板——DeepSeek Harness 中的 Agent 会直接获得 doubao_generate_image 与 doubao_image_status 两个原生工具,像调用内置命令一样操控 Tabbit 浏览器中的豆包网页版完成文生图,并自动按 /rc_gen_image/<hash> 唯一哈希去重、优选 cgen_wm0 2730×1536 纯净无水印原图直接呈现在对话流中。

1. 开源仓库与官方包地址(MIT 协议,开箱即用):

2. 读完本文你将彻底掌握以下 4 项核心工程能力:

  • 为什么「原生 Agent 工具(Native Tool)」远胜于「输入框手动 UI 面板」:深入剖析 DSH @deepseek-ai/dsh-tools 的工具注册机制、JSON Schema 编译契约以及 link: 插件跨包解析路由(ProfileRuntimeResolution.routeLinked 与 peerDependencies 门禁);
  • 豆包网页版 cgen_wm0 2730×1536 无水印原图提取原理:揭秘豆包 Seedream 5.0 网页端同时挂载 cthumb(缩略图)、cgen_lwm3(右下角带水印展示图)与 cgen_wm0(画布底层无水印超清原图)的 DOM 渲染规律,以及如何通过 /rc_gen_image/<hash> 哈希去重与质量评分矩阵精准锁定无水印原图;
  • 绕过前端安全 SDK(bdms-sdk)拦截的混合下载架构:为什么在 Playwright page.evaluate 页面上下文内直接 fetch(byteimgUrl) 会必然触发 Failed to fetch?如何采用「浏览器内 DOM 采样 + Node.js 宿主端携带 Referer 直连拉取」实现 100% 稳定落盘;
  • 极速「豆包」对话模式自动切换与全链路防呆:如何自动检测并跳出耗时的「豆包·工作(云电脑画布)」模式(将生图耗时从 150 秒缩短至 22 秒),以及如何自动处理推广弹窗遮挡与扫码登录截图回传。

文章目录


一、为什么 AI 生图插件应该做成「Agent 原生工具」而非「手动表单面板」?(架构演进篇)

1.1 从一个直觉误区说起:给电钻加满手动旋钮 vs 让机械臂直接握住电钻

很多开发者在编写第一个 AI 生图插件时,第一反应往往是在聊天输入框上方塞一个密密麻麻的「生图工作台面板」:放一个提示词输入框、一个比例下拉框、七八个风格标签按钮,再加一个“点击生成”按钮。

这种设计看似直观,但在真实的 Agentic Workflow(智能体工作流) 中却存在三个致命缺陷:

  1. 打断多步自主编排链路(Breaking Autonomous Chains):
    当你让 Agent 执行一个复合任务(例如:“帮我写一篇技术教程,自动生成一张 16:9 的 3D 科技感封面图和两张章节配图,然后一起打包发布”)时,如果生图能力被锁死在前端 UI 按钮里,Agent 在执行到一半时就只能停下来干等人类去点按钮,完全丧失了多步工具自主编排的能力。
  2. 丧失大模型自身的 Prompt 扩写与分镜设计能力:
    用户日常随口说出的需求往往只有短短十几个字(如“画一只在月球上的宇航员橘猫”)。如果由 Agent 通过原生工具 doubao_generate_image 发起调用,大模型会在调用工具前自动根据上下文将其扩写为包含镜头景别、主光方向、材质细节、构图焦点与色彩对比的专业摄影级 Prompt,生图质量远高于用户手填的简短词条。
  3. 挤占宝贵的对话视口空间:
    常驻在输入框上方的折叠面板不仅增加视觉噪音,而且每次切换参数都要人工点选;而注册为原生工具后,界面保持 100% 纯净,用户只需用自然语言发号施令,Agent 自动完成参数映射、浏览器操控、无水印原图下载与多模态展示。

下面通过一张双模式架构对比图,直观展示「传统手动 UI 面板模式」与「dsh-doubao-image 原生 Agent 工具模式」在调用链路上的本质区别:

演进升级:从人工表单到原生工具契约

dsh-doubao-image 原生 Agent 工具模式(模型自主编排 + 无水印 2.7K 直出)

用户自然语言指令
(支持单次或复合任务)

Agent 自动扩写摄影级 Prompt
调用 doubao_generate_image 工具

操控 Tabbit 豆包网页版
切换极速模式 + 提交渲染

哈希去重优选 cgen_wm0
2730×1536 无水印原图

注入 ctx.attachments
对话流内原位高清渲染

传统手动 UI 面板模式(人工点选表单,打断 Agent 自主工作流)

用户手动展开面板
填写短词条 + 点选比例

前端发 HTTP 请求
触发单次死板脚本

抓回带水印图片链接
无法与多步任务串联

1.2 三种 AI 生图接入方案的全维度工程对比

为了帮助大家在不同业务场景下做出清晰的技术选型,下面从鉴权成本、分辨率与水印、Agent 自主编排能力、风控稳定性与多轮追问改图支持五个维度,对比三种主流接入方案:

对比维度商业生图 API(如按量计费接口)传统浏览器爬虫 / 页面内 fetch 脚本dsh-doubao-image 原生工具插件(本文方案)
API Key 与计费成本需申请商业密钥并绑定账单,按张计费(约 ¥0.2~¥0.4/张)零 API 费用,但需每次手动配置 Cookie 字符串零 API Key、零额外费用,直接复用 Tabbit 浏览器已登录豆包会话
输出分辨率与水印取决于接口档位,部分默认带显式/隐式水印极易误抓 -cthumb 模糊缩略图或 cgen_lwm3 右下角带水印图2730×1536(2.7K 超清),自动优选画布底层 cgen_wm0 纯净无水印原图
Agent 自主工具调用支持 Function Calling,但无法复用网页端画布对话上下文不支持,通常只能通过命令行手动触发原生注册 doubao_generate_image 工具,支持模型自主扩写 Prompt 与多步编排
前端风控与下载稳定性走服务端接口,无浏览器风控问题页面内 fetch 被豆包 bdms-sdk 拦截必报 Failed to fetchDOM 签名 URL 提取 + Node.js 宿主带 Referer 直连下载,100% 绕过页面拦截
单次生图端到端耗时约 10~20 秒若误入「豆包·工作」云电脑画布模式需 120~160 秒自动检测并切回极速「豆包」标准对话模式,稳定 20~25 秒出图

二、核心原理拆解:豆包网页版 DOM 图像矩阵与 cgen_wm0 无水印提取算法

2.1 揭秘豆包网页版的一图三轨 URL 结构(cthumb vs cgen_lwm3 vs cgen_wm0)

当你使用浏览器开发者工具观察豆包网页版(https://www.doubao.com/chat/)生成一张 AI 图片的过程时,你会发现页面 DOM 中并不会只出现一个 <img> 标签,而是先后挂载多达 3 种不同后缀模板的 byteimg.com 签名 URL,它们共享同一个 /rc_gen_image/<32位哈希> 路径标识:

  1. 第一阶段:渐进式模糊缩略图(-cthumb)
    URL 形如 .../rc_gen_image/df8c3dad746c43c994739e80f4c33c4d.jpeg~tplv-a9rns2rl98-cthumb_lwm3.png?...。这张图在生成初期率先挂载,用于展示高斯模糊的加载过渡效果,分辨率低且带有水印。如果脚本一看到新 <img> 出现就立即停止轮询,抓回来的必然是模糊废片。
  2. 第二阶段:标准对话带水印展示图(-cgen_lwm3)
    URL 形如 .../rc_gen_image/df8c3dad746c43c994739e80f4c33c4d.jpeg~tplv-a9rns2rl98-cgen_lwm3.png?...。分辨率达到了 2730×1536,但模板后缀 lwm3(Logo Watermark)会在图片右下角合成显眼的「豆包 AI 生成」半透明文字水印。
  3. 第三阶段:画布/预览层无水印超清原图(-cgen_wm0)
    URL 形如 .../rc_gen_image/df8c3dad746c43c994739e80f4c33c4d.jpeg~tplv-a9rns2rl98-cgen_wm0.webp?... 或 ...cgen_wm0.png?...。模板后缀 wm0(Watermark 0)代表零水印超清母版,分辨率同样为 2730×1536,画面右下角完全没有任何水印遮挡!值得注意的是,在豆包画布或缩略预览条中,cgen_wm0 对应的 <img> 元素在页面上的 CSS 渲染尺寸(clientWidth)可能只有 18px × 18px,但其真实图像尺寸(naturalWidth × naturalHeight)却是完整的 2730 × 1536!

如果我们的过滤算法简单粗暴地把所有 clientWidth < 120 的 <img> 全部当成小图标丢弃,就会在画布模式下把最宝贵的 cgen_wm0.png 无水印原图直接漏掉!

下面通过一张时序与过滤状态机图,展示 dsh-doubao-image 如何通过哈希聚类与三级质量评分(qualityScore)精准锁定无水印原图:

Node.js 原图下载器 (Referer) 哈希去重与 wm0 优选器 Tabbit Browser (doubao.com) DSH Agent (doubao_generate_image) Node.js 原图下载器 (Referer) 哈希去重与 wm0 优选器 Tabbit Browser (doubao.com) DSH Agent (doubao_generate_image) 剔除 -cthumb 缩略图、/rc/icon/ 静态图标及 naturalWidth < 360 的小图 对 /rc_gen_image/<hash> 按哈希归并,计算质量分: wm0.png (3分) > wm0.webp (2分) > lwm3 (1分) loop [每 2.5 秒轮询 DOM 图像树] 1. 检查是否处于慢速「工作」模式,自动点击「豆包」芯片切回极速模式 1 2. 采集发送前页面基准图片集合 baselineUrls & baselineKeys 2 3. 向 .ProseMirror 注入风格/比例增强 Prompt 并点击发送 3 4. 扫描全部 <img> (src, naturalWidth, clientWidth, complete) 4 5. 等待候选图进入 wm0 无水印态或连续稳定轮次达标 5 6. 返回最优签名 URL 列表(绕过页面内 bdms-sdk fetch 拦截) 6 7. Node.js 携带 Referer: https://www.doubao.com/ 下载原图落盘 7 8. 注册 ctx.attachments.saveImage 并返回多模态图文块 8
2.2 为什么不能在浏览器 page.evaluate 内部直接 fetch 图片?

在早期版本调试中,我曾尝试在 Playwright 的 page.evaluate 内部直接调用浏览器的 window.fetch(img.src) 将图片转为 Base64 返回。然而在豆包网页版中,这一调用会 100% 失败并抛出:

TypeError: Failed to fetch
    at window.fetch (https://lf-flow-web-cdn.doubao.com/.../bdms-sdk.js)

原因在于:豆包网页前端加载了字节跳动的安全风控 SDK(bdms-sdk),该脚本重写(Monkey-patch)了页面全局的 window.fetch 与 XMLHttpRequest。当页面脚本尝试直接向跨子域的 p3-flow-imagex-sign.byteimg.com 发起编程式 fetch 请求时,会被拦截器判定为异常请求并阻断。

解决方案非常优雅:byteimg.com 的图片 URL 本身已经携带了完整的时效签名参数(x-expires 与 x-signature),服务端只校验 HTTP 请求头中的 Referer: https://www.doubao.com/。因此,我们只需要在 Playwright 脚本中提取出 <img> 的签名 src 字符串,回到 Node.js 宿主进程 中使用原生 globalThis.fetch(src, { headers: { Referer: 'https://www.doubao.com/' } }) 拉取二进制流,即可彻底绕过前端 bdms-sdk 的拦截,实现毫秒级满速下载!

2.3 核心算法实战:豆包图像候选去重与 wm0 质量评分引擎(Python 完整验证版)

为了便于在 Python Agent 服务端或独立脚本中直接复用这套「哈希去重 + 三级质量评分」逻辑,下面给出完整可运行的 Python 工程实现(已通过 ast.parse 语法校验):

from __future__ import annotations

import re
from dataclasses import dataclass
from typing import Dict, Iterable, List
from urllib.parse import urlparse


@dataclass(frozen=True)
class DomImageSnapshot:
    """浏览器 DOM 采样得到的单个 <img> 元素快照与优选等级。"""
    src: str
    natural_width: int
    natural_height: int
    client_width: int
    client_height: int
    is_complete: bool = True


class ArtworkCandidateSelector:
    """豆包网页版生成图候选过滤器:剔除缩略图与图标,按哈希优选 wm0 无水印原图。"""

    RC_GEN_PATTERN = re.compile(r"/rc_gen_image/([^.~/?#]+)", re.IGNORECASE)
    EXCLUDED_TOKENS = ("-cthumb", "/rc/icon/", "/static/image/", "avatar", "qrcode", "favicon")

    @classmethod
    def extract_artwork_key(cls, url: str) -> str:
        """提取生成图的唯一内容哈希键,使同一张图的 lwm3 与 wm0 归入同一桶。"""
        match = cls.RC_GEN_PATTERN.search((url or "").strip())
        if match:
            return f"rc_gen_image:{match.group(1).lower()}"
        parsed = urlparse((url or "").strip())
        return f"{parsed.netloc}{parsed.path}"

    @classmethod
    def select_best_candidates(
        cls, snapshots: Iterable[DomImageSnapshot], baseline_urls: Iterable[str] = ()
    ) -> List[Dict[str, object]]:
        """过滤页面噪声图片,并对同一哈希的候选图自动保留最高质量的无水印版本。"""
        baseline_set = {u.strip() for u in baseline_urls if u and u.strip()}
        baseline_keys = {cls.extract_artwork_key(u) for u in baseline_set}
        best_by_key: Dict[str, Dict[str, object]] = {}

        for item in snapshots:
            raw_url = (item.src or "").strip()
            lower_url = raw_url.lower()
            if not raw_url.startswith(("http://", "https://")) or raw_url in baseline_set:
                continue
            if any(tok in lower_url for tok in cls.EXCLUDED_TOKENS) or lower_url.endswith(".svg"):
                continue
            if "/rc_gen_image/" not in lower_url and (item.client_width < 120 or item.client_height < 120):
                continue
            if not item.is_complete or item.natural_width < 360 or item.natural_height < 360:
                continue
            art_key = cls.extract_artwork_key(raw_url)
            if art_key in baseline_keys:
                continue
            tier = 3 if "wm0.png" in lower_url else (2 if "wm0" in lower_url else 1)
            prev = best_by_key.get(art_key)
            if prev is None or tier > int(prev["quality_tier"]):
                best_by_key[art_key] = {
                    "image_key": art_key, "source_url": raw_url, "watermark_free": tier >= 2,
                    "width": item.natural_width, "height": item.natural_height, "quality_tier": tier,
                }
        return list(best_by_key.values())

三、DeepSeek Harness 原生工具插件的三大深水区避坑指南(工程实战篇)

在将 dsh-doubao-image 注册为 DeepSeek Harness 的原生 Agent 工具并在 Desktop 宿主进程中热重载(HMR)时,我们先后攻克了三个极易踩坑的底层架构细节。这些经验对所有编写 DSH 宿主工具插件的开发者都具有直接的参考价值。

避坑三:豆包双模式耗时陷阱

停留在『豆包·工作』云电脑模式
启动画布 CLI 耗时 150s+

检测 create_office_task_button
自动点击顶栏『豆包』切换芯片

回归标准极速生图模式
22 秒直出 2.7K 无水印原图

避坑二:Cordis Context Proxy 门禁

直接读取未声明的 ctx.locale
或 ctx.systemPrompt

触发 Cordis Proxy 拦截:
cannot get property without inject

改用 ctx.get('locale') 与
ctx.inject(['systemPrompt'], fn)

避坑一:Linked 插件跨包路由

link: 插件导入 @deepseek-ai/dsh-tools

必须在 package.json 声明
peerDependencies + engines.dsh

激活 routeLinked() 路由
编译合法 JSON Schema

3.1 避坑一:link: 插件的 peerDependencies 路由门禁与 JSON Schema 编译

在 DSH 的插件加载器(@deepseek-ai/dsh-app-boot)中,当一个插件通过本地软链接或 Profile 安装在 ~/.dsh/profiles/desktop/node_modules/dsh-doubao-image 下时,插件内部执行 await import('@deepseek-ai/dsh-tools') 并不会走标准的向上级目录查找,而是由 ProfileRuntimeResolution.routeLinked() 进行安全路由拦截。

核心机制:routeLinked() 会调用 readPeerNames(directory) 读取插件 package.json 中的 peerDependencies 字段——只有显式列在 peerDependencies 中的 @deepseek-ai/* 宿主包,才会被允许路由到 DSH 宿主安装目录!同时,为了通过 evaluatePluginCompatibility() 的版本兼容性预检,必须在 package.json 中同步声明 "engines": { "dsh": ">=0.1.0-0" }:

{
  "name": "dsh-doubao-image",
  "version": "0.1.0",
  "engines": {
    "node": ">=18.0.0",
    "dsh": ">=0.1.0-0"
  },
  "peerDependencies": {
    "@deepseek-ai/cordis": "*",
    "@deepseek-ai/dsh-tools": "*",
    "@deepseek-ai/schemastery": "*"
  }
}

此外,@deepseek-ai/dsh-tools 的 ToolRuntime.register() 会对工具的 parameters 执行 assertObjectJsonSchema() 校验,并对 output.schema 执行 assertSupportedJsonSchema() 校验(仅允许 object、array、string、number、integer、boolean、null 七种标准 JSON Schema 类型)。即使在单元测试环境回退到本地 fallbackDefineTool 时,也必须将简写的属性字典编译为标准 { type: "object", properties, required } 结构,并将 output.schema 声明为 { type: "object", additionalProperties: true }。

3.2 避坑二:Cordis ctx Proxy 的未声明服务访问拦截(cannot get property without inject)

在 Cordis 插件框架中,传入 apply(ctx, config) 的 ctx 是一个受依赖注入(inject)严格保护的 Proxy 对象。如果你的插件只声明了:

export const inject = ['tools'];

却在 apply(ctx) 函数体里直接写了 if (ctx.locale) { ... } 或 if (ctx.systemPrompt) { ... },Cordis 的 Proxy getter 会立即抛出致命异常:

Error: cannot get property "locale" without inject

这会导致插件的 Fiber 直接进入 fiberPhase: "failed" 状态,进而连带导致后续的 ctx.tools.register 根本无法执行!

正确的工程写法是:

  1. 对于可选的即时服务(如 locale 或 attachments),使用 ctx.get('locale') 安全读取(未注册时返回 undefined,绝不抛错);
  2. 对于需要等待就绪的子服务(如 systemPrompt 与 webServer),优先调用 ctx.inject(['systemPrompt'], (promptCtx) => { ... }) 注册子 Fiber,确保主工具注册完全不受可选服务生命周期的影响。

下面给出 Python 版插件清单与工具 Schema 合规性静态审计器代码(控制在 55 行以内,可直接集成到 CI 预检流水线):

from __future__ import annotations

import json
from pathlib import Path
from typing import Any, Dict, List, Set


class PluginManifestAuditor:
    """校验 DSH 工具插件的 package.json 跨包路由声明与 JSON Schema 合法性。"""

    ALLOWED_TYPES: Set[str] = {"object", "array", "string", "number", "integer", "boolean", "null"}
    REQUIRED_PEERS: Set[str] = {
        "@deepseek-ai/cordis",
        "@deepseek-ai/dsh-tools",
        "@deepseek-ai/schemastery",
    }

    @classmethod
    def audit_package_manifest(cls, manifest_path: Path) -> List[str]:
        """检查 package.json 是否包含 engines.dsh、peerDependencies 与国际化导出。"""
        data: Dict[str, Any] = json.loads(manifest_path.read_text(encoding="utf-8"))
        errors: List[str] = []
        engines = data.get("engines") or {}
        if not isinstance(engines, dict) or not engines.get("dsh"):
            errors.append("ENGINES_DSH_MISSING: 必须声明 engines.dsh 以通过宿主预检")

        peers = set((data.get("peerDependencies") or {}).keys())
        missing_peers = cls.REQUIRED_PEERS - peers
        if missing_peers:
            errors.append(f"PEER_DEPS_INCOMPLETE: 缺少 {sorted(missing_peers)}")

        exports_map = data.get("exports") or {}
        for req_key in ("./package.json", "./locale/*.json"):
            if req_key not in exports_map:
                errors.append(f"EXPORTS_METADATA_MISSING: 缺少 {req_key} 导出项")
        return errors

    @classmethod
    def validate_tool_schema(cls, tool_spec: Dict[str, Any]) -> List[str]:
        """校验编译后的工具定义是否符合 ToolRuntime 的 JSON Schema 约束。"""
        issues: List[str] = []
        params = tool_spec.get("parameters") or {}
        if params.get("type") != "object" or not isinstance(params.get("properties"), dict):
            issues.append("INVALID_PARAM_SCHEMA: parameters 必须包含 type='object' 与 properties")
        out_type = ((tool_spec.get("output") or {}).get("schema") or {}).get("type")
        if out_type is not None and out_type not in cls.ALLOWED_TYPES:
            issues.append(f"UNSUPPORTED_OUTPUT_SCHEMA_TYPE: 非法输出类型 {out_type}")
        return issues
3.3 避坑三:自动识别并跳出慢速「豆包·工作」云电脑画布模式

豆包网页版近期在左上角引入了 「豆包」与「工作」双模式切换芯片(button[data-testid="workspace-switch-chip"]):

  • 当处于 「工作(云电脑)」模式 时,发送一条生图指令会触发后台启动云端容器、读取创意设计规范文档、初始化画布 Workspace、写入设计 Brief 再调用模型生图,全流程往往耗时 120~160 秒;
  • 而当处于 标准「豆包」对话模式 时,发送同样的生图指令会直接调用 Seedream 5.0 极速渲染通道,仅需 20~25 秒 即可生成 2730×1536 超清大图!

为此,dsh-doubao-image 在每次执行生图脚本的第 3 步内置了智能模式纠偏:一旦检测到页面存在 [data-testid="create_office_task_button"] 或 [data-testid="chat_input_action_mode"](即当前误处于「豆包·工作」模式),会自动点击顶栏的 豆包 芯片切回极速标准模式,将生图响应速度提升 5 倍以上。


四、Prompt 工程自动化:内置 8 大视觉风格预设与多模态附件注入

为了让 Agent 在调用 doubao_generate_image 时只需传入简洁的风格枚举(如 style: "chinese-ink" 或 style: "cinematic-cg")就能稳定产出大师级画质,插件内置了经过实测调优的视觉风格增强矩阵与多模态输出渲染器。

4.1 视觉风格预设矩阵与适用场景对照表
风格预设 ID (style)中文名称自动注入的底层光影与材质增强提示词(Prompt Hint)典型适用场景
cinematic-cg电影级 CG电影级 CG 渲染,极致光影质感,8K 超高清细节,Octane Render技术博客 16:9 封面图、英雄区(Hero Section)主视觉海报
photorealistic写实摄影大师级写实摄影,自然景深,真实皮肤与材质纹理,徕卡镜头光学质感电商产品写实样机、人物纪实、自然风光配图
cyberpunk赛博朋克赛博朋克霓虹未来主义,冷暖高对比光效,雨夜反射,未来科技感AI / 安全 / 极客主题演讲 PPT 背景、未来城市概念图
chinese-ink国风水墨东方美学新国风水墨意境,留白构图,宣纸纹理,淡雅晕染国风游戏概念设定、古诗词意境插画、文化专题头图
anime动漫二次元高品质新海诚/吉卜力动画电影风格,通透光感,细腻色彩与云层光影二次元角色立绘、轻小说插图、青春校园风海报
3d-isometric3D 微缩盲盒C4D + Blender 3D 盲盒潮玩渲染,柔和全局光照,磨砂亚克力与细腻粘土材质App 空状态插画、架构模块 3D 等距图标、IP 潮玩形象
minimal-editorial极简矢量插画现代极简扁平矢量插画,高级配色,几何构图,干净利落的设计感SaaS 官网功能配图、报刊杂志风章节导图、UI 引导页
4.2 提示词组装与 DSH 多模态附件渲染器实现(Python 完整实现)

当图片下载到本地 doubao_images/ 目录后,dsh-doubao-image 不仅会在工具结果中返回文件路径与分辨率元数据,还会自动调用 ctx.get('attachments').saveImage({ data: new Uint8Array(buffer), mediaType }),并在 output.render(result) 中返回 { type: 'image', attachment } 内容块。这样一来,生成的高清图片会直接作为多模态视觉输入呈现在聊天界面与大模型的视觉上下文中,Agent 可以立即对刚刚生成的图片进行视觉自检(Visual Self-Verification)!

下面是对应的 Prompt 组装器与多模态结果构建器代码(共 54 行,已通过 ast.parse 语法校验):

from __future__ import annotations

import re
from typing import Any, Dict, List


STYLE_HINT_CATALOG: Dict[str, str] = {
    "auto": "",
    "cinematic-cg": "电影级 CG 渲染,极致光影质感,8K 超高清细节,Octane Render",
    "photorealistic": "大师级写实摄影,自然景深,真实皮肤与材质纹理,徕卡镜头光学质感",
    "cyberpunk": "赛博朋克霓虹未来主义,冷暖高对比光效,雨夜反射,未来科技感",
    "chinese-ink": "东方美学新国风水墨意境,留白构图,宣纸纹理,淡雅晕染",
    "anime": "高品质新海诚/吉卜力动画电影风格,通透光感,细腻色彩与云层光影",
    "3d-isometric": "C4D + Blender 3D 盲盒潮玩渲染,柔和全局光照,磨砂亚克力与细腻粘土材质",
    "minimal-editorial": "现代极简扁平矢量插画,高级配色,几何构图,干净利落的设计感",
}


class DoubaoPromptAndResultBuilder:
    """负责将结构化生图参数合成为豆包指令,并将落盘图像封装为多模态内容块。"""

    TRIGGER_RE = re.compile(r"^(请)?(帮我)?(用豆包)?(生成|画|绘制|制作)(一张|一幅|一个)?(图片|图像|画|海报|封面)?[::\s]*")

    @classmethod
    def build_enriched_prompt(
        cls, user_prompt: str, aspect_ratio: str = "16:9", style_preset: str = "auto", negative_prompt: str = ""
    ) -> str:
        """合成带生图触发前缀、风格描述、画面比例与负向提示词的完整指令。"""
        cleaned = (user_prompt or "").strip()
        if not cleaned:
            raise ValueError("生图提示词 prompt 不能为空")
        has_trigger = bool(cls.TRIGGER_RE.search(cleaned)) or ("生成图片" in cleaned)
        head = cleaned if has_trigger else f"请生成图片:{cleaned}"

        suffixes: List[str] = []
        style_hint = STYLE_HINT_CATALOG.get((style_preset or "auto").strip().lower(), style_preset.strip())
        if style_hint:
            suffixes.append(f"画面风格:{style_hint}")
        if aspect_ratio and aspect_ratio not in cleaned:
            suffixes.append(f"画面比例:{aspect_ratio}")
        if negative_prompt.strip():
            suffixes.append(f"避免出现:{negative_prompt.strip()}")
        return f"{head}({';'.join(suffixes)})" if suffixes else head

    @classmethod
    def render_multimodal_blocks(cls, status: str, prompt_text: str, saved_files: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """将生图结果转换为 DSH 聊天界面可直接渲染的文本摘要 + 多模态图像块列表。"""
        blocks: List[Dict[str, Any]] = [{"type": "text", "text": f"status: {status}\nprompt: {prompt_text}"}]
        for item in saved_files:
            if isinstance(item.get("attachment"), dict):
                blocks.append({"type": "image", "attachment": item["attachment"]})
        return blocks

五、实机运行效果展示与三步极速安装指南

5.1 实机效果一:Agent 调用 doubao_generate_image 直出 2730×1536 无水印超清原图

当我们在 DeepSeek Harness 对话框中直接向 Agent 发送指令,Agent 会自动调用 doubao_generate_image 原生工具,操控 Tabbit 浏览器中的豆包网页版完成生成,并自动优选 cgen_wm0 2730×1536 无水印原图直接呈现在回复中(注意右下角完全没有任何水印遮挡):

1. 电影级 CG 风格(style: "cinematic-cg", aspectRatio: "16:9", 2730×1536 无水印 PNG 原图):

由 doubao_generate_image 原生工具生成的 2730x1536 无水印月球宇航员橘猫原图

2. 东方国风水墨风格(style: "chinese-ink", aspectRatio: "16:9", 2730×1536 无水印 WebP 原图):

由 doubao_generate_image 原生工具极速生成的 2730x1536 无水印国风水墨仙侠奇观图

3. Tabbit 浏览器中豆包网页版自动化生图现场实拍:

Tabbit 浏览器豆包网页版自动化生图现场

5.2 三步极速安装与配置指南

你可以通过以下任意一种方式将 dsh-doubao-image 安装到你的 DeepSeek Harness 环境中:

# 方式一:通过 npm 官方源一键安装(推荐)
dsh plugin add dsh-doubao-image

# 方式二:安装到 Desktop 桌面端 Profile
dsh plugin --profile desktop add dsh-doubao-image

# 方式三:通过 GitHub Release 预构建包直接安装
dsh plugin --profile desktop add https://github.com/xt765/dsh-doubao-image/releases/latest/download/dsh-doubao-image.tgz

安装完成后,你可以在 「设置(Settings) → 插件(Plugins) → 豆包网页生图 Agent 工具」 中按需调整默认参数,或直接保持开箱即用的默认配置:

配置项名称类型默认值核心作用与调优建议
enabledbooleantrue控制是否向 Agent 注册 doubao_generate_image 与 doubao_image_status 原生工具
defaultAspectRatiostring"16:9"当模型未显式传入 aspectRatio 时默认使用的画幅比例(支持 1:1、16:9、9:16、4:3、3:4 等)
defaultStylestring"auto"默认附加的视觉风格预设(建议保持 auto 由模型按场景自主选择)
outputDirstring"doubao_images"下载的 2.7K 无水印原图在当前工作区下的默认保存目录
timeoutMsnumber120000单次生图最大轮询等待毫秒数(范围 30000 ~ 180000)
keepTabbooleantrue生图结束后是否保留浏览器中的豆包标签页,便于后续多轮追问改图

六、总结与开源仓库地址

本文从 AI Agent 在真实工程场景下的多模态生图痛点出发,完整拆解了 dsh-doubao-image v0.1.0 的设计哲学与四大核心技术细节:

  1. 原生工具化架构:摒弃繁琐的手动表单面板,通过 @deepseek-ai/dsh-tools 注册 doubao_generate_image 与 doubao_image_status 原生工具,释放大模型自主扩写摄影级 Prompt 与多步任务编排的潜力;
  2. cgen_wm0 无水印原图优选算法:利用 /rc_gen_image/<hash> 唯一哈希归并候选图,通过三级质量评分自动优选 2730×1536 纯净无水印原图;
  3. 跨上下文直连下载:在浏览器 DOM 采样签名 URL 后交由 Node.js 宿主携带 Referer 直连拉取,100% 规避页面内 bdms-sdk 对 fetch 的风控拦截;
  4. 极速模式自动切换:自动识别并跳出耗时的「豆包·工作」云电脑模式,稳定在 20~25 秒内完成超清生图并注入当前对话多模态附件。

如果你觉得这个插件对你的日常开发或内容创作有帮助,欢迎前往 GitHub / Gitee 点亮一颗 Star ⭐,或在 Issue 区交流更多实用功能点子!

  • GitHub 仓库:https://github.com/xt765/dsh-doubao-image
  • Gitee 镜像:https://gitee.com/xt765/dsh-doubao-image
  • npm 包主页:https://www.npmjs.com/package/dsh-doubao-image
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值