mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-07 16:14:30 +00:00
fix(rel): 场景贯穿流水线到块层 + 编辑不再丢置信度/场景 + 构建默认带 onnxruntime
三件事,前两件是上一轮热部署暴露/遗留的真缺陷。
1) 热部署差点静默降级(已修)
`make build` 之前**不带任何 tags**,而发行构建(deploy/packaging/build.sh)
默认 HOMED_TAGS=onnxruntime,package-linux.sh 还会直接拒收非 onnxruntime 二进制。
实测差异:33MB vs 84MB;启动日志里
「multimodal space active: provider=chineseclip dim=512」整行消失、
少加载一个插件(chinese-clip/qwen3vl provider 降级)、
静态词向量退回 fallback。即「随手 make build」与「发行构建」不是同一个东西,
而部署时无从察觉。
修:Makefile 的 build 默认 HOMED_TAGS ?= onnxruntime(与打包脚本一致),
构建后自动校验二进制里有没有 onnxruntime,缺了就打 WARN。
生产已按此重新构建部署(v1.4.0+hotfix.d98bf51,已核实 provider 行回归)。
2) memory_edit 每跑一次就静默降级一次(新)
memory_edit 是「按包含匹配 Purge + 写新三元组」,中间那一步把旧关系的
置信度、原句、**场景引用**全丢了:置信度被重置成默认 1.0,场景钉死的记忆
被打散成无场景。而关系复审心跳(reviewLoop)走的正是这条路——每轮复审都
在无声地削记忆质量。
修:编辑前用 FindRelations 精确取回旧关系,把置信度/原句/场景带到新三元组;
新增 ScenesOfRelation。Purge(hard/soft)与 PurgeNoise/PurgeOrphans 之后
统一清理悬空 scene_refs,SceneStats 不再说谎。
3) 场景贯穿流水线到块层(按「rel 应贯穿整条流水线」的设计)
此前场景只到 relation/entity:块(L0/L3 一等记忆块)没有场景,于是
「那场 QQ 对话里发过来的那张图」在场面重现时永远取不回来。
- MemoryBlock.Scene + memory_blocks.scene 列(幂等 ALTER 迁移)。
- scene_refs 增加 ref_text 承载字符串主键(块/文档 id 不是数值)。
**不能只 ALTER ADD COLUMN**:唯一约束要从 (scene_id,kind,ref_id) 变成
含 ref_text 的四元组,而 ALTER 改不了约束——旧约束会让「同场景第 2 个块」
直接冲突(只在多块场景暴露)。改为按列探测后整表重建并搬运旧数据。
- PutMemoryBlocks 同事务挂 scene_refs(kind='block');无场景重写不覆盖已有场景
(否则一次无场景重写就静默抹掉挂载)。
- RecallByScene 返回块;FormatContext 增「场景素材」段(模态 + 文本/短 digest),
上限 3 条。
- 生产者接线:attachBlocksToSentence 让块继承承载它的三元组的场景;
linkBlocksToDocument 让文档的块继承文档来源场景(QQ 归档的图挂 chan:qq)。
验证:go build/vet 干净,go test -count=1 ./... 全绿。
新增用例:场景块(取回/同场景多块/无场景重写不抹场景/悬空引用清理)、
**旧表结构迁移**(降级成旧 scene_refs 后重开,旧数据保留且多块可写)、
场景素材注入、FindRelations+ScenesOfRelation 编辑搬运闭环。
生产:已重建(-tags onnxruntime)并原子替换 /usr/local/bin/homed + 重启,
35 插件全加载、panic/fatal=0、chineseclip 空间 active。
This commit is contained in:
@ -106,8 +106,9 @@ type InjectedContext struct {
|
||||
// Scenes 是本轮识别出的当前场景;SceneRelations 是被钉在这些场景上的
|
||||
// 记忆(带 relation_type 与原句)。两者都进注入文本——场景记忆是
|
||||
// **带条件的规则**,只给实体名等于没召回。
|
||||
Scenes []string `json:"scenes,omitempty"`
|
||||
SceneRelations []Relation `json:"scene_relations,omitempty"`
|
||||
Scenes []string `json:"scenes,omitempty"`
|
||||
SceneRelations []Relation `json:"scene_relations,omitempty"`
|
||||
SceneBlocks []MemoryBlock `json:"scene_blocks,omitempty"`
|
||||
}
|
||||
|
||||
// BuildContext 不带场景的召回(保持既有行为:词法 + 实体名向量)。
|
||||
@ -181,6 +182,7 @@ func (idx *Indexer) BuildContextInScene(userInput string, scenes []string) *Inje
|
||||
if sceneRecall != nil {
|
||||
ctx.Scenes = sceneRecall.Scenes
|
||||
ctx.SceneRelations = sceneRecall.Relations
|
||||
ctx.SceneBlocks = sceneRecall.Blocks
|
||||
}
|
||||
|
||||
if len(filtered) > 0 {
|
||||
@ -251,7 +253,7 @@ func (idx *Indexer) BuildToolPrompt() string {
|
||||
}
|
||||
|
||||
func (idx *Indexer) FormatContext(ctx *InjectedContext) string {
|
||||
if ctx == nil || (len(ctx.Entities) == 0 && len(ctx.SceneRelations) == 0) {
|
||||
if ctx == nil || (len(ctx.Entities) == 0 && len(ctx.SceneRelations) == 0 && len(ctx.SceneBlocks) == 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -274,6 +276,28 @@ func (idx *Indexer) FormatContext(ctx *InjectedContext) string {
|
||||
}
|
||||
b.WriteString("\n")
|
||||
}
|
||||
// 场景块:块是流水线里最细的子项目(一段转写、一张图的描述)。
|
||||
// 只给 id 没用,要给能判断「这是什么」的短文本。
|
||||
if len(ctx.SceneBlocks) > 0 {
|
||||
b.WriteString("场景素材: ")
|
||||
for i, blk := range ctx.SceneBlocks {
|
||||
if i >= maxSceneRecallBlocks {
|
||||
b.WriteString("…")
|
||||
break
|
||||
}
|
||||
if i > 0 {
|
||||
b.WriteString(" | ")
|
||||
}
|
||||
b.WriteString(string(blk.Modality))
|
||||
b.WriteString(" ")
|
||||
if blk.Text != "" {
|
||||
b.WriteString(truncateRunes(blk.Text, sceneSentenceMaxRunes))
|
||||
} else {
|
||||
b.WriteString(shortBlockDigest(blk.PayloadDigest))
|
||||
}
|
||||
}
|
||||
b.WriteString("\n")
|
||||
}
|
||||
b.WriteString("(以上是该场景下的既有约定,请照办)\n")
|
||||
}
|
||||
|
||||
@ -316,6 +340,17 @@ const maxSceneRecallRelations = 8
|
||||
// sceneSentenceMaxRunes 是场景关系后附原句的截断长度。
|
||||
const sceneSentenceMaxRunes = 60
|
||||
|
||||
// maxSceneRecallBlocks 是场景块在注入文本里的条数上限(同为常驻内容,要封顶)。
|
||||
const maxSceneRecallBlocks = 3
|
||||
|
||||
// shortBlockDigest 取 digest 前 12 位做展示(与 L3 里引用媒体的写法一致)。
|
||||
func shortBlockDigest(d string) string {
|
||||
if len(d) <= 12 {
|
||||
return d
|
||||
}
|
||||
return d[:12]
|
||||
}
|
||||
|
||||
func truncateRunes(s string, max int) string {
|
||||
r := []rune(s)
|
||||
if len(r) <= max {
|
||||
|
||||
Reference in New Issue
Block a user