Files
HomeAgent/internal/sdk/knowledge.go
JianFeeeee 41d754334e feat(kbtree): 知识库分类树的独立只读服务 + agent 技能 + WebUI 树浏览
让**外部 agent** 也能按分类树用这套知识库。HomeAgent 自己的 agent 仍
直接调内部方法(knowledge_search/create 等),走进程内直调,不经此服务。

一、内核树视图(internal/knowledge/tree.go)
  为什么不复用 TreeIndex:那个是**内部导出物**,面向 .index.json 落盘,
  每个条目带 top-20 的 TF-IDF 特征向量。直接序列化给外部有三个问题:
  体积(200 条时 .index.json 已 246KB 且冗余存了 preview,而正本在
  content.md)、泄漏(稀疏特征表 = 分词/IDF 内部表示)、语义错位
  (外部要的是"有哪些分类、每类下有什么")。
  新增 TreeView/Subtree/Categories/CategoryCounts:不含向量,带条目数
  与可读摘要,支持 MaxDepth 懒加载、IncludeItems 只看结构。
  节点 Name 是**本级段名**("go")、Path 是完整路径("tech/go")——
  最初把全路径写进 Name,前端拼层级会得到 "tech/tech/go",已修。

二、kbtree 插件:独立 HTTP 服务(默认 127.0.0.1:9892)
  为何不挂在 WebUI 的 /api/v1/knowledge* 下:
  1. 不共享鉴权与端口。WebUI 的 api_key 是给人操作界面用的,把它分发给
     外部 agent 等于把管理面凭据扩散出去。本服务用**独立 token** +
     独立端口,可单独关闭(token 未配置则启动时随机生成)。
  2. 只读。写入要决定分类归属与媒体处理,外部自行拼装容易造出越界/重名
     条目 —— 写入留给内核工具。
  3. 形状按树组织,而不是平铺搜索接口。
  端点:/tree(可指定 category/depth/items)、/categories、/counts、
  /search、/ (自述)。全部需 token(X-API-Key / Bearer / ?token=),
  非 GET 一律 405。无知识库时 Start 直接失败,不占端口。
  鉴权与 Slowloris/超时设置照 remotedevice 范式。

三、agent 技能(assets/skills/knowledge-base/SKILL.md)
  指令文档型 skill:教模型"先看树 → 定位分类 → 分类内检索",并列出
  易错点(name 已含分类别再拼、只看第一条、404 附现有分类)。
  加载与校验由 internal/plugin/skill_bundled_test.go 守住 —— 这条断言
  的由来:非白名单的二级标题会被 extractToolDefs 当成工具定义,报错
  "invalid tool name",而提示与真正原因(标题层级)毫无关联。
  kbtree 的测试还会校验文档提到的端点与代码一致,防漂移。

四、WebUI 树浏览(前端真正用起来,而非留一个没人调的端点)
  面板加可折叠的分类树:逐级点选即把搜索范围切到该子树(原先是让人
  手打分类名)。当前范围有可见标签与「全库」复位。
2026-09-26 14:20:19 +08:00

82 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sdk
import (
"gitcode.com/JianFeeeee/HomeAgent/internal/knowledge"
pubsdk "gitcode.com/JianFeeeee/homeagent-sdk/sdk"
)
// KnowledgeAPI 是内置插件使用的全量知识库接口。
//
// 为什么不把多模态加进 pubsdk.KnowledgeAPI:那会改动
// third_party/homeagent-sdk/sdk/ 的公开契约,而发布纪律要求
// `git diff main -- third_party/homeagent-sdk/sdk/` 恒为 0
// (改动它等于一次 major bump + 完整的外部发版流程)。
// internal/sdk 明确不受此约束("内部实现自由"),且这里本来就是
// "内核侧接口 = 公共接口 + 内置插件额外能力" 的既有范式
// (见 PluginSDK 遮蔽访问器:Settings/Memory/TextMemory/DocMemory…)。
// 结果是:内置插件(含子进程插件的 core handler)拿到多模态能力,
// 而外部 SDK 契约保持逐字不变。
type KnowledgeAPI interface {
pubsdk.KnowledgeAPI
// Stats 返回知识库的运行统计。
Stats() map[string]interface{}
// Remove 按名称删除一条知识。
Remove(name string) error
// SearchIn 在某个分类子树内检索(category 为空 = 全库)。
SearchIn(query, category string, topK int) ([]*Knowledge, error)
// Tree 返回分类树视图(面向服务:不带向量,只带计数与摘要)。
Tree(opt KnowledgeTreeOptions) (*KnowledgeTreeView, error)
// Subtree 返回某棵子树;category 为空等价于 Tree。
Subtree(category string, opt KnowledgeTreeOptions) (*KnowledgeTreeView, error)
// Categories 列出全部分类路径(去重排序)。
Categories() ([]string, error)
// CategoryCounts 给出每个分类的条目数,按数量倒序。
CategoryCounts() ([]KnowledgeCategoryCount, error)
// AddWithMedia 写入带媒体的知识。媒体是一等节点:其向量会与正文向量
// 在多模态统一空间内融合,使该条目能按图本身被召回。
//
// 未接入多模态空间时与 Add 等价(媒体仍被记录,只是不参与召回)。
AddWithMedia(name, content string, media []KnowledgeMediaRef) error
// AttachMedia 给已有知识追加媒体,并当场重算其稠密向量。
AttachMedia(name string, media ...KnowledgeMediaRef) error
// ReindexDense 重建稠密向量(模型/维度变化后调用),返回新建与跳过条数。
ReindexDense() (built, skipped int)
// DenseStats 报告稠密路的接线与覆盖情况。
DenseStats() map[string]interface{}
}
// KnowledgeMediaRef 是媒体在知识条目中的一等引用。
//
// 与内核 knowledge.KnowledgeMediaRef 是**类型别名**而非新类型:别名
// 才能穿过 C ABI / JSON 边界;若是两种结构,core handler 还得再做一次
// 手工转换,漏一处就是「媒体被静默丢弃」。
type KnowledgeMediaRef = knowledge.KnowledgeMediaRef
// Knowledge 沿用公共 SDK 的类型,保证内外两侧对同一批知识条目的
// 字段理解一致(跨 ABI 传递时按此结构序列化)。
type Knowledge = pubsdk.Knowledge
// KnowledgeTreeOptions 控制树视图的取舍。
type KnowledgeTreeOptions struct {
// MaxDepth 限制层数,0 = 不限。分类多时用它做懒加载。
MaxDepth int
// IncludeItems 是否填充条目详情(只看结构时可关掉)。
IncludeItems bool
// PreviewLimit 预览字数上限,0 用内核默认。
PreviewLimit int
}
// KnowledgeTreeView 是分类树节点。
type KnowledgeTreeView = knowledge.TreeView
// KnowledgeTreeItemView 是树上的知识条目。
type KnowledgeTreeItemView = knowledge.TreeItemView
// KnowledgeTreeMediaView 是条目挂载的媒体摘要。
type KnowledgeTreeMediaView = knowledge.TreeMediaView
// KnowledgeCategoryCount 是一个分类的条目数。
type KnowledgeCategoryCount = knowledge.CategoryCount