Files
TencentDB-Agent-Memory/scripts/README.memory-tencentdb-ctl.md
T

343 lines
17 KiB
Markdown
Raw Normal View History

# memory-tencentdb-ctl.sh — memory_tencentdb (TDAI) 运维脚本
> 配合 [`install_hermes_memory_tencentdb.sh`](./install_hermes_memory_tencentdb.sh) 使用。
> 先跑安装脚本部署好插件 + Node 依赖,之后日常的启停 / 配置全部通过 `memory-tencentdb-ctl.sh` 完成。
## 1. 运行模式
脚本有两种模式,**默认是独立模式**,完全不触碰 `~/.hermes`
| 模式 | 激活方式 | 做什么 | 不做什么 |
|---|---|---|---|
| `standalone`(默认) | 无需任何参数 | 启停 Gateway;写 `$TDAI_DATA_DIR/tdai-gateway.json`;日志落 `$TDAI_DATA_DIR/logs/` | 不写 `$HERMES_HOME/env.d/`,不改 `$HERMES_HOME/config.yaml`,不读 hermes 相关 env |
| `hermes` | 命令行追加 `--hermes`,或环境 `MEMORY_TENCENTDB_MODE=hermes` | standalone 的全部 + `config llm` 同步写 `$HERMES_HOME/env.d/memory-tencentdb-llm.sh`;日志落 `$HERMES_HOME/logs/memory_tencentdb/`;开放 `enable-hermes-memory` 子命令 | — |
> **为什么 hermes 模式要多写 env 文件?**
> 因为 hermes 进程会托管式地把 Gateway 以子进程拉起来(supervisor 用 `os.environ.copy()` 传环境),此时 Gateway 读不到 `tdai-gateway.json` 所在的 shell 环境,必须通过 `$HERMES_HOME/env.d/*.sh` 让 hermes 自身 `source` 才能把凭据传进去。独立模式下 Gateway 自己读 JSON,无此需要。
## 2. 路径
> **路径变量约定**:本节及后续示例统一用 `$HERMES_HOME` 指代 hermes 的家目录,**默认 `~/.hermes`**,但你可以通过环境变量覆盖(例如 `export HERMES_HOME=/srv/hermes`),脚本和 hermes 自身都遵守这个变量。
>
> 自 0.4.x 起,所有 tdai 相关数据/代码默认收纳到统一根目录 `$MEMORY_TENCENTDB_ROOT`(默认 `~/.memory-tencentdb`)之下:
>
> - `$TDAI_INSTALL_DIR` 默认 `$MEMORY_TENCENTDB_ROOT/tdai-memory-openclaw-plugin`(即 `~/.memory-tencentdb/tdai-memory-openclaw-plugin`
> - `$TDAI_DATA_DIR` 默认 `$MEMORY_TENCENTDB_ROOT/memory-tdai`(即 `~/.memory-tencentdb/memory-tdai`
>
> 下文出现这些变量时**先 `export` 一份覆盖**,再跑命令即可全局生效。
> 旧版本使用 `~/tdai-memory-openclaw-plugin` 与 `~/memory-tdai``install_hermes_memory_tencentdb.sh` 在升级时会自动迁移这两个旧目录到新位置。
| 路径 | standalone | hermes | 作用 |
|---|---|---|---|
| `$TDAI_INSTALL_DIR` | ✅ | ✅ | 插件源码 + `node_modules` + `src/gateway/server.ts` |
| `$TDAI_DATA_DIR/tdai-gateway.json` | ✅ | ✅ | Gateway 主配置:`llm` / `memory.embedding` / `memory.tcvdb` / `memory.storeBackend`,权限 `0600` |
| `$TDAI_DATA_DIR/logs/` | ✅ 日志 | — | `gateway.stdout.log` / `gateway.stderr.log` / `gateway.pid` |
| `$HERMES_HOME/logs/memory_tencentdb/` | — | ✅ 日志 | 同上,换目录 |
| `$HERMES_HOME/env.d/memory-tencentdb-llm.sh` | — | ✅ | hermes 启动前 `source`,给 supervisor 托管的 Gateway 子进程注入 LLM 凭据 |
| `$HERMES_HOME/config.yaml` | — | ✅ | `enable-hermes-memory` 修改其 `memory.provider` |
| Gateway 监听 | `127.0.0.1:8420` | `127.0.0.1:8420` | 可被 `MEMORY_TENCENTDB_GATEWAY_HOST/PORT` 覆盖 |
所有路径都能用同名环境变量覆盖(再次列出便于对照):`MEMORY_TENCENTDB_ROOT`(默认 `~/.memory-tencentdb`)、`TDAI_INSTALL_DIR`(默认 `$MEMORY_TENCENTDB_ROOT/tdai-memory-openclaw-plugin`)、`TDAI_DATA_DIR`(默认 `$MEMORY_TENCENTDB_ROOT/memory-tdai`)、`HERMES_HOME`(默认 `~/.hermes`)、`MEMORY_TENCENTDB_LOG_DIR``MEMORY_TENCENTDB_GATEWAY_HOST/PORT`
依赖:`bash``python3``node >= 22``npx``lsof``ss`
## 3. 安装 & 调用
脚本随 npm 包发布到 `node_modules/.../scripts/` 下,但**没有**注册为 `bin` 命令。要用全局命令名调用,必须自己做一次软链。
### 3.1 从 npm 包里直接运行(无需任何配置)
```bash
npm install @tencentdb-agent-memory/memory-tencentdb
# 项目内安装,路径可由 npm root 动态算出
"$(npm root)/@tencentdb-agent-memory/memory-tencentdb/scripts/memory-tencentdb-ctl.sh" --help
# 全局安装则用 npm root -g
"$(npm root -g)/@tencentdb-agent-memory/memory-tencentdb/scripts/memory-tencentdb-ctl.sh" --help
```
`npm root` / `npm root -g` 会在所有包管理器(npm / pnpm / yarn)和不同的 prefix 配置下返回正确目录,避免硬编码 `node_modules/` 路径。适合一次性、临时使用的场景。
### 3.2 软链到 PATH(推荐给运维 / 长期使用)
不论脚本来源(git clone 出来的仓库 / `npm install` 装的包 / 自定义部署目录),先把脚本路径**算出来存到一个变量里**,再统一做软链。这样无需关心你把仓库放在 `~/code/``/opt/`、还是别的什么地方。
```bash
# 第一步:定位 memory-tencentdb-ctl.sh 的真实路径(任选一种来源)
# (a) 从 git 仓库(在仓库根目录或任意子目录里执行)
SCRIPT="$(git -C "$(git rev-parse --show-toplevel)" ls-files | \
grep -E 'scripts/memory-tencentdb-ctl\.sh$' | head -1)"
SCRIPT="$(git rev-parse --show-toplevel)/$SCRIPT"
# (b) 从已 npm 全局安装的包
SCRIPT="$(npm root -g)/@tencentdb-agent-memory/memory-tencentdb/scripts/memory-tencentdb-ctl.sh"
# (c) 从项目本地的 node_modules
SCRIPT="$(npm root)/@tencentdb-agent-memory/memory-tencentdb/scripts/memory-tencentdb-ctl.sh"
# (d) 完全手写绝对路径(如部署到非标准位置)
SCRIPT="/opt/tdai/scripts/memory-tencentdb-ctl.sh"
# 第二步:验证路径正确,然后软链
test -f "$SCRIPT" && echo "ok: $SCRIPT" || { echo "not found"; exit 1; }
chmod +x "$SCRIPT"
sudo ln -sf "$SCRIPT" /usr/local/bin/memory-tencentdb-ctl
# 同样的办法把 install_hermes_memory_tencentdb.sh 链接成 install-memory-tencentdb(可选)
INSTALL_SCRIPT="$(dirname "$SCRIPT")/install_hermes_memory_tencentdb.sh"
test -f "$INSTALL_SCRIPT" && {
chmod +x "$INSTALL_SCRIPT"
sudo ln -sf "$INSTALL_SCRIPT" /usr/local/bin/install-memory-tencentdb
}
```
之后直接 `memory-tencentdb-ctl …` / `install-memory-tencentdb …`
> **为什么不直接用 `npm bin` 注册?** 这两个脚本是运维工具而不是包的核心 API,主仓库希望用户**显式**完成 PATH 注册(避免无意中污染全局命令空间,并避免 npm 卸载时静默移除运维入口)。
## 4. 生命周期管理(两种模式通用)
```bash
memory-tencentdb-ctl start # 若 :8420 已占用会直接返回;否则后台 spawn,等待 /health 通过
memory-tencentdb-ctl stop # 先 SIGTERM5s 内未退则 SIGKILL
memory-tencentdb-ctl restart
memory-tencentdb-ctl status # 打印模式、端口、data/log 路径、进程状态
memory-tencentdb-ctl health # GET /health,纯 python3 实现,不要求 curl
memory-tencentdb-ctl logs # tail -f stdout + stderr
memory-tencentdb-ctl logs err 500 # 只看 stderr 最近 500 行
```
启动命令解析顺序:
1. 环境变量 `MEMORY_TENCENTDB_GATEWAY_CMD``install_hermes_memory_tencentdb.sh` 写入 `/etc/profile.d/memory-tencentdb-env.sh` 的那条)。
2. 回退到 `sh -c 'cd $TDAI_INSTALL_DIR && exec npx tsx src/gateway/server.ts'`
启动时会自动 `source` 的环境文件:
- 两种模式:`/etc/profile.d/memory-tencentdb-env.sh`
- 仅 hermes 模式:`/etc/profile.d/hermes-env.sh` 以及 `$HERMES_HOME/env.d/*.sh`
## 5. 配置 LLM / Embedding / VDB
三类凭据统一落到 `$TDAI_DATA_DIR/tdai-gateway.json``0600`,原子写)。**`config llm``--hermes` 模式下会额外写一份 env 文件**Embedding / VDB 从不写 env。
### 5.1 LLM
```bash
# standalone 模式:只写 tdai-gateway.json
memory-tencentdb-ctl config llm \
--api-key "sk-xxxxxxxxxxxx" \
--base-url "https://api.openai.com/v1" \
--model "gpt-4o" \
--restart
# hermes 模式:tdai-gateway.json + $HERMES_HOME/env.d/memory-tencentdb-llm.sh
memory-tencentdb-ctl --hermes config llm \
--api-key "sk-xxxxxxxxxxxx" \
--base-url "https://api.openai.com/v1" \
--model "gpt-4o" \
--restart
```
- JSON 写入点:`$.llm.{baseUrl, apiKey, model}`
- env 文件写入(仅 `--hermes`):`TDAI_LLM_*``MEMORY_TENCENTDB_LLM_*` 别名(Python provider 的 `get_config_schema()` 会读后者)。
### 5.2 Embedding
默认关闭(`provider=none`)。启用远端 OpenAI 兼容服务:
```bash
memory-tencentdb-ctl config embedding \
--provider openai \
--api-key "sk-xxxx" \
--base-url "https://api.openai.com/v1" \
--model "text-embedding-3-small" \
--dimensions 1536 \
--restart
# 关闭 embedding(退化为 BM25/关键词召回)
memory-tencentdb-ctl config embedding --provider none --restart
```
- JSON 写入点:`$.memory.embedding.{provider, baseUrl, apiKey, model, dimensions, enabled, proxyUrl?}`
- `qclaw` provider 额外要求 `--proxy-url`
- 校验规则与 `src/config.ts``parseConfig()` 对齐:`dimensions` 为正整数,非 `none` 必须带 `apiKey/baseUrl/model/dimensions`;缺项直接报错不写半残 JSON。
### 5.3 VectorDBTencent Cloud VDB / tcvdb
```bash
memory-tencentdb-ctl config vdb \
--url "http://xxx-vdb.tencentclb.com:8100" \
--username root \
--api-key "YOUR-VDB-API-KEY" \
--database "openclaw_memory" \
--alias "primary" \
--embedding-model "bge-large-zh" \
--ca-pem "/etc/ssl/vdb-ca.pem" \
--restart
```
- JSON 写入点:`$.memory.tcvdb.{url, username, apiKey, database, alias?, caPemPath?, embeddingModel?}`
- 默认同时把 `$.memory.storeBackend` 切到 `"tcvdb"`;只想预埋配置先不切,加 `--no-set-backend`
- `--ca-pem` 只写路径不复制文件;脚本会校验可读性。
### 5.4 退回本地 SQLite(关闭 VDB 后端)
```bash
# 默认:保留 memory.tcvdb 凭据(方便随时再切回去),仅把 storeBackend 改回 sqlite
memory-tencentdb-ctl config vdb-off --restart
# 同时把腾讯云 VDB 的 url / apiKey / database 等凭据从 JSON 中清掉
memory-tencentdb-ctl config vdb-off --purge-creds --restart
```
- JSON 写入点:把 `$.memory.storeBackend` 设为 `"sqlite"``--purge-creds` 时额外删除整段 `$.memory.tcvdb`
- `$.llm` / `$.memory.embedding` 等其它顶级段**完全保留**,hermes 侧 `memory.provider` **不动**(仍是 `memory_tencentdb`,只是它内部存储退回 sqlite)。
- 配置文件不存在时给出 `warn` 并写入仅含 `{"memory":{"storeBackend":"sqlite"}}` 的最小配置。
-`config vdb` 完全镜像:可与 `--dry-run` / `--restart` 组合使用。
### 5.5 查看当前配置
```bash
memory-tencentdb-ctl config show
```
- 打印 `tdai-gateway.json``apiKey`/`password`/`token` 字段自动脱敏为 `<redacted:NN chars>`
- hermes 模式下额外打印 `$HERMES_HOME/env.d/memory-tencentdb-*.sh`(API key 也会脱敏),可直接贴工单。
## 6. 打通 hermes(仅 `--hermes` 模式)
```bash
memory-tencentdb-ctl --hermes enable-hermes-memory
```
幂等:把 `$HERMES_HOME/config.yaml``memory:` 段的 `provider:` 改成 `memory_tencentdb`(不存在则新增整段)。改完后重启 hermes:
```bash
source "$HERMES_HOME/env.d/memory-tencentdb-llm.sh"
pkill -f hermes-agent || true
hermes
```
> **关于写入策略**:脚本采用"格式保真"双路径,**永不重写整个 YAML**:
>
> 1. **首选**:检测到 [`ruamel.yaml`](https://yaml.readthedocs.io/) 时走 round-trip,完整保留注释、键序、引号、缩进风格(推荐 `pip install --user ruamel.yaml` 享受最佳保真度,**非必装**);
> 2. **降级**:未安装 ruamel 时走最小化原位行编辑——只重写 `provider:` 那一行,缩进直接从同段已有兄弟键的前缀**逐字符拷贝**(零猜测、零格式破坏);
> 3. 若 `memory:` 段不存在,则在文件末尾追加最小段,缩进从文档其它顶级段的子键拓印。
>
> 实测对真实 `~/.hermes/config.yaml` 做 byte-for-byte diff,除 `provider` 值本身外其余字节完全一致。
非 hermes 模式下调用该命令会直接报错退出。
> 想反过来"保留 hermes provider 不变,仅让 TDAI 内部存储退回 sqlite",用 §5.4 的 `config vdb-off` 即可(不需要也**不要**改 hermes 的 `memory.provider`)。
## 7. 典型使用流程
### 场景 AGateway 独立部署(不使用 hermes
```bash
# 1) 安装
# INSTALL_SCRIPT 的取值方式见上文 3.2 节(git rev-parse / npm root / 手填均可)
# 例如从 git 仓库根:INSTALL_SCRIPT="$(git rev-parse --show-toplevel)/scripts/install_hermes_memory_tencentdb.sh"
# 从 npm 全局: INSTALL_SCRIPT="$(npm root -g)/@tencentdb-agent-memory/memory-tencentdb/scripts/install_hermes_memory_tencentdb.sh"
bash "$INSTALL_SCRIPT"
# 2) 只配 Gateway 所需凭据
memory-tencentdb-ctl config llm --api-key "sk-..." --base-url "https://api.openai.com/v1" --model gpt-4o
memory-tencentdb-ctl config embedding --provider openai --api-key "sk-..." --base-url "https://api.openai.com/v1" \
--model text-embedding-3-small --dimensions 1536
memory-tencentdb-ctl config vdb --url "http://xxx:8100" --api-key "..." --database openclaw_memory
# 3) 启动 + 自检
memory-tencentdb-ctl start
memory-tencentdb-ctl status
memory-tencentdb-ctl health # 预期: {"status":"ok",...}
```
### 场景 B:集成 hermes
```bash
# 1) 安装(与场景 A 相同;INSTALL_SCRIPT 由上文 3.2 节算出)
bash "$INSTALL_SCRIPT"
# 2) 全程加 --hermes(或 export MEMORY_TENCENTDB_MODE=hermes 一次)
memory-tencentdb-ctl --hermes config llm --api-key "sk-..." --base-url "https://api.openai.com/v1" --model gpt-4o
memory-tencentdb-ctl --hermes config embedding --provider openai --api-key "sk-..." \
--base-url "https://api.openai.com/v1" \
--model text-embedding-3-small --dimensions 1536
memory-tencentdb-ctl --hermes config vdb --url "http://xxx:8100" --api-key "..." --database openclaw_memory
# 3) 启动 Gateway(通常由 hermes supervisor 托管,这里是手动兜底)
memory-tencentdb-ctl --hermes start
memory-tencentdb-ctl --hermes status
# 4) 在 hermes config 里启用 provider,并重启 hermes
memory-tencentdb-ctl --hermes enable-hermes-memory
source "$HERMES_HOME/env.d/memory-tencentdb-llm.sh"
pkill -f hermes-agent ; hermes
```
如果嫌 `--hermes` 每次都要带,可以:
```bash
export MEMORY_TENCENTDB_MODE=hermes
```
之后所有调用自动切到 hermes 模式,命令行无需再加 `--hermes`
### 场景 C:临时把 TDAI 的存储退回 sqlite(保留 hermes 集成)
适用于 VDB 不可达 / 排障 / 离线开发等场景:希望 hermes 端 `memory.provider` 仍是 `memory_tencentdb`,但让 Gateway 改用本地 SQLite 落盘。
```bash
# (A) 默认:保留 memory.tcvdb 凭据,仅把 storeBackend 切回 sqlite
memory-tencentdb-ctl config vdb-off --restart
# (B) 排障结束想切回 vdb:当前需要重新跑一次 config vdb(必填项需重新提供,
# 即使 JSON 里凭据还在;脚本是基于必填校验的"重新声明"语义,不是 toggle
memory-tencentdb-ctl config vdb \
--url "http://xxx-vdb.tencentclb.com:8100" \
--api-key "<你的 KEY>" \
--database "openclaw_memory" \
--restart
# (C) 彻底放弃 vdb:清掉凭据
memory-tencentdb-ctl config vdb-off --purge-creds --restart
```
> 之所以 (B) 不提供"零参数 vdb-on",是因为原 `config vdb` 子命令把 `--url/--api-key/--database` 设为强校验,避免用户拼装出半残配置;如果你希望把"已存的凭据重新激活"也做成单命令,告诉维护者补一个 `config vdb-on` 即可(实现方式与 `vdb-off` 完全镜像)。
> **不要**为了"切回 sqlite"去改 `~/.hermes/config.yaml` 的 `memory.provider`hermes 看到的依然是 `memory_tencentdb` provider,存储后端切换是 Gateway 内部的事,对 hermes 完全透明。
## 8. 全局选项 & 调试技巧
- 所有写操作支持 `--dry-run`(放在命令最前),会打印将要写入的内容但不落盘:
```bash
memory-tencentdb-ctl --dry-run config llm --api-key k --base-url https://x --model m
```
- 敏感文件权限一律 `0600``env.d/memory-tencentdb-llm.sh` 含明文 API key**不要** commit。
- 启动失败:`memory-tencentdb-ctl logs err 200` 查看 stderr;手动前台跑一遍更容易看到报错:
```bash
cd "$TDAI_INSTALL_DIR" && npx tsx src/gateway/server.ts
```
- 端口冲突:`MEMORY_TENCENTDB_GATEWAY_PORT=18420 memory-tencentdb-ctl restart`。
- 验证 hermes 有没有吃到新 envhermes 模式):
```bash
tr '\0' '\n' < /proc/$(pgrep -n hermes-agent)/environ | grep -E 'TDAI_|MEMORY_TENCENTDB_'
```
## 9. 退出码
| 码 | 含义 |
|---|---|
| 0 | 成功 |
| 1 | 参数错误 / 业务校验失败(如 `--base-url` 非 http(s);在 standalone 下调 hermes 专属命令) |
| 2 | 写盘失败(磁盘满、权限不足等) |
| 127 | 依赖缺失(`python3` / `node` / `npx` |
---
要封装成 systemd unit,基于 `memory-tencentdb-ctl start` / `memory-tencentdb-ctl stop` 写 `Type=forking` 的 service 即可(Gateway 是无状态 HTTP sidecar,不依赖 systemd readiness 协议)。