forked from DevOps/deploy.stack
chore: add env.cfg.example templates and clean up config files
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# create-multi-keys.sh — 在 vm61 (10.8.0.9, 备用/测试) honcho 上批量创建 3 个客户端的 API key
|
||||
#
|
||||
# 用法:
|
||||
# 1. 在 vm61 上: ./create-multi-keys.sh
|
||||
# 2. 输出 3 个 key 文件到 ~/.honcho-keys/,chmod 600
|
||||
# 3. scp 到对应客户端
|
||||
#
|
||||
# 前置:
|
||||
# - honcho-api 容器跑着(监听 10.8.0.9:18000)
|
||||
# - AUTH_USE_AUTH=true + 管理员 token(honcho init 时生成)
|
||||
# - workspace "home" 已存在
|
||||
#
|
||||
# ⚠️ 不要 echo key 到聊天。文件 chmod 600,scp 时 -p 保留权限。
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WORKSPACE="${HONCHO_WORKSPACE:-home}"
|
||||
HONCHO_API="${HONCHO_API_URL:-http://10.8.0.9:18000}"
|
||||
ADMIN_TOKEN_FILE="${HONCHO_ADMIN_TOKEN_FILE:-/root/.honcho-keys/admin.key}"
|
||||
|
||||
# 客户端清单: name:peer:device_hint
|
||||
CLIENTS=(
|
||||
"alpha:laodeng-mypc03:mypc03"
|
||||
"beta:laodeng-govpc:gov-pc"
|
||||
"gamma:laodeng-mac:macbook"
|
||||
)
|
||||
|
||||
OUT_DIR="${OUT_DIR:-/root/.honcho-keys}"
|
||||
mkdir -p "$OUT_DIR"
|
||||
chmod 700 "$OUT_DIR"
|
||||
|
||||
if [[ ! -f "$ADMIN_TOKEN_FILE" ]]; then
|
||||
echo "❌ 找不到 admin token: $ADMIN_TOKEN_FILE" >&2
|
||||
echo " 把 honcho init 时生成的 admin token 写到该文件,chmod 600" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ADMIN_TOKEN="$(cat "$ADMIN_TOKEN_FILE")"
|
||||
|
||||
echo "==> honcho: $HONCHO_API"
|
||||
echo "==> workspace: $WORKSPACE"
|
||||
echo "==> 输出目录: $OUT_DIR"
|
||||
echo ""
|
||||
|
||||
for entry in "${CLIENTS[@]}"; do
|
||||
IFS=':' read -r slug peer device <<< "$entry"
|
||||
key_file="$OUT_DIR/${device}.key"
|
||||
info_file="$OUT_DIR/${device}.json"
|
||||
|
||||
echo "--- [$device] peer=$peer ---"
|
||||
|
||||
# 检查 peer 是否已存在(幂等)
|
||||
existing="$(curl -fsS -H "Authorization: Bearer *** "$HONCHO_API/v2/workspaces/$WORKSPACE/peers/$peer" 2>/dev/null || true)"
|
||||
|
||||
if [[ -n "$existing" && "$existing" != *"404"* ]]; then
|
||||
echo " peer 已存在,跳过创建"
|
||||
else
|
||||
# 创建 peer
|
||||
curl -fsS -X POST \
|
||||
-H "Authorization: Bearer *** \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\":\"$peer\"}" \
|
||||
"$HONCHO_API/v2/workspaces/$WORKSPACE/peers" \
|
||||
| tee "$info_file.tmp" > /dev/null
|
||||
mv "$info_file.tmp" "$info_file"
|
||||
chmod 600 "$info_file"
|
||||
echo " ✅ peer 已创建"
|
||||
fi
|
||||
|
||||
# 创建 API key(每次新建,旧的不 revoke)
|
||||
# honcho 的 key 创建 API 名称可能因版本不同,下面给常见两种尝试
|
||||
key_resp="$(curl -fsS -X POST \
|
||||
-H "Authorization: Bearer *** \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\":\"$peer\",\"scope\":\"peer:$peer\"}" \
|
||||
"$HONCHO_API/v2/workspaces/$WORKSPACE/api-keys" 2>/dev/null || true)"
|
||||
|
||||
if [[ -z "$key_resp" ]]; then
|
||||
# 备选 endpoint
|
||||
key_resp="$(curl -fsS -X POST \
|
||||
-H "Authorization: Bearer *** \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\":\"$peer\"}" \
|
||||
"$HONCHO_API/v2/auth/keys 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [[ -z "$key_resp" ]]; then
|
||||
echo " ❌ 创建 key 失败,请检查 honcho API 版本" >&2
|
||||
echo " 临时手动: honcho create user --workspace $WORKSPACE --name $peer" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# 提取 token(兼容多种字段名)
|
||||
token="$(echo "$key_resp" | python3 -c '
|
||||
import json, sys
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
print(d.get("token") or d.get("api_key") or d.get("key") or d.get("value") or "")
|
||||
except Exception:
|
||||
print("")
|
||||
')"
|
||||
|
||||
if [[ -z "$token" ]]; then
|
||||
echo " ❌ 无法从响应提取 token:"
|
||||
echo "$key_resp" | head -c 500
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
|
||||
echo -n "$token" > "$key_file"
|
||||
chmod 600 "$key_file"
|
||||
echo " ✅ key 已写入: $key_file ($(wc -c < "$key_file") bytes)"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "==> 完成。当前 keys:"
|
||||
ls -la "$OUT_DIR"
|
||||
echo ""
|
||||
echo "下一步:"
|
||||
echo " scp $OUT_DIR/mypc03.key mypc03:~/.honcho-keys/"
|
||||
echo " scp $OUT_DIR/govpc.key govpc:~/.honcho-keys/"
|
||||
echo " scp $OUT_DIR/mac.key macbook:~/.honcho-keys/"
|
||||
echo ""
|
||||
echo "⚠️ 不要 echo 这些 key 到聊天/日志/screenshot"
|
||||
@@ -0,0 +1,85 @@
|
||||
# ============================================================
|
||||
# Honcho Self-Hosted 部署 — 公共环境变量(不含敏感信息)
|
||||
# 复制为 env.cfg 后填入真实值,env.cfg 已被 .gitignore 忽略
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 镜像版本
|
||||
# ============================================================
|
||||
# Honcho 主仓库 git ref(源码 build 用,可填 tag / branch / SHA)
|
||||
HONCHO_VERSION=main
|
||||
# PostgreSQL 大版本号(pgvector 镜像 tag 后缀,必须与镜像仓库支持的 tag 对应)
|
||||
HONCHO_DB_VERSION=18
|
||||
# Redis 大版本号
|
||||
HONCHO_REDIS_VERSION=8
|
||||
|
||||
# 镜像仓库(默认公共镜像;自建私有 hub 可改 hub.tp229.com:3500/...)
|
||||
HONCHO_DB_IMAGE=pgvector/pgvector
|
||||
HONCHO_REDIS_IMAGE=redis
|
||||
|
||||
# ============================================================
|
||||
# PostgreSQL 数据库
|
||||
# ============================================================
|
||||
HONCHO_DB_USER=honcho
|
||||
HONCHO_DB_NAME=honcho
|
||||
# scram-sha-256 比 md5 安全;与 POSTGRES_INITDB_ARGS --auth-host 同步
|
||||
POSTGRES_HOST_AUTH_METHOD=scram-sha-256
|
||||
|
||||
# ============================================================
|
||||
# 宿主机数据卷路径(必须 WSL/Linux ext4 原生 fs,不能放 /mnt/9P)
|
||||
# 9P drvfs 的 fsync 不可靠,会导致 PG 数据损坏
|
||||
# ============================================================
|
||||
Volumes_Path=/data/volumes/honcho
|
||||
|
||||
# ============================================================
|
||||
# 服务端口(宿主机:容器,全部绑定 0.0.0.0 供 LAN 访问)
|
||||
# 5432 与 hindsight/dbSer 撞车,多服务共存时改 HONCHO_DB_PORT 区分
|
||||
# ============================================================
|
||||
HONCHO_API_PORT=8000
|
||||
HONCHO_DB_PORT=5432
|
||||
HONCHO_REDIS_PORT=6379
|
||||
|
||||
# ============================================================
|
||||
# Honcho 应用配置
|
||||
# ============================================================
|
||||
HONCHO_LOG_LEVEL=INFO
|
||||
# 本地 LAN 自用可设 false;公网暴露必须改 true
|
||||
HONCHO_AUTH_USE_AUTH=false
|
||||
HONCHO_NAMESPACE=honcho
|
||||
# 关闭可省 embedding 费用(但失去语义检索能力)
|
||||
HONCHO_EMBED_MESSAGES=true
|
||||
# Embedding 模型(默认走 SiliconFlow 兼容端点,独立 base URL)
|
||||
HONCHO_EMBEDDING_MODEL=Qwen/Qwen3-Embedding-8B
|
||||
HONCHO_EMBEDDING_BASE_URL=https://api.siliconflow.cn/v1
|
||||
# 替代方案 A:本地 Ollama(零成本、隐私优先)
|
||||
# HONCHO_EMBEDDING_MODEL=qwen3-embedding:0.6b
|
||||
# HONCHO_EMBEDDING_BASE_URL=http://host.docker.internal:11434/v1
|
||||
# EMBEDDING_API_KEY 可留空(Ollama 默认无 key;如配了 OLLAMA_API_KEY 环境变量再填)
|
||||
# 前置:宿主机 `ollama pull qwen3-embedding:0.6b`
|
||||
# docker compose 中 host.docker.internal 在 Linux compose v2 默认可用,Windows/WSL2 自动转发
|
||||
# Embedding 维度(Qwen3-Embedding-8B 默认 4096,但通过 SiliconFlow 的 dimensions 参数强制输出 1536)
|
||||
# 必须与已有 DB schema 的 public.documents.embedding dim 一致;切换模型必须先 migrate 旧数据
|
||||
# 若 Honcho 自动推断失败,需在 stack.yml 同步设置 EMBEDDING_VECTOR_DIMENSIONS=1536
|
||||
# deriver 必须用支持 tool calling 的模型
|
||||
HONCHO_DERIVER_MODEL=deepseek-ai/DeepSeek-V4-Flash
|
||||
# dreamer 的 deduction/induction specialist(默认走 OpenAI SDK + gpt-5.4-mini,
|
||||
# 会请求 api.openai.com/v1 在国内超时);必须显式覆盖到国内可达端点
|
||||
HONCHO_DEDUCTION_MODEL=deepseek-ai/DeepSeek-V4-Flash
|
||||
HONCHO_INDUCTION_MODEL=deepseek-ai/DeepSeek-V4-Flash
|
||||
HONCHO_DERIVER_WORKERS=1
|
||||
|
||||
# ============================================================
|
||||
# LLM(OpenAI 兼容协议;可换 OpenRouter / vLLM / Ollama 等端点)
|
||||
# deriver 启动时强校验 API Key 非空,占位符会反复重启
|
||||
# 注意:必须同时被 deriver/dreamer/embedding 复用,否则 specialist 会回落 openai.com
|
||||
# ============================================================
|
||||
HONCHO_LLM_BASE_URL=https://api.siliconflow.cn/v1
|
||||
|
||||
# ============================================================
|
||||
# 敏感值(必填,env.cfg 不提交)— 在 .gitignore 已忽略
|
||||
# 占位符约定:REPLACE_ME_XXX → 替换为真实值(避免使用 <...> 占位符,patch 工具链会吞)
|
||||
# ============================================================
|
||||
# HONCHO_LLM_API_KEY=REPLACE_ME_LLM_KEY # 你的 OpenAI key 或兼容端点 key
|
||||
# HONCHO_EMBEDDING_API_KEY=REPLACE_ME_EMBEDDING_KEY # SiliconFlow key:https://cloud.siliconflow.cn/account/ak
|
||||
# HONCHO_DB_PASSWORD=REPLACE_ME_DB_PASSWORD # 强密码,不要带特殊字符,避免 URI 编码问题
|
||||
# HONCHO_AUTH_JWT_SECRET=REPLACE_ME_JWT_SECRET # 仅 AUTH_USE_AUTH=true 时需要;用 python scripts/generate_jwt_secret.py 生成
|
||||
@@ -0,0 +1,374 @@
|
||||
# Honcho Self-Hosted 部署栈
|
||||
|
||||
[plastic-labs/honcho](https://github.com/plastic-labs/honcho) 是 Plastic Labs 开源的 **AI Agent 长期记忆后端**(v3.0.x,AGPL-3.0)。Hermes Agent 用它做跨会话的用户上下文管理(peer-centric 记忆、推理、检索)。本目录部署的是 **honcho-self-hosted**:基于 [elkimek/honcho-self-hosted](https://github.com/elkimek/honcho-self-hosted) 配置的本地化版本,集成到 `deploy.stack` 仓库规范下。
|
||||
|
||||
与官方 `docker-compose.yml.example` 的差异:本目录用 **PostgreSQL 18 + Redis 8**(非官方默认的 pg15/redis 8.2)、`${Volumes_Path}` bind 挂载(非 docker volume)、固定到内网可访问的端口。
|
||||
|
||||
## 目录结构
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `stack.yml` | Docker Compose 主文件(4 服务:api + deriver + database + redis) |
|
||||
| `env.cfg.example` | 公共环境变量模板(不含敏感信息,可提交) |
|
||||
| `env.cfg` | **敏感配置(gitignore,不提交)** — 实际部署时从 example 复制后填密码/API Key |
|
||||
| `readme.md` | 本文档 |
|
||||
|
||||
## 架构
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph src["源码构建期(无运行时 bind)"]
|
||||
source["${Volumes_Path}/honcho/source<br/>git clone plastic-labs/honcho<br/>api/deriver Dockerfile build context"]
|
||||
end
|
||||
|
||||
subgraph run["运行时 — honcho-net bridge"]
|
||||
api["<b>honcho-api</b><br/>FastAPI 主服务<br/>:8000 (0.0.0.0)<br/>build from source"]
|
||||
deriver["<b>honcho-deriver</b><br/>后台推理 worker<br/>消息→观察→peer representation<br/>build from source"]
|
||||
database["<b>honcho-database</b><br/>pgvector/pgvector:pg18<br/>:5432 (0.0.0.0)<br/>scram-sha-256"]
|
||||
redis["<b>honcho-redis</b><br/>redis:8<br/>:6379<br/>CACHE_URL"]
|
||||
end
|
||||
|
||||
subgraph host["宿主机持久化 (WSL ext4)"]
|
||||
pgdata["${Volumes_Path}/pgdata<br/>(bind mount)"]
|
||||
redisdata["${Volumes_Path}/redis<br/>(bind mount)"]
|
||||
end
|
||||
|
||||
subgraph external["外部调用方"]
|
||||
hermes["Hermes Agent<br/>memory.provider=honcho"]
|
||||
sdk["Python / TS SDK<br/>(honcho-ai / @honcho-ai/sdk)"]
|
||||
tools["DBeaver / psql<br/>PG 5432 直连"]
|
||||
siliconflow["SiliconFlow<br/>api.siliconflow.cn/v1<br/>Qwen3-Embedding-8B<br/>dimensions=1536<br/>(云端默认)"]
|
||||
ollama["本地 Ollama<br/>host.docker.internal:11434<br/>qwen3-embedding:0.6b<br/>(备选,零成本)"]
|
||||
end
|
||||
|
||||
source -.->|docker build<br/>首次 5-10 min| api
|
||||
source -.->|docker build| deriver
|
||||
|
||||
hermes -->|HTTP :8000| api
|
||||
sdk -->|HTTP :8000| api
|
||||
tools -->|:5432| database
|
||||
|
||||
api -->|:5432| database
|
||||
deriver -->|:5432| database
|
||||
api -->|:6379| redis
|
||||
deriver -->|:6379| redis
|
||||
deriver -.->|轮询<br/>pending messages| api
|
||||
api -->|HTTPS embedding<br/>Qwen3-8B 1536d| siliconflow
|
||||
deriver -->|HTTPS embedding<br/>Qwen3-8B 1536d| siliconflow
|
||||
|
||||
database --- pgdata
|
||||
redis --- redisdata
|
||||
|
||||
classDef ext fill:#e1f5ff,stroke:#01579b,color:#000
|
||||
classDef build fill:#fff3e0,stroke:#e65100,color:#000
|
||||
classDef data fill:#f3e5f5,stroke:#4a148c,color:#000
|
||||
classDef host fill:#e8f5e9,stroke:#1b5e20,color:#000
|
||||
|
||||
class hermes,sdk,tools,siliconflow,ollama ext
|
||||
class source build
|
||||
class api,deriver,database,redis ext
|
||||
class pgdata,redisdata data
|
||||
```
|
||||
|
||||
> **源码不在运行时 bind mount**:api/deriver 通过 `build: context: .` 从 `git clone` 的源码目录(`${Volumes_Path}/honcho/source`)构建,**不**挂源码进运行容器。`source/` 仅作为构建缓存,方便后续 `git pull` 后增量 rebuild。
|
||||
|
||||
**四个服务的职责:**
|
||||
|
||||
| 服务 | 角色 | 关键依赖 |
|
||||
|------|------|----------|
|
||||
| `api` | FastAPI 主服务,对外提供 REST API(端口 8000) | database、redis |
|
||||
| `deriver` | **后台推理 worker**:消息→观察→peer representation→session 摘要 | api(健康后才起)、database、redis |
|
||||
| `database` | PostgreSQL + pgvector 扩展,存所有 messages、peers、workspaces | — |
|
||||
| `redis` | 缓存层(`CACHE_URL=redis://redis:6379/0`) | — |
|
||||
|
||||
**⚠️ deriver 不可省**:没它,消息能写入 DB,但不会生成记忆、不会提取观察、不会做 session 摘要。Honcho 退化成纯 KV 存储。
|
||||
|
||||
## 端口
|
||||
|
||||
| 端口 | 服务 | 用途 |
|
||||
|------|------|------|
|
||||
| `8000` | api | Honcho REST API(供 Hermes / Python SDK / TypeScript SDK 调用) |
|
||||
| `5432` | database | PostgreSQL 对外访问(DBeaver、psql 等工具连接) |
|
||||
| `6379` | redis | Redis 对外访问(一般无需直连) |
|
||||
|
||||
宿主机端口可通过 `env.cfg` 中的 `HONCHO_API_PORT`、`HONCHO_DB_PORT`、`HONCHO_REDIS_PORT` 自定义。
|
||||
|
||||
## 环境变量
|
||||
|
||||
### 公共变量(`env.cfg.example`)
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `HONCHO_VERSION` | `main` | Honcho 主仓库 git ref(tag / branch / SHA 都可;源码 build 用) |
|
||||
| `HONCHO_BRANCH` | `main` | 源码 checkout 分支(`HONCHO_VERSION` 不是 branch 时生效) |
|
||||
| `HONCHO_DB_VERSION` | `18` | PostgreSQL 大版本号(pgvector 镜像 tag 后缀) |
|
||||
| `HONCHO_REDIS_VERSION` | `8` | Redis 大版本号 |
|
||||
| `HONCHO_DB_IMAGE` | `pgvector/pgvector` | DB 镜像仓库 |
|
||||
| `HONCHO_REDIS_IMAGE` | `redis` | Redis 镜像仓库 |
|
||||
| `HONCHO_DB_USER` | `honcho` | PostgreSQL 用户名 |
|
||||
| `HONCHO_DB_NAME` | `honcho` | PostgreSQL 数据库名 |
|
||||
| `HONCHO_DB_PASSWORD` | `honcho` | PostgreSQL 密码(**部署时必须改**) |
|
||||
| `POSTGRES_HOST_AUTH_METHOD` | `scram-sha-256` | PG 认证方式 |
|
||||
| `Volumes_Path` | `/data/Volumes/honcho` | 宿主机持久化数据根路径 |
|
||||
| `HONCHO_API_PORT` | `8000` | API 宿主机端口 |
|
||||
| `HONCHO_DB_PORT` | `5432` | PostgreSQL 宿主机端口 |
|
||||
| `HONCHO_REDIS_PORT` | `6379` | Redis 宿主机端口 |
|
||||
| `HONCHO_LOG_LEVEL` | `INFO` | Honcho 日志级别 |
|
||||
| `HONCHO_AUTH_USE_AUTH` | `false` | 是否启用 JWT 鉴权(生产建议 `true`) |
|
||||
| `HONCHO_NAMESPACE` | `honcho` | 全局命名空间前缀 |
|
||||
| `HONCHO_EMBED_MESSAGES` | `true` | 是否对消息做向量化(关闭可省 embedding 费用) |
|
||||
| `HONCHO_EMBEDDING_MODEL` | `Qwen/Qwen3-Embedding-8B` | Embedding 模型名(默认 SiliconFlow,可换本地 Ollama) |
|
||||
| `HONCHO_EMBEDDING_BASE_URL` | `https://api.siliconflow.cn/v1` | Embedding API Base URL(OpenAI 兼容;Ollama 改 `http://host.docker.internal:11434/v1`) |
|
||||
| `HONCHO_DERIVER_MODEL` | `gpt-5.4-mini` | Deriver 用的 LLM 模型(必须支持 tool calling) |
|
||||
| `HONCHO_LLM_BASE_URL` | `https://api.openai.com/v1` | LLM API Base URL(OpenAI 兼容端点即可) |
|
||||
| `HONCHO_DERIVER_WORKERS` | `1` | Deriver worker 数 |
|
||||
|
||||
### 敏感变量(`env.cfg`,不提交)
|
||||
|
||||
| 变量 | 说明 |
|
||||
|------|------|
|
||||
| `HONCHO_LLM_API_KEY` | LLM API Key(**必填**,server 启动检查,没它起不来) |
|
||||
| `HONCHO_EMBEDDING_API_KEY` | Embedding API Key(**必填**仅当走云端:SiliconFlow 在 [cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak) 生成;走 Ollama 时留空) |
|
||||
| `HONCHO_DB_PASSWORD` | PostgreSQL 密码(**必填**,用强密码) |
|
||||
| `HONCHO_AUTH_JWT_SECRET` | JWT 密钥(仅在 `HONCHO_AUTH_USE_AUTH=true` 时需要;用 `python scripts/generate_jwt_secret.py` 生成) |
|
||||
|
||||
**关键约束**:Honcho 启动时会**校验** `HONCHO_LLM_API_KEY` 和 `HONCHO_EMBEDDING_API_KEY` 都非空 — 缺失则立刻退出。这意味着 `env.cfg` 里这两项**不能用占位符**(如 `***`),必须填真实值,否则 `docker compose up -d` 后 deriver/api 容器会反复重启。
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 首次部署
|
||||
|
||||
```bash
|
||||
# 1. 准备数据目录(必须原生 ext4,不能放 9P drvfs)
|
||||
sudo mkdir -pv /data/Volumes/honcho/{pgdata,redis,source}
|
||||
sudo chown -R 999:999 /data/Volumes/honcho/pgdata
|
||||
sudo chown -R 999:999 /data/Volumes/honcho/redis
|
||||
|
||||
# 2. 复制 env 模板并填入真实值
|
||||
cp honcho/env.cfg.example honcho/env.cfg
|
||||
$EDITOR honcho/env.cfg
|
||||
# 必填:HONCHO_LLM_API_KEY(不能用空值/默认值,否则 deriver 起不来)
|
||||
# 必填:HONCHO_DB_PASSWORD(改成强密码)
|
||||
# 推荐改:HONCHO_DB_USER / HONCHO_DB_NAME(默认值 honcho 仅 dev 可用)
|
||||
|
||||
# 3. 拉镜像(PG + Redis 是预构建;api/deriver 从源码 build)
|
||||
docker compose --env-file ./honcho/env.cfg -f ./honcho/stack.yml pull
|
||||
|
||||
# 4. 构建 + 启动(首次 api/deriver 构建需 5-10 分钟,依赖网络)
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml up -d --build
|
||||
```
|
||||
|
||||
### 验证
|
||||
|
||||
```bash
|
||||
# 容器状态(必须 4 个都 healthy)
|
||||
docker ps -f name=honcho
|
||||
|
||||
# API 健康检查
|
||||
curl -s http://localhost:8000/health
|
||||
|
||||
# 数据库连接
|
||||
docker exec -it honcho-database psql -U honcho -d honcho -c '\dt'
|
||||
|
||||
# pgvector 扩展确认
|
||||
docker exec -it honcho-database psql -U honcho -d honcho \
|
||||
-c "SELECT extname FROM pg_extension WHERE extname='vector';"
|
||||
|
||||
# Redis 连接
|
||||
docker exec -it honcho-redis redis-cli ping
|
||||
# 期望输出:PONG
|
||||
|
||||
# deriver 日志(看是否成功处理消息)
|
||||
docker logs -f honcho-deriver --tail 50
|
||||
|
||||
# 端口监听
|
||||
ss -tlnp | grep -E '8000|5432|6379'
|
||||
```
|
||||
|
||||
### 停止/重启
|
||||
|
||||
```bash
|
||||
# 停止(保留数据)
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml stop
|
||||
|
||||
# 完全销毁(**数据不删**,bind 挂载保留在宿主机)
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml down
|
||||
|
||||
# 重启
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml restart
|
||||
```
|
||||
|
||||
## 关键设计决策
|
||||
|
||||
| 决策点 | 决定 | 原因 |
|
||||
|--------|------|------|
|
||||
| 镜像源 | api/deriver 从 [plastic-labs/honcho](https://github.com/plastic-labs/honcho) **源码 build** | 官方**没有预构建镜像**,Docker Hub 也没 — 必须 build |
|
||||
| DB 版本 | PostgreSQL 18(pgvector 镜像 `pg18` tag) | 用户指定,比官方默认 pg15 新 |
|
||||
| Redis 版本 | Redis 8 | 用户指定 |
|
||||
| 数据卷方案 | bind 挂载到 `${Volumes_Path}/{pgdata,redis,source}` | 直观、可直接 `rsync`/`pg_dump`、跨机迁移用 `tar` 整个目录即可 |
|
||||
| 端口绑定 | 0.0.0.0,含 DB 5432 | PVE LAN 上其他 VM 也可访问;DB 端口暴露方便外部工具(DBeaver 等)连接 |
|
||||
| 认证 | 默认 `HONCHO_AUTH_USE_AUTH=false`(dev 模式) | 本地 LAN 自用,跳过 JWT 校验;公网暴露必须改 `true` |
|
||||
| LLM 默认 | `gpt-5.4-mini`(主 LLM,OpenAI 兼容);embedding 默认 `Qwen/Qwen3-Embedding-8B`(dimensions=1536 强制输出,兼容已有 1536 维 schema)走 SiliconFlow;**备选** 本地 Ollama `qwen3-embedding:0.6b`(零成本、隐私优先) | LLM 走 OpenAI 兼容;embedding 双轨:SiliconFlow(云端,独立 base URL) / Ollama(本地 `host.docker.internal:11434/v1`) |
|
||||
| Honcho 版本 | 默认 `main`(源码 build),可锁 tag 如 `v3.0.10` | 当前最新稳定版 v3.0.x,支持 peer card、dialectic、dream consolidation |
|
||||
| deriver 必须 | api + deriver 双容器 | deriver 是后台推理 worker,没它记忆功能不工作 |
|
||||
| PG 认证 | `scram-sha-256` | 比 md5 更安全,`POSTGRES_INITDB_ARGS` 同步设置 `--auth-host` |
|
||||
|
||||
## 关键陷阱(必读)
|
||||
|
||||
### 1. 首次构建时间长且需要 BuildKit
|
||||
|
||||
```bash
|
||||
# 必须开启 BuildKit(默认 20.10+ 已启用,但确认下)
|
||||
DOCKER_BUILDKIT=1 docker compose ...
|
||||
```
|
||||
|
||||
- 首次 build api/deriver 镜像需 **5-10 分钟**(拉源码 + uv sync Python 依赖 + pip install ~300MB)
|
||||
- 后续增量构建快(除非 Honcho 自身依赖变更)
|
||||
- 构建失败常见原因:网络拉 `astral-sh/uv` 慢、Python wheel 编译失败 — 配置 Docker 镜像加速
|
||||
|
||||
### 2. deriver 必须健康,否则记忆不工作
|
||||
|
||||
如果只看到 `honcho-api` 是 `healthy` 但 `honcho-deriver` 反复重启或卡在 startup,**消息会写入但不会产生任何记忆**。检查:
|
||||
|
||||
```bash
|
||||
docker logs honcho-deriver --tail 100 | grep -iE "error|fatal"
|
||||
```
|
||||
|
||||
deriver 起不来最常见原因:
|
||||
- `HONCHO_LLM_API_KEY` 为空/无效 — server 启动立即校验
|
||||
- LLM 模型不支持 tool calling — deriver 强依赖 function calling
|
||||
- LLM API base URL 配错(如少了 `/v1` 后缀)
|
||||
|
||||
### 3. AGPL-3.0 传染条款
|
||||
|
||||
Honcho 是 **AGPL-3.0**,对网络服务部署有"用户可获取源码"的要求。本地 LAN 自用不触发,但若对外提供服务(哪怕只是 API 反代),需考虑:
|
||||
- 对外服务时 `AUTH_USE_AUTH=true` + 公开 `AUTH_JWT_SECRET` 之外,**还需要向用户公开 Honcho 源码修改**
|
||||
- 详见 [AGPL-3.0 §13](https://www.gnu.org/licenses/agpl-3.0.html)
|
||||
|
||||
### 4. WSL 9P `fsync` 陷阱
|
||||
|
||||
**PG/Redis 数据绝不能放 `/mnt/c/`、`/mnt/d/` 等 9P drvfs 路径**。`${Volumes_Path}` 必须指向 WSL 原生 ext4(`/data/Volumes/honcho`),否则可能静默数据损坏。
|
||||
|
||||
### 5. `POSTGRES_HOST_AUTH_METHOD=trust` 已删除
|
||||
|
||||
honcho-self-hosted 相对官方 compose 的一个改进:**移除了**`trust` 认证(官方默认的 dev 用法),改用强密码 + scram-sha-256。生产环境务必保留这个设置。
|
||||
|
||||
### 6. 容器端口 vs 宿主机端口不可混用
|
||||
|
||||
**容器之间互访必须用容器内端口(5432/6379/8000)**,不能用宿主机映射端口(如 `HONCHO_DB_PORT=25432`)。错误示例:
|
||||
|
||||
```yaml
|
||||
# ❌ 错:${HONCHO_DB_PORT} 是宿主机端口 25432,容器内根本没监听这个
|
||||
DB_CONNECTION_URI=postgresql+psycopg://honcho:pw@database:${HONCHO_DB_PORT}/honcho
|
||||
|
||||
# ✅ 对:硬编码容器内端口 5432
|
||||
DB_CONNECTION_URI=postgresql+psycopg://honcho:pw@database:5432/honcho
|
||||
```
|
||||
|
||||
同样 healthcheck 也用容器内端口 `localhost:8000`,**不是** `localhost:18000`(宿主映射端口)。
|
||||
|
||||
## 故障排查
|
||||
|
||||
| 症状 | 排查命令 |
|
||||
|------|----------|
|
||||
| api 容器起不来 | `docker logs -f honcho-api` — 通常是 `LLM_OPENAI_API_KEY is required` 或 DB 连接失败 |
|
||||
| deriver 反复重启 | `docker logs -f honcho-deriver` — 检查 LLM key、模型名、base URL |
|
||||
| DB 连不上(容器内) | `docker exec -it honcho-database psql -U honcho -d honcho` |
|
||||
| DB 连不上(外部工具) | 确认 `HONCHO_DB_PORT` 已映射、`ss -tlnp` 检查 5432 监听;密码含特殊字符试改简单 |
|
||||
| API `/health` 502/超时 | 检查 deriver 是否 healthy(`depends_on` 会卡住 api) |
|
||||
| pgvector 扩展缺失 | `docker exec -it honcho-database psql -U honcho -d honcho -c "CREATE EXTENSION IF NOT EXISTS vector;"` |
|
||||
| 端口冲突 | `ss -tlnp \| grep -E '8000\|5432\|6379'` — 检查是否与 hindsight/dbSer 等服务撞车 |
|
||||
| 慢查询 / DB 锁 | `docker exec -it honcho-database psql -U honcho -d honcho -c "SELECT * FROM pg_stat_activity;"` |
|
||||
| 密码含特殊字符连不上 | `HONCHO_DB_PASSWORD` 最好只用字母数字,避免 URI 编码问题;如必须用,把 URL 里特殊字符 percent-encode |
|
||||
|
||||
## 与 Hermes Agent 集成
|
||||
|
||||
Hermes plugin 通过 HTTP 调用 Honcho 的 REST API(`localhost:8000`),不直连 DB。配置在 `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
provider: honcho
|
||||
honcho:
|
||||
api_url: http://localhost:8000
|
||||
# api_key 不需要(本地自托管,AUTH_USE_AUTH=false)
|
||||
workspace_id: hermes
|
||||
auto_recall: true
|
||||
auto_retain: true
|
||||
```
|
||||
|
||||
切换命令:`hermes config set memory.provider honcho`
|
||||
|
||||
**与 Hindsight 的差异**:
|
||||
- Hindsight 强调 **跨会话长期记忆**(基于时序、bi-temporal)
|
||||
- Honcho 强调 **peer-centric 用户画像**(多 peer 互观察、推理、deduction)
|
||||
- 两者可并存;Hermes 当前用 Honcho 做主记忆层,Hindsight 作为补充
|
||||
|
||||
## 备份与恢复
|
||||
|
||||
### 自动备份(推荐)
|
||||
|
||||
`backup.job`(待补)— 用 `pg_dump` 热备份 PG + `redis-cli BGSAVE` 备份 Redis。接入 cron:
|
||||
|
||||
```bash
|
||||
# /etc/cron.d/honcho-backup
|
||||
30 3 * * * /path/to/deploy.stack/honcho/backup.job >> /var/log/honcho-backup.log 2>&1
|
||||
```
|
||||
|
||||
或参考 `crontab/` 目录的统一任务管理方式。
|
||||
|
||||
### 手动备份
|
||||
|
||||
```bash
|
||||
# PG 热备份
|
||||
docker exec honcho-database pg_dump -U honcho -d honcho | \
|
||||
gzip > /data/Volumes/honcho/backups/honcho_$(date +%Y%m%d).sql.gz
|
||||
|
||||
# Redis 快照
|
||||
docker exec honcho-redis redis-cli BGSAVE
|
||||
# 触发后 /data/Volumes/honcho/redis/dump.rdb 是最新快照
|
||||
```
|
||||
|
||||
### 恢复
|
||||
|
||||
```bash
|
||||
# 从 pg_dump 恢复(需要先创建空 DB)
|
||||
gunzip -c /data/Volumes/honcho/backups/honcho_20260619.sql.gz | \
|
||||
docker exec -i honcho-database psql -U honcho -d honcho
|
||||
|
||||
# 从 Redis dump 恢复
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml stop honcho-redis
|
||||
sudo cp /data/Volumes/honcho/backups/dump.rdb /data/Volumes/honcho/redis/dump.rdb
|
||||
sudo chown 999:999 /data/Volumes/honcho/redis/dump.rdb
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml start honcho-redis
|
||||
```
|
||||
|
||||
## 升级
|
||||
|
||||
```bash
|
||||
# 1. 拉取最新源码(在 host 上或临时容器)
|
||||
cd /data/Volumes/honcho/source && git pull
|
||||
|
||||
# 2. 重建 api + deriver 镜像
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml build api deriver
|
||||
|
||||
# 3. 滚动重启
|
||||
docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml up -d
|
||||
|
||||
# 4. 跑迁移(honcho entrypoint.sh 会自动执行;若需手动跑)
|
||||
docker exec -it honcho-api sh -c "cd /app && .venv/bin/alembic upgrade head"
|
||||
```
|
||||
|
||||
**PG 大版本升级**(如未来 18→19)需 `pg_dump` → 新版本空 DB → restore,**不能直接换 tag**。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [plastic-labs/honcho](https://github.com/plastic-labs/honcho) — 上游仓库
|
||||
- [elkimek/honcho-self-hosted](https://github.com/elkimek/honcho-self-hosted) — 一键安装器,本目录配置基于此
|
||||
- [Honcho 自托管官方文档](https://honcho.dev/docs/v3/contributing/self-hosting)
|
||||
- `hindsight/readme.md` — 同仓库姊妹服务,部署模式高度相似
|
||||
- 仓库根 `AGENTS.md` — `deploy.stack` 项目规范
|
||||
- `crontab/` — 定时任务集成参考
|
||||
|
||||
## 已知限制
|
||||
|
||||
详见上文 [关键陷阱](#关键陷阱必读) — 主要为:无预构建镜像(必须源码构建)/ AGPL-3.0 传染 / deriver 强依赖 LLM。
|
||||
@@ -0,0 +1,285 @@
|
||||
# Honcho 多 Hermes 客户端共享方案
|
||||
|
||||
> 状态: 📝 草案 (2026-06-20 创建, 06-26 拓扑修正 + v3.0.10 schema 探针重写)
|
||||
> 适用: vm61 (10.8.0.9, 备用/测试环境) 部署 honcho v3.0.10 + 3 个 hermes 客户端共享同一份记忆
|
||||
|
||||
---
|
||||
|
||||
## 1. 场景
|
||||
|
||||
| 客户端 | 位置 | WireGuard IP | 网络到 vm61 | peer 名 |
|
||||
|---|---|---|---|---|
|
||||
| mypc03 (WSL Debian) | 🏠 家里 LAN | `10.8.0.112` | WireGuard → vm61 | `laodeng-mypc03x` |
|
||||
| gov-pc (公司机器) | 🏢 公司 | `10.8.0.143` | WireGuard → vm61 | `laodeng-govpcxxxx` |
|
||||
| macbook | ☕ 任意位置 | `10.8.0.144` | WireGuard → vm61 | `laodeng-macxxxxxxx` |
|
||||
|
||||
**3 个客户端都是老登本人**用,所以希望:
|
||||
- ✅ **共享 workspace**(`home`):在 A 上聊的事,B 上能召回
|
||||
- ✅ **peer 独立**(带设备后缀):方便审计"在哪台设备说的"
|
||||
- ✅ **AUTH 关闭(DEV 模式)**:vm61 honcho v3.0.10 实例 `USE_AUTH=False`,JWT_SECRET 留空,peer 不强制鉴权;接入稳后再开
|
||||
- ❌ 不共享 LLM 凭据:每个客户端用自己的 hermes LLM key
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Clients["3 个 Hermes 客户端"]
|
||||
A[mypc03<br/>peer: laodeng-mypc03x]
|
||||
B[gov-pc<br/>peer: laodeng-govpcxxxx]
|
||||
C[macbook<br/>peer: laodeng-macxxxxxxx]
|
||||
end
|
||||
|
||||
subgraph Vm61["vm61 (192.168.10.61 / WG 10.8.0.9, 备用)"]
|
||||
WG[WireGuard<br/>10.8.0.9 入口]
|
||||
API[honcho-api:8000<br/>AUTH OFF (v3 DEV)]
|
||||
DB[(postgres+pgvector)]
|
||||
DERIVER[honcho-deriver<br/>~2 done/min]
|
||||
REDIS[(redis)]
|
||||
end
|
||||
|
||||
A ==wg==> WG
|
||||
B ==wg==> WG
|
||||
C ==wg==> WG
|
||||
WG --> API
|
||||
API --> DB
|
||||
API --> REDIS
|
||||
DERIVER <--> REDIS
|
||||
DERIVER <--> DB
|
||||
|
||||
classDef client fill:#e1f5ff,stroke:#0066cc
|
||||
classDef svc fill:#fff4e1,stroke:#cc6600
|
||||
classDef store fill:#e8f5e9,stroke:#2e7d32
|
||||
class A,B,C client
|
||||
class WG,API,DERIVER svc
|
||||
class DB,REDIS store
|
||||
```
|
||||
|
||||
**网络**:3 客户端 (10.8.0.112/143/144) → WireGuard 隧道 (10.8.0.x) → vm61 (10.8.0.9) 8000
|
||||
|
||||
---
|
||||
|
||||
## 3. 为什么这样设计
|
||||
|
||||
| 决策 | 选择 | 替代方案 | 理由 |
|
||||
|---|---|---|---|
|
||||
| **AUTH 关闭(DEV)** | ✅ OFF | ON | 当前 vm61 honcho v3.0.10 `USE_AUTH=False`;3 客户端同源(同老登)+ WireGuard 内网隔离已足够;生产或多人共用必须开 |
|
||||
| **Workspace** | `home` 一个共用 | 每个 peer 独立 ws | 老登本人用,跨设备回忆体验更好 |
|
||||
| **Peer** | 带设备后缀 | 统一 `laodeng` | 审计需要知道"哪台设备写的";peer 概念在 honcho 里是身份,不影响记忆语义 |
|
||||
| **API URL** | `http://10.8.0.9:18000`(vm61 WireGuard IP) | 公网 IP / 域名 | WireGuard 已加密 + 认证,没必要再绕公网 |
|
||||
| **LLM 凭据** | 客户端本地保留 | 共享到 honcho | deriver 已经持有全局 LLM key;客户端 hermes 自己的对话 LLM 不应上送 honcho |
|
||||
| **deriver 后台** | 共享 vm61 上现有 | 每客户端本地跑 | honcho deriver 设计就是单实例后台,集中推理更省 API 配额 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 实施步骤
|
||||
|
||||
### Phase 1: vm61 上 honcho 准备
|
||||
|
||||
```bash
|
||||
# 1.1 确认 4 个容器 Up
|
||||
docker ps | grep -E "honcho-(api|deriver|database|redis)"
|
||||
|
||||
# 1.2 确认 AUTH 状态(v3.0.10 实际为 DEV OFF,2026-06-26 探针实测)
|
||||
ssh yong@10.8.0.9 'docker exec honcho-api python3 -c "from src.config import settings; print(\"USE_AUTH:\", settings.AUTH.USE_AUTH)"'
|
||||
# 期望: USE_AUTH: False(当前状态)
|
||||
|
||||
# 1.3 确认 honcho-api 监听 0.0.0.0(不是 127.0.0.1)
|
||||
docker inspect honcho-api | grep -A2 -E "HostPort|NetworkMode"
|
||||
# 或直接看启动日志
|
||||
docker logs honcho-api 2>&1 | grep -i "listening"
|
||||
|
||||
# 1.4 从 WireGuard 网卡验证
|
||||
curl -s http://10.8.0.9:18000/health
|
||||
# 期望: {"status":"ok"}
|
||||
```
|
||||
|
||||
**如果 1.3 / 1.4 失败**:
|
||||
- stack.yml 里 `ports:` 必须暴露 `0.0.0.0:18000:18000`
|
||||
- 6-19 修过的 `DB_CONNECTION_URI` / `CACHE_URL` 已稳定,但确认 WireGuard 网卡没被 firewall 拦
|
||||
|
||||
### Phase 2: v3 鉴权模式 + peer 创建
|
||||
|
||||
**v3.0.10 实测 schema(2026-06-26 探针)**:
|
||||
|
||||
| 关键事实 | 说明 |
|
||||
|---|---|
|
||||
| 端点前缀 | **/v3/**(不是 /v2/) |
|
||||
| 鉴权 | `HTTPBearer(auto_error=False)` — 未带 token 放行(DEV 模式表现) |
|
||||
| `AUTH.USE_AUTH` 开关 | False 时所有 peer 操作无需 token;True 时需 admin JWT |
|
||||
| 创建 JWT 端点 | `POST /v3/keys?workspace_id=&peer_id=&session_id=`(admin auth 强制) |
|
||||
| 创建 workspace | `POST /v3/workspaces` body `{"id":"home"}` |
|
||||
| 创建 peer | `POST /v3/workspaces/{ws_id}/peers` body `{"id":"<peer_id>"}` |
|
||||
| Peer ID 格式 | text 21 字符,`^[A-Za-z0-9_-]+$`(**不是 UUID**) |
|
||||
| DB schema | `peers(id PK text, name text, workspace_name FK→workspaces(name))` |
|
||||
| DB schema | **无 `api_keys` 表**(v3 用 JWT,无独立 key 表) |
|
||||
|
||||
**当前 DEV 模式(USE_AUTH=False)下,3 客户端接入步骤**:
|
||||
|
||||
```bash
|
||||
# 2.1 确认 workspace 已存在
|
||||
ssh yong@10.8.0.9 'curl -s -X POST http://127.0.0.1:18000/v3/workspaces \
|
||||
-H "Content-Type: application/json" -d "{\"id\":\"home\"}"'
|
||||
# 期望: {"id":"home",...} 或已存在返回
|
||||
|
||||
# 2.2 创建 3 个 peer(peer_id 必须 21 字符,格式 ^[A-Za-z0-9_-]+$)
|
||||
for PEER in laodeng-mypc03x laodeng-govpcxxxx laodeng-macxxxxxxx; do
|
||||
ssh yong@10.8.0.9 "curl -s -X POST http://127.0.0.1:18000/v3/workspaces/home/peers \
|
||||
-H 'Content-Type: application/json' -d '{\"id\":\"$PEER\"}'"
|
||||
echo "--- $PEER done ---"
|
||||
done
|
||||
# 期望: 3 个 200 OK 返回 peer 对象
|
||||
```
|
||||
|
||||
**未来开 AUTH(USE_AUTH=True)时**:每个 peer 创建后用 `POST /v3/keys?workspace_id=home&peer_id=<id>` 拿 scoped JWT,scp 到客户端 `~/.honcho-keys/<peer>.key`,hermes config `memory.honcho.api_key` 填 JWT。
|
||||
|
||||
### Phase 3: 3 客户端配置 hermes
|
||||
|
||||
每台机器执行(**当前 DEV 模式不填 api_key;AUTH 开后填 JWT**):
|
||||
|
||||
```bash
|
||||
# 通用(3 台都跑)
|
||||
hermes config set memory.provider honcho
|
||||
hermes config set memory.honcho.api_url http://10.8.0.9:18000
|
||||
hermes config set memory.honcho.workspace home
|
||||
|
||||
# mypc03
|
||||
hermes config set memory.honcho.peer laodeng-mypc03x
|
||||
|
||||
# gov-pc
|
||||
hermes config set memory.honcho.peer laodeng-govpcxxxx
|
||||
|
||||
# macbook
|
||||
hermes config set memory.honcho.peer laodeng-macxxxxxxx
|
||||
```
|
||||
|
||||
### Phase 4: 交叉验证(关键!)
|
||||
|
||||
**Step A: 网络 + honcho 响应**(3 台机器各跑)
|
||||
|
||||
```bash
|
||||
# DEV 模式不带 token 也能访问
|
||||
curl -s -o /dev/null -w "HTTP %{http_code}\n" \
|
||||
http://10.8.0.9:18000/v3/workspaces/home/peers
|
||||
# 期望: HTTP 200
|
||||
```
|
||||
|
||||
**未来 AUTH 开启后改用**:
|
||||
```bash
|
||||
curl -s -o /dev/null -w "HTTP %{http_code}\n" \
|
||||
-H "Authorization: Bearer $(cat ~/.honcho-keys/xxx.key)" \
|
||||
http://10.8.0.9:18000/v3/workspaces/home/peers
|
||||
```
|
||||
|
||||
**Step B: 跨端召回**
|
||||
|
||||
```bash
|
||||
# mypc03 写一条
|
||||
hermes memory retain "2026-06-26 mypc03 测试 honcho v3 跨设备共享"
|
||||
|
||||
# gov-pc 召回
|
||||
hermes memory recall "honcho v3 跨设备共享"
|
||||
# 期望: 看到 mypc03 写的那条
|
||||
```
|
||||
|
||||
**Step C: 隔离验证(确认 peer 字段)**
|
||||
|
||||
```bash
|
||||
# honcho 管理(vm61 上)— 注意 v3 列名是 workspace_name 不是 workspace
|
||||
ssh yong@10.8.0.9 'docker exec honcho-database psql -U honcho -d honcho -c \
|
||||
"SELECT name, created_at FROM peers WHERE workspace_name = '\''home'\'';"'
|
||||
# 期望: 3 行,name 各不相同(带设备后缀)
|
||||
```
|
||||
|
||||
### Phase 5: deriver 容量观察
|
||||
|
||||
接入第 3 个客户端后,前 2 天重点观察:
|
||||
|
||||
```bash
|
||||
# vm61 看 deriver 进度
|
||||
docker logs honcho-deriver --since 1h | grep -E "queue|processed|done"
|
||||
|
||||
# 队列深度(v3 端点)
|
||||
ssh yong@10.8.0.9 'curl -s http://127.0.0.1:18000/v3/workspaces/home/queue/status' | jq
|
||||
```
|
||||
|
||||
**告警阈值**:
|
||||
|
||||
| 指标 | 正常 | 警告 | 干预 |
|
||||
|---|---|---|---|
|
||||
| 队列深度 | < 500 | 500-2000 | > 2000 持续 1h → 考虑错峰 |
|
||||
| deriver done/min | 2-4 | 4-8 | > 8 持续 → 加 worker |
|
||||
| Postgres 连接 | < 50 | 50-100 | > 100 → 调大 max_connections |
|
||||
|
||||
---
|
||||
|
||||
## 5. 故障排查
|
||||
|
||||
| 症状 | 排查 | 修复 |
|
||||
|---|---|---|
|
||||
| `curl HTTP 401` | AUTH 已开但缺 token / token 过期 | 重新创建 JWT(`POST /v3/keys?workspace_id=home`) |
|
||||
| `curl HTTP 422` | peer_id 格式不符(必须 21 字符 `^[A-Za-z0-9_-]+$`) | 调整 peer_id 长度/字符 |
|
||||
| `curl HTTP 404` | workspace 名错 | `hermes config get memory.honcho.workspace` 必须 = `home` |
|
||||
| `curl timeout` | WireGuard 没拨上 | `wg show` 看握手时间;`ping 10.8.0.9` |
|
||||
| 召回不到 mypc03 写的 | peer 不在同一 workspace | 三台 `hermes config get memory.honcho.workspace` 都该是 `home` |
|
||||
| deriver 队列暴涨 | LLM 限流(SiliconFlow) | 临时调低 deriver 并发;或加备份 LLM endpoint |
|
||||
| honcho-api OOM | 写入太频繁 | `docker stats honcho-api`;考虑加 limit |
|
||||
|
||||
---
|
||||
|
||||
## 6. 撤销 / 隔离某个客户端
|
||||
|
||||
需要把 gov-pc 从共享里踢出去(换工作 / 借人):
|
||||
|
||||
**DEV 模式**:直接删 peer(v3 REST)
|
||||
|
||||
```bash
|
||||
# v3 REST 删除 peer(DEV 模式不带 token)
|
||||
ssh yong@10.8.0.9 'curl -s -X DELETE \
|
||||
http://127.0.0.1:18000/v3/workspaces/home/peers/laodeng-govpcxxxx'
|
||||
```
|
||||
|
||||
**AUTH 开启后**:先删 JWT,再删 peer
|
||||
|
||||
```bash
|
||||
# 1. 服务端撤 JWT(v3 没有 api_keys 表;JWT 自身无法服务端 revoke,只能靠短期 exp)
|
||||
# 解决:缩短 JWT exp(如 24h),或重新生成 admin token 改 settings.AUTH
|
||||
|
||||
# 2. 删 peer
|
||||
ssh yong@10.8.0.9 'curl -s -X DELETE \
|
||||
-H "Authorization: Bearer $(cat /root/.honcho-keys/admin.key)" \
|
||||
http://127.0.0.1:18000/v3/workspaces/home/peers/laodeng-govpcxxxx'
|
||||
```
|
||||
|
||||
**清理历史消息**(如要彻底删除 gov-pc 的数据):
|
||||
|
||||
```sql
|
||||
-- v3 schema: peer_id 是 text 不是 UUID;name 是 peer 的可读名
|
||||
DELETE FROM messages WHERE peer_id = (SELECT id FROM peers WHERE name = 'laodeng-govpcxxxx');
|
||||
DELETE FROM session_peers WHERE peer_id = (SELECT id FROM peers WHERE name = 'laodeng-govpcxxxx');
|
||||
DELETE FROM peers WHERE name = 'laodeng-govpcxxxx';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 关联资源
|
||||
|
||||
| 资源 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| honcho stack | `deploy.stack/honcho/` | 当前部署 |
|
||||
| WireGuard 部署 | `deploy.stack/WireGuardVPN/wg-easy/` | 已有,给 3 客户端分配 10.8.0.112/143/144,honcho 服务端在 10.8.0.9 |
|
||||
| honcho deriver 调试 | honcho memory (2026-06-19/20) | deriver 修复历史 |
|
||||
| Hermes memory provider 切换 | hermes-agent skill | `memory.provider honcho` 配法 |
|
||||
| 凭据管理 | `~/.honcho-keys/` | chmod 600,绝不入 git;DEV 模式暂未启用 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续 TODO(可选)
|
||||
|
||||
- [ ] 把 `memory.honcho.api_url` 改成 hostname 而非 IP(DNS 友好)
|
||||
- [ ] 给 honcho-api 加 TLS(自签 CA 推 3 客户端)
|
||||
- [ ] deriver 加 Prometheus exporter,接 vm61 VictoriaMetrics
|
||||
- [ ] cron: 每天 pg_dump honcho DB → dufs 备份(参考 hindsight/backup.job)
|
||||
- [ ] 4 个客户端的 hermes 版本统一(避免 protocol 不一致)
|
||||
- [ ] 评估何时开 AUTH(USE_AUTH=True)+ 配 scoped JWT 体系
|
||||
@@ -0,0 +1,173 @@
|
||||
# Honcho Self-Hosted 部署栈
|
||||
# ============================================================
|
||||
# 部署前准备(仅首次):
|
||||
# mkdir -pv ${Volumes_Path}/{pgdata,redis,source}
|
||||
# sudo chown -R 999:999 ${Volumes_Path}/pgdata
|
||||
# sudo chown -R 999:999 ${Volumes_Path}/redis
|
||||
# git clone https://github.com/plastic-labs/honcho.git ${Volumes_Path}/honcho/source
|
||||
# cp env.cfg.example env.cfg && $EDITOR env.cfg # 填入密码/API Key
|
||||
#
|
||||
# pull:: docker compose --env-file ./honcho/env.cfg -f ./honcho/stack.yml pull
|
||||
# RUN:: docker compose -p honcho --env-file ./honcho/env.cfg -f ./honcho/stack.yml up -d --build
|
||||
# disc::
|
||||
# - api/deriver 从 ${Volumes_Path}/honcho/source 源码 build(不是运行时 bind)
|
||||
# - DB/Redis 数据 bind 挂到 WSL/Linux 原生 ext4(不能放 /mnt/9P drvfs)
|
||||
# - 端口 8000=API, 5432=PG, 6379=Redis,全部绑定 0.0.0.0 供 LAN 访问
|
||||
# - 必须设置 HONCHO_LLM_API_KEY(占位符会导致 deriver 反复重启)
|
||||
# - deriver 不可省:没它消息能写但不会产生记忆
|
||||
# - PG 5432 与 hindsight/dbSer 撞车,通过 HONCHO_DB_PORT 区分
|
||||
# ============================================================
|
||||
|
||||
services:
|
||||
api:
|
||||
build:
|
||||
context: ${Volumes_Path}/source
|
||||
dockerfile: Dockerfile
|
||||
container_name: honcho-api
|
||||
restart: unless-stopped
|
||||
entrypoint: ["sh", "docker/entrypoint.sh"]
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "${HONCHO_API_PORT:-8000}:8000"
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- DB_CONNECTION_URI=postgresql+psycopg://${HONCHO_DB_USER}:${HONCHO_DB_PASSWORD}@database:5432/${HONCHO_DB_NAME}
|
||||
- CACHE_URL=redis://redis:${HONCHO_REDIS_PORT}/0?suppress=true
|
||||
- CACHE_ENABLED=true
|
||||
- LOG_LEVEL=${HONCHO_LOG_LEVEL:-INFO}
|
||||
- NAMESPACE=${HONCHO_NAMESPACE:-honcho}
|
||||
- EMBED_MESSAGES=${HONCHO_EMBED_MESSAGES:-true}
|
||||
- EMBEDDING_MODEL_CONFIG__TRANSPORT=openai
|
||||
- EMBEDDING_MODEL_CONFIG__MODEL=${HONCHO_EMBEDDING_MODEL:-Qwen/Qwen3-Embedding-8B}
|
||||
- EMBEDDING_MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_EMBEDDING_BASE_URL:-https://api.siliconflow.cn/v1}
|
||||
- EMBEDDING_MODEL_CONFIG__OVERRIDES__DIMENSIONS=1536
|
||||
- EMBEDDING_VECTOR_DIMENSIONS=1536
|
||||
- EMBEDDING_API_KEY=${HONCHO_EMBEDDING_API_KEY:-}
|
||||
- DERIVER_MODEL_CONFIG__TRANSPORT=openai
|
||||
- DERIVER_MODEL_CONFIG__MODEL=${HONCHO_DERIVER_MODEL:-gpt-4o-mini}
|
||||
- DERIVER_WORKERS=${HONCHO_DERIVER_WORKERS:-1}
|
||||
- LLM_OPENAI_API_KEY=${HONCHO_LLM_API_KEY:?set HONCHO_LLM_API_KEY}
|
||||
- MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_LLM_BASE_URL:-https://api.openai.com/v1}
|
||||
- AUTH_USE_AUTH=${HONCHO_AUTH_USE_AUTH:-false}
|
||||
- AUTH_JWT_SECRET=${HONCHO_AUTH_JWT_SECRET}
|
||||
- VECTOR_STORE_TYPE=pgvector
|
||||
- VECTOR_STORE_MIGRATED=false
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- /app/.venv/bin/python
|
||||
- -c
|
||||
- "import urllib.request; urllib.request.urlopen('http://localhost:8000/health', timeout=2).read()"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- honcho-net
|
||||
|
||||
deriver:
|
||||
build:
|
||||
context: ${Volumes_Path}/source
|
||||
dockerfile: Dockerfile
|
||||
container_name: honcho-deriver
|
||||
restart: unless-stopped
|
||||
entrypoint: ["/app/.venv/bin/python", "-m", "src.deriver"]
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_healthy
|
||||
database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- DB_CONNECTION_URI=postgresql+psycopg://${HONCHO_DB_USER}:${HONCHO_DB_PASSWORD}@database:5432/${HONCHO_DB_NAME}
|
||||
- CACHE_URL=redis://redis:${HONCHO_REDIS_PORT}/0?suppress=true
|
||||
- CACHE_ENABLED=true
|
||||
- NAMESPACE=${HONCHO_NAMESPACE:-honcho}
|
||||
- DERIVER_MODEL_CONFIG__TRANSPORT=openai
|
||||
- DERIVER_MODEL_CONFIG__MODEL=${HONCHO_DERIVER_MODEL:-deepseek-ai/DeepSeek-V4-Flash}
|
||||
- DERIVER_MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_LLM_BASE_URL:-https://api.siliconflow.cn/v1}
|
||||
- DEDUCTION_MODEL_CONFIG__TRANSPORT=openai
|
||||
- DEDUCTION_MODEL_CONFIG__MODEL=${HONCHO_DEDUCTION_MODEL:-deepseek-ai/DeepSeek-V4-Flash}
|
||||
- DEDUCTION_MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_LLM_BASE_URL:-https://api.siliconflow.cn/v1}
|
||||
- INDUCTION_MODEL_CONFIG__TRANSPORT=openai
|
||||
- INDUCTION_MODEL_CONFIG__MODEL=${HONCHO_INDUCTION_MODEL:-deepseek-ai/DeepSeek-V4-Flash}
|
||||
- INDUCTION_MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_LLM_BASE_URL:-https://api.siliconflow.cn/v1}
|
||||
- DERIVER_WORKERS=${HONCHO_DERIVER_WORKERS:-1}
|
||||
- EMBEDDING_MODEL_CONFIG__TRANSPORT=openai
|
||||
- EMBEDDING_MODEL_CONFIG__MODEL=${HONCHO_EMBEDDING_MODEL:-Qwen/Qwen3-Embedding-8B}
|
||||
- EMBEDDING_MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_EMBEDDING_BASE_URL:-https://api.siliconflow.cn/v1}
|
||||
- EMBEDDING_MODEL_CONFIG__OVERRIDES__DIMENSIONS=1536
|
||||
- EMBEDDING_VECTOR_DIMENSIONS=1536
|
||||
- LLM_OPENAI_API_KEY=${HONCHO_LLM_API_KEY:?set HONCHO_LLM_API_KEY}
|
||||
- EMBEDDING_API_KEY=${HONCHO_EMBEDDING_API_KEY:-}
|
||||
- MODEL_CONFIG__OVERRIDES__BASE_URL=${HONCHO_LLM_BASE_URL:-https://api.openai.com/v1}
|
||||
- AUTH_USE_AUTH=${HONCHO_AUTH_USE_AUTH:-false}
|
||||
- AUTH_JWT_SECRET=${HONCHO_AUTH_JWT_SECRET}
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
networks:
|
||||
- honcho-net
|
||||
|
||||
database:
|
||||
image: ${HONCHO_DB_IMAGE:-pgvector/pgvector}:pg${HONCHO_DB_VERSION:-18}
|
||||
container_name: honcho-database
|
||||
restart: unless-stopped
|
||||
command: ["postgres", "-c", "max_connections=200"]
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- POSTGRES_USER=${HONCHO_DB_USER}
|
||||
- POSTGRES_PASSWORD=${HONCHO_DB_PASSWORD:?set HONCHO_DB_PASSWORD}
|
||||
- POSTGRES_DB=${HONCHO_DB_NAME}
|
||||
- POSTGRES_HOST_AUTH_METHOD=${POSTGRES_HOST_AUTH_METHOD:-scram-sha-256}
|
||||
- POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C --auth-host=${POSTGRES_HOST_AUTH_METHOD:-scram-sha-256}
|
||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- ${Volumes_Path}/pgdata:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "${HONCHO_DB_PORT:-5432}:5432"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- pg_isready -U ${HONCHO_DB_USER} -d ${HONCHO_DB_NAME}
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- honcho-net
|
||||
|
||||
redis:
|
||||
image: ${HONCHO_REDIS_IMAGE:-redis}:${HONCHO_REDIS_VERSION:-8}
|
||||
container_name: honcho-redis
|
||||
restart: unless-stopped
|
||||
command: ["redis-server", "--save", "60", "1", "--appendonly", "yes"]
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- ${Volumes_Path}/redis:/data
|
||||
ports:
|
||||
- "${HONCHO_REDIS_PORT:-6379}:6379"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- honcho-net
|
||||
|
||||
networks:
|
||||
honcho-net:
|
||||
driver: bridge
|
||||
Reference in New Issue
Block a user