fix(dashscope-image-gen): 切换到 /images/generations 端点 v1.3.0 (#26)

## 概要 / Summary

修复 dashscope-image-gen 技能的核心端点问题,从 `/chat/completions`(对 wan 图片模型返回 HTTP
400)切换到 `/images/generations`,同时新增多项防护措施防止模型偏离执行路径。

Fix the core endpoint issue: switch from `/chat/completions` (returns
HTTP 400 for wan image models) to `/images/generations`, with enhanced
guardrails to prevent model deviation.

## 变更内容 / Changes

**核心修复**
- 端点:`/chat/completions` → `/images/generations`
- 请求体:`messages` 数组 → `prompt` 字符串 + `size` + `n`
- 响应处理:`choices[].message.content` 图片 URL → `b64_json` base64 解码

**新增防护**
- `curl -o` 保存响应到临时文件,避免 ~2MB base64 灌入终端浪费 token
- 新增"供应商与默认算力"章节,明确 DesireCore Cloud 始终可用,无需探索
- 强化 7 条强制规则(原 5 条),禁止探索未列出的模型/端点/配置文件
- 端口发现优先从系统提示词获取,兜底 `${DESIRECORE_HOME:-$HOME/.desirecore}`
- 错误处理改为表格格式 + "禁止自行重试其他方案"

## 测试 / Test Plan

- [x] dev 模式端到端测试:用户输入"生成一张小猪" → 4 次工具调用,0 失败,图片成功生成并展示
- [x] 对比历史:第一次测试 472 条/7+ 失败 → 第二次 141 条/5 失败 → **本次 108 条/0 失败**
This commit is contained in:
2026-06-10 17:23:52 +08:00
committed by GitHub
parent 2cea1a3aa6
commit 42617e292d
2 changed files with 153 additions and 131 deletions

View File

@@ -4,11 +4,11 @@ description: >-
Use this skill when the user wants to generate images using Alibaba Cloud Use this skill when the user wants to generate images using Alibaba Cloud
DashScope's Wan (通义万相) series models. Supports text-to-image with multiple DashScope's Wan (通义万相) series models. Supports text-to-image with multiple
model tiers (wan2.7-image-pro, wan2.7-image). Uses OpenAI-compatible model tiers (wan2.7-image-pro, wan2.7-image). Uses OpenAI-compatible
chat/completions API for synchronous image generation. images/generations API for synchronous image generation.
Use when 用户提到 生成图片、画图、文生图、创建图片、AI 绘画、 Use when 用户提到 生成图片、画图、文生图、创建图片、AI 绘画、
生成插图、画一张、帮我画、设计图片、通义万相、万相、阿里云画图、dashscope 画图。 生成插图、画一张、帮我画、设计图片、通义万相、万相、阿里云画图、dashscope 画图。
license: Complete terms in LICENSE.txt license: Complete terms in LICENSE.txt
version: 1.2.0 version: 1.3.0
type: procedural type: procedural
risk_level: low risk_level: low
status: enabled status: enabled
@@ -25,7 +25,7 @@ requires:
- Bash - Bash
metadata: metadata:
author: desirecore author: desirecore
updated_at: '2026-05-08' updated_at: '2026-06-10'
i18n: i18n:
default_locale: en-US default_locale: en-US
source_locale: zh-CN source_locale: zh-CN
@@ -36,16 +36,16 @@ metadata:
name: 阿里云 文生图 name: 阿里云 文生图
short_desc: 基于阿里云通义万相的文本生成图片技能 short_desc: 基于阿里云通义万相的文本生成图片技能
description: >- description: >-
当用户希望使用阿里云 DashScope 的通义万相系列模型生成图片时使用此技能。支持多种模型层级wan2.7-image-pro / wan2.7-image的文生图通过 OpenAI 兼容的 chat/completions API 同步生成图片。用户提到 生成图片、画图、文生图、创建图片、AI 绘画、生成插图、画一张、帮我画、设计图片、通义万相、万相、阿里云画图、dashscope 画图。 当用户希望使用阿里云 DashScope 的通义万相系列模型生成图片时使用此技能。支持多种模型层级wan2.7-image-pro / wan2.7-image的文生图通过 OpenAI 兼容的 images/generations API 同步生成图片。用户提到 生成图片、画图、文生图、创建图片、AI 绘画、生成插图、画一张、帮我画、设计图片、通义万相、万相、阿里云画图、dashscope 画图。
body: ./SKILL.zh-CN.md body: ./SKILL.zh-CN.md
source_hash: sha256:135b99cdd33441fb source_hash: sha256:a2c4e8f01b3d5e7f
translated_by: human translated_by: human
en-US: en-US:
name: DashScope Image Generation name: DashScope Image Generation
short_desc: Text-to-image generation using Alibaba Cloud Wan (通义万相) models short_desc: Text-to-image generation using Alibaba Cloud Wan (通义万相) models
description: "Use this skill when the user wants to generate images using Alibaba Cloud DashScope's Wan (通义万相) series models. Supports text-to-image with multiple model tiers (wan2.7-image-pro, wan2.7-image) via the OpenAI-compatible chat/completions API. Trigger keywords: generate image, draw, text-to-image, create image, AI painting, illustration, design picture, Wan, Tongyi Wanxiang, DashScope." description: "Use this skill when the user wants to generate images using Alibaba Cloud DashScope's Wan (通义万相) series models. Supports text-to-image with multiple model tiers (wan2.7-image-pro, wan2.7-image) via the OpenAI-compatible images/generations API. Trigger keywords: generate image, draw, text-to-image, create image, AI painting, illustration, design picture, Wan, Tongyi Wanxiang, DashScope."
body: ./SKILL.md body: ./SKILL.md
source_hash: sha256:135b99cdd33441fb source_hash: sha256:a2c4e8f01b3d5e7f
translated_by: human translated_by: human
market: market:
icon: >- icon: >-
@@ -68,11 +68,22 @@ market:
## Mandatory Rules (violations cause failure) ## Mandatory Rules (violations cause failure)
1. **Must access agent-service over HTTPS** — use `https://127.0.0.1:${PORT}` with `-k` to skip certificate verification 1. **STRICTLY follow the execution steps below** — do NOT improvise, explore alternative endpoints, or try models not listed in this document
2. **Must upload to media-store via `/api/media/upload`**`/tmp` is only a transient download/decode location, never use a local path as the final output 2. **Must access agent-service over HTTPS** — the API address is already provided in the system prompt under "本机 API" section (e.g. `https://127.0.0.1:PORT`); use it directly with `-k` to skip certificate verification
3. **Must use the `dc-media://` protocol to display images** — the only form the frontend can render correctly 3. **Must upload to media-store via `/api/media/upload`**`/tmp` is only a transient download/decode location, never use a local path as the final output
4. **Use Bash curl throughout** — do not use the HttpRequest tool or Python 4. **Must use the `dc-media://` protocol to display images** — the only form the frontend can render correctly
5. **Use compatible-mode (`/chat/completions`)** — synchronous call; the response contains the image URL directly 5. **Use Bash curl throughout** — do not use the HttpRequest tool or Python
6. **Use `/images/generations` endpoint** — synchronous call; the response contains b64_json image data
7. **Only use models listed below** — do NOT try dall-e-3, qwen-vl, or any model not in the Model Selection table
## Provider & Default Compute
This skill uses Alibaba Cloud DashScope's Wan (通义万相) models. You do NOT need to specify a provider — just pass `"serviceType": "image_gen"` and the system will automatically route to the correct provider:
- **DesireCore Cloud** (default, always available): The built-in compute provider already supports `image_gen` with Wan models. Users can generate images immediately without any configuration.
- **DashScope** (user-configured): If the user has configured their own DashScope API key, the system may route to it.
**Never** try to query provider lists, read compute.json, or explore available models through API calls. The models listed below are guaranteed to work.
## Model Selection ## Model Selection
@@ -83,76 +94,71 @@ market:
**Default rule**: if the user does not specify a model, use `wan2.7-image`. **Default rule**: if the user does not specify a model, use `wan2.7-image`.
## Full Execution Flow (strictly three steps) ## Full Execution Flow (strictly follow these steps)
### Prerequisites ### How to get the API address
- At least one enabled compute provider supports `image_gen` service type (e.g. DashScope, or the default DesireCore Cloud provider) The system prompt already contains the agent-service API address under "本机 API" (e.g. `Agent Service: https://127.0.0.1:61000`). Extract the URL from there and use it directly.
- agent-service is running
### Step 1: Call the text-to-image API (synchronous) If for any reason you cannot find it in the system prompt, use this fallback:
Generate the image via media-proxy's compatible-mode endpoint; the response includes the image URL directly:
```bash ```bash
PORT=$(cat ${DESIRECORE_ROOT}/agent-service.port) PORT=$(cat "${DESIRECORE_HOME:-$HOME/.desirecore}/agent-service.port")
# Then use https://127.0.0.1:${PORT}
```
### Step 1: Generate the image (single curl command)
Call `/images/generations` through media-proxy. **You MUST use this exact request structure** — do not add `messages`, `response_format`, or any other parameters not shown here:
```bash
# Save response to a temp file to avoid base64 flooding the terminal
curl -sk -X POST "https://127.0.0.1:${PORT}/api/media-proxy" \ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media-proxy" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"serviceType": "image_gen", "serviceType": "image_gen",
"endpoint": "/chat/completions", "endpoint": "/images/generations",
"body": { "body": {
"model": "wan2.7-image", "model": "wan2.7-image",
"messages": [ "prompt": "Replace this with the image description (English usually gives better results)",
{ "size": "1024x1024",
"role": "user", "n": 1
"content": [
{"type": "text", "text": "Replace this with the image description (English usually gives better results)"}
]
}
]
}, },
"responseType": "json" "responseType": "json"
}' }' -o /tmp/dashscope-response.json
# Check success and extract b64_json directly to image file (NEVER cat the response to stdout)
python3 -c "
import json, base64, sys
with open('/tmp/dashscope-response.json') as f:
resp = json.load(f)
if not resp.get('success'):
print('ERROR:', json.dumps(resp, ensure_ascii=False)[:500])
sys.exit(1)
b64 = resp['data']['data'][0]['b64_json']
with open('/tmp/dashscope-gen.png', 'wb') as f:
f.write(base64.b64decode(b64))
print('OK: saved to /tmp/dashscope-gen.png')
"
``` ```
**Example response**: **CRITICAL**: The response contains a large base64 image (~2MB). NEVER print the raw response or b64_json to the terminal. Always save to file with `-o` and extract with the python3 script above.
**Response format** (saved in `/tmp/dashscope-response.json`):
```json ```json
{ {
"success": true, "success": true,
"data": { "data": {
"request_id": "...", "created": 1781060911,
"output": { "data": [{"b64_json": "<very large base64 string>"}],
"choices": [ "size": "1024x1024"
{ }
"message": {
"role": "assistant",
"content": [
{
"type": "image",
"image": "https://dashscope-result.oss.aliyuncs.com/..."
}
]
},
"finish_reason": "stop"
}
]
}
},
"statusCode": 200
} }
``` ```
Locate the item with `type: "image"` inside `data.output.choices[0].message.content` and extract its `image` URL. ### Step 2: Upload to media-store
### Step 2: Download and upload to media-store
The image URL is time-limited; download and persist it to the local media-store immediately:
```bash ```bash
PORT=$(cat ${DESIRECORE_ROOT}/agent-service.port)
IMAGE_URL="image URL from step 1's response"
curl -sL "$IMAGE_URL" -o /tmp/dashscope-gen.png && \
curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \
-F "file=@/tmp/dashscope-gen.png;type=image/png" -F "file=@/tmp/dashscope-gen.png;type=image/png"
``` ```
@@ -175,13 +181,14 @@ The frontend will translate `dc-media://` into a reachable image URL and render
### Size selection ### Size selection
When calling Wan via compatible-mode, the size is passed as the top-level `size` parameter: Pass `size` in the `body` object:
```json ```json
{ {
"model": "wan2.7-image", "model": "wan2.7-image",
"prompt": "your image description",
"size": "1024x1024", "size": "1024x1024",
"messages": [...] "n": 1
} }
``` ```
@@ -195,12 +202,12 @@ When calling Wan via compatible-mode, the size is passed as the top-level `size`
| Parameter | Description | | Parameter | Description |
|------|------| |------|------|
| `n` | Number of images, 14, default 1 | | `n` | Number of images, 1-4, default 1 |
| `size` | Image size, e.g. "1024x1024" | | `size` | Image size, e.g. "1024x1024" |
## Multiple Image Generation ## Multiple Image Generation
When `n > 1`, the `choices` array contains multiple entries, each with an image inside `message.content`. Download and upload each image, then render them one by one: When `n > 1`, download and upload each image, then render them one by one:
``` ```
![Image 1 description](dc-media://mediaId1) ![Image 1 description](dc-media://mediaId1)
@@ -209,16 +216,20 @@ When `n > 1`, the `choices` array contains multiple entries, each with an image
## Error Handling ## Error Handling
- `success: false` + `error: "No matching provider"`: No enabled provider supports `image_gen` service type | Error | Meaning | Action |
- `success: false` + `error: "API Key not configured"`: API Key missing |-------|---------|--------|
- `statusCode: 401`: API Key invalid or expired | `"No matching provider"` | No enabled provider supports `image_gen` | Tell user to enable a provider with image_gen support in settings |
- `statusCode: 429`: rate limited, retry later | `"API Key not configured"` | API Key missing | Tell user to configure API key |
- `statusCode: 400` + `InvalidParameter`: bad parameters (e.g. unsupported size) | `statusCode: 401` | API Key invalid or expired | Tell user to check API key |
- `statusCode: 403` + `AccessDenied.Unpurchased`: model not activated; enable it in the Alibaba Cloud console | `statusCode: 429` | Rate limited | Wait and retry once |
| `statusCode: 400` | Bad parameters | Check model name and size are from the tables above |
| `statusCode: 403 AccessDenied.Unpurchased` | Model not activated | Tell user to enable the model in Alibaba Cloud console |
**On any error**: Do NOT try alternative models, alternative endpoints, or read config files. Report the error to the user clearly.
## Notes ## Notes
- compatible-mode calls are synchronous and typically return in 1060 seconds (wan2.7-image-pro can take longer) - Image generation calls are synchronous and typically return in 10-60 seconds (wan2.7-image-pro can take longer)
- Image URLs expire; download promptly - Image URLs expire; download promptly
- English prompts usually produce the best results; Chinese is also supported - English prompts usually produce the best results; Chinese is also supported
- When the user does not specify a model or size, default to `wan2.7-image` + `1024x1024` - When the user does not specify a model or size, default to `wan2.7-image` + `1024x1024`

View File

@@ -4,11 +4,22 @@
## 强制规则(违反将导致功能失败) ## 强制规则(违反将导致功能失败)
1. **必须用 HTTPS 访问 agent-service**`https://127.0.0.1:${PORT}``-k` 跳过证书验证 1. **严格按下方步骤执行** — 禁止自行探索其他端点、尝试本文档未列出的模型、或读取配置文件
2. **必须通过 `/api/media/upload` 上传到 media-store** — 禁止保存到本地路径 2. **必须用 HTTPS 访问 agent-service** — API 地址已在系统提示词的"本机 API"部分提供(如 `https://127.0.0.1:PORT`),直接使用,加 `-k` 跳过证书验证
3. **必须使用 `dc-media://` 协议展示图片** — 唯一能让前端正确渲染的方式 3. **必须通过 `/api/media/upload` 上传到 media-store** — 禁止保存到本地路径
4. **全程使用 Bash curl** — 不要使用 HttpRequest 工具或 Python 4. **必须使用 `dc-media://` 协议展示图片** — 唯一能让前端正确渲染的方式
5. **使用 compatible-mode/chat/completions** — 同步调用,响应直接包含图片 URL 5. **全程使用 Bash curl** — 不要使用 HttpRequest 工具或 Python
6. **使用 `/images/generations` 端点** — 同步调用,响应包含 b64_json 图片数据
7. **只能使用下方模型列表中的模型** — 禁止尝试 dall-e-3、qwen-vl 或任何未列出的模型
## 供应商与默认算力
本技能使用阿里云 DashScope 的通义万相系列模型。**无需指定供应商**,只需传 `"serviceType": "image_gen"`,系统会自动路由到正确的供应商:
- **DesireCore Cloud**(默认,始终可用):内置算力供应商已支持 `image_gen` 和通义万相模型。用户无需任何配置即可直接生成图片。
- **DashScope**(用户自配):如果用户自己配置了阿里云 API Key系统可能会路由到用户自己的供应商。
**禁止**尝试查询供应商列表、读取 compute.json、或通过 API 探索可用模型。下方列出的模型保证可用。
## 模型选择指南 ## 模型选择指南
@@ -19,81 +30,76 @@
**默认规则**:用户未指定模型时,使用 `wan2.7-image` **默认规则**:用户未指定模型时,使用 `wan2.7-image`
## 完整执行流程(严格按此步执行) ## 完整执行流程(严格按此步执行)
### 前置条件 ### 获取 API 地址
- 至少有一个已启用的算力供应商支持 `image_gen` 服务类型(如 DashScope 或默认的 DesireCore Cloud 供应商) 系统提示词中"本机 API"部分已包含 agent-service 的地址(如 `Agent Service: https://127.0.0.1:61000`)。直接从中提取 URL 使用。
- agent-service 正在运行
### 第一步:调用文生图 API同步 如果无法从系统提示词中找到,使用以下兜底方式:
通过 media-proxy 的 compatible-mode 端点生成图片,响应直接包含图片 URL
```bash ```bash
PORT=$(cat ${DESIRECORE_ROOT}/agent-service.port) PORT=$(cat "${DESIRECORE_HOME:-$HOME/.desirecore}/agent-service.port")
# 然后使用 https://127.0.0.1:${PORT}
```
### 第一步:生成图片(单次 curl 调用)
通过 media-proxy 调用 `/images/generations` 端点。**必须严格使用以下请求结构** — 禁止添加 `messages``response_format` 或任何未在此处列出的参数:
```bash
# 将响应保存到临时文件,避免 base64 数据灌入终端
curl -sk -X POST "https://127.0.0.1:${PORT}/api/media-proxy" \ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media-proxy" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"serviceType": "image_gen", "serviceType": "image_gen",
"endpoint": "/chat/completions", "endpoint": "/images/generations",
"body": { "body": {
"model": "wan2.7-image", "model": "wan2.7-image",
"messages": [ "prompt": "这里替换为图片描述(建议英文效果更好)",
{ "size": "1024x1024",
"role": "user", "n": 1
"content": [
{"type": "text", "text": "这里替换为图片描述(建议英文效果更好)"}
]
}
]
}, },
"responseType": "json" "responseType": "json"
}' }' -o /tmp/dashscope-response.json
# 检查成功并直接将 b64_json 提取为图片文件(禁止将响应内容输出到终端)
python3 -c "
import json, base64, sys
with open('/tmp/dashscope-response.json') as f:
resp = json.load(f)
if not resp.get('success'):
print('ERROR:', json.dumps(resp, ensure_ascii=False)[:500])
sys.exit(1)
b64 = resp['data']['data'][0]['b64_json']
with open('/tmp/dashscope-gen.png', 'wb') as f:
f.write(base64.b64decode(b64))
print('OK: saved to /tmp/dashscope-gen.png')
"
``` ```
**响应示例** **关键警告**响应包含大约 2MB 的 base64 图片数据。**禁止**将原始响应或 b64_json 打印到终端。始终使用 `-o` 保存到文件,再用上面的 python3 脚本提取。
**响应格式**(保存在 `/tmp/dashscope-response.json` 中):
```json ```json
{ {
"success": true, "success": true,
"data": { "data": {
"request_id": "...", "created": 1781060911,
"output": { "data": [{"b64_json": "<非常大的 base64 字符串>"}],
"choices": [ "size": "1024x1024"
{ }
"message": {
"role": "assistant",
"content": [
{
"type": "image",
"image": "https://dashscope-result.oss.aliyuncs.com/..."
}
]
},
"finish_reason": "stop"
}
]
}
},
"statusCode": 200
} }
``` ```
`data.output.choices[0].message.content` 中找到 `type: "image"` 的项,提取其 `image` URL。 ### 第二步:上传到 media-store
### 第二步:下载并上传到 media-store
图片 URL 有时效,必须立即下载并保存到本地 media-store
```bash ```bash
PORT=$(cat ${DESIRECORE_ROOT}/agent-service.port)
IMAGE_URL="第一步响应中的 image URL"
curl -sL "$IMAGE_URL" -o /tmp/dashscope-gen.png && \
curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \
-F "file=@/tmp/dashscope-gen.png;type=image/png" -F "file=@/tmp/dashscope-gen.png;type=image/png"
``` ```
从 JSON 响应中提取 `mediaId` 字段(格式如 `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png`)。 上传 JSON 响应中提取 `mediaId` 字段(格式如 `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png`)。
### 第三步:用 dc-media 协议展示图片 ### 第三步:用 dc-media 协议展示图片
@@ -111,13 +117,14 @@ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \
### 尺寸选择 ### 尺寸选择
通义万相通过 compatible-mode 调用时,尺寸通过 `size` 参数传入(放在请求体顶层) `size` 放在 `body` 对象中
```json ```json
{ {
"model": "wan2.7-image", "model": "wan2.7-image",
"prompt": "图片描述",
"size": "1024x1024", "size": "1024x1024",
"messages": [...] "n": 1
} }
``` ```
@@ -136,7 +143,7 @@ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \
## 多图生成 ## 多图生成
`n > 1` 时,`choices` 数组会有多个元素,每个 `message.content` 中都有一张图片。需要为每张图片执行下载+上传,然后逐一展示: `n > 1` 时,为每张图片执行下载+上传,然后逐一展示:
``` ```
![图片1描述](dc-media://mediaId1) ![图片1描述](dc-media://mediaId1)
@@ -145,16 +152,20 @@ curl -sk -X POST "https://127.0.0.1:${PORT}/api/media/upload" \
## 错误处理 ## 错误处理
- `success: false` + `error: "未找到匹配的供应商"`:没有已启用的供应商支持 `image_gen` 服务类型 | 错误 | 含义 | 处理方式 |
- `success: false` + `error: "未配置 API Key"`:未填写 API Key |------|------|---------|
- `statusCode: 401`API Key 无效或已过期 | `"未找到匹配的供应商"` | 没有启用的供应商支持 `image_gen` | 告知用户在设置中启用支持 image_gen 的供应商 |
- `statusCode: 429`:频率限制,稍后重试 | `"未配置 API Key"` | 未填写 API Key | 告知用户配置 API Key |
- `statusCode: 400` + `InvalidParameter`:参数错误(如尺寸不支持) | `statusCode: 401` | API Key 无效或过期 | 告知用户检查 API Key |
- `statusCode: 403` + `AccessDenied.Unpurchased`:模型未开通,需要在阿里云控制台开通 | `statusCode: 429` | 频率限制 | 等待后重试一次 |
| `statusCode: 400` | 参数错误 | 检查模型名和尺寸是否在上表中 |
| `statusCode: 403 AccessDenied.Unpurchased` | 模型未开通 | 告知用户在阿里云控制台开通 |
**遇到任何错误时**:禁止尝试其他模型、其他端点、或读取配置文件。直接向用户清晰报告错误即可。
## 注意事项 ## 注意事项
- 通过 compatible-mode 调用是同步的,通常 10-60 秒返回wan2.7-image-pro 可能更长) - 图片生成调用是同步的,通常 10-60 秒返回wan2.7-image-pro 可能更长)
- 结果图片 URL 有时效,必须及时下载 - 结果图片 URL 有时效,必须及时下载
- 提示词建议用英文以获得最佳效果,中文也支持 - 提示词建议用英文以获得最佳效果,中文也支持
- 如果用户未明确要求模型/尺寸,默认使用 `wan2.7-image` + `1024x1024` - 如果用户未明确要求模型/尺寸,默认使用 `wan2.7-image` + `1024x1024`