From 17ad1698291859a6df2af1f05dd57ab9b66b6149 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sun, 16 Aug 2026 22:08:01 +0800 Subject: [PATCH] =?UTF-8?q?refactor(team-communication):=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E9=85=8D=E7=BD=AE=E8=A1=A8=EF=BC=8C=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20skill?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 团队角色/问题类型/冒泡路径不再用 DB 表 + CRUD,改为 team-communication skill (产线默认规范,项目可覆盖): - 删 pipeline_team_roles/pipeline_problem_types 两表 model+json+api dspy - 回退 pipeline_core/init.py CRUD 函数 + load_path.py 路段 - 重写 team-communication SKILL.md 为分层可覆盖规范文档 --- json/pipeline_problem_types.json | 27 ----- json/pipeline_team_roles.json | 27 ----- models/pipeline_problem_types.json | 87 -------------- models/pipeline_team_roles.json | 106 ------------------ pipeline_core/init.py | 74 ------------ scripts/load_path.py | 17 --- .../all/team-communication/SKILL.md | 105 +++++++++-------- .../api/pipeline_problem_types_create.dspy | 5 - .../api/pipeline_problem_types_delete.dspy | 5 - .../api/pipeline_problem_types_update.dspy | 5 - wwwroot/api/pipeline_team_roles_create.dspy | 5 - wwwroot/api/pipeline_team_roles_delete.dspy | 5 - wwwroot/api/pipeline_team_roles_update.dspy | 5 - 13 files changed, 56 insertions(+), 417 deletions(-) delete mode 100644 json/pipeline_problem_types.json delete mode 100644 json/pipeline_team_roles.json delete mode 100644 models/pipeline_problem_types.json delete mode 100644 models/pipeline_team_roles.json delete mode 100644 wwwroot/api/pipeline_problem_types_create.dspy delete mode 100644 wwwroot/api/pipeline_problem_types_delete.dspy delete mode 100644 wwwroot/api/pipeline_problem_types_update.dspy delete mode 100644 wwwroot/api/pipeline_team_roles_create.dspy delete mode 100644 wwwroot/api/pipeline_team_roles_delete.dspy delete mode 100644 wwwroot/api/pipeline_team_roles_update.dspy diff --git a/json/pipeline_problem_types.json b/json/pipeline_problem_types.json deleted file mode 100644 index 75041f1..0000000 --- a/json/pipeline_problem_types.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "tblname": "pipeline_problem_types", - "title": "问题类型", - "params": { - "sortby": "name", - "browserfields": { - "exclouded": ["id", "description", "escalation_path"], - "cwidth": {} - }, - "editexclouded": [ - "id", "created_at" - ], - "editable": { - "new_data_url": "{{entire_url('../api/pipeline_problem_types_create.dspy')}}", - "update_data_url": "{{entire_url('../api/pipeline_problem_types_update.dspy')}}", - "delete_data_url": "{{entire_url('../api/pipeline_problem_types_delete.dspy')}}" - }, - "confidential_fields": [], - "subtables": [ - { - "field": "pipeline_id", - "title": "所属产线", - "subtable": "pipelines" - } - ] - } -} diff --git a/json/pipeline_team_roles.json b/json/pipeline_team_roles.json deleted file mode 100644 index 18b3de9..0000000 --- a/json/pipeline_team_roles.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "tblname": "pipeline_team_roles", - "title": "团队角色", - "params": { - "sortby": "role_name", - "browserfields": { - "exclouded": ["id", "description"], - "cwidth": {} - }, - "editexclouded": [ - "id", "created_at" - ], - "editable": { - "new_data_url": "{{entire_url('../api/pipeline_team_roles_create.dspy')}}", - "update_data_url": "{{entire_url('../api/pipeline_team_roles_update.dspy')}}", - "delete_data_url": "{{entire_url('../api/pipeline_team_roles_delete.dspy')}}" - }, - "confidential_fields": [], - "subtables": [ - { - "field": "pipeline_id", - "title": "所属产线", - "subtable": "pipelines" - } - ] - } -} diff --git a/models/pipeline_problem_types.json b/models/pipeline_problem_types.json deleted file mode 100644 index a4e30f3..0000000 --- a/models/pipeline_problem_types.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "summary": [ - { - "name": "pipeline_problem_types", - "title": "问题类型表", - "primary": [ - "id" - ] - } - ], - "fields": [ - { - "name": "id", - "title": "id", - "type": "str", - "length": 32, - "nullable": "no", - "uitype": "hidden" - }, - { - "name": "pipeline_id", - "title": "所属产线", - "type": "str", - "length": 32, - "nullable": "no", - "uitype": "select" - }, - { - "name": "name", - "title": "问题类型标识", - "type": "str", - "length": 50, - "nullable": "no", - "uitype": "text" - }, - { - "name": "title", - "title": "显示名", - "type": "str", - "length": 100, - "uitype": "text" - }, - { - "name": "description", - "title": "说明", - "type": "text", - "uitype": "textarea" - }, - { - "name": "escalation_path", - "title": "冒泡路径(JSON角色数组,如[\"main_agent\",\"customer\"])", - "type": "text", - "uitype": "textarea" - }, - { - "name": "created_at", - "title": "创建时间", - "type": "timestamp", - "uitype": "timestamp" - } - ], - "indexes": [ - { - "name": "idx_problemtype_pipeline", - "idxtype": "index", - "idxfields": [ - "pipeline_id" - ] - }, - { - "name": "idx_problemtype_name", - "idxtype": "unique", - "idxfields": [ - "pipeline_id", - "name" - ] - } - ], - "codes": [ - { - "field": "pipeline_id", - "table": "pipelines", - "valuefield": "id", - "textfield": "name" - } - ] -} diff --git a/models/pipeline_team_roles.json b/models/pipeline_team_roles.json deleted file mode 100644 index fdcc020..0000000 --- a/models/pipeline_team_roles.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "summary": [ - { - "name": "pipeline_team_roles", - "title": "团队角色表", - "primary": [ - "id" - ] - } - ], - "fields": [ - { - "name": "id", - "title": "id", - "type": "str", - "length": 32, - "nullable": "no", - "uitype": "hidden" - }, - { - "name": "pipeline_id", - "title": "所属产线", - "type": "str", - "length": 32, - "nullable": "no", - "uitype": "select" - }, - { - "name": "role_name", - "title": "角色标识", - "type": "str", - "length": 50, - "nullable": "no", - "uitype": "text" - }, - { - "name": "agentid", - "title": "Agent标识(同角色多agent区分,人可空)", - "type": "str", - "length": 64, - "nullable": "yes", - "uitype": "text" - }, - { - "name": "role_type", - "title": "角色类型", - "type": "str", - "length": 20, - "nullable": "no", - "default": "agent", - "uitype": "select" - }, - { - "name": "display_name", - "title": "显示名", - "type": "str", - "length": 100, - "uitype": "text" - }, - { - "name": "description", - "title": "职责说明", - "type": "text", - "uitype": "textarea" - }, - { - "name": "created_at", - "title": "创建时间", - "type": "timestamp", - "uitype": "timestamp" - } - ], - "indexes": [ - { - "name": "idx_teamrole_pipeline", - "idxtype": "index", - "idxfields": [ - "pipeline_id" - ] - }, - { - "name": "idx_teamrole_name", - "idxtype": "unique", - "idxfields": [ - "pipeline_id", - "role_name", - "agentid" - ] - } - ], - "codes": [ - { - "field": "pipeline_id", - "table": "pipelines", - "valuefield": "id", - "textfield": "name" - }, - { - "field": "role_type", - "table": "appcodes_kv", - "valuefield": "k", - "textfield": "v", - "cond": "parentid='team_role_type'" - } - ] -} diff --git a/pipeline_core/init.py b/pipeline_core/init.py index ac39972..74c9550 100644 --- a/pipeline_core/init.py +++ b/pipeline_core/init.py @@ -297,67 +297,6 @@ async def delete_llm(params_kw): return json.dumps(result, ensure_ascii=False, default=str) -async def _simple_crud(table, op, params_kw): - """团队沟通配置表通用 CRUD(table: 表名, op: create/update/delete)。""" - result = {'success': False, 'message': ''} - try: - db, dbname = _get_sor() - async with db.sqlorContext(dbname) as sor: - data = params_kw.copy() - data.pop('page', None) - data.pop('rows', None) - data.pop('data_filter', None) - if op == 'create': - data['id'] = getID() - await sor.C(table, data) - result['id'] = data['id'] - result['success'] = True - result['message'] = '创建成功' - elif op == 'update': - rid = data.pop('id', None) - if not rid: - result['message'] = '缺少id' - else: - await sor.U(table, {**data, 'id': rid}) - result['success'] = True - result['message'] = '更新成功' - else: - rid = params_kw.get('id') - if not rid: - result['message'] = '缺少id' - else: - await sor.D(table, {'id': rid}) - result['success'] = True - result['message'] = '删除成功' - except Exception as e: - result['message'] = str(e) - return json.dumps(result, ensure_ascii=False, default=str) - - -async def create_pipeline_team_role(params_kw): - return await _simple_crud('pipeline_team_roles', 'create', params_kw) - - -async def update_pipeline_team_role(params_kw): - return await _simple_crud('pipeline_team_roles', 'update', params_kw) - - -async def delete_pipeline_team_role(params_kw): - return await _simple_crud('pipeline_team_roles', 'delete', params_kw) - - -async def create_pipeline_problem_type(params_kw): - return await _simple_crud('pipeline_problem_types', 'create', params_kw) - - -async def update_pipeline_problem_type(params_kw): - return await _simple_crud('pipeline_problem_types', 'update', params_kw) - - -async def delete_pipeline_problem_type(params_kw): - return await _simple_crud('pipeline_problem_types', 'delete', params_kw) - - def load_pipeline_core(): """注册函数到 ServerEnv""" env = ServerEnv() @@ -386,19 +325,6 @@ def load_pipeline_core(): env.update_pipeline_versions = update_pipeline_version env.delete_pipeline_version = delete_pipeline_version env.delete_pipeline_versions = delete_pipeline_version - # Team communication (团队沟通:团队角色 + 问题类型) - env.create_pipeline_team_role = create_pipeline_team_role - env.create_pipeline_team_roles = create_pipeline_team_role - env.update_pipeline_team_role = update_pipeline_team_role - env.update_pipeline_team_roles = update_pipeline_team_role - env.delete_pipeline_team_role = delete_pipeline_team_role - env.delete_pipeline_team_roles = delete_pipeline_team_role - env.create_pipeline_problem_type = create_pipeline_problem_type - env.create_pipeline_problem_types = create_pipeline_problem_type - env.update_pipeline_problem_type = update_pipeline_problem_type - env.update_pipeline_problem_types = update_pipeline_problem_type - env.delete_pipeline_problem_type = delete_pipeline_problem_type - env.delete_pipeline_problem_types = delete_pipeline_problem_type # Publish env.publish_pipeline = publish_pipeline debug(f'[{MODULE_NAME}] module loaded') diff --git a/scripts/load_path.py b/scripts/load_path.py index 9538a6e..d2c4241 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -45,23 +45,6 @@ PATHS_LOGINED = [ f"/{MOD}/api/pipelines_create.dspy", f"/{MOD}/api/pipelines_update.dspy", f"/{MOD}/api/pipelines_delete.dspy", - # Team communication (团队沟通:团队角色 + 问题类型 CRUD) - f"/{MOD}/pipeline_team_roles/index.ui", - f"/{MOD}/pipeline_team_roles/get_pipeline_team_roles.dspy", - f"/{MOD}/pipeline_team_roles/add_pipeline_team_roles.dspy", - f"/{MOD}/pipeline_team_roles/update_pipeline_team_roles.dspy", - f"/{MOD}/pipeline_team_roles/delete_pipeline_team_roles.dspy", - f"/{MOD}/pipeline_problem_types/index.ui", - f"/{MOD}/pipeline_problem_types/get_pipeline_problem_types.dspy", - f"/{MOD}/pipeline_problem_types/add_pipeline_problem_types.dspy", - f"/{MOD}/pipeline_problem_types/update_pipeline_problem_types.dspy", - f"/{MOD}/pipeline_problem_types/delete_pipeline_problem_types.dspy", - f"/{MOD}/api/pipeline_team_roles_create.dspy", - f"/{MOD}/api/pipeline_team_roles_update.dspy", - f"/{MOD}/api/pipeline_team_roles_delete.dspy", - f"/{MOD}/api/pipeline_problem_types_create.dspy", - f"/{MOD}/api/pipeline_problem_types_update.dspy", - f"/{MOD}/api/pipeline_problem_types_delete.dspy", ] diff --git a/skills_library/all/team-communication/SKILL.md b/skills_library/all/team-communication/SKILL.md index f5e7a3e..b782850 100644 --- a/skills_library/all/team-communication/SKILL.md +++ b/skills_library/all/team-communication/SKILL.md @@ -1,66 +1,73 @@ --- name: team-communication -description: 团队沟通(通用问题冒泡)——问题按类型沿冒泡路径在团队角色间流转,解决即停、未解决继续冒泡、尽头由人兜底。触发:agent 发现问题、角色提问、PM 退回、故障上报、客户提问等。 +description: 团队沟通规范(问题冒泡)——定义团队角色、问题类型、冒泡路径,agent 有问题时据此处理(提问题/找自己要处理的/回答/转交)。产线定义默认规范,项目可用同名 skill 覆盖。触发:agent 发现问题、角色缺信息、PM 退回、故障上报、客户提问、待处理问题>0。 --- -# 团队沟通(通用问题冒泡) +# 团队沟通(问题冒泡)规范 -## 核心概念 +本 skill 是**规范**(团队结构 + 问题类型 + 冒泡路径)。问题操作的工具由系统固化, +agent 读本 skill 理解规范后,用工具执行。 -- **团队** = 一组不同角色的 agent + 人(`pipeline_team_roles` 表,每个成员 = role_name + agentid)。 - - 多 agent 存在:同一角色可有多个 agent,必须用 `agentid` 区分到具体处理方。 - - `role_type`:`agent`(AI agent)/ `human`(人,如客户)。 -- **问题类型**(`pipeline_problem_types`)= 一条冒泡路径 `escalation_path`(处理方序列)。 -- **冒泡路径条目**:`"role_name"`(该角色任意 agent/人)或 `{"role":"x","agentid":"y"}`(指定 agent)。 +## 一、核心模型 -## 冒泡规则(核心) +- **团队** = 一组不同角色的 agent + 人。多 agent 存在:同一角色可有多个 agent, + 处理方必须精确到 `角色 + agentid`(agentid 空 = 该角色任意 agent)。 +- **问题类型** = 一种问题 + 一条冒泡路径(处理方序列)。 +- **冒泡规则**:问题产生后从路径第一个处理方开始;处理方解决了→停(answered); + 没解决→沿路径转给下一个处理方;路径尽头通常是「人」兜底。 -``` -提出问题 raise → 沿路径第一个处理方开始 - ↓ -处理方判断: - 解决了 → resolve(status=answered,停止冒泡,任务恢复) - 没解决 → escalate(escalation_pos+1,沿路径继续走到下一个处理方) - ↓ -路径尽头 = 最后一个处理方(通常是"人" customer,兜底) -``` +## 二、团队角色(产线默认) -## 工具 +| 角色 | 类型 | 职责 | +|---|---|---| +| main_agent | agent | 用户面对话 agent,回答问题、路由到客户 | +| pm | agent | 项目经理,审核交付件、退回意见 | +| requirement | agent | 需求分析师 | +| design | agent | 系统设计师 | +| develop | agent | 开发工程师 | +| test | agent | 测试工程师 | +| deploy | agent | 部署运维 | +| customer | human | 人类客户,最终兜底 | -| 工具 | 作用 | -|---|---| -| `list_questions` | 列出「当前该我(主agent)处理」的问题(不混入退回给角色 agent 的) | -| `answer_question` | 回答/解决 → 停止冒泡,任务恢复 | -| `escalate_question` | 答不了 → 沿冒泡路径转下一个处理方(通常转客户) | -| `diagnose_project` | 「待回答问题」计数 = 当前该主 agent 处理的问题数 | - -后端引擎(`pipeline_service/communication.py`):`raise_problem` / `resolve_problem` / `escalate_problem` / `list_problems_for`。 - -## 处理流程(发现「待回答问题」> 0 时必须执行) - -1. `list_questions` 列出所有「待我处理」的 pending 问题,不要只报统计数字。 -2. 对每个问题: - - 你能解决 → `answer_question` 直接回答(任务自动恢复,冒泡停止)。 - - 你答不了 → `escalate_question` 沿冒泡路径转下一个处理方(客户),等对方回答后再闭环。 - -## SDLC 产线默认问题类型(sdlc_general) +## 三、问题类型与冒泡路径(产线默认) | 问题类型 | 冒泡路径 | 说明 | |---|---|---| -| `need_info` | `[main_agent, customer]` | 角色 agent 缺信息 → 主 agent 答 / 转客户 | -| `review_reject` | `[被退角色, pm]` | PM 退回 → 被退角色响应 / 兜回 pm | -| `fault_report` | `[main_agent, customer]` | 任务失败报障 → 主 agent / 客户人工介入 | +| need_info | main_agent → customer | 角色缺信息向上提问,主 agent 答 / 转客户 | +| review_reject | 被退角色 → pm | PM 退回,被退角色响应后复审 | +| fault_report | main_agent → customer | 任务失败报障,主 agent / 客户人工介入 | -## 多 agent 路由规则 +冒泡路径是**规范**,由 agent 读后决策「下一个转给谁」,系统不把路径存进数据。 -- 处理方 `agentid` 为空 = 该角色任意 agent 可处理。 -- 处理方 `agentid` 指定 = 只有该 agent 能处理(同角色其他 agent 看不到)。 -- 角色 agent 重新认领任务时,只注入「本角色/本 agent」应响应的 pending 退回意见(`get_task_qa(include_pending_for=role, include_pending_agentid=agentid)`)。 +## 四、工具(系统固化,产线无关) -## 相关文件 +| 工具 | 作用 | +|---|---| +| raise_problem(problem_type, question, first_handler_role, first_handler_agentid) | 提问题,显式指定首处理方 | +| list_problems_for(role, agentid) | 查「当前该我处理」的问题(确定性过滤) | +| resolve_problem(question_id, answer) | 解决 → 停止冒泡 | +| escalate_problem(question_id, next_handler_role, next_handler_agentid) | 没解决 → 显式转给下一个处理方 | -- `pipeline_service/communication.py` — 通用冒泡引擎(raise/resolve/escalate/list_for) -- `pipeline_service/questions.py` — 向后兼容层(agent_ask/answer_question/forward_question 委托 communication) -- `pipeline_service/agent_loop.py` — 角色提问(need_info)、PM 退回(review_reject)、故障(fault_report)、PM 审核通过答结 -- `pipeline_service/sdlc_ability.py` — cockpit 工具 list_questions/answer_question/escalate_question -- `pipeline-core/models/pipeline_team_roles.json` + `pipeline_problem_types.json` — 团队角色 + 问题类型定义 +cockpit 侧包装:`list_questions`(查待我处理的)、`answer_question`(回答)、 +`escalate_question`(转给客户)。 + +## 五、处理流程(agent 侧) + +1. 我发现问题 → `raise_problem`,按问题类型 + 冒泡路径指定首处理方。 +2. 我可能被指派处理问题 → `list_problems_for(我的角色, 我的 agentid)` 查待办, + 不要只报统计数字,逐条读。 +3. 我能解决 → `resolve_problem`(任务自动恢复,冒泡停止)。 +4. 我答不了 → `escalate_problem`,沿冒泡路径转给下一个处理方。 + +## 六、分层与覆盖 + +- 本 skill 是**产线级默认规范**(skills_library 模板)。 +- 项目可用**同名 team-communication skill** 放在项目 skills 目录覆盖: + 同名问题类型 → 项目覆盖;新增 → 追加;未定义 → 兜底到产线级。 +- 加载顺序:项目级 → 产线级 → 全局兜底。 + +## 七、状态与归属 + +- 状态只有 `pending`(冒泡中)/ `answered`(已解决)。 +- 归属 = `current_handler_role` + `current_handler_agentid` 两列, + 由工具维护,查询走确定性 SQL,不靠 LLM 扫全文。 diff --git a/wwwroot/api/pipeline_problem_types_create.dspy b/wwwroot/api/pipeline_problem_types_create.dspy deleted file mode 100644 index b8ef0f7..0000000 --- a/wwwroot/api/pipeline_problem_types_create.dspy +++ /dev/null @@ -1,5 +0,0 @@ -func = create_pipeline_problem_type -if func is None: - return json.dumps({'status': 'error', 'message': 'function not found'}) -result = await func(params_kw) -return result diff --git a/wwwroot/api/pipeline_problem_types_delete.dspy b/wwwroot/api/pipeline_problem_types_delete.dspy deleted file mode 100644 index d61c204..0000000 --- a/wwwroot/api/pipeline_problem_types_delete.dspy +++ /dev/null @@ -1,5 +0,0 @@ -func = delete_pipeline_problem_type -if func is None: - return json.dumps({'status': 'error', 'message': 'function not found'}) -result = await func(params_kw) -return result diff --git a/wwwroot/api/pipeline_problem_types_update.dspy b/wwwroot/api/pipeline_problem_types_update.dspy deleted file mode 100644 index 8235682..0000000 --- a/wwwroot/api/pipeline_problem_types_update.dspy +++ /dev/null @@ -1,5 +0,0 @@ -func = update_pipeline_problem_type -if func is None: - return json.dumps({'status': 'error', 'message': 'function not found'}) -result = await func(params_kw) -return result diff --git a/wwwroot/api/pipeline_team_roles_create.dspy b/wwwroot/api/pipeline_team_roles_create.dspy deleted file mode 100644 index 2d63b9c..0000000 --- a/wwwroot/api/pipeline_team_roles_create.dspy +++ /dev/null @@ -1,5 +0,0 @@ -func = create_pipeline_team_role -if func is None: - return json.dumps({'status': 'error', 'message': 'function not found'}) -result = await func(params_kw) -return result diff --git a/wwwroot/api/pipeline_team_roles_delete.dspy b/wwwroot/api/pipeline_team_roles_delete.dspy deleted file mode 100644 index 8d8f5db..0000000 --- a/wwwroot/api/pipeline_team_roles_delete.dspy +++ /dev/null @@ -1,5 +0,0 @@ -func = delete_pipeline_team_role -if func is None: - return json.dumps({'status': 'error', 'message': 'function not found'}) -result = await func(params_kw) -return result diff --git a/wwwroot/api/pipeline_team_roles_update.dspy b/wwwroot/api/pipeline_team_roles_update.dspy deleted file mode 100644 index 01192b8..0000000 --- a/wwwroot/api/pipeline_team_roles_update.dspy +++ /dev/null @@ -1,5 +0,0 @@ -func = update_pipeline_team_role -if func is None: - return json.dumps({'status': 'error', 'message': 'function not found'}) -result = await func(params_kw) -return result