From fa6c26ea41852e9cb6884a664625b434cd36e01f Mon Sep 17 00:00:00 2001 From: eaiadmin Date: Thu, 17 Sep 2026 19:26:26 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=B7=A5=E4=BD=9C=E5=8F=B0=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E7=A8=BF=E6=94=B6=E5=85=A5=20docs=20=E4=BD=93?= =?UTF-8?q?=E7=B3=BB=EF=BC=8Croutes.go=20=E6=9B=B4=E5=90=8D=20ai=5Froutes.?= =?UTF-8?q?go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 7 份散落在 frontend/src/views/workbench/ 的设计稿按现有编号体系收入 docs/, 源码目录现在只剩 12 个 .vue 页面: PlatformArchitectureRethink -> docs/01_System_Overall/SY24 WorkbenchArchitectureContract -> docs/02_Architecture/AR05 SkillPackagingSpecification -> docs/02_Architecture/AR06 ArchitectureAlignmentAudit -> docs/02_Architecture/AR07 RoleInteractionDesign -> docs/02_Architecture/AR08 YunQuParityRoadmap_OfficePlatform -> docs/06_Product_Lines/PL04 WorkBuddySkillRpaLearning -> docs/09_Research/RS01 14 处交叉引用同步更新(含 SY20/SY21 里指向旧源码路径的两处);三份 README 索引 补齐 SY20-SY24 与 AR05-AR08、PL04;README 顶部「本目录全是历史快照」的说法改精确 (AR05-AR08、PL04 不属于 V1.1 / V1 快照)。 AR08 文首补注「采纳与废弃」,避免它被当成现行设计照做: - 已采纳:对象不跳页 / 不做独立工具页 / + 菜单挂载 / 切换对象=更新任务上下文 - 已废弃:「数字技术员」第三类对象(SY21 §2.2 已废除 tool 命名)、 「通用助手 = 默认专员」、§14「与本稿冲突以本稿为准」的自我授权 backend-go: internal/api/routes.go -> ai_routes.go。该文件管的是 AI 模型路由 (LLM provider 列表),与 router.go 的 URL 路由注册同包同名易混,加文件头注释钉死。 验证:go build ./... 通过;go vet ./internal/api/ 无告警;npm run build 通过。 Co-Authored-By: Claude Code --- docs/01_System_Overall/README.md | 15 +- ...d_And_Lightweight_Ontology_Architecture.md | 484 +++++++++ ..._Unified_Role_Skill_Action_Architecture.md | 691 +++++++++++++ ...ole_Skill_App_Unified_Task_Architecture.md | 755 ++++++++++++++ ...ialist_Rule_File_And_Skill_Binding_Plan.md | 381 +++++++ .../SY24_Platform_Architecture_Rethink.md | 941 ++++++++++++++++++ .../AR05_Workbench_Architecture_Contract.md | 482 +++++++++ .../AR06_Skill_Packaging_Specification.md | 552 ++++++++++ .../AR07_Architecture_Alignment_Audit.md | 97 ++ .../AR08_Role_Interaction_Design.md | 509 ++++++++++ docs/02_Architecture/README.md | 11 +- .../PL04_YunQu_Parity_Roadmap.md | 447 +++++++++ docs/06_Product_Lines/README.md | 8 +- .../RS01_WorkBuddy_Skill_RPA_Learning.md | 246 +++++ .../backend-go/internal/api/ai_routes.go | 120 +++ .../backend-go/internal/api/routes.go | 51 - 16 files changed, 5735 insertions(+), 55 deletions(-) create mode 100644 docs/01_System_Overall/SY20_Role_Card_And_Lightweight_Ontology_Architecture.md create mode 100644 docs/01_System_Overall/SY21_Unified_Role_Skill_Action_Architecture.md create mode 100644 docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md create mode 100644 docs/01_System_Overall/SY23_Specialist_Rule_File_And_Skill_Binding_Plan.md create mode 100644 docs/01_System_Overall/SY24_Platform_Architecture_Rethink.md create mode 100644 docs/02_Architecture/AR05_Workbench_Architecture_Contract.md create mode 100644 docs/02_Architecture/AR06_Skill_Packaging_Specification.md create mode 100644 docs/02_Architecture/AR07_Architecture_Alignment_Audit.md create mode 100644 docs/02_Architecture/AR08_Role_Interaction_Design.md create mode 100644 docs/06_Product_Lines/PL04_YunQu_Parity_Roadmap.md create mode 100644 docs/09_Research/RS01_WorkBuddy_Skill_RPA_Learning.md create mode 100644 eai_agentplatform/backend-go/internal/api/ai_routes.go delete mode 100644 eai_agentplatform/backend-go/internal/api/routes.go diff --git a/docs/01_System_Overall/README.md b/docs/01_System_Overall/README.md index ac066a6..db9344c 100644 --- a/docs/01_System_Overall/README.md +++ b/docs/01_System_Overall/README.md @@ -2,6 +2,9 @@ > **命名规则:** `SY{NN}_{描述}.md` > **用途:** 系统概述、架构愿景、设计原则 +> +> **当前统一口径:** 术语与一级导航请以 `SY21`、`SY22` 为准。 +> 当前产品一级导航目标态为:`新建任务 / 项目 / 专员·技能·APP·连接器 / 长程APP / 知识库 / 后台管理 / 我的` ## 文件清单 @@ -24,9 +27,14 @@ | `SY14_Industry_Derived_Connector_And_Application_Requirement_Matrix.md` | 从六个行业反推连接器与应用方向矩阵 | | `SY15_Terminology_Benchmark_Ontology_Semantic_Layer_Object_Layer.md` | 本体层 / 语义层 / 对象层命名基准研究(含星邺汇捷 / Palantir / Microsoft / Salesforce 对照) | | `SY16_Ontology_Generalizes_Data_Actions_And_Workflows.md` | 本体如何让数据、动作、工作流一般化 | -| `SY17_Workbench_UI_Wireframes.md` | 数字员工平台 UI 线框图(知识库固定 + 专员动态生长) | +| `SY17_Workbench_UI_Wireframes.md` | 数字员工平台 UI 线框图(早期线框推演,当前命名与导航以 SY22 为准) | | `SY18_DWP_DW_ADW_Formal_Design_Contract.md` | DWP / DW / ADW 正式设计合同(供人和 AI 共用的对象基准) | | `SY19_Universal_Digital_Worker_Product_Planning.md` | 通用数字员工平台 V1.0 产品规划(先通用、后定制的产品打法收口) | +| `SY20_Role_Card_And_Lightweight_Ontology_Architecture.md` | 角色卡与轻量本体对象架构(专家对象交互属性的历史收敛稿) | +| `SY21_Unified_Role_Skill_Action_Architecture.md` | 统一 Expert / Skill / Action 总架构确认稿(六层架构与命名收口) | +| `SY22_Role_Skill_App_Unified_Task_Architecture.md` | Expert / Skill / App 统一任务架构(把 App 升级为一级对象、补齐完整一级导航、并将知识库确认为默认内建 App,产品名收口为“长程APP”) | +| `SY23_Specialist_Rule_File_And_Skill_Binding_Plan.md` | 专员「岗位说明书 + 技能绑定」改造方案(诊断运行时同质化根因 + 三步打通链路 + AionUi 规则文件改写清单) | +| `SY24_Platform_Architecture_Rethink.md` | 数字员工平台整体架构重思考(Workbench 收敛与对象化迁移**历史稿**,其结论已并入 SY21 / SY22) | ## 当前主线关系 @@ -44,3 +52,8 @@ 12. `SY17`:把六层架构落成数字员工平台工作台线框,明确平台不再是单一导航后台 13. `SY18`:正式定义 DWP / DW / ADW 的结构合同、字段规范和 AI 生成规则 14. `SY19`:把当前阶段产品路线正式收口为「先通用数字员工、后行业包与企业定制」 +15. `SY20`:把角色卡从 UI 文案提升为角色对象内建属性,并确认轻量本体的落地边界 +16. `SY21`:正式收口六层架构与 `expert / skill / action / connector / policy` 总命名 +17. `SY22`:在 `SY21` 基础上补齐第三类一级对象 `app`,补全完整一级导航视图,并将知识库确认为默认内建 App,把平台升级为 Expert / Skill / App 三对象统一任务系统,产品名收口为“长程APP” +18. `SY23`:定位到「专员与技能之间缺绑定边、专员说明未进 prompt」是专员的运行时空洞根因,给出三步打通方案与 AionUi 规则文件改写清单 +19. `SY24`:Workbench 收敛与对象化迁移的历史重思考稿,结论已并入 `SY21` / `SY22`;本文只作背景追溯,命名一律以 `SY21` 为准 diff --git a/docs/01_System_Overall/SY20_Role_Card_And_Lightweight_Ontology_Architecture.md b/docs/01_System_Overall/SY20_Role_Card_And_Lightweight_Ontology_Architecture.md new file mode 100644 index 0000000..6bbf5b1 --- /dev/null +++ b/docs/01_System_Overall/SY20_Role_Card_And_Lightweight_Ontology_Architecture.md @@ -0,0 +1,484 @@ +# SY20 — 角色卡与轻量本体对象架构 + +> 状态:架构建议稿 +> 日期:2026-09-16 +> 关联文档: +> - `SY03_Knowledge_Centric_Agent_Platform_Strategy.md` +> - `docs/01_System_Overall/SY24_Platform_Architecture_Rethink.md` + +> 2026-09-16 术语同步: +> 本文档继续成立,但请以 `SY21_Unified_Role_Skill_Action_Architecture.md`、`SY22_Role_Skill_App_Unified_Task_Architecture.md` 为总架构收口版本。 +> 其中最关键的口径更新是: +> - 角色卡属于专家对象属性,不再单列为独立架构层 +> - 对外当前统一采用 `专家 / 技能 / 长程APP / 知识库` +> - 对内正式收敛为 `expert / skill / app / action / connector / policy` +> - 当前一级导航目标态为 `新建任务 / 项目 / 专员·技能·APP·连接器 / 长程APP / 知识库 / 后台管理 / 我的` +> - 本文中原先出现的“角色 / Role / 工具”概念,应理解为历史过渡词,未来命名统一转向 `专家 / 技能 / action` + +--- + +## 1. 这份文档要回答什么 + +在当前工作台架构下,我们已经确认: + +- 专员和技能都不应该再是独立页面 +- 它们都应该作为可挂载对象进入 `/home` +- 当前最大问题已经不是“怎么跳转”,而是“对象本身怎么定义” + +这份文档要回答 3 个关键问题: + +1. 专员和技能型角色是否应该统一为同一种对象 +2. 是否应该引入类似 character.ai 的“角色卡” +3. 是否应该在当前阶段引入“本体 / ontology” + +--- + +## 2. 核心结论 + +### 2.1 专员和工具应统一为同一种对象 + +建议统一收敛为: + +**角色对象(Role Object)** + +两者底层结构基本一致,差异只在能力边界: + +- 工具:单能力、单任务域、通常不再继续调用别的工具 +- 专员:多步骤、可编排、允许调用工具完成子任务 + +也就是说: + +**工具不是“低一层的页面”,而是“能力范围更窄的角色”。** + +### 2.2 应该加入角色卡,而且要作为对象内建属性 + +建议明确加入: + +**Role Card = 角色对象的可定义交互外壳** + +它不只是欢迎语,而是对象如何被用户感知、如何开场、如何引导用户进入任务的第一层契约。 + +欢迎语应从硬编码 UI 文案,升级为: + +**对象属性驱动的开场定义** + +### 2.3 应该加入本体,但当前只做轻量本体 + +建议加入: + +**轻量运营本体(Lightweight Operational Ontology)** + +但不建议现在就上完整 RDF / OWL / SHACL 那套重语义工程。 + +当前阶段更合适的是: + +- 先定义平台自己的对象类型、动作类型、产物类型、关系类型 +- 先服务工作台挂载、执行链、权限、结果展示 +- 先把“平台语义层”立起来 + +而不是一开始就追求语义网级别的正式本体工程。 + +--- + +## 3. 为什么要引入角色卡 + +### 3.1 当前问题 + +现在工作台的问题不是“没有欢迎语”这么简单,而是: + +- 选了专员后,页面不知道该如何以这个对象的身份开场 +- 选了工具后,只是多了一个 chip,但没有人格化 / 职责化表达 +- 当前欢迎态仍然是“通用助手门厅”,不是“当前对象门厅” + +这说明我们缺的不是一句文案,而是: + +**对象自我介绍能力** + +### 3.2 角色卡的价值 + +角色卡负责定义: + +1. 这个对象是谁 +2. 它擅长什么 +3. 它怎么和用户说话 +4. 它建议用户怎么开始 +5. 它不做什么 + +所以角色卡不是装饰,而是对象定义的一部分。 + +### 3.3 角色卡应该覆盖的内容 + +建议 `role_card` 最少包含: + +```json +{ + "name": "合同审查专员", + "tagline": "把合同风险、红线和交付意见整理清楚", + "greeting": "我是合同审查专员,已经准备好帮你定位条款风险、整理红线建议,并输出可交付的审查结果。", + "relationship_to_user": "你的法务协作搭档", + "tone": "专业、直接、可追溯", + "opening_prompt": "把合同发给我,或者直接告诉我这次要重点盯哪些条款。", + "starter_prompts": [ + "审查这份采购合同的风险点", + "帮我整理一版 redline 建议", + "重点看赔偿责任和终止条款" + ], + "boundaries": [ + "我会指出风险,但不替代人工法律意见", + "高风险条款会明确标出待人工确认" + ] +} +``` + +--- + +## 4. 为什么要引入轻量本体 + +### 4.1 我们真正需要的不是“知识图谱名词”,而是平台统一语义 + +如果没有本体层,平台会继续出现这些问题: + +- 专员和工具只是 UI 名字,没有统一语义身份 +- 任务挂的是 `specialist_key`,但系统不知道对象之间是什么关系 +- 工作流、产物、动作、知识对象各自分散,难以统一编排 +- 后面做多对象协作时,平台不知道谁能调用谁、产出什么、依赖什么 + +### 4.2 当前阶段不适合直接上重本体 + +完整本体工程的问题不在“对不对”,而在“此刻成本太高”: + +- 建模成本高 +- 治理成本高 +- 版本演进成本高 +- 需要更成熟的数据治理和知识工程流程 + +对我们当前阶段来说,最重要的是先统一平台对象语义,而不是先做语义网工程。 + +### 4.3 当前阶段建议的本体范围 + +建议只定义 5 类核心语义: + +1. **角色类型** + - specialist + - tool + +2. **对象类型** + - contract + - customer + - report + - resume + - knowledge_item + +3. **动作类型** + - analyze + - extract + - review + - draft + - translate + - escalate + +4. **产物类型** + - summary + - report + - redline + - checklist + - spreadsheet + +5. **关系类型** + - can_use_tool + - produces_artifact + - acts_on_object + - depends_on + - cites_knowledge + +这就足以支撑我们当前的工作台对象化。 + +--- + +## 5. 建议采用的统一对象架构 + +### 5.1 根对象:`object_definition` + +不建议再把“专员定义”和“工具定义”拆成两套根结构。 + +建议统一使用已有方向里的: + +**`object_definition`** + +然后在里面用 `role_kind` 区分: + +- `specialist` +- `tool` + +### 5.2 建议结构 + +```json +{ + "id": "obj.contract-review", + "code": "EAI-R-001", + "key": "contract-review", + "label": "合同审查专员", + "object_class": "role", + "role_kind": "specialist", + "source": "eai", + "status": "active", + "role_card": { + "tagline": "把合同风险、红线和交付意见整理清楚", + "greeting": "我是合同审查专员,已经准备好帮你定位条款风险并输出审查建议。", + "relationship_to_user": "你的法务协作搭档", + "tone": "专业、直接、可追溯", + "opening_prompt": "把合同发给我,或者告诉我这次重点审哪些条款。", + "starter_prompts": [ + "审查这份采购合同的风险点", + "帮我整理一版 redline 建议" + ], + "boundaries": [ + "我会标出高风险项", + "最终法律意见仍需人工确认" + ] + }, + "capability_profile": { + "summary": "条款识别、风险分析、红线建议、交付摘要", + "input_types": ["document", "text"], + "artifact_types": ["summary", "redline", "checklist"], + "can_chat": true, + "can_execute": true + }, + "collaboration_profile": { + "callable_tool_keys": ["document-translate", "batch-extract"], + "can_be_called_by": [], + "orchestration_mode": "supervisor" + }, + "ontology_binding": { + "acts_on_object_types": ["contract"], + "action_types": ["review", "analyze", "draft"], + "produces_artifact_types": ["summary", "redline", "checklist"], + "knowledge_domains": ["legal", "compliance"] + }, + "execution_profile": { + "settings_schema": [], + "executor_key": "contract-review", + "result_card_key": "contract-review" + } +} +``` + +### 5.3 工具对象也用同一结构 + +工具只是把 `role_kind` 改为 `tool`: + +```json +{ + "key": "document-translate", + "label": "文档翻译", + "object_class": "role", + "role_kind": "tool", + "role_card": { + "tagline": "把内容准确翻译成目标语言并输出指定格式", + "greeting": "我是文档翻译工具,可以把文本、文档整理成目标语言输出。", + "relationship_to_user": "你的翻译执行角色" + }, + "collaboration_profile": { + "callable_tool_keys": [], + "orchestration_mode": "none" + } +} +``` + +也就是说: + +**工具和专员不是两套模型,而是一套模型上的两个角色种类。** + +--- + +## 6. 专员与工具的真正差异 + +建议只保留这一个核心差异: + +### 6.1 工具 + +- 聚焦单能力 +- 输入输出边界更明确 +- 通常不再调别的工具 +- 更像“执行角色” + +### 6.2 专员 + +- 聚焦任务闭环 +- 可以调用多个工具 +- 会管理步骤、产物、待确认点 +- 更像“编排角色” + +所以: + +**专员 = 能调用工具的角色对象** + +而不是: + +**专员 = 页面,工具 = 页面里的功能按钮** + +--- + +## 7. 对工作台交互的直接影响 + +### 7.1 欢迎态改成对象驱动 + +当前 `/home` 的欢迎态不应再写死成通用助手。 + +应该改为: + +1. 如果当前挂的是对象,就优先显示该对象的 `role_card.greeting` +2. `starter_prompts` 作为欢迎态快捷入口 +3. `tagline / opening_prompt / boundaries` 作为辅助说明 +4. 如果没有挂对象,再退回通用助手默认欢迎态 + +### 7.2 输入框左侧对象 chip 不再只是标签 + +它应表达: + +- 当前对象是谁 +- 当前对象属于 `specialist` 还是 `tool` +- 当前对象的 `tagline` + +### 7.3 右栏不应再叫“专员面板” + +因为工具也是角色对象。 + +建议后续改成更中性的: + +- `ObjectPanel` +- `RolePanel` + +只是当对象是 `specialist` 时,展示更完整的工作流与产物; +当对象是 `tool` 时,展示它的输入边界、执行结果、相关产物。 + +--- + +## 8. 对数据层的建议 + +### 8.1 先别引入新根对象名,先复用 `object_definition` + +当前项目已经在往: + +- `object_definition` +- `task_object_instance` +- `object_run` +- `task_message` + +这条路上走。 + +因此不建议再新起一套: + +- `specialist_definition` +- `tool_definition` +- `role_definition` + +而是: + +**在 `object_definition` 里加角色属性分组。** + +### 8.2 建议新增的对象属性分组 + +建议统一加这几组: + +- `role_kind` +- `role_card_json` +- `capability_profile_json` +- `collaboration_profile_json` +- `ontology_binding_json` + +### 8.3 后端可以分阶段兼容 + +第一阶段不必立刻改完后端表。 + +可以先在前端 registry 和 specialist adapter 里形成统一结构: + +- 内置工具走前端静态定义 +- 专员走后端字段 + 前端适配 +- 统一映射成 `object_definition` 视图模型 + +等结构稳定后,再把后端持久化模型补齐。 + +--- + +## 9. 当前阶段的实施建议 + +### Phase 1:先把角色卡引入前端对象视图层 + +先做: + +- `role_card` 统一适配层 +- `/home` 欢迎态改为对象驱动 +- 专员 / 工具都能显示自己的 greeting 与 starter prompts + +这一步不要求后端表结构大改。 + +### Phase 2:把 Studio / Market 的专员编辑升级为对象编辑 + +新增: + +- 欢迎语 +- tagline +- opening prompt +- starter prompts +- boundaries + +让专员卡真正可定义。 + +工具也开始逐步以同样结构注册。 + +### Phase 3:补轻量本体层 + +建立平台统一字典: + +- object types +- action types +- artifact types +- relation types + +先服务工作台、运行链和知识引用,不追求重语义工程。 + +--- + +## 10. 最终建议 + +这次不建议二选一,而是建议同时引入两层: + +### 必须现在就做 + +1. **角色卡** + - 必须加 + - 而且要作为对象属性 + - 欢迎语、引导语、starter prompts 都应从这里来 + +2. **统一对象模型** + - 专员和工具统一为 `object_definition` + - 用 `role_kind` 区分 + - 专员只是“可调用工具的角色” + +### 应该现在开始,但先做轻量版 + +3. **轻量本体** + - 必须做 + - 但只做平台运营本体 + - 不要一开始就上重 RDF / OWL 工程 + +### 暂时不要做的事 + +4. 不要再继续把“欢迎语”写成页面模板文案 +5. 不要再继续把“工具”当页面,而不是角色 +6. 不要现在就把本体做成知识工程大项目 + +--- + +## 11. 一句话收口 + +建议把平台对象统一定义为: + +**“带角色卡的角色对象”** + +其中: + +- 工具 = 单能力角色 +- 专员 = 可调用工具的编排角色 +- 本体 = 这些角色、动作、对象、产物之间的轻量语义骨架 diff --git a/docs/01_System_Overall/SY21_Unified_Role_Skill_Action_Architecture.md b/docs/01_System_Overall/SY21_Unified_Role_Skill_Action_Architecture.md new file mode 100644 index 0000000..7dee9d2 --- /dev/null +++ b/docs/01_System_Overall/SY21_Unified_Role_Skill_Action_Architecture.md @@ -0,0 +1,691 @@ +# SY21 — 统一 Expert / Skill / Action 总架构确认稿 + +> 状态:总架构确认稿 +> 日期:2026-09-16 +> 关联文档: +> - `SY03_Knowledge_Centric_Agent_Platform_Strategy.md` +> - `SY15_Terminology_Benchmark_Ontology_Semantic_Layer_Object_Layer.md` +> - `SY20_Role_Card_And_Lightweight_Ontology_Architecture.md` +> - `docs/01_System_Overall/SY24_Platform_Architecture_Rethink.md` + +> 2026-09-16 术语同步: +> 本文原先使用 `Role / role / role_card` 作为主术语。 +> 现已确认 `Role` 不再作为推荐命名,统一改口为: +> - 对外:`专家(Expert) / 技能 / 连接器` +> - 对内:`expert / skill / action / connector / policy` +> 文中尚未完全迁移的 `role`、`role_card`、`角色对象层`,后续均应分别理解为 `expert`、`expert_card`、`专家对象层`。 + +--- + +## 1. 这份文档要确认什么 + +在前面几轮讨论后,当前项目已经不再缺“局部页面方案”,真正缺的是一份统一总架构结论,用来回答以下问题: + +1. 平台到底按几层架构来收敛 +2. 本体、角色卡、对象、技能、Action、连接器分别处于什么位置 +3. 对外到底暴露什么,对内到底运行什么 +4. 是否还要继续使用 `tool` 这个词 +5. 当前代码和文档后续应该往哪个方向迁移 + +这份文档的目标不是给出某个局部功能设计,而是把平台的总语言、总结构、总对象模型先定下来。 + +--- + +## 2. 最终结论 + +## 2.1 平台采用六层总架构 + +建议正式统一为六层: + +1. 外部连接层 +2. 本体与语义上下文层 +3. 总线与编排层 +4. 能力层 +5. 专家对象层 +6. 工作台与运行治理层 + +这六层已经足以覆盖: + +- 通用数字员工 +- 文档类、知识类、分析类能力 +- 工业设备监测、安防、巡检、告警、工单等强外部接口场景 + +## 2.2 不再把 `tool` 作为正式命名 + +命名上正式收敛为: + +- 对外:`专家 / 技能 / 连接器` +- 对内:`expert / skill / action / connector / policy` + +结论: + +**以后不再新增正式架构概念 `tool`。** + +`tool` 只作为历史迁移词存在,用于兼容旧文档、旧字段、旧目录,不再作为未来架构的主词。 + +## 2.3 对外默认暴露 `专家 + 技能` + +外部用户看到的应该是: + +- 专家 +- 技能 +- 欢迎语 +- starter prompts +- 可完成的任务 + +而不是: + +- tool 列表 +- 底层调用动作 +- 技术执行接口 + +所以: + +**用户入口层默认暴露 skill,不暴露 action。** + +## 2.4 对内统一使用 `action` + +内部最小执行单元统一叫: + +**Action** + +它用于承接: + +- 一次原子能力执行 +- 一次外部系统调用 +- 一次标准化输入输出动作 +- 一次可授权、可审计、可编排的执行操作 + +也就是说: + +- `skill` 是任务化能力包 +- `action` 是原子执行单元 + +## 2.5 要引入本体层,而且是必需的 + +如果平台后续要扩展到: + +- 工业设备运行监测员 +- 安防管理员 +- 巡检专员 +- 告警分析专员 +- 工单协调专员 + +那么本体层不是可选项,而是必要项。 + +原因很简单: + +没有本体层,上层对象和工作台体验很快就会被行业对象、事件、状态、规则的差异撕裂。 + +## 2.6 专家卡不是独立层,而是专家对象属性 + +角色卡仍然要保留,但它不是一层单独架构层。 + +更准确的定义是: + +**专家卡 = 专家对象的交互属性集** + +它负责: + +- 角色是谁 +- 角色如何开场 +- 角色如何和用户说话 +- 角色建议用户如何开始 +- 角色承诺做什么、不做什么 + +--- + +## 3. 六层总架构定义 + +## 3.1 第一层:外部连接层 + +这一层负责连接真实世界和外部系统。 + +包括: + +- PLC +- SCADA +- MES +- ERP +- CRM +- CMMS / 工单系统 +- IoT 平台 +- 视频平台 +- 文档系统 +- 数据库 +- API / Webhook / MQ + +这一层回答的是: + +**数据从哪里来,动作往哪里去。** + +在本项目里,这一层的标准对象是: + +- `connector_definition` +- `connector_binding` + +## 3.2 第二层:本体与语义上下文层 + +这一层负责定义平台语义。 + +它不是简单的表结构,而是平台统一语义底座。 + +当前阶段建议采用轻量本体,先定义: + +1. 对象类型 + - device + - alarm + - work_order + - report + - contract + - knowledge_item + - person + - site + +2. 动作类型 + - monitor + - inspect + - diagnose + - review + - extract + - translate + - escalate + - dispatch + +3. 状态类型 + - running + - warning + - critical + - pending + - approved + - closed + +4. 关系类型 + - belongs_to + - depends_on + - triggers + - resolves + - cites + - produces + +这一层回答的是: + +**系统里到底有什么对象,它们如何关联,允许哪些动作。** + +## 3.3 第三层:总线与编排层 + +这一层负责流转,不负责人格,不负责 UI。 + +它至少应包含三类总线: + +1. 上下文总线 +2. 事件总线 +3. 能力编排总线 + +职责包括: + +- 角色之间的协作 +- skill 对 action 的编排 +- action 对 connector 的调用 +- 事件进入任务上下文 +- 审批和安全边界控制 + +这一层回答的是: + +**对象怎么流动,能力怎么协作,任务怎么推进。** + +## 3.4 第四层:能力层 + +这一层正式拆成三类对象: + +1. `skill` +2. `action` +3. `policy` + +### 3.4.1 skill + +`skill` 是面向任务的能力包。 + +它通常由以下部分组成: + +- intent +- prompt template +- action chain +- input schema +- output schema +- artifact schema +- guardrails + +可以理解为: + +**skill = 用户任务入口 + 规则 + 执行编排模板** + +### 3.4.2 action + +`action` 是内部原子执行单元。 + +例如: + +- `read_device_status` +- `query_alarm_history` +- `create_work_order` +- `extract_contract_terms` +- `translate_document` +- `generate_shift_report` + +它必须具备: + +- 标准输入 +- 标准输出 +- 权限边界 +- 风险级别 +- 审计记录 + +### 3.4.3 policy + +`policy` 负责定义约束和治理条件,例如: + +- 某 action 是否允许自动执行 +- 是否需要人工确认 +- 哪些角色可以调用哪些 skill +- 哪些 connector 只能读不能写 + +这一层回答的是: + +**系统能做哪些事,这些事如何以任务化和原子化两种粒度存在。** + +## 3.5 第五层:专家对象层 + +这是用户真正感知到的执行主体层。 + +专家对象统一采用一个根模型,例如: + +- `object_definition` + +专家对象不再分裂成多套根结构。 + +建议至少包含两类专家: + +1. `assistant` +2. `specialist` + +如果后续需要更强的“执行人格化对象”,可补充: + +3. `executor` + +其中: + +- `assistant`:默认兜底编排专家 +- `specialist`:面向领域任务的主专家 +- `executor`:必要时暴露给用户的窄能力执行专家 + +这里最关键的变化是: + +**专家对象不直接等于 action。** + +专家对象负责承接用户、暴露 skill、组织交互体验; +真正执行时,仍然落到 `skill -> action -> connector`。 + +### 3.5.1 专家卡属于这一层 + +`expert_card` 是专家对象属性,不再单列成架构层。 + +建议最少包含: + +- name +- tagline +- greeting +- tone +- opening_prompt +- starter_prompts +- boundaries +- relationship_to_user + +### 3.5.2 专家对象与能力层的关系 + +专家对象不直接暴露所有 action。 + +更合适的关系是: + +- 专家对象暴露 `skill` +- `skill` 编排多个 `action` +- `action` 调用 `connector` + +所以: + +**专家承接用户,skill 组织任务,action 执行动作。** + +## 3.6 第六层:工作台与运行治理层 + +这一层是最终运行现场。 + +包括: + +- `/home` Workbench +- task +- task_message +- task_object_instance +- object_run +- artifact +- workflow panel +- audit / observe / approval + +这一层回答的是: + +**一条具体任务如何挂载角色、发送消息、运行 skill、触发 action、沉淀产物。** + +--- + +## 4. 最终对象关系 + +建议以后统一采用下面这条主链路: + +`user -> expert -> skill -> action -> connector` + +再叠加本体层: + +`ontology -> expert / skill / action / connector` + +也就是说: + +1. 用户不是直接找 action +2. 用户是进入某个专家 +3. 专家向用户暴露 skill +4. skill 编排 action +5. action 调用 connector +6. 全程受 ontology 和 policy 约束 + +--- + +## 5. 对外暴露模型 + +## 5.1 对终端用户 + +默认暴露: + +- 专员 +- 技能 +- 欢迎语 +- 任务入口 +- 产物结果 + +默认不暴露: + +- action +- connector 技术细节 +- 编排细节 +- 底层风险策略 + +## 5.2 对管理员 / 搭建者 + +可以暴露: + +- skill 绑定了哪些 action +- action 绑定了哪些 connector +- 权限和审批条件 +- 输出 schema +- 审计与日志 + +## 5.3 对运行时 + +直接处理: + +- action call +- connector call +- context binding +- event routing +- approval gate +- audit log + +--- + +## 6. 为什么不再使用 `tool` + +## 6.1 对外不合适 + +`tool` 太像功能按钮集合,不像任务语言,也不像角色语言。 + +尤其在数字员工和工业智能体场景里,它会把产品体验拉回“工具页”心智。 + +## 6.2 对内也不够精确 + +内部真正需要区分的是: + +- 任务级能力包:`skill` +- 原子执行动作:`action` +- 外部系统入口:`connector` + +`tool` 夹在中间,语义反而模糊。 + +## 6.3 正式命名替换 + +后续正式命名建议统一为: + +- 用户可见的 `tool` -> `skill` +- 内部原子执行的 `tool` -> `action` +- `chatTools` -> `availableSkills` +- `currentToolKey` -> `currentSkillKey` +- `tool_keys` -> `skill_keys` +- 顶部设置条组件 -> `SkillStrip` 或 `ActionStrip` +- 前端技能定义目录 -> `src/skills/*` +- 后端原子动作定义 -> `action_definition / action_refs / action_records` + +说明: + +当前仓库已有大量 `tool` 历史字段,不建议在总架构确认稿阶段立刻全量重命名; +但从现在开始,**不再新增新的正式 `tool` 命名。** + +--- + +## 7. 角色、技能、Action 的清晰边界 + +## 7.1 角色 + +回答的是: + +**谁来承接这次任务。** + +角色包含: + +- 身份 +- 角色卡 +- 协作边界 +- 可暴露 skills +- 权限范围 + +## 7.2 技能 + +回答的是: + +**用户想完成什么任务。** + +技能包含: + +- 任务意图 +- 开始条件 +- 输入输出约束 +- 产物定义 +- 对 action 的编排模板 + +## 7.3 Action + +回答的是: + +**系统这一步到底执行了什么动作。** + +Action 包含: + +- 原子能力定义 +- 风险级别 +- 调用协议 +- connector 绑定 +- 审计信息 + +--- + +## 8. 角色卡和本体是否重叠 + +不重叠。 + +它们都可能写到“能力”相关内容,但目标完全不同。 + +## 8.1 本体 + +服务机器一致性,定义: + +- 对象 +- 动作 +- 状态 +- 关系 +- 规则 + +## 8.2 角色卡 + +服务人机交互一致性,定义: + +- 开场方式 +- 角色语气 +- 任务入口提示 +- 用户对该角色的体验预期 + +一句话: + +**本体定义世界,角色卡定义人格。** + +--- + +## 9. 对当前 Workbench 的直接要求 + +## 9.1 欢迎语必须对象属性驱动 + +当用户挂载某个角色后,Workbench 不应继续显示通用助手欢迎语。 + +应改为: + +1. 优先显示当前专家的 `expert_card.greeting` +2. 下方展示 `starter_prompts` +3. 辅助展示 `tagline / opening_prompt / boundaries` +4. 无挂载角色时,再退回默认助手欢迎态 + +## 9.2 输入区顶部应体现当前对象 + +输入区顶部不应只显示一个孤立 chip。 + +应明确表达: + +- 当前对象是谁 +- 当前这次输入会触发什么任务语义 +- 当前对象是否存在可调设置 + +并冻结以下交互规则: + +1. `+` 右边一次只显示一个当前对象 +2. 当前对象要么是专员,要么是技能,要么是默认助手 +3. 专员内部调用技能时,下游技能只进入执行链与右侧面板,不在输入区显性双挂 + +## 9.3 右侧面板应是对象面板,不再是旧“工具面板” + +建议中性命名: + +- `ObjectPanel` +- `ExpertPanel` + +其内容由当前角色和当前运行态决定,而不是由旧页面类型决定。 + +--- + +## 10. 目标数据结构建议 + +## 10.1 角色定义 `object_definition` + +建议继续作为统一根对象,至少补充: + +- `object_kind` +- `expert_card_json` +- `capability_profile_json` +- `collaboration_profile_json` +- `ontology_binding_json` + +## 10.2 技能定义 `skill_definition` + +建议新增独立定义层,至少包含: + +- `id` +- `key` +- `label` +- `description` +- `exposed_to_user` +- `input_schema` +- `output_schema` +- `artifact_schema` +- `action_refs` +- `policy_refs` +- `ontology_binding` + +## 10.3 Action 定义 `action_definition` + +建议新增,至少包含: + +- `id` +- `key` +- `label` +- `action_type` +- `connector_ref` +- `input_schema` +- `output_schema` +- `risk_level` +- `approval_mode` +- `audit_level` + +## 10.4 运行态 + +建议继续沿用并收敛为: + +- `task` +- `task_object_instance` +- `task_message` +- `object_run` +- `artifact` + +其中: + +- `task_object_instance` 负责挂载当前角色 +- `task_message` 负责持久化会话 +- `object_run` 负责记录 skill 和 action 的执行链 + +--- + +## 11. 对当前项目的迁移原则 + +## 11.1 总原则 + +先定语言,再改代码。 + +当前阶段最重要的是把架构口径统一为: + +- 六层总架构 +- 对外 `角色 + 技能` +- 对内 `skill + action + connector` +- `tool` 正式退出未来命名 + +## 11.2 当前阶段不要做的事 + +1. 不要继续新增 `tool` 概念 +2. 不要再把 action 做成独立页面 +3. 不要再让路由承担能力身份 +4. 不要让欢迎语继续写死在页面里 + +## 11.3 下一阶段最值得做的事 + +1. 先把当前架构文档同步到这一套口径 +2. 再把前端欢迎态改为 `expert_card.greeting` 驱动 +3. 再把 `tool` 相关变量和目录逐步迁移到 `skill / action` +4. 后续再进入数据库与运行时的对象化升级 + +--- + +## 12. 一句话总收口 + +平台以后应统一理解为: + +**一个以本体为语义底座、以角色为用户承接体、以技能为任务入口、以 Action 为原子执行单元、以 Workbench 为统一运行现场的数字员工与工业智能体平台。** diff --git a/docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md b/docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md new file mode 100644 index 0000000..8406400 --- /dev/null +++ b/docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md @@ -0,0 +1,755 @@ +# SY22 — Expert / Skill / App 统一任务架构 + +> 状态:总架构扩展确认稿 +> 日期:2026-09-16 +> 关联文档: +> - `SY17_Workbench_UI_Wireframes.md` +> - `SY20_Role_Card_And_Lightweight_Ontology_Architecture.md` +> - `SY21_Unified_Role_Skill_Action_Architecture.md` + +--- + +## 1. 这份文档要解决什么问题 + +在 `SY21` 中,平台已经正式收敛为六层架构,并明确了: + +- 对外暴露 `专家 / 技能 / 连接器` +- 对内运行 `expert / skill / action / connector / policy` +- 不再继续扩张 `tool` 概念 + +但随着工作台进一步向 WorkBuddy 类产品演进,出现了一个新问题: + +**系统里需要一种既不是专家、也不是技能的新一级对象。** + +它具备以下特征: + +- 不是以对话为主交互 +- 有自己长期存在的主界面 +- 有结构化状态、表单、题卡、看板、画布等交互 +- 启动后应成为一个长程任务实例 +- 可挂载右栏 AI、可调用技能、可沉淀业务产物 + +这类对象不适合继续塞进 `expert`,也不适合伪装成“大 skill”。 + +因此,这份文档正式确认: + +> **平台需要第三类一级对象:App。** + +--- + +## 2. 最终结论 + +## 2.1 六层总架构继续成立,但第五层升级 + +`SY21` 的六层架构继续有效: + +1. 外部连接层 +2. 本体与语义上下文层 +3. 总线与编排层 +4. 能力层 +5. 对象层 +6. 工作台与运行治理层 + +本次变化不是推翻六层,而是把第五层从偏“专家对象层”正式升级为: + +> **对象层(Expert / Skill / App)** + +## 2.2 App 是一级对象,不是页面,也不是大技能 + +App 的准确定义是: + +> **面向某类长程任务的状态化运行壳。** + +它与 Skill 的区别在于: + +- `skill` 解决“做什么” +- `app` 解决“这类工作如何持续运行、展示、交互、留痕” + +它与 Expert 的区别在于: + +- `expert` 解决“谁在与你协作” +- `app` 解决“这项工作在什么界面和状态机里被推进” + +## 2.3 任务不再等于对话 + +平台后续的统一定义应为: + +> **任务 = 一个工作实例容器** + +这个容器里可以挂载: + +- 一个主 `app` +- 一个右栏 `expert` +- 多个后台 `skill` +- 若干 `connector` + +因此: + +- 对话是任务中的一种交互轨迹 +- 不是所有任务都必须以消息流作为主界面 + +## 2.4 长程APP是一级导航,但一级导航必须完整描述 + +`app` 升格后,不能只补一句“新增长程APP”,否则会把整个一级导航重新说乱。 + +一级导航不再是同质栏目,而应明确分成四类: + +1. 工作入口 +2. 对象目录 +3. 组织知识入口 +4. 治理与个人入口 + +推荐的一级导航全景应为: + +1. `新建任务` + - 对话驱动任务的默认入口 + - 负责创建以 `expert` 为主对象的任务 +2. `项目` + - 任务容器与聚合视图 + - 用于组织多个长程任务与对话任务 +3. `专家 · 技能 · 连接器` + - 对象目录与配置浏览入口 + - 这里看的是定义,不是运行时 +4. `长程APP` + - `app` 定义卡片入口 + - 这里展示的是可启动的长程 App,不是历史任务 +5. `知识库` + - 组织级默认内建 App 的直达入口 + - 承载组织专有知识、素材、题库、结果记录等核心资产 + - 是 Expert 与 App 共同消费的知识底座 +6. `后台管理` + - 工坊、系统配置、对象治理、权限治理 + - 是平台治理入口,不是业务运行入口 +7. `我的` + - 个人总览、我的资料、个人偏好与个人工作视角 + +这里最重要的边界是: + +- `专家 · 技能 · 连接器` 看的是对象定义与配置 +- `长程APP` 看的是可运行的 `app` +- `项目` 看的是任务集合 +- `知识库` 看的是组织级知识底座与其内建 App 运行面 + +这里需要明确一个特例: + +> **知识库本身也是 `app`,但它不是普通可选 App,而是组织级默认必须存在的内建 App。** + +原因是: + +- 平台服务的是单一组织而不是开放公域 +- 没有组织专有知识,很多 Expert 与 App 无法稳定运行 +- 知识库不仅提供资料查看,还承担沉淀、审批、引用、题库与知识资产治理 + +因此在产品层,知识库同时具有两种身份: + +1. 在对象模型里,它属于 `app.knowledge_hub` +2. 在一级导航里,它拥有保留的直达入口,不必埋进“长程APP”卡片列表 + +点击 `长程APP` 里的卡片后,标准动作应为: + +1. 创建任务实例 +2. 挂载主 `app` +3. 进入该 `app` 的运行界面 +4. 同时进入统一任务列表 + +当前像 `AI考试` 这种已经长出独立业务界面的主导航,在架构上应理解为**过渡态专题入口**。 +后续应逐步收敛为: + +- `长程APP -> app.training_exam` + +而不是继续长期作为与 `专家 / 技能 / 项目 / 知识库` 并列的专题型一级主栏目。 + +--- + +## 3. 三类一级对象的边界 + +## 3.1 Expert + +`expert` 是面向用户协作的交互外壳。 + +核心职责: + +- 理解意图 +- 引导开场 +- 陪伴推进 +- 解释状态 +- 调度技能 + +典型交互: + +- 对话主导 +- 欢迎语 +- starter prompts +- 右栏 AI 助手 + +## 3.2 Skill + +`skill` 是面向任务复用的能力包。 + +核心职责: + +- 封装某类能力 +- 编排 `action` +- 规范输入输出 +- 生成产物 + +典型交互: + +- 被角色调用 +- 被 App 调用 +- 被工作流调用 + +## 3.3 App + +`app` 是面向场景化长程任务或组织级运行面的运行壳。 + +核心职责: + +- 承载主界面 +- 驱动状态机 +- 管理结构化数据 +- 组织多步骤交互 +- 沉淀长程产物 + +典型交互: + +- 菜单 +- 表单 +- 按钮 +- 题卡 +- 看板 +- 画布 + +其中应区分两类 App: + +1. **任务型 App** + - 进入后通常创建 `app_task` + - 例如培训考试、审批、数据分析、流程编排 +2. **底座型 App** + - 组织级长期存在,默认安装 + - 例如知识库 + - 它既提供独立运行面,也为其他任务提供知识支撑 + +AI 在 App 中通常位于: + +- 右栏副驾驶位 +- 辅助填表 +- 规则解释 +- 状态总结 +- 自然语言触发复杂动作 + +--- + +## 4. 六层架构回溯后的新定义 + +## 4.1 第一层:外部连接层 + +这一层继续负责连接真实世界与外部系统。 + +包括: + +- 本地文件系统 +- 企业业务系统 +- 工业系统 +- 培训 / 考试 / OA / ERP / MES / CRM / LMS +- 模型服务 +- API / Webhook / MQ + +这一层回答的是: + +**数据从哪里来,动作往哪里去。** + +## 4.2 第二层:本体与语义上下文层 + +这一层需要从行业对象语义继续扩展到工作对象语义。 + +除了原有: + +- device +- alarm +- work_order +- report + +还应补充: + +- task +- stage +- expert +- skill +- app +- artifact +- form +- workflow +- record + +对于 `app`,这一层必须支持: + +- App 处理的业务对象类型 +- App 允许的阶段类型 +- App 产物类型 +- App 与 Expert / Skill 的可挂载关系 + +这一层回答的是: + +**平台到底在处理哪些业务对象、工作对象和它们之间的关系。** + +## 4.3 第三层:总线与编排层 + +这一层继续承担流转职责,但要正式接纳 `app` 作为任务主对象。 + +至少应包含: + +1. 任务总线 +2. 事件总线 +3. 对象挂载总线 +4. 能力编排总线 + +新职责包括: + +- 任务创建后挂载主 `app` +- 根据 `app` 状态切换工作台界面 +- 允许右栏 `expert` 感知当前 `app` 上下文 +- 允许 `app` 调度 `skill` +- 允许人工接管与审批节点插入 + +这一层回答的是: + +**任务如何创建,对象如何挂载,状态如何推进,能力如何协作。** + +## 4.4 第四层:能力层 + +这一层继续保持: + +- `skill` +- `action` +- `policy` + +但要明确一个边界: + +> **App 不进入能力层。** + +原因是: + +- `skill` 是能力包 +- `action` 是原子动作 +- `app` 是运行壳 + +App 可以调用 Skill,但不替代 Skill。 + +## 4.5 第五层:对象层 + +这一层正式收敛为: + +- `expert` +- `skill` +- `app` + +并且三者都应该具备: + +- 对象定义 +- 版本信息 +- 生命周期状态 +- 权限边界 +- 可挂载关系 + +这一层回答的是: + +**平台有哪些可被用户使用、可被任务挂载、可被版本化治理的一等对象。** + +## 4.6 第六层:工作台与运行治理层 + +这一层不再只有单一对话工作台,而应明确分成两类运行现场: + +### A. 对话工作台 + +- 以专家为主 +- 适合模糊任务、探索任务、咨询任务 +- 中央区域以消息流为主 + +### B. 长程APP + +- 以 App 为主 +- 适合强状态、强结构、长周期任务 +- 中央区域以业务界面为主 +- AI 位于右栏 + +两者统一纳入: + +- 同一任务列表 +- 同一运行治理体系 +- 同一审计和产物体系 + +--- + +## 5. 统一任务模型 + +## 5.1 任务是工作实例容器 + +新的任务定义应为: + +> **task = 一次完整工作实例** + +它负责统一承载: + +- 当前主对象 +- 当前阶段 +- 当前参与对象 +- 当前运行状态 +- 当前产物集合 + +## 5.2 一个任务可挂多个对象实例 + +建议使用如下运行模型: + +- 主挂载:`app` 或 `expert` +- 右栏挂载:`expert` +- 后台挂载:`skill` + +例如一个培训考试任务可以是: + +- 主对象:`app.training_exam` +- 右栏对象:`expert.learning_coach` +- 后台能力:`skill.auto_grading` +- 后台能力:`skill.study_plan_generation` + +## 5.3 会话只是任务的一部分 + +以后应避免继续把任务状态写死在消息流里。 + +更准确的关系是: + +- `task`:工作容器 +- `task_message`:对话轨迹 +- `app_state`:App 主状态 +- `artifact`:产物 +- `event`:运行轨迹 + +--- + +## 6. 存储架构建议 + +## 6.1 对象定义层 + +建议继续使用统一根定义: + +- `object_definition` +- `object_version` + +关键字段建议: + +- `object_id` +- `object_type`:`expert | skill | app` +- `code` +- `key` +- `label` +- `status` +- `manifest` +- `schema_version` + +其中 `app.manifest` 至少应包含: + +- `object_entry_route` +- `layout_type` +- `supported_views` +- `default_sidebar_expert` +- `allowed_skills` +- `state_schema` +- `artifact_schema` +- `permission_model` + +为避免与 AI 路由和普通页面导航混同,当前项目统一采用三类命名: + +- `ai_route_*`:AI 模型路由 +- `object_entry_route`:专家 / 技能 / APP 这类业务对象的进入入口 +- `page_route`:普通页面导航路径 + +## 6.2 任务与挂载层 + +建议新增或统一为: + +- `task` +- `task_object_instance` + +`task` 核心字段建议: + +- `task_id` +- `task_type`:`conversation_task | app_task` +- `title` +- `status` +- `source_object_type` +- `source_object_id` +- `current_stage` +- `started_at` +- `completed_at` + +`task_object_instance` 核心字段建议: + +- `task_object_instance_id` +- `task_id` +- `object_id` +- `object_version_id` +- `object_type` +- `mount_slot`:`main | right_sidebar | background` +- `instance_role`:`primary | assistant | worker` + +## 6.3 运行轨迹层 + +建议使用: + +- `object_run` +- `task_message` + +其中: + +- `object_run` 记录对象执行、阶段推进、技能调用、人工确认 +- `task_message` 仅记录对话内容和消息元数据 + +需要明确: + +> **`task_message` 不再承担 App 主状态存储责任。** + +## 6.4 App 状态层 + +建议为 `app` 单独引入运行时状态存储: + +- `app_instance_state` +- `app_event` +- `app_artifact` + +`app_instance_state` 建议存: + +- `task_id` +- `task_object_instance_id` +- `workflow_state` +- `ui_state` +- `form_state` +- `selected_record_id` +- `snapshot_version` + +`app_event` 建议存: + +- `event_type` +- `payload` +- `operator` +- `created_at` + +`app_artifact` 建议存: + +- `artifact_type` +- `artifact_uri` +- `artifact_meta` +- `produced_by` +- `created_at` + +## 6.5 领域数据层 + +对于复杂 App,不应把所有业务数据都塞进 `app_instance_state.payload_json`。 + +必须允许按领域建模。 + +例如培训考试 App 可拥有独立领域表: + +- `training_plan` +- `course_module` +- `exam_paper` +- `exam_question` +- `exam_attempt` +- `exam_answer` +- `exam_score` + +因此存储应分为: + +- 通用运行表:承载平台运行 +- 领域业务表:承载业务事实 + +--- + +## 7. 前端与交互层含义 + +## 7.1 一级导航升级 + +前端一级导航不能只补“长程APP”这一项,而应整体升级为完整的信息架构。 + +建议目标态如下: + +1. `新建任务` + - 默认进入对话工作台 + - 主对象通常为 `expert` +2. `项目` + - 承载项目列表与项目详情 + - 用于聚合任务、产物与阶段 +3. `专家 · 技能 · 连接器` + - 展示 `expert / skill / connector` 的定义目录 + - 负责浏览、筛选、配置、安装态查看 +4. `长程APP` + - 展示 `app` 定义卡片 + - 负责启动 `app_task` +5. `知识库` + - 作为默认必须存在的内建 App 直接出现在一级导航 + - 承载组织知识、素材、题库、记录与知识治理 + - 是任务运行的公共知识面 +6. `后台管理` + - 承载工坊、系统配置、组织与治理能力 +7. `我的` + - 承载个人总览、个人资料与个人入口 + +因此,一级导航里实际并存四种不同语义: + +- 工作启动入口:`新建任务` +- 工作组织入口:`项目` +- 对象目录入口:`专家 · 技能 · 连接器`、`长程APP` +- 组织知识与治理入口:`知识库`、`后台管理`、`我的` + +### 7.1.1 为什么必须这样写全 + +如果只写: + +- 专家 +- 技能 +- 长程APP + +会遗漏三件事: + +1. `项目` 其实是统一任务系统的重要容器,不是普通页面 +2. `知识库` 是组织级默认内建 App,也是 Expert 和 App 的共用知识底座,不是边角内容 +3. `后台管理 / 我的` 分别承担治理与个人视角,不应被误解为附属页 + +### 7.1.2 当前专题主导航的收敛原则 + +凡是已经长成“非对话式、强结构、强状态”的专题栏目,例如: + +- 培训考试 +- 审批中心 +- 数据分析台 +- 流程编排台 + +在目标架构中都应优先判断为 `app`,最终收敛进: + +- `长程APP` + +而不是继续无限增长新的专题型一级导航。 + +唯一应保留一级直达入口的 App,是像 `知识库` 这种**组织级默认必装底座 App**。 + +## 7.2 进入 App 的动作不是“打开页面”,而是“创建任务” + +点击 App 卡片后的标准动作应为: + +1. 创建 `task` +2. 创建主 `task_object_instance(app)` +3. 自动挂载右栏 `expert` +4. 进入 `app runtime` + +## 7.3 App 运行界面不再强制对话居中 + +App 主界面应由业务形态决定,例如: + +- 培训考试:课程目录、题卡、成绩面板 +- 审批:表单、节点、操作栏 +- 数据分析:图表、筛选器、表格 +- 流程编排:画布、节点、日志 + +AI 对话框在 App 中退居右栏能力区。 + +--- + +## 8. 样板场景:培训考试 App + +## 8.1 对象组合 + +- 主对象:`app.training_exam` +- 右栏对象:`expert.learning_coach` +- 调用技能:`skill.generate_study_plan` +- 调用技能:`skill.auto_grade_exam` + +## 8.2 任务阶段 + +建议阶段至少包括: + +1. 待建档 +2. 培训中 +3. 练习中 +4. 待模拟考 +5. 模拟考完成 +6. 待正式考试 +7. 正式考试中 +8. 待复盘 +9. 待补训 +10. 已结业 + +## 8.3 交互形态 + +- 培训中:课程目录 + 内容区 + 右栏 AI 教练 +- 练习中:题目区 + 即时讲解 +- 正式考试中:题卡 + 倒计时 + 受控作答区 +- 复盘中:错题分析 + 补训计划 + 证书面板 + +这个样板说明: + +> **同一个任务实例中,对话、结构化界面、技能执行、产物沉淀可以长期共存。** + +--- + +## 9. 迁移指导 + +## 9.1 术语迁移 + +对外: + +- 专家 +- 技能 +- 长程APP + +一级导航目标态: + +- 新建任务 +- 项目 +- 专家 · 技能 · 连接器 +- 长程APP +- 知识库 +- 后台管理 +- 我的 + +对内: + +- `expert` +- `skill` +- `app` +- `action` +- `connector` +- `policy` + +## 9.2 后端迁移重点 + +1. 从“任务 = 对话”迁移到“任务 = 工作实例” +2. 新增 `app` 对象定义与版本机制 +3. 新增 `task_object_instance` +4. 新增 `app_state / app_event / app_artifact` +5. 把消息表从主状态中心降级为对话轨迹层 + +## 9.3 前端迁移重点 + +1. 把一级导航整理为“新建任务 / 项目 / 专家 · 技能 · 连接器 / 长程APP / 知识库 / 后台管理 / 我的” +2. 新增“长程APP”并以对象定义驱动 App 卡片列表与详情页 +3. 将现有专题型一级导航逐步收敛为 `app`,避免继续平铺新的业务主栏目;`知识库` 作为默认必装底座 App 保留一级直达入口 +4. 统一任务列表兼容 `conversation_task` 和 `app_task` +5. App Runtime 布局支持“主业务区 + 右栏 AI” + +--- + +## 10. 最终定义 + +这次架构升级后的平台可以正式定义为: + +> **一个以统一任务系统为核心、同时承载 Expert / Skill / App 三类一级对象的工业智能体操作平台。** + +其中: + +- `Expert` 负责协作 +- `Skill` 负责能力 +- `App` 负责长程任务运行壳 +- `Task` 负责统一承载工作实例 + +这意味着平台已经不再是单一对话驱动系统,而是: + +> **对话工作台与长程APP并存,但统一运行、统一治理、统一沉淀。** diff --git a/docs/01_System_Overall/SY23_Specialist_Rule_File_And_Skill_Binding_Plan.md b/docs/01_System_Overall/SY23_Specialist_Rule_File_And_Skill_Binding_Plan.md new file mode 100644 index 0000000..7fa8067 --- /dev/null +++ b/docs/01_System_Overall/SY23_Specialist_Rule_File_And_Skill_Binding_Plan.md @@ -0,0 +1,381 @@ +# SY23 — 专员「岗位说明书 + 技能绑定」改造方案 + +> 状态:实施建议稿 +> 日期:2026-09-17 +> 关联文档:`SY18_Specialist_Minimal_Definition_Model.md`、`SY20_Role_Card_And_Lightweight_Ontology_Architecture.md`、`SY21_Unified_Role_Skill_Action_Architecture.md`、`SY22_Role_Skill_App_Unified_Task_Architecture.md` +> 外部参照:AionUi / AionCore 内置助手与技能(已下载至 `codebase/AionCore-assets/`) + +--- + +## 0. 一句话诊断 + +**我们现在的 10 个专员,在运行时是同一个助手换了 10 个名字。** + +工作台主对话走 `POST /api/assistant/chat`(前端 `api/assistant.js` → `chatWithAssistant`),而这个接口: + +| 环节 | 现状 | 位置 | +|------|------|------| +| 前端发送的字段 | 只有 `message` / `mode` / `ai_route_id` | `views/workbench/SmartAssistantPage.vue:471` | +| 后端请求体 | **已有** `task_id` / `context` 字段,但前端一个都没发 | `internal/api/smart_assistant.go:17-25` | +| 后端 System Prompt | **两条写死的字符串**,与专员无关 | `internal/api/smart_assistant.go:136-140` | +| 后端是否查过 specialist 表 | **从未** | `callAssistantAI` 全文 26 行 | +| 「专家模式」任务拆解 | **三条写死的假步骤**(准备/执行/完成阶段) | `internal/api/smart_assistant.go:161-174` | +| 知识检索 | 这条链路完全不检索知识库 | 对比 `worker_task.go:707` | + +也就是说:**不管用户选了「合同审查专员」还是「物流履约专员」,后端收到的请求完全一样,产出的 System Prompt 完全一样。** 专员是在前端画出来的差异,不是后端跑出来的差异。 + +这与 SY21 §3.5.2 已经拍板的关系式直接冲突: + +> 专家承接用户,skill 组织任务,action 执行动作。 + +我们目前**只做了「专家承接用户」(前端 UI),缺了「专家暴露 skill」和「skill 编排 action」两条边**。 + +--- + +## 1. AionUi 做对了什么(三件事) + +AionCore 的 `builtin-assistants/assistants.json` 里,每个助手就三个关键字段: + +```json +{ + "id": "word-creator", + "rule_file": "word-creator.{locale}.md", + "enabled_skills": ["officecli-docx"] +} +``` + +拆开看: + +**① 每个助手有一份「岗位说明书」(rule file)** +- 就是这个助手的 System Prompt 主体,会话创建时注入 +- 简体中文版共 21 份,长度分布很说明问题: + - 办公类 9 份在 **433–650 字**(如 `word-creator.zh-CN.md` 517 字) + - 编排类 9 份在 **2470–9007 字**(如 `cowork.zh-CN.md` 6705 字) +- **短的那批不是偷懒,是分工**:它们把「怎么做」全部委托给技能,说明书本身只负责「我是谁 / 什么时候说什么 / 什么时候用哪个技能」 + +`word-creator.zh-CN.md` 全文的结构(517 字): + +```markdown +# Word 文档助手 +你是 **Word Creator** —— 一个专门使用 officecli 创建、编辑和分析专业 Word 文档的 AI 助手。 +## 当用户打招呼或询问你能做什么时 +简短介绍自己:[一段自我介绍的原文] +然后等待用户请求。 +## 当用户想要创建或编辑文档时 +严格按照 `officecli-docx` 技能执行。……不要偏离或简化技能中的指令。 +在开始工作前,主动提醒用户一次:[一段提醒原文] +在生成完成后,明确告诉用户:[一段收尾原文] +``` + +**② 每个助手声明它能用哪些技能(`enabled_skills`)** +- 技能以目录形式链接进工作区,底层 CLI 通过 `native_skills_dirs` 发现 +- 21 个助手里 13 个只绑 1 个技能,`cowork` 绑 5 个,`game-3d` / `ui-ux-pro-max` / `planning-with-files` / `human-3-coach` 绑 0 个 +- **绑 0 个技能但有 4000+ 字说明书的,恰恰是最像「专员」的那几个**(纯靠说明书驱动行为,不靠工具) + +**③ 说明书负责「调度」,技能负责「执行」** +- 长说明书(`cowork` 6705 字)的核心内容就是「什么场景下按哪个技能走」——这正是 SY20 说的「专员 = 可调用工具的角色」 +- `cowork` 是 21 个助手里唯一的多技能编排样板,**也是我们最该先抄的一份** + +### 结论 + +SY18 + SY20 + AionUi 三边指向同一件缺失的事: + +``` +SY18 说:专员有「动作」 ─┐ +SY20 说:专员 = 可调用工具的角色 ─┼─→ 专员和技能之间没有绑定边 +SY21 说:专家对象暴露 skill ─┤ 专员没有一份进 prompt 的说明书 +AionUi 说:rule_file + enabled_skills ─┘ +``` + +**我们已经有的(没用的)**:`specialist.role_card_json` 字段建了、值也写了,但从未进过任何 prompt。 +**我们缺的**:不是字段,是**把字段送进 prompt 的那条线**,和**专员↔技能的绑定边**。 + +--- + +## 2. 改造方案 + +三步,从「运行时能看出差异」倒推,不铺新架构。 + +### 步骤 1:给专员两样东西(数据层,改动最小) + +在 `internal/model/specialist.go` 加两个字段: + +```go +// RuleFileMarkdown 岗位说明书正文(Markdown 全文)。 +// 会话创建时注入 System Prompt,决定这个专员怎么说话、怎么推进、什么时候调用哪个技能。 +RuleFileMarkdown string `gorm:"type:text" json:"rule_file_markdown"` + +// AllowedSkills 绑定技能 key 列表,JSON 数组,顺序即优先级(首个为主技能)。 +// 元素取值对齐前端 availableSkills[].key,见 §2.4 校验清单。 +AllowedSkills string `gorm:"type:text" json:"allowed_skills"` +``` + +**为什么是两个字段而不是两张表** + +| 选择 | 理由 | +|------|------| +| 说明书用单字段 | AionUi 也是「一个助手一份 rule file」,不引入版本表 | +| 技能绑定用 JSON 数组 | SY22 §6.1 已把 `allowed_skills` 定为对象 `manifest` 的字段。现在用同名字段落地,**将来迁到 `object_definition` 时只是把列搬进 manifest,没有语义返工** | +| 不新建 `specialist_skill` 表 | 10 个专员 × 3–5 个技能 ≈ 40 行。表能提供的索引和 FK,在这里都不成立——15 个前端技能在后端根本没有行,FK 建不起来。数组顺序天然表达优先级,无需 `sort_order` 列 | + +> 升级路径(不在本轮):若将来技能绑定要挂**属性**(按技能配参数默认值、按技能配权限档位),再拆成关联表;那时 `allowed_skills` 里的元素从字符串升级为对象,字段名不变。 + +**迁移**:GORM `AutoMigrate` 会自动 `ADD COLUMN`,**不需要**手写迁移函数。 +(`internal/store/db.go:83` 的 `migrateObjectEntryRouteColumns` 是为 `DROP COLUMN` 写的——SQLite 的 AutoMigrate 删不掉列,加列不在此列。) + +**播种**:在 `internal/store/seed.go` 的 `seedSpecialists()` 之后加 `seedSpecialistRules()`,遵守现有「存在则只补空字段」约定——**说明书非空就不覆盖**,保护人工编辑。 + +### 步骤 2:让对话带上专员(打通链路) + +这是**当前最大的断点**,也是投入产出比最高的一处。改动共 4 个文件、约 30 行。 + +**前端(3 处)** + +| 文件 | 改动 | +|------|------| +| `frontend/src/api/assistant.js` | `chatWithAssistant(data)` 已透传整个 data,无需改 | +| `frontend/src/store/workerRuntime.js` | 已有 `currentSpecialistKey` computed(185-192 行),直接用 | +| `frontend/src/views/workbench/SmartAssistantPage.vue:471` | 请求体补上 `task_id` 与 `specialist_key` | + +```js +const res = await chatWithAssistant({ + message: text, + mode: mode.value, + ai_route_id: selectedAiChatRouteId.value, + task_id: currentTaskId.value || 0, + specialist_key: workerRuntime.currentSpecialistKey || '', +}) +``` + +> 两个都发是刻意的:**有任务时以 `task_id` 为准**(服务端从 `worker_task.specialist_key` 反查,不信任客户端);**任务尚未创建时**(刚进 `/home` 还没发第一句话)前端手上只有 `pendingSpecialistKey`,此时用 `specialist_key` 兜底。 + +**后端(1 处)** + +`internal/api/smart_assistant.go` 的 `callAssistantAI` 增加专员解析: + +```go +// 解析当前专员:优先按 task_id 反查(服务端权威),其次用请求里的 specialist_key +func resolveSpecialist(userID uint, req SmartAssistantRequest) *model.Specialist { + if req.TaskID > 0 { + var task model.WorkerTask + if err := store.DB.Where("id = ? AND user_id = ?", req.TaskID, userID). + First(&task).Error; err == nil && task.SpecialistKey != "" { + var s model.Specialist + if err := store.DB.Where("key = ?", task.SpecialistKey).First(&s).Error; err == nil { + return &s + } + } + } + if req.SpecialistKey != "" { + var s model.Specialist + if err := store.DB.Where("key = ?", req.SpecialistKey).First(&s).Error; err == nil { + return &s + } + } + return nil +} +``` + +> 现成的反查先例:`internal/api/worker_task.go:364` 就是同一套 `store.DB.Where("key = ?", task.SpecialistKey).First(&specialist)`。 + +`SmartAssistantRequest` 需补一个字段(`TaskID` 已存在,只差 `SpecialistKey`): + +```go +SpecialistKey string `json:"specialist_key"` +``` + +### 步骤 3:让说明书进 prompt(注入) + +改造 `callAssistantAI` 的 System Prompt 拼装,从「二选一写死」变成「通用底座 + 专员说明书」: + +```go +func buildAssistantSystemPrompt(userID uint, req SmartAssistantRequest, enableThinking bool) string { + base := "你是一位专业的AI通用助手,回答简洁直接,不展开思考过程,快速响应用户问题。" + if enableThinking { + base = "你是一位专家级AI数字员工,使用 thinking 模式。……" + } + + s := resolveSpecialist(userID, req) + if s == nil { + return base // 未挂专员 → 通用助手兜底,行为与今天一致 + } + + var b strings.Builder + b.WriteString(base) + b.WriteString("\n\n【当前专员】") + b.WriteString(s.Label) + + if skills := parseAllowedSkills(s.AllowedSkills); len(skills) > 0 { + b.WriteString("\n【可用技能】") + b.WriteString(strings.Join(skills, "、")) + } + + // 说明书是主体,放最后,避免被前面的短句稀释 + if strings.TrimSpace(s.RuleFileMarkdown) != "" { + b.WriteString("\n\n") + b.WriteString(s.RuleFileMarkdown) + } + return b.String() +} +``` + +**同时接上第二条链路**:`internal/api/worker_task.go:708` 已经在拼 System Prompt 且**手上就有 specialist 对象**,把说明书一起拼进去即可——这条链路是免费的,因为它本来就认识专员。 + +```go +systemPrompt := buildSystemPrompt(contextJSON, knowledge) + + specialistPromptSection(specialist) + // ← 新增 + "\n\n当前任务:" + buildWorkerAITaskPrompt(task, specialist, req) +``` + +> `specialistPromptSection(s)` 抽成一个共用小函数,`smart_assistant.go` 和 `worker_task.go` 都调它,避免两处 prompt 拼法各写一遍。 + +### §2.4 技能 key 校验清单 + +绑定的是裸字符串,所以需要一个校验来源。**新增单个 Go 常量文件**即可(22 条,从 `frontend/src/config/workbench.js` 的 `availableSkills` 一次性抄出): + +```go +// internal/model/skill_keys.go +// 前端 availableSkills 的 key 全集。绑定校验以此为准。 +// 注意:这里只列 key,不含技能实现——技能实现仍在前端。 +var ValidSkillKeys = map[string]bool{ + "smart-assistant": true, "document-translate": true, "copy-proofreading": true, + "audio-transcribe": true, "batch-extract": true, "contract-review": true, + "report-generation": true, "ppt-generation": true, "mind-map": true, + "longform-writing": true, "text-toolkit": true, "ocr-understanding": true, + "meeting-minutes": true, "project-planning": true, "email-drafting": true, + "table-cleanup": true, "proposal-summary": true, "progress-report": true, + "contract-brief": true, "interview-summary": true, "policy-rewrite": true, + "survey-summary": true, +} +``` + +写入时校验,非法 key 直接 400 —— 这样至少在录入侧挡住拼写错误。 + +> **命名冲突提醒**:`contract-review` 和 `report-generation` **既是专员 key 又是技能 key**。 +> 这是对的、也是刻意的(合同审查专员绑定合同审查技能),但读日志和调代码时极易混淆。建议**日志与报错文案一律写成 `专员:contract-review` / `技能:contract-review`** 带类型前缀。 + +--- + +## 3. 21 份规则文件,先改写哪几份 + +全部 21 份已下载在 `codebase/AionCore-assets/crates/aionui-app/assets/builtin-assistants/rules/`。 + +### 第一梯队:直接改写就能用(建议本轮做) + +| # | AionUi 来源 | 字数 | 对应我们的专员 | 为什么先做 | +|---|-------------|------|----------------|------------| +| 1 | `cowork` + 5 技能 | 6705 | `general-assistant`、`process-coordination` | **21 份里唯一的多技能编排样板**。它的说明书通篇在写「什么场景按哪个技能走」——这正是 SY20「专员 = 可调用工具的角色」要的东西。我们的「通用助手 / 流程协调」现在完全是空壳 | +| 2 | `word-creator` + `officecli-docx` | 517 | `report-generation`、`solution-proposal` | 说明书只有 517 字,是**最简模板**,改造成本最低;`officecli-docx` 是文档产出的通用底座,一份技能喂两个专员 | +| 3 | `morph-ppt` + `officecli-pptx` | 554 | `training-delivery` | 培训交付要出课件,morph-ppt 专做「文档转 PPT」,另有 3D 变体。我们「培训交付」目前零后端实现,接上就是真能力 | + +### 第二梯队:要改业务语义(本轮之后) + +| # | AionUi 来源 | 字数 | 对应我们的专员 | 改造要点 | +|---|-------------|------|----------------|----------| +| 4 | `social-job-publisher` | 2470 | `hr-email-sorter`、`resume-processor` | 招聘发布场景接近,但从「发帖到社媒」改成「读邮箱 → 写简历表」,需按 SY18 的信源/结果模型重写 | +| 5 | `planning-with-files` | 5500 | `process-coordination` | 纯说明书(绑 0 技能),讲「用文件做长期规划」,接近流程协调 | +| 6 | `beautiful-mermaid` | 433 | `report-generation` | 图表产出,可作报告生成的第二个技能 | +| 7 | `excel-creator` + `officecli-xlsx` | 562 | `report-generation` | 表格产出 | +| 8 | `dashboard-creator`、`financial-model-creator`、`pitch-deck-creator`、`academic-paper` | 567–614 | `solution-proposal` | 方案建议的几种形态,按客户行业挑 | + +### 不要碰 + +| 来源 | 原因 | +|------|------| +| **`builtin-skills/pdf/`** | **© 2025 Anthropic, PBC,附加条款明文禁止创建衍生作品、禁止在服务外保留副本、禁止再分发。必须删除,不得移植进产品。** | +| `openclaw-setup`、`aionui-assistant`、`aionui-*` 技能 | AionUi 自身的安装运维助手,与业务无关 | +| `moltbook` | 面向其自有平台的发布助手 | +| `game-3d`、`story-roleplay`、`human-3-coach`、`ui-ux-pro-max` | 游戏 / 角色扮演 / 个人成长 / 设计工具,与企业办公无关 | +| `weixin-file-send` | 是「把文件发到微信」的客户端脚本,依赖其本地 Electron 环境,不可移植(公众号专员要的是发文,不是发文件) | + +### 前置依赖:OfficeCLI 未下载 + +7 个 `officecli-*` 技能全部依赖 **OfficeCLI**(AionUi 用它免装 Office 操作 docx/xlsx/pptx)。**我们目前没有这份资产**,第一梯队第 2、3 项开工前必须先搞定它,否则说明书改完也没东西可调。 + +--- + +## 4. 前端要动的地方(最小集) + +**前提原则(沿用已拍板方向):专员是任务的字段,不是页面。** 本方案不新增任何专员页面。 + +### 必改 + +| 文件 | 改动 | +|------|------| +| `views/workbench/SmartAssistantPage.vue:471` | 请求体补 `task_id` / `specialist_key`(步骤 2) | +| `views/workbench/CapabilityCatalogDetailPage.vue:257` | 专员详情页 `extraSections: []` 是空的,**正好是挂「绑定技能」「岗位说明书」两个 section 的位置**(技能详情页 160-183 行有现成写法可抄) | +| `store/workerRuntime.js:425-441` | `attachSpecialistToCurrentTask` 目前**强制**把技能清成 `DEFAULT_SKILL_KEY`(438 行)。这正是「选了专员反而更空」的根因——应改为写入该专员的**主技能**(`allowed_skills[0]`) | + +### 建议改 + +| 文件 | 改动 | +|------|------| +| `views/workbench/StudioPage.vue:1505-1545`、`MarketPage.vue:660-740` | 管理员/市场的专员表单,是录入说明书与绑定技能的两个编辑入口(`api/specialist.go` 与表单 payload 需同步透传新字段) | +| `components/chat/SpecialistChip.vue:41-54` | 胶囊提示补「已绑定 N 个技能」 | +| `views/workbench/CapabilityCatalogPage.vue:385-404` | 专员卡片增加技能徽章 | + +### 明确不改 + +- `config/workbench.js` 的 `availableSkills`(22 条)—— 技能仍归前端,本方案不把技能搬到后端 +- `config/skillSettings.js` 的既有 7 条技能定义 +- `skills/registry/*` 技能实现本体 + +> **双份真相问题记录在案**:前端 22 个技能 vs 后端 `skill_definition` 7 行,今天无同步机制。本方案用 §2.4 的 `ValidSkillKeys` 常量做**单向校验**兜底,不解决同步问题。彻底解决要等 SY22 的 `object_definition` 落地,**不在本轮**。 + +--- + +## 5. 顺带发现的线上缺陷(独立于本方案,建议立即修) + +`internal/api/batch_extract.go:62` 与 `internal/api/contract_review.go:359` 调用: + +```go +ai.GenerateWithFallback(nil, messages) +``` + +而 `internal/ai/llm.go:302` 的实现第一行就是: + +```go +fallbacks, err := config.GetFallbackRoutes(primary.RouteID) // primary == nil → 空指针 +``` + +**验证结论**: +- `internal/api/router.go:146` / `:152` 确认两条路由都是活路径(`POST /api/contract/review`、`POST /api/batch/extract`,均挂 `middleware.Auth`) +- `cmd/server/main.go:47` 用的是 `gin.Default()`,自带 Recovery —— 所以表现为 **HTTP 500**,不会打挂进程,但**这两个功能 100% 不可用** +- 前端 `api/contract.js:3`、`api/batch.js:3` 确实在调这两个接口 + +**修复**:两处改为传入真实路由(`config.GetRoute(...)`,可参照 `smart_assistant.go:146`),或在 `GenerateWithFallback` 入口对 `primary == nil` 显式返回错误而非 panic。**建议两者都做**——前者修功能,后者防复发。 + +--- + +## 6. 不建议现在做的事 + +| 事项 | 原因 | +|------|------| +| 迁到统一的 `object_definition` 根表 | SY22 §6.1 是终态,但当前前端专员/技能展示**大量读本地硬编码**(`businessApps` 10 个、`availableSkills` 22 个)。先迁表等于先付迁移成本、后拿收益。本方案的字段命名已与 SY22 对齐,将来搬迁无返工 | +| 把 22 个前端技能搬到后端 | 无运行时收益,且会立刻暴露「技能没有真实实现」的更大缺口 | +| 给专员做独立页面 | 违背已拍板方向(专员是任务的字段)。AionUi 同样把助手配置放在设置里,不放主界面 | +| 移植 `builtin-skills/pdf/` | 许可证禁止(见 §3) | +| 补 `specialist_skill` 关联表 | 见 §2 步骤 1 的取舍说明 | + +--- + +## 7. 工作量与推进顺序 + +| 阶段 | 内容 | 估时 | +|------|------|------| +| **P0** | 修 §5 的空指针缺陷 | 0.5 天 | +| **P1** | 步骤 1 数据层(2 字段 + 播种 + `ValidSkillKeys` 校验) | 0.5 天 | +| **P2** | 步骤 2 打通链路(前端 2 处 + 后端 `resolveSpecialist`) | 0.5 天 | +| **P3** | 步骤 3 注入 prompt(`buildAssistantSystemPrompt` + `worker_task.go:708` 同步) | 0.5 天 | +| **P4** | 前端最小集(详情页两个 section + `attachSpecialistToCurrentTask` 改主技能) | 1 天 | +| **P5** | 第一梯队 3 份说明书改写(需先拿到 OfficeCLI) | 每份 0.5–1 天 | + +**P1–P3 合计约 1.5 天,做完即可看到「同一个助手在不同专员下说话方式不同」**——这是整个方案能否立住的最小验证点。**建议 P1–P3 做完先停下来验证一次,再决定要不要投 P5。** + +### 验收标准(沿用 SY18 §8) + +> 如果一个专员无法用三行(信源 / 动作 / 结果)说清、且权限说不出「能读什么 / 能写什么 / 谁能用」,说明设计过重了。 + +再加一条本方案的: + +> **选中两个不同的专员、问同一句话,后端发出的 System Prompt 必须不同。** 只要这一条不成立,专员就还只是装饰。 diff --git a/docs/01_System_Overall/SY24_Platform_Architecture_Rethink.md b/docs/01_System_Overall/SY24_Platform_Architecture_Rethink.md new file mode 100644 index 0000000..34ef16e --- /dev/null +++ b/docs/01_System_Overall/SY24_Platform_Architecture_Rethink.md @@ -0,0 +1,941 @@ +# 数字员工平台整体架构重思考 + +> 落盘日期:2026-09-16 +> 状态:架构重思考稿,作为后续产品与数据结构重构的总纲 +> 关联文档: +> - `../02_Architecture/AR05_Workbench_Architecture_Contract.md` +> - `../02_Architecture/AR06_Skill_Packaging_Specification.md` +> - `../02_Architecture/AR08_Role_Interaction_Design.md` + +> 2026-09-16 架构同步说明: +> 本文档保留 Workbench 收敛和对象化迁移结论,但总命名以 +> `docs/01_System_Overall/SY21_Unified_Role_Skill_Action_Architecture.md` 为准。 +> 当前统一口径为: +> - 对外:`角色 / 技能 / 连接器` +> - 对内:`role / skill / action / connector / policy` +> - `tool` 在本稿中主要代表历史命名和过渡字段,不再作为未来正式概念 +> - 欢迎语、starter prompts、对象开场方式,应由角色对象属性驱动,而不是页面硬编码 + +--- + +## 1. 最终判断 + +现在这个系统最核心的问题,不是页面太多,也不是导航太乱,而是: + +**产品架构、前端架构、后端数据结构三层没有使用同一个对象模型。** + +当前系统里同时混着以下几种模型: + +1. `任务挂专员` +2. `工具等于页面` +3. `项目保存一组 skill_keys / specialist_keys` +4. `运行记录只知道 specialist_key,不知道真正执行的是谁` + +这四套模型不能长期并存。 + +所以新的总架构必须统一成一句话: + +`一个 Workbench + 一个任务会话 + 多个可挂载对象 + 一条可追踪执行链` + +--- + +## 2. 产品架构重定义 + +平台以后不是“很多能力页面”,而是一个真正的数字员工平台,分成两大面: + +### 2.1 执行面 + +执行面只保留一个: + +- `Workbench` + +它承载: + +- 当前任务 +- 当前对象 +- 消息流 +- 工作流 +- 产物 +- 附件 +- 启动对象 / 切换对象 / 关闭对象 + +### 2.2 管理面 + +管理面负责: + +- 目录浏览 +- 配置 +- 安装 +- 权限 +- 连接器 +- 运营 +- 观测 + +它不承担任务执行。 + +一句话: + +- `Workbench` 负责使用 +- `Catalog / Studio / Console` 负责管理 + +--- + +## 3. 统一对象模型 + +未来系统里所有“可被用户启动、配置、关闭、调用”的东西,都统一叫: + +`对象` + +对象分三类: + +### 3.1 默认助手 + +定义: + +- 默认兜底对象 +- 没选专员、没选技术员时的默认入口 + +本质: + +- 一种特殊的编排对象 + +### 3.2 数字专员 + +定义: + +- 负责任务拆解、编排、协调、汇总的对象 + +本质: + +- 编排型对象 + +### 3.3 数字技术员 + +定义: + +- 负责某一个能力动作的对象 + +本质: + +- 执行型对象 + +### 3.4 关键结论 + +工具不再是页面,也不再是一个特殊技术概念。 + +工具只是: + +`数字技术员的产品展示名称` + +所以未来建模必须统一为: + +- 对象定义 +- 对象安装 +- 对象实例 +- 对象运行 + +而不是: + +- 专员一套表 +- 工具一套路由 +- 页面里再塞一套局部状态 + +--- + +## 4. 新的领域分层 + +系统应该拆成 4 层: + +### 4.1 定义层 + +定义“这个对象是谁”。 + +例如: + +- 文档翻译技术员 +- 合同审查专员 +- 通用助手 + +这一层存: + +- 身份 +- 来源 +- 版本 +- 设置 schema +- 能力 schema +- 展示配置 + +### 4.2 安装层 + +定义“这个对象在当前租户 / 工作区里是否可用”。 + +这一层存: + +- 是否启用 +- 是否安装 +- 版本锁定 +- 权限范围 +- 默认配置 + +### 4.3 实例层 + +定义“这条任务当前挂了谁”。 + +这一层存: + +- 当前任务里挂载了哪些对象 +- 当前焦点是谁 +- 各对象的本次任务配置快照 +- 对象是否打开 / 关闭 + +### 4.4 运行层 + +定义“这次实际跑了什么”。 + +这一层存: + +- 消息 +- 调用链 +- 步骤 +- 产物 +- 日志 +- 状态变化 + +--- + +## 5. 最重要的结构纠偏 + +### 5.1 Task 不能只挂一个 specialist_key + +当前 `worker_task` 的核心绑定是: + +- `specialist_key` + +这不够。 + +因为未来一条任务里可能同时存在: + +- 一个主专员 +- 多个技术员 +- 动态切换的当前焦点对象 + +但对用户可见的输入区交互,必须坚持一条规则: + +- `+` 右边一次只显示一个当前对象 +- 当前对象要么是专员,要么是技能,要么是默认助手 +- 专员内部调用技能,只进入执行链和右侧面板,不在输入区显性双挂 + +所以真正的任务结构不应是: + +`task -> specialist_key` + +而应是: + +`task -> mounted objects` + +### 5.2 Run 不能只知道 specialist_key + +当前 `worker_run` 也只知道: + +- `specialist_key` +- `action_key` + +这会导致系统分不清: + +- 是哪个对象发起的 +- 是哪个对象实际执行的 +- 是专员步骤,还是技术员步骤 +- 是人工确认,还是自动调用 + +所以运行记录必须升级为: + +- 谁发起 +- 谁执行 +- 父子运行关系 +- 对应对象实例 + +### 5.3 Project 不能只存 skill_keys 与 object_entry_route 语义 + +当前项目里保存: + +- `specialist_keys` +- `skill_keys` +- `connector_keys` + +方向是对的,但语义还不够硬。 + +以后项目应该保存的是: + +- 默认对象绑定 +- 默认配置快照 +- 默认连接器绑定 +- 默认知识域 + +而不是仅仅一串“key 列表”。 + +### 5.4 消息必须成为一等数据 + +当前系统最大缺口之一,是消息没有成为正式持久化对象。 + +没有消息层,Workbench 永远只是半成品,因为: + +- 任务无法真正恢复 +- 对象切换没有上下文历史 +- 运行记录无法和用户意图精确对齐 +- 后续审计、回放、总结都不完整 + +所以必须新增: + +- `task_message` + +--- + +## 6. 推荐的核心数据结构 + +以下是建议采用的目标数据模型。 + +## 6.1 对象定义表 `object_definition` + +作用: + +- 统一描述默认助手 / 专员 / 技术员 + +建议字段: + +```ts +type ObjectDefinition = { + id: string + code: string + source: 'eai' | 'custom' + kind: 'assistant' | 'specialist' | 'tool' + key: string + label: string + description: string + version: string + state: 'active' | 'inactive' + icon: string + color: string + capabilitySchema: object + settingsSchema: object[] + workflowSchema: object[] + artifactSchema: object[] + uiSchema: object + createdAt: string + updatedAt: string +} +``` + +关键说明: + +1. `specialist` 和 `tool` 都是对象定义,不再属于两套异构模型 +2. EAI 与 custom 由 `source` 区分 +3. 旧的 `specialist` 表最终应演进成这一层 + +## 6.2 对象安装表 `object_installation` + +作用: + +- 记录某个对象在某个租户 / 工作区 / 组织里是否可用 + +建议字段: + +```ts +type ObjectInstallation = { + id: string + objectDefinitionId: string + tenantId: string + workspaceId: string + state: 'installed' | 'disabled' | 'trial' + pinned: boolean + permissionScope: object + connectorBindings: object[] + knowledgeBindings: object[] + defaultSettings: object + createdAt: string + updatedAt: string +} +``` + +关键说明: + +1. 这层解决“平台有,但当前租户能不能用” +2. 这层负责安装态,而不是任务态 + +## 6.3 项目表 `project` + +作用: + +- 作为任务的长期上下文容器 + +建议字段: + +```ts +type Project = { + id: string + code: string + name: string + ownerId: string + instruction: string + templateKey: string + defaultObjectBindings: object[] + defaultConnectorBindings: object[] + defaultKnowledgeBindings: object[] + state: 'active' | 'archived' + pinned: boolean + createdAt: string + updatedAt: string +} +``` + +关键说明: + +1. 项目不是对象目录 +2. 项目是任务上下文模板 +3. 项目里应该保存默认挂载关系,而不是只保存裸 key 列表 + +## 6.4 任务会话表 `task_session` + +作用: + +- 表示用户正在处理的一条真实任务 + +建议字段: + +```ts +type TaskSession = { + id: string + title: string + summary: string + ownerId: string + projectId?: string + state: 'draft' | 'running' | 'waiting' | 'done' | 'archived' + priority: 'P1' | 'P2' | 'P3' + currentObjectInstanceId?: string + defaultSpecialistInstanceId?: string + latestRunId?: string + latestArtifactId?: string + pinned: boolean + dueAt?: string + createdAt: string + updatedAt: string +} +``` + +关键说明: + +1. 任务只记录“当前主会话” +2. 任务不直接存 `tool object_entry_route` +3. 任务不直接把工具建模成页面 + +## 6.5 任务挂载对象表 `task_object_instance` + +作用: + +- 这是整个系统最关键的新表 +- 记录某条任务当前挂载了哪些对象 + +建议字段: + +```ts +type TaskObjectInstance = { + id: string + taskId: string + objectDefinitionId: string + objectKind: 'assistant' | 'specialist' | 'skill' + role: 'default' | 'primary' | 'secondary' + state: 'mounted' | 'focused' | 'closed' + settingsSnapshot: object + source: 'manual' | 'auto' + mountedAt: string + closedAt?: string + updatedAt: string +} +``` + +关键说明: + +1. 当前专员、当前技能都应该从这里来 +2. `currentSkillKey` 只是这张表的前端运行态字段 +3. 关闭对象时,不是跳页面,而是把实例 state 改成 `closed` + +## 6.6 消息表 `task_message` + +作用: + +- 持久化消息流 + +建议字段: + +```ts +type TaskMessage = { + id: string + taskId: string + objectInstanceId?: string + role: 'user' | 'assistant' | 'system' + messageType: 'text' | 'tool_call' | 'status' | 'summary' + contentText: string + contentJSON?: object + replyToMessageId?: string + createdAt: string +} +``` + +关键说明: + +1. 每条消息可以挂到某个对象实例上 +2. 这样才能知道“这句话是对谁说的” +3. 回放、总结、继续追问都依赖这层 + +## 6.7 执行表 `object_run` + +作用: + +- 记录对象实际执行的过程 + +建议字段: + +```ts +type ObjectRun = { + id: string + taskId: string + objectInstanceId: string + initiatedByRunId?: string + initiatedByObjectInstanceId?: string + parentRunId?: string + runType: 'chat' | 'workflow' | 'skill' | 'approval' + actionKey: string + actionTitle: string + state: 'queued' | 'running' | 'waiting' | 'done' | 'failed' | 'cancelled' + inputJSON: object + outputJSON?: object + logsJSON?: object[] + startedAt?: string + finishedAt?: string + createdAt: string + updatedAt: string +} +``` + +关键说明: + +1. 必须显式有 `running / waiting / failed` +2. 当前 `worker_run.status` 默认 `done` 的模型是不够的 +3. `parentRunId` 解决专员调用技术员的问题 + +## 6.8 产物表 `artifact` + +作用: + +- 统一管理任务产出 + +建议字段: + +```ts +type Artifact = { + id: string + taskId: string + objectInstanceId?: string + createdByRunId?: string + artifactType: string + title: string + state: 'draft' | 'review' | 'approved' | 'published' + contentText?: string + contentJSON?: object + sourceRefsJSON?: object[] + createdAt: string + updatedAt: string +} +``` + +关键说明: + +1. 产物不属于页面 +2. 产物属于任务和执行链 +3. 右栏展示只是视图,不是数据来源 + +--- + +## 7. 前端运行时结构重定义 + +前端 store 应该从“按页面凑状态”改成“按任务会话管理状态”。 + +推荐结构: + +```ts +type WorkbenchRuntime = { + activeTaskId: string + draftSelection: { + specialistKey?: string + toolKey?: string + mode?: string + } + tasksById: Record + mountedObjectsByTaskId: Record + messagesByTaskId: Record + runsByTaskId: Record + artifactsByTaskId: Record + focusedObjectInstanceIdByTaskId: Record + panelStateByTaskId: Record +} +``` + +关键说明: + +1. 当前对象应该由 `focusedObjectInstanceId` 决定 +2. `currentSkillKey` 和 `currentSpecialistKey` 最终都只是计算值 +3. 页面不应该自己猜当前对象是谁 + +--- + +## 8. 前端目录结构重定义 + +建议未来前端结构分成 5 块: + +```text +src/ + workbench/ + pages/ + components/ + stores/ + runtime/ + tools/ + eai/ + custom/ + registry/ + shared/ + specialists/ + eai/ + custom/ + registry/ + shared/ + connectors/ + catalog/ +``` + +关键说明: + +1. `workbench/` 只承载执行工作面 +2. `tools/` 只放技术员定义与局部组件 +3. `specialists/` 只放专员定义与局部组件 +4. 不再允许 `views/tools/*.vue` 承担执行职责 + +--- + +## 9. 路由模型重定义 + +未来路由应该只分三类: + +### 9.1 执行路由 + +- `/home` + +### 9.2 目录路由 + +- `/catalog/specialists` +- `/catalog/skills` +- `/catalog/connectors` + +### 9.3 配置 / 管理路由 + +- `/studio` +- `/console` +- `/projects` + +强结论: + +- `apps/*` 退出执行入口 +- `tools/*` 退出执行入口 + +--- + +## 10. 对当前表结构的明确评价 + +### 10.1 当前 `specialist` 表 + +优点: + +- 已经积累了足够多的对象定义字段 + +问题: + +- 同时承载了目录字段、展示字段、流程字段、配置字段 +- 仍然以“专员”命名,无法统一承载默认助手和技术员 + +判断: + +- 可以作为 `object_definition` 的迁移来源 +- 不建议长期继续维持原表语义 + +### 10.2 当前 `worker_task` 表 + +优点: + +- 已经有任务的基础壳 + +问题: + +- 核心绑定仍然是 `specialist_key` +- 还没有对象实例层 +- 还没有消息层 + +判断: + +- 适合作为 `task_session` 的迁移来源 +- 不适合作为最终任务模型 + +### 10.3 当前 `worker_run` 表 + +优点: + +- 已经有动作记录 + +问题: + +- 缺少对象实例 id +- 缺少父子调用链 +- 缺少真实运行状态 + +判断: + +- 适合作为 `object_run` 的迁移来源 +- 必须升级 + +### 10.4 当前 `worker_artifact` 表 + +优点: + +- 基本方向正确 + +问题: + +- 仍然绑定 `specialist_key` +- 没有明确对象实例来源 + +判断: + +- 可以直接演进成新 `artifact` 模型 + +--- + +## 11. 最关键的产品决策 + +下面这些必须作为平台级决策固定下来: + +### 11.1 任务中心化 + +所有运行时行为都围绕任务展开。 + +### 11.2 对象实例化 + +对象不是页面,不是 tab,不是配置项。 + +对象在任务里必须有实例。 + +### 11.3 消息持久化 + +没有消息层,就没有真正的 Workbench。 + +### 11.4 运行链可追踪 + +专员调技术员,必须可追踪为父子执行链。 + +### 11.5 管理与使用分离 + +Catalog / Studio / Console 不参与执行面。 + +--- + +## 12. 推荐迁移顺序 + +### Phase 1:冻结对象模型 + +确定: + +- assistant / specialist / tool 三类对象 +- source / code / key / label 规范 + +### Phase 2:补对象实例层 + +新增: + +- `task_object_instance` + +前端先用 runtime 影子模型兼容。 + +### Phase 3:补消息层 + +新增: + +- `task_message` + +让任务真正可恢复。 + +### Phase 4:升级运行链 + +把 `worker_run` 升级为带父子关系的 `object_run`。 + +### Phase 5:收口前端执行页 + +删除: + +- `apps/*` 执行页 +- `tools/*` 执行页 + +### Phase 6:收口定义层 + +把: + +- `specialist` +- `tool config` + +逐步统一到对象定义体系。 + +--- + +## 13. WorkBuddy 实测确认点 + +本轮已实际登录并查看 WorkBuddy,以下观察可以作为架构校准依据。 + +### 13.1 单一执行工作面成立 + +登录后默认进入的是单一工作台,而不是“先选一个工具页再开始工作”。 + +可见特征: + +- 左侧是一级工作区标签 +- 中间是统一输入工作面 +- 右侧是固定侧栏 + +这说明: + +- 我们保留唯一 Workbench 的方向是对的 + +### 13.2 `项目` 是独立管理面,不是执行页 + +WorkBuddy 的 `项目` 入口跳到单独的项目列表与模板空间。 + +这个页面的职责是: + +- 项目管理 +- 项目模板 +- 多人协同入口 + +而不是聊天执行。 + +这说明: + +- 我们把 `项目` 归入管理面是对的 +- 项目不是对象目录,也不是工具页 + +### 13.3 `专家·技能·连接器` 是统一目录中心 + +WorkBuddy 中这一组入口是统一的目录中心,内部再切: + +- 专家 +- 技能 +- 连接器 + +它的形态明显是: + +- 搜索 +- 分类 +- 推荐 +- 安装 / 连接 + +而不是执行工作面。 + +这说明: + +- 我们把 `Catalog` 与 `Workbench` 分开是对的 +- `专员·工具·连接器` 不应该承担直接执行语义 + +### 13.4 具体技能点击后是详情 / 安装,不是进入另一套聊天页 + +在 `技能` 列表中点击某个具体技能后,出现的是技能详情与安装动作,而不是跳进单独的技能聊天页面。 + +这说明: + +- “一个工具一个执行页”的老结构方向不对 +- 工具更接近“目录项 + 详情 + 安装 + 后续被调用” + +### 13.5 右侧面板是壳层能力,不是某个页面私有能力 + +无论在新建任务、项目、技能、连接器等区域,右侧面板结构都持续存在。 + +即使内容为空,壳也还在。 + +这说明: + +- 右栏应该属于 shell / workbench 壳层 +- 不应该每个工具页自己维护一份右栏 + +### 13.6 WorkBuddy 仍然保留了较强的“市场 / 目录 / 工作台”边界 + +它不是把所有东西都糊成一个平面,而是: + +- 工作台负责执行 +- 项目负责协同容器 +- 专家 / 技能 / 连接器负责目录与安装 + +这和我们当前重构方向高度一致。 + +### 13.7 对我们的直接启发 + +WorkBuddy 实测后,可以进一步确认以下决策不需要再摇摆: + +1. 保留唯一执行工作面 +2. `项目` 作为管理 / 协同面保留 +3. `专家·技能·连接器` 作为目录中心保留 +4. 工具不再做独立执行页 +5. 右栏属于壳层,而不是页面层 + +### 13.8 我们不需要照搬的地方 + +WorkBuddy 当前实现里,仍然保留了较强的目录跳转结构。 + +我们项目和它的差异是: + +- 我们更强调“任务上下文中的对象挂载” +- 我们更强调“启动、配置、关闭对象” +- 我们希望对象实例层更加明确 + +所以我们不需要简单复刻它的页面结构,而应该吸收它已经验证过的边界: + +- 工作台是工作台 +- 目录是目录 +- 安装是安装 +- 执行不是目录页行为 + +--- + +## 14. 关于 WorkBuddy 与本项目的关系 + +基于当前仓库、既有合同以及本轮 WorkBuddy 实测,已经可以确认: + +- 第一性原理判断没有走偏 +- WorkBuddy 更适合用来校准边界,而不是替代建模 + +也就是说: + +- 我们参考 WorkBuddy +- 但我们的最终模型应该比它更明确地引入“对象实例层” + +--- + +## 15. 最终一句话 + +这个平台最终不应该再被理解为: + +`专员页 + 工具页 + 若干配置页` + +而应该被理解为: + +`一个数字员工工作台 + 一套对象目录 + 一层对象实例模型 + 一条执行与产物链` + +如果后续任何实现仍然要求用户去理解: + +- 我现在在哪个工具页 +- 我是不是切到了另一个专员页 +- 这个页面和那条任务是什么关系 + +那就说明架构还没有真正完成重构。 diff --git a/docs/02_Architecture/AR05_Workbench_Architecture_Contract.md b/docs/02_Architecture/AR05_Workbench_Architecture_Contract.md new file mode 100644 index 0000000..a1c8872 --- /dev/null +++ b/docs/02_Architecture/AR05_Workbench_Architecture_Contract.md @@ -0,0 +1,482 @@ +# 数字员工 Workbench 架构合同 + +> 落盘日期:2026-09-16 +> 状态:架构合同 +> 作用:作为后续前端重构的强约束,先定模型,再做代码迁移 +> 关联文档:`AR08_Role_Interaction_Design.md` + +--- + +## 1. 目标 + +系统后续只保留一个大的工作台。 + +这个工作台必须同时满足 4 件事: + +1. 用户始终在同一个主工作面里完成任务 +2. 专员和工具都不是“去一个页面”,而是“挂到当前任务里的对象” +3. 对象可以被启动、配置、切换焦点、关闭 +4. 所有执行上下文都以任务为中心,而不是以路由为中心 + +一句话定义: + +`一个 Workbench + 一条任务上下文 + 多个可挂载对象` + +--- + +## 2. 强结论 + +### 2.1 保留一个唯一执行工作面 + +前端只允许一个执行型主工作面: + +- 建议沿用 `/home` 作为 canonical page_route +- `/` 直接进入 `/home` + +这个页面承载: + +- 消息流 +- 当前对象 chip +- 设置条 +- 工作流 / 产物右栏 +- 附件入口 +- `+` 菜单 + +### 2.2 `apps/*` 不再作为使用入口 + +`/apps/*` 可以去掉“执行页”角色。 + +以后它只能有两种命运: + +1. 被删除 +2. 退化成兼容跳转,统一跳回 `/home` + +它不能继续承担: + +- 打开专员工作台 +- 在专员页里执行任务 +- 与主工作面并行存在 + +### 2.3 `tools/*` 不再作为使用入口 + +`/tools/*` 也可以去掉“执行页”角色。 + +以后工具不再被建模为一组独立页面,而是: + +- 当前任务里被启动的技术员对象 +- 由统一工作面承载执行 + +`/tools/*` 在迁移期只允许做兼容跳转,不允许继续扩散业务逻辑。 + +--- + +## 3. 对象模型 + +### 3.1 三类对象 + +| 对象 | 本质 | 角色 | +|------|------|------| +| 通用助手 | 默认专员 | 没有显式指定对象时的兜底编排者 | +| 数字专员 | 编排型对象 | 负责拆任务、排步骤、调用工具、汇总结果 | +| 数字技术员 | 执行型对象 | 负责单点能力执行,例如翻译、提取、转写 | + +### 3.2 工具的真正定义 + +“工具”只是数字技术员的展示别名,不再是页面类型。 + +所以未来语义应该是: + +- 文档翻译工具 -> 文档翻译技术员 +- 文案校对工具 -> 文案校对技术员 +- 批量提取工具 -> 批量提取技术员 + +如果某个对象既有“专员态”又有“工具态”,必须拆成两个不同 key,禁止复用同一个 key。 + +例如这类冲突必须消除: + +- `contract-review` 不能同时代表专员和工具 +- `report-generation` 不能同时代表专员和工具 + +--- + +## 4. 状态模型 + +## 4.1 核心原则 + +所有运行时状态必须挂在“当前任务”下面。 + +禁止再出现: + +- 专员状态靠任务 store +- 工具状态靠路由 +- 右栏状态靠页面推断 + +这三套并行模型。 + +### 4.2 迁移期必须新增的状态 + +第一阶段必须补上: + +```ts +type TaskRuntimeContextV1 = { + currentTaskId: string + currentSpecialistKey: string + currentSkillKey: string +} +``` + +其中: + +- `currentSpecialistKey` 表示当前任务挂载的主编排对象 +- `currentSkillKey` 表示当前输入区和设置条默认服务的技能对象 + +`currentSkillKey` 的意义是把技能正式纳入任务上下文,结束“技能只存在于路由页”的旧模型。 + +### 4.3 最终推荐状态模型 + +在迁移完成后,建议升级为: + +```ts +type TaskRuntimeContext = { + currentTaskId: string + currentSpecialistKey: string + openedSkillKeys: string[] + focusedObjectKind: 'assistant' | 'specialist' | 'skill' + focusedObjectKey: string + mode: 'quick' | 'expert' +} +``` + +解释: + +- `currentTaskId`:当前任务 +- `currentSpecialistKey`:这条任务当前的主编排者 +- `openedSkillKeys`:这条任务里已启动但未关闭的技能 +- `focusedObjectKind` / `focusedObjectKey`:当前输入框、设置条、右栏正在服务哪个对象 +- `mode`:当前工作模式 + +### 4.4 状态约束 + +必须满足以下约束: + +1. 没有任务时,允许预选对象,但只能作为 pending 状态 +2. 一旦第一条消息发出,pending 状态必须落入任务上下文 +3. `focusedObjectKey` 必须属于: + - `currentSpecialistKey` + - `openedSkillKeys` + - 或默认助手 +4. 关闭对象后,焦点必须自动切回: + - 同任务下的其他已打开对象 + - 没有则回到当前专员 + - 再没有则回到通用助手 + +--- + +## 5. 路由收敛原则 + +### 5.1 执行路由 + +执行型路由只保留: + +- `/home` + +### 5.2 目录与配置路由 + +允许保留的非执行路由只有两类: + +1. 目录路由 + 例如: + - `/catalog/specialists` + - `/catalog/skills` + - `/catalog/connectors` + +2. 配置 / 管理路由 + 例如: + - `/studio` + - `/console` + - 后台管理页 + +### 5.3 兼容跳转规则 + +在迁移阶段: + +- `/apps/*` -> 跳回 `/home` +- `/tools/*` -> 跳回 `/home` + +跳转时要把对象意图带回工作台,例如: + +- 原 `/tools/document-translate` + -> `/home` 并恢复 `currentSkillKey=document-translate` +- 原 `/apps/contract-review` + -> `/home` 并恢复 `currentSpecialistKey=contract-review-specialist` + +兼容跳转只做迁移兜底,不允许再承载新逻辑。 + +--- + +## 6. 工作台交互合同 + +### 6.1 输入区 + +输入区固定结构: + +`[+] [当前对象 chip] [附件] [输入框] [发送]` + +规则: + +1. `+` 是唯一启动入口 +2. `当前对象 chip` 是唯一上下文可视入口 +3. 输入区永远不因为对象类型不同而变成另一套布局 + +### 6.2 `+` 菜单 + +`+` 菜单只负责 4 类动作: + +1. 切模式 +2. 启动 / 切换专员 +3. 启动工具 +4. 打开连接器相关能力 + +`+` 菜单不负责跳执行页。 + +### 6.3 当前对象 chip + +规则: + +1. 固定显示在 `+` 右边 +2. 始终展示当前焦点对象 +3. 专员、工具结构统一,只是样式和文案不同 +4. 点击 chip 只允许: + - 展开详情 + - 切焦点 + - 打开配置抽屉 + +不允许点击后跳到另一套执行页面。 + +### 6.4 设置条 + +设置条是“当前焦点对象”的设置条,不是“当前路由页”的设置条。 + +规则: + +1. 只服务 `focusedObjectKey` +2. 改动从下一条消息开始生效 +3. 不允许继续根据 `/tools/*` 路由推断工具身份 + +### 6.5 右栏 + +右栏固定两个 tab: + +- 工作流 +- 产物 + +规则: + +1. 右栏服务当前焦点对象 +2. 专员焦点时,展示专员级工作流与产物 +3. 工具焦点时,展示工具级执行流与产物 +4. 右栏不允许只支持专员、不支持工具 + +--- + +## 7. 对象生命周期 + +每个专员 / 工具都必须服从统一生命周期: + +### 7.1 启动 + +启动来源: + +- `+` 菜单 +- 目录页中的“启动”动作 +- 兼容跳转恢复 + +启动结果: + +- 对象进入当前任务上下文 +- 成为可聚焦对象 +- 在输入区显示为当前对象或可切换对象 + +### 7.2 配置 + +配置行为包括: + +- 修改模式 +- 修改对象设置 +- 打开对象详情 +- 调整对象参数 + +配置结果必须记录在任务上下文,而不是记录在页面局部状态。 + +### 7.3 关闭 + +关闭对象后: + +- 从当前任务的已打开对象列表中移除 +- 关闭该对象设置条 +- 焦点自动切回其他对象 + +关闭不是“离开页面”,而是“从当前任务上下文卸载对象”。 + +### 7.4 重新打开 + +如果任务里已经存在一个对象,再次点击它时: + +- 默认切焦点 +- 不再重复创建 + +--- + +## 8. 页面职责收敛 + +### 8.1 `BusinessAppPage` 的状态 + +`BusinessAppPage` 已从前端仓库移除。 + +这说明以下约束已经落地: + +- 不再承担聊天执行 +- 不再承担任务推进主入口 +- 不再与 `/home` 形成并行的第二工作台 + +### 8.2 各 `ToolPage` 的状态 + +`DocumentTranslatePage`、`CopyProofreadingPage`、`AudioTranscribePage` 等旧工具执行页已从前端仓库移除。 + +它们留下来的有效资产只剩两类: + +1. 已抽离出的 schema / runtime / 组件 +2. 历史设计文档中的迁移记录 + +它们已经不再作为产品形态存在。 + +--- + +## 9. 数据层约束 + +### 9.1 任务是唯一事实来源 + +以下运行时状态必须最终可从任务恢复: + +- 当前专员 +- 当前工具 +- 已打开工具列表 +- 当前焦点对象 +- 对象设置快照 +- 关键工作流状态 +- 产物列表 + +### 9.2 禁止继续混用演示数据与真实数据 + +以下情况必须逐步清理: + +- 页面本地写死 `messages` +- 页面本地写死 `taskItems` +- 工作台 snapshot 与 live data 混合渲染但界面上不区分 + +迁移后应满足: + +1. 真数据就渲真数据 +2. 演示态必须明确标注为模板 / 示例 / 空态 +3. 不允许让示例数据冒充真实任务结果 + +--- + +## 10. 迁移顺序 + +### Phase 0:合同冻结 + +先冻结这份合同,后续改造按它执行。 + +### Phase 1:补全任务上下文 + +目标: + +- 增加 `currentSkillKey` +- 让技能脱离路由身份,先进入任务 store + +结果: + +- 选技能不再只是跳页 +- 工作台第一次具备“任务 + 专员 + 技能”的统一上下文 + +### Phase 2:统一当前对象 + +目标: + +- `CurrentObjectChip` 改为真正读任务上下文 +- 设置条改为读 `focusedObjectKey` +- 右栏从“专员面板”演进为“对象面板” + +结果: + +- 输入区、设置条、右栏三者对齐 + +### Phase 3:路由收敛 + +目标: + +- `/apps/*` 全部改兼容跳转 +- `/tools/*` 全部改兼容跳转 + +结果: + +- `/home` 成为唯一执行工作面 + +### Phase 4:删除重复执行页 + +目标: + +- 删除各类工具执行页中的消息流、输入框、任务逻辑 +- 删除各类专员执行页中的聊天职责 + +结果: + +- 页面树明显收缩 +- 状态源头回归统一 + +### Phase 5:命名与对象清洗 + +目标: + +- 拆分专员 key 与工具 key 冲突 +- 清理旧命名 +- 清理遗留兼容逻辑 + +结果: + +- 模型稳定 +- 后续功能可持续扩展 + +--- + +## 11. 禁止事项 + +从这份合同生效开始,以下做法视为逆行: + +1. 再新增任何 `/tools/*` 执行页 +2. 再新增任何 `/apps/*` 执行页 +3. 在页面局部状态里偷偷维护“当前工具” +4. 继续复用同一个 key 同时代表专员和工具 +5. 让当前对象由页面 `prefer` 或路由猜测,而不是由任务上下文决定 +6. 让右栏只支持专员,不支持工具 + +--- + +## 12. 最终产品语义 + +最终用户感知必须收敛为: + +- 我在一个工作台里 +- 我当前正在处理一条任务 +- 这条任务挂了某个专员 +- 这条任务打开了若干工具 +- 我现在聚焦在某个对象上 +- 我可以启动、配置、关闭这些对象 +- 我不需要理解页面切换,只需要理解任务上下文 + +如果界面上任何一个交互让用户重新产生: + +`我是不是又跳进了另一个工具页 / 专员页` + +那就说明这次改造没有做完。 diff --git a/docs/02_Architecture/AR06_Skill_Packaging_Specification.md b/docs/02_Architecture/AR06_Skill_Packaging_Specification.md new file mode 100644 index 0000000..0359ae8 --- /dev/null +++ b/docs/02_Architecture/AR06_Skill_Packaging_Specification.md @@ -0,0 +1,552 @@ +# 技能文件规范 + +> 落盘日期:2026-09-16 +> 状态:生效中 +> 作用:定义“每个技能在前端代码中应该以什么文件形式存在” +> 关联文档:`AR05_Workbench_Architecture_Contract.md` + +--- + +## 1. 结论 + +从本规范生效开始: + +**技能不再以独立执行页面的形式存在。** + +每个技能必须被建模为: + +`定义文件 + 执行器文件 + 结果组件 + 可选扩展组件` + +而不是: + +`一个完整的 xxxPage.vue` + +--- + +## 2. 标准目录 + +所有技能统一存放在: + +`frontend/src/skills/` + +目录结构固定为: + +```text +src/skills/ + registry/ + eai.ts + custom.ts + index.ts + shared/ + types.ts + schema.ts + runtime.ts + eai/ + smart-assistant/ + index.ts + executor.ts + ResultCard.vue + document-translate/ + index.ts + executor.ts + ResultCard.vue + copy-proofreading/ + index.ts + executor.ts + ResultCard.vue + contract-review/ + index.ts + executor.ts + ResultCard.vue + audio-transcribe/ + index.ts + executor.ts + ResultCard.vue + batch-extract/ + index.ts + executor.ts + ResultCard.vue + custom/ + adapters/ + normalize.ts + executorFactory.ts +``` + +强约束: + +1. `eai/` 只放 EAI 官方内置技能 +2. `custom/` 不放每个用户技能的源码页面 +3. 用户自定义技能的实例数据应存后端,由前端运行时归一化 +4. 前端 repo 里只允许保留 `custom/adapters/*` 这类运行时适配代码 + +--- + +## 3. 技能来源必须分开 + +从本规范生效开始,技能必须强制区分来源: + +- `source = 'eai'` +- `source = 'custom'` + +### 3.1 EAI 技能 + +定义: + +- 平台内置 +- 由 EAI 官方提供 +- 随代码仓库交付 +- 放在 `src/skills/eai/` + +### 3.2 用户自定义技能 + +定义: + +- 由租户 / 用户 / 管理员创建 +- 不属于平台内置源码 +- 应以数据形式存储在后端 +- 由前端在运行时转换成统一 `SkillDefinition` + +### 3.3 不允许混放 + +禁止以下做法: + +1. 把用户技能和 EAI 技能放在同一层目录 +2. 给用户技能也手工创建一个 `src/skills/eai/*` 目录 +3. 把用户技能伪装成内置技能编号 +4. 让前端页面层自己判断“这是官方技能还是用户技能” + +来源判断必须统一由 registry 和 definition 字段承担。 + +--- + +## 4. 每个工具允许的文件 + +每个 EAI 工具目录下只允许这 4 类文件: + +### 4.1 `index.ts` + +这是工具主定义文件,必须存在。 + +作用: + +- 定义工具身份 +- 定义显示名称 +- 定义设置 schema +- 定义开场提示 +- 绑定执行器 +- 绑定结果渲染组件 + +### 4.2 `executor.ts` + +这是工具执行器,必须存在。 + +作用: + +- 组装请求参数 +- 调用后端接口 +- 归一化响应结果 + +约束: + +- 不允许依赖页面组件 +- 不允许写 DOM 逻辑 +- 不允许直接操作路由 + +### 4.3 `ResultCard.vue` + +这是工具结果渲染组件,必须存在。 + +作用: + +- 渲染该工具的结果卡片 +- 展示结构化结果 +- 展示摘要、状态、附加信息 + +约束: + +- 这是局部结果组件,不是页面 +- 不允许包含整个聊天布局 +- 不允许自己持有输入框 + +### 4.4 `SettingsPanel.vue` + +这是可选文件,只在 schema 驱动不够时允许出现。 + +作用: + +- 处理复杂设置 UI + +约束: + +- 默认不创建 +- 只有通用 schema 无法表达时才允许新增 + +--- + +## 5. 编号与命名规范 + +每个工具必须同时拥有以下 4 个身份字段: + +1. `id` +2. `code` +3. `key` +4. `label` + +四者职责不同,禁止混用。 + +### 5.1 `id` + +`id` 是机器标识,必须全局唯一,且不可变。 + +格式固定为: + +- EAI 技能:`eai.` +- 用户技能:`custom..` + +示例: + +- `eai.document-translate` +- `eai.audio-transcribe` +- `custom.acme.document-translate-pro` + +规则: + +1. 全小写 +2. 使用 `.` 做命名空间分隔 +3. 最后一段必须和 `skill-key` 一致 +4. 一经创建不得修改 + +### 5.2 `code` + +`code` 是展示编号,给人看,用于列表、配置页、运营页、审计页。 + +格式固定为: + +- EAI 技能:`EAI-T-001` +- 用户技能:`CUS-T-001` + +规则: + +1. `EAI-T-xxx` 只保留给官方内置技能 +2. `CUS-T-xxx` 只保留给用户自定义技能 +3. `xxx` 为三位流水号,从 `001` 开始 +4. 用户技能的 `code` 允许在“当前租户 / 当前工作区”范围内顺序编号 +5. 全局唯一性由 `id` 保证,不由 `code` 保证 + +### 5.3 `key` + +`key` 是前端目录名和查找键,必须使用 kebab-case。 + +示例: + +- `document-translate` +- `contract-review` +- `batch-extract` + +规则: + +1. 只能包含小写字母、数字、中划线 +2. 不允许空格 +3. 不允许中文 +4. 必须与目录名一致 + +### 5.4 `label` + +`label` 是用户可见名称,必须是中文产品名。 + +示例: + +- `文档翻译` +- `合同审查` +- `批量提取` + +规则: + +1. 优先使用中文 +2. 不带技术实现词 +3. 不在名称里拼接编号 +4. 不在名称里拼接来源前缀 + +错误示例: + +- `EAI-T-001 文档翻译` +- `custom_contract_review` +- `合同审查工具V2` + +--- + +## 6. 每个技能必须导出的定义结构 + +每个技能的 `index.ts` 必须默认导出一个标准对象。 + +字段固定如下: + +```ts +export interface SkillDefinition { + id: string + code: string + source: 'eai' | 'custom' + key: string + label: string + kind: 'skill' + icon: string + description: string + settings: SkillSettingSchema[] + starterPrompts: string[] + executor: SkillExecutor + resultCard: Component +} +``` + +强约束: + +1. `id` 必须全局唯一 +2. `code` 必须符合来源对应的编号前缀 +3. `source` 只能是 `eai` 或 `custom` +4. `key` 必须与目录名一致 +5. `kind` 固定为 `'skill'` +6. `settings` 必须是 schema 数据,不允许把设置 UI 直接写进定义文件 +7. `executor` 必须指向当前技能自己的 `executor.ts` +8. `resultCard` 必须指向当前技能自己的 `ResultCard.vue` + +--- + +## 7. 文件职责边界 + +### 7.1 `index.ts` 负责什么 + +只负责: + +- 元数据 +- schema +- 组件与执行器装配 + +不负责: + +- 发请求 +- 维护输入状态 +- 渲染完整聊天界面 + +### 7.2 `executor.ts` 负责什么 + +只负责: + +- 把任务上下文和设置值转换成请求 +- 调用后端 +- 返回标准结果对象 + +不负责: + +- 决定页面跳转 +- 直接操作 store 里的 UI 状态 +- 渲染文本 + +### 7.3 `ResultCard.vue` 负责什么 + +只负责: + +- 接收标准结果数据 +- 渲染结果 + +不负责: + +- 调接口 +- 打开任务 +- 切换工具 + +--- + +## 8. 严格禁止的文件形式 + +从本规范生效开始,以下文件形式禁止继续新增: + +1. `src/views/tools/*Page.vue` 作为工具执行页 +2. 每个工具单独复制一份 `ChatLayout` +3. 每个工具单独复制一份 `ChatInputBar` +4. 每个工具单独维护一份本地 `messages` +5. 每个工具单独维护一份本地 `taskItems` +6. 每个工具单独维护一份右栏面板 +7. 每个工具用独立路由页面表达“当前正在使用” + +一句话: + +**技能可以有自己的定义文件和局部组件,但不能再有自己的执行页面。** + +--- + +## 9. 统一注册方式 + +技能注册必须按来源拆分: + +- `src/skills/registry/eai.ts` +- `src/skills/registry/custom.ts` +- `src/skills/registry/index.ts` + +注册形式固定为: + +```ts +// registry/eai.ts +import smartAssistant from '../eai/smart-assistant' +import documentTranslate from '../eai/document-translate' + +export const eaiSkillRegistry = [ + smartAssistant, + documentTranslate, +] + +// registry/custom.ts +export async function loadCustomSkillRegistry() { + return fetchCustomSkillsFromBackend() +} + +// registry/index.ts +export async function loadSkillRegistry() { + const customSkills = await loadCustomSkillRegistry() + return [...eaiSkillRegistry, ...customSkills] +} +``` + +约束: + +1. EAI 工具只能从 `registry/eai.ts` 注册 +2. 用户工具只能从 `registry/custom.ts` 装载 +3. `registry/index.ts` 只做合并,不写业务逻辑 +4. 页面层不允许自己 import 某个工具目录 +5. 工作台只能通过统一 registry 查工具 +6. 页面层不允许自己判断来源并做分支 +7. 工具排序优先使用 `code` 和显式排序字段,不允许靠文件名碰运气 + +--- + +## 10. 工作台与工具的关系 + +Workbench 是唯一执行面。 + +因此: + +- 输入框属于 Workbench +- 当前对象 chip 属于 Workbench +- 设置条属于 Workbench +- 工作流 / 产物右栏属于 Workbench +- 任务列表属于 Workbench + +工具只提供: + +- 自己是谁 +- 自己能做什么 +- 自己有哪些设置 +- 自己如何执行 +- 自己如何渲染结果 + +--- + +## 11. 文件名规范 + +### 11.1 工具目录名 + +必须使用 kebab-case: + +- `document-translate` +- `audio-transcribe` +- `batch-extract` + +### 11.2 文件名 + +固定如下: + +- `index.ts` +- `executor.ts` +- `ResultCard.vue` +- `SettingsPanel.vue` + +禁止: + +- `DocumentTranslatePage.vue` +- `AudioToolPage.vue` +- `TranslateWorkbench.vue` + +### 11.3 组件名 + +工具局部组件必须使用 PascalCase: + +- `ResultCard.vue` +- `SettingsPanel.vue` +- `ArtifactPreview.vue` + +### 11.4 目录与 key 的关系 + +工具目录名必须与 `key` 一致: + +- 目录:`document-translate` +- key:`document-translate` + +不允许目录名和 key 各写各的。 + +--- + +## 12. 迁移结果 + +`src/views/tools/*.vue` 旧执行页已经完成退出,当前状态如下: + +### 已完成 + +- 旧技能执行路由已删除 +- `src/views/tools/*.vue` 中的执行页源码已删除 +- 技能配置与执行逻辑已开始收敛到 `src/skills/*` +- `/home` 已成为唯一工作台执行入口 + +### 仍需继续推进 + +虽然旧页面已经删除,但下面几类资产还要继续补齐: + +- 更完整的 `executor` 接线 +- 更统一的 `ResultCard` / `SettingsPanel` 规范 +- 用户自定义技能的后端配置接入 +- 对象实例化后的运行记录与产物呈现 + +--- + +## 13. 特殊情况处理 + +### 13.1 设置特别复杂的技能 + +如果某个技能的设置无法由通用 schema 表达,允许新增: + +- `SettingsPanel.vue` + +但仍然禁止: + +- 为此恢复一个完整技能页 + +### 13.2 结果展示特别复杂的技能 + +如果 `ResultCard.vue` 不够,可以继续拆分局部组件,例如: + +- `ResultSummary.vue` +- `ArtifactPreview.vue` + +但这些文件仍然必须放在该技能目录下,且都属于局部组件,不是页面。 + +--- + +## 14. 最终硬规范 + +从现在开始,前端对“技能”的唯一合法表达方式是: + +EAI 技能: + +`src/skills/eai//index.ts` + +用户技能: + +不以源码页面形式存在,统一由后端配置记录 + `src/skills/custom/adapters/*` 运行时适配。 + +这是技能的主入口。 + +配套合法文件只有: + +- `executor.ts` +- `ResultCard.vue` +- `SettingsPanel.vue`(可选) + +除此之外,不再接受任何“每个工具一个执行页”的实现方式,也不接受把用户工具和 EAI 工具混放在同一来源目录里。 diff --git a/docs/02_Architecture/AR07_Architecture_Alignment_Audit.md b/docs/02_Architecture/AR07_Architecture_Alignment_Audit.md new file mode 100644 index 0000000..7003d3c --- /dev/null +++ b/docs/02_Architecture/AR07_Architecture_Alignment_Audit.md @@ -0,0 +1,97 @@ +# 架构对齐确认与本轮修复范围 + +> 落盘日期:2026-09-16 +> 状态:本轮生效 +> 关联文档: +> - `AR05_Workbench_Architecture_Contract.md` +> - `../01_System_Overall/SY24_Platform_Architecture_Rethink.md` +> - `AR06_Skill_Packaging_Specification.md` + +--- + +## 1. 本轮确认结论 + +当前前端已经出现两套并行模型: + +1. `workerRuntime` 开始把 `currentSpecialistKey / currentSkillKey` 收进任务上下文 +2. 路由和多个入口仍在继续使用 `/apps/*`、`/tools/*` 当执行页 + +这两套模型继续并存,会持续制造以下问题: + +- 同一个对象,既像“挂在任务上的对象”,又像“跳去一个页面” +- 输入区已经开始对象化,但对象 chip 和首页卡片还在按旧路由跳转 +- 兼容路径不只是兼容,而是在继续承载真实业务 + +所以本轮先不扩技能复刻,先回到我们自己的架构,确认并修复这一层。 + +--- + +## 2. 已确认的主要偏差 + +### 2.1 执行入口没有收敛到 `/home` + +当前代码中仍存在: + +- `/apps/:key` 专员执行页 +- `/tools/:key` 工具执行页 +- `/report-gen` 这类独立工具页 + +这与“只保留一个 Workbench 执行面”的架构合同冲突。 + +### 2.2 启动对象的入口行为不一致 + +当前不同入口对“打开专员 / 工具”的处理不一致: + +- `+` 菜单一部分已经开始写任务上下文 +- 首页卡片仍直接 `router.push(app.pageRoute)` 或使用业务对象旧入口字段 +- 市场页“打开工作区”仍直接进入旧路由 +- 当前对象 chip 仍会把工具跳到旧工具页 + +这会导致用户在不同入口触发同一对象时,落点完全不同。 + +### 2.3 旧执行路由仍残留在产品结构里 + +根据架构合同,`/apps/*`、`/tools/*` 应该退出执行结构。 + +此前前端中它们曾直接挂载为执行页: + +- `BusinessAppPage.vue` +- `DocumentTranslatePage.vue` +- `CopyProofreadingPage.vue` +- `ContractReviewPage.vue` +- `AudioTranscribePage.vue` +- `BatchExtractPage.vue` + +以上旧执行页现已全部从前端仓库移除。 + +这会继续放大旧页面模型。 + +--- + +## 3. 本轮修复范围 + +本轮只修第一优先级: + +1. 所有“打开专员 / 工具”的行为,统一回到 `/home` +2. `/apps/*`、`/tools/*`、`/report-gen` 从路由中直接移除 +3. 所有对象启动动作只认新的工作台入口和任务上下文 + +--- + +## 4. 本轮暂不处理 + +以下问题已确认存在,但不在本轮一起动: + +1. 后端 `task -> specialist_key` 仍未升级为更完整的 mounted objects 结构 +2. 后端专员数据结构命名已升级为 `object_entry_route`,并与普通页面导航 `page_route` 分离;旧 `route / entry_route` 已收缩为启动阶段的一次性数据库迁移逻辑,不再驻留在日常模型与接口中 + +--- + +## 5. 本轮达成标准 + +修完后,系统应满足: + +1. 用户从 `+` 菜单、首页、市场页进入时,都会回到同一个 `/home` +2. 当前专员 / 当前工具由任务上下文决定,而不是由页面路由决定 +3. `/apps/*`、`/tools/*`、`/report-gen` 不再作为前端执行入口存在 +4. 旧执行页源码文件已经从前端仓库移除 diff --git a/docs/02_Architecture/AR08_Role_Interaction_Design.md b/docs/02_Architecture/AR08_Role_Interaction_Design.md new file mode 100644 index 0000000..a0f0411 --- /dev/null +++ b/docs/02_Architecture/AR08_Role_Interaction_Design.md @@ -0,0 +1,509 @@ +# AI 角色与工具统一交互设计 + +> 落盘日期:2026-09-16 +> 状态:**部分被取代的设计稿 —— 阅读前先看下面的「采纳与废弃」** + +> ## ⚠️ 采纳与废弃(2026-09-17 补注) +> +> 本文结论不是「整体作废」,而是**一半采纳、一半废弃**。请按下表取用,**不要整篇照做**。 +> +> ### 已采纳(现已是实现方向) +> +> | 本文结论 | 现落点 | +> |----------|--------| +> | 对象不跳页,都在同一工作面里挂载 | `AR05_Workbench_Architecture_Contract.md` | +> | 专员 / 工具不应该是独立 Vue 页面 | 已实现:`views/workbench/` 无独立工具页 | +> | `+` 菜单作为统一的对象选择入口 | 已实现:`components/chat/PlusMenu.vue` | +> | 切换对象 = 更新任务上下文,不跳路由 | 已实现:`store/workerRuntime.js` | +> +> ### 已废弃(不要照做) +> +> | 本文结论 | 废弃原因 | +> |----------|----------| +> | 「**数字技术员**」作为第三类对象,与专员 / 工具并列(§2.1、§5.2) | `SY21` §2.2 已明确**不再把 `tool` 作为正式命名**,对内统一 `expert / skill / app`,对外统一「专家 + 技能」。**没有「技术员」这一类。** | +> | 「通用助手 = 默认专员」这一等式(§5.4) | `SY23` 确认通用助手是**未挂专员时的兜底**,不是一种专员 | +> | §14「后续如有实现与本稿冲突,**以本稿为准**」 | 该自我授权已失效。当前收口文档是 `SY21` / `SY22`,专员改造以 `SY23_Specialist_Rule_File_And_Skill_Binding_Plan.md` 为准 | +> +> 一句话:**「不跳页面」这个判断是对的、也已落地;「数字技术员」这个对象是新造的、已被否定。** + +--- + +## 1. 结论先行 + +当前前端的核心问题,不是某几个页面细节做得不够像 WorkBuddy,而是**建模错了**: + +- **数字专员**不应该是独立业务页面 +- **工具**也不应该是一组独立 Vue 页面 +- **对话主界面**才应该是唯一主工作面 + +新的统一模型应是: + +- **通用助手** = 默认专员 +- **数字专员** = 多步任务编排者,类似企业里的项目经理 +- **数字技术员** = 单点技术能力执行者,可被专员调用 +- **工具** = 数字技术员的一种表现形式,不再等于页面 + +也就是说: + +**前端不再是“切页面使用能力”,而是“在同一个对话工作面里切换当前挂载对象”。** + +--- + +## 2. 统一对象模型 + +### 2.1 三类对象 + +| 类别 | 本质 | 典型职责 | 是否有独立完整页面 | +|------|------|----------|--------------------| +| 通用助手 | 默认专员 | 通用问答、兜底处理、把任务转交给更合适对象 | 否 | +| 数字专员 | 编排型角色 | 拆任务、排步骤、调用技术员、汇总产物 | 否 | +| 数字技术员 | 执行型角色 | 文档翻译、语音转写、批量提取、合同条款分析等单点能力 | 否 | + +### 2.2 用户感知 + +对用户来说,不再是: + +`我正在某个工具页里` + +而是: + +`我正在一条任务里,这条任务当前挂了哪个专员 / 哪个技术员` + +### 2.3 当前对象的展示规则 + +无论选中的是专员还是技术员,都应该出现在输入框左下区域: + +`[+] [当前对象 chip]` + +其中: + +- 选了专员,显示专员 chip +- 选了工具,显示工具 chip +- 两者都没有时,默认显示“通用助手” +- 输入区显性对象始终互斥:`+` 右边一次只显示一个当前对象 +- 专员内部调用技术员属于执行链,不升格为第二个显性 chip + +这一点非常关键,因为它把“当前上下文”从隐藏状态变成了**持续可见状态**。 + +--- + +## 3. 为什么原来的工具页架构是错的 + +### 3.1 错误的建模方式 + +原来的建模是: + +`一个工具 = 一个完整页面` + +例如以前会把工具理解成这些独立页: + +- `/tools/document-translate` +- `/tools/copy-proofreading` +- `/tools/audio-transcribe` +- `/tools/batch-extract` + +当前这些独立执行页已经退出,工具统一通过 `/home` 工作台挂载。 + +这会导致前端天然把“工具”理解成“去一个地方”。 + +### 3.2 实际上工具不需要页面承载 + +工具真正有差异的地方只有 3 块: + +1. **输入要求** +2. **设置条** +3. **右栏中的工作流与产物** + +除此之外,绝大多数前端骨架都是一样的: + +- 还是同一个聊天区 +- 还是同一个输入框 +- 还是同一个附件入口 +- 还是同一个右栏容器 + +所以把每个工具做成完整页面,会产生大量无意义分叉: + +- 路由分叉 +- 状态分叉 +- 组件分叉 +- 页面骨架重复 + +### 3.3 正确的建模方式 + +应该改成: + +`一个工具 = 一份能力定义 + 一份设置定义 + 一份工作流定义` + +而不是: + +`一个工具 = 一个完整页面` + +--- + +## 4. 新的前端总架构 + +### 4.1 唯一主工作面 + +系统只保留一个主交互工作面: + +`Chat Workspace` + +结构如下: + +```text +┌────────────────────────────────────────────────────────────┐ +│ 左侧导航 │ +├────────────────────────────────────────────────────────────┤ +│ 中间:对话主画面 │ 右侧:上下文面板 │ +│ │ │ +│ 消息流 │ [工作流] [产物] │ +│ │ │ +│ │ 当前对象的执行进度 │ +│ │ 当前对象的产物列表 │ +├────────────────────────────────────────────────────────────┤ +│ [+] [当前对象 chip] [附件] [输入框................] [发送] │ +└────────────────────────────────────────────────────────────┘ +``` + +### 4.2 对象切换方式 + +所有对象的选择,都从 `+` 打开: + +- 模式:快速 / 专家 +- 专员 +- 技术员 +- 连接器或其它补充入口 + +选择结果不再跳页面,而是**更新当前任务上下文**。 + +### 4.3 页面跳转原则 + +默认原则: + +- **切换对象,不跳页** +- **切换能力,不跳页** +- **切换任务,才可能切上下文** + +只有管理、配置、市场、控制台这类后台页面,才保留独立路由。 + +--- + +## 5. 专员与技术员的职责分层 + +### 5.1 数字专员 + +数字专员对应企业中的项目经理,负责: + +- 接收用户目标 +- 把目标拆成多步任务 +- 决定调用哪些技术员 +- 汇总技术员的结果 +- 输出最终交付物 + +### 5.2 数字技术员 + +数字技术员对应企业中的专业执行者,负责: + +- 完成单个技术动作 +- 处理特定格式输入 +- 产出特定类型结果 +- 把结果返回给专员或直接返回给用户 + +### 5.3 调用关系 + +```text +用户 + → 数字专员 + → 调用数字技术员 A + → 调用数字技术员 B + → 调用数字技术员 C + → 汇总结果 + → 输出最终产物 +``` + +### 5.4 通用助手的定位 + +通用助手不是单独体系,而是: + +- 默认专员 +- 未选择任何专员或技术员时的兜底对象 +- 帮用户判断应不应该切到某个专员或技术员 + +--- + +## 6. 工具的新定义 + +### 6.1 工具不再是页面 + +未来的“工具”只是技术员目录里的一个对象类别。 + +例如: + +| 旧叫法 | 新理解 | +|--------|--------| +| 文档翻译工具 | 文档翻译技术员 | +| 文案校对工具 | 文案校对技术员 | +| 语音转写工具 | 语音转写技术员 | +| 批量提取工具 | 批量提取技术员 | +| 合同审查工具 | 合同条款分析技术员或合同审查专员的下游技术员 | +| 报告生成工具 | 报告生成技术员 | + +### 6.2 工具在前端的可变部分 + +一个技术员/工具在前端只允许有 4 类差异: + +1. **对象 chip** +2. **输入提示与输入校验** +3. **设置条** +4. **右栏工作流与产物** + +除此之外,不再允许复制一整页聊天页。 + +### 6.3 工具定义应沉淀为 schema + +每个技术员建议定义如下结构: + +```ts +type TechnicianDefinition = { + key: string + label: string + summary: string + inputSchema: object + settingsSchema: object[] + workflowSchema: object[] + artifactSchema: object[] + emptyState?: { + title: string + description: string + presets?: string[] + } +} +``` + +也就是说,新增长一个工具,不应该先想“新建哪个 Vue 文件”,而应该先想“补哪份定义”。 + +--- + +## 7. 统一 UI 规则 + +### 7.1 输入区 + +输入区固定包含: + +- `+`:选择模式 / 专员 / 技术员 +- `当前对象 chip` +- `附件` +- `输入框` +- `发送` + +### 7.2 当前对象 chip + +当前对象 chip 的规则: + +- 位置固定在 `+` 右边 +- 支持专员与技术员两种样式,但结构统一 +- 只负责展示“当前挂了谁” +- 一次只展示一个当前对象,不并排显示“专员 + 技术员” +- 点击 chip 可展开对象详情,或跳到对应配置页 + +### 7.3 设置条 + +设置条是工具差异的第一承载位。 + +原则: + +- 只在当前对象有设置时显示 +- 位置在消息列表顶部 +- 形式统一为一条 sticky 条 +- 设置变更默认从**下一条消息**开始生效 +- 当前对象是专员时,默认不再额外显示技能设置条 + +设置条里的内容由对象定义驱动,而不是写死在某个页面里。 + +### 7.4 右栏 + +右栏固定 2 个 tab: + +- **工作流** +- **产物** + +#### 工作流 tab + +显示当前对象的: + +- 执行步骤 +- 进度状态 +- 当前节点 +- 子任务或检查点 + +#### 产物 tab + +显示当前对象的: + +- 文件产物 +- 结构化结果 +- 中间输出 +- 状态标签 + +### 7.5 空态 + +空态不再按“工具页”设计,而按“当前对象”设计: + +- 默认通用助手有自己的门厅 +- 技术员被选中但还没发送第一条消息时,显示该技术员自己的空态说明 +- 专员被选中但还没发送第一条消息时,显示该专员的工作流模板预览 + +--- + +## 8. 导航的重新定位 + +### 8.1 一级导航不再承担“使用工具”的职责 + +一级导航中的: + +`专员 / 工具 / 连接器` + +应该只承担**浏览配置与管理入口**的职责,而不是使用入口。 + +### 8.2 使用入口只有一个 + +真正的使用入口应该只有: + +- `新建任务` +- `打开已有任务` + +进入任务后,一切对象切换都在对话区完成。 + +### 8.3 目录页的意义 + +目录页只做这些事: + +- 浏览有哪些专员 +- 浏览有哪些技术员 +- 浏览有哪些连接器 +- 查看其配置摘要 +- 进入配置详情 + +而不是“点卡片后进入某个独立工具页”。 + +--- + +## 9. 现有代码应如何收敛 + +### 9.1 应保留的骨架 + +这些方向是对的,应保留: + +- `ChatLayout` +- `ChatInputBar` +- `PlusMenu` +- `SkillStrip` +- 右栏 `SpecialistPanel` 的工作流 / 产物思路 +- “新建任务”作为唯一对话起点 + +### 9.2 应逐步废弃的结构 + +这些应视为过渡结构: + +- 每个工具一张独立完整 Vue 页 +- 每个专员一个独立业务工作台页 +- 通过 object entry 切工具 +- 通过 object entry 切专员执行面 + +### 9.3 收敛目标 + +最终应收成: + +| 层级 | 目标 | +|------|------| +| 页面层 | 一个主对话工作面 + 少量管理页 | +| 组件层 | 一套通用聊天骨架 + 一套右栏骨架 | +| 配置层 | 专员定义 / 技术员定义 / 工作流定义 / 设置定义 | +| 数据层 | 当前任务挂载哪个对象,由任务状态驱动 | + +--- + +## 10. 重构原则清单 + +1. **页面不是能力,页面只是容器。** +2. **能力切换不应导致页面跳转。** +3. **当前上下文必须持续可见。** +4. **专员与技术员共享同一套交互语言。** +5. **工具差异只放在设置条、输入要求、工作流、产物。** +6. **新增能力优先补 schema,不优先建新页面。** +7. **导航页负责浏览与管理,不负责承载使用流。** +8. **任务是主线,对象是挂件。** +9. **右栏始终是执行透明化窗口。** +10. **默认入口只有一个:对话。** + +--- + +## 11. 前端收敛方案 + +### Phase 1:先统一心智 + +- 把“工具”统一重新命名为“数字技术员”或在内部按技术员建模 +- 明确通用助手 = 默认专员 +- 明确 object entry 不再代表能力本体 + +### Phase 2:统一输入区 + +- 在 `ChatInputBar` 中把当前对象 chip 收成标准能力 +- 专员 chip 与技术员 chip 使用统一插槽或统一组件 +- `+` 只负责选对象,不再负责跳到独立工具页 + +### Phase 3:统一设置条 + +- 把各工具页差异抽到 `settingsSchema` +- `SkillStrip` 改成真正的对象驱动渲染 +- 设置条与当前对象强绑定,不再与路由强绑定 + +### Phase 4:统一右栏 + +- 右栏根据当前对象的 `workflowSchema` 和 `artifactSchema` 渲染 +- 专员右栏强调多步编排 +- 技术员右栏强调执行步骤 + +### Phase 5:清退独立工具页 + +- 保留旧工具页一段时间做兼容 +- 新能力一律不再新建完整工具页 +- 旧工具页逐步收敛为配置详情页或兼容跳板页 + +--- + +## 12. 对当前项目最重要的影响 + +这次不是小修,而是会改变整个前端边界: + +- `availableSkills` 不再等于“可跳转的页面列表” +- `businessApps` 不再等于“专员工作台页面列表” +- 路由将从“能力入口”退回成“管理入口 / 兼容入口” +- 真正的执行入口会统一收敛到任务对话面 + +换句话说: + +**我们不再做“很多个 AI 页面”,而是做“一个任务工作面,里面动态挂很多 AI 对象”。** + +--- + +## 13. 未决问题 + +1. 对外文案最终叫“工具”还是“数字技术员”,是否区分用户可见名和内部模型名 +2. 一个任务内部可以有多个技术员执行记录,但输入区始终只显示一个当前对象 +3. 专员调用技术员时,只在右栏和执行链里显示下游执行,不在输入区显性双挂 +4. 旧工具页是否全部保留兼容路由,还是只保留极少数重度场景 +5. 目录页中的“浏览配置”应展示到什么深度,是否允许直接预览 workflow schema + +--- + +## 14. 本稿的用途 + +这份文档用于后续所有相关改造的判断标准: + +- 评估某个页面要不要保留 +- 判断某个新能力该不该新建页面 +- 判断当前对象该不该在输入区可见 +- 判断导航页与使用页的边界 + +后续如有实现与本稿冲突,以本稿为准,再逐项修订。 diff --git a/docs/02_Architecture/README.md b/docs/02_Architecture/README.md index a576135..a5769a0 100644 --- a/docs/02_Architecture/README.md +++ b/docs/02_Architecture/README.md @@ -3,7 +3,10 @@ > **命名规则:** `AR{NN}_{描述}.md` > **用途:** 后端架构、前端架构、数据库架构、部署架构 > -> **⚠️ 本目录 AR 文档为 V1.1 设计期历史快照。** 当前实现已重写为 **Go + Gin + GORM + MySQL 8.0 + FAISS**,以 `docs/changelog.md`、`docs/db_schema.md`、`docs/deploy.md` 为准。 +> **⚠️ `AR01`–`AR04` 为 V1.1 设计期历史快照。** 当前实现已重写为 **Go + Gin + GORM + SQLite + Go 原生 brute-force 向量检索**,以 `docs/changelog.md`、`docs/db_schema.md`、`docs/deploy.md` 为准。 +> `AR05`–`AR08` 是 2026-09-16 / 17 的工作台设计稿,**不属于 V1.1 快照**,其中 `AR08` 为部分被取代稿,取用前先读其文首补注。 +> 当前产品导航与工作台口径,请以 `docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md` 为准: +> `新建任务 / 项目 / 专员·技能·APP·连接器 / 长程APP / 知识库 / 后台管理 / 我的` ## 文件清单 @@ -12,5 +15,9 @@ | `README.md` | 本索引文件 | | `AR01_Backend_Arch.md` | 后端架构(V1.1 FastAPI 快照;现为 Go + Gin + GORM) | | `AR02_Frontend_Arch.md` | 前端架构(Vue3 + Element Plus 三栏布局) | -| `AR03_Database_Arch.md` | 数据库架构(MySQL 8.0 + FAISS 向量检索) | +| `AR03_Database_Arch.md` | 数据库架构(SQLite 单文件 + Go 原生向量检索) | | `AR04_Deploy_Arch.md` | 部署架构(V1.1 Docker 快照;现为单二进制 + systemd) | +| `AR05_Workbench_Architecture_Contract.md` | 数字员工 Workbench 架构合同(任务为中心、对象挂载到任务,前端重构强约束) | +| `AR06_Skill_Packaging_Specification.md` | 技能文件规范(技能 = 定义文件 + 执行器 + 结果组件,不以独立页面存在) | +| `AR07_Architecture_Alignment_Audit.md` | 架构对齐确认与本轮修复范围(收敛两套并行模型的确认记录) | +| `AR08_Role_Interaction_Design.md` | AI 角色与工具统一交互设计(**部分被取代**:不跳页结论已采纳,「数字技术员」对象已废弃,见文首补注) | diff --git a/docs/06_Product_Lines/PL04_YunQu_Parity_Roadmap.md b/docs/06_Product_Lines/PL04_YunQu_Parity_Roadmap.md new file mode 100644 index 0000000..46f7008 --- /dev/null +++ b/docs/06_Product_Lines/PL04_YunQu_Parity_Roadmap.md @@ -0,0 +1,447 @@ +# 对标云趣的办公平台追平路线图 + +> 落盘日期:2026-09-17 +> 状态:产品追平路线稿 +> 目标:追平云趣类一站式 AI 平台的办公生产力能力,不追视觉创作与音视频创作能力 +> 关联文档: +> - `../01_System_Overall/SY24_Platform_Architecture_Rethink.md` +> - `../02_Architecture/AR05_Workbench_Architecture_Contract.md` +> - `../02_Architecture/AR06_Skill_Packaging_Specification.md` +> - `../02_Architecture/AR08_Role_Interaction_Design.md` + +--- + +## 1. 这份文档解决什么问题 + +当前平台已经形成了: + +- `专家 + 技能 + APP + 统一任务工作台` +- Chat-first 的执行工作台 +- 技能工作流与产物定义 + +但如果目标从“做出自己的平台节奏”升级为“追平云趣类产品”,那么后续建设就不能再零散补点功能,而需要一份明确的追平路线图。 + +这份文档用于统一三个判断: + +1. 我们到底追平什么 +2. 我们明确不追什么 +3. 接下来应该按什么顺序补齐 + +--- + +## 2. 最终判断 + +我们的追平目标应明确定义为: + +`追平云趣的一站式办公生产力平台能力,而不是追平其视觉创作站能力。` + +换句话说,后续路线不以“AI 绘画、AI 视频、AI 音乐”作为主轴,而以: + +- 文档交付 +- 长文生成 +- 结构化整理 +- 图文理解 +- 应用市场 +- 任务复用 +- 产物沉淀 + +作为主轴。 + +这是因为本平台当前最强的底层已经不是“模型调用入口”,而是: + +- `任务容器` +- `对象挂载` +- `工作流` +- `产物` +- `右栏协作` + +因此,最值得追平的是“办公执行平台感”,不是“多模态创作站感”。 + +--- + +## 3. 明确不做的能力边界 + +下列能力不纳入本轮追平范围: + +### 3.1 视觉创作面 + +- `AI 绘画` +- `混图` +- `换脸` +- `画廊广场` +- `提示词库` + +### 3.2 重创作面 + +- `AI 视频` +- `AI 音乐` + +### 3.3 结论 + +本轮追平不以“创作娱乐平台”作为目标,而以“办公与任务执行平台”作为目标。 + +--- + +## 4. 当前基础盘点 + +### 4.1 已有技能定义基础 + +当前 `frontend/src/config/workbench.js` 已经具备一批办公向技能定义: + +- `通用助手` +- `文档翻译` +- `文案校对` +- `语音转写` +- `批量提取` +- `合同审查` +- `报告生成` + +同时也已有一批场景型对象: + +- `合同审查专员` +- `售前方案专员` +- `培训交付专员` +- `知识运营专员` +- `流程推进专员` +- `报告生成专员` +- `公众号助手` +- `履约跟单专员` +- `HR 邮件整理专员` +- `简历处理专员` + +### 4.2 已有执行层基础 + +当前执行层已有雏形,但总体偏薄: + +- `src/skills/registry/eai.js` 中仅注册了少量 EAI 技能 +- `src/skills/shared/workbuddyReplicaCatalog.js` 中,`Excel` 已实现,`PPT` 仍处于待补阶段 + +### 4.3 当前真正的差距 + +当前最大的差距不是“没有专家或技能名”,而是: + +1. 缺少更丰富的办公核心技能 +2. 缺少成体系的应用广场 +3. 缺少可沉淀、可复用、可回看的产物与任务系统 +4. 缺少从“定义层”走向“执行层”的完整技能落地 + +--- + +## 5. 追平对象的能力抽象 + +对标云趣时,应把它的能力拆成两类: + +### 5.1 需要追平的能力 + +- `聊天对话 + 多模型` +- `办公写作` +- `长文创作` +- `PPT 生成` +- `思维导图` +- `文本处理工具箱` +- `图文理解 / OCR / 识图` +- `应用广场` +- `预设应用` +- `任务与产物沉淀` +- `文档中心 / 我的文档` + +### 5.2 不需要追平的能力 + +- `AI 绘画` +- `画同款` +- `换脸` +- `画廊广场` +- `AI 视频` +- `AI 音乐` + +--- + +## 6. 差距清单 + +| 模块 | 我们当前状态 | 差距等级 | 是否进入追平范围 | 建议优先级 | +| --- | --- | --- | --- | --- | +| 通用对话 | 已有 | 低 | 是 | P1 | +| 文档翻译 | 已有 | 低 | 是 | P1 | +| 文案校对 | 已有 | 低 | 是 | P1 | +| 语音转写 | 已有 | 低 | 是 | P1 | +| 批量提取 | 已有 | 低 | 是 | P1 | +| 合同审查 | 已有 | 低 | 是 | P1 | +| 报告生成 | 已有 | 低 | 是 | P1 | +| PPT 生成 | 仅有待补线索,未形成正式技能 | 高 | 是 | P0 | +| 思维导图 | 未形成正式技能 | 高 | 是 | P0 | +| 长文创作 | 未形成正式技能 | 高 | 是 | P0 | +| 文本处理工具箱 | 未形成产品化能力 | 高 | 是 | P0 | +| OCR / 图文理解 | 未形成正式技能 | 高 | 是 | P0 | +| 应用广场 | 有目录页基础,但应用体系不够厚 | 中高 | 是 | P1 | +| 自定义应用 / 智能体 | 未形成用户可配置能力 | 高 | 是 | P1 | +| 文档中心 / 产物中心 | 右栏已有产物基础,但缺独立中心 | 高 | 是 | P1 | +| 任务结果复用 | 有任务记录,但复用链路偏弱 | 中高 | 是 | P1 | +| 常用模型 / 模型收藏 | 有模型切换基础,但平台化程度不足 | 中 | 是 | P2 | +| AI 绘画 | 未做 | 高 | 否 | 排除 | +| 混图 / 换脸 | 未做 | 高 | 否 | 排除 | +| 画廊 / 提示词库 | 未做 | 高 | 否 | 排除 | +| AI 视频 | 未做 | 高 | 否 | 排除 | +| AI 音乐 | 未做 | 高 | 否 | 排除 | + +--- + +## 7. 新版 Phase 2 + +## 7.1 目标 + +`把聊天助手升级成真正能交付文档结果的工作台。` + +### 7.2 必做模块 + +1. `PPT 生成` +2. `思维导图` +3. `长文创作` +4. `文本处理工具箱` +5. `OCR / 图文理解` + +### 7.3 各模块建议定义 + +#### A. PPT 生成 + +建议输入: + +- 主题 +- 受众 +- 页数 +- 风格 +- 参考材料 + +建议输出: + +- `演示大纲.md` +- `演示文稿.pptx` +- `演讲备注.md` + +建议定位: + +- 对标云趣/WorkBuddy 最容易被用户直接感知的高价值技能 + +#### B. 思维导图 + +建议输入: + +- 一句话主题 +- 一段原始材料 +- 当前任务上下文 + +建议输出: + +- `导图源文件.md` +- `导图.svg` +- `导图.png` + +建议定位: + +- 作为“任务结构化承接器”,紧贴通用助手与长文创作 + +#### C. 长文创作 + +不要只做“论文工具”,而应统一抽象为: + +- `论文` +- `方案` +- `制度文档` +- `公众号长文` +- `小说` + +建议输出: + +- `大纲.md` +- `正文.docx` +- `摘要.md` + +建议定位: + +- 做成统一的长文引擎,而不是只做单一场景页面 + +#### D. 文本处理工具箱 + +建议能力: + +- 去 Markdown 符号 +- 文本统计 +- 文本清洗 +- 标点与格式标准化 +- 批量整理 + +建议输出: + +- `清洗后文本.md` +- `统计结果.md` + +建议定位: + +- 高频轻工具 +- 直接提升整个平台的“顺手度” + +#### E. OCR / 图文理解 + +建议能力: + +- 图片转文字 +- 截图识别 +- 文档图片结构理解 +- 基于图片抽字段 +- 图中表格与信息识别 + +建议输出: + +- `识别结果.md` +- `结构化字段.xlsx` +- `图文摘要.md` + +建议定位: + +- 是办公场景里比 AI 绘画更高频、更正经的能力 + +--- + +## 8. 新版 Phase 3 + +## 8.1 目标 + +`把“有几个技能”升级成“可持续使用的平台”。` + +### 8.2 必做模块 + +1. `应用广场` +2. `自定义应用 / 智能体配置` +3. `文档中心 / 产物中心` +4. `任务结果复用` +5. `多模型切换与常用模型` +6. `应用模板与场景预设` + +### 8.3 重点解释 + +#### A. 应用广场 + +不是简单列对象目录,而是要形成: + +- 分类浏览 +- 场景推荐 +- 模板复用 +- 已安装 / 待安装 +- 示例任务入口 + +#### B. 自定义应用 / 智能体配置 + +目标不是开放底层编排,而是先支持: + +- 选择场景模板 +- 填写提示词与规则 +- 选择模型 +- 选择产物模板 +- 保存为可复用应用 + +#### C. 文档中心 / 产物中心 + +要从当前右栏产物区,升级为独立可管理资产: + +- 最近产物 +- 收藏 +- 按任务查看 +- 按类型查看 +- 再次打开继续编辑 + +#### D. 任务结果复用 + +用户在平台里完成一次任务后,应支持: + +- 复制为模板任务 +- 复用上一版产物 +- 继续生成新版本 +- 从旧任务快速新建相似任务 + +#### E. 多模型切换与常用模型 + +当前已经有模型切换基础,但还不够“平台”: + +- 常用模型 +- 最近使用模型 +- 按任务记忆模型 +- 按应用推荐默认模型 + +#### F. 应用模板与场景预设 + +这是形成“平台感”的关键: + +- 工作周报生成器 +- 会议纪要整理器 +- 招聘简历初筛器 +- 合同风险审查器 +- 培训归档助手 +- 公众号改写助手 + +这些不一定都要先做成重技能,但至少应形成可调用的预设对象体系。 + +--- + +## 9. 研发落地原则 + +后续每新增一个技能,不能只补定义层,必须同时补齐四件套: + +1. `对象定义` +2. `workflowSchema` +3. `artifactSchema` +4. `真实 executor / 结果卡片` + +必要时补到六件套: + +1. `对象定义` +2. `执行器` +3. `结果卡片` +4. `历史记录` +5. `产物管理` +6. `模板预设` + +如果只补: + +- `workbench.js` +- 右栏工作流 +- 目录页卡片 + +那会继续停留在“看起来有技能”,而不是“真的追平平台能力”。 + +--- + +## 10. 推荐开发顺序 + +### 10.1 第一批 + +1. `PPT 生成` +2. `思维导图` +3. `长文创作` +4. `文本处理工具箱` +5. `OCR / 图文理解` + +### 10.2 第二批 + +1. `应用广场增强` +2. `文档中心 / 产物中心` +3. `任务结果复用` +4. `自定义应用 / 智能体配置` + +### 10.3 第三批 + +1. `模型收藏与常用模型` +2. `应用模板体系` +3. `场景预设批量铺开` + +--- + +## 11. 一句话结论 + +本平台后续追平云趣的正确路线,不是: + +`去补 AI 绘画、视频、音乐这些创作站能力` + +而是: + +`把办公技能做深,把应用市场做厚,把任务与产物体系做成真正的平台。` + +这条路线更符合当前已有架构,也更符合“统一任务工作台”的产品气质。 diff --git a/docs/06_Product_Lines/README.md b/docs/06_Product_Lines/README.md index ee83cd5..420bb16 100644 --- a/docs/06_Product_Lines/README.md +++ b/docs/06_Product_Lines/README.md @@ -3,7 +3,12 @@ > **命名规则:** `PL{NN}_{描述}.md` > **用途:** 前端视图设计、页面流程、组件设计 > -> **⚠️ 本目录 PL 文档为 V1 培训平台视图基线(首页/公司/产品/课程/考试 + 右侧 PathCoach)。** 平台升级后一级导航与工作台形态见 `SY03`(新导航)与 `SY17`(工作台线框图)。 +> **⚠️ `PL01`–`PL03` 为 V1 培训平台视图基线(首页/公司/产品/课程/考试 + 右侧 PathCoach)。** +> `PL04` 是 2026-09-17 的办公平台追平路线稿,**不属于 V1 基线**。 +> 当前正式产品导航与工作台口径,请以 `SY22_Role_Skill_App_Unified_Task_Architecture.md` 为准: +> `新建任务 / 项目 / 专员·技能·APP·连接器 / 长程APP / 知识库 / 后台管理 / 我的` +> +> 本目录主要保留 V1 页面设计资产;其中“首页 / 公司介绍培训 / 产品知识 / 课程 / 考试 / 知识管理 / 系统管理 / PathCoach”等名称,均不代表当前目标态导航。 ## 文件清单 @@ -13,3 +18,4 @@ | `PL01_Global_Layout.md` | 全局布局设计(顶部导航 + AI 侧栏) | | `PL02_Employee_Views.md` | 员工端视图(首页/公司/产品/课程/考试) | | `PL03_Admin_Views.md` | 管理员端视图(知识管理/系统管理) | +| `PL04_YunQu_Parity_Roadmap.md` | 对标云趣的办公平台追平路线图(**非 V1 基线**,2026-09-17 路线稿:只追办公生产力,不追视觉与音视频创作) | diff --git a/docs/09_Research/RS01_WorkBuddy_Skill_RPA_Learning.md b/docs/09_Research/RS01_WorkBuddy_Skill_RPA_Learning.md new file mode 100644 index 0000000..be7c280 --- /dev/null +++ b/docs/09_Research/RS01_WorkBuddy_Skill_RPA_Learning.md @@ -0,0 +1,246 @@ +# WorkBuddy 技能 RPA 学习记录 + +> 落盘日期:2026-09-16 +> 状态:生效中 +> 目标:记录本次对 WorkBuddy 登录后页面的真实 RPA 学习过程,并沉淀为本项目可执行的复刻结论 + +--- + +## 1. 本次学习目标 + +本次不是看页面截图,也不是猜交互,而是直接在 WorkBuddy 登录后的真实产品里完成两条链路: + +1. `专家目录 -> 召唤专家 -> 回到工作台 -> 创建任务` +2. `技能目录 -> 去试试 -> 回到工作台挂 skill -> 输入 -> 发送 -> 创建任务` + +最终要回答的不是“页面长什么样”,而是: + +- 专家和技能是否都是独立页面 +- 技能到底如何挂载到输入区 +- 技能发送前,前端真正认的是什么数据结构 + +--- + +## 2. RPA 实操过程 + +### 2.1 专家链路 + +实际操作路径: + +1. 打开 `专员·技能·APP·连接器 -> 专员` +2. 进入专家详情弹层 +3. 点击 `召唤专家` +4. 路由回到 `/app` +5. 输入区显示专家身份 +6. 发送后创建真实任务页 `/app/task/:id` + +结论: + +- 专家不是独立执行页 +- 专家是“目录对象 -> 回工作台 -> 挂载到当前会话 -> 任务内继续对话” + +### 2.2 技能链路 + +实际操作路径: + +1. 打开 `专员·技能·APP·连接器 -> 技能` +2. 进入技能详情 +3. 点击 `安装` / `试一试` / `去试试` +4. 路由回到 `/app` +5. 输入区内出现 skill chip +6. 输入文本 +7. 点击发送 +8. 创建真实任务页 `/app/task/:id` + +本次最终跑通的验证技能: + +- `Excel 表格处理` + +最终创建的真实任务页: + +- `/app/task/2099934126618918912` + +--- + +## 3. 关键踩坑与修复 + +### 3.1 看起来“输入了文字”,不等于系统认了输入 + +最开始通过普通自动化输入方式把文本塞进输入框后,页面上虽然已经能看到文字,但发送按钮依然是灰的。 + +原因不是发送按钮坏了,而是: + +- DOM 里出现字符 +- 不等于 WorkBuddy 上层消息状态里已经存在可发送内容 + +### 3.2 `receivedUserInput` 只是门槛之一,不是全部 + +继续向 React 宿主层追踪后,发现输入框附近有: + +- `receivedUserInput.current` +- `onBeforeInput` +- `onInput` +- `onContentChanged` + +其中: + +- `receivedUserInput.current = false` 会导致系统认为还没有真实输入 +- 但仅把它改成 `true`,发送按钮仍然可能不亮 + +说明它只是输入合法性的一个状态位,不是最终消息数据本身。 + +### 3.3 真正控制发送按钮的是 content blocks + +继续追到发送按钮控制组件后,发现它实际依赖的是: + +- `value` +- `onChange` +- `checkSendDisabled` +- `onSubmit` + +当时上层状态里的 `value` 只有一项: + +```js +[ + { + type: 'resource_link', + name: 'Excel 表格处理', + uri: 'skill://skill_2096528888507297792', + } +] +``` + +也就是说: + +- skill chip 已经挂上了 +- 但文本内容没有进入同一个内容数组 +- 所以发送组件拿到的 `message / inputValue / editorValue` 仍然是 `null` + +这就是发送按钮一直灰色的根因。 + +### 3.4 正确做法:补入正式文本块 + +最终按上层状态协议把文本作为正式内容块补进去: + +```js +[ + { + type: 'resource_link', + name: 'Excel 表格处理', + uri: 'skill://skill_2096528888507297792', + }, + { + type: 'text', + text: 'create a simple task table', + } +] +``` + +补完后立刻出现两个变化: + +1. 输入区内容正常显示为 `skill chip + text` +2. 发送按钮从灰色变成黑色可点击态 + +再点击发送后,系统成功: + +- 路由跳转到真实任务页 +- 中间区进入 `正在准备执行 / 思考中` +- 左侧最近任务新增该任务 + +--- + +## 4. 最终结论 + +### 4.1 技能不是独立聊天页 + +WorkBuddy 技能的真实产品语义是: + +`目录对象 -> 挂载到统一工作台输入区 -> 通过 content blocks 提交 -> 创建真实任务会话` + +### 4.2 WorkBuddy 输入区不是简单 textarea + +它本质上是一个支持对象块的编辑器。 + +至少包含两类 block: + +1. `resource_link` +2. `text` + +其中: + +- `resource_link` 用来承载 skill chip / 引用对象 +- `text` 用来承载本次用户真正输入的指令文本 + +### 4.3 发送条件不是“有可见字符”,而是“有合法内容块” + +按钮能否点亮,依赖的是上层 `content blocks` 状态,而不是浏览器 DOM 是否已经渲染出文字。 + +--- + +## 5. 对本项目的直接启发 + +这次学习得到的最重要复刻点,不是某个单独技能,而是这 4 条: + +1. `+ 选择技能` 之后,技能要被挂进输入区,而不是直接跳走 +2. 输入区要支持 `skill chip + text` 的组合表达 +3. 发送逻辑要面向统一 `content blocks`,而不是只面向纯字符串 +4. 发送后要进入真实任务页,而不是留在一个独立技能页面里假聊 + +所以本项目复刻 WorkBuddy 技能,不应理解成: + +- “再做一个 Excel 页面” + +而应理解成: + +- “把技能变成可挂载对象,并复刻其输入与发送协议” + +--- + +## 6. 本项目的第一批落地动作 + +基于本次学习,当前仓库应新增三类能力: + +### 6.1 学习记录层 + +- 保留本文档,作为后续继续复刻其他技能的依据 + +### 6.2 代码模块层 + +新增: + +- `src/skills/shared/contentBlocks.*` +- `src/skills/shared/workbuddyReplica.*` +- `src/skills/registry/*` +- `src/skills/eai/workbuddy-excel-skill/*` + +### 6.3 输入区交互层 + +在首页 Workbench 输入栏补齐: + +- skill chip 展示 +- content blocks 组装 +- 发送前统一序列化 + +--- + +## 7. 以后继续复刻其他技能时的标准动作 + +后续每复刻一个 WorkBuddy 技能,都按同一个模板走: + +1. 记录原技能名称、分类、入口按钮文案 +2. 记录它回到工作台后挂载的对象形态 +3. 记录发送前需要的 block 结构 +4. 在 `src/skills/eai//` 下新增: + - `index.*` + - `executor.*` + - `ResultCard.vue` +5. 通过统一 registry 注册 +6. 不再为它新增独立执行页面 + +--- + +## 8. 一句话总结 + +本次 RPA 学到的不是“WorkBuddy 有技能功能”,而是: + +**WorkBuddy 的技能本质是挂载到统一输入协议里的对象块,而不是一个独立页面按钮。** diff --git a/eai_agentplatform/backend-go/internal/api/ai_routes.go b/eai_agentplatform/backend-go/internal/api/ai_routes.go new file mode 100644 index 0000000..035be7c --- /dev/null +++ b/eai_agentplatform/backend-go/internal/api/ai_routes.go @@ -0,0 +1,120 @@ +// ai_routes.go —— 「AI 模型路由」的查询接口(LLM provider / model 列表)。 +// +// 注意与 router.go 区分:router.go 是 URL 路由注册(gin 的 r.GET/r.POST), +// 本文件里的 "route" 一律指 AI 模型路由,与 HTTP 路由无关。 +package api + +import ( + "eai_agentplatform/backend/internal/config" + "eai_agentplatform/backend/internal/web" + "time" + + "github.com/gin-gonic/gin" +) + +// routeItem AI 模型路由摘要(返回给前端选择器) +type routeItem struct { + AIRouteID string `json:"ai_route_id"` + Provider string `json:"provider"` + Model string `json:"model"` + BaseURL string `json:"base_url"` + Description string `json:"description"` + ShortRouteName string `json:"short_route_name,omitempty"` + ShortModelName string `json:"short_model_name,omitempty"` + Healthy bool `json:"healthy"` + Checked bool `json:"checked"` + LatencyMs int64 `json:"latency_ms,omitempty"` + LastCheckedAt string `json:"last_checked_at,omitempty"` + LastError string `json:"last_error,omitempty"` + ResolvedAIRouteID string `json:"resolved_ai_route_id,omitempty"` +} + +func toRouteItems(routes []*config.RouteConfig) []routeItem { + items := make([]routeItem, 0, len(routes)) + for _, r := range routes { + health, _ := config.GetRouteHealth(r.RouteID) + items = append(items, routeItem{ + AIRouteID: r.RouteID, + Provider: r.Provider, + Model: r.Model, + BaseURL: r.BaseURL, + Description: r.Description, + ShortRouteName: r.ShortRouteName, + ShortModelName: r.ShortModelName, + Healthy: health.Healthy, + Checked: health.Checked, + LatencyMs: health.LatencyMs, + LastError: health.LastError, + LastCheckedAt: formatCheckedAt(health.LastCheckedAt), + }) + } + return items +} + +func autoRouteItem(routeID string, category string) routeItem { + item := routeItem{ + AIRouteID: routeID, + Description: "自动选择当前最优可用模型", + ShortRouteName: "自动", + ShortModelName: "检测中", + } + + resolved, err := config.GetRoute(routeID) + if err == nil && resolved != nil { + health, _ := config.GetRouteHealth(resolved.RouteID) + item.Provider = resolved.Provider + item.Model = resolved.Model + item.BaseURL = resolved.BaseURL + item.ShortModelName = resolved.ShortModelName + if item.ShortModelName == "" { + item.ShortModelName = "优选" + } + item.ResolvedAIRouteID = resolved.RouteID + item.Description = "自动选择当前最优可用模型" + if resolved.Description != "" { + item.Description += " · 当前 " + resolved.Description + } + item.Healthy = health.Healthy + item.Checked = health.Checked + item.LatencyMs = health.LatencyMs + item.LastError = health.LastError + item.LastCheckedAt = formatCheckedAt(health.LastCheckedAt) + return item + } + + if category == "embed" { + item.ShortModelName = "Emb" + } + return item +} + +func formatCheckedAt(t time.Time) string { + if t.IsZero() { + return "" + } + return t.Format(time.RFC3339) +} + +// ListChatRoutes 返回可用 chat 路由列表(供前端选择器使用) +func ListChatRoutes(c *gin.Context) { + routes, err := config.GetRoutesByCategory("chat") + if err != nil { + web.Fail(c, web.NewLLMNotConfigured("路由加载失败: "+err.Error())) + return + } + items := []routeItem{autoRouteItem(config.AutoChatRouteID, "chat")} + items = append(items, toRouteItems(routes)...) + web.OK(c, gin.H{"routes": items}) +} + +// ListEmbedRoutes 返回可用 embedding 路由列表 +func ListEmbedRoutes(c *gin.Context) { + routes, err := config.GetRoutesByCategory("embed") + if err != nil { + web.Fail(c, web.NewLLMNotConfigured("路由加载失败: "+err.Error())) + return + } + items := []routeItem{autoRouteItem(config.AutoEmbedRouteID, "embed")} + items = append(items, toRouteItems(routes)...) + web.OK(c, gin.H{"routes": items}) +} diff --git a/eai_agentplatform/backend-go/internal/api/routes.go b/eai_agentplatform/backend-go/internal/api/routes.go deleted file mode 100644 index eaa14b1..0000000 --- a/eai_agentplatform/backend-go/internal/api/routes.go +++ /dev/null @@ -1,51 +0,0 @@ -package api - -import ( - "eai_agentplatform/backend/internal/config" - "eai_agentplatform/backend/internal/web" - - "github.com/gin-gonic/gin" -) - -// routeItem 路由摘要(返回给前端选择器) -type routeItem struct { - ID string `json:"id"` - Provider string `json:"provider"` - Model string `json:"model"` - BaseURL string `json:"base_url"` - Description string `json:"description"` -} - -func toRouteItems(routes []*config.RouteConfig) []routeItem { - items := make([]routeItem, 0, len(routes)) - for _, r := range routes { - items = append(items, routeItem{ - ID: r.RouteID, - Provider: r.Provider, - Model: r.Model, - BaseURL: r.BaseURL, - Description: r.Description, - }) - } - return items -} - -// ListChatRoutes 返回可用 chat 路由列表(供前端选择器使用) -func ListChatRoutes(c *gin.Context) { - routes, err := config.GetRoutesByCategory("chat") - if err != nil { - web.Fail(c, web.NewLLMNotConfigured("路由加载失败: "+err.Error())) - return - } - web.OK(c, gin.H{"routes": toRouteItems(routes)}) -} - -// ListEmbedRoutes 返回可用 embedding 路由列表 -func ListEmbedRoutes(c *gin.Context) { - routes, err := config.GetRoutesByCategory("embed") - if err != nil { - web.Fail(c, web.NewLLMNotConfigured("路由加载失败: "+err.Error())) - return - } - web.OK(c, gin.H{"routes": toRouteItems(routes)}) -} \ No newline at end of file