OpenRouter 模型能力声明 & 下游项目多模态识别分析

生成时间: 2026-06-02 · 分析范围: OpenRouter /v1/models 接口、oh-my-pi (packages/ai)、pi-mono (packages/ai)

目录

  1. OpenRouter 如何声明模型能力
  2. 当前项目 (oh-my-pi) 如何识别多模态
  3. pi-mono 如何识别多模态
  4. 关键差异与能力缺口
  5. 你需要区分的三类模型实际表现

1. OpenRouter 如何声明模型能力

1.1 核心结构:architecture 字段

OpenRouter 的 GET /v1/models 在每个模型条目中返回一个 architecture 对象,这是模型能力的主要声明方式

{
  "architecture": {
    "modality":          "text+image+video->text",
    "input_modalities":  ["text", "image", "video"],
    "output_modalities": ["text"],
    "tokenizer":         "Qwen3",
    "instruct_type":     null
  }
}

当前 OpenRouter 目录(342 个模型)中存在 15 种独特的 architecture 组合:

modalityinput_modalitiesoutput_modalities典型模型
text->texttexttextMiniMax M2.7, Qwen3.6 Max, DeepSeek V3
text+image->texttext, imagetextGPT-4o, MiniMax-01, Qwen3 VL
text+image+video->texttext, image, videotextQwen3.6 Flash/Plus/27B, MiniMax M3
text+image+file->texttext, image, filetextGPT-4o-mini, Claude 4 Sonnet
text+image+file+audio+video->textfull 5-modalitytextGemini 2.5/3.x 系列
text+audio->text+audiotext, audiotext, audioGPT Audio / GPT Audio Mini
text+file+audio->texttext, audio, filetextMistral Voxtral
...以及其他 8 种组合

1.2 辅助能力信号

除了 architecture,还有其他字段携带能力信息:

字段含义示例
supported_parametersAPI 参数支持列表["tools", "reasoning", "tool_choice", "structured_outputs"]
supported_voicesTTS 声音列表当前绝大多数为 null
top_provider.max_completion_tokens最大输出 token16384
context_length上下文长度128000

1.3 关键发现:ASR 模型在独立类别中,不在 /v1/models Chat 列表

✅ 千问 3 ASR Flash 确实存在于 OpenRouter 上!

模型 ID: qwen/qwen3-asr-flash-2026-02-10 · 名称: Qwen: Qwen3 ASR Flash
发布日期: 2026-05-14 · 定价: $0.000035/音频秒(非 token 定价)

但它不在 /v1/models 的 Chat 模型列表中出现——因为它属于 Transcription(语音转录)类别,与 Chat/Text 模型是不同的业务范畴。

特征Chat 模型 (Qwen3.6 等)Transcription 模型 (Qwen3 ASR)
API 端点POST /v1/chat/completionsPOST /v1/audio/transcriptions
在 /v1/models 列表中?✅ 是❌ 否(或因 output=transcription 被过滤)
architecture.modalitytext+image...->text未知(不在标准 Chat 模型列表)
定价方式按 token按音频秒 ($0.000035/s)
输入格式JSON messagesbase64 编码音频 (wav/mp3/flac)
核心参数messages, tools, temperatureinput_audio.data, input_audio.format

OpenRouter 的模型分类体系实际上有多个输出类别:Text、Image、Embeddings、Audio、Video、Rerank、SpeechTranscription。当前 /v1/models 接口主要返回 Chat/Text 类模型,ASR 类的 Transcription 模型可能在其他端点或需要显式查询。

OpenRouter 网站搜索 "qwen3-asr" 能看到这个模型被归类在 "Transcription" 过滤器下(另外 341 个模型属于 Text 类别)。这说明 OpenRouter 有能力在多个 API 端点下承载不同类型的模型。

2. 当前项目 (oh-my-pi) 如何识别多模态

2.1 Model 类型定义

文件: packages/ai/src/types.ts L881-944

