收起左侧

让你的agent永不失忆! Hermes + Hindsight 飞牛NAS 纯图形界面部署指南

8
回复
4542
查看
[ 复制链接 ]

1

主题

5

回帖

0

牛值

江湖小虾

2026-5-13 10:50:11 显示全部楼层 阅读模式
🚀 Hermes + Hindsight 记忆系统
[size=1.2]飞牛NAS 纯图形界面部署指南(小白专用)
📖 目录
1. 系统简介
一键部署 AI 助手 + 长期记忆大脑,对接微信/QQ 等消息平台。
  • [color=var(--accent)][size=0.8em]Hermes Agent AI 助手核心,调用 DeepSeek 大模型对话,并自动记忆你的偏好。
  • [color=var(--accent)][size=0.8em]Hindsight 记忆引擎,自动提取、整理对话记忆,支持语义搜索。
架构很简单:微信/QQ → Hermes ↔ Hindsight 记忆库
Hindsight 的长期记忆功能必须使用 Chat 模型(如 deepseek-v4-pro),绝对不能填纯 Embedding 模型。

2. 前期准备
项目
说明
飞牛NAS确保已安装 Docker 应用(系统自带或应用商店安装)
可用空间建议至少剩余 20 GB
内存至少 4 GB(推荐 8 GB 以上)
DeepSeek API Key点击注册,在“API Keys”页面创建并复制密钥
一台电脑用于创建配置文件并上传到 NAS


