diff --git a/pipeline_platform/platform_ability.py b/pipeline_platform/platform_ability.py index 2f27b2d..31f8e6d 100644 --- a/pipeline_platform/platform_ability.py +++ b/pipeline_platform/platform_ability.py @@ -43,7 +43,7 @@ OWNER_ORG = "owner" # openai_compat —— 同步 chat/completions 一次往返 # dashscope_async —— 异步执行器:提交任务→轮询 query_profile_ids→取结果(2026-09-05) # 其他协议的适配模板会存入 llm_api_profile 备查,但运行时暂不渲染。 -RUNTIME_PROTOCOLS = ("openai_compat", "dashscope_async") +RUNTIME_PROTOCOLS = ("openai_compat", "dashscope_async", "dashscope_sync") # ────────────────────── 会话级规格缓存(extract 锚定,2026-09-05)────────────────────── # 根因:apply_llm_config 要求 LLM 把 extract 返回的大 JSON 规格逐字复制进参数, @@ -354,7 +354,7 @@ _EXTRACT_PROMPT = """你是大模型 API 配置专家。通读下面这份模型 { "vendor_name": "供应商名称", "base_url": "API 基础地址——必须取文档示例请求 URL 中除接口路径外的完整前缀(含 /api/v1 或 /compatible-mode/v1 等路径段,如 https://dashscope.aliyuncs.com/api/v1)。禁止只填裸域(如 https://dashscope.aliyuncs.com)——裸域拼接口路径必 404", - "protocol": "openai_compat | dashscope_async | custom(能走 /chat/completions 的填 openai_compat)", + "protocol": "openai_compat | dashscope_sync | dashscope_async | custom(能走 /chat/completions 的填 openai_compat;DashScope 原生接口按交互形态二选一,见下方协议判定规则)", "endpoints": [{"base_url": "...", "region": "domestic|international", "timeout": 60}], "chat_path": "对话接口路径(如 /chat/completions)", "auth_header": "认证头格式说明(如 Bearer API_KEY)", @@ -381,11 +381,12 @@ _EXTRACT_PROMPT = """你是大模型 API 配置专家。通读下面这份模型 "doc_notes": "文档中影响配置的关键注意点" } -异步模型规则: -- 文档描述「先提交任务、再轮询查询结果」的模型,sync_mode 填 async,并提取 async_steps: +协议判定规则(2026-09-08 qwen-image-plus 实测教训:交互形态有三种,同步生成此前被误判成异步): +- **dashscope_sync(同步生成)**:调用示例是 `MultiModalConversation.call(stream=False)` 或一次 HTTP 请求直接返回产物(图像/语音),无 task_id、无轮询查询接口 → sync_mode=sync、async_steps=[]、**不带 X-DashScope-Async 头**。 +- **dashscope_async(异步任务)**:文档描述「先提交任务拿 task_id、再轮询查询结果」,或示例带 `X-DashScope-Async: enable` 头 → sync_mode=async,并提取 async_steps: 至少一条 purpose=query(查询任务状态/结果);若文档另有独立下载/取文件接口,再加一条 purpose=download。 -- 任务查询接口通常是**供应商级共用**的(如 DashScope 全系生成模型都是 GET /tasks/{task_id}), - path 照文档逐字抄;同供应商多个模型会复用同一份查询模板,不要因模型而异。 +- 判据优先级:**调用示例的交互形态 > 供应商惯例**。同一供应商(如 DashScope)可同时有同步生成模型(图像/语音)和异步任务模型(长视频)——按各模型自己的文档判,不要按供应商一刀切。 +- 任务查询接口通常是**供应商级共用**的(如 DashScope 全系异步模型都是 GET /tasks/{task_id}),path 照文档逐字抄;同供应商多个模型会复用同一份查询模板,不要因模型而异。 - 同步模型 async_steps 填空数组 []。 能力判定铁律(2026-09-06 wan3.0-video-prime 误判教训——概述明写"四模态全能参考"、 @@ -1517,9 +1518,14 @@ def _headers_from_spec(spec): continue if isinstance(v, str) and v.strip(): headers[k] = v.strip() - # 协议兜底:dashscope_async 提交必须带异步开关头(文档示例遗漏也不至于提交即失败) + # 协议兜底:dashscope_async 提交必须带异步开关头(文档示例遗漏也不至于提交即失败); + # dashscope_sync 是同步生成(MultiModalConversation stream=False 类,即时返回产物), + # **绝不能带异步头**——带了上游按异步受理,不支持异步的密钥直接 403 + # (2026-09-08 qwen-image-plus 实测:'current user api does not support asynchronous calls')。 if str(spec.get('protocol') or '').strip() == 'dashscope_async': headers.setdefault('X-DashScope-Async', 'enable') + elif str(spec.get('protocol') or '').strip() == 'dashscope_sync': + headers.pop('X-DashScope-Async', None) return headers