mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
feat(memory): 千问文本塔 ONNX 嵌入器(onnxruntime 标签,含 stub)
与 internal/memory/clip 同模式:`//go:build onnxruntime` 编真实实现,无标签时 走 stub,默认构建不链接 onnxruntime、行为不变。 加载契约(目录由 core.memory.multimodal_space.model_dir 指定): TextTower.onnx + 外部权重分片、tokenizer.json、embed_config.json。 图内已含 last-token 池化,输出即 [batch, dim];L2 归一化在 Go 侧做。 两个刻意的设计选择: 1. **EmbedImageDense 明确报错,不返回零向量** 导出的是文本塔,视觉塔未导出。返回零向量会让「写入了但检索不到」, 把跨模态检索失效变成静默故障;明确报错则调用方(mediaref.go)log 后 跳过写向量,文本路径不受影响。 2. **Fingerprint 只哈希图文件 + 配置 + 外部权重的文件名与大小** 该目录有 6.5GB 权重分片,启动时全读一遍要几十秒、会阻塞 homeagent 启动。 换模型必然改变文件集合或大小,足以识别切换;代价是理论上存在 「大小相同但内容不同」的漏判,对本地单机部署可接受。已写入注释。 模板渲染(renderInstructionInput)放在无构建标签的 tokenizer.go,因此可被 测试覆盖:参考数据里有该模板串的用例,逐 token 对齐验证——模板差一个字符, 池化取到的「最后一个有效 token」位置就变,向量就不同,且不会报错。 验证:6 个测试全绿;go build ./...(stub)与 go build -tags onnxruntime (真实实现)均通过。
This commit is contained in:
@ -136,6 +136,24 @@ func (t *Tokenizer) SpecialID(content string) (int, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// DefaultInstruction 是导出脚本随 embed_config.json 写入的默认指令。
|
||||
const DefaultInstruction = "Represent the user's input."
|
||||
|
||||
// renderInstructionInput 按模型自带的对话模板拼输入(无构建标签,便于测试)。
|
||||
//
|
||||
// 必须与 HuggingFace processor 的 apply_chat_template(add_generation_prompt=True)
|
||||
// 产出完全一致:指令放 system、正文放 user、以 assistant 起始符结尾。差一个
|
||||
// 特殊 token,池化取到的「最后一个有效 token」位置就变了,嵌入也就不同——
|
||||
// 而且不会报错。参考数据集里有该模板串的用例,能逐 token 对齐验证。
|
||||
func renderInstructionInput(instruction, text string) string {
|
||||
if instruction == "" {
|
||||
instruction = DefaultInstruction
|
||||
}
|
||||
return "<|im_start|>system\n" + instruction +
|
||||
"<|im_end|>\n<|im_start|>user\n" + text +
|
||||
"<|im_end|>\n<|im_start|>assistant\n"
|
||||
}
|
||||
|
||||
// Encode 把文本编码为 token id 序列(不含特殊 token、不做截断)。
|
||||
func (t *Tokenizer) Encode(text string) []int {
|
||||
var ids []int
|
||||
|
||||
Reference in New Issue
Block a user