配合
install_hermes_memory_tencentdb.sh使用。 先跑安装脚本部署好插件 + Node 依赖,之后日常的启停 / 配置全部通过memory-tencentdb-ctl.sh完成。
脚本有两种模式,默认是独立模式,完全不触碰 ~/.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,无此需要。
路径变量约定:本节及后续示例统一用
$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。
脚本随 npm 包发布到 node_modules/.../scripts/ 下,但没有注册为 bin 命令。要用全局命令名调用,必须自己做一次软链。
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" --helpnpm root / npm root -g 会在所有包管理器(npm / pnpm / yarn)和不同的 prefix 配置下返回正确目录,避免硬编码 node_modules/ 路径。适合一次性、临时使用的场景。
不论脚本来源(git clone 出来的仓库 / npm install 装的包 / 自定义部署目录),先把脚本路径算出来存到一个变量里,再统一做软链。这样无需关心你把仓库放在 ~/code/、/opt/、还是别的什么地方。
# 第一步:定位 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 卸载时静默移除运维入口)。
memory-tencentdb-ctl start # 若 :8420 已占用会直接返回;否则后台 spawn,等待 /health 通过
memory-tencentdb-ctl stop # 先 SIGTERM,5s 内未退则 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 行启动命令解析顺序:
- 环境变量
MEMORY_TENCENTDB_GATEWAY_CMD(install_hermes_memory_tencentdb.sh写入/etc/profile.d/memory-tencentdb-env.sh的那条)。 - 回退到
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
三类凭据统一落到 $TDAI_DATA_DIR/tdai-gateway.json(0600,原子写)。config llm 在 --hermes 模式下会额外写一份 env 文件;Embedding / VDB 从不写 env。
# 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()会读后者)。
默认关闭(provider=none)。启用远端 OpenAI 兼容服务:
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?}。 qclawprovider 额外要求--proxy-url。- 校验规则与
src/config.ts的parseConfig()对齐:dimensions为正整数,非none必须带apiKey/baseUrl/model/dimensions;缺项直接报错不写半残 JSON。
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只写路径不复制文件;脚本会校验可读性。
# 默认:保留 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组合使用。
memory-tencentdb-ctl config show- 打印
tdai-gateway.json,apiKey/password/token字段自动脱敏为<redacted:NN chars>。 - hermes 模式下额外打印
$HERMES_HOME/env.d/memory-tencentdb-*.sh(API key 也会脱敏),可直接贴工单。
memory-tencentdb-ctl --hermes enable-hermes-memory幂等:把 $HERMES_HOME/config.yaml 的 memory: 段的 provider: 改成 memory_tencentdb(不存在则新增整段)。改完后重启 hermes:
source "$HERMES_HOME/env.d/memory-tencentdb-llm.sh"
pkill -f hermes-agent || true
hermes关于写入策略:脚本采用"格式保真"双路径,永不重写整个 YAML:
- 首选:检测到
ruamel.yaml时走 round-trip,完整保留注释、键序、引号、缩进风格(推荐pip install --user ruamel.yaml享受最佳保真度,非必装);- 降级:未安装 ruamel 时走最小化原位行编辑——只重写
provider:那一行,缩进直接从同段已有兄弟键的前缀逐字符拷贝(零猜测、零格式破坏);- 若
memory:段不存在,则在文件末尾追加最小段,缩进从文档其它顶级段的子键拓印。实测对真实
~/.hermes/config.yaml做 byte-for-byte diff,除provider值本身外其余字节完全一致。
非 hermes 模式下调用该命令会直接报错退出。
想反过来"保留 hermes provider 不变,仅让 TDAI 内部存储退回 sqlite",用 §5.4 的
config vdb-off即可(不需要也不要改 hermes 的memory.provider)。
# 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",...}# 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 每次都要带,可以:
export MEMORY_TENCENTDB_MODE=hermes之后所有调用自动切到 hermes 模式,命令行无需再加 --hermes。
适用于 VDB 不可达 / 排障 / 离线开发等场景:希望 hermes 端 memory.provider 仍是 memory_tencentdb,但让 Gateway 改用本地 SQLite 落盘。
# (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_tencentdbprovider,存储后端切换是 Gateway 内部的事,对 hermes 完全透明。
- 所有写操作支持
--dry-run(放在命令最前),会打印将要写入的内容但不落盘: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;手动前台跑一遍更容易看到报错:cd "$TDAI_INSTALL_DIR" && npx tsx src/gateway/server.ts
- 端口冲突:
MEMORY_TENCENTDB_GATEWAY_PORT=18420 memory-tencentdb-ctl restart。 - 验证 hermes 有没有吃到新 env(hermes 模式):
tr '\0' '\n' < /proc/$(pgrep -n hermes-agent)/environ | grep -E 'TDAI_|MEMORY_TENCENTDB_'
| 码 | 含义 |
|---|---|
| 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 协议)。