export interface Model<TApi extends Api = any> {
  id: string;
  name: string;
  api: TApi;
  provider: Provider;
  baseUrl: string;
  reasoning: boolean;
  input: ("text" | "image")[];  // ← 只支持 text 和 image!
  cost: { ... };
  contextWindow: number;
  maxTokens: number;
  thinking?: ThinkingConfig;   // 思考能力元数据
  compat?: OpenAICompat | AnthropicCompat;
}

核心局限: input 字段的类型是 ("text" | "image")[],不包含 "audio""video""file"。整个项目的数据模型中不支持表达音频/视频/文件输入能力。

2.2 OpenRouter 模型发现流程

文件: packages/ai/src/provider-models/openai-compat.ts L1349-1401

运行时调用 openrouterModelManagerOptions()fetchOpenAICompatibleModels(),逐模型映射:

// L1371-1381: 图像支持的判定
const modality = String(entry.architecture?.modality ?? "");
return {
  ...defaults,
  reasoning: params.includes("reasoning"),
  input: modality.includes("image") ? ["text", "image"] : ["text"],
  // ↑ 仅检查 modality 字符串是否包含 "image"
  // 完全不检查 audio / video / file
};

判定规则:

2.3 其他 provider 的通用识别方式

通过 toInputCapabilities() (L50-56) 处理的 providers(models.dev 数据源、ZenMux 等):

function toInputCapabilities(value: unknown): ("text" | "image")[] {
  if (!Array.isArray(value)) return ["text"];
  const supportsImage = value.some(item => item === "image");
  return supportsImage ? ["text", "image"] : ["text"];
}

Ollama: 检查 capabilities.includes("vision") (L324-325)。

2.4 模型目录生成

文件: packages/ai/src/models.ts — 从 models.json 加载静态预生成目录,不做运行时动态发现。

OpenRouter 被配置为 allowUnauthenticated: true 的 catalog provider(见 descriptors.ts L217-221),可以在构建期拉取模型列表。

3. pi-mono 如何识别多模态

3.1 与 oh-my-pi 相同的模型类型

文件: packages/ai/src/types.ts L546-576

export interface Model<TApi extends Api> {
  id: string;
  name: string;
  api: TApi;
  provider: Provider;
  reasoning: boolean;
  input: ("text" | "image")[];  // ← 相同的两值联合类型
  // ...
}

3.2 静态模型目录生成

文件: packages/ai/scripts/generate-models.ts L281-337

pi-mono 在构建时调用 fetchOpenRouterModels() 拉取 OpenRouter 的 /v1/models,然后写入 models.generated.ts

async function fetchOpenRouterModels(): Promise<Model<any>[]> {
  const response = await fetch("https://openrouter.ai/api/v1/models");
  const data = await response.json();
  
  for (const model of data.data) {
    // 仅包含支持 tools 的模型
    if (!model.supported_parameters?.includes("tools")) continue;
    
    const input: ("text" | "image")[] = ["text"];
    if (model.architecture?.modality?.includes("image")) {
      input.push("image");
    }  // ← 同样的 image-only 检查
    
    models.push({
      id: model.id,
      reasoning: model.supported_parameters?.includes("reasoning") || false,
      input,
      // ...
    });
  }
}

3.3 独立的图像生成系统

pi-mono 有一个完全独立的图像生成子系统:

文件作用
src/image-models.generated.ts预生成的图像生成模型目录(Flux, DALL-E 等)
src/images.ts图像生成入口 generateImages()
src/images-api-registry.ts图像 API 提供者注册表
src/providers/images/openrouter.tsOpenRouter 图像生成实现(chat completions → base64 图片)

ImagesModel 类型有 inputoutput 两个字段,但同样限 ("text" | "image")[]

4. 关键差异与能力缺口

维度OpenRouter 声明oh-my-pi 模型pi-mono 模型
输入模态 text, image, video, audio, file (5 种) text, image (2 种) text, image (2 种)
输出模态 text, audio, image (3 种) text (隐式) text (隐式,图像输出在 ImagesModel)
视觉判定 modality.includes("image") ✅ 相同逻辑 ✅ 相同逻辑
推理判定 supported_parameters ✅ 相同逻辑 ✅ 相同逻辑
音频判定 modality.includes("audio") ❌ 不支持 ❌ 不支持
视频判定 modality.includes("video") ❌ 不支持 ❌ 不支持
文件判定 modality.includes("file") ❌ 不支持 ❌ 不支持
语音输出(TTS) supported_voices (大部分为 null) ❌ 无概念 ❌ 无概念

