本文讲为什么和总体结构。
| 想找 | 看哪里 |
|---|---|
| 日常命令、参数、deploy.yaml 字段速查 | deployment-cli.md |
| 验证一次完整部署(local) | release-tests/README.md |
| 本地模拟 npm 发布 | local-release-verification.md |
| 升级/兼容 upstream Understand-Anything plugin | understand-anyway compat --plugin-root <dir> --update |
读者:
- 部署/接入用户:理解架构后跳 deployment-cli.md 直接抄命令。
- OSS 维护者:新增命令 / profile / 部署能力时,回到第 3、4 节判断分层。
- Node.js 20+
- upstream Understand-Anything plugin 独立安装(Understand-Anyway 不捆绑)
- 每个被分析项目是本机可读的 git checkout
- 从源码 checkout 运行时需要 pnpm 9+
- LLM / 鉴权 / 组织策略 / 通知 / 品牌资源走 YAML provider 包名动态加载;开源代码不内置任何私有 provider
标准安装形态是直接从 npm 安装 CLI:
mkdir understand-anyway-ops
cd understand-anyway-ops
npm init -y
npm install @understand-anyway/cli
npx understand-anyway --help如果是在维护本仓库或做发版前验证,再从源码 checkout 运行:
pnpm install && pnpm build无源码树的运维脚本入口见 deployment-cli.md §1.11。
+------------------+ +-------------------+ +--------------------+
| daily-update.sh | -> | nightly-project-* | -> | refresh-prod-* |
+------------------+ +-------------------+ +--------------------+
| | |
v v v
gateway publish build + publish registry + shared
(versioned release) (per-project version) gateway remount
落盘形态(标准版本化布局,由 project-state publish 与 gateway publish 维护):
$UA_PROJECTS_ROOT/
├── gateway/
│ ├── config/{projects.json,deploy.yaml}
│ ├── registry.json
│ ├── portal-assets/
│ ├── operations/{nightly,daily}-runs/
│ └── runtime/{current,stable} → releases/<vid>/
└── projects/<project>/
├── versioned-state.json
├── current → versions/<vid>/
├── stable → versions/<vid>/
└── versions/<vid>/{.understand-anything,dashboard-dist}
禁止扁平绕过:所有部署用例必须经过 project-state publish 落入 versions/<vid>/。详见 release-tests/local/repo-checkout/expected-layout.md。
旧布局不会自动迁移:如果仍存在 $UA_PROJECTS_ROOT/config/projects.json,CLI / scripts 会提示迁到 $UA_PROJECTS_ROOT/gateway/config/projects.json,项目状态请重新 init/build/publish 或手动搬到 projects/<projectId>/ 后再验证。
deploy.yaml 是真相源(参见 packages/cli/deploy.example.yaml 和 deployment-cli.md §0)。
优先级(高 → 低):
| 层级 | 来源 | 覆盖动机 |
|---|---|---|
| 1 | CLI flag | 一次性临时覆盖 |
| 2 | 受支持的 UA_* env |
机器固定值(如 UA_DEPLOY_PROFILE / UA_PLUGIN_ROOT / UA_PROJECTS_ROOT / UA_CONFIG) |
| 3 | YAML profiles.<name> |
选定的运行模板 |
| 4 | YAML 顶层(deploy.* / gateway.* / record.* / providers.*) |
全局基础值 |
| 5 | 代码默认 | 兜底 |
env 层不是通配层;只有显式列出的 UA_* 才参与覆盖。具体名单见 deployment-cli.md §0。
配置 discovery(依次):
--config <file|dir>UA_CONFIG=<file|dir>./deploy.yaml或./config/deploy.yaml- 可执行包根目录下的
deploy.yaml或config/deploy.yaml
Secret 注入只允许占位符:
providers:
llm:
config:
token: "{{ LLM_TOKEN }}" # 来自 shell env 或 .env 链
caBundle: "{{ file('/run/secrets/ca.pem') }}" # 文件内容 trimsecret value 不写入 deploy.yaml。
Understand-Anyway 同时保留 flat 命令和动词族子命令。
Flat 命令(一次运行做一个稳定动作,参数主要描述输入输出):
build对一个 repo 产出/更新 graph stateserve --project <id>读取已注册项目并启动只读 gatewaycompat探测 upstream contract driftbatch-mapper-worker内部 worker,非稳定公共入口
动词族子命令(同一资源有多个生命周期动作):
dashboard <start|build-dist|stop|stop-all|status>gateway <publish|set-stable|rollback|list|gc>project-state <publish|set-stable|list|gc>notify nightlyrepair <llm-failures|llm-graph-failures>
判定规则:
- 一次稳定动作 + 输入输出参数 → flat
- 同资源多生命周期动作 → 动词族
- 只服务内部调度、不承诺兼容性 → 内部命令(隐藏)
- 新增动作改变已有资源状态 → 放入已有动词族,不要用 profile 伪装成动作
- 维度正交:profile 描述环境/运行模板;args 描述本次调用动作和目标。
- 普适性:profile 必须能多次复用,不能只表达一次性任务。
- 优先级:显式 CLI flag 永远高于 env、profile、deploy 默认值。
- profile 不表达动作:动作必须由命令或子命令表达,profile 只补参数。
正反例:
| 场景 | 推荐 | 不推荐 | 原因 |
|---|---|---|---|
| nightly 构建模板 | build --deploy-profile prod --llm-profile traex |
build --nightly |
nightly 是参数组合,不是新动作 |
| 临时降并发 | build --deploy-profile prod --mapper-concurrency 1 |
新增 debug-low-concurrency profile |
一次性 override 应放 CLI flag |
| rollback | gateway rollback |
--profile rollback |
rollback 是动作,必须是子命令 |
| 开 portal + 鉴权 | serve --serve-profile sso-portal |
新 flat 命令 serve-sso |
这是 serve 参数组合 |
| 受控 LLM 修复 | repair llm-failures --project <id> |
build --deploy-profile repair-llm |
修复不是 build 模板 |
三件套都是编排器,只透传拓扑和 profile 选择参数(host/port/project/deploy-profile/llm-profile/plugin-root/dry-run)。provider 细节、record、retry 策略走 deploy.yaml。具体参数表见 deployment-cli.md §2。
daily-update.sh
├─ self-update (git pull + pnpm install + pnpm build)
├─ gateway publish gate (best-effort)
├─ nightly-project-sync.sh
│ ├─ per-project: git pull → build → project-state publish → graph-health gate
│ └─ gateway/operations/nightly-latest.json + 项目级 nightly-latest.json
├─ notify nightly (best-effort)
├─ refresh-prod-server.sh
│ └─ 项目通过门禁 → dashboard build-dist → registry upsert → 共享 gateway 重挂
└─ aggregate-daily.mjs
关键约束:
- 共享 gateway 永远是 stop-before-start,每次 refresh 都重挂
- 项目门禁条件:
nightly-latest.json.overallStatus === "success";没通过的项目不刷新(必须先跑通 nightly) - 救急路径用 CLI 子命令直跑(如
understand-anyway dashboard build-dist),不要给编排脚本加--rebuild类开关
Gateway release 不可变。运行态通过两个指针管理:
current:当前对外运行版本stable:人工确认可回滚版本
GC 必须保护 current + stable;rollback 只翻转指针,不重建 release。
具体命令在 deployment-cli.md §1.8 / §3。
nightly 强制走 understand-anyway review-graph-health 默认 gate(确定性 graph-health 检查)。CLI 不暴露外部 review hook —— 想接入外部 review 请实现一个 wrapper 命令并替换 review-graph-health 调用,或者把 review 逻辑落到 yaml 后续扩展点(暂未提供)。
review 输出契约:
{"approved": true, "issues": [], "warnings": [], "stats": {}}详细字段 + nightly result.json schema 见各项目 nightly-runs/<run-id>/result.json。
开源默认走 LocalFileNotifyProvider,写入:
<projectsRoot>/notifications/<run-id>.json
外部 IM / 告警系统必须通过 overlay provider 接入:
understand-anyway notify nightly \
--report "$UA_PROJECTS_ROOT/gateway/operations/nightly-latest.json" \
--notify-provider "<your-notify-provider-package>"provider 包名只在 deploy.yaml providers.notify.package 里声明,或者上面 CLI 一次性指定。第三方包需在部署机另外 npm install,CLI 通过动态 import 加载。
repair 是人工触发的受控路径,永远不属于 nightly 主链路:
repair llm-failures:读最近一次 LLM stats,重跑失败文件,patch batch artifact,merge 持久化repair llm-graph-failures:扫 graph-level enrichment gap,写 deferred report(不直接改 graph)
报告写入:
<state-dir>/.understand-anything/repair-runs/<run-id>/result.json
| 需求 | 落点 |
|---|---|
| 新增一次性动作(改资源状态) | 已有动词族的子命令 |
| 新增可复用部署环境 | deploy.yaml deployProfiles.<name> |
| 新增可复用 LLM provider | deploy.yaml llmProfiles.<name> |
| 新增本次调用的一次性参数 | flat 命令的 CLI flag |
| 新增机器固定身份 / 默认值 | UA_* env(在 ~/.env),并在 schema 显式声明 |
| 新增外部系统接入 | provider 包名 + deploy.yaml providers.*,不入开源代码 |
新增前必须能用第 4、5 节的判定规则给出明确归属;否则停一停,先讨论。