OpenGlass 图像描述评测:基于 moondream 与 llava 多模型对比的 prompts 批处理管线
OpenGlass 图像描述评测:基于 moondream 与 llava 多模型对比的 prompts 批处理管线
导读
本文围绕 OpenGlass 仓库中 prompts/series_1/img_46.md 这份文档展开:它以一张室内建筑管道场景图为样本,记录了 4 个不同视觉语言模型(VLMs)对同一图像的描述输出。通过拆解该文档的结构与内容,并结合仓库中 prompts/generate.ts、sources/agent/imageDescription.ts 与 sources/modules/ollama.ts 的源码实现,你可以掌握 OpenGlass 的图像描述评测管线的完整工作方式、各模型输出风格的差异,以及如何复现、扩展这套多模型对比实验。
一、文档是什么:一次多模型图像描述对比实验的记录
img_46.md 是一份由脚本自动生成的评测报告,全文按固定格式组织,用 ####标题#### 分隔四个模型各自的输出,分别来自:
| 输出段落标题 | 对应模型/服务 | 在源码中的调用 |
|---|---|---|
####Description#### |
默认视觉模型 moondream:1.8b-v2-fp16 | imageDescription.ts 的默认参数 |
####Description (llava-llama3)#### |
Ollama 上的 llava-llama3 | generate.ts 显式传入模型名 |
####Description (llava:34b-v1.6)#### |
Ollama 上的 llava:34b-v1.6 | generate.ts |
####Description (moondream:1.8b-v2-fp16)#### |
Ollama 上的 moondream:1.8b-v2-fp16 | generate.ts |
这份文档的核心价值在于:同一张图片、同一个 system prompt,只改变底层模型,就能横向对比不同 VLM 在物体识别、空间关系描述、材质判断、光线感知上的能力差异——这正是 OpenGlass 眼镜端图像理解功能在选型时的重要依据。
文档对应的样本图
文档描述的场景是 img_46 这张 600x800 的室内照片(prompts/series_1/img_46.jpeg),图片列表中与本文档主题强相关的图即此图,用于对照各模型描述的真实场景。
二、逐模型解读:四个 VLM 对同一场景的描述差异
将 img_46.md 中四段描述与图片本身对照,可以清晰看到模型能力的层级差异:
2.1 默认 Description(moondream 默认输出)
The image features a large, white pipe running across the ceiling of an indoor space. The pipe is connected to a circular air vent located on the right side of the room. There are several windows in the background, providing natural light and ventilation for the area.
默认输出抓住主干:识别出天花板上的白色大型管道、右侧的圆形通风口(air vent)、背景多扇窗户及其采光通风作用。表述简洁、信息密度高,但对管道的吊挂方式和更细的构件没有展开。
2.2 llava-llama3
...a white ceiling fan is suspended from the roof. The fan, with its black circular blade, hangs on a white pole that extends diagonally across the frame. The background reveals a brick wall punctuated by two windows, and a glass door.
llava-llama3 产生了明显偏差:把沿斜向延伸的白色通风管道误判为"白色吊扇(ceiling fan)",并把圆形旋流风口当作"黑色圆形叶片"。同时它补充了砖墙(brick wall)、玻璃门等细节,语言更生动,但物体识别准确性下降。这个例子恰好说明:同一 prompt 下,模型参数规模与训练数据分布会直接影响视觉描述的正确性。
2.3 llava:34b-v1.6
The image shows the interior of a building with an architectural structure that suggests it could be part of a railway station or perhaps an older public building. The ceiling is vaulted and features what appears to be exposed ductwork, possibly for ventilation or heating. There's also a visible air conditioning unit on one of the ducts. Sunlight filters through windows located near the top of the wall...
34B 参数量的 llava 给出了最"推理化"的描述:不仅识别出裸露风管(exposed ductwork),还推断建筑类型(火车站/旧公共建筑)、指出窗边阳光营造的氛围,并提到墙面的大幅板材贴面带来工业美学。它的描述最长、最富上下文推理,但也加入了"可能""或许"这类主观推断,说明大模型倾向于补全场景叙事。
2.4 moondream:1.8b-v2-fp16(显式指定)
The image captures the interior of a building, with an overhead pipe or duct running from the ceiling down to the bottom. The roof and walls are white in color... there are four visible windows located throughout the space.
moondream 1.8B 作为仓库默认的轻量模型,输出介于两者之间:识别出管道/风管(pipe or duct)、白色屋顶墙面、多扇窗户,并给出了窗户数量的明确计数(four visible windows)。相比 34B 模型,它不做场景推断,但保持事实性描述。
小结:四段描述的横向对比
| 维度 | moondream(默认) | llava-llama3 | llava:34b-v1.6 | moondream(显式) |
|---|---|---|---|---|
| 物体识别 | 管道+圆形通风口,准确 | 误判为吊扇+叶片 | 风管+空调机组,准确 | 管道/风管,准确 |
| 细节深度 | 中 | 中 | 高(含材质、建筑类型推断) | 中(含窗户计数) |
| 推断成分 | 低 | 中 | 高(推测建筑类型) | 低 |
| 语言风格 | 简洁客观 | 生动但易错 | 叙事化、上下文丰富 | 简洁事实性 |
三、源码级剖析:这份文档是如何生成的
3.1 批处理脚本:prompts/generate.ts
prompts/generate.ts 是整套评测的驱动脚本,逻辑分三步:
- 收集图片:遍历
__dirname(即 prompts 目录)下所有子目录(series_1、series_2 等),收集其中所有.jpeg文件,并把对应的.md路径作为输出目标(generate.ts); - 批量推理:对每个图片依次调用 4 个测试函数(Description 默认模型、llava-llama3、llava:34b-v1.6、moondream:1.8b-v2-fp16),每次推理前先向
outputs追加####标题####段头再追加模型输出(generate.ts); - 写回文件:把拼接好的全部输出写回对应
.md(generate.ts)。
同时脚本使用 cli-progress 打印进度条,方便长时间批量推理时观察进度;被注释掉的 imageBlurry 部分表明还预留了"模糊度检测"评测项。
3.2 图像描述入口:sources/agent/imageDescription.ts
每个模型的实际推理都收敛到 imageDescription 这一个函数:
export async function imageDescription(src: Uint8Array, model: KnownModel = 'moondream:1.8b-v2-fp16'): Promise<string> {
return ollamaInference({
model: model,
messages: [{
role: 'system',
content: 'You are a very advanced model and your task is to describe the image as precisely as possible. Transcribe any text you see.'
}, {
role: 'user',
content: 'Describe the scene',
images: [src],
}]
});
}
值得注意的细节:
- 默认模型是
moondream:1.8b-v2-fp16,这就是文档中第一段无后缀Description的来源; - System Prompt 固定为"尽可能精确描述图像,并转写你看到的任何文字"——因此文档中所有模型都接到同一指令,差异完全来自模型本身;
- 用户消息以
images数组携带二进制图像数据,Describe the scene是统一的问题。
3.3 推理层:sources/modules/ollama.ts
ollamaInference 负责把图片转成 Ollama API 可接受的格式并做请求:
- 将每条消息的
images(Uint8Array)通过 toBase64 转成 base64 字符串; - 对消息 content 用 trimIdent 清理缩进;
- POST 到
keys.ollama配置的地址(stream: false,即一次性返回); - 从响应
message.content取回文本并 trim 后返回。
请求包裹在 backoff 重试机制中:失败时指数退避等待后重试(默认最小延迟 250ms、最大 1000ms、最多 50 次失败计数),保证长时间批量评测在 Ollama 服务偶发抖动时也能稳定跑完。KnownModel 类型(ollama.ts)列出了仓库支持的模型集合,包括 llama3、llava-llama3、llava:34b-v1.6、moondream 系列等,新增模型只需扩展该联合类型即可。
四、从评测文档到眼镜端 Agent:描述的用途
img_46.md 这类描述文档并非孤立产出,它们服务于 OpenGlass 眼镜端的视觉问答链路。在 sources/agent/Agent.ts 中:
addPhoto把眼镜拍摄的每张照片交给默认的imageDescription生成描述,并以{ photo, description }形式缓存(Agent.ts);answer把多条描述拼接成Image #0 / #1 ...的上下文文本,再交给 llamaFind(走 Groq 的 llama3-70b-8192)回答用户问题(Agent.ts)。
也就是说:评测文档中比较的这些描述质量,直接决定了眼镜端"看图问答"的上限——描述越准确,Groq 的 llama3 基于描述作答时就越不容易被误导。img_46.md 中 llava-llama3 把管道误判成吊扇的例子,恰好是选择描述模型时必须警惕的失败模式。
五、复现与扩展:如何自行跑通这套评测
5.1 环境准备
- 安装依赖(仓库为 Expo/TypeScript 项目):在仓库根目录执行
npm install或yarn install(README.md); - 配置密钥:在 sources/keys.ts 对应的环境变量中填入
EXPO_PUBLIC_GROQ_API_KEY、EXPO_PUBLIC_OLLAMA_API_URL、EXPO_PUBLIC_OPENAI_API_KEY;Ollama 默认地址为http://localhost:11434/api/chat; - 拉取模型:
ollama pull moondream:1.8b-v2-fp16,并按需ollama pull llava-llama3、ollama pull llava:34b-v1.6。
5.2 运行生成脚本
在仓库根目录执行:
npx ts-node prompts/generate.ts
脚本会自动遍历 prompts/ 下所有 series 子目录的 .jpeg,逐张调用 4 个模型推理,并将结果按 ####模型名#### 格式写入同名 .md 文件——新放入 series 目录的一张 jpeg,就会生成一份和 img_46.md 结构完全一致的新文档。
5.3 扩展新模型
在 ollama.ts 的 KnownModel 联合类型中加入新模型名(如 llava:13b),并在 generate.ts 中仿照现有四个 runTest 调用增加一段即可。若需调整描述指令,修改 imageDescription 中的 system prompt 后重新运行脚本,即可得到同一 prompt 下所有模型的对比输出。
六、实践启示与注意事项
- 同一 prompt、不同模型的差异可能很大:
img_46.md展示的吊扇误判证明,轻量模型并非总是更差,llava-llama3 在物体识别上反而败给了 1.8B 的 moondream;选型时应以批量评测数据为准,而非模型名或参数量; - 描述质量决定下游问答质量:眼镜端
Agent.answer只依赖描述文本作答,描述中的任何错误都会被放大到最终答案,因此评测文档是构建可靠智能眼镜问答系统的第一道质量门; - 大模型更爱"脑补":34B 的 llava 输出最具叙事性,但也加入了"可能是火车站"这类未经证实的推断;面向"精确转写、客观描述"的场景,需在 prompt 层面约束模型减少推测;
- 管线可复现:整个评测管线由 generate.ts、imageDescription.ts、ollama.ts 三处源码构成,配合 time.ts 的重试机制,可在本地完整复现,为后续接入更大模型(如 gpt-4o,见 openai.ts 的
describeImage)提供了清晰的扩展点。
结语
prompts/series_1/img_46.md 虽然只是一份自动生成的评测输出,但它完整承载了 OpenGlass 视觉能力的评估方法论:用固定 prompt 驱动多模型横向对比,用统一格式沉淀结论,再用结论指导眼镜端 Agent 的模型选型。理解这份文档的生成链路,也就理解了 OpenGlass 从"拍照"到"理解场景"再到"回答提问"整条视觉智能管线的第一环。