diff --git a/gitbooks/features/cloud-deploy.zh-CN.md b/gitbooks/features/cloud-deploy.zh-CN.md new file mode 100644 index 000000000..3b32219ef --- /dev/null +++ b/gitbooks/features/cloud-deploy.zh-CN.md @@ -0,0 +1,517 @@ +--- +description: 在云端托管 headless openhuman-core——DigitalOcean App Platform、Fly.io 或任何 VPS 上的 Docker Compose。 +icon: cloud +lang: zh-CN +--- + +# 云端部署 + +OpenHuman 是一个桌面应用,但它的 **Rust 核心**(`openhuman-core`)是一个可以托管在云端的 headless JSON-RPC 服务器。单独部署核心的用途包括: + +- 多设备访问,让多个桌面客户端指向同一个托管核心 +- 没有本地 Rust 工具链的内部测试人员 +- 应该比笔记本 session 更长寿的长运行 cron job / webhook + +本指南涵盖四条部署路径,由易到难: + +1. [DigitalOcean App Platform:一键部署](#1-digitalocean-app-platform-一键部署) +2. [DigitalOcean App Platform:通过 doctl 手动部署](#2-digitalocean-app-platform-通过-doctl-手动部署) +3. [任何 VPS 通过 Docker Compose](#3-任何-vps-通过-docker-compose) +4. [Fly.io](#4-flyio) + +每条路径部署的内容相同:一个运行 `openhuman-core serve` 在端口 `7788` 上的单一容器。公共主机应位于提供商的 TLS 之后,例如 `https://core.example.com/rpc`。仅限私有的主机——localhost、RFC1918 网络或 Tailscale 等 tailnet——可以使用纯 HTTP,例如 `http://100.x.x.x:7788/rpc`,当核心无法从公共互联网访问时。桌面应用已经知道如何与远程核心通信;在 `app/.env.local` 中设置 `OPENHUMAN_CORE_RPC_URL` 和 `OPENHUMAN_CORE_TOKEN=...`,然后启动即可。 + +--- + +## Bearer token 的单一事实来源 + +每次 `/rpc` 调用都携带 `Authorization: Bearer `。核心在启动时通过两种方式加载该 token([`src/core/auth.rs`](../../src/core/auth.rs)): + +1. **`OPENHUMAN_CORE_TOKEN` 环境变量**——由调用方预置(Tauri 壳层、Docker、App Platform、systemd unit 等)。核心原样使用此值,**绝不**写入文件。 +2. **`{workspace}/core.token` 文件**——仅在 `OPENHUMAN_CORE_TOKEN` 未设置时由核心在首次启动时生成。独立运行的 `openhuman core run` 使用此方式,以便 CLI 客户端可以 `cat` 该文件。 + +**任何远程 / Docker 化部署的经验法则:始终设置 `OPENHUMAN_CORE_TOKEN`。** 不要在容器中依赖 `core.token`——临时文件系统会在重新部署时丢失它,任何试图从容器外部读取该文件的客户端都会得到过期或空值。这两条路径在启动时故意互斥;混合使用是"重新部署后 dashboard 报 401"的最常见原因。 + +要检查*运行中*的核心在使用什么,在主机上运行 [`scripts/print-core-token.sh`](../../scripts/print-core-token.sh)(或在容器内使用 `docker compose exec`): + +```bash +scripts/print-core-token.sh --where # 打印 'env' 或 'file:/path' +scripts/print-core-token.sh --redact # 前 8 个十六进制字符 + '…'(适合日志) +scripts/print-core-token.sh # 完整值(直接管道到客户端) +``` + +桌面应用的首次运行选择器也在 Core RPC URL + token 字段旁暴露了一个**测试连接**按钮,它向该 URL 和输入的 token 触发 `core.ping`,并在持久化配置之前内联报告 `Connected ✓` / `Auth failed` / `Unreachable`。 + +--- + +## 开始前的准备工作 + +| 设置 | 必需 | 说明 | +| ---- | ---- | ---- | +| `OPENHUMAN_CORE_TOKEN` | 是 | 客户端发送给 `/rpc` 的 Bearer token。用 `openssl rand -hex 32` 生成。**任何持有此 token 的人都可以驱动核心。** | +| `BACKEND_URL` | 是 | 核心通信的 Tinyhumans 后端(生产环境为 `https://api.tinyhumans.ai`)。 | +| `OPENHUMAN_APP_ENV` | 否 | `production` 或 `staging`。默认 `production`。 | +| `OPENHUMAN_CORE_HOST` | 否 | 容器中默认 `0.0.0.0`。 | +| `OPENHUMAN_CORE_PORT` | 否 | 默认 `7788`。 | +| `RUST_LOG` | 否 | `info` 足够;`debug` 用于排查。 | + +运行中的容器暴露的端点: + +- `GET /health`,公共存活探针。每条部署路径的健康检查都使用它。 +- `POST /rpc`,受 bearer 保护的 JSON-RPC 入口。 +- `GET /events`、`GET /ws/dictation`,公共流式通道。 + +`OPENHUMAN_WORKSPACE` 目录(容器内为 `/home/openhuman/.openhuman`)保存核心的配置、sqlite 数据库和技能状态。**在每个生产部署中将其挂载到持久卷**,否则重启时会丢失数据。 + +--- + +## 1. DigitalOcean App Platform:一键部署 + +点击下面的按钮,从本仓库的 [`.do/app.yaml`](../../.do/app.yaml) 创建一个新的 App Platform 应用: + +[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/tinyhumansai/openhuman/tree/main) + +然后,在 App Platform UI 中,**在首次部署完成之前**: + +1. 打开 **Settings → App-Level Environment Variables** 标签页。 +2. 将占位符 `OPENHUMAN_CORE_TOKEN` 值替换为强 secret(`openssl rand -hex 32`)。标记为 encrypted。 +3. 如果部署的是 staging,将 `OPENHUMAN_APP_ENV` 改为 `staging`,`BACKEND_URL` 改为 `https://staging-api.tinyhumans.ai`。 +4. 点击 **Save**。App Platform 用新 secret 重新部署。 + +App Platform 处理 TLS、崩溃重启、日志流式传输和 `git push` 时的滚动重新部署(在 `.do/app.yaml` 中设置 `deploy_on_push: true` 以选择加入)。 + +> **持久化说明:** App Platform Basic 不提供块存储。核心的工作区位于容器的临时文件系统中,重新部署时会丢失。如需持久存储,请附加托管数据库或升级到支持卷的套餐。参见 [Compose 路径](#3-任何-vps-通过-docker-compose)获取开箱即用持久卷的自助替代方案。 + +--- + +## 2. DigitalOcean App Platform:通过 doctl 手动部署 + +如果你不想点击 UI: + +```bash +# 一次性:安装 doctl 并认证。 +doctl auth init + +# 编辑 .do/app.yaml - 将 OPENHUMAN_CORE_TOKEN 设置为真实值(或通过 --spec 配合 envsubst 在创建时传入)。然后: +doctl apps create --spec .do/app.yaml + +# 观察构建: +doctl apps list +doctl apps logs --type build --follow +``` + +编辑 spec 后更新现有应用: + +```bash +doctl apps update --spec .do/app.yaml +``` + +--- + +## 3. 任何 VPS 通过 Docker Compose + +适用于任何安装了 Docker Engine ≥ 24 和 Compose 插件的主机。DigitalOcean Droplet、Hetzner、Linode、EC2、家用服务器。 + +每个生产版本都会向 GHCR 发布多标签镜像: + +```bash +docker pull ghcr.io/tinyhumansai/openhuman-core:latest # 追踪最新生产切版 +docker pull ghcr.io/tinyhumansai/openhuman-core:v1.2.4 # 按 GitHub Release tag 固定 +docker pull ghcr.io/tinyhumansai/openhuman-core:1.2.4 # 按 SemVer 固定 +``` + +镜像是 `linux/amd64`。arm64 主机拉取独立 tarball,该 tarball 附在同一 GitHub Release 中(`openhuman-core--aarch64-unknown-linux-gnu.tar.gz`),或在 arm64 构建器上从源码构建镜像。 + +使用已发布镜像快速运行: + +```bash +docker run -d --name openhuman-core -p 7788:7788 \ + -e OPENHUMAN_CORE_TOKEN="$(openssl rand -hex 32)" \ + -e BACKEND_URL=https://api.tinyhumans.ai \ + -e OPENHUMAN_APP_ENV=production \ + -v openhuman-workspace:/home/openhuman/.openhuman \ + ghcr.io/tinyhumansai/openhuman-core:latest +``` + +或使用仓库内的 Compose 文件(仍然从 `Dockerfile` 本地构建镜像;在 `docker-compose.yml` 中将 `image:` 字段切换为 `ghcr.io/tinyhumansai/openhuman-core:latest` 以改用已发布镜像): + +```bash +# 在服务器上: +git clone https://github.com/tinyhumansai/openhuman.git +cd openhuman + +# 配置 secrets: +cp .env.example .env +# 编辑 .env - 至少填写: +# BACKEND_URL=https://api.tinyhumans.ai +# OPENHUMAN_CORE_TOKEN= +# OPENHUMAN_APP_ENV=production + +# 构建并启动: +docker compose up -d + +# 验证: +docker compose ps +curl -fsS http://localhost:7788/health +``` + +### 无 Docker 的 Headless 安装 + +如果主机无法运行 Docker,抓取附在最新 [GitHub Release](https://github.com/tinyhumansai/openhuman/releases/latest) 中的独立 CLI tarball: + +```bash +# 选择匹配你主机架构的 tarball。 +ARCH="$(uname -m)" +case "$ARCH" in + x86_64) TARGET=x86_64-unknown-linux-gnu ;; + aarch64) TARGET=aarch64-unknown-linux-gnu ;; + *) echo "Unsupported arch: $ARCH"; exit 1 ;; +esac +VERSION=1.2.4 # 设置为你想要的版本 +curl -fsSL "https://github.com/tinyhumansai/openhuman/releases/download/v${VERSION}/openhuman-core-${VERSION}-${TARGET}.tar.gz" \ + | tar -xz -C /usr/local/bin +openhuman-core --version +``` + +然后在你选择的 service manager 下运行 `openhuman-core serve`(systemd、supervisord 等),使用上述相同的环境变量。 + +### Headless 自更新契约 + +Headless 部署应将 `openhuman.update_apply` 视为安全原语:它下载 release asset,将其原子地写入当前二进制文件旁边,然后返回。不会自动退出。 + +`openhuman.update_run` 遵循 `config.update.restart_strategy`: + +- `self_replace`(默认):stage 二进制文件,发布一个进程内重启请求,让运行中的核心自行 respawn。 +- `supervisor`:stage 二进制文件并返回 `restart_requested=false`。你的外部 service manager 必须重启进程。 + +对于长运行的 Linux 服务,设置: + +```toml +[update] +restart_strategy = "supervisor" +rpc_mutations_enabled = false +``` + +或等效的环境变量: + +```bash +OPENHUMAN_AUTO_UPDATE_RESTART_STRATEGY=supervisor +OPENHUMAN_AUTO_UPDATE_RPC_MUTATIONS_ENABLED=false +``` + +推荐的 `systemd` 配置: + +```ini +Restart=always +ExecReload=/bin/kill -HUP $MAINPID +``` + +运维流程: + +1. 调用 `openhuman.update_check` 发现 release。 +2. 在你的 `update.toml` 中配置 `restart_strategy = "supervisor"`(或设置 `OPENHUMAN_AUTO_UPDATE_RESTART_STRATEGY=supervisor`),以便核心 stage 新二进制文件而不尝试自行 re-exec,然后调用 `openhuman.update_apply` 或 `openhuman.update_run`。`restart_strategy` 是配置设置,不是 RPC 参数。 +3. 显式重启 unit:`systemctl restart openhuman`。 + +如果下载或 staging 失败,运行中的二进制文件会保持原位,不会请求重启。如果 staged 二进制文件在重启后被证明有问题,通过你的包管理器、镜像标签或 release artifact 恢复之前的二进制文件,然后再次重启 supervisor。 + +Compose 文件([`docker-compose.yml`](../../docker-compose.yml))将核心映射到 `:7788`,挂载命名卷 `openhuman-workspace` 用于持久化,并设置 `restart: unless-stopped` 以便主机重启后核心自动恢复。 + +### 更新 + +```bash +git pull +docker compose build +docker compose up -d +``` + +对于暴露 RPC 的生产部署,建议禁用可变的 update RPC(`OPENHUMAN_AUTO_UPDATE_RPC_MUTATIONS_ENABLED=false`),并通过你现有的镜像标签或包管理流程执行 rollout。 + +### 日志 + +```bash +docker compose logs -f openhuman-core +``` + +### 轮换 bearer token + +`OPENHUMAN_CORE_TOKEN` 是公共互联网与完整 RPC 访问之间的唯一屏障。按时间表轮换它,并在任何疑似泄露后轮换: + +```bash +# 1. 生成新 token 并更新服务器端 .env。 +openssl rand -hex 32 > /tmp/new-token +sed -i.bak "s|^OPENHUMAN_CORE_TOKEN=.*|OPENHUMAN_CORE_TOKEN=$(cat /tmp/new-token)|" .env +rm /tmp/new-token .env.bak + +# 2. 重启容器,让新值到达核心进程。 +docker compose up -d --force-recreate openhuman-core + +# 3. 确认运行中的容器正在使用新 token(脱敏)。 +docker compose exec openhuman-core /bin/sh -c \ + 'echo -n "$OPENHUMAN_CORE_TOKEN" | head -c 8; echo "…"' + +# 4. 更新每个桌面客户端(切换模式 → 在选择器中重新粘贴,或编辑 app/.env.local 中的 OPENHUMAN_CORE_TOKEN 然后重新启动)。仍然持有旧 token 的客户端会在下一次 /rpc 调用时收到 HTTP 401——这是预期行为,不是回归。 +``` + +对于 App Platform,在 **Settings → App-Level Environment Variables** 中执行相同操作:编辑 `OPENHUMAN_CORE_TOKEN` secret,让 App Platform 重新部署。没有单独的 token 文件需要删除;环境变量是唯一的状态。 + +### 置于 TLS 之后 + +使用 Caddy、nginx 或 Traefik 作为 `:7788` 的反向代理。最小 `Caddyfile`: + +```caddy +core.example.com { + reverse_proxy localhost:7788 +} +``` + +--- + +## 将桌面应用指向托管核心 + +在桌面应用的环境文件(`app/.env.local`)中: + +```bash +# 使用托管核心而不是生成本地 sidecar。 +OPENHUMAN_CORE_RUN_MODE=external +OPENHUMAN_CORE_RPC_URL=https://core.example.com/rpc +OPENHUMAN_CORE_TOKEN=<你在服务器上设置的相同 token> +``` + +对于没有公共 IP 的私有 tailnet-only VM,改用 tailnet URL: + +```bash +OPENHUMAN_CORE_RUN_MODE=external +OPENHUMAN_CORE_RPC_URL=http://100.x.x.x:7788/rpc +OPENHUMAN_CORE_TOKEN=<你在服务器上设置的相同 token> +``` + +重启桌面应用。`App.tsx` 中的 provider 链会将所有 RPC 调用路由到远程核心;其他一切不变。公共 `http://` 主机被应用选择器拒绝;对任何可从公共网络访问的核心使用 HTTPS。 + +--- + +## 命名卷所有权与 Docker entrypoint + +Docker 默认创建 `root:root` 拥有的命名卷。因为核心以非 root `openhuman` 用户(UID 10001)运行,banner 之后的首次写入——`init_rpc_token → write_token_file` 到 `$OPENHUMAN_WORKSPACE`——如果没有先修复所有权,会抛出 `Permission denied (os error 13)`。 + +镜像在 `/usr/local/bin/docker-entrypoint-core.sh` 附带一个专用 entrypoint,它: + +1. 以 `root` 启动。 +2. 对 `$OPENHUMAN_WORKSPACE` 和 `$HOME/.openhuman`(`OPENHUMAN_CORE_TOKEN` 未设置时 `core.token` 被写入的目录)运行 `mkdir -p` + `chown openhuman:openhuman`。 +3. 调用 `exec gosu openhuman openhuman-core "$@"` 来降权并移交控制权给二进制文件。 + +这是**幂等的**:在新创建的卷上,chown 会修复 root 拥有的目录;在已经修复过的卷上,chown 是 no-op。从早于该修复的镜像升级时,不需要手动执行 `docker volume rm`。 + +该 entrypoint 名为 `docker-entrypoint-core.sh`,仅接入根 `Dockerfile`。E2E 镜像(`e2e/docker-entrypoint.sh`)不受影响。 + +--- + +## 4. Fly.io + +[Fly.io](https://fly.io) 非常适合 `openhuman-core`:它自动处理 TLS,在所有套餐上支持持久卷,并且可以自动停止空闲机器以削减成本。 + +### 前置条件 + +- 安装并认证 [flyctl](https://fly.io/docs/flyctl/install/)(`fly auth login`) +- Fly.io 账户 + +### 步骤 1 —— 启动应用 + +```bash +fly launch --no-deploy --config .fly/fly.toml +``` + +Fly.io 自动检测 `Dockerfile`。选择靠近你用户的区域,并在提示时跳过首次部署。这会生成一个配置文件。 + +### 步骤 2 —— 配置 `.fly/fly.toml` + +仓库在 [`.fly/fly.toml`](../../.fly/fly.toml) 附带一个模板。用 `fly launch` 期间选择的值填充 `` 和 ``: + +```toml +app = '' +primary_region = '' + +[build] + dockerfile = "Dockerfile" + +[env] + OPENHUMAN_CORE_HOST = "0.0.0.0" + OPENHUMAN_CORE_PORT = "7788" + OPENHUMAN_WORKSPACE = "/home/openhuman/.openhuman" + RUST_LOG = "info" + +[[mounts]] + source = "openhuman_workspace" + destination = "/home/openhuman/.openhuman" + +[http_service] + internal_port = 7788 + force_https = true + auto_stop_machines = 'stop' + auto_start_machines = true + # min_machines_running = 0 在空闲时完全停止机器(最便宜),但 + # 空闲后的第一个请求需要支付冷启动惩罚(容器启动 + + # Rust 二进制文件初始化——数秒)。设为 1 可保持一台机器热备。 + min_machines_running = 0 + processes = ['app'] + + [[http_service.checks]] + interval = "30s" + timeout = "5s" + grace_period = "10s" + method = "GET" + path = "/health" + +[[vm]] + memory = '1gb' + cpus = 1 +``` + +### 步骤 3 —— 创建持久卷 + +```bash +fly volumes create openhuman_workspace --size 5 --region --config .fly/fly.toml +``` + +**将工作区挂载到持久卷**,否则每次重新部署都会丢失数据。 + +### 步骤 4 —— 设置 secrets + +```bash +# 必需 +fly secrets set OPENHUMAN_CORE_TOKEN="$(openssl rand -hex 32)" +fly secrets set BACKEND_URL="https://api.tinyhumans.ai" +fly secrets set OPENHUMAN_APP_ENV="production" + +# 建议——任何可公开访问的部署: +fly secrets set OPENHUMAN_AUTO_UPDATE_RPC_MUTATIONS_ENABLED="false" +fly secrets set OPENHUMAN_AUTO_UPDATE_RESTART_STRATEGY="supervisor" + +# 可选——错误报告和 analytics: +fly secrets set OPENHUMAN_CORE_SENTRY_DSN="https://@o.ingest.sentry.io/" +fly secrets set OPENHUMAN_ANALYTICS_ENABLED="true" +``` + +保存 `OPENHUMAN_CORE_TOKEN` 的值——你稍后需要它来连接桌面应用。**任何持有此 token 的人都可以驱动核心**;像密码一样对待它,并在任何疑似泄露后通过 `fly secrets set OPENHUMAN_CORE_TOKEN="$(openssl rand -hex 32)"` 轮换。 + +### 步骤 5 —— 部署 + +```bash +fly deploy --config .fly/fly.toml +``` + +验证核心健康: + +```bash +curl -fsS https://.fly.dev/health +``` + +### 步骤 6 —— 将桌面应用指向托管核心 + +在 `app/.env.local` 中: + +```bash +OPENHUMAN_CORE_RUN_MODE=external +OPENHUMAN_CORE_RPC_URL=https://.fly.dev/rpc +OPENHUMAN_CORE_TOKEN=<你在步骤 4 中设置的 token> +``` + +或使用桌面应用中的**首次运行选择器**(Core RPC URL + token 字段,带**测试连接**按钮)来配置,无需编辑文件。 + +### 持续部署 + +要在每次推送到 `main` 时自动重新部署,在 `.github/workflows/fly-deploy.yml` 添加 workflow 文件: + +```yaml +name: Fly Deploy +on: + push: + branches: + - main + paths: + - 'src/**' + - 'Cargo.toml' + - 'Cargo.lock' + - 'Dockerfile' + - '.fly/fly.toml' + - 'scripts/docker-entrypoint-core.sh' +jobs: + deploy: + name: Deploy openhuman-core + runs-on: ubuntu-latest + concurrency: deploy-group + steps: + - uses: actions/checkout@v4 + # 将 Fly action 固定到带标签的 release(或完整 commit SHA),而不是 @master—— + # 追踪移动分支意味着信任未来推送到那里的每个 commit,包括被入侵的维护者账户所做的任何 commit。 + - uses: superfly/flyctl-actions/setup-flyctl@1.5 + - run: flyctl deploy --remote-only --config .fly/fly.toml + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} +``` + +用 `fly tokens create deploy` 生成部署 token,并将其作为名为 `FLY_API_TOKEN` 的仓库 secret 添加。 + +### 更新 + +```bash +fly deploy --config .fly/fly.toml +``` + +对于固定版本的部署,在 `.fly/fly.toml` 中更新镜像标签并重新部署: + +```toml +[build] + image = "ghcr.io/tinyhumansai/openhuman-core:v1.2.4" +``` + +### 日志 + +```bash +fly logs --config .fly/fly.toml +``` + +### 已知陷阱 —— 卷上的 UID 不匹配 + +如果你在从 `Dockerfile` 构建(创建 UID 10001 的 `openhuman` 用户)和拉取预构建的 GHCR 镜像(使用 UID 1000)之间切换,已写入持久卷的文件会被旧 UID 拥有,并在启动时产生 `Permission denied (os error 13)`。 + +通过 SSH 进入并重新拥有工作区来修复: + +```bash +fly ssh console --config .fly/fly.toml +chown -R openhuman:openhuman /home/openhuman/.openhuman/ +exit +fly machine restart --config .fly/fly.toml +``` + +--- + +## 冒烟测试 + +仓库附带 [`.github/workflows/deploy-smoke.yml`](../../.github/workflows/deploy-smoke.yml),它在每次触及部署工件的 PR 上运行。它构建 Docker 镜像、启动它并轮询 `/health`,以便云部署路径中的回归在到达 `main` 之前就在 CI 中失败。 + +该 workflow 包含两个 job: + +- **`docker-image`**——设置 `OPENHUMAN_CORE_TOKEN` 且不挂载卷。保护 DigitalOcean App Platform 路径(`.do/app.yaml`),其中 token 始终预置且不挂载持久卷。 +- **`docker-volume-permissions`**——省略 `OPENHUMAN_CORE_TOKEN` 并在 `/home/openhuman/.openhuman` 挂载一个新的匿名卷。复现 issue #2065 的确切失败模式,并断言 `/health` 返回 200 且日志中不存在 `Permission denied (os error 13)`。 + +要在本地运行相同的检查: + +```bash +docker build -t openhuman-core:smoke . + +# Token-set 路径(App Platform): +docker run -d --name oh-smoke -p 7788:7788 \ + -e OPENHUMAN_CORE_TOKEN=smoke-test-token \ + openhuman-core:smoke +curl -fsS http://localhost:7788/health +docker rm -f oh-smoke + +# Fresh-volume / no-token 路径(Docker Compose、VPS): +docker volume create oh-vol-test +docker run -d --name oh-vol-smoke -p 7789:7788 \ + -v oh-vol-test:/home/openhuman/.openhuman \ + openhuman-core:smoke +curl -fsS http://localhost:7789/health +docker rm -f oh-vol-smoke +docker volume rm oh-vol-test +``` diff --git a/gitbooks/features/native-tools/tool-memory.zh-CN.md b/gitbooks/features/native-tools/tool-memory.zh-CN.md new file mode 100644 index 000000000..d29fc6561 --- /dev/null +++ b/gitbooks/features/native-tools/tool-memory.zh-CN.md @@ -0,0 +1,83 @@ +--- +description: 持久化的、工具作用域规则,用于安全关键型指引和学习成果。 +icon: shield-check +lang: zh-CN +--- + +# 工具级记忆 + +工具级记忆层捕获关于智能体应如何使用特定工具的**可执行指引**——它与[记忆工具](memory-tools.zh-CN.md)的通用召回不同,也与 `tool_effectiveness` 统计命名空间相区别。它是把"永远不要给 Sarah 发邮件"转化为智能体在每一轮后续中都必须遵守的硬约束的表面。 + +它实现了 [issue #1400](https://github.com/tinyhumansai/openhuman/issues/1400)——一个用于持久化学习成果和高优先级规则的一流存储与检索系统。 + +## 存储内容 + +每个工具都有自己的命名空间 **`tool-{tool_name}`**,与 `global`、`skill-{id}` 以及仅用于统计的 `tool_effectiveness` 命名空间相区分。在其内部,每条记录都是一个 `ToolMemoryRule`: + +| 字段 | 用途 | +| ---- | ---- | +| `id` | 每条规则的稳定 UUID。Upsert 会复用相同 id。 | +| `tool_name` | 规则适用的工具(例如 `send_email`、`shell`)。 | +| `rule` | 智能体必须遵循的自然语言指引。 | +| `priority` | `critical`、`high` 或 `normal`。驱动检索 + 压缩策略。 | +| `source` | `user_explicit`、`post_turn` 或 `programmatic`——来源。 | +| `tags` | 自由标签(`safety`、`permission`……)。 | +| `created_at` / `updated_at` | RFC3339 时间戳。 | + +统计(`tool_effectiveness/tool/{name}`)和规则(`tool-{name}/rule/{id}`)按设计位于*不同*的命名空间——一个追踪"发生了什么",另一个追踪"对此该做什么"。 + +## 优先级层级 + +| 优先级 | 存储位置 | 抗压缩? | +| ------ | -------- | -------- | +| `critical` | 通过 `ToolMemoryRulesSection` 钉入**系统提示**。 | **是**——系统提示按 session 冻结,不会被 mid-session 压缩器重写。 | +| `high` | 同一块系统提示中,排在 critical 之后。 | **是**——机制相同。 | +| `normal` | 存储在命名空间中;通过 `memory_recall` 按需检索。 | 否——与任何其他命名空间记忆一样可被压缩。 | + +抗压缩属性是结构性的:critical 和 high 规则 riding 在*系统提示*中,而推理后端的 prefix cache 会在整个 session 期间保持其冻结。没有任何方式能让 token 压缩静默丢弃一条 `critical` 规则。 + +## 捕获流水线 + +每轮之后有两条自动捕获路径触发(通过 `ToolMemoryCaptureHook`): + +1. **用户指令**——用户消息中的 `never `、`don't ...`、`do not ...` 或 `stop ing ...` 等句子会被提升为匹配工具的 **Critical** 规则。通用名词别名将 `"email"` 映射到名为 `send_email` 的工具,`"shell"` 映射到 `bash`/`exec` 等;当没有别名匹配时,规则会落在该轮次中第一个运行的工具上,使其保持在相关调用现场附近。 +2. **重复工具失败**——在一轮中失败两次或以上的工具会获得一条 **Normal** 优先级的观察记录,失败类别被内联摘要,以便智能体下次考虑该工具时有上下文。 + +当学习子系统开启时,该 hook 默认启用。用 `OPENHUMAN_LEARNING_TOOL_MEMORY_CAPTURE_ENABLED=0` 选择性禁用。 + +## 工具选择时的检索 + +在 session 开始时,harness 通过 `ToolMemoryStore::rules_for_prompt` 预取每条 Critical 和 High 规则,将它们渲染到 `## Tool-scoped rules` 块中,并把该块钉入系统提示。因为提示在 session 生命周期内被冻结,这些规则在每一轮的工具选择时——以及任何实际工具执行之前——都是可见的。 + +低优先级指引不占用提示预算;智能体通过针对 `tool-{name}` 命名空间调用 `memory_recall` 按需获取它们。 + +## RPC 表面 + +`memory` 命名空间下暴露六个方法: + +| 方法 | 用途 | +| ---- | ---- | +| `memory.tool_rule_put` | Upsert 一条规则。对安全关键型条目使用 `priority='critical'`。 | +| `memory.tool_rule_get` | 通过 `(tool_name, id)` 获取一条规则。 | +| `memory.tool_rule_list` | 列出某工具的所有规则,按优先级 + 新鲜度排序。 | +| `memory.tool_rule_delete` | 删除一条规则。 | +| `memory.tool_rules_for_prompt` | 返回渲染后的 Markdown 块 + 结构化快照——session builder 所钉入的内容。 | +| `memory.tool_rules_json` | 原始 JSON 列表(供信封消费者使用)。 | + +JSON payload 使用 snake_case(`priority: "critical"`、`source: "user_explicit"`)。每个方法都经过与其他记忆 RPC 相同的 `active_memory_client` 管道。 + +## 端到端安全场景 + +"永远不要给 Sarah 发邮件"路径已被回归测试覆盖: + +1. 用户在调用了 `send_email` 的轮次中说 *"Never email Sarah at sarah@example.com."* +2. `ToolMemoryCaptureHook` 提取该指令,将 `email` 别名映射到 `send_email` 工具,并在 `tool-send_email/rule/{uuid}` 下写入一条 Critical 规则。 +3. 在下一个 session 中,`prefetch_tool_memory_rules_blocking` 拉取每条 Critical 和 High 规则,session builder 将 `ToolMemoryRulesSection` 追加到系统提示。 +4. 智能体在选择工具之前就看到 `### \`send_email\`` 后跟 `- **[critical]** Never email Sarah at sarah@example.com.`,并且该规则在任何 mid-session token 压缩中都能存活。 + +覆盖率与集成测试位于 `src/openhuman/memory/tool_memory/`。 + +## 另请参阅 + +- [记忆工具](memory-tools.zh-CN.md)——通用 `recall`、`store`、`forget`。 +- [智能 Token 压缩](../token-compression.zh-CN.md)——系统提示被保护免受的内容。 diff --git a/gitbooks/overview/troubleshooting-sign-in.zh-CN.md b/gitbooks/overview/troubleshooting-sign-in.zh-CN.md new file mode 100644 index 000000000..72e09056e --- /dev/null +++ b/gitbooks/overview/troubleshooting-sign-in.zh-CN.md @@ -0,0 +1,62 @@ +--- +description: >- + 诊断登录失败、OAuth 回调无法完成以及远程核心 RPC 认证问题。 +icon: key +lang: zh-CN +--- + +# 登录故障排查 + +当社交登录卡住、返回欢迎界面,或核心日志中出现未授权的 `/auth` 请求时,使用此 checklist。 + +## 检查后端可达性 + +从桌面应用所在的同一网络,验证公共 OpenHuman 端点: + +```bash +curl -I https://tinyhumans.ai/ +curl -I https://api.tinyhumans.ai/health +``` + +如果网站能加载但 API 端点失败,桌面应用可能无法将 OAuth 回调兑换为 session。在 issue 报告中记录 HTTP 状态码、区域和 DNS 结果。 + +## 检查所选核心 + +如果你使用**高级**远程核心模式,在开始 OAuth 之前确认 RPC URL 和 bearer token: + +```bash +curl -sS https://your-core.example/rpc \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer CORE_TOKEN" \ + -d '{"jsonrpc":"2.0","id":1,"method":"core.ping","params":{}}' +``` + +`401` 响应表示桌面 token 与远程核心 token 不匹配。在重试 Google 或 GitHub 登录之前先修复这个问题。 + +## 检查深度链接回调 + +成功的桌面 OAuth 以 `openhuman://auth?...` 回调结束。如果浏览器显示了该 URL 但应用仍停留在欢迎界面: + +1. 确保只运行了一个 OpenHuman 桌面实例。 +2. 重启应用,保持相同的远程核心设置,并重试登录。 +3. 如果使用远程核心,检查核心是否收到 `openhuman.auth_store_session`。 + +对于远程核心,临时手动注入可以确认核心本身是正常的: + +```bash +curl -sS https://your-core.example/rpc \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer CORE_TOKEN" \ + -d '{"jsonrpc":"2.0","id":1,"method":"openhuman.auth_store_session","params":{"token":"JWT_FROM_CALLBACK"} }' +``` + +不要把真实 JWT 粘贴到公共 GitHub issue 中。对 token 进行脱敏处理,只附加状态码、主机名、应用版本、操作系统和相关日志行。 + +## Bug 报告中应包含的内容 + +* 应用版本和操作系统。 +* 核心模式是本地还是远程。 +* RPC URL 主机、脱敏后的 token 状态和 `core.ping` 结果。 +* 使用的 OAuth 提供商。 +* 浏览器中是否出现了 `openhuman://auth` URL。 +* 如果存在,第一条未授权日志行。