适用版本:ChengOS v0.1.0+ | 最后核对:2026-08-12 | 来源:
crates/cheng-core/src/domain/knowledge_base、crates/cheng-core/src/domain/workspace、crates/cheng-nodes/src/nodes/builtin/workspace、crates/cheng-engine/src/executor/context.rs
工作区是其他一切的容器——文档、表格、会话、文件和知识库。知识库则是工作区范围内的向量集合:工作区中可被检索的那一半。
要理解本页(以及大部分数据节点),先得搞清楚「当前工作区」是怎么抵达一个正在运行的节点的,所以从这里开始。
工作区
Workspace(聚合根)
├── tenant_id、owner_id
├── WorkspaceMember[] (owner / admin / editor / viewer)
└── WorkspaceSettings
├── default_workflow_id (AI 会话使用的工作流)
├── features (工作区级功能开关)
├── storage_quota
├── trace_retention
└── artifacts (上传上限、LLM 预览预算、保留策略)
成员角色为 owner、admin、editor、viewer。只有 owner 和 admin 能修改工作区设置。
工作区是软删除的(deleted_at),因此删掉一个工作区不会立刻销毁其中的文档与表格。
trace_retention 和 artifacts 值得知道,因为它们正是两件人们通常去全局配置里找的东西的工作区级覆盖项:执行轨迹保留多久,以及产物多大时会被存储拒绝。
环境上下文:节点如何知道自己在哪个工作区
多数数据节点都有一个 workspace_id 输入,它在画布上是隐藏的(x-hidden),通常留空。引擎会在运行时注入它。
有三个字段按这种方式处理——AMBIENT_CONTEXT_FIELDS:
conversation_id workspace_id document_id
它们优先从智能体上下文的 metadata 解析,其次从执行 metadata 解析(conversation_id 还会回落到智能体的 session_id)。
与安全相关的细节是:对工具调用而言,环境注入会强制覆盖模型给出的值。 大语言模型无法通过在工具调用里编造一个 workspace_id 来扩大自己的作用域,因为引擎会在模型产出之后替换该字段。这与沙箱根目录同理——模型给出的 sandbox_root 会被直接丢弃,只采用画布上的静态值。
workspace/context 把注入的值作为普通节点输出暴露出来——workspace_id 加一个 has_workspace 布尔值——供工作流据此分支或记录日志。当工作流是在任何工作区之外被触发时,has_workspace 为假,这在渠道和 API 入口是真实存在的情况。
跨工作区覆盖被刻意不做成画布节点。工作区的选择归应用与 API 入口所有;工作流无法横向伸手去够另一个工作区。
工作区初始化
工作区记录创建后,一个 bootstrap 服务可以选择性地为它填充内容。所有选项默认关闭,由调用方按需开启:
| 选项 | 创建内容 |
|---|---|
create_folders |
根目录树(文档 / 表格 / 会话 / 工作流) |
create_welcome_document |
一篇欢迎文档(需要 create_folders) |
create_default_conversation |
一个初始会话(需要 create_folders) |
create_default_table |
一张初始表格(需要 create_folders) |
create_knowledge_base |
一个默认知识库 |
configure_ai |
功能开关与 default_workflow_id |
依赖规则由 normalize() 强制执行,因此不自洽的组合会被纠正,而不是静默地只生效一半。default_full() 预设只创建目录树——文档、表格、会话和知识库都在用户真正需要时由各自的节点惰性创建。
知识库
KnowledgeBase
├── workspace_id
├── name、description
├── collection_name ← Qdrant 集合名
├── status ← active | building | error | archived
├── document_count
└── config { embedding_model、chunk_size、chunk_overlap…… }
除非你显式指定,集合名会生成为 kb_<workspace_id>_<kb_id>。这种命名就是隔离边界:两个工作区在向量数据库里永远不会撞车,因为工作区 id 是集合名的一部分。
状态在你用脚本操作时很关键。知识库在创建或索引期间为 building,此时查询它为时过早;error 表示索引失败;archived 表示已停用但保留。
config 携带向量嵌入参数——embedding_model、chunk_size、chunk_overlap——以及任意额外设置。它们是每个知识库独立的,而非全局:同一个工作区里的两个知识库可以使用不同的向量嵌入模型。这也正是它们不可互换的原因——用一个向量嵌入模型写入的向量,无法用另一个来检索。
知识库节点
workspace/knowledge_base 有三种模式:
| 模式 | 必填 | 返回 |
|---|---|---|
select(默认) |
kb_id |
选中的知识库 |
list |
— | 工作区内全部知识库 |
create |
name(可选 description、embedding_model) |
新建的知识库 |
输出除了结构化的 knowledge_base 对象,还把 workspace_id 和 kb_id 暴露为扁平的顶层字段,正是为了能直接连到 RAG 节点的输入上,省掉中间的映射步骤。
在 select 模式下,kb_id 是一个动态下拉,选项来自 GET /api/v1/workspaces/current/knowledge-bases?limit=200——你按名字挑,节点存 UUID。
REST 访问
知识库挂在工作区之下管理:
GET|POST /workspaces/:workspace_id/knowledge-bases
GET|PUT|DELETE /workspaces/:workspace_id/knowledge-bases/:kb_id
GET /workspaces/current/knowledge-bases
current 路由从请求上下文解析工作区,节点的下拉用的就是它。
串起来
常见的组合是:
workspace/knowledge_base(select)
│ kb_id
▼
rag/document_indexer ──► 把向量写入集合
…
rag/retriever ──► 查询时把它们取回
知识库创建一次,然后在索引工作流和问答工作流里都按 id 引用它。RAG 管线设计讲的是这两个节点内部发生了什么。
下一步
- RAG 管线设计——建立在知识库之上的索引与检索。
- 文档工作区——被索引的那些文档。
- 存储、Redis 与向量配置——向量数据库本身的配置。

暂无评论内容