From 2ae01c20505453c5670cd2e057a83db20ee82167 Mon Sep 17 00:00:00 2001 From: ssurui Date: Thu, 3 Sep 2026 14:33:58 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=A4=8D=E6=9F=A5=E7=A1=AE=E8=AE=A4=20?= =?UTF-8?q?er=5Fbackend=20=E5=B7=B2=E6=94=AF=E6=8C=81=E5=A4=9A=E6=A8=A1?= =?UTF-8?q?=E6=80=81=EF=BC=8C=E8=A7=A3=E9=99=A4=E6=8B=8D=E7=85=A7=E6=8F=90?= =?UTF-8?q?=E9=97=AE=E7=9A=84=E9=98=BB=E5=A1=9E=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现场重新查询 er_backend 状态,确认已换成带 --mmproj 的多模态配置 (allow_image=1,vision 896x896),并对 ER_BACKEND_URL/v1/chat/completions 做了端到端真实请求验证(HTTP 200,正确识别测试图片颜色),证明前端 可以直接按现有代理路径发送 image_url content-part,不需要额外适配层。 顺带记录实测性能数据(极简图片 prompt_tokens=808,prefill ~2s)用于 后续加载态 UI 设计参考,更新分阶段计划:阶段0 已完成,阶段1/2 可并行开始。 Co-Authored-By: Claude Sonnet 5 --- docs/feature-pic-design.md | 83 ++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/docs/feature-pic-design.md b/docs/feature-pic-design.md index 026fa43..86300d8 100644 --- a/docs/feature-pic-design.md +++ b/docs/feature-pic-design.md @@ -1,6 +1,7 @@ # 拍照提问模式 —— 设计方案 状态:**草案,未实现**。本文档只做设计,`feature_pic` 分支尚未修改任何业务代码。 +唯一的硬阻塞项(后端视觉能力)已于 2026-09-03 复查解除,见 §2.2。 ## 1. 背景与目标 @@ -23,30 +24,49 @@ Chromium/Electron 的 `navigator.mediaDevices.getUserMedia()` 原生支持 UVC 一台设备接了两个摄像头,需要在 UI 里做设备选择(`enumerateDevices()` 列出后选 `deviceId`), 或者约定固定用其中一个(待确认哪个摄像头是安装时实际对外的那个)。 -### 2.2 推理后端视觉能力 —— **当前不支持,是最大阻塞项** +### 2.2 推理后端视觉能力 —— **已确认可用(2026-09-03 复查更新)** -现场查询 er_backend(`http://127.0.0.1:17700/api/generate/status`),当前加载模型是文本模型, -llama-server 启动日志明确打印: +初次核实时(见本文档历史)当前模型是纯文本的,`allow_image=0`;**复查时 er_backend 已经换成带 +`--mmproj` 的多模态配置**: ``` -=model_desc = qwen35 9B Q4_0 -=allow_image = 0 +/home/work/houmo-HLIELLama-xh2-2.1.0/bin/llama-server \ + -m /home/work/models/LLM/HiModel_xh2_qwen3.5-9b_w4a8_256_256k_b1_1chip_2cores_v1.4.0_20260708.gguf \ + --mmproj /home/work/models/LLM/mmproj_xh2_qwen3.5-9b_w4a8_2cores_vit_896x896_v1.4.0_20260708.gguf \ + -c 8192 --parallel 1 --host 127.0.0.1 --no-warmup --port 8081 --presence_penalty 1.5 --reasoning-budget 0 +``` + +启动日志确认: + +``` +loaded multimodal model, '.../mmproj_xh2_qwen3.5-9b_w4a8_2cores_vit_896x896_v1.4.0_20260708.gguf' +==========model info=========================== +=allow_image = 1 =allow_audio = 0 -=vision_width = 0 -=vision_height= 0 +=vision_width = 896 +=vision_height= 896 +=model_desc = qwen35 9B Q4_0 +==========model info=========================== ``` -跑在揽月 NPU 定制版 llama-server(`houmo-HLIELLama-xh2-2.1.0`)上。**`allow_image=0` 是运行时读出的模型能力, -不是配置开关**——要让这个后端接受图片输入,前提条件是: +**并且做了端到端真实请求验证**(不只是看模型加载日志),直接对 `http://127.0.0.1:17700/v1/chat/completions` +(即前端 `generator.ts` 实际会调用的同一个地址)发了一个带 `image_url` content-part 的请求: -1. er_backend 那边要换成一个视觉多模态模型(如 Qwen2-VL / MiniCPM-V / LLaVA 系列的 GGUF + mmproj), - 且这个模型要能在揽月 NPU(HoumoNPU LQ50-24GB)上跑起来; -2. Houmo 这个定制版 llama-server 分支要支持 `--mmproj` 加载和 `/v1/chat/completions` 的 - `image_url` content-part 输入(这是 upstream llama.cpp 的能力,定制分支是否移植了未知); -3. 这两点都不是 `elec_rag_ui` 这个前端仓库能决定或实现的,需要跟 er_backend / 硬件适配团队确认。 +``` +HTTP 200,耗时 2.6s +返回:{"content": "黑色"} —— 测试图片本身就是 1x1 黑色像素,模型回答正确, + 证明图片被真实理解,不是被忽略/幻觉回答 +``` -**结论:这是一个跨团队依赖,不是前端待办项。** 在没有确认可用的视觉模型之前,前端这边能做的是把 -UI、拍照、请求组装、流式渲染这套壳子先搭好、可 mock 验证,等后端具备能力后接上真实模型联调。 +**结论:阻塞项已解除**,现在的 er_backend 代理路径(`ER_BACKEND_URL/v1/chat/completions`)原生支持 +OpenAI 风格的 `image_url` content-part,前端可以直接照 §5.2 的格式发请求,不需要额外适配层。 + +**顺带记录的性能数据**(用于 §6 加载态 UI 设计参考):这次测试用的是 1×1 像素的极简测试图, +`prompt_tokens` 却达到了 **808**——印证了启动日志里的警告"Qwen-VL models require at minimum +1024 image tokens",即**无论照片内容/分辨率如何,视觉编码本身有一个较高的固定 token 开销** +(896×896 的 ViT 编码器决定的,不是按源图片大小线性变化)。prefill 速度约 373 tokens/s, +换算下来光是"看懂一张图"这一步就要 ~2 秒起,生成回答的时间还要另外算——真实拍照场景(图片本身 ++ 问题文字)单次问答预计在 3-8 秒量级,UI 必须要有明确的"识别中"等待态,不能让用户以为卡死了。 ## 3. 功能范围(建议先做 MVP) @@ -175,27 +195,28 @@ vision: { | 阶段 | 内容 | 前置条件 | |---|---|---| -| 0 | 跟 er_backend/硬件团队确认视觉模型可用性(模型+mmproj+定制llama-server支持) | 无,最先做,可能耗时最长 | -| 1 | 摄像头取景/拍照 UI(`CameraCapture.vue`),先只做交互不接后端,用假数据验证体验 | 无 | -| 2 | IPC + `visionGenerator.ts` 打通,`generator.ts` content 类型改造 | 阶段0 有阶段性结果(哪怕是测试环境有一个能跑的视觉模型) | -| 3 | 配置项、设置页开关、真机联调(含真实摄像头 + 真实视觉模型) | 阶段1、2完成 | +| 0 | ~~跟 er_backend/硬件团队确认视觉模型可用性~~ **已完成**(2026-09-03,见 §2.2,端到端验证通过) | — | +| 1 | 摄像头取景/拍照 UI(`CameraCapture.vue`),先只做交互,用假数据验证体验 | 无 | +| 2 | IPC + `visionGenerator.ts` 打通,`generator.ts` content 类型改造 | 无(阶段0已就绪,可直接对真实后端联调) | +| 3 | 配置项、设置页开关、真机联调(含真实摄像头 + 真实视觉模型,重点测真实照片而非1x1测试图的延迟/效果) | 阶段1、2完成 | | 4 | 打包验证(照片相关无新增大文件,不影响现有打包体积) | 阶段3完成 | -阶段 1 可以和阶段 0 并行——UI 壳子不依赖后端是否具备视觉能力。 +阶段 0 已解除,1/2 可以直接开始且互不依赖,建议并行推进。 ## 8. 风险与未决问题 -1. **(阻塞)视觉模型可用性**:见 §2.2,需要外部确认,是本功能能否上线的唯一决定因素。 -2. Electron 权限处理器对摄像头请求的 `permission` 字符串需要实测确认(§5.1)。 -3. 两个摄像头哪个是实际安装朝向的那个(500万 vs 800万像素那颗),需要现场看一下物理安装位置, +1. Electron 权限处理器对摄像头请求的 `permission` 字符串需要实测确认(§5.1)。 +2. 两个摄像头哪个是实际安装朝向的那个(500万 vs 800万像素那颗),需要现场看一下物理安装位置, UI 上是默认写死还是给用户切换待定。 -4. 图片 base64 塞进 `/v1/chat/completions` 请求体,走 er_backend 代理转发时有没有请求体大小限制 - (nginx/代理层常见的 `client_max_body_size` 之类),需要实测一次较大分辨率照片是否会被拒绝, - §5.4 的 `maxImageDimension` 压缩正是为了控制这个风险。 -5. 揽月 NPU 跑视觉模型的推理速度未知(多模态模型通常比纯文本模型更吃算力/显存),首次联调时要 - 实测响应时延,评估是否需要专门的等待态 UI 提示。 +3. 图片 base64 塞进 `/v1/chat/completions` 请求体,走 er_backend 代理转发时有没有请求体大小限制 + (nginx/代理层常见的 `client_max_body_size` 之类),已验证极小图片可以正常通过代理,但**没测过 + 真实分辨率照片**(896×896 甚至更大的 base64 体积),§5.4 的 `maxImageDimension` 压缩正是为了 + 控制这个风险,阶段3要专门测一次。 +4. 揽月 NPU 视觉推理延迟:见 §2.2 实测数据,极简图片仅 prefill 就要 ~2s,真实照片 + 生成完整回答 + 预计 3-8 秒量级,UI 必须要有明确的"识别中"等待态。 +5. `--reasoning-budget 0` 这个启动参数暗示当前配置关闭了推理/think 模式,视觉问答场景要不要开 + thinking(现有 ChatPanel 的 `` 块渲染能力目前用不上),待联调时确认输出格式是否有变化。 ## 9. 下一步 -不写业务代码,先推进 §7 阶段 0(跟 er_backend/硬件团队确认视觉模型)—— 这是唯一的硬阻塞项, -其余都是 `elec_rag_ui` 仓库内部能自主推进的常规前端开发工作。 +阻塞项已解除,可以直接开始 §7 阶段 1(UI 壳子)和阶段 2(后端联调),两者互不依赖,建议同时推进。