English · 简体中文

![dsh-agnes-image banner](docs/banner.svg) # dsh-agnes-image

license node runtime deps dsh profiles stars

**一个工具,三种模式。** Agnes Image 2.5 Flash(`agnes-image-2.5-flash`)的 DeepSeek Harness 插件:**文生图、图生图、多图合成**,生成结果落盘为会话工作区里的真实 PNG——可以直接展示、present,或用 `read_image` 回看校验。 一个工具的表面之下,是多数生图插件省略掉的部分:**让一条丢包链路表现得像可靠服务的网络工程**。「工程细节深挖」里的每一条结论都来自实测,不是猜测。 ## 为什么是这个插件 | 你得到的 | 它改变了什么 | | --- | --- | | **三模式共用一个 Schema** | 不传 `image`=文生图;传 1 张=图生图;传多张=多图合成。模型永远不用纠结选哪个工具。 | | **落盘文件,不是 URL** | 字节以内联 base64 直接返回并写入会话工作区,agent 拿到的是可渲染、可比对、可作为参考图再次喂回的真实路径。 | | **确定性连接路径** | 仅在插件自己的 socket 上钉死 IPv4——同一个请求 **~9s 落地,而不是 20s+ 超时**(实测,见下文)。 | | **面向丢包设计** | 有界重试只覆盖连接级失败;任何 HTTP 状态码与 abort 绝不重试。 | | **密钥热轮换** | 每次调用实时解析 4 个密钥来源——轮换密钥后下一次调用即生效,无需重启。 | | **零运行时依赖** | 只有 `node:https` + harness SDK。没有别的要装,也没有别的会坏。 | | **可读的失败** | 任何错误——包括 `message` 为空的 `AggregateError`——都被归一化成一行可执行的信息,并注明实际尝试次数。 | ## 安装 需要 Node.js **22+** 与一个 DeepSeek Harness profile(`web` / `desktop` / `headless`)。 ```sh # 从 GitHub 安装 dsh plugin --profile web add github:Lijianan-123/dsh-agnes-image # 或本地克隆后安装 git clone https://github.com/Lijianan-123/dsh-agnes-image.git dsh plugin --profile web add ./dsh-agnes-image ``` 安装后重启 harness。然后配置 API 密钥(任选其一): ```sh # 1. 环境变量 export AGNES_API_KEY=sk-... # 2. harness 凭据库: ~/.dsh/.credentials.yaml → refs.AGONES_API_KEY # 3. 密钥文件: ~/.dsh/agnes-image.json → {"apiKey": "sk-..."} ``` ## 使用 装好后直接用自然语言: > 生成一张 16:9 的产品头图:深色背景上的玻璃与金属质感医疗设备,柔和轮廓光,产品摄影风格。 > 把这张 UI 截图和这个 logo 合成一张干净的应用商店预览卡片。 | 参数 | 必填 | 说明 | | --- | --- | --- | | `prompt` | ✅ | 画什么 / 怎么改。推荐结构:主体 + 场景 + 风格 + 光照 + 构图 + 质量。 | | `size` | | 分辨率档位 `1K` / `2K` / `3K` / `4K`(默认 `2K`)。 | | `ratio` | | 宽高比 `1:1` `3:4` `4:3` `16:9` `9:16` `2:3` `3:2` `21:9`(默认 `1:1`)。 | | `image` | | 参考图数组(公网 https URL 或 `data:` URI)。传 1 张=图生图,多张=多图合成。 | | `model` | | 模型 id,默认 `agnes-image-2.5-flash`。 | | `output_path` | | 目标路径(相对工作区)。默认 `agnes-images/<时间戳>-<提示词slug>.png`。 | 实测输出尺寸(与官方文档一致): | ratio | 1K | 2K | | --- | --- | --- | | `1:1` | 1024×1024 | 2048×2048 | | `16:9` | 1312×736 | 2624×1472 | ## 配置 全部可选,以下为 Loader 应用的默认值: ```jsonc { "apiKey": "", // 内联密钥;优先级最高 "credentialRef": "AGONES_API_KEY", "endpoint": "https://apihub.agnes-ai.com/v1/images/generations", "model": "agnes-image-2.5-flash", "defaultSize": "2K", "defaultRatio": "1:1", "outputDir": "", // 留空 → <会话工作区>/agnes-images "timeoutMs": 300000, "attempts": 3 // 连接级失败的总尝试次数 } ``` **密钥解析顺序**(每次调用重新解析,绝不缓存):插件配置 → harness 凭据库 → 环境变量(`AGONES_API_KEY` / `AGNES_API_KEY`)→ 密钥文件。轮换密钥后**下一次调用即生效,无需重启**。 ## 工程细节深挖 四个实战踩坑细节,浓缩在约 470 行零依赖代码里。每一条都来自一次真实的排查——下面的实测数据,就是这个插件可靠、而裸 `fetch` 封装不可靠的原因。 ### 1. 必须钉死 IPv4 + 关掉 happy-eyeballs——且只作用于自己的 socket `apihub.agnes-ai.com` 解析到 Cloudflare(`104.18.18.62` / `104.18.19.62`)**并带不可路由的 AAAA 记录**。Node 默认 `autoSelectFamily` 会做 happy-eyeballs 多地址竞速:先耗在 IPv6 上,最后以 **20s+ 的全地址 ETIMEDOUT** 收场,而且抛的是 `message` 为空的 `AggregateError`——模型侧只看到一句空 `Error:`,完全不可诊断。 修复是 `family: 4` + `autoSelectFamily: false`,把连接收敛成**单条 IPv4 路径,且不修改进程级 DNS**: | 方式 | 结果 | | --- | --- | | 默认(autoSelectFamily + AAAA) | 间歇 20s+ 全地址 `ETIMEDOUT`,空 `AggregateError` | | 自定义 `lookup` 钉 family 4 | **仍会走到 IPv6**(多地址路径下未生效),不可靠 | | `family: 4` + `autoSelectFamily: false` | **稳定成功 ~9s** | > 第二行是陷阱:用自定义 `lookup` 钉 `family: 4`,错误里却仍出现 IPv6 地址——`autoSelectFamily` 路径下它没被采纳。别只看"成功过一次"就下结论。 ### 2. 链路本身丢包——重试,但只重试连接级失败 同一个请求可能这一分钟全地址超时、下一分钟正常返回。插件做有界退避重试(默认 3 次,600/1200ms),且**只在"没收到任何 HTTP 响应"时重试**。`AbortError` 与任何 HTTP 状态码都不重试;每次失败都被归一化成一行注明实际尝试次数的信息。 ### 3. 取图只用一跳,而不是两跳(一处设计取舍) 官方默认返回图片 **URL**,需要向另一个主机(`platform-outputs.agnes-ai.space`)发起第二次网络往返。实测中生成已经成功、**却卡在下载这一跳**,把一次成功的生成浪费掉。 因此插件改为**在生成响应里直接要 base64**:文生图用 `return_base64: true`,图生图/多图合成用 `extra_body.response_format: "b64_json"`。一次请求拿到字节,没有第二个主机、没有可被卡住的下载。URL 下载仅作为兜底。 | 取图方式 | 实测耗时 | | --- | --- | | URL + 下载(两跳) | 58.3s(且下载被 abort 过一次) | | **内联 base64(一跳)** | **16.6s** | ### 4. `response_format` 不能放顶层 官方明确要求放在 `extra_body.response_format`(图生图的 `extra_body.image` 同理)。顶层放 `response_format`、或给图生图传 `tags: ["img2img"]` 都是错的。插件按模式分别构造 payload。 ## 验证 离线端到端冒烟测试:导入插件 → 假 cordis ctx 捕获工具 → 真实调用 → 校验落盘字节数。 ```sh node scripts/smoke.mjs <插件目录> <工作区目录> # registered tool: agnes_image # elapsed: 16600 ms # PASS: byte count matches disk ``` ## 已知边界:router-standard 预设的阶段门控 `router-standard` 预设用 `tools.restrict` 做渐进披露(白名单 = 阶段工具 ∪ `META_TOOLS` ∩ `GLOBAL_SAFE`)。`agnes_image` 不在其中,所以在该预设的会话里**阶段 0–2 不可见,到阶段 3(验证/交付)才开放**。内置预设(`standard` / `minimal` / `ptc` / `cordis`)与无预设会话不受此限制。 ## 兼容性 - `@deepseek-ai/dsh-tools` `>=0.1.5-rc.1 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0`、`@deepseek-ai/schemastery` `^3.18.2`——全部为范围声明,不硬编码 DSH 版本。 - Node.js 22+;除 harness SDK 外仅用 Node 内置模块。 ## 觉得有用? 如果这个插件帮你省了一次排查,或者工程深挖让你有所收获——欢迎 ⭐。Issue 和 PR 都欢迎。 ## License [MIT](LICENSE) © 2026 Jianan Li