Files

22 KiB
Raw Permalink Blame History

项目对话与任务协同系统 —— 架构设计文档

版本: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 步):细化工作流阶段流转、文档状态流转的完整定义。

这两块是骨架的基础,定了之后后续步骤就能顺次展开。