适用版本:ChengOS v0.1.0+ | 最后核对:2026-08-12 | 来源:
crates/cheng-core/src/domain/document、crates/cheng-nodes/src/nodes/builtin/document、chengflow-ui/src/features/document、chengflow-ui/src/features/shadow
ChengOS 里的文档不是一个 Markdown 文件,而是存放在数据库中的块树,带有自己的版本历史,以及一个暂存区——Shadow 会话——让智能体可以提出修改,而在人类确认之前完全不触碰原文档。
正是这个设计,让文档可以放心交给模型去改。
领域模型
Document(聚合根)
├── BlockTree
│ └── Block
│ ├── BlockType (paragraph、heading1..3、code……)
│ ├── BlockContent (文本、代码、待办、图片、Callout……)
│ └── BlockMeta (优先级、标签)
├── DocumentVersion[] (历史快照)
└── ShadowSession? (已暂存、尚未应用)
└── ShadowOperation[]
每个块都有稳定的 id、一个父块,以及在兄弟节点中的有序位置。因此编辑文档意味着定位到某个块,而不是某个字符偏移——这恰恰是 LLM 的修改可被评审的原因:差异是一组块,而不是一段文本补丁。
块类型:paragraph、heading1、heading2、heading3、code、bullet_list、numbered_list、todo_item、quote、callout、image、table_view、embed、divider。
块元数据里有两个字段,其重要性远超它的外表:
- 优先级——
low、normal、medium、high、critical - 标签——逗号分隔的列表
它们不是装饰品,而是把文档喂给模型时的过滤轴(见下文《把文档喂给大语言模型》),因此一份 40 页的文档可以在不搭建检索管线的前提下,被缩减为「只要打了 spec 标签的 critical 块」。
编辑器里的文档
文档工作台就在画布旁边:一个文档列表、已打开文档的标签页,以及块编辑器。文档属于某个工作区,而当前工作区会被自动注入到节点执行中——多数文档节点的 workspace_id 留空即可继承。
文档节点
画布上可见的有七个节点,其余的是被 Hub 使用的内部机件。
| 节点 | 作用 |
|---|---|
document/create |
创建文档,可同时写入第一个块 |
document/query |
读取文档——按块返回,或用 as_markdown 返回 Markdown |
document/update_block |
替换某个块的内容或类型 |
document/format_for_llm |
面向模型渲染文档,并可过滤 |
document/extract_items |
把块标签与行转换成可循环的 items |
document/ops_hub |
把整套文档工具暴露给智能体 |
document/query 同时返回块列表和推导出的计数(block_count、character_count),外加 plain_text——足以在决定如何处理之前先按文档体量做分支判断。
document_id 字段是一个动态下拉:选项来自 GET /api/v1/documents?limit=200,而 X-Workspace-Id 中间件已经把它限定在当前工作区。你按标题挑选文档,节点存的是它的 UUID。
把文档喂给大语言模型
document/format_for_llm 之所以存在,是因为把整篇文档塞进提示词通常是错的。它提供四个旋钮:
| 选项 | 取值 | 默认 |
|---|---|---|
priority_filter |
all、high_only、critical_only、normal_and_above |
all |
tag_filter |
逗号分隔的标签 | 无 |
sort_order |
original、priority_desc、priority_asc |
original |
output_format |
markdown、plain_text、structured |
markdown |
外加 max_chars(0 表示不限)和 include_metadata。structured 会在输出里保留块 id——当你期望模型去修改文档时正需要它,因为模型要靠这些 id 把自己的改动定位回去。
Shadow 会话:安全的 AI 编辑
智能体的每一次写入都走 Shadow 会话,而不是直接落到块树上。
shadow_create ──► shadow_write ──► shadow_complete ──► shadow_await_review
(分叉) (暂存操作) (generating→ (阻塞直到
pending_review) 人做出决定)
│
接受 ─────────────┴──────── 拒绝
│ │
merged discarded
Shadow 状态:generating、pending_review、merged、discarded、partially_accepted、expired。其中 merged、discarded、expired 是终态。
partially_accepted 最值得注意——评审是按块进行的,所以用户可以只采纳智能体五处修改中的三处,其余继续挂起。
在界面上,这体现为 Shadow 评审条和块级差异查看器:暂存的插入、更新与删除会叠加显示在真实文档上;如果智能体写作期间底层文档发生了变动,还有一个冲突解决弹窗。
有两个后果值得记牢:
- Hub 的写操作可能返回
requires_review: true和一个shadow_id。执行会进入waiting_for_review并持久地停在那里,直到决策到来——见执行模型。 - 每个写操作都接受
dry_run: true,它只暂存并返回差异而不实际应用。这是让模型自查的低成本手段。
操作 Hub
document/ops_hub 是一个连到智能体 tools 端口的节点,它把整套文档工具一次性暴露出去。智能体通过 operation 字段挑选能力;而节点上的开关决定哪些操作根本存在。
读操作(默认开):query、format_for_llm、document_info、list_documents、search_documents、diff_document、export_document。
写操作(默认关,各自有独立开关):create、create_block、update_block、replace_text、delete_block、move_block、batch_ops、rename_document、duplicate_document、import_document、delete_document、restore_from_export。
开关关闭的操作会立即失败且无任何副作用——智能体无法靠话术绕过开关,因为检查发生在操作执行之前。
调用形态是:operation 和 document_id 放在顶层,其余全部放进 config。扁平的顶层参数也会被接受并折叠进 config,因为模型两种写法都会产出。
有三个操作值得单独点名:
replace_text做精确文本替换,块内其余内容保持不变。用block_id把范围限定到单个块,或用match_scope: document加max_replacements作用于整篇文档。只要模型只需改一句话,它就优于update_block。batch_ops通过单个 Shadow 会话原子地应用最多 100 个操作,于是一次多处改写会作为一个变更集被评审,而不是十二个。export_document配output_format: snapshot会产出一个自包含、可还原的载荷。在危险修改前先拍一个快照,之后用restore_from_export即可回滚。注意:完整的版本历史回滚尚未实现——目前只有快照还原和按内容重新解析这两条路径。
把文档变成循环项
document/extract_items 把文档的标签和行转换成可供循环或批量子流程迭代的数组。用 target 选择抽取什么——tags、lines、pairs、objects、groups;用 combine 选择如何组合——list、sequential、random、selected、zip 或 cartesian(上限 10000 项)。
实用套路:按任务给文档中的块打标签,抽取 pairs,再把它们交给批量子流程逐个处理。
下一步
- 表格工作区——结构化数据的对应物。
- 知识库与工作区上下文——文档在哪里被索引。
- 人工审批与评审——Shadow 会话所依托的评审机制。

暂无评论内容