核心问题: 两个项目的 Model 类型定义在架构层面就排除了 audio/video/file 模态。

即使 OpenRouter 返回了完整的能力声明,下游代码在映射阶段就把这些信息丢弃了。要支持音频/ASR 模型,需要:

  1. 扩展 Model.input 的联合类型
  2. 在 OpenRouter 发现代码中读取 architecture.input_modalities 而不仅仅是 modality 字符串
  3. 在 provider 层面实现音频消息的编码/解码

5. 你需要区分的三类模型 — 实际表现

5.1 千问 3 ASR Flash(语音识别)

✅ 存在于 OpenRouter,但需要特殊处理。

模型 ID: qwen/qwen3-asr-flash-2026-02-10
类别: Transcription(不在 /v1/models Chat 列表中)
端点: POST https://openrouter.ai/api/v1/audio/transcriptions
定价: $0.000035/音频秒
能力: 11 种语言(含中文方言),自动语言检测,支持噪声环境

调用方式(Python 示例):

import requests, base64, json

with open("audio.wav", "rb") as f:
    base64_audio = base64.b64encode(f.read()).decode("utf-8")

response = requests.post(
    url="https://openrouter.ai/api/v1/audio/transcriptions",
    headers={"Authorization": "Bearer $OPENROUTER_API_KEY"},
    data=json.dumps({
        "model": "qwen/qwen3-asr-flash-2026-02-10",
        "input_audio": {"data": base64_audio, "format": "wav"}
    })
)
print(response.json()["text"])

对下游应用的影响:这是一个完全不同的 API 契约。无法通过检查 /v1/modelsarchitecture 字段发现它。下游需要:

5.2 千问 3.6(多模态视觉模型)

模型 IDmodalityoh-my-pi 识别为
qwen/qwen3.6-flashtext+image+video->textinput: ["text", "image"]
qwen/qwen3.6-27btext+image+video->textinput: ["text", "image"]
qwen/qwen3.6-max-previewtext->textinput: ["text"]

qwen3.6-max-preview 是唯一的纯文本版本。 其他 Qwen 3.6 变体都有 image+video 能力,但下游只标记了 image。video 能力信息在映射阶段被丢弃。

5.3 MiniMax M2.7 / M3

模型 IDmodalityoh-my-pi 识别为
minimax/minimax-m2.7text->textinput: ["text"]
minimax/minimax-m3text+image+video->textinput: ["text", "image"]

区分正确:纯文本 vs 多模态可以依据 modality.includes("image") 准确判断。

5.4 下游应用的建议区分方案

如果你的下游应用需要精确区分三类模型:

function classifyModel(entry) {
  const m = entry.architecture?.modality ?? "";
  const inputs = entry.architecture?.input_modalities ?? [];
  
  return {
    isPureText:    inputs.length === 1 && inputs[0] === "text",
    hasVision:     m.includes("image") || inputs.includes("image"),
    hasAudio:     m.includes("audio") || inputs.includes("audio"),
    hasVideo:     m.includes("video") || inputs.includes("video"),
    hasFile:     m.includes("file")  || inputs.includes("file"),
    hasReasoning: entry.supported_parameters?.includes("reasoning"),
  };
}

最佳实践: 优先使用 architecture.input_modalities 数组做能力判定,architecture.modality 字符串作为快速索引。

input_modalities 是显式枚举,不依赖字符串匹配(比如 "image" vs "images" 不会有歧义)。


分析完成。相关文件路径:
~/GitHub/oh-my-pi/packages/ai/src/types.ts (Model 类型定义)
~/GitHub/oh-my-pi/packages/ai/src/provider-models/openai-compat.ts (OpenRouter 发现 → L1371)
~/GitHub/pi-mono/packages/ai/scripts/generate-models.ts (静态目录生成 → L281)
~/GitHub/pi-mono/packages/ai/src/types.ts (pi-mono Model 类型)