mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
feat(knowledge): 分类过滤与多模态打通到工具/插件边界
- internal/sdk:KnowledgeAPI 增加 SearchIn/AddWithMedia/AttachMedia/ ReindexDense/DenseStats;新增 MediaAPI(Put/Stat/Get)与 PluginSDK.Media(), registry 装配。**公开 SDK 契约一字未动** —— third_party/homeagent-sdk/sdk/ 的 diff 恒为 0(发布纪律的硬约束),走 internal/sdk 这条明确不受冻结约束 的内部扩展路径。 - proc:新增 knowledge.addWithMedia(正文与媒体清单都走共享内存,与 doc.insertWithMedia 同形);knowledge.search 支持 category。 - corehandler 用**局部接口 + 类型断言**取扩展能力,而非直接引 internal/sdk: 后者已依赖 internal/plugin 的类型,直接引会成环(CoreSDK 注释已警示)。 断言失败明确报"能力不可用",不静默退化成"媒体已写入"。 - agent 工具面:knowledge_search 增加 category;knowledge_create 增加 media_digests(复用 doc_commit 的 digest 前缀解析 + Stat 回读 MIME)。 顺带修 knowledge_search 的分类前缀重复(Name 已含分类,旧代码又拼一次, 实测输出 tech/go/tech/go/并发)。 - agent 启动接线多模态空间,顺序为先接线再 ReindexDense(否则首次启动 算出的向量因 MediaStore 未就绪而不落盘)。
This commit is contained in:
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
agentAPI "gitcode.com/JianFeeeee/HomeAgent/internal/agent/api"
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/knowledge"
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory"
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/document"
|
||||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/text"
|
||||
@ -536,6 +537,30 @@ func (a *Agent) executeSocialTool(tc agentAPI.ToolCall) string {
|
||||
}
|
||||
}
|
||||
|
||||
// knowledgeMediaRefs 把模型给的 digest 列表解析成知识条目的媒体引用。
|
||||
//
|
||||
// 复用 doc_commit 的既有约定:digest 可传前缀(ResolvePrefix),解析不了
|
||||
// 的跳过而不是报错——模型偶尔会把 digest 记错,不该让整次写入失败。
|
||||
// MIME 从媒体存储回读,嵌入时需要(EmbedImageDense 靠它判定模态)。
|
||||
func (a *Agent) knowledgeMediaRefs(digests []string) []knowledge.KnowledgeMediaRef {
|
||||
if a.mediaStore == nil || len(digests) == 0 {
|
||||
return nil
|
||||
}
|
||||
var out []knowledge.KnowledgeMediaRef
|
||||
for _, d := range a.resolveMediaDigests(digests) {
|
||||
it, err := a.mediaStore.Stat(d)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, knowledge.KnowledgeMediaRef{
|
||||
Digest: it.Digest,
|
||||
MIME: it.MIME,
|
||||
Kind: string(it.Kind),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *Agent) executeKnowledgeTool(tc agentAPI.ToolCall) string {
|
||||
if a.knowledge == nil {
|
||||
return "知识库不可用"
|
||||
@ -550,7 +575,10 @@ func (a *Agent) executeKnowledgeTool(tc agentAPI.ToolCall) string {
|
||||
if query == "" {
|
||||
return "请输入查询关键词"
|
||||
}
|
||||
results := a.knowledge.Search(query, topK)
|
||||
// 可选分类限定:把召回限制在某棵分类子树内(前缀匹配,见
|
||||
// knowledge.Store.SearchIn)。不传 = 全库。
|
||||
category, _ := tc.Arguments["category"].(string)
|
||||
results := a.knowledge.SearchIn(query, category, topK)
|
||||
if len(results) == 0 {
|
||||
return "未找到相关知识"
|
||||
}
|
||||
@ -559,11 +587,9 @@ func (a *Agent) executeKnowledgeTool(tc agentAPI.ToolCall) string {
|
||||
if i >= topK {
|
||||
break
|
||||
}
|
||||
label := k.Name
|
||||
if k.Category != "" {
|
||||
label = k.Category + "/" + k.Name
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("[%s]\n%s", label, truncateStr(k.Content, 200)))
|
||||
// Name 已是含分类的规范名("tech/go/并发"),分类前缀就在里面。
|
||||
// 曾经这里再拼一次 Category,输出成 "tech/go/tech/go/并发"(实测)。
|
||||
parts = append(parts, fmt.Sprintf("[%s]\n%s", k.Name, truncateStr(k.Content, 200)))
|
||||
}
|
||||
return strings.Join(parts, "\n---\n")
|
||||
|
||||
@ -573,9 +599,16 @@ func (a *Agent) executeKnowledgeTool(tc agentAPI.ToolCall) string {
|
||||
if name == "" || content == "" {
|
||||
return "name 和 content 不能为空"
|
||||
}
|
||||
if err := a.knowledge.Add(name, content); err != nil {
|
||||
// 模型可显式关联已入库的媒体(与 doc_commit 的 media_digests 同形)。
|
||||
// 这些媒体成为知识条目的一等节点:其向量会与正文向量融合,
|
||||
// 使该条目能按图本身被召回,而不依赖任何生成的描述文本。
|
||||
media := a.knowledgeMediaRefs(getStringSlice(tc.Arguments, "media_digests"))
|
||||
if err := a.knowledge.AddWithMedia(name, content, media); err != nil {
|
||||
return fmt.Sprintf("知识创建失败: %v", err)
|
||||
}
|
||||
if len(media) > 0 {
|
||||
return fmt.Sprintf("知识「%s」已创建并向量化索引(%d 字符,%d 个媒体参与跨模态召回)", name, len(content), len(media))
|
||||
}
|
||||
return fmt.Sprintf("知识「%s」已创建并向量化索引(%d 字符)", name, len(content))
|
||||
|
||||
case "knowledge_list":
|
||||
|
||||
Reference in New Issue
Block a user