mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-26 20:33:15 +00:00
docs(kbtree): 补客户端封装脚本 + 本机部署交接说明
SKILL.md 里原本只有 curl 示例,agent 用起来要自己拼 URL 与鉴权头。 补 scripts/kb_tree.sh(照 dify-ops 的做法把脚本随 skill 分发): - 子命令 tree/categories/counts/search,选项 -q/-c/-d/-i/-l - token 读取顺序:KB_TOKEN 环境变量 → config/config.json。 **故意不接受命令行传 token**(会进 shell 历史与 ps 输出) - 预检端口:不通时直接说明「服务未上线」并给出上线步骤, 而不是抛 curl: (7) Connection refused 让用户自己猜 - 错误翻译成人话:401 → 令牌无效;404 → 附上服务端返回的现有分类 (用 curl -w 而非 -f,否则 404 响应体里最有用的那份清单会被丢掉) - 退出码:0 成功 / 2 参数 / 3 令牌 / 4 分类不存在 / 5 HTTP / 7 连不上 / 8 请求失败 DEPLOY.md 是给部署方的交接单:本机 kbtree 代码已合入 main 且 skill/token 已就位,但**运行中的二进制里没有 kbtree**(14:35 有人换过一版二进制), 故替换与重启留给部署方。含备份/替换/验证步骤、回滚方式、端口与 token 说明。 token 与 config.json **不入库**(config/ 目录留空),安装时由部署方从 配置库 config_kbtree 表读取后写入本机。
This commit is contained in:
105
assets/skills/knowledge-base/DEPLOY.md
Normal file
105
assets/skills/knowledge-base/DEPLOY.md
Normal file
@ -0,0 +1,105 @@
|
||||
# kbtree 本机部署交接(交给部署方执行)
|
||||
|
||||
我负责把 kbtree 的**代码**合入 main,并把 **skill + 调用方法**在本机装好。
|
||||
**二进制替换与重启由你做** —— 我不碰运行中的生产守护进程。
|
||||
|
||||
## 现状(交接时的事实)
|
||||
|
||||
| 项 | 状态 |
|
||||
|---|---|
|
||||
| kbtree 代码 | ✅ 已在 `main`(`41d7543`),已推送 |
|
||||
| skill | ✅ 已装 `/home/newqqagent/skills/knowledge-base/` |
|
||||
| token | ✅ 已写入 `config_kbtree` 表(固定值,重启不变) |
|
||||
| 配置库备份 | ✅ `config.db.bak-20260926-143643` |
|
||||
| **服务** | ❌ **未上线** —— 运行中的二进制里没有 kbtree |
|
||||
| 我构建的候选二进制 | `/tmp/homed-new`(84.7MB,与 main 同源,`-tags onnxruntime`) |
|
||||
|
||||
**为何未上线**:14:35 有人替换了 `/usr/local/bin/homed`(84,985,720 字节)并重启了
|
||||
服务(现 PID 1450152)。那个二进制与 main 构建**不是同一份**,比我的大 2.4MB。
|
||||
直接部署会覆盖它 —— 所以交给你决定何时、以及以哪个版本为准。
|
||||
|
||||
实测确认现役二进制不含 kbtree:
|
||||
|
||||
```bash
|
||||
strings /usr/local/bin/homed | grep -c kbtree # → 0
|
||||
ss -ltn | grep 9892 # → 无监听
|
||||
```
|
||||
|
||||
## 上线步骤
|
||||
|
||||
**必须按顺序,且第 1 步不能用 `cp`**:
|
||||
|
||||
```bash
|
||||
DATA=/home/newqqagent
|
||||
|
||||
# 1. 备份配置库(WAL 模式下 cp 会拿到不一致快照,必须用 .backup)
|
||||
sqlite3 $DATA/config.db ".backup '$DATA/config.db.bak-$(date +%Y%m%d-%H%M%S)'"
|
||||
|
||||
# 2. 确认要部署的二进制
|
||||
strings /tmp/homed-new | grep -c kbtree # 期望 ≥ 1;为 0 说明候选不对
|
||||
|
||||
# 3. 原子替换(install 内部是 rename,不会写坏运行中进程的映像)
|
||||
install -m 0755 /tmp/homed-new /usr/local/bin/homed
|
||||
|
||||
# 4. 重启
|
||||
systemctl restart homeagent
|
||||
|
||||
# 5. 验证
|
||||
systemctl is-active homeagent
|
||||
journalctl -u homeagent --since "-2min" | grep kbtree
|
||||
ss -ltn | grep 9892
|
||||
```
|
||||
|
||||
### 第 5 步期望看到
|
||||
|
||||
```
|
||||
[kbtree] 已启动 http://127.0.0.1:9892
|
||||
[kbtree] 外部 agent 可用:GET /tree、/categories、/counts、/search?q=&category=
|
||||
```
|
||||
|
||||
## 部署后的冒烟测试
|
||||
|
||||
```bash
|
||||
cd /home/newqqagent/skills/knowledge-base
|
||||
|
||||
./scripts/kb_tree.sh -h # 帮助(不需要 token)
|
||||
./scripts/kb_tree.sh categories # 分类列表
|
||||
./scripts/kb_tree.sh counts # 各分类条目数
|
||||
./scripts/kb_tree.sh tree -d 1 -i 0 # 只看第一层结构
|
||||
./scripts/kb_tree.sh search -q 知识库 -c tech -l 3
|
||||
```
|
||||
|
||||
token 自动从 `config/config.json` 读(权限 600),无需手动 export。
|
||||
覆盖方式:`KB_TOKEN=xxx ./scripts/kb_tree.sh ...` 或改那个 json。
|
||||
|
||||
## 端口与 token
|
||||
|
||||
- 监听:`kbtree.listen_addr` = `127.0.0.1:9892`(**仅本机**)
|
||||
- token:`kbtree.token` 已在 `config_kbtree` 表里设为固定值。
|
||||
若要改成随机(每次重启变),把该行 value 置空即可 ——
|
||||
但那样每次重启都要重新把 token 告诉所有使用者。
|
||||
- 改 token 时**两处一起改**:`config_kbtree` 表 + `skills/knowledge-base/config/config.json`。
|
||||
|
||||
要对外(别的机器)时改 `listen_addr` 为 `0.0.0.0:9892`,
|
||||
但**先想清楚 token 怎么分发** —— 它是唯一的屏障。
|
||||
|
||||
## 退出码约定(脚本)
|
||||
|
||||
| 码 | 含义 |
|
||||
|---|---|
|
||||
| 0 | 成功 |
|
||||
| 2 | 参数错误 / 未知命令 |
|
||||
| 3 | 令牌无效(401) |
|
||||
| 4 | 分类不存在(404,stderr 会列出现有分类) |
|
||||
| 5 | 其它 HTTP 错误 |
|
||||
| 7 | 连不上(**通常是服务未上线**) |
|
||||
| 8 | 请求发送失败 |
|
||||
|
||||
## 回滚
|
||||
|
||||
```bash
|
||||
install -m 0755 <旧二进制> /usr/local/bin/homed
|
||||
systemctl restart homeagent
|
||||
```
|
||||
|
||||
配置与 skill 都不影响回滚(kbtree 未启动时它们只是闲置文件)。
|
||||
@ -34,6 +34,23 @@ AUTH="X-API-Key: $KB_TOKEN" # 或 Authorization: Bearer <token> 或 ?token=
|
||||
curl -s -H "$AUTH" "$BASE/"
|
||||
```
|
||||
|
||||
### 本机封装脚本(推荐先用它)
|
||||
|
||||
`scripts/kb_tree.sh` 把上面四条命令封好了,省得手拼 URL 与鉴权头:
|
||||
|
||||
```bash
|
||||
S=~/.claude/skills/knowledge-base/scripts/kb_tree.sh # 按实际安装路径调整
|
||||
|
||||
$S # 整棵树
|
||||
$S tree -c tech -d 1 # tech 子树,只看第一层
|
||||
$S categories # 分类列表
|
||||
$S counts # 各分类条目数
|
||||
$S search -q goroutine -c tech
|
||||
```
|
||||
|
||||
token 读取顺序:环境变量 `KB_TOKEN` → 同上<E5908C><E4B88A>目录的 `../config.json`。
|
||||
**不要**把 token 写在命令行上(会进 shell 历史与 `ps` 输出)。
|
||||
|
||||
### 核心工作流:先看树,再定向检索
|
||||
|
||||
**别一上来就全文搜索。** 知识库是分层的,先定位分类能显著提高命中率,
|
||||
|
||||
154
assets/skills/knowledge-base/scripts/kb_tree.sh
Executable file
154
assets/skills/knowledge-base/scripts/kb_tree.sh
Executable file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env bash
|
||||
# kbtree 客户端:按分类树检索 HomeAgent 知识库。
|
||||
#
|
||||
# 由 knowledge-base skill 调用(agent 读 SKILL.md 后按需调本脚本)。
|
||||
# 也可人工使用:
|
||||
# kb_tree.sh # 整棵树
|
||||
# kb_tree.sh -c tech -d 1 # tech 子树,只看一层
|
||||
# kb_tree.sh -q goroutine -c tech # 在 tech 子树内检索
|
||||
# kb_tree.sh -l # 列分类
|
||||
#
|
||||
# token 读取顺序:环境变量 KB_TOKEN > 本目录 config.json > 报错。
|
||||
# 故意不放命令行参数:token 会进 shell 历史与 ps 输出。
|
||||
set -euo pipefail
|
||||
|
||||
BASE="${KB_BASE:-http://127.0.0.1:9892}"
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# 读 token
|
||||
# 帮助:-h/--help 必须在解析命令之前判,否则会被当成未知命令
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
-h|--help)
|
||||
echo "用法:"
|
||||
echo " kb_tree.sh [tree|categories|counts|search] [选项]"
|
||||
echo "选项:"
|
||||
echo " -q 关键词 检索词(给了 q 就走 search)"
|
||||
echo " -c 分类 限定分类子树(前缀匹配),如 tech / tech/go"
|
||||
echo " -d 层数 树展开层数,1=只看第一层(懒加载)"
|
||||
echo " -i 0|1 是否带条目详情,默认 1"
|
||||
echo " -l 条数 search 的返回条数,默认 10"
|
||||
echo "环境变量: KB_TOKEN(也可放同目录 config/config.json)"
|
||||
exit 0 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
if [[ -z "${KB_TOKEN:-}" ]]; then
|
||||
CFG="$HERE/../config.json"
|
||||
if [[ -f "$CFG" ]]; then
|
||||
KB_TOKEN="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("token",""))' "$CFG" 2>/dev/null || true)"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "${KB_TOKEN:-}" ]]; then
|
||||
cat >&2 <<'EOF'
|
||||
kbtree: 未找到访问令牌。
|
||||
|
||||
取 token 的办法(其一):
|
||||
1. 若 homed 启动日志里有「token 未配置,本次随机生成」,那行日志附近有 token;
|
||||
2. 若已配置过固定 token,从配置库读:
|
||||
sqlite3 <data_dir>/config.db "SELECT value FROM config_kbtree WHERE key='token'"
|
||||
3. 直接设置:export KB_TOKEN=<token>
|
||||
|
||||
token 未配置时服务会在启动时随机生成,进程重启即失效。
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
auth=(-H "X-API-Key: ${KB_TOKEN}")
|
||||
|
||||
cmd="${1:-tree}"; shift || true
|
||||
query=""; category=""; depth=""; items=""; limit=""
|
||||
while getopts "q:c:d:i:l:h" opt 2>/dev/null; do
|
||||
case "$opt" in
|
||||
q) query="$OPTARG" ;;
|
||||
c) category="$OPTARG" ;;
|
||||
d) depth="$OPTARG" ;;
|
||||
i) items="$OPTARG" ;;
|
||||
l) limit="$OPTARG" ;;
|
||||
h) echo "用法: kb_tree.sh [tree|categories|counts|search] -q 关键词 -c 分类 -d 层数 -i 0|1 -l 条数"; exit 0 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 预检:端口通不通。不通就直说"服务未上线",
|
||||
# 而不是让用户看 curl: (7) Connection refused 后自行猜测。
|
||||
HOSTPORT="${BASE#http://}"; HOSTPORT="${HOSTPORT%%/*}"
|
||||
if ! (exec 3<>"/dev/tcp/${HOSTPORT%%:*}/${HOSTPORT##*:}") 2>/dev/null; then
|
||||
cat >&2 <<EOF
|
||||
kbtree: 连不上 $BASE(端口未监听)。
|
||||
|
||||
最常见原因——**服务还没上线**。kbtree 是 HomeAgent 的内置插件,
|
||||
需要二进制里含它才会启动。若 homed 是在合入该插件之前构建/部署的,
|
||||
就一直没有这个服务。上线后验证:
|
||||
|
||||
systemctl show homeagent -p MainPID --value
|
||||
strings /usr/local/bin/homed | grep -c kbtree # 0 = 二进制里没有
|
||||
|
||||
本机上线步骤(会重启守护进程):
|
||||
sqlite3 <data_dir>/config.db ".backup '<data_dir>/config.db.bak-\$(date +%Y%m%d-%H%M%S)'"
|
||||
install -m 0755 <新二进制> /usr/local/bin/homed # 勿用 cp:会写坏运行中进程的映像
|
||||
systemctl restart homeagent
|
||||
journalctl -u homeagent -f | grep kbtree
|
||||
EOF
|
||||
exit 7
|
||||
fi
|
||||
|
||||
enc() { python3 -c 'import sys,urllib.parse;print(urllib.parse.quote(sys.argv[1]))' "$1"; }
|
||||
|
||||
# kb_call 发请求并把错误翻译成人话。
|
||||
# 不用 curl -f:它只吐 "curl: (22) 404",把服务端给的有用信息(404 会附现有分类)
|
||||
# 全丢了 —— 而那恰恰是排查时最需要的。
|
||||
kb_call() {
|
||||
local url="$1" raw code
|
||||
raw="$(curl -sS -w $'\n%{http_code}' "${auth[@]}" "$url" 2>&1)" || {
|
||||
echo "kbtree: 请求失败: ${raw}" >&2; exit 8
|
||||
}
|
||||
code="$(printf '%s' "$raw" | tail -n1)"
|
||||
body="$(printf '%s' "$raw" | sed '$d')"
|
||||
case "$code" in
|
||||
2*) printf '%s' "$body" | python3 -m json.tool; return 0 ;;
|
||||
401) echo "kbtree: 令牌无效(401)。检查 config/config.json 或 KB_TOKEN 是否与 config_kbtree 表一致。" >&2; exit 3 ;;
|
||||
404) echo "kbtree: 分类不存在(404)。服务端返回的现有分类:" >&2
|
||||
printf '%s' "$body" | KB_BODY="$body" python3 -c '
|
||||
import json, os, sys
|
||||
try:
|
||||
d = json.loads(os.environ.get("KB_BODY",""))
|
||||
print(" " + ", ".join(d.get("categories", [])), file=sys.stderr)
|
||||
except Exception:
|
||||
print(" (无法解析响应体)", file=sys.stderr)
|
||||
'
|
||||
exit 4 ;;
|
||||
*) echo "kbtree: HTTP $code" >&2; printf '%s\n' "$body" >&2; exit 5 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$cmd" in
|
||||
tree|categories|counts|search) ;;
|
||||
*) echo "未知命令: $cmd" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
if [[ "$cmd" == "categories" ]]; then
|
||||
kb_call "$BASE/categories"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$cmd" == "counts" ]]; then
|
||||
kb_call "$BASE/counts"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$cmd" == "search" || -n "$query" ]]; then
|
||||
[[ -n "$query" ]] || { echo "search 需要 -q 关键词" >&2; exit 2; }
|
||||
url="$BASE/search?q=$(enc "$query")"
|
||||
[[ -n "$category" ]] && url="$url&category=$(enc "$category")"
|
||||
[[ -n "$limit" ]] && url="$url&limit=$limit"
|
||||
kb_call "$url"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 默认:树
|
||||
url="$BASE/tree"
|
||||
[[ -n "$category" ]] && url="$url?category=$(enc "$category")"
|
||||
q=""
|
||||
[[ -n "$depth" ]] && q="depth=$depth"
|
||||
[[ -n "$items" ]] && q="${q:+$q&}items=$items"
|
||||
[[ -n "$q" ]] && url="$url?$q"
|
||||
kb_call "$url"
|
||||
Reference in New Issue
Block a user