docs(system): 纳管系统架构设计与演进规划文档

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WeiCHEN
2026-09-07 21:27:21 +08:00
co-authored by Cursor
parent 7346fcae64
commit e2759394ca
+593
View File
@@ -0,0 +1,593 @@
# 项目对话与任务协同系统 —— 架构设计文档
> 版本:v0.1(骨架设计阶段)
> 日期:2026-09-07
---
## 一、项目背景
### 1.1 已有能力
团队已经构建了一个**智能体小队**,底层基于 PI-agent 实现,并对外暴露了调用接口。该智能体小队能够根据输入的任务,调度多个智能体协同工作,完成复杂任务的执行与产出。
### 1.2 新的系统目标
基于上述智能体小队的能力,构建一个**项目级对话与任务协同系统**,承担以下职责:
1. **日常对话处理**:与项目成员进行自然语言交互,回答问题、提供信息、辅助决策。
2. **工作区感知**:系统能够感知工作区的全部内容,包括:
- 所有用户的对话历史
- 用户上传的文档
- 智能体输出的信息
- 智能体生成的文档
3. **任务执行**:根据用户的请求执行任务,任务可以路由到:
- 智能体小队(复杂、多步、需要协作的任务)
- 单个智能体(边界清晰、可独立完成的任务)
### 1.3 关键设计决策:对话系统复用 PI-agent
经过评估,**对话系统复用 PI-agent 作为编排层**是更合适的方案,理由:
- 智能体小队本身已是基于 PI-agent 实现,能力栈一致,技术复用度高
- 对话系统与执行系统共享 PI-agent 框架,减少技术异构性
- 未来扩展(如新增工具、新增技能)可以统一在 PI-agent 生态内完成
因此本系统的技术栈统一在 PI-agent 之上,分层划分职责。
---
## 二、系统需求
### 2.1 用户与角色
系统服务于**多用户、多项目**的场景。典型用户角色包括:
- 系统工程师
- 项目经理
- 软件工程师
- 其他项目相关角色
每个用户在不同的项目下可以承担不同的角色(编制人、审核人、批准人),角色的差异决定了用户对文档的权限边界。
### 2.2 项目与工作流
- 一个项目下会有**多个工作流**(如需求分析、设计、实施、验收等阶段各自对应一个工作流)。
- 同一时间,一个项目**只能激活一个工作流**。
- 工作流由若干**阶段**组成,阶段之间存在进入/退出约束。
- 工作流内包含若干**文档任务**,每个文档任务有明确的状态机。
### 2.3 文档任务
文档任务是工作流的核心载体,规则如下:
- 每个文档任务都有**编制负责人**,只有编制负责人可以发起文档编制。
- 其他用户**不能**直接发起文档编制,但可以向项目补充信息和材料。
- 文档之间存在**网状依赖关系**:
- 一个补充信息可能影响多个文档
- 一个文档可能影响多个阶段、多个其他文档
- 依赖图是 DAG 甚至带反向引用(修订回溯)的结构
### 2.4 文档的编制、审核、批准
每个文档在其生命周期内涉及三类角色:
| 角色 | 权限 |
|------|------|
| 编制人 | 可修改文档正文、查看修改历史、撤回修改 |
| 审核人 | 不可修改正文,只能添加审核意见、通过或驳回 |
| 批准人 | 不可修改正文,只能添加批准意见、最终通过或最终驳回 |
- 审核驳回 → 文档回到编制阶段,附上意见
- 批准驳回 → 升级处理(需更高决策流程)
### 2.5 文档认领机制
为了让编制人对文档形成稳定的认知,避免被他人擅自修改打乱思路:
- **认领定义**(最小实现):点开过文档、或者通过对话导出过文档,即视为认领。
- **认知偏差保护**:文档被编制负责人认领后:
- 若自上次修改后**编制负责人未查看过新版本** → 智能体小队可直接修改,不通知编制负责人
- 若编制负责人**已查看过最新版本** → 修改前必须通知编制负责人确认
无论哪种情况,都需要告知:
- **发起人**:补充了什么信息、编辑后可能产生什么影响
- **被通知者**:同样的信息(确认时需要知道全貌)
### 2.6 多用户并发
- 一个项目会有**多个用户同时**与智能体对话。
- 用户的请求类型多样:补充材料、发起任务、查询进度、闲聊等。
- 项目状态是全局唯一的,需要协调多个用户的并发请求,避免冲突。
---
## 三、系统骨架设计
### 3.1 总体架构:三层模型
系统采用三层架构,明确分离对话、决策、执行三种职责:
```
┌───────────────────────────────────────────────┐
│ L1 协作对话层(PI-agent,对话系统) │
│ - 与单个用户的多轮对话 │
│ - 不做项目状态决策 │
│ - 输出:候选意图 + 证据 + 置信度 │
└───────────────────────────────────────────────┘
│ 提交候选意图
▼
┌───────────────────────────────────────────────┐
│ L2 项目协调层(项目协调引擎,独立服务) │
│ - 持有项目状态、工作流状态、文档依赖图 │
│ - 验证候选意图的合法性 │
│ - 决定接受 / 拒绝 / 排队 / 转交 │
│ - 触发文档版本、依赖重算、通知 │
└───────────────────────────────────────────────┘
│ 派发的执行任务
▼
┌───────────────────────────────────────────────┐
│ L3 任务执行层(智能体小队 + 单智能体) │
│ - 起草、修订、审核、检索 │
│ - 输出文档版本、检索结果 │
└───────────────────────────────────────────────┘
```
**为什么需要独立的 L2?**
- 多用户并行时,需要一个**全局状态持有者**决定谁的动作被接受。
- 文档依赖图是**强结构化数据**,不适合塞进 LLM 的 prompt 推理。
- 权限规则是**确定性的**,应该由规则引擎执行而非 LLM 自觉。
- L1 的 PI-agent 是对话接口,L3 的智能体是执行单元,**L2 是调度者**。
### 3.2 Context:对话与执行的统一上下文
整个系统的核心信号是:**项目状态、用户负责的文档、进行中的任务,都会成为对话和执行的上下文**。
这不是 prompt 里的提示词,而是一个**结构化数据对象**,由后端服务组装,对话系统和执行智能体共同消费。
#### 3.2.1 UserProjectContext 结构
```
UserProjectContext {
user: {
id, name, role, project_role
}
project: {
id, name,
current_workflow, // 当前激活的工作流
current_stage, // 工作流的当前阶段
stage_rules // 当前阶段的进入/退出约束
}
user_docs: {
composed: [DocA, DocB, ...] // 用户编制的文档
reviewed: [DocC, ...] // 用户审核的文档
approved: [DocD, ...] // 用户批准的文档
claimed: [DocE, ...] // 用户认领过的文档
}
pending: {
confirm_modifications: [...], // 需要用户确认的批次修改
pending_reviews: [...], // 待用户审核的文档
pending_approvals: [...], // 待用户批准的文档
my_drafts_in_progress: [...], // 用户编制中的文档
unread_supplements: [...] // 项目内用户未读的信息补充
}
available_actions: [
"COMPOSE_DOC" // 限制: 仅 user_docs.composed
"SUPPLEMENT_INFO" // 限制: 当前阶段允许
"REVIEW_DOC" // 限制: 仅 user_docs.reviewed
"APPROVE_DOC" // 限制: 仅 user_docs.approved
"EXPORT_DOC" // 限制: 认领后会触发认知偏差检查
"VIEW_DOC" // 限制: 项目内所有相关文档
...
]
recent_events: [...] // 项目内最近 N 条事件
}
```
#### 3.2.2 Context 的两个关键角色
**角色一:意图判断的"已知信息"**
LLM 拿到 Context 后,看到的不是"用户在说什么",而是"用户是谁 + 项目在哪 + 用户能做什么 + 现在有什么事"。意图判断从"开放式分类"变成"在已知约束下选择"。
意图判断的 prompt 模板极简化:
```
你是用户的项目助理。基于用户的项目上下文回答或执行。
【用户项目上下文】
{{context_json}}
【用户输入】
{{user_input}}
【判断】
- 用户的真实意图是? (从 available_actions 里选)
- 需要追问吗? 需要哪些信息?
- 还是直接执行? 执行什么动作?
```
**角色二:任务执行的"硬约束"**
执行智能体被调用时也会拿到 Context,把"能不能做"、"做了之后会触发什么"、"不能做什么"这些硬约束前置到执行层。
例如,智能体小队被调用去修改 DocA 时:
```
任务:修改 DocA 的第3.2 节
约束:
- 编制人是 UserX(不能改 DocA 的其他章节,除非有明确授权)
- 当前阶段: 编制中(允许修改)
- DocA 当前版本: v3,编制人 UserX 已查看 v2(认知偏差敏感)
→ 修改后必须通知 UserX 确认
- DocA 引用了 DocC(下游依赖,需记录影响但不自动改 DocC)
- DocA 被 DocE 引用(上游依赖,DocE 需要被标记"待复核")
```
#### 3.2.3 Context 的组装与生命周期
**组装服务**(最小实现):
```
context_service.assemble(user_id, project_id) -> UserProjectContext:
user = db.get_user(user_id)
project = db.get_project(project_id)
workflow = db.get_workflow(project.current_workflow)
stage = workflow.stages[project.current_stage]
user_docs = db.get_user_doc_relations(user_id, project_id)
pending = db.get_pending_for_user(user_id, project_id)
events = db.get_recent_events(project_id, limit=20)
actions = compute_available_actions(user, project, stage, user_docs)
return UserProjectContext(...)
```
**生命周期**:
- Context 是**只读快照**,每次用户发起对话时由后端组装。
- 对话期间如果发生重要项目事件,协调层通过事件流通知对话系统,触发 Context 重新组装。
- Context 是结构化数据,不依赖 LLM 处理,可以直接查询和聚合。
### 3.3 多用户并发的协调
L1 的 PI-agent **不直接决策**,每个用户的对话实例只负责:
1. 解析用户输入,产出**候选意图**(不是决策,是提案)。
2. 把候选意图 + 上下文证据打包提交给 L2。
3. 等 L2 给回执后,再生成对话回复。
L2 收到候选意图后做:
- **冲突检测**:该时刻其他用户提交了什么?是否冲突?
- **状态检查**:当前工作流阶段是否允许该动作?
- **权限检查**:该用户在他提到的对象上有该权限吗?
- **依赖检查**:依赖的文档是否已就绪?
通过 → 接受;不通过 → 返回带原因的状态码给 PI-agent(例如 `REJECT_REASON_DOC_PENDING`、`REJECT_REASON_ROLE_NOT_OWNER`),PI-agent 用回执生成自然语言反馈。
### 3.4 文档认领与认知偏差机制(骨架版)
#### 3.4.1 认领判定(最小实现)
```
用户与某文档发生以下交互 → 标记该文档为该用户已认领
- 通过对话打开文档查看
- 通过对话导出文档
```
#### 3.4.2 认知偏差检查(文档级,最小实现)
```
doc.modify(doc_id, new_content):
if doc.claimed_by_user contains current_user:
require_owner_confirmation() // 编制负责人确认
else:
modify_directly() // 直接修改
notify_originator_and_affected():
- 补充了什么信息
- 修改了哪些章节
- 可能的下游影响
```
**延后细化项**(数据结构预留位置,实现延后):
- 章节级别的已读标记
- "纯查阅模式"(避免用户误触)
- 影响图的递归分析
- 通知分级(P0/P1/P2/P3)
### 3.5 文档状态机(骨架版)
```
DRAFT // 编制中
├── DRAFT_AUTO_MODIFIED // 未认领用户被直接修改
├── DRAFT_PENDING_CONFIRM // 认领用户被修改,待确认
DRAFT_REVISED // 编制完成
↓
UNDER_REVIEW // 待审核
├── REVIEW_PASSED
└── REVIEW_REJECTED → DRAFT // 审核驳回
PENDING_APPROVAL // 待批准
├── APPROVED // 已批准
└── REJECTED → DRAFT (升级) // 批准驳回
```
每个状态关联:
- 允许的操作
- 需要的角色
- 触发的通知
- 依赖的检查
### 3.6 信息补充的批次化处理
信息补充是事件流,文档修改是批次处理,两者解耦:
```
信息补充事件 ──→ 待处理信息池(每个文档一个池)
│
│ 触发条件(手动触发优先)
▼
修改批次(一次性生成新版本)
│
│ 影响分析 + 认知偏差检查
▼
确认 / 执行
```
触发条件(骨架阶段先支持手动触发):
- **对话触发**:用户主动说"可以开始改了"
- **阈值触发**:累积信息量达到阈值(后续迭代)
- **时间触发**:超过某个时间窗口(后续迭代)
- **阶段触发**:当前工作流阶段即将结束(后续迭代)
---
## 四、意图识别框架方案
### 4.1 为什么不采用简单的"剥洋葱"分类
最初的设计直觉是建立一个意图分类图(树或图结构),从粗粒度意图类型开始,逐层细化分支,最终落到具体任务。
这种思路在**单用户、单轮、任务边界清晰**的场景下可行,但在本系统中遇到根本性挑战:
| 问题 | 原因 |
|------|------|
| 路径爆炸 | 文档类型 × 当前阶段 × 涉及角色 × 历史决策 × 用户权限,组合后分支极大 |
| 状态被忽略 | "帮我继续那份合同"和"开始新的合同"完全不同入口,需要状态上下文 |
| 模糊输入 | "那个事你帮我处理下"这种请求无法单路径归类 |
| 多用户并发 | 多个用户同时对话,单个用户的意图图无法反映全局冲突 |
因此本系统采用更精细的四步法,结合 Context 实现意图识别。
### 4.2 四步法意图识别框架
```
用户输入
↓
[Step 1] 领域路由(Domain Routing)
↓
[Step 2] 意图细化 + 槽位识别(Intent + Slot Filling)
↓
[Step 3] 状态机查询(State Lookup)
↓
[Step 4] 动态规划与执行(Plan-Execute)
```
#### 4.2.1 第一步:领域路由
**职责**:将请求归入大类。
- 闲聊 / 检索
- 工作流类(起草、修订、审核、批准、查询进度)
- 文档类(生成、导出、查看、修订)
- 查询类(项目状态、文档状态、待办事项)
- 外部系统操作类
**实现要点**:
- 分支控制在 5-6 个以内
- 可使用 LLM 分类,也可使用规则
- 故意保持粗粒度,下面还有修正机会
**关键**:注入 Context 之后,LLM 看到的不是"用户说什么",而是"用户是谁 + 项目在哪 + 用户能做什么",分类准确率大幅提升。
#### 4.2.2 第二步:意图细化 + 槽位识别
**职责**:在大类下识别具体意图,并抽取关键参数。
```
候选意图:
- 起草(槽位:文档类型、模板、关联项目阶段)
- 修订(槽位:目标文档、修订章节、修订依据)
- 审核(槽位:目标文档、审核标准)
- 批准(槽位:目标文档)
- 查询进度(槽位:项目、工作流、文档)
```
**核心设计**:**不要追求一次到位**。允许输出"需要澄清的槽位列表",通过追问填槽。
```
SlotFillingResult {
intent: "MODIFY_DOC",
filled_slots: {
target_doc: "DocA", // 已识别
section: "3.2", // 已识别
},
missing_slots: [
"modification_basis" // 缺少:依据是什么补充材料
],
clarification_question: "您希望根据哪份补充材料来修订第3.2 节?"
}
```
#### 4.2.3 第三步:状态机查询
**职责**:调用 L2 协调层,查实例的当前状态、历史决策、待办动作。
这一步是"剥洋葱"思路缺失的关键。意图识别完毕后,**不是直接执行**,而是先看"它现在在哪"。
```
StateLookup {
doc_state: "DRAFT",
doc_version: "v3",
claimed_by: ["UserX"],
last_viewed_by_owner: "v2", // 编制人看过 v2
pending_actions: ["PENDING_CONFIRM_FOR_MOD_v3"],
blocking_dependencies: ["DocC状态: 待复核"]
}
```
基于状态查询结果,可以决定:
- 是否需要编制负责人确认(认知偏差)
- 是否需要等待依赖文档就绪
- 是否需要排队等待其他用户动作完成
#### 4.2.4 第四步:动态规划与执行
**职责**:基于前三步结果,动态生成执行计划。
```
[规划] LLM 根据意图 + 状态 + 上下文生成执行计划
[校验] 工作流规则引擎校验计划合法性
[执行] 一步步执行,每步有 checkpoint
[审批] 对应人工节点挂起,收集批准后再继续
[沉淀] 状态写回工作流引擎,文档归档到工作区
```
**关键原则**:
- 计划应该是**动态生成的、有校验的、有人工节点的**
- 关键节点(审批、对外发送、修改已发布文档)必须有人工 gate
- 不要让 agent 自主完成闭环动作
### 4.3 候选意图的多输出策略
LLM 在意图判断时,**不要直接选一个**,而是输出 top3 + 置信度:
```
Candidates:
1. SUPPLEMENT_INFO (置信度: 0.72)
证据: 用户提到"附件"、"参考"、"情况说明"
2. INITIATE_MODIFY (置信度: 0.45)
证据: 用户提到"改一下"、"更新"
3. CASUAL_CHAT (置信度: 0.15)
证据: 问候语 + 无明确项目对象
```
再结合 Context 中的规则佐证:
- 候选 1 是否匹配当前工作流阶段允许的信息收集动作?
- 候选 2 提到的对象是不是该用户有权限编辑的文档?
- 候选 3 是不是真的没有项目对象?
最后由 L2 做终审,无论 L1 觉得哪个候选最可能,都要提交给 L2 校验。
### 4.4 用户澄清策略
**原则**:**必要时追问,但不滥用追问**。
```
if top1_confidence > 0.75 and top1_passes_rule_check:
execute_directly()
elif top1_and_top2_confidence_close and neither_passed:
ask_user_to_clarify() // "您是想……还是想……?"
else:
fall_through_to_L2_review() // L2 终审决定
```
澄清问题应该:
- 一句话能问清
- 给出候选项让用户选择
- 不要超过 2-3 个问题
### 4.5 意图识别的可观测性
复杂意图系统上线后一定会出错。**必须**记录日志:
```
IntentLog {
session_id,
user_input,
context_snapshot_id,
step1_domain: "WORKFLOW",
step1_confidence: 0.91,
step2_intent: "MODIFY_DOC",
step2_filled_slots: {...},
step2_missing_slots: [...],
step3_state_lookup: {...},
step4_plan: {...},
final_outcome: "ACCEPTED" | "REJECTED" | "PENDING_USER" | "PENDING_L2",
reject_reason: null | "REJECT_REASON_..."
}
```
错了能定位,能加规则或加 few-shot 样本修正。
---
## 五、实施优先级与延后项
### 5.1 骨架阶段必须做
按优先级落地,每步独立可测:
| 步骤 | 内容 | 验证方式 |
|------|------|----------|
| 第 1 步 | 数据模型 + Context 组装 API | 手动调用 API 验证 Context 正确性 |
| 第 2 步 | 项目与文档状态机(正常流程) | 单元测试覆盖所有合法转移 |
| 第 3 步 | 对话系统接入 Context | 简单动作:打开/导出/查看待办 |
| 第 4 步 | 执行智能体接入 Context | 验证智能体在 Context 约束下行为正确 |
| 第 5 步 | 基础事件流与通知(消息列表) | 事件写入数据库、消息列表可读 |
| 第 6 步 | 审核、批准的最小闭环 | 端到端走通一个完整审批流 |
### 5.2 数据模型预留但实现延后
数据结构上为以下能力留好位置,实现上先简化:
- 文档章节级别的已读标记(先做文档级)
- 影响图的递归分析(先做直接依赖列表)
- 通知分级(P0/P1/P2/P3,先做平铺)
- 意见流的独立存储(先做内嵌字段)
- 批次修改的自动触发(先做手动触发)
- 跨项目协调(先做单项目)
### 5.3 关键设计原则总结
1. **骨架优先**:先跑通最小可用闭环,再迭代细节。
2. **职责分离**:对话(L1)、协调(L2)、执行(L3)各司其职。
3. **Context 驱动**:让系统基于已知事实判断,而不是让 LLM 从零推理。
4. **状态机核心**:项目、工作流、文档的所有规则都落到状态机转移约束里。
5. **规则优先于 LLM**:确定性逻辑(权限、状态、依赖)由规则引擎执行,LLM 只做语言理解。
6. **可观测性先行**:每一步意图判断都要可追溯,能定位错误。
---
## 附录 A:术语表
| 术语 | 定义 |
|------|------|
| PI-agent | 智能体框架,对话和执行系统的统一技术栈 |
| 智能体小队 | 基于 PI-agent 的多智能体协同执行系统 |
| Context | UserProjectContext,对话与执行的统一上下文 |
| 工作流 | 项目下的一个流程,由多个阶段组成 |
| 文档任务 | 工作流内的文档编制任务 |
| 编制人 | 负责文档起草与修订的角色 |
| 审核人 | 负责文档审核的角色,不可修改正文 |
| 批准人 | 负责文档最终批准的角色,不可修改正文 |
| 认领 | 用户对文档形成认知的动作(点开/导出) |
| 认知偏差 | 编制人看过文档后被他人擅自修改会扰乱其判断的现象 |
| 候选意图 | L1 对话层输出的意图提案,非最终决策 |
| L1 / L2 / L3 | 协作对话层 / 项目协调层 / 任务执行层 |
---
## 附录 B:下一步建议
按本文档落地时,下一步建议从以下两项开始:
1. **数据模型 + Context 组装 API(第 1 步)**:定义数据库表、Context 数据结构、组装查询接口。
2. **状态机设计(第 2 步)**:细化工作流阶段流转、文档状态流转的完整定义。
这两块是骨架的基础,定了之后后续步骤就能顺次展开。