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 树浏览(前端真正用起来,而非留一个没人调的端点)
  面板加可折叠的分类树:逐级点选即把搜索范围切到该子树(原先是让人
  手打分类名)。当前范围有可见标签与「全库」复位。
This commit is contained in:
JianFeeeee
2026-09-26 14:19:34 +08:00
parent ce694bc1a1
commit 41d754334e
14 changed files with 2071 additions and 9 deletions

View File

@ -0,0 +1,131 @@
---
name: knowledge-base
description: 按分类树检索 HomeAgent 知识库。当需要查阅项目知识、架构约定、历史决策,或用户提到"知识库/knowledge/知识库有哪些/这个项目的约定是什么"时使用。支持树形导航、分类内检索、以图搜知识。
version: 1.1.0
author: HomeAgent
---
## Usage
先看树定位分类,再做定向检索。接口由 HomeAgent 的 `kbtree` 插件提供,
只读、需 token。详见下方"接入"。
HomeAgent 知识库按**分类树**组织(`tech/go/并发`、`life/sleep` …)。
### 何时用
- 用户问"这个项目/内核的某个约定是什么" → 先看树,找对分类再检索
- 用户提到"知识库"或某个看起来像分类名的词(如 `tech/go`)→ 查该子树
- 用户给了图片并问"知识库里有相关的吗" → 见"以图搜知识"
### 接入
服务默认监听 `127.0.0.1:9892`(配置项 `kbtree.listen_addr`),只读,
每次请求需带 token(配置项 `kbtree.token`;未配置则启动时随机生成)。
```bash
BASE=http://127.0.0.1:9892
AUTH="X-API-Key: $KB_TOKEN" # 或 Authorization: Bearer <token> 或 ?token=
```
先摸清可用接口:
```bash
curl -s -H "$AUTH" "$BASE/"
```
### 核心工作流:先看树,再定向检索
**别一上来就全文搜索。** 知识库是分层的,先定位分类能显著提高命中率,
也能避免把范围外的弱匹配当答案。
#### 第 1 步 · 看有哪些分类
```bash
curl -s -H "$AUTH" "$BASE/categories"
# {"categories":["cook","life","tech","tech/go","tech/rust"]}
# 内容最多的分类(按条目数倒序)
curl -s -H "$AUTH" "$BASE/counts"
# {"counts":[{"category":"tech","count":3}, ...], "total":5}
```
#### 第 2 步 · 浏览树结构
```bash
# 整棵树,只要结构
curl -s -H "$AUTH" "$BASE/tree?items=0"
# 只要第一层 —— 分类多时用来做懒加载
curl -s -H "$AUTH" "$BASE/tree?depth=1&items=0"
# 某棵子树,带条目详情
curl -s -H "$AUTH" "$BASE/tree?category=tech/go"
```
节点里 `name` 是**本级段名**(`"go"`),`path` 是**完整路径**
(`"tech/go"`)。拼层级用 `name`,把 `path` 拿去请求子节点。
`item_count` 是本级条目数,`total_count` 是整棵子树。
#### 第 3 步 · 分类内检索
```bash
# 关键词 + 分类子树(推荐)
curl -s -H "$AUTH" "$BASE/search?q=goroutine&category=tech"
# 全库
curl -s -H "$AUTH" "$BASE/search?q=goroutine&limit=5"
```
`category` 是**前缀匹配**:`tech` 会命中 `tech/go`、`tech/rust` 下的条目;
传 `tech/go` 只命中它自己的子树。
### 以图搜知识(多模态)
若知识条目挂了图片,它在**多模态统一空间**里有向量,能被图片本身检索到。
前提是宿主已接入多模态向量 provider(否则只是记录了媒体,不参与召回)。
判断是否就绪:HomeAgent 自身的知识库接口会返回稠密路状态
(`dense.enabled` / `dense.ready` / `dense.total`)。若为未启用,
**不要承诺"能以图搜"**。
本服务只提供**按关键词检索**——把图片字节提交给嵌入服务计算向量不在此接口内。所以:
- 用户给了图 → 用图的**可见内容**(或你先读图得到的文字)当关键词检索
- 或用本机可用的读图工具先看图,再拿描述来检索
### 读结果
`/search` 每条结果:
| 字段 | 含义 |
|---|---|
| `name` | 知识名(**已含分类前缀**,如 `tech/go/并发`) |
| `content` | 正文全文 |
`/tree` 里的条目额外有 `preview`(前 120 字)、`size`、`updated_at`、
`media`(挂载的媒体 digest/mime/kind)。
### 易错点
- **`name` 已经含分类**。不要再拼 `category + "/" + name`,会得到
`tech/go/tech/go/并发`。
- **检索会返回弱匹配。** 词法路会给所有条目打一个低分,靠排序把强命中顶到
前面。**只看第一条**;第一条明显不相关就换个分类或关键词,别把第 2、3 条
当答案。
- **分类不存在返回 404**,并在 `categories` 字段里附上现有分类 —— 用它自查
拼写。
- **`items=0` 只是不要正文**,`total_count` 仍准确,可用于判断规模。
- **本服务只读**。写方法返回 405。要写知识请用 HomeAgent 主 agent 的
`knowledge_create`(或 WebUI 界面),不要试图绕过它直接写这个接口。
- 知识名里不能有 `..`、空格(会被规范成 `_`)、点开头的段。
### 写入
本服务不提供写入。若你在 HomeAgent 主 agent 内部,写入用内核工具:
```
knowledge_create name="tech/go/调度" content="正文..."
```
`name` 用 `/` 表示分类层级(如 `tech/go/调度`)。写完它**立刻可检索**
(词法 IDF 是增量维护的,不必重启)。

View File

@ -0,0 +1,6 @@
{
"name": "knowledge-base",
"description": "按分类树检索 HomeAgent 知识库:树形导航、分类内检索、以图搜知识",
"version": "1.1.0",
"author": "HomeAgent"
}