feat(hindsight): 新增 Hindsight 方案三部署 stack

采用 DB+Hindsight 分离部署方案:
- pgvector/pgvector:pg18 向量数据库
- ghcr.nju.edu.cn/vectorize-io/hindsight:latest 应用
- 0.0.0.0:8888/9999 端口绑定
- ~/hindsight/pgdata bind mount (避免 9P fsync 性能)
- HF_CACHE_DIR 参数化,适配非 WSL 环境
- 每日 pg_dump 备份,7 天保留

参考 Obsidian 知识库 DevOps/04-AI工具/Hindsight部署指南.md
This commit is contained in:
2026-06-08 00:03:53 +08:00
parent b5fdc1682b
commit 9c83f6e2e8
4 changed files with 303 additions and 0 deletions

25
hindsight/backup.job Normal file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# ============================================================
# Hindsight 备份任务(每日 02:30 跑cron 部署参考 crontab/
# - 热备份docker exec pg_dump 落盘到 bind 挂载的 backups/
# - 保留 7 天的 .sql.gz
# ============================================================
set -euo pipefail
BACKUP_DIR="/home/geng/hindsight/backups"
KEEP_DAYS=7
TS=$(date +%Y%m%d_%H%M%S)
FNAME="hindsight_db_${TS}.sql.gz"
mkdir -p "${BACKUP_DIR}"
docker exec hindsight-db pg_dump \
-U hindsight_user \
-d hindsight_db \
--no-owner --no-privileges \
| gzip > "${BACKUP_DIR}/${FNAME}"
# 清理超过 KEEP_DAYS 天的旧备份
find "${BACKUP_DIR}" -name "hindsight_db_*.sql.gz" -mtime +${KEEP_DAYS} -delete
echo "[backup] ok: ${FNAME} ($(du -h "${BACKUP_DIR}/${FNAME}" | cut -f1))"

39
hindsight/env.cfg.example Normal file
View File

@@ -0,0 +1,39 @@
# ============================================================
# Hindsight 部署 — 公共环境变量(不含敏感信息)
# 复制为 env.cfg 后填入真实值env.cfg 已被 .gitignore 忽略
# ============================================================
# 镜像版本
HINDSIGHT_VERSION=latest
HINDSIGHT_DB_VERSION=18
# 镜像源
HINDSIGHT_DB_IMAGE=pgvector/pgvector
HINDSIGHT_APP_IMAGE=ghcr.nju.edu.cn/vectorize-io/hindsight
# 数据库账号/库名
HINDSIGHT_DB_USER=hindsight_user
HINDSIGHT_DB_NAME=hindsight_db
# 宿主机数据卷路径(**必须 WSL/Linux ext4 原生 fs**,不能放 /mnt/9P
# bind 挂载 PostgreSQL 数据;放在 ~/hindsight/pgdata 而非 /mnt/d/mydata/
# 因为 9P drvfs 的 fsync 不可靠,会导致 PG 数据损坏。
Volumes_Path=/home/geng/hindsight
# 服务端口(宿主机:容器)
HINDSIGHT_API_PORT=8888
HINDSIGHT_ADMIN_PORT=9999
# LLMMiniMax OpenAI-compatible 协议)
HINDSIGHT_API_LLM_PROVIDER=MiniMax-CN
HINDSIGHT_API_LLM_MODEL=MiniMax-M3
HINDSIGHT_API_LLM_BASE_URL=https://api.minimaxi.com/v1
# 日志
HINDSIGHT_API_LOG_LEVEL=info
# ============================================================
# 敏感值必填env.cfg 不提交)— 在 .gitignore 已忽略
# ============================================================
# HINDSIGHT_DB_PASSWORD=<强密码>
# HINDSIGHT_API_LLM_API_KEY=<你的 MiniMax key>

168
hindsight/readme.md Normal file
View File

@@ -0,0 +1,168 @@
# Hindsight 部署栈
[vectorize-io/hindsight](https://github.com/vectorize-io/hindsight) 是一个面向 LLM Agent 的长期记忆后端,采用 PostgreSQL/pgvector 存储。Hermes Agent 用它做跨会话长期记忆。
本目录是 **方案三DB + Hindsight 分离部署**`/home/geng/hindsight/` 下的 `docker-compose.yaml` + `.env` + `pgdata/`)迁移到 `deploy.stack` 仓库的版本。
## 目录结构
| 文件 | 说明 |
|------|------|
| `stack.yml` | Docker Compose 主文件2 服务db + hindsight |
| `env.cfg.example` | 公共环境变量模板(不含敏感信息,可提交) |
| `env.cfg` | **敏感配置gitignore不提交** — 实际部署时从 example 复制后填密码/API Key |
| `backup.job` | 每日 `pg_dump` 热备份脚本,保留 7 天 |
| `readme.md` | 本文档 |
## 架构
```
┌──────────────────────┐ 5432 ┌──────────────────────┐
│ hindsight-app 容器 │ ────────────► │ hindsight-db 容器 │
│ (ghcr.nju.edu.cn/ │ │ (pgvector/pgvector │
│ vectorize-io/ │ :8888 API │ :pg18) │
│ hindsight) │ :9999 Admin │ │
└──────────────────────┘ └──────────────────────┘
│ │
▼ bind mount ▼ bind mount
~/.cache/huggingface /home/geng/hindsight/pgdata
(BGE + ms-marco 复用) (PG 数据,WSL 原生 fs)
```
## 部署步骤
### 首次部署
```bash
# 1. 准备数据目录WSL/Linux 原生 fs不能放 /mnt/9P
sudo mkdir -pv /home/geng/hindsight/pgdata /home/geng/hindsight/backups
sudo chown -R 999:999 /home/geng/hindsight/pgdata
# 2. 复制 env 模板并填入真实值
cp env.cfg.example env.cfg
$EDITOR env.cfg
# 必填HINDSIGHT_DB_PASSWORD, HINDSIGHT_API_LLM_API_KEY
# 3. 拉镜像
docker compose --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml pull
# 4. 启动
docker compose -p hindsight --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml up -d
```
### 验证
```bash
# 容器状态
docker ps -f name=hindsight
# DB 启动正常(首次启动会建表)
docker exec -it hindsight-db psql -U hindsight_user -d hindsight_db -c '\dt'
# 端口监听
ss -tlnp | grep -E '8888|9999'
# API 健康检查
curl -s http://localhost:8888/health
```
### 停止/重启
```bash
# 停止(保留数据)
docker compose -p hindsight --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml stop
# 完全销毁(**数据不删**bind 挂载保留在宿主机)
docker compose -p hindsight --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml down
# 重启
docker compose -p hindsight --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml restart
```
## 关键设计决策
| 决策点 | 决定 | 原因 |
|--------|------|------|
| 部署位置 | `/home/geng/hindsight/`WSL 原生 fs | `/mnt/d/mydata/` 是 9P drvfsPG 在 9P 上 fsync 不可靠会损坏数据Hindsight 跟随 Hermes 配置放 `~/` 下 |
| 数据卷方案 | bind 挂载到 `~/hindsight/pgdata` | 直观、可直接 `rsync`/`pg_dump`、跨机迁移用 `tar` 整个目录即可(用户决策,覆盖默认命名卷) |
| 端口绑定 | 0.0.0.0:8888 / 0.0.0.0:9999 | PVE LAN 上其他 VM 也可能访问(用户决策) |
| 镜像源 | `ghcr.nju.edu.cn/vectorize-io/hindsight` | 南京大学 ghcr 镜像,国内拉得快(用户偏好) |
| LLM | MiniMax-M3 via api.minimaxi.com | 用 MiniMax 的 OpenAI-compatible 协议 |
| 嵌入模型 | 容器内自带 BGE-small-en-v1.5 | 不需要额外配HF 缓存 bind 复用免重下 |
| 旧数据迁移 | 见 `docs-hermes-Hindsight-记忆系统部署指南.md` 决策表 | 走 Azip 导入) 或 B重置新 DB 路径 |
## 备份与恢复
### 自动备份
`backup.job``pg_dump` 热备份脚本(不停服),落盘到 bind 挂载的 `backups/`。接入 cron
```bash
# /etc/cron.d/hindsight-backup 或 crontab -e
30 2 * * * /mnt/d/mydata/cnphpbb/deploy.stack/hindsight/backup.job >> /var/log/hindsight-backup.log 2>&1
```
或参考 `crontab/` 目录的统一任务管理方式(`shell/up.bash` 会处理 `chmod +x`)。
### 手动备份
```bash
# 热备份(推荐)
docker exec hindsight-db pg_dump -U hindsight_user -d hindsight_db | gzip > ~/hindsight/backups/manual_$(date +%Y%m%d).sql.gz
# 冷备份(停服时,更彻底)
docker compose -p hindsight -f ./hindsight/stack.yml stop
sudo rsync -a /home/geng/hindsight/pgdata/ /home/geng/hindsight/backups/pgdata-cold/
docker compose -p hindsight -f ./hindsight/stack.yml start
```
### 恢复
```bash
# 从 pg_dump 恢复
gunzip -c ~/hindsight/backups/hindsight_db_20260607_023000.sql.gz \
| docker exec -i hindsight-db psql -U hindsight_user -d hindsight_db
# 从冷备份恢复(停服 + 替换 bind 目录)
docker compose -p hindsight -f ./hindsight/stack.yml down
sudo rm -rf /home/geng/hindsight/pgdata/*
sudo rsync -a /home/geng/hindsight/backups/pgdata-cold/ /home/geng/hindsight/pgdata/
sudo chown -R 999:999 /home/geng/hindsight/pgdata
docker compose -p hindsight --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml up -d
```
## 故障排查
| 症状 | 排查命令 |
|------|----------|
| 容器起不来 | `docker logs -f hindsight-app` / `docker logs -f hindsight-db` |
| DB 连不上 | `docker exec -it hindsight-db psql -U hindsight_user -d hindsight_db` |
| 慢查询 | 在 psql 里 `SELECT * FROM pg_stat_activity;` |
| 端口冲突 | `ss -tlnp \| grep -E '8888\|9999'` |
| 端口未对外 | `ss -tlnp` 看是不是只监听 `127.0.0.1`,确认 `ports:` 没加 IP 前缀 |
| BGE 模型重下 | 容器内是否有 `HF_HUB_OFFLINE=1` 和 bind 挂的 HF 缓存 |
| glibc 错误 | 0.7.2 内嵌 pg0 需 glibc 2.38,方案三已用独立容器避开 |
## 与 Hermes 集成
Hermes plugin 通过 HTTP 调用本服务的 API`localhost:8888`),不直连 DB。配置在 `~/.hermes/config.yaml`
```yaml
memory:
provider: hindsight
hindsight:
api_url: http://localhost:8888
bank_id: hermes
memory_mode: hybrid
auto_recall: true
auto_retain: true
retain_async: true
```
切换命令:`hermes config set memory.provider hindsight`
## 相关文档
- `~/Obsibian/MyNotes/DevOps/04-AI工具/docs-hermes-Hindsight-记忆系统部署指南.md` — 完整部署指南700+ 行,含方案对比、旧数据迁移决策表)
- 仓库根 `AGENTS.md``deploy.stack` 项目规范
- `crontab/` — 定时任务集成参考

71
hindsight/stack.yml Normal file
View File

@@ -0,0 +1,71 @@
# Hindsight 部署栈
# ============================================================
# 部署前准备(仅首次):
# mkdir -pv /home/geng/hindsight/pgdata /home/geng/hindsight/backups
# sudo chown -R 999:999 /home/geng/hindsight/pgdata
# cp env.cfg.example env.cfg && $EDITOR env.cfg # 填入密码/API Key
#
# pull:: docker compose --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml pull
# RUN:: docker compose -p hindsight --env-file ./hindsight/env.cfg -f ./hindsight/stack.yml up -d
# disc::
# - DB 数据 bind 挂到 /home/geng/hindsight/pgdataWSL 原生 fs,避 9P fsync 风险)
# - 复用宿主 HF 缓存bge + ms-marco 不重下)
# - 镜像走南京大学 ghcr 镜像,国内拉得快
# - 端口 8888=API, 9999=Admin UI,绑定 0.0.0.0 供 LAN VM 访问
# ============================================================
services:
db:
image: ${HINDSIGHT_DB_IMAGE}:pg${HINDSIGHT_DB_VERSION:-18}
container_name: hindsight-db
restart: unless-stopped
environment:
- TZ=Asia/Shanghai
- POSTGRES_USER=${HINDSIGHT_DB_USER:-hindsight_user}
- POSTGRES_PASSWORD=${HINDSIGHT_DB_PASSWORD:?set HINDSIGHT_DB_PASSWORD}
- POSTGRES_DB=${HINDSIGHT_DB_NAME:-hindsight_db}
- POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- ${Volumes_Path}/pgdata:/var/lib/postgresql/${HINDSIGHT_DB_VERSION:-18}/docker
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${HINDSIGHT_DB_USER:-hindsight_user} -d ${HINDSIGHT_DB_NAME:-hindsight_db}"]
interval: 10s
timeout: 5s
retries: 10
networks:
- hindsight-net
hindsight:
image: ${HINDSIGHT_APP_IMAGE}:${HINDSIGHT_VERSION:-latest}
container_name: hindsight-app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "${HINDSIGHT_API_PORT:-8888}:8888"
- "${HINDSIGHT_ADMIN_PORT:-9999}:9999"
environment:
- TZ=Asia/Shanghai
- HINDSIGHT_API_LLM_PROVIDER=${HINDSIGHT_API_LLM_PROVIDER}
- HINDSIGHT_API_LLM_API_KEY=${HINDSIGHT_API_LLM_API_KEY:?set HINDSIGHT_API_LLM_API_KEY}
- HINDSIGHT_API_LLM_MODEL=${HINDSIGHT_API_LLM_MODEL}
- HINDSIGHT_API_LLM_BASE_URL=${HINDSIGHT_API_LLM_BASE_URL}
- HINDSIGHT_API_DATABASE_URL=postgresql://${HINDSIGHT_DB_USER}:${HINDSIGHT_DB_PASSWORD}@db:5432/${HINDSIGHT_DB_NAME}
- HINDSIGHT_API_LOG_LEVEL=${HINDSIGHT_API_LOG_LEVEL:-info}
- HF_HUB_OFFLINE=1
- TRANSFORMERS_OFFLINE=1
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
# 复用宿主 HF 缓存,bge + ms-marco 不重下
- /home/geng/.cache/huggingface:/home/hindsight/.cache/huggingface
- ${Volumes_Path}/backups:/home/hindsight/backups
networks:
- hindsight-net
networks:
hindsight-net:
driver: bridge