feat(team-communication): 团队沟通配置 — 团队角色(+agentid) + 问题类型(冒泡路径)
新增通用问题冒泡的数据模型与配置 CRUD: - models/json: pipeline_team_roles(角色+agentid,多agent区分) + pipeline_problem_types(escalation_path) - pipeline_core/init.py: _simple_crud 通用 CRUD + 6 个 create/update/delete 注册 - wwwroot/api: 6 个 dspy 端点 - scripts/load_path.py: RBAC 路径 - skills_library/all/team-communication/SKILL.md: 团队沟通技能
This commit is contained in:
parent
670e73d8e5
commit
ff02533cb6
27
json/pipeline_problem_types.json
Normal file
27
json/pipeline_problem_types.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
27
json/pipeline_team_roles.json
Normal file
27
json/pipeline_team_roles.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
87
models/pipeline_problem_types.json
Normal file
87
models/pipeline_problem_types.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
106
models/pipeline_team_roles.json
Normal file
106
models/pipeline_team_roles.json
Normal file
@ -0,0 +1,106 @@
|
||||
{
|
||||
"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'"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -297,6 +297,67 @@ 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()
|
||||
@ -325,6 +386,19 @@ 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')
|
||||
|
||||
@ -45,6 +45,23 @@ 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",
|
||||
]
|
||||
|
||||
|
||||
|
||||
66
skills_library/all/team-communication/SKILL.md
Normal file
66
skills_library/all/team-communication/SKILL.md
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
name: team-communication
|
||||
description: 团队沟通(通用问题冒泡)——问题按类型沿冒泡路径在团队角色间流转,解决即停、未解决继续冒泡、尽头由人兜底。触发:agent 发现问题、角色提问、PM 退回、故障上报、客户提问等。
|
||||
---
|
||||
|
||||
# 团队沟通(通用问题冒泡)
|
||||
|
||||
## 核心概念
|
||||
|
||||
- **团队** = 一组不同角色的 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)。
|
||||
|
||||
## 冒泡规则(核心)
|
||||
|
||||
```
|
||||
提出问题 raise → 沿路径第一个处理方开始
|
||||
↓
|
||||
处理方判断:
|
||||
解决了 → resolve(status=answered,停止冒泡,任务恢复)
|
||||
没解决 → escalate(escalation_pos+1,沿路径继续走到下一个处理方)
|
||||
↓
|
||||
路径尽头 = 最后一个处理方(通常是"人" customer,兜底)
|
||||
```
|
||||
|
||||
## 工具
|
||||
|
||||
| 工具 | 作用 |
|
||||
|---|---|
|
||||
| `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 / 客户人工介入 |
|
||||
|
||||
## 多 agent 路由规则
|
||||
|
||||
- 处理方 `agentid` 为空 = 该角色任意 agent 可处理。
|
||||
- 处理方 `agentid` 指定 = 只有该 agent 能处理(同角色其他 agent 看不到)。
|
||||
- 角色 agent 重新认领任务时,只注入「本角色/本 agent」应响应的 pending 退回意见(`get_task_qa(include_pending_for=role, include_pending_agentid=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` — 团队角色 + 问题类型定义
|
||||
5
wwwroot/api/pipeline_problem_types_create.dspy
Normal file
5
wwwroot/api/pipeline_problem_types_create.dspy
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
||||
5
wwwroot/api/pipeline_problem_types_delete.dspy
Normal file
5
wwwroot/api/pipeline_problem_types_delete.dspy
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
||||
5
wwwroot/api/pipeline_problem_types_update.dspy
Normal file
5
wwwroot/api/pipeline_problem_types_update.dspy
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
||||
5
wwwroot/api/pipeline_team_roles_create.dspy
Normal file
5
wwwroot/api/pipeline_team_roles_create.dspy
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
||||
5
wwwroot/api/pipeline_team_roles_delete.dspy
Normal file
5
wwwroot/api/pipeline_team_roles_delete.dspy
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
||||
5
wwwroot/api/pipeline_team_roles_update.dspy
Normal file
5
wwwroot/api/pipeline_team_roles_update.dspy
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
||||
Loading…
x
Reference in New Issue
Block a user