diff --git a/docs/openclaw-API响应性能分析与优化.md b/docs/openclaw-API响应性能分析与优化.md index 22134d7..64e2e26 100644 --- a/docs/openclaw-API响应性能分析与优化.md +++ b/docs/openclaw-API响应性能分析与优化.md @@ -141,7 +141,7 @@ openclaw 的 agent 是 ReAct 式循环:**模型判断 → 调工具 → 结果 | 模型请求 `timeoutMs` | `undefined` | 日志中 `timeoutMs=undefined`,**模型 HTTP 请求无显式超时**;挂住时只能靠 `agents.defaults.timeoutSeconds=3600`(1 小时)兜底 | | `agents.defaults.maxConcurrent` | `2` | 单 agent 并发上限 2(11 个 agent 共用同一 gateway 进程) | | `tools.profile` | `full` | 全量工具集,工具越多模型越容易多轮试探 | -| CLI 运行时 | Node **22.23.1** | 非交互 shell 的 PATH 不含 nvm,`node` 落到系统 `/usr/bin/node`(22),导致 `openclaw models list` **直接报错拒跑**(详见 §4 建议 P0-1) | +| CLI 运行时 | Node **22.23.1**(系统默认) | 非交互 shell 的 PATH 不含 nvm:轻则 `openclaw: command not found`,重则因 Node 22 触发 `node:sqlite` 准入拒跑。详见 §3 的 P0-1(含包装脚本已落地方案) | --- @@ -153,27 +153,69 @@ openclaw 的 agent 是 ReAct 式循环:**模型判断 → 调工具 → 结果 **现象**:`openclaw models list` 报 `Node 22.23.1: node:sqlite truncates TEXT at embedded NUL (nodejs/node#61954); use 24.16+/26.1+` + **根因(2026-09-16 核实)**:系统级 `/usr/bin/node` 是 **v22.23.1**;nvm 的 26.8.2 只在 `~/.nvm/versions/node/v26.8.2/bin/`。**非交互式 SSH(或任何未加载 nvm 的 shell)PATH 不含 nvm 目录**,于是 `node` 落到 `/usr/bin/node` = 22: ``` -$ ssh bk02 'echo $PATH' → /home/yangxuan/.cargo/bin:/usr/local/bin:/usr/bin:/bin:... +$ ssh bk02 'echo $PATH' → /home/yangxuan/.cargo/bin:/usr/local/bin:/usr/bin:/bin:... (0 处含 .nvm) $ ssh bk02 'node -v' → v22.23.1 ← 落到系统 node $ ssh bk02 '~/.nvm/versions/node/v26.8.2/bin/node -v' → v26.8.2 ``` > 与 `.nvmrc` **无关**(已验证 `~/.openclaw/.nvmrc`、`~/deepseek-harness/.nvmrc` 均不存在)。已确认 `nvm alias default` 本就是 `26`——**问题只在 PATH 未加载 nvm**。 -**动作**:凡脚本 / 非交互调用 openclaw,都必须先加载 nvm 或用绝对路径,不要裸调 `node`: +#### 三种场景的行为差异(实测,别再混为一谈) + +| 场景 | 命令 | 实测结果 | +|---|---|---| +| **① 非交互 ssh 裸调** | `ssh bk02 'openclaw models list'` | **`openclaw: command not found`** —— nvm 未加载,连 openclaw 都不在 PATH(路径是 `~/.nvm/versions/node/v26.8.2/bin/openclaw`) | +| **② PATH 里有 openclaw 但 Node 是 22** | `env -i PATH=/usr/bin:/bin openclaw models list` | **报上面那条 `Node 22.23.1: node:sqlite ...` 并拒跑** | +| **③ 交互式 shell**(已加载 nvm,PATH 含 v26 目录) | `openclaw models list` | **正常输出** | + +**关键机制**:openclaw 入口自带**运行时准入 + 自动重试**。当 `#!/usr/bin/env node` 拿到不合格的 Node,而 **PATH 里还存在合格版本(24.16+/26.1+)时,它会自动改用那个 node 重跑**: + +``` +$ openclaw: Retrying with "/home/yangxuan/.nvm/versions/node/v26.8.2/bin/node" + (PATH; current Node failed runtime admission) ← 只是警告,不失败 +$ openclaw: Node 22.23.1: node:sqlite ... use 24.16+/26.1+ ← PATH 无合格 Node 时才拒跑 +``` + +所以**判定标准是「PATH 里有没有合格的 Node」,不是「默认 node 是几」**。 + +#### 动作 + +**交互式使用**(日常最常用)——建一个包装脚本,一劳永逸,不必每次记得 `nvm use`: ```bash -export NVM_DIR=$HOME/.nvm; . $NVM_DIR/nvm.sh # 交互式登录先做(系统说明 §0 已要求) -node -v # 期望 v26.8.2 -openclaw models list --provider deepseek # 期望能正常列出 - -# 非交互/脚本场景:直接给绝对路径,绕开 PATH -~/.nvm/versions/node/v26.8.2/bin/node --version +mkdir -p ~/.local/bin +cp ~/.openclaw/scripts/bin/openclaw ~/.local/bin/openclaw # 仓库内已留存副本 +chmod +x ~/.local/bin/openclaw +openclaw models list --provider deepseek # 期望正常列出 ``` +包装脚本内容(固定绝对路径,绕开 PATH 解析): + +```sh +#!/bin/sh +exec "/home/yangxuan/.nvm/versions/node/v26.8.2/bin/node" \ + "/home/yangxuan/.nvm/versions/node/v26.8.2/lib/node_modules/openclaw/openclaw.mjs" "$@" +``` + +**非交互 / 脚本 / cron / systemd**——这些场景**不加载 `~/.profile`,所以 `~/.local/bin` 也不在 PATH**,包装脚本不生效,必须显式加载 nvm 或用绝对路径: + +```bash +# 方式一:先加载 nvm(推荐,之后 openclaw/node 都正确) +export NVM_DIR=$HOME/.nvm; . $NVM_DIR/nvm.sh +node -v # 期望 v26.8.2 +openclaw models list --provider deepseek + +# 方式二:只用绝对路径(不依赖 shell 初始化) +~/.nvm/versions/node/v26.8.2/bin/node --version +~/.nvm/versions/node/v26.8.2/bin/openclaw models list +``` + +> systemd 服务不受影响:`openclaw-gateway.service` 的 `ExecStart` 写的就是 nvm 26 的绝对路径。 + ### P0-2 减少工具循环轮次(针对 94.6%,收益最大) 轮次是延迟的乘数:**每减少一轮,省下「一次模型往返 + 一次工具等待」(实测中位 6 秒)**。