Skip to content

[Feature] 支持 rerank 和 embedding 多模态 #10550

Open

Description

@Mr-Python-in-China

功能描述

按照 https://github.com/AstrBotDevs/AstrBot/issues/9360#issuecomment-6146642982,另开 issue。

建议为多模态 embedding 和 rerank 模型提供其他模态输入的支持,例如 qwen3-vl-embedding。

使用场景

更好实现搜图、搜视频等。

检查清单

  • 我已在 Issue 列表中搜索过相关功能,确认该功能想法从未被提出过。
  • 我建议的功能与 AstrBot 本体相关,而非在建议某一插件的功能。
  • 我已阅读并同意本项目的贡献者行为准则。
  • (可选)我愿意提交 PR 以帮助实现该功能。

Activity

  1. LIghtJUNction commented on Oct 14, 2026

    @LIghtJUNction
    Contributor

    我按当前 master@770bd0e 把 provider 接口、知识库入库、检索和媒体存储链路串了一遍。这个需求不能只在某个 provider 中增加 image/video 字段:当前 DashScope 适配器虽然已经会把 qwen3-vl-embedding 路由到多模态 endpoint,但 AstrBot 上层仍然只能传文本,所以现在实际可用的仍是“用多模态模型做文本 embedding”。

    判断与代码依据

    • astrbot/core/provider/provider.py::EmbeddingProvider 的 get_embedding(text: str)、get_embeddings(text: list[str]) 以及批处理接口都把输入固定为字符串;RerankProvider.rerank 也固定为 query: str, documents: list[str]。
    • astrbot/core/provider/sources/dashscope_embedding_source.py::DashScopeEmbeddingProvider.get_embeddings 能识别 qwen*-vl-embedding,但构造的是 [{"text": t} for t in text],没有任何图片或视频入口。
    • astrbot/core/provider/sources/nvidia_rerank_source.py::_build_payload 即使默认模型名是 llama-nemotron-rerank-vl-1b-v2,仍只发送 {"text": ...}。
    • astrbot/core/db/vec_db/faiss_impl/vec_db.py::insert_batch/retrieve 的入库内容、查询都为 str;astrbot/core/knowledge_base/retrieval/manager.py::_rerank 只把 RetrievalResult.content 文本传给 reranker。
    • 文档解析其实已经能产出媒体:parsers/base.py::ParseResult.media,KBHelper.upload_document 会保存为 KBMedia;但 KBMedia 只有 doc_id,没有 chunk/vector 关联,文本向量的 metadata 也没有 media_id/modality。因此这些文件目前无法沿向量检索链进入 embedding 或 rerank。

    建议修改

    建议先定义 provider 无关的输入协议,再逐个适配 provider,而不是把 str | dict 直接散落到各实现。可采用一个窄的 tagged union,例如:

    EmbeddingInput = TextInput(text) | ImageInput(uri, mime_type) | VideoInput(uri, ...)
    RerankItem = TextInput(...) | ImageInput(...) | MixedInput(parts=[...])
    • EmbeddingProvider 保留现有字符串方法作为兼容包装,新增 typed input/batch 方法及 supported_modalities;不支持的模态在发网络请求前返回明确错误。
    • DashScope 适配器负责把 typed input 映射为 SDK 的 {"text": ...}、{"image": ...}、{"video": ...},并复用现有媒体解析工具处理本地路径、URL、data URL、MIME 和大小限制;不要让 KB 层拼 provider 私有 JSON。
    • 入库侧需要明确“媒体是独立检索单元,还是与相邻文本组成 mixed item”。无论哪种,都要把 media_id、modality、来源 doc_id 以及可选 chunk_index 写进向量 metadata;否则命中向量后无法稳定还原原媒体。
    • FaissVecDB.retrieve 和 RetrievalManager.retrieve/_rerank 应接受 typed query。纯图片查询可跳过 BM25;混合查询的 dense/sparse 结果再走现有 fusion。Rerank 只在 provider 声明支持相应 query/document 模态时启用,否则明确降级到融合结果。
    • 媒体文件、文档元数据和 FAISS 写入目前是多存储补偿事务;新增媒体向量后应纳入 KBHelper 与 FaissVecDB._rollback_partial_insert 的失败清理及删除路径,避免留下孤儿向量或文件。

    修改后的效果

    现有纯文本 provider、已有知识库和插件调用不需要改动;选择多模态 provider 时,图片/视频才能真正作为索引项或查询进入 provider。返回结果可通过 metadata 找回原始媒体,而不是只有无法展示的向量。unsupported modality、媒体解析失败和 rerank 不支持时也会得到可观察的错误/降级,不会静默当文本处理。

    验证建议

    建议分层增加:

    • provider contract:文本/图片/视频/mixed payload、批量顺序、维度、空输入、超大文件、错误 MIME、远程 URL 失败及不支持模态;
    • DashScope/NVIDIA payload golden tests,确认模型名带 VL 不等于自动获得图片输入,且 headers/base URL/并发行为不回归;
    • KB 入库:PDF 图片或直接上传图片能生成带 media_id 的向量,失败时文档行、媒体文件、FAISS id 全部回滚,删除文档也同步清理;
    • 检索:以图搜图、文本搜图、混合 query、纯文本旧知识库,以及 rerank 支持/不支持多模态两条路径;
    • 跨 provider:同一 typed input 在至少一个多模态实现成功,在文本-only OpenAI/Ollama 等实现中于请求前稳定拒绝。

    建议把第一阶段范围收敛为“typed provider contract + DashScope 图片 embedding + KB 图片独立索引/检索”,视频和多模态 rerank在协议与数据模型稳定后再扩展,回归面会更可控。

  2. Mr-Python-in-China commented on Oct 15, 2026

    @Mr-Python-in-China
    Author

    哦对了 qwen的那个模型 视频模态 只支持从公网下载视频文件 不能嵌入到请求里
    还得考虑一下上传视频的问题

  3. LIghtJUNction commented on Oct 16, 2026

    @LIghtJUNction
    Contributor

    补充上一条分析:新增的“视频可能只能以公网 URL 交给 provider”约束,会把模态能力和传输方式分成两个必须独立声明的维度。下面只补充之前未展开的上传/临时 URL 链路,不重复 typed input、向量 metadata 和检索方案。

    已确认的代码事实

    • astrbot/core/knowledge_base/kb_helper.py::_save_media 把解析出的媒体写到 kb_medias_dir/.../<media_id>.<ext>;KBMedia.file_path(astrbot/core/knowledge_base/models.py)保存的是 AstrBot 本机路径。目前这条链路不会生成 provider 可访问的 URL。
    • AstrBot 已有可借鉴的出口:astrbot/core/message/components.py::Video.register_to_file_service/to_dict 可借助 callback_api_base 和 FileTokenService 生成 /api/file/<token>。
    • 但 astrbot/core/file_token_service.py::FileTokenService 默认令牌只有 300 秒且 single_use=True;handle_file 第一次访问即删除令牌。astrbot/dashboard/api/files.py::_serve_token_file 返回文件,相关路由在认证中间件中免登录,安全性依赖高熵 token。
    • 当前 EmbeddingProvider/DashScope embedding 适配器仍只接收文本,所以知识库本地文件也没有调用上述文件服务的机会。

    因此,若直接在 DashScope 适配器里对本地视频调用现有 Video.register_to_file_service,可能出现:provider 先发 HEAD、跟随重定向或下载重试 → 单次令牌被首次访问消耗 → 真正 GET/重试得到 404。若未配置或外网无法访问 callback_api_base,请求也会在 provider 侧失败。这一行为是根据常见的远程抓取流程作出的风险推断;“目标模型只接受公网 URL”的精确契约仍建议在实现前用对应模型 ID、API 文档或一份脱敏请求/响应确认,尤其要确认是否会 HEAD、重试、限制 URL 有效期和文件大小。

    修改建议

    1. 在上条建议的 provider input contract 中同时声明 transport capability,例如:
      supported_modalities={text,image,video}、accepted_transports={inline,url,local_path},不要仅凭模型名带 vl 推断。provider 在发请求前选择受支持的表示;没有可用表示时返回明确配置错误,不能静默退化成文本。
    2. 在 provider 与 KB 之间增加一个请求级的 media reference resolver:
      • 原始受信任 HTTPS URL 且 provider 支持 URL 时,可按策略直接引用;
      • 本地 KBMedia.file_path/用户上传文件且 provider 只支持 URL 时,生成短期、不可猜的 callback URL;
      • provider 支持 inline/local path 时分别选择相应表示。KB 层仍保存稳定的 media_id/file_path,不要把临时公网 URL 持久化到数据库或向量 metadata。
    3. 为远程 provider 的临时 URL 使用 single_use=False,TTL 覆盖请求、下载和有限重试;provider 调用完成后在 finally 中主动撤销(FileTokenService 目前还需要增加 revoke/unregister),异常路径同样清理。URL 不得写入普通日志,因为 token 本身就是读取凭据。
    4. 在创建 URL 前校验 callback_api_base 已配置为 provider 可达的 HTTPS 地址,并做一次明确的本地配置检查;不可达时向用户提示“需要公网回调地址”,不要等到远端返回模糊下载失败。文件服务应只映射已经登记的媒体 ID/路径,校验 MIME、大小和所属 KB/调用上下文,不能接受任意服务器路径。
    5. “上传视频”建议复用服务器管理的上传/KB 媒体存储:上传后返回 media ID,再由 resolver 选择传输方式。若允许用户提供远程 URL并由 AstrBot 预下载,还需沿用严格的 SSRF、重定向、大小、超时和 MIME 校验;不要让 provider 适配器直接下载任意 URL。
    6. 视频索引还需确定粒度。若按片段/采样帧索引,应把 media_id + start_ms/end_ms 写进向量 metadata,命中后才能回到原视频时间段;整段视频只产生一个向量则需要明确模型时长/大小上限。

    修改后的效果

    用户上传到 AstrBot 的本地视频可在不永久公开文件的情况下交给 URL-only 云 provider;HEAD/重试不会因单次令牌偶发失败,超时和异常后也不会长期暴露。不同 provider 可按各自支持的 inline/URL/local-path 传输,而不会把 DashScope 特例泄漏到 KB 数据模型。缺少公网回调、文件超限或 provider 不支持视频时,用户会在请求前收到可操作的错误。

    验证建议

    • 本地视频 → 临时 URL → 模拟 provider 执行 HEAD、GET、重复 GET/一次重试,TTL 内都成功,完成或异常后 token 失效;
    • 未配置、配置为内网地址或外网不可达的 callback_api_base,请求前返回明确错误;
    • 错误 MIME、超限视频、已删除文件、过期 token、provider 超时/取消时均正确清理,日志不包含完整 token;
    • 两个 KB/用户并发请求不能凭 media ID 或旧 token 读取彼此文件;
    • provider capability matrix 覆盖 inline-only、URL-only、local-only、text-only,确认无支持传输时不会发网络请求;
    • 视频分段入库后,检索结果能通过 media_id/start_ms/end_ms 稳定定位并展示原视频片段。
  4. Mr-Python-in-China commented on Oct 16, 2026

    @Mr-Python-in-China
    Author

    ai说百炼自带临时存储

    文档里确实有但没说embedding可以用

    我没有验证

    如果是真的就好办了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions