2026-05-16 22:03:14 +08:00
|
|
|
|
# 09 页面 AI 快速块编辑 Runtime Review
|
|
|
|
|
|
|
2026-05-18 17:01:35 +08:00
|
|
|
|
> 状态:`done`
|
2026-05-16 22:03:14 +08:00
|
|
|
|
>
|
|
|
|
|
|
> 日期:2026-05-16
|
|
|
|
|
|
>
|
|
|
|
|
|
> 关联主线:
|
2026-05-23 23:38:42 +08:00
|
|
|
|
> - `design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`
|
|
|
|
|
|
> - `design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
|
2026-05-16 22:03:14 +08:00
|
|
|
|
> - `design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`
|
|
|
|
|
|
> - `design/05-editor-mainline/done/5-13-page-block-identity-and-command-contract-v1.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-05-18 17:01:35 +08:00
|
|
|
|
## 0. 归档说明
|
|
|
|
|
|
|
|
|
|
|
|
本文件是 2026-05-16 的页面 AI fast block edit 历史审查快照。其记录的 `local_rule` / `doc_apply_block_ops` 快路径已被后续 `mnote.doc.markdown_edit` 主路径替代,不再作为当前 runtime 口径。
|
|
|
|
|
|
|
|
|
|
|
|
当前有效口径见:
|
|
|
|
|
|
|
|
|
|
|
|
- [10-current-mnote-ai-runtime-review-v1](./10-current-mnote-ai-runtime-review-v1.md)
|
|
|
|
|
|
- [11-current-full-architecture-review-v1](./11-current-full-architecture-review-v1.md)
|
|
|
|
|
|
- [7-18 AI markdown_edit 阶段状态合同漂移](../../../bugs/07-ai/done/7-18-ai-markdown-edit-phase-state-contract-drift-v1.md)
|
|
|
|
|
|
- [7-20 page_ai_workflow 绕过 Hermes tool executor / audit / toggle](../../../bugs/07-ai/done/7-20-page-ai-workflow-bypasses-hermes-tool-executor-v1.md)
|
|
|
|
|
|
|
|
|
|
|
|
归档后的结论:`page-ai/block-edit-workflow` 仍是简单编辑 fast-path 入口,但当前实现应通过模型生成 markdown search/replace / full_content 后调用 `mnote.doc.markdown_edit`,并复用统一 mnote tool executor;`mnote.doc.apply_block_ops` / `mnote.block.*` 只作为结构性块操作辅助。
|
|
|
|
|
|
|
2026-05-16 22:03:14 +08:00
|
|
|
|
## 1. 本轮结论
|
|
|
|
|
|
|
|
|
|
|
|
页面 AI 块写入的慢点不在 Rust 块工具本身,也不在 Convex 持久化本身。
|
|
|
|
|
|
|
|
|
|
|
|
本轮真实浏览器 smoke 显示:
|
|
|
|
|
|
|
|
|
|
|
|
- 旧路径:页面 AI 先调用 `/api/page-ai/block-edit-workflow`,快路径模型阶段耗时约 `7695ms`,随后因模型输出的块定位未命中 projection,`doc_apply_block_ops` 返回 `mnote_block_not_found`,前端继续 fallback 到 `/api/hermes/client/runs`,最终由 Hermes agent 调 `mnote.doc.apply_block_ops` 写入,总可见耗时约 `13246ms`。
|
|
|
|
|
|
- 新路径:同一类简单中文块操作先由 mnote 本地 planner 解析为 `replace/insert_after/delete` operations,再直接调用 Rust `doc_apply_block_ops`。浏览器 smoke 回读可见耗时 `788ms`;后端日志显示 `operation_source=local_rule`、`model_ms=0`、`apply_ms=42`、`total_ms=42`,且未进入 `/api/hermes/client/runs`。
|
|
|
|
|
|
|
|
|
|
|
|
因此,当前要继续做的是 Hermes 工具路由、上下文冻结、dry-run/review 与 Rust 写入校验基建,而不是继续让 Hermes agent 反复执行同一个端到端动作,也不是在 mnote 内新建第二套 AI runtime。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 慢的直接原因
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 通用 agent 编排链路太长
|
|
|
|
|
|
|
|
|
|
|
|
旧页面 AI 编辑链路实际包含:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
浏览器输入
|
|
|
|
|
|
-> Hermes session/profile/tools 初始化
|
|
|
|
|
|
-> 模型理解页面任务
|
|
|
|
|
|
-> 模型选择工具
|
|
|
|
|
|
-> 工具调用
|
|
|
|
|
|
-> 回读或继续推理
|
|
|
|
|
|
-> 最终回复
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这适合复杂任务,但不适合“把 A 替换为 B / 在 A 后插入 C / 删除 D”这类明确块操作。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 模型直接产 operations 不够可靠
|
|
|
|
|
|
|
|
|
|
|
|
本轮快路径第一版已经绕开 Hermes agent,但仍让 DeepSeek 直接根据 `page_xml/page_text` 生成 operations。失败点是:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
model_ms ~= 7695
|
|
|
|
|
|
operations = 3
|
|
|
|
|
|
apply -> mnote_block_not_found
|
|
|
|
|
|
fallback -> Hermes agent
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
说明模型输出了看似正确的操作数,但 block 定位信息没有命中当前 Page Aggregate projection。这个问题不能靠增加 smoke 次数解决,必须让 mnote runtime 在模型前后都掌握定位与校验。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 失败后 fallback 放大了耗时
|
|
|
|
|
|
|
|
|
|
|
|
第一版前端逻辑在快路径失败时继续进入 `/api/hermes/client/runs`。这导致一次用户请求可能经历:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
快路径模型失败成本 + Hermes agent 成功成本
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
本轮已改为:只有后端明确返回 `page_ai_workflow_not_block_edit` 才允许 fallback;其他快路径错误直接在本轮 run 中失败展示,避免重复写入和重复等待。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 已完成的修正
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 页面 AI 快速块编辑 route
|
|
|
|
|
|
|
|
|
|
|
|
已新增并接入:
|
|
|
|
|
|
|
|
|
|
|
|
- `POST /api/page-ai/block-edit-workflow`
|
|
|
|
|
|
- 文件:`rust/crates/mnote-web/src/routes/page_ai_workflow.rs`
|
|
|
|
|
|
|
|
|
|
|
|
该 route 负责:
|
|
|
|
|
|
|
|
|
|
|
|
- 接收当前页面冻结后的 `mnote.page_ai_context.v1`。
|
|
|
|
|
|
- 为明确中文编辑语句先走本地 operation planner。
|
|
|
|
|
|
- 无法本地解析时才调用小模型生成 operations。
|
|
|
|
|
|
- 最终统一走 `mnote.doc.apply_block_ops`,由 Rust 生成 canonical content 并保存。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 简单块操作本地 planner
|
|
|
|
|
|
|
|
|
|
|
|
已支持这类明确表达:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
把「A」替换为「B」;
|
|
|
|
|
|
在「C」后插入「D」;
|
|
|
|
|
|
删除「E」。
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
输出直接是:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{"op":"replace","matchText":"A","content":"B"},
|
|
|
|
|
|
{"op":"insert_after","matchText":"C","content":"D"},
|
|
|
|
|
|
{"op":"delete","matchText":"E"}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
该层的目的不是做通用自然语言理解,而是把高频、低歧义、可确定的块编辑从模型路径剥离出来。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 快路径可观测性
|
|
|
|
|
|
|
|
|
|
|
|
后端日志已记录:
|
|
|
|
|
|
|
|
|
|
|
|
- workflow started/completed
|
|
|
|
|
|
- operation source:`local_rule` 或 `model`
|
|
|
|
|
|
- operations 数量
|
|
|
|
|
|
- model 耗时
|
|
|
|
|
|
- apply 耗时
|
|
|
|
|
|
- total 耗时
|
|
|
|
|
|
|
|
|
|
|
|
smoke 也已在失败时写出 evidence JSON,并记录 `/api/page-ai/*` 与 `/api/hermes/client/*` 请求/响应。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 验证证据
|
|
|
|
|
|
|
|
|
|
|
|
命令:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cargo test -p mnote-web page_ai_workflow -- --nocapture
|
|
|
|
|
|
cargo test -p mnote-web hermes_tools -- --nocapture
|
|
|
|
|
|
MNOTE_PAGE_AI_FAST_TIMEOUT_MS=60000 node scripts/task-page-ai-block-edit-workflow-smoke.js
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
结果:
|
|
|
|
|
|
|
|
|
|
|
|
- `page_ai_workflow`:2 passed。
|
|
|
|
|
|
- `hermes_tools`:22 passed。
|
|
|
|
|
|
- 浏览器 smoke:通过。
|
|
|
|
|
|
|
|
|
|
|
|
最新浏览器 evidence:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
/mnt/Data1T/mnote/tmp/page-ai-block-edit-workflow-smoke/mp86uciu.json
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
关键值:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"timingsMs": {
|
|
|
|
|
|
"pageAiWriteVisible": 788
|
|
|
|
|
|
},
|
|
|
|
|
|
"usedFastWorkflow": true,
|
|
|
|
|
|
"usedHermesRun": false,
|
|
|
|
|
|
"finalTexts": [
|
|
|
|
|
|
"第一段 mp86uciu",
|
|
|
|
|
|
"插入段 mp86uciu",
|
|
|
|
|
|
"第二段已修改 mp86uciu"
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
后端关键日志:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
operation_source="local_rule"
|
|
|
|
|
|
model_ms=0
|
|
|
|
|
|
apply_ms=42
|
|
|
|
|
|
total_ms=42
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 剩余问题
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 不能把本地 planner 当成完整 AI runtime
|
|
|
|
|
|
|
|
|
|
|
|
当前本地 planner 只覆盖低歧义中文引号表达。它证明了正确的 runtime 方向,但不是最终答案。
|
|
|
|
|
|
|
|
|
|
|
|
需要继续建设:
|
|
|
|
|
|
|
|
|
|
|
|
- PageAIContextBuilder:冻结 selection/page context,减少模型输入。
|
|
|
|
|
|
- PageAIIntentParser:先判定是明确块操作、结构化改写、摘要问答、还是复杂编辑。
|
|
|
|
|
|
- PageAIOperationPlanner:把明确操作转成 `mnote.doc.apply_block_ops`,复杂操作才调用小模型。
|
|
|
|
|
|
- PageAIOperationValidator:模型输出后必须用 projection 校验 blockId/matchText/allowedTargetBlockIds。
|
|
|
|
|
|
- PageAIApplyController:统一处理 yolo 写入、失败展示、回读验证、审计日志。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 模型输出 operations 仍需修
|
|
|
|
|
|
|
|
|
|
|
|
当请求不能被本地 planner 解析时,仍会调用模型。该路径必须补:
|
|
|
|
|
|
|
|
|
|
|
|
- 输出 schema 更严格,禁止模型臆造 blockId。
|
|
|
|
|
|
- 优先 `matchText` 或由服务端根据 text resolve block,而不是信任模型 blockId。
|
|
|
|
|
|
- 模型输出后做 dry-run validate,不命中时不要 fallback Hermes agent 重新跑。
|
|
|
|
|
|
- 把 validation error 反馈给用户或进入后续 clarify/retry,而不是隐式整页写。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 Hermes agent 不应承担短路径编辑
|
|
|
|
|
|
|
|
|
|
|
|
Hermes 仍适合:
|
|
|
|
|
|
|
|
|
|
|
|
- 多步骤页面理解。
|
|
|
|
|
|
- 跨页面检索。
|
|
|
|
|
|
- 工具不可直接表达的复杂任务。
|
|
|
|
|
|
- 外部 skill/plugin 编排。
|
|
|
|
|
|
|
|
|
|
|
|
但对当前页面小段落块增删改,mnote 自己的 runtime 应该在浏览器/Rust route 内完成 `intent -> operations -> apply -> readback`。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 下一步建议
|
|
|
|
|
|
|
|
|
|
|
|
优先级应从“继续 smoke”切到“补 AI runtime 基建”:
|
|
|
|
|
|
|
|
|
|
|
|
1. `PageAIIntentParser`
|
|
|
|
|
|
- 输入:用户 prompt、scope、selection、page context。
|
|
|
|
|
|
- 输出:`direct_block_ops | model_block_ops | question | unsupported`。
|
|
|
|
|
|
- 目标:不让每条简单编辑都进入 Hermes agent。
|
|
|
|
|
|
|
|
|
|
|
|
2. `PageAIOperationPlanner`
|
|
|
|
|
|
- 扩展当前本地 planner。
|
|
|
|
|
|
- 支持常见中文/英文明确表达。
|
|
|
|
|
|
- 支持选区内“改成/润色/拆成列表”等可控操作。
|
|
|
|
|
|
|
|
|
|
|
|
3. `PageAIOperationValidator`
|
|
|
|
|
|
- 所有 operations apply 前先 resolve projection。
|
|
|
|
|
|
- 对 blockId、matchText、allowedTargetBlockIds、editable、children、revisionRef 做统一校验。
|
|
|
|
|
|
- 失败返回结构化错误,不 fallback 通用 agent。
|
|
|
|
|
|
|
|
|
|
|
|
4. `PageAIApplyController`
|
|
|
|
|
|
- 统一 yolo 模式下的写入、回读、状态展示和失败提示。
|
|
|
|
|
|
- 后续再接 preview/review session,而不是现在把 review 作为默认阻塞。
|
|
|
|
|
|
|
|
|
|
|
|
5. 模型路径瘦身
|
|
|
|
|
|
- 对必须调用小模型的任务,发送 `page_xml/text + allowed operations schema`。
|
|
|
|
|
|
- 模型只负责生成候选 operations;最终定位、校验和写入仍由 Rust runtime 负责。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 当前判断
|
|
|
|
|
|
|
|
|
|
|
|
小段落编辑低于 10s 已经被证明可达,且当前 smoke 为 `788ms`。
|
|
|
|
|
|
|
|
|
|
|
|
下一阶段的关键不是再证明“能写”,而是把这条快路径产品化:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
用户意图
|
|
|
|
|
|
-> mnote intent/parser
|
|
|
|
|
|
-> operation planner
|
|
|
|
|
|
-> projection validator
|
|
|
|
|
|
-> Rust apply
|
|
|
|
|
|
-> readback
|
|
|
|
|
|
-> UI 状态/审计
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Hermes agent 应从默认编辑执行器退回到复杂任务编排器。
|