docs: 工作台设计稿收入 docs 体系,routes.go 更名 ai_routes.go

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 <noreply@anthropic.com>
This commit is contained in:
eaiadmin
2026-09-17 19:26:26 +08:00
co-authored by Claude Code
parent 24cac4de6e
commit fa6c26ea41
16 changed files with 5735 additions and 55 deletions
+14 -1
View File
@@ -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` 为准
@@ -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. 一句话收口
建议把平台对象统一定义为:
**“带角色卡的角色对象”**
其中:
- 工具 = 单能力角色
- 专员 = 可调用工具的编排角色
- 本体 = 这些角色、动作、对象、产物之间的轻量语义骨架
@@ -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 为统一运行现场的数字员工与工业智能体平台。**
@@ -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并存,但统一运行、统一治理、统一沉淀。**
@@ -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 必须不同。** 只要这一条不成立,专员就还只是装饰。
@@ -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<string, TaskSession>
mountedObjectsByTaskId: Record<string, TaskObjectInstance[]>
messagesByTaskId: Record<string, TaskMessage[]>
runsByTaskId: Record<string, ObjectRun[]>
artifactsByTaskId: Record<string, Artifact[]>
focusedObjectInstanceIdByTaskId: Record<string, string>
panelStateByTaskId: Record<string, { activeTab: 'workflow' | 'artifacts' }>
}
```
关键说明:
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. 最终一句话
这个平台最终不应该再被理解为:
`专员页 + 工具页 + 若干配置页`
而应该被理解为:
`一个数字员工工作台 + 一套对象目录 + 一层对象实例模型 + 一条执行与产物链`
如果后续任何实现仍然要求用户去理解:
- 我现在在哪个工具页
- 我是不是切到了另一个专员页
- 这个页面和那条任务是什么关系
那就说明架构还没有真正完成重构。
@@ -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. 最终产品语义
最终用户感知必须收敛为:
- 我在一个工作台里
- 我当前正在处理一条任务
- 这条任务挂了某个专员
- 这条任务打开了若干工具
- 我现在聚焦在某个对象上
- 我可以启动、配置、关闭这些对象
- 我不需要理解页面切换,只需要理解任务上下文
如果界面上任何一个交互让用户重新产生:
`我是不是又跳进了另一个工具页 / 专员页`
那就说明这次改造没有做完。
@@ -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.<skill-key>`
- 用户技能:`custom.<owner-key>.<skill-key>`
示例:
- `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/<skill-key>/index.ts`
用户技能:
不以源码页面形式存在,统一由后端配置记录 + `src/skills/custom/adapters/*` 运行时适配。
这是技能的主入口。
配套合法文件只有:
- `executor.ts`
- `ResultCard.vue`
- `SettingsPanel.vue`(可选)
除此之外,不再接受任何“每个工具一个执行页”的实现方式,也不接受把用户工具和 EAI 工具混放在同一来源目录里。
@@ -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. 旧执行页源码文件已经从前端仓库移除
@@ -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. 本稿的用途
这份文档用于后续所有相关改造的判断标准:
- 评估某个页面要不要保留
- 判断某个新能力该不该新建页面
- 判断当前对象该不该在输入区可见
- 判断导航页与使用页的边界
后续如有实现与本稿冲突,以本稿为准,再逐项修订。
+9 -2
View File
@@ -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 角色与工具统一交互设计(**部分被取代**:不跳页结论已采纳,「数字技术员」对象已废弃,见文首补注) |
@@ -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 绘画、视频、音乐这些创作站能力`
而是:
`把办公技能做深,把应用市场做厚,把任务与产物体系做成真正的平台。`
这条路线更符合当前已有架构,也更符合“统一任务工作台”的产品气质。
+7 -1
View File
@@ -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 路线稿:只追办公生产力,不追视觉与音视频创作) |
@@ -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/<skill-key>/` 下新增:
- `index.*`
- `executor.*`
- `ResultCard.vue`
5. 通过统一 registry 注册
6. 不再为它新增独立执行页面
---
## 8. 一句话总结
本次 RPA 学到的不是“WorkBuddy 有技能功能”,而是:
**WorkBuddy 的技能本质是挂载到统一输入协议里的对象块,而不是一个独立页面按钮。**
@@ -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})
}
@@ -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)})
}