Files
TencentDB-Agent-Memory/scripts/README.memory-tencentdb-ctl.md
2026-05-29 17:51:28 +08:00

343 lines
17 KiB
Markdown
Raw Permalink 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.
# memory-tencentdb-ctl.sh — memory_tencentdb运维脚本
> 配合 [`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 协议)。