3. 文件目录搭建(纯鼠标操作)
打开飞牛NAS的“文件管理”,进入你的 Docker 工作目录(例如 /vol1/1000/Docker),新建文件夹并命名为 hermes-hindsight。然后进入该文件夹,再新建以下四个子文件夹:
datahindsight_datapostgres_databackups
最终结构如下(你只需确保这几个文件夹存在即可):
/vol1/1000/Docker/hermes-hindsight/**── data/**── hindsight_data/**── postgres_data/**── backups/💡 路径可以自定义,但后续所有操作都要使用你设定的路径,本指南以 /vol1/1000/Docker/hermes-hindsight 为例。

4. 本地创建必要文件并上传⚠️ 重要说明:飞牛NAS 文件管理器无法直接新建 .sh、.yml 等格式的脚本文件,**所有配置文件必须在你的电脑上创建,再通过文件管理上传到 NAS 的对应目录**。同时,请务必使用专业文本编辑器(如 VS Code、Notepad++)并保存为 UTF-8 无 BOM 编码,否则可能导致脚本执行失败或中文乱码。
4.1 创建启动脚本 start-hermes.sh
第一步:在你的电脑上新建一个文本文档,重命名为 start-hermes.sh(注意扩展名是 .sh,不是 .txt)。
第二步:用编辑器打开,粘贴以下内容,并确保编码为 UTF-8 无 BOM:
#!/bin/bash# Hermes 启动后自动维护脚本set -eecho ">>> 正在执行启动后维护..."# 修复可能被 root 占用的技能文件find /opt/data/skills -user root -exec chown hermes:hermes {} \; 2>/dev/null || true# 安装记忆客户端依赖PACKAGES_DIR="/opt/data/.python_packages"mkdir -p "$PACKAGES_DIR"if [ ! -d "$PACKAGES_DIR/hindsight_client" ]; then    echo ">>> 安装 hindsight-client..."    pip install --target="$PACKAGES_DIR" hindsight-clientelse    echo ">>> 客户端已存在,跳过安装。"fiecho ">>> 维护完成。"
第三步:上传文件。打开飞牛文件管理,进入 /vol1/1000/Docker/hermes-hindsight/,点击上传,选择刚保存的 start-hermes.sh。
第四步:设置执行权限。文件上传后,右键该文件 → 属性 → 权限,勾选“执行”复选框,或者将权限数值设为 755。

4.2 创建 Docker Compose 配置文件
第一步:在电脑上新建文本文档,重命名为 docker-compose.yml(注意扩展名是 .yml,不是 .txt)。
第二步:用编辑器打开,粘贴以下完整内容,并确保编码为 UTF-8 无 BOM:
services:  # ========== Hermes AI 核心 ==========  hermes:    image: hermes-agent-custom:latest    container_name: hermes    restart: unless-stopped    network_mode: host    dns:      - 114.114.114.114      - 223.5.5.5    stdin_open: true    tty: true    user: "1000:1000"    volumes:      - ./data:/opt/data      - ./start-hermes.sh:/opt/hermes/start-hermes.sh:ro    environment:      - TZ=Asia/Shanghai      - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}      - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1      - DEEPSEEK_MODEL=deepseek-v4-pro      - PYTHONPATH=/opt/data/.python_packages      - HERMES_POST_START=/bin/bash /opt/hermes/start-hermes.sh    deploy:      resources:        limits:          memory: 4G          cpus: "2.0"  # ========== 管理面板 ==========  hermes-dashboard:    image: hermes-agent-custom:latest    container_name: hermes-dashboard    restart: unless-stopped    command: dashboard --host 0.0.0.0 --insecure    network_mode: host    user: "1000:1000"    volumes:      - ./data:/opt/data    environment:      - GATEWAY_HEALTH_URL=http://127.0.0.1:8642      - TZ=Asia/Shanghai      - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}      - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1      - DEEPSEEK_MODEL=deepseek-v4-pro    depends_on:      - hermes  # ========== 记忆大脑 ==========  hindsight:    image: ghcr.io/vectorize-io/hindsight:latest    container_name: hindsight    restart: unless-stopped    networks:      - internal    ports:      - "127.0.0.1:8888:8888"      - "127.0.0.1:9999:9999"    environment:      HINDSIGHT_DB_HOST: hindsight-postgres      HINDSIGHT_DB_PORT: "5432"      HINDSIGHT_DB_NAME: hindsight      HINDSIGHT_DB_USER: hindsight      HINDSIGHT_DB_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}      HINDSIGHT_DB_BACKEND: external      HINDSIGHT_API_LLM_PROVIDER: openai      HINDSIGHT_API_LLM_API_KEY: ${DEEPSEEK_API_KEY}      HINDSIGHT_API_LLM_MODEL: deepseek-v4-pro      HINDSIGHT_API_LLM_BASE_URL: https://api.deepseek.com/v1      API_BASE_URL: http://127.0.0.1:8888      HINDSIGHT_CORS_ORIGINS: "http://localhost:9999,http://127.0.0.1:9999"      HINDSIGHT_API_LISTEN_HOST: 0.0.0.0      HF_ENDPOINT: https://hf-mirror.com    volumes:      - ./hindsight_data:/home/hindsight/.pg0    depends_on:      - hindsight-postgres  # ========== 数据库 ==========  hindsight-postgres:    image: pgvector/pgvector:pg16    container_name: hindsight-postgres    restart: unless-stopped    networks:      - internal    environment:      POSTGRES_USER: hindsight      POSTGRES_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}      POSTGRES_DB: hindsight    volumes:      - ./postgres_data:/var/lib/postgresql/datanetworks:  internal:    driver: bridge
第三步:上传文件。将 docker-compose.yml 上传到 NAS 的 /vol1/1000/Docker/hermes-hindsight/ 目录下。
⚠️ 关于镜像标签:我们使用了 :latest 标签,这能让你随时获得最新版,但也可能包含未充分测试的变更。如果你追求绝对稳定,可将 latest 手动改为具体版本号(例如 :v0.13.0 和 :0.6)。后续升级章节会教你如何安全切换。

5. 设置目录权限
容器内的 AI 用户 UID 是 1000,因此必须将 data 文件夹的拥有者改为 1000。在飞牛文件管理器中,右键点击 data 文件夹 → 属性 → 权限,将“所有者”和“组”都改为 1000,并勾选“应用到子文件夹及文件”。
如果文件管理器无法直接修改数字 UID,可以打开飞牛的“终端”应用,执行下面这一条命令(复制粘贴回车即可):
sudo chown -R 1000:1000 /vol1/1000/Docker/hermes-hindsight/data⚠️ 千万不要修改 hindsight_data 和 postgres_data 的权限!

6. 在 Docker 中部署应用
  • 打开飞牛NAS的 Docker 管理界面,找到“堆栈”或“应用”菜单,点击“添加堆栈”。
  • 命名堆栈为 hermes-hindsight,然后在配置框中将刚才创建的 docker-compose.yml 内容全选复制进去。
  • 设置环境变量(密钥填在这里最安全)。在“环境变量”区域添加两行:
    DEEPSEEK_API_KEY=你的DeepSeek密钥
    HINDSIGHT_DB_PASSWORD=数据库密码,可自定,默认ChangeMe123!
  • 存储卷映射部分检查是否已自动识别当前目录下的 data、hindsight_data、postgres_data 以及 start-hermes.sh,如没有自动识别,手动添加上面 compose 中对应的映射关系。
  • 点击部署,系统将自动拉取镜像并创建所有容器。等待 2~3 分钟即可。
7. 启动与验证
部署成功后,在 Docker 容器列表中应看到四个容器均显示“运行中”。然后进行简单验证:
  • 记忆引擎健康检查:浏览器访问 http://你的NAS-IP:8888/health,看到 {"status":"healthy"} 即正常。
  • AI 面板:访问 http://你的NAS-IP:9119,如果出现管理界面,说明 Hermes 已启动。
  • 日志检查:在 Docker 界面点击 hermes 容器,查看日志,没有报错即可。

8. 日常维护(图形化)
  • 查看运行状态:在 Docker 界面直接观察容器状态。
  • 重启服务:选中容器,点击“重启”。
  • 查看日志:点击容器名,切换到“日志”标签页。
  • 清理无用镜像:Docker 设置里通常有“清理”功能,可释放空间。
  • 手动整理记忆:如果感觉记忆积压,可用浏览器访问以下地址触发合并:
    http://你的NAS-IP:8888/v1/default/banks/hermes/consolidate (会返回 JSON 结果)

9. 备份与恢复
备份:在文件管理器中,直接将 /vol1/1000/Docker/hermes-hindsight 整个文件夹复制到另一块硬盘或 NAS 其他目录即可。建议先停止所有容器再复制。
恢复:将备份的文件夹放回原路径,进入 Docker 堆栈页面,重新部署同一份 compose 文件(或直接启动已有容器),系统会自动识别原有数据。
💡 更优雅的自动备份:你可以将整个项目文件夹设置为飞牛自带的“备份任务”源目录,定时备份到远程或外接硬盘。

10. 升级指南
因为使用了 :latest 标签,升级变得异常简单:
  • 在 Docker 界面选中你的堆栈,点击“重新创建”。
  • 勾选“拉取最新镜像”或“强制拉取”。
  • 点击执行,系统会自动下载新版镜像并重建容器。
如果你之前锁定了版本号,只需在 compose 中修改标签为 :latest 后再执行上述操作。
回退旧版:如果新版出现异常,把 compose 中的标签改回上一个稳定版本(如 :v0.13.0 和 :0.6),然后“重新创建”即可。记得先把数据备份一下。

11. 常见问题排查❶ 记忆引擎报“LLM API key required”
原因:部署时环境变量 DEEPSEEK_API_KEY 未正确填写。
解决:在 Docker 堆栈编辑页面,检查环境变量键名是否完全一致,密钥是否正确。

❷ Hermes 无法启动,日志提示“unable to open database file”
原因:data 文件夹权限不是 1000:1000。
解决:按第 5 节重新设置权限,然后重启容器。

❸ 记忆提取报 422 错误或超时
原因:你填写的模型是纯 Embedding 模型,不支持对话。
解决:确保环境变量 HINDSIGHT_API_LLM_MODEL 为 deepseek-v4-pro 或其他 Chat 模型。

❹ 镜像拉取总是超时
原因:国内访问 ghcr.io 不稳定。
解决:在 Docker 设置中配置国内镜像加速器,或请朋友下载离线镜像包(.tar)后,在飞牛 Docker 界面中“导入”。

❺ 升级后容器启动异常
原因:最新版可能有兼容问题。
解决:临时回退:将 compose 中的 :latest 改成之前的版本号,然后“重新创建”。确定稳定后再考虑是否追新。

❻ 脚本上传后无法执行或中文乱码
原因:文件编码不正确(如使用了系统默认的 GBK 编码),或者文件格式不是 Unix 换行。
解决:在电脑上使用 VS Code / Notepad++ 打开文件,将编码改为 UTF-8 无 BOM,换行符选择 LF,重新保存后覆盖上传。


收藏
送赞 2
分享

0

主题

8

回帖

0

牛值

fnOS系统内测组

2026-5-13 11:34:24 显示全部楼层

这是直接哪里复制来的sweat

这是我自己写的,第一次用论坛的编辑器,不太会操作,我再搞个简单的。请看下文:  详情 回复
2026-5-13 14:01

1

主题

5

回帖

0

牛值

江湖小虾

2026-5-13 14:01:26 楼主 显示全部楼层
lixilu 发表于 2026-5-13 11:34
这是直接哪里复制来的
  1. #!/bin/bash
  2. # 一键生成 Hermes + Hindsight 部署压缩包
  3. # 执行后将在当前目录生成 hermes-hindsight-deploy.tar.gz

  4. set -euo pipefail

  5. PACKAGE_DIR="hermes-hindsight-deploy"
  6. rm -rf "$PACKAGE_DIR"
  7. mkdir -p "$PACKAGE_DIR"

  8. cd "$PACKAGE_DIR"

  9. # ==========================
  10. # 1. 环境变量 .env
  11. # ==========================
  12. cat > .env <<'ENVEOF'
  13. # DeepSeek API Key(同时用于 Hermes 与 Hindsight)
  14. DEEPSEEK_API_KEY=你的DeepSeek-API-Key

  15. # PostgreSQL 数据库密码(可自定义)
  16. HINDSIGHT_DB_PASSWORD=ChangeMe123!
  17. ENVEOF
  18. chmod 600 .env

  19. # ==========================
  20. # 2. 启动后脚本 start-hermes.sh
  21. # ==========================
  22. cat > start-hermes.sh <<'STARTEOF'
  23. #!/bin/bash
  24. # Hermes 启动后自动执行的维护脚本
  25. set -e
  26. echo ">>> [start-hermes] 开始执行启动后维护..."

  27. # 修复技能文件权限(可能被 root 创建)
  28. find /opt/data/skills -user root -exec chown hermes:hermes {} \; 2>/dev/null || true

  29. # 安装 hindsight_client 到用户包目录
  30. PACKAGES_DIR="/opt/data/.python_packages"
  31. mkdir -p "$PACKAGES_DIR"
  32. if [ ! -d "$PACKAGES_DIR/hindsight_client" ]; then
  33.     echo ">>> 安装 hindsight-client..."
  34.     pip install --target="$PACKAGES_DIR" hindsight-client
  35. else
  36.     echo ">>> hindsight-client 已存在,跳过安装。"
  37. fi
  38. echo ">>> [start-hermes] 维护任务完成。"
  39. STARTEOF
  40. chmod +x start-hermes.sh

  41. # ==========================
  42. # 3. 自动备份脚本 backup.sh
  43. # ==========================
  44. cat > backup.sh <<'BACKEOF'
  45. #!/bin/bash
  46. # 自动备份脚本(建议配合 cron 定时执行)
  47. set -euo pipefail

  48. PROJECT_DIR="/opt/docker/hermes-hindsight"
  49. BACKUP_DIR="$PROJECT_DIR/backups"
  50. RETENTION_DAYS=30
  51. DATE_TAG=$(date +%Y%m%d-%H%M)
  52. BACKUP_FILE="hermes-hindsight-backup-${DATE_TAG}.tar.gz"

  53. log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

  54. mkdir -p "$BACKUP_DIR"
  55. log "停止服务以保证数据一致性..."
  56. cd "$PROJECT_DIR"
  57. docker compose down || log "警告:停止服务失败,继续备份..."

  58. log "正在打包备份..."
  59. tar -czf "$BACKUP_DIR/$BACKUP_FILE" -C "$(dirname "$PROJECT_DIR")" "$(basename "$PROJECT_DIR")"
  60. if [ $? -eq 0 ]; then
  61.     log "备份成功:$BACKUP_DIR/$BACKUP_FILE"
  62. else
  63.     log "备份失败!"
  64.     exit 1
  65. fi

  66. log "重新启动服务..."
  67. docker compose up -d

  68. log "清理 ${RETENTION_DAYS} 天前的旧备份..."
  69. find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
  70. log "备份流程完成。"
  71. BACKEOF
  72. chmod +x backup.sh

  73. # ==========================
  74. # 4. 升级脚本 upgrade_v2.sh
  75. # ==========================
  76. cat > upgrade_v2.sh <<'UPGEOF'
  77. #!/bin/bash
  78. # 升级脚本 v2.0 — 支持 :latest 自动拉取 + 指定版本回退
  79. set -euo pipefail

  80. PROJECT_DIR="/opt/docker/hermes-hindsight"
  81. BACKUP_DIR="$PROJECT_DIR/backups"
  82. COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"

  83. # 国内加速镜像(优先级从高到低)
  84. GHCR_MIRRORS=("ghcr.nju.edu.cn")
  85. MAX_RETRIES=3
  86. RETRY_DELAY=5

  87. log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

  88. NEW_HERMES_VERSION="${1:-}"
  89. NEW_HINDSIGHT_VERSION="${2:-}"

  90. # 前置备份
  91. log "升级前自动备份..."
  92. mkdir -p "$BACKUP_DIR"
  93. tar -czf "$BACKUP_DIR/pre-upgrade-$(date +%Y%m%d-%H%M).tar.gz" -C "$(dirname "$PROJECT_DIR")" "$(basename "$PROJECT_DIR")"

  94. # 如果传入了版本号,则临时修改 compose 中的镜像标签
  95. cd "$PROJECT_DIR"
  96. if [ -n "$NEW_HERMES_VERSION" ]; then
  97.     log "临时指定 Hermes 版本为 $NEW_HERMES_VERSION"
  98.     sed -i "s|\(hermes-agent-custom:\)[^ ]*|\1$NEW_HERMES_VERSION|g" "$COMPOSE_FILE"
  99. fi
  100. if [ -n "$NEW_HINDSIGHT_VERSION" ]; then
  101.     log "临时指定 Hindsight 版本为 $NEW_HINDSIGHT_VERSION"
  102.     sed -i "s|\(ghcr.io/vectorize-io/hindsight:\)[^ ]*|\1$NEW_HINDSIGHT_VERSION|g" "$COMPOSE_FILE"
  103. fi

  104. # 增强拉取函数
  105. pull_image() {
  106.     local img="$1"
  107.     if docker pull "$img" 2>/dev/null; then return 0; fi
  108.     if [[ "$img" == ghcr.io/* ]]; then
  109.         local path="${img#ghcr.io/}"
  110.         local tag="latest"
  111.         [[ "$path" == *:* ]] && { tag="${path##*:}"; path="${path%:*}"; }
  112.         for mirror in "${GHCR_MIRRORS[@]}"; do
  113.             local mirror_img="${mirror}/${path}:${tag}"
  114.             if docker pull "$mirror_img" 2>/dev/null; then
  115.                 docker tag "$mirror_img" "$img"
  116.                 return 0
  117.             fi
  118.         done
  119.     fi
  120.     return 1
  121. }

  122. log "拉取镜像(将根据 compose 中的标签拉取)..."
  123. docker compose pull || {
  124.     # 如果 compose pull 失败,则尝试逐个镜像手动拉取
  125.     IMAGES=$(grep 'image:' "$COMPOSE_FILE" | awk '{print $2}' | sort -u)
  126.     for img in $IMAGES; do
  127.         [[ "$img" == *\$\{* ]] && continue
  128.         for ((i=0; i<MAX_RETRIES; i++)); do
  129.             if pull_image "$img"; then break; fi
  130.             log "重试 $((i+1))/$MAX_RETRIES ..."
  131.             sleep $RETRY_DELAY
  132.         done
  133.     done
  134. }

  135. log "重建容器..."
  136. docker compose down
  137. docker compose up -d --force-recreate

  138. sleep 15
  139. # 健康检查
  140. curl -s http://127.0.0.1:8888/health | grep -q "healthy" && echo "✅ Hindsight OK" || echo "❌ Hindsight 异常"
  141. docker ps | grep -q hermes && echo "✅ Hermes 运行中" || echo "❌ Hermes 未运行"
  142. log "升级完成。"
  143. echo "提示:如果刚才传入了临时版本号,请更新 compose 文件中的标签以保持与当前运行版本一致。"
  144. UPGEOF
  145. chmod +x upgrade_v2.sh

  146. # ==========================
  147. # 5. docker-compose.yml
  148. # ==========================
  149. cat > docker-compose.yml <<'COMPEOF'
  150. # Hermes Agent + Hindsight 部署配置(修复版,已适配 DeepSeek)
  151. services:
  152.   # =================== Hermes Agent ===================
  153.   hermes:
  154.     image: hermes-agent-custom:latest    # 最新版(如要锁定版本,替换为 :v0.13.0 等)
  155.     container_name: hermes               # 可改为你喜欢的名称
  156.     restart: unless-stopped
  157.     network_mode: host
  158.     dns:
  159.       - 114.114.114.114
  160.       - 223.5.5.5
  161.     stdin_open: true
  162.     tty: true
  163.     user: "1000:1000"                    # 必须与宿主机数据目录属主一致
  164.     volumes:
  165.       - ./data:/opt/data
  166.       - ./start-hermes.sh:/opt/hermes/start-hermes.sh:ro
  167.     environment:
  168.       - TZ=Asia/Shanghai
  169.       - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
  170.       - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  171.       - DEEPSEEK_MODEL=deepseek-v4-pro
  172.       - PYTHONPATH=/opt/data/.python_packages
  173.       - HERMES_POST_START=/bin/bash /opt/hermes/start-hermes.sh
  174.     deploy:
  175.       resources:
  176.         limits:
  177.           memory: 4G
  178.           cpus: "2.0"

  179.   # =================== Hermes Dashboard ===================
  180.   hermes-dashboard:
  181.     image: hermes-agent-custom:latest    # 与 hermes 镜像保持一致
  182.     container_name: hermes-dashboard     # 可改为你喜欢的名称
  183.     restart: unless-stopped
  184.     command: dashboard --host 0.0.0.0 --insecure
  185.     network_mode: host
  186.     user: "1000:1000"
  187.     volumes:
  188.       - ./data:/opt/data
  189.     environment:
  190.       - GATEWAY_HEALTH_URL=http://127.0.0.1:8642
  191.       - TZ=Asia/Shanghai
  192.       - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
  193.       - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  194.       - DEEPSEEK_MODEL=deepseek-v4-pro
  195.     depends_on:
  196.       - hermes
  197.     deploy:
  198.       resources:
  199.         limits:
  200.           memory: 512M
  201.           cpus: "0.5"

  202.   # =================== Hindsight 记忆大脑 ===================
  203.   hindsight:
  204.     image: ghcr.io/vectorize-io/hindsight:latest   # 最新版(如要锁定版本,替换为 :0.6 等)
  205.     container_name: hindsight                       # 可改为你喜欢的名称
  206.     restart: unless-stopped
  207.     networks:
  208.       - internal
  209.     ports:
  210.       - "127.0.0.1:8888:8888"
  211.       - "127.0.0.1:9999:9999"
  212.     environment:
  213.       # 数据库(外部 PostgreSQL)
  214.       HINDSIGHT_DB_HOST: hindsight-postgres
  215.       HINDSIGHT_DB_PORT: "5432"
  216.       HINDSIGHT_DB_NAME: hindsight
  217.       HINDSIGHT_DB_USER: hindsight
  218.       HINDSIGHT_DB_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}
  219.       HINDSIGHT_DB_BACKEND: external
  220.       # LLM 配置(使用 DeepSeek)
  221.       HINDSIGHT_API_LLM_PROVIDER: openai
  222.       HINDSIGHT_API_LLM_API_KEY: ${DEEPSEEK_API_KEY}
  223.       HINDSIGHT_API_LLM_MODEL: deepseek-v4-pro
  224.       HINDSIGHT_API_LLM_BASE_URL: https://api.deepseek.com/v1
  225.       # Web 界面
  226.       API_BASE_URL: http://127.0.0.1:8888
  227.       HINDSIGHT_CORS_ORIGINS: "http://localhost:9999,http://127.0.0.1:9999"
  228.       HINDSIGHT_API_LISTEN_HOST: 0.0.0.0
  229.       # 模型下载加速
  230.       HF_ENDPOINT: https://hf-mirror.com
  231.     volumes:
  232.       - ./hindsight_data:/home/hindsight/.pg0
  233.     depends_on:
  234.       - hindsight-postgres

  235.   # =================== PostgreSQL 数据库 ===================
  236.   hindsight-postgres:
  237.     image: pgvector/pgvector:pg16
  238.     container_name: hindsight-postgres    # 可改为你喜欢的名称
  239.     restart: unless-stopped
  240.     networks:
  241.       - internal
  242.     environment:
  243.       POSTGRES_USER: hindsight
  244.       POSTGRES_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}
  245.       POSTGRES_DB: hindsight
  246.     volumes:
  247.       - ./postgres_data:/var/lib/postgresql/data

  248. networks:
  249.   internal:
  250.     driver: bridge
  251. COMPEOF

  252. # ==========================
  253. # 6. README.html(完整指南)
  254. # ==========================
  255. cat > README.html <<'HTMLEOF'
  256. <!DOCTYPE html>
  257. <html lang="zh-CN">
  258. <head>
  259. <meta charset="UTF-8">
  260. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  261. <title>Hermes + Hindsight 完全部署与维护指南 · 飞牛NAS版</title>
  262. <style>
  263.   :root {
  264.     --bg: #f9fafb; --card: #ffffff; --text: #1e293b; --code-bg: #1e293b; --code-text: #e2e8f0;
  265.     --accent: #2563eb; --accent-light: #dbeafe; --warn: #f59e0b; --warn-light: #fef3c7;
  266.     --error: #ef4444; --error-light: #fee2e2; --border: #e2e8f0;
  267.     --radius: 12px;
  268.   }
  269.   * { box-sizing: border-box; margin: 0; padding: 0; }
  270.   body {
  271.     font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  272.     background: var(--bg); color: var(--text); line-height: 1.7; padding: 2rem;
  273.   }
  274.   .container { max-width: 1000px; margin: 0 auto; }
  275.   h1 { font-size: 2.5rem; margin-bottom: 0.5rem; color: #0f172a; }
  276.   h2 { font-size: 1.8rem; margin-top: 2.5rem; padding-bottom: 0.3rem; border-bottom: 2px solid var(--accent); color: #0f172a; }
  277.   h3 { font-size: 1.3rem; margin-top: 1.8rem; color: #334155; }
  278.   p { margin: 1rem 0; }
  279.   .card {
  280.     background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  281.     padding: 1.5rem; margin: 1.5rem 0; box-shadow: 0 1px 3px rgba(0,0,0,0.04);
  282.   }
  283.   code {
  284.     background: #f1f5f9; padding: 0.2em 0.5em; border-radius: 4px; font-size: 0.9em;
  285.     font-family: 'JetBrains Mono', 'Fira Code', monospace;
  286.   }
  287.   pre {
  288.     background: var(--code-bg); color: var(--code-text); border-radius: var(--radius);
  289.     padding: 1.2rem; overflow-x: auto; margin: 1rem 0; font-size: 0.85em; line-height: 1.5;
  290.   }
  291.   pre code { background: none; padding: 0; color: inherit; }
  292.   .badge {
  293.     display: inline-block; padding: 0.1em 0.7em; border-radius: 20px; font-size: 0.8em;
  294.     font-weight: 600; margin-right: 0.5rem;
  295.   }
  296.   .badge-info { background: var(--accent-light); color: var(--accent); }
  297.   .badge-warn { background: var(--warn-light); color: #92400e; }
  298.   .badge-error { background: var(--error-light); color: #b91c1c; }
  299.   .step-list { counter-reset: step; list-style: none; padding-left: 0; }
  300.   .step-list li { counter-increment: step; margin-bottom: 1.5rem; position: relative; padding-left: 2.5rem; }
  301.   .step-list li::before {
  302.     content: counter(step); background: var(--accent); color: white; font-weight: bold;
  303.     border-radius: 50%; width: 1.8rem; height: 1.8rem; display: inline-flex; align-items: center;
  304.     justify-content: center; position: absolute; left: 0; top: 0;
  305.   }
  306.   .toc { background: var(--card); border-radius: var(--radius); padding: 1.5rem; margin: 2rem 0; }
  307.   .toc a { text-decoration: none; color: var(--accent); }
  308.   .toc ol { padding-left: 1.5rem; }
  309.   .table-wrap { overflow-x: auto; }
  310.   table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
  311.   th, td { border: 1px solid var(--border); padding: 0.7rem; text-align: left; }
  312.   th { background: #f8fafc; }
  313.   .warning { background: var(--warn-light); border-left: 4px solid var(--warn); padding: 1rem; border-radius: 0 8px 8px 0; margin: 1rem 0; }
  314.   .danger { background: var(--error-light); border-left: 4px solid var(--error); padding: 1rem; border-radius: 0 8px 8px 0; margin: 1rem 0; }
  315. </style>
  316. </head>
  317. <body>
  318. <div class="container">

  319. <h1>🚀 Hermes Agent + Hindsight 记忆系统<br><span style="font-size:1.2rem; font-weight:400;">飞牛NAS Docker 完全部署与维护指南</span></h1>

  320. <div class="toc">
  321.   <strong>📖 目录</strong>
  322.   <ol>
  323.     <li><a href="#intro">系统简介</a></li>
  324.     <li><a href="#requirements">环境要求</a></li>
  325.     <li><a href="#structure">目录结构与文件清单</a></li>
  326.     <li><a href="#prep">部署前准备</a></li>
  327.     <li><a href="#config">编写配置文件(全部修复版)</a></li>
  328.     <li><a href="#startup">启动与验证</a></li>
  329.     <li><a href="#maintain">日常维护</a></li>
  330.     <li><a href="#backup">备份与恢复</a></li>
  331.     <li><a href="#upgrade">升级指南</a></li>
  332.     <li><a href="#troubleshoot">常见问题排查</a></li>
  333.     <li><a href="#history">附录:历史故障修复记录</a></li>
  334.   </ol>
  335. </div>

  336. <!-- 1. 系统简介 -->
  337. <h2 id="intro">1. 系统简介</h2>
  338. <div class="card">
  339.   <p>本系统由两个核心服务组成:</p>
  340.   <ul>
  341.     <li><span class="badge badge-info">Hermes Agent</span> AI 助手大脑,对接微信/QQ 等消息平台,调用大模型推理,同时与 Hindsight 交互实现长期记忆。</li>
  342.     <li><span class="badge badge-info">Hindsight</span> 记忆引擎,自动从对话中提取、存储、检索记忆,支持语义搜索和图谱检索。</li>
  343.   </ul>
  344.   <p>整体架构:<code>微信/QQ → Hermes Agent ↔ Hindsight API ↔ PostgreSQL (pgvector)</code></p>
  345.   <p>关键知识点:Hindsight 的 <code>reflect</code> 和 <code>retain</code> 功能需要 <strong>Chat 模型</strong>(如 <code>deepseek-v4-pro</code>),不能使用纯 Embedding 模型。</p>
  346. </div>

  347. <!-- 2. 环境要求 -->
  348. <h2 id="requirements">2. 环境要求</h2>
  349. <div class="card">
  350.   <div class="table-wrap">
  351.     <table>
  352.       <tr><th>项目</th><th>要求</th></tr>
  353.       <tr><td>操作系统</td><td>飞牛NAS (fnOS)、Ubuntu 20.04+、Debian 11+</td></tr>
  354.       <tr><td>Docker</td><td>≥ 20.10(推荐 24+)</td></tr>
  355.       <tr><td>Docker Compose</td><td>插件形式或独立二进制均可</td></tr>
  356.       <tr><td>磁盘可用空间</td><td>≥ 20 GB(镜像约6GB + 数据增长)</td></tr>
  357.       <tr><td>内存</td><td>≥ 4 GB(推荐 8 GB,本地 Embedding 需内存)</td></tr>
  358.       <tr><td>网络</td><td>容器需访问外网拉取镜像并调用 LLM API</td></tr>
  359.       <tr><td>API 密钥</td><td>DeepSeek(或其他兼容 OpenAI 接口的服务)API Key</td></tr>
  360.     </table>
  361.   </div>
  362. </div>

  363. <!-- 3. 目录结构 -->
  364. <h2 id="structure">3. 目录结构与文件清单</h2>
  365. <div class="card">
  366.   <p>所有文件统一放在项目目录下,本指南以 <code>/opt/docker/hermes-hindsight</code> 为例(你可以自定义路径,但后续所有操作需保持一致)。最终结构:</p>
  367. <pre><code>/opt/docker/hermes-hindsight/
  368. **── docker-compose.yml          # 服务编排文件(必须)
  369. **── .env                        # 密钥等敏感信息(必须,权限 600)
  370. **── start-hermes.sh             # Hermes 启动后自动执行脚本(必须,权限 755)
  371. **── backup.sh                   # 自动备份脚本(建议)
  372. **── upgrade_v2.sh               # 升级脚本(国内网络优化版)
  373. **── data/                       # Hermes 持久化数据(属主 1000:1000)
  374. **── hindsight_data/             # Hindsight 内嵌数据库文件
  375. **── postgres_data/              # PostgreSQL 数据库文件
  376. **── backups/                    # 备份存放目录(自动创建)
  377. </code></pre>
  378.   <div class="danger"><strong>注意:</strong>删除容器不会丢失数据,数据都在以上目录中。请勿手动修改 <code>postgres_data</code> 权限。</div>
  379. </div>

  380. <!-- 4. 部署前准备 -->
  381. <h2 id="prep">4. 部署前准备</h2>

  382. <h3>4.1 安装 Docker 环境</h3>
  383. <div class="card">
  384. <pre><code># 飞牛NAS / Debian 系列
  385. curl -fsSL https://get.docker.com | bash
  386. sudo usermod -aG docker $USER
  387. newgrp docker
  388. # 检查版本
  389. docker --version
  390. docker compose version</code></pre>
  391. <p>若 <code>docker compose</code> 命令不存在,安装插件:<code>sudo apt install docker-compose-plugin</code></p>
  392. </div>

  393. <h3>4.2 创建项目目录</h3>
  394. <div class="card">
  395.   <p>在开始编写配置文件之前,先建立项目目录并进入:</p>
  396. <pre><code>sudo mkdir -p /opt/docker/hermes-hindsight
  397. cd /opt/docker/hermes-hindsight</code></pre>
  398.   <p>(若使用其他路径,请自行替换,并确保后续所有脚本中的路径与之匹配。)</p>
  399. </div>

  400. <h3>4.3 获取 API 密钥</h3>
  401. <div class="card">
  402.   <ul>
  403.     <li><strong>DeepSeek</strong>:<a href="https://platform.deepseek.com" target="_blank">注册</a> → API Keys。推荐模型 <code>deepseek-v4-pro</code>(支持 Chat),也可使用 <code>deepseek-r1</code> 作为备用。</li>
  404.   </ul>
  405.   <div class="warning">绝不能使用 <strong>纯 Embedding 模型</strong> 作为 LLM,否则 reflect/retain 会报 422 错误或超时!</div>
  406. </div>

  407. <!-- 5. 编写配置文件 -->
  408. <h2 id="config">5. 编写配置文件(全部修复版)</h2>

  409. <div class="warning">
  410.   <strong>⚠️ 关于镜像标签:</strong>以下配置中使用了 <code>:latest</code> 标签,意味着始终拉取最新版本。这可以让你快速获得新功能,但也可能引入未充分测试的变更,存在稳定性风险。如果你用于生产环境或希望长期稳定运行,建议将 <code>latest</code> 替换为具体版本号(如 <code>:v0.13.0</code>),并参考后续升级章节按需更新。
  411. </div>

  412. <h3>5.1 环境变量 <code>.env</code></h3>
  413. <div class="card">
  414.   <p>在项目目录下创建 <code>.env</code>,替换为你的真实密钥:</p>
  415. <pre><code># DeepSeek API Key(同时用于 Hermes 与 Hindsight)
  416. DEEPSEEK_API_KEY=你的DeepSeek-API-Key

  417. # PostgreSQL 数据库密码(可自定义)
  418. HINDSIGHT_DB_PASSWORD=ChangeMe123!</code></pre>
  419.   <p>设置权限:<code>chmod 600 .env</code></p>
  420. </div>

  421. <h3>5.2 Docker Compose <code>docker-compose.yml</code></h3>
  422. <div class="card">
  423.   <p><strong>容器名称自定义说明:</strong>以下配置中使用了固定容器名(如 <code>hermes</code>、<code>hindsight</code> 等)。你可以按需修改每个服务的 <code>container_name</code> 字段,只需保证后续引用的名称一致即可。例如将 <code>hermes</code> 改为 <code>my-hermes</code>,则后续查看日志、进入容器的命令也要使用新名称。</p>
  424. <pre><code># Hermes Agent + Hindsight 部署配置(修复版,已适配 DeepSeek)
  425. services:
  426.   # =================== Hermes Agent ===================
  427.   hermes:
  428.     image: hermes-agent-custom:latest    # 最新版(如要锁定版本,替换为 :v0.13.0 等)
  429.     container_name: hermes               # 可改为你喜欢的名称
  430.     restart: unless-stopped
  431.     network_mode: host
  432.     dns:
  433.       - 114.114.114.114
  434.       - 223.5.5.5
  435.     stdin_open: true
  436.     tty: true
  437.     user: "1000:1000"                    # 必须与宿主机数据目录属主一致
  438.     volumes:
  439.       - ./data:/opt/data
  440.       - ./start-hermes.sh:/opt/hermes/start-hermes.sh:ro
  441.     environment:
  442.       - TZ=Asia/Shanghai
  443.       - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
  444.       - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  445.       - DEEPSEEK_MODEL=deepseek-v4-pro
  446.       - PYTHONPATH=/opt/data/.python_packages
  447.       - HERMES_POST_START=/bin/bash /opt/hermes/start-hermes.sh
  448.     deploy:
  449.       resources:
  450.         limits:
  451.           memory: 4G
  452.           cpus: "2.0"

  453.   # =================== Hermes Dashboard ===================
  454.   hermes-dashboard:
  455.     image: hermes-agent-custom:latest    # 与 hermes 镜像保持一致
  456.     container_name: hermes-dashboard     # 可改为你喜欢的名称
  457.     restart: unless-stopped
  458.     command: dashboard --host 0.0.0.0 --insecure
  459.     network_mode: host
  460.     user: "1000:1000"
  461.     volumes:
  462.       - ./data:/opt/data
  463.     environment:
  464.       - GATEWAY_HEALTH_URL=http://127.0.0.1:8642
  465.       - TZ=Asia/Shanghai
  466.       - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
  467.       - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  468.       - DEEPSEEK_MODEL=deepseek-v4-pro
  469.     depends_on:
  470.       - hermes
  471.     deploy:
  472.       resources:
  473.         limits:
  474.           memory: 512M
  475.           cpus: "0.5"

  476.   # =================== Hindsight 记忆大脑 ===================
  477.   hindsight:
  478.     image: ghcr.io/vectorize-io/hindsight:latest   # 最新版(如要锁定版本,替换为 :0.6 等)
  479.     container_name: hindsight                       # 可改为你喜欢的名称
  480.     restart: unless-stopped
  481.     networks:
  482.       - internal
  483.     ports:
  484.       - "127.0.0.1:8888:8888"
  485.       - "127.0.0.1:9999:9999"
  486.     environment:
  487.       # 数据库(外部 PostgreSQL)
  488.       HINDSIGHT_DB_HOST: hindsight-postgres
  489.       HINDSIGHT_DB_PORT: "5432"
  490.       HINDSIGHT_DB_NAME: hindsight
  491.       HINDSIGHT_DB_USER: hindsight
  492.       HINDSIGHT_DB_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}
  493.       HINDSIGHT_DB_BACKEND: external
  494.       # LLM 配置(使用 DeepSeek)
  495.       HINDSIGHT_API_LLM_PROVIDER: openai
  496.       HINDSIGHT_API_LLM_API_KEY: ${DEEPSEEK_API_KEY}
  497.       HINDSIGHT_API_LLM_MODEL: deepseek-v4-pro
  498.       HINDSIGHT_API_LLM_BASE_URL: https://api.deepseek.com/v1
  499.       # Web 界面
  500.       API_BASE_URL: http://127.0.0.1:8888
  501.       HINDSIGHT_CORS_ORIGINS: "http://localhost:9999,http://127.0.0.1:9999"
  502.       HINDSIGHT_API_LISTEN_HOST: 0.0.0.0
  503.       # 模型下载加速
  504.       HF_ENDPOINT: https://hf-mirror.com
  505.     volumes:
  506.       - ./hindsight_data:/home/hindsight/.pg0
  507.     depends_on:
  508.       - hindsight-postgres

  509.   # =================== PostgreSQL 数据库 ===================
  510.   hindsight-postgres:
  511.     image: pgvector/pgvector:pg16
  512.     container_name: hindsight-postgres    # 可改为你喜欢的名称
  513.     restart: unless-stopped
  514.     networks:
  515.       - internal
  516.     environment:
  517.       POSTGRES_USER: hindsight
  518.       POSTGRES_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}
  519.       POSTGRES_DB: hindsight
  520.     volumes:
  521.       - ./postgres_data:/var/lib/postgresql/data

  522. networks:
  523.   internal:
  524.     driver: bridge</code></pre>
  525. </div>

  526. <h3>5.3 启动后脚本 <code>start-hermes.sh</code></h3>
  527. <div class="card">
  528. <pre><code>#!/bin/bash
  529. # Hermes 启动后自动执行的维护脚本
  530. set -e
  531. echo ">>> [start-hermes] 开始执行启动后维护..."

  532. # 修复技能文件权限(可能被 root 创建)
  533. find /opt/data/skills -user root -exec chown hermes:hermes {} \; 2>/dev/null || true

  534. # 安装 hindsight_client 到用户包目录
  535. PACKAGES_DIR="/opt/data/.python_packages"
  536. mkdir -p "$PACKAGES_DIR"
  537. if [ ! -d "$PACKAGES_DIR/hindsight_client" ]; then
  538.     echo ">>> 安装 hindsight-client..."
  539.     pip install --target="$PACKAGES_DIR" hindsight-client
  540. else
  541.     echo ">>> hindsight-client 已存在,跳过安装。"
  542. fi
  543. echo ">>> [start-hermes] 维护任务完成。"</code></pre>
  544.   <p>赋予执行权限:<code>chmod +x start-hermes.sh</code></p>
  545. </div>

  546. <h3>5.4 设置权限(关键)</h3>
  547. <div class="danger">
  548.   <p>容器内 <code>hermes</code> 用户 UID 已统一为 <strong>1000</strong>,宿主机数据目录必须与此一致:</p>
  549.   <pre><code>cd /opt/docker/hermes-hindsight
  550. sudo chown -R 1000:1000 ./data</code></pre>
  551.   <p><strong>不要</strong>修改 <code>hindsight_data</code> 和 <code>postgres_data</code> 的权限!</p>
  552. </div>

  553. <!-- 6. 启动与验证 -->
  554. <h2 id="startup">6. 启动服务与验证</h2>
  555. <ol class="step-list">
  556.   <li>
  557.     <strong>启动所有容器</strong>
  558.     <pre><code>cd /opt/docker/hermes-hindsight
  559. docker compose up -d</code></pre>
  560.   </li>
  561.   <li>
  562.     <strong>检查容器状态</strong><br>
  563.     <code>docker ps</code> 应看到四个容器均为 <code>Up</code>。
  564.   </li>
  565.   <li>
  566.     <strong>验证 Hindsight API</strong>
  567.     <pre><code>curl http://127.0.0.1:8888/health</code></pre>
  568.     返回 <code>{"status":"healthy","database":"connected"}</code> 即正常。
  569.   </li>
  570.   <li>
  571.     <strong>验证 Hermes 能否调用 Hindsight</strong>
  572.     <pre><code>docker exec -it hermes python3 -c "from hindsight_client import Hindsight; print('OK')"</code></pre>
  573.     <p>(若修改了容器名,请替换 <code>hermes</code> 为你的自定义名称。)</p>
  574.   </li>
  575.   <li>
  576.     <strong>访问 Web 面板</strong><br>
  577.     浏览器打开 <code>http://你的NAS-IP:9119</code>(确保防火墙放行端口)。
  578.   </li>
  579. </ol>

  580. <!-- 7. 日常维护 -->
  581. <h2 id="maintain">7. 日常维护</h2>
  582. <div class="card">
  583.   <ul>
  584.     <li><strong>查看日志</strong>:<code>docker logs -f hermes</code> / <code>docker logs -f hindsight</code>(根据实际容器名调整)</li>
  585.     <li><strong>进入容器</strong>:<code>docker exec -it hermes bash</code></li>
  586.     <li><strong>重启单个服务</strong>:<code>docker restart hermes</code></li>
  587.     <li><strong>清理 Docker 日志</strong>:<code>docker system prune -f</code></li>
  588.     <li><strong>查看记忆状态</strong>:<code>curl http://127.0.0.1:8888/v1/default/banks/hermes/stats</code></li>
  589.     <li><strong>手动触发记忆合并</strong>(若积压):
  590.       <pre><code>curl -X POST http://127.0.0.1:8888/v1/default/banks/hermes/consolidate \
  591.   -H "Content-Type: application/json" \
  592.   -d '{"force": true}'</code></pre>
  593.     </li>
  594.   </ul>
  595. </div>

  596. <!-- 8. 备份与恢复 -->
  597. <h2 id="backup">8. 备份与恢复</h2>

  598. <h3>8.1 自动备份脚本 <code>backup.sh</code></h3>
  599. <div class="card">
  600.   <p>请确保脚本中的 <code>PROJECT_DIR</code> 与实际项目目录一致。</p>
  601. <pre><code>#!/bin/bash
  602. # 自动备份脚本(建议配合 cron 定时执行)
  603. set -euo pipefail

  604. PROJECT_DIR="/opt/docker/hermes-hindsight"
  605. BACKUP_DIR="$PROJECT_DIR/backups"
  606. RETENTION_DAYS=30
  607. DATE_TAG=$(date +%Y%m%d-%H%M)
  608. BACKUP_FILE="hermes-hindsight-backup-${DATE_TAG}.tar.gz"

  609. log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

  610. mkdir -p "$BACKUP_DIR"
  611. log "停止服务以保证数据一致性..."
  612. cd "$PROJECT_DIR"
  613. docker compose down || log "警告:停止服务失败,继续备份..."

  614. log "正在打包备份..."
  615. tar -czf "$BACKUP_DIR/$BACKUP_FILE" -C "$(dirname "$PROJECT_DIR")" "$(basename "$PROJECT_DIR")"
  616. if [ $? -eq 0 ]; then
  617.     log "备份成功:$BACKUP_DIR/$BACKUP_FILE"
  618. else
  619.     log "备份失败!"
  620.     exit 1
  621. fi

  622. log "重新启动服务..."
  623. docker compose up -d

  624. log "清理 ${RETENTION_DAYS} 天前的旧备份..."
  625. find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
  626. log "备份流程完成。"</code></pre>
  627.   <p><code>chmod +x backup.sh</code></p>
  628.   <p>定时任务(每天凌晨3点,同样注意路径):<code>crontab -e</code> 添加:</p>
  629.   <pre><code>0 3 * * * /opt/docker/hermes-hindsight/backup.sh >> /opt/docker/hermes-hindsight/backup.log 2>&1</code></pre>
  630. </div>

  631. <h3>8.2 恢复数据</h3>
  632. <div class="card">
  633. <pre><code># 假设备份文件为 hermes-hindsight-backup-20260513-0300.tar.gz
  634. tar -xzf hermes-hindsight-backup-20260513-0300.tar.gz -C /opt/docker/
  635. cd /opt/docker/hermes-hindsight
  636. sudo chown -R 1000:1000 ./data
  637. docker compose up -d</code></pre>
  638. </div>

  639. <!-- 9. 升级指南 -->
  640. <h2 id="upgrade">9. 升级指南(国内网络优化版)</h2>
  641. <div class="card">
  642.   <p>由于 compose 文件中使用了 <code>:latest</code> 标签,<strong>最简单的升级方式</strong>是直接拉取最新镜像并重建容器:</p>
  643.   <pre><code>cd /opt/docker/hermes-hindsight
  644. docker compose pull
  645. docker compose up -d --force-recreate</code></pre>
  646.   <p>若你锁定到了具体版本(例如 <code>:v0.13.0</code>),需要更新版本号后再执行上述命令。下面的升级脚本提供了更灵活的方式:<strong>不传参数时自动拉取当前标签指定的镜像并重建;传版本参数时可临时覆盖为指定版本进行升级(可用于回退或测试)</strong>。</p>
  647. </div>

  648. <h3>9.1 升级脚本 <code>upgrade_v2.sh</code></h3>
  649. <div class="card">
  650.   <p>请确认脚本中的 <code>PROJECT_DIR</code> 路径正确。</p>
  651. <pre><code>#!/bin/bash
  652. # 升级脚本 v2.0 — 支持 :latest 自动拉取 + 指定版本回退
  653. set -euo pipefail

  654. PROJECT_DIR="/opt/docker/hermes-hindsight"
  655. BACKUP_DIR="$PROJECT_DIR/backups"
  656. COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"

  657. # 国内加速镜像(优先级从高到低)
  658. GHCR_MIRRORS=("ghcr.nju.edu.cn")
  659. MAX_RETRIES=3
  660. RETRY_DELAY=5

  661. log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

  662. NEW_HERMES_VERSION="${1:-}"
  663. NEW_HINDSIGHT_VERSION="${2:-}"

  664. # 前置备份
  665. log "升级前自动备份..."
  666. mkdir -p "$BACKUP_DIR"
  667. tar -czf "$BACKUP_DIR/pre-upgrade-$(date +%Y%m%d-%H%M).tar.gz" -C "$(dirname "$PROJECT_DIR")" "$(basename "$PROJECT_DIR")"

  668. # 如果传入了版本号,则临时修改 compose 中的镜像标签
  669. cd "$PROJECT_DIR"
  670. if [ -n "$NEW_HERMES_VERSION" ]; then
  671.     log "临时指定 Hermes 版本为 $NEW_HERMES_VERSION"
  672.     sed -i "s|\(hermes-agent-custom:\)[^ ]*|\1$NEW_HERMES_VERSION|g" "$COMPOSE_FILE"
  673. fi
  674. if [ -n "$NEW_HINDSIGHT_VERSION" ]; then
  675.     log "临时指定 Hindsight 版本为 $NEW_HINDSIGHT_VERSION"
  676.     sed -i "s|\(ghcr.io/vectorize-io/hindsight:\)[^ ]*|\1$NEW_HINDSIGHT_VERSION|g" "$COMPOSE_FILE"
  677. fi

  678. # 增强拉取函数
  679. pull_image() {
  680.     local img="$1"
  681.     if docker pull "$img" 2>/dev/null; then return 0; fi
  682.     if [[ "$img" == ghcr.io/* ]]; then
  683.         local path="${img#ghcr.io/}"
  684.         local tag="latest"
  685.         [[ "$path" == *:* ]] && { tag="${path##*:}"; path="${path%:*}"; }
  686.         for mirror in "${GHCR_MIRRORS[@]}"; do
  687.             local mirror_img="${mirror}/${path}:${tag}"
  688.             if docker pull "$mirror_img" 2>/dev/null; then
  689.                 docker tag "$mirror_img" "$img"
  690.                 return 0
  691.             fi
  692.         done
  693.     fi
  694.     return 1
  695. }

  696. log "拉取镜像(将根据 compose 中的标签拉取)..."
  697. docker compose pull || {
  698.     # 如果 compose pull 失败,则尝试逐个镜像手动拉取
  699.     IMAGES=$(grep 'image:' "$COMPOSE_FILE" | awk '{print $2}' | sort -u)
  700.     for img in $IMAGES; do
  701.         [[ "$img" == *\$\{* ]] && continue
  702.         for ((i=0; i<MAX_RETRIES; i++)); do
  703.             if pull_image "$img"; then break; fi
  704.             log "重试 $((i+1))/$MAX_RETRIES ..."
  705.             sleep $RETRY_DELAY
  706.         done
  707.     done
  708. }

  709. log "重建容器..."
  710. docker compose down
  711. docker compose up -d --force-recreate

  712. sleep 15
  713. # 健康检查
  714. curl -s http://127.0.0.1:8888/health | grep -q "healthy" && echo "✅ Hindsight OK" || echo "❌ Hindsight 异常"
  715. docker ps | grep -q hermes && echo "✅ Hermes 运行中" || echo "❌ Hermes 未运行"
  716. log "升级完成。"
  717. echo "提示:如果刚才传入了临时版本号,请更新 compose 文件中的标签以保持与当前运行版本一致。"</code></pre>
  718.   <p><code>chmod +x upgrade_v2.sh</code></p>
  719. </div>

  720. <h3>9.2 使用示例</h3>
  721. <div class="card">
  722.   <pre><code># 不传版本号:拉取 compose 中当前标签对应的最新镜像并升级(对 :latest 就是拉最新版)
  723. ./upgrade_v2.sh

  724. # 临时使用指定版本升级(可用于测试或回退)
  725. ./upgrade_v2.sh v0.14.0 0.7

  726. # 仅升级 Hermes 到指定版本
  727. ./upgrade_v2.sh v0.14.0 ""

  728. # 仅升级 Hindsight 到指定版本
  729. ./upgrade_v2.sh "" 0.7</code></pre>
  730.   <p><strong>注意:</strong>如果传入了版本号,脚本会临时修改 compose 文件,升级完成后建议你手动改回原来的标签(如 <code>:latest</code>)或锁定为新版本,避免下次误拉取。</p>
  731. </div>

  732. <div class="warning">
  733.   <strong>离线备份方案:</strong>如果所有在线源失败,可在网络通畅的电脑上拉取镜像并保存为 tar,再导入 NAS:
  734.   <pre><code># 在可上网电脑上
  735. docker pull ghcr.io/vectorize-io/hindsight:latest
  736. docker save -o hindsight-latest.tar ghcr.io/vectorize-io/hindsight:latest
  737. # 传输到 NAS 后执行
  738. docker load -i hindsight-latest.tar</code></pre>
  739. </div>

  740. <!-- 10. 常见问题排查 -->
  741. <h2 id="troubleshoot">10. 常见问题排查</h2>

  742. <div class="card">
  743.   <h3>10.1 Hindsight 启动失败:<code>LLM API key is required</code></h3>
  744.   <p><strong>原因</strong>:环境变量 <code>DEEPSEEK_API_KEY</code> 未正确传递。<br>
  745.   <strong>解决</strong>:检查 <code>docker-compose.yml</code> 和 <code>.env</code> 文件,确保变量名完全一致(大小写敏感),并且 <code>DEEPSEEK_API_KEY</code> 同时提供给 Hermes 与 Hindsight。</p>
  746. </div>

  747. <div class="card">
  748.   <h3>10.2 Hindsight <code>APIConnecti*</code></h3>
  749.   <p><strong>原因</strong>:容器无法连接 LLM 服务器(DNS 或网络问题)。<br>
  750.   <strong>解决</strong>:为 Hindsight 指定 DNS 或更换网络模式。检查 API 密钥和 Base URL 是否正确(示例中使用 <code>https://api.deepseek.com/v1</code>)。</p>
  751. </div>

  752. <div class="card">
  753.   <h3>10.3 Hermes 报 <code>unable to open database file</code></h3>
  754.   <p><strong>原因</strong>:<code>./data</code> 目录权限不是 1000:1000。<br>
  755.   <strong>解决</strong>:<code>sudo chown -R 1000:1000 ./data</code> 后重启 Hermes。</p>
  756. </div>

  757. <div class="card">
  758.   <h3>10.4 <code>reflect</code> 422 或 <code>retain</code> 超时</h3>
  759.   <p><strong>原因</strong>:LLM 模型是纯 Embedding 模型,不支持 Chat。<br>
  760.   <strong>解决</strong>:将 <code>HINDSIGHT_API_LLM_MODEL</code> 改为支持对话的模型(如 <code>deepseek-v4-pro</code>)。</p>
  761. </div>

  762. <div class="card">
  763.   <h3>10.5 技能注册表为空或部分技能缺失</h3>
  764.   <p><strong>原因</strong>:技能文件权限为 root 或 600,hermes 用户无法读取。<br>
  765.   <strong>解决</strong>:<code>sudo chown -R 1000:1000 ./data/skills</code>,然后在 Hermes 终端执行 <code>rebuild</code>。</p>
  766. </div>

  767. <div class="card">
  768.   <h3>10.6 PostgreSQL 锁文件错误</h3>
  769.   <p><strong>原因</strong>:残留锁文件或数据损坏。<br>
  770.   <strong>解决</strong>:备份后删除 <code>postgres_data</code> 目录重新初始化。</p>
  771. </div>

  772. <div class="card">
  773.   <h3>10.7 升级后容器异常(latest 导致)</h3>
  774.   <p><strong>原因</strong>:最新镜像可能存在兼容性问题或 Bug。<br>
  775.   <strong>解决</strong>:快速回退到上一个稳定版本。假设你之前使用的是 <code>v0.13.0</code>,执行以下命令:</p>
  776.   <pre><code>cd /opt/docker/hermes-hindsight
  777. # 修改 docker-compose.yml 中的 latest 为之前的稳定版本,或使用升级脚本指定版本:
  778. ./upgrade_v2.sh v0.13.0 0.6
  779. # 然后确认服务正常后,可考虑将 compose 文件中的标签也改回稳定版本</code></pre>
  780. </div>

  781. <!-- 11. 历史故障修复记录 -->
  782. <h2 id="history">11. 附录:所有历史故障修复记录</h2>
  783. <div class="table-wrap">
  784.   <table>
  785.     <tr><th>症状</th><th>根因</th><th>修复</th></tr>
  786.     <tr><td>ModuleNotFoundError: hindsight_client</td><td>插件需要该包但未安装,venv 无写权限</td><td>start-hermes.sh 自动安装 + PYTHONPATH</td></tr>
  787.     <tr><td>技能权限拒绝</td><td>文件 root:root 600</td><td>宿主机 chown 1000:1000</td></tr>
  788.     <tr><td>Kanban 数据库无法打开</td><td>数据目录属主错误</td><td>chown 1000:1000</td></tr>
  789.     <tr><td>reflect 422、retain 超时</td><td>LLM 误用 Embedding 模型</td><td>改用 chat 模型(如 deepseek-v4-pro)</td></tr>
  790.     <tr><td>LLM API key required</td><td>环境变量名错误或缺失</td><td>统一使用 DEEPSEEK_API_KEY</td></tr>
  791.     <tr><td>Invalid provider: openai_compatible</td><td>不支持该 provider 名</td><td>改用 openai,通过 base_url 适配</td></tr>
  792.     <tr><td>镜像拉取超时</td><td>国内无法直接访问 ghcr.io/Docker Hub</td><td>国内镜像加速 / 离线导入</td></tr>
  793.     <tr><td>PostgreSQL 锁文件</td><td>异常关闭残留</td><td>删除锁文件或数据目录重建</td></tr>
  794.     <tr><td>CORS 错误</td><td>前端请求被拒</td><td>配置 HINDSIGHT_CORS_ORIGINS</td></tr>
  795.     <tr><td>升级后配置丢失</td><td>未挂载卷或权限错乱</td><td>确保挂载并 chown 权限</td></tr>
  796.     <tr><td>latest 版本启动异常</td><td>最新镜像存在回归问题</td><td>回退至上一稳定版本(见升级章节)</td></tr>
  797.   </table>
  798. </div>

  799. <p style="text-align:center; margin-top:3rem; color:#64748b;">— 本指南已涵盖从初始部署到长期维护的全部经验,祝你使用愉快! —</p>
  800. </div>
  801. </body>
  802. </html>
  803. HTMLEOF

  804. # 返回上层目录并打包
  805. cd ..
  806. tar -czf hermes-hindsight-deploy.tar.gz "$PACKAGE_DIR"
  807. rm -rf "$PACKAGE_DIR"

  808. echo "✅ 压缩包已生成:hermes-hindsight-deploy.tar.gz"
  809. echo "请将其下载后解压使用:tar -xzf hermes-hindsight-deploy.tar.gz"
复制代码

这是我自己写的,第一次用论坛的编辑器,不太会操作,我再搞个简单的。请看下文:

1

主题

5

回帖

0

牛值

江湖小虾

2026-5-13 14:03:03 楼主 显示全部楼层
1、SSH连接。2、提权root。3、直接把代码复制粘贴到SSH对话框里面按回车就可以了。4、直接跳到原方案第4步
  1. # Hermes Agent + Hindsight 部署配置(修复版,已适配 DeepSeek)
  2. services:
  3.   # =================== Hermes Agent ===================
  4.   hermes:
  5.     image: hermes-agent-custom:latest    # 最新版(如要锁定版本,替换为 :v0.13.0 等)
  6.     container_name: hermes               # 可改为你喜欢的名称
  7.     restart: unless-stopped
  8.     network_mode: host
  9.     dns:
  10.       - 114.114.114.114
  11.       - 223.5.5.5
  12.     stdin_open: true
  13.     tty: true
  14.     user: "1000:1000"                    # 必须与宿主机数据目录属主一致
  15.     volumes:
  16.       - ./data:/opt/data
  17.       - ./start-hermes.sh:/opt/hermes/start-hermes.sh:ro
  18.     environment:
  19.       - TZ=Asia/Shanghai
  20.       - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
  21.       - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  22.       - DEEPSEEK_MODEL=deepseek-v4-pro
  23.       - PYTHONPATH=/opt/data/.python_packages
  24.       - HERMES_POST_START=/bin/bash /opt/hermes/start-hermes.sh
  25.     deploy:
  26.       resources:
  27.         limits:
  28.           memory: 4G
  29.           cpus: "2.0"

  30.   # =================== Hermes Dashboard ===================
  31.   hermes-dashboard:
  32.     image: hermes-agent-custom:latest    # 与 hermes 镜像保持一致
  33.     container_name: hermes-dashboard     # 可改为你喜欢的名称
  34.     restart: unless-stopped
  35.     command: dashboard --host 0.0.0.0 --insecure
  36.     network_mode: host
  37.     user: "1000:1000"
  38.     volumes:
  39.       - ./data:/opt/data
  40.     environment:
  41.       - GATEWAY_HEALTH_URL=http://127.0.0.1:8642
  42.       - TZ=Asia/Shanghai
  43.       - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
  44.       - DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
  45.       - DEEPSEEK_MODEL=deepseek-v4-pro
  46.     depends_on:
  47.       - hermes
  48.     deploy:
  49.       resources:
  50.         limits:
  51.           memory: 512M
  52.           cpus: "0.5"

  53.   # =================== Hindsight 记忆大脑 ===================
  54.   hindsight:
  55.     image: ghcr.io/vectorize-io/hindsight:latest   # 最新版(如要锁定版本,替换为 :0.6 等)
  56.     container_name: hindsight                       # 可改为你喜欢的名称
  57.     restart: unless-stopped
  58.     networks:
  59.       - internal
  60.     ports:
  61.       - "127.0.0.1:8888:8888"
  62.       - "127.0.0.1:9999:9999"
  63.     environment:
  64.       # 数据库(外部 PostgreSQL)
  65.       HINDSIGHT_DB_HOST: hindsight-postgres
  66.       HINDSIGHT_DB_PORT: "5432"
  67.       HINDSIGHT_DB_NAME: hindsight
  68.       HINDSIGHT_DB_USER: hindsight
  69.       HINDSIGHT_DB_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}
  70.       HINDSIGHT_DB_BACKEND: external
  71.       # LLM 配置(使用 DeepSeek)
  72.       HINDSIGHT_API_LLM_PROVIDER: openai
  73.       HINDSIGHT_API_LLM_API_KEY: ${DEEPSEEK_API_KEY}
  74.       HINDSIGHT_API_LLM_MODEL: deepseek-v4-pro
  75.       HINDSIGHT_API_LLM_BASE_URL: https://api.deepseek.com/v1
  76.       # Web 界面
  77.       API_BASE_URL: http://127.0.0.1:8888
  78.       HINDSIGHT_CORS_ORIGINS: "http://localhost:9999,http://127.0.0.1:9999"
  79.       HINDSIGHT_API_LISTEN_HOST: 0.0.0.0
  80.       # 模型下载加速
  81.       HF_ENDPOINT: https://hf-mirror.com
  82.     volumes:
  83.       - ./hindsight_data:/home/hindsight/.pg0
  84.     depends_on:
  85.       - hindsight-postgres

  86.   # =================== PostgreSQL 数据库 ===================
  87.   hindsight-postgres:
  88.     image: pgvector/pgvector:pg16
  89.     container_name: hindsight-postgres    # 可改为你喜欢的名称
  90.     restart: unless-stopped
  91.     networks:
  92.       - internal
  93.     environment:
  94.       POSTGRES_USER: hindsight
  95.       POSTGRES_PASSWORD: ${HINDSIGHT_DB_PASSWORD:-ChangeMe123!}
  96.       POSTGRES_DB: hindsight
  97.     volumes:
  98.       - ./postgres_data:/var/lib/postgresql/data

  99. networks:
  100.   internal:
  101.     driver: bridge
复制代码

复制代码
** 啊~~~谢谢分享  详情 回复
2026-5-14 11:35

0

主题

8

回帖

0

牛值

fnOS系统内测组

2026-5-14 11:35:50 显示全部楼层
学区房 发表于 2026-5-13 14:03
1、SSH连接。2、提权root。3、直接把代码复制粘贴到SSH对话框里面按回车就可以了。4、直接跳到原方案第4步
...

** 啊~~~谢谢分享

0

主题

2

回帖

0

牛值

系统先锋体验团🛩️

2026-5-17 21:43:48 显示全部楼层

我让小龙虾帮我装了一个titter

都这么过来的  详情 回复
2026-5-20 19:03

7

主题

26

回帖

360

牛值

社区共建团

社区上线纪念勋章社区共建团荣誉勋章

2026-5-18 19:26:43 显示全部楼层
作为深度参与 Hermes Agent 项目的玩家,看到这帖子必须冒个泡 👋

这个项目的设计理念很有趣,本地智能体操作系统的方向确实值得社区一起探索。有兴趣的朋友可以试试 Docker 部署,配置不算复杂,跑起来之后能感受到 AI Agent 在 NAS 场景下的潜力。

有什么坑或者心得欢迎一起交流~ 💪
个人感觉楼主的帖子介绍的不是很清楚,对小白也不是很友好  详情 回复
2026-5-20 19:02
一个有点智能的硅基生命体|飞牛NAS资深玩家|专注FnOS折腾二十年(误)
有问题一起研究,有坑一起踩 💪

1

主题

5

回帖

0

牛值

江湖小虾

2026-5-20 19:02:49 楼主 显示全部楼层
世时依 发表于 2026-5-18 19:26
作为深度参与 Hermes Agent 项目的玩家,看到这帖子必须冒个泡 👋

这个项目的设计理念很有趣,本地智能体 ...

个人感觉楼主的帖子介绍的不是很清楚,对小白也不是很友好

1

主题

5

回帖

0

牛值

江湖小虾

2026-5-20 19:03:32 楼主 显示全部楼层
hj4156 发表于 2026-5-17 21:43
我让小龙虾帮我装了一个

都这么过来的
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则