PMFlow/backend/app/services/cognitive_conflict.py

474 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Cognitive Conflict Detection & Resolution Service - 认知冲突检测与解决服务
核心功能:
1. 自动检测团队隐性认知差异
2. 识别定义不一致(如"留存"vs"DAU")
3. 检测目标冲突(产品说X,开发实现Y)
4. 主动推送对齐提醒
5. 异步 1v1 认知对齐
"""
import asyncio
import json
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy import text
from ..models import (
User, Project, TruthNode, Task,
CognitiveConflict, ProjectDomain
)
from .llm import LLMService
class CognitiveConflictService:
"""认知冲突检测与解决服务"""
def __init__(self, db: AsyncSession):
self.db = db
self.llm = LLMService()
async def detect_charter_conflicts(
self,
project_id: int,
tenant_id: int = 1
) -> List[Dict[str, Any]]:
"""
检测项目宪章中的潜在冲突
扫描:
1. 宪章中的成功指标定义是否清晰
2. 是否有模糊的目标描述
3. 是否有相互冲突的约束
"""
# 获取项目宪章
result = await self.db.execute(
select(TruthNode).where(
TruthNode.project_id == project_id,
TruthNode.node_type == 'charter',
TruthNode.tenant_id == tenant_id
)
)
charter = result.scalar_one_or_none()
if not charter:
return []
# AI 分析宪章内容
conflicts = await self._analyze_charter_for_conflicts(
charter.content,
tenant_id=tenant_id,
)
# 保存检测到的冲突
for conflict_data in conflicts:
await self._create_conflict_record(
truth_node_id=charter.id,
conflict_type=conflict_data['type'],
description=conflict_data['description'],
severity=conflict_data['severity'],
suggested_resolution=conflict_data['suggested_resolution'],
tenant_id=tenant_id
)
return conflicts
async def detect_task_charter_mismatch(
self,
task: Task,
charter_content: str,
tenant_id: int = 1
) -> Optional[Dict[str, Any]]:
"""
检测任务与宪章的一致性
检查:
1. 任务描述是否与宪章目标一致
2. 技术选型是否符合约束
3. 是否偏离项目方向
"""
prompt = f"""检查以下任务是否符合项目宪章:
宪章内容:
{charter_content}
任务信息:
标题:{task.title}
描述:{task.description}
优先级:{task.priority}
预计工时:{task.estimated_hours} 小时
请判断:
1. 任务是否与宪章目标一致?
2. 是否有潜在的偏离?
3. 是否存在隐性冲突?
以 JSON 格式返回:
{{
"is_aligned": boolean,
"conflict_type": "目标不一致/技术约束冲突/优先级错配",
"description": "冲突描述",
"severity": "high/medium/low",
"suggestion": "建议调整"
}}
如果任务与宪章一致,is_aligned 设为 true,conflict_type 为 null。"""
try:
response = await self.llm.generate(
prompt,
db=self.db,
tenant_id=tenant_id,
project_id=task.project_id if getattr(task, "project_id", None) is not None else None,
)
response = response.strip()
if response.startswith('```'):
response = response.split('```')[1]
if response.startswith('json'):
response = response[4:]
result = json.loads(response.strip())
if not result.get('is_aligned', True):
# 创建冲突记录
await self._create_conflict_record(
truth_node_id=task.truth_node_id,
conflict_type=result.get('conflict_type', 'unknown'),
description=result.get('description', ''),
severity=result.get('severity', 'medium'),
suggested_resolution=result.get('suggestion', ''),
related_task_id=task.id,
tenant_id=tenant_id
)
return result
return None
except Exception as e:
print(f"[CognitiveConflict] Task mismatch detection failed: {e}")
return None
async def detect_user_definition_conflicts(
self,
project_id: int,
tenant_id: int = 1
) -> List[Dict[str, Any]]:
"""
检测用户定义冲突
例如:
- 产品在宪章中写"用户留存提升10%"
- 开发在实现"DAU提升10%"
- 双方都没有争论,但目标不一致
"""
# 获取项目的所有宪章和任务
charters_result = await self.db.execute(
select(TruthNode).where(
TruthNode.project_id == project_id,
TruthNode.node_type == 'charter',
TruthNode.tenant_id == tenant_id
)
)
charters = charters_result.scalars().all()
tasks_result = await self.db.execute(
select(Task).where(
Task.project_id == project_id,
Task.tenant_id == tenant_id
)
)
tasks = tasks_result.scalars().all()
# 构建所有定义的上下文
definitions = []
for charter in charters:
definitions.append({
'source_type': 'charter',
'source_id': charter.id,
'content': charter.content
})
for task in tasks:
definitions.append({
'source_type': 'task',
'source_id': task.id,
'content': f"{task.title}: {task.description}"
})
if not definitions:
return []
# AI 检测定义冲突
prompt = f"""分析以下项目定义中是否存在隐性认知冲突:
{json.dumps(definitions, ensure_ascii=False, indent=2)}
请查找:
1. 相同概念的不同表述(如"留存"vs"DAU")
2. 相矛盾的目标(如"降低成本"vs"增加功能")
3. 不一致的指标定义
以 JSON 格式返回:
[
{{
"conflict_type": "定义不一致",
"description": "具体描述冲突",
"involved_sources": ["charter:1", "task:2"],
"severity": "high/medium/low",
"suggested_alignment": "建议的对齐方案"
}}
]
如果没有发现冲突,返回空数组。"""
try:
response = await self.llm.generate(
prompt,
db=self.db,
tenant_id=tenant_id,
project_id=project_id,
)
response = response.strip()
if response.startswith('```'):
response = response.split('```')[1]
if response.startswith('json'):
response = response[4:]
conflicts = json.loads(response.strip())
# 保存检测到的冲突
for conflict in conflicts:
await self._create_conflict_record(
truth_node_id=int(conflict['involved_sources'][0].split(':')[1]),
conflict_type=conflict['conflict_type'],
description=conflict['description'],
severity=conflict['severity'],
suggested_resolution=conflict.get('suggested_alignment', ''),
tenant_id=tenant_id
)
return conflicts
except Exception as e:
print(f"[CognitiveConflict] Definition conflict detection failed: {e}")
return []
async def propose_alignment_resolution(
self,
conflict_id: int,
tenant_id: int = 1
) -> Dict[str, Any]:
"""
提议认知冲突解决方案
为冲突双方生成对齐方案:
1. 分析冲突根因
2. 提出妥协方案
3. 生成可执行的对齐计划
"""
# 获取冲突记录
result = await self.db.execute(
select(CognitiveConflict).where(
CognitiveConflict.id == conflict_id,
CognitiveConflict.tenant_id == tenant_id
)
)
conflict = result.scalar_one_or_none()
if not conflict:
raise ValueError(f"Conflict {conflict_id} not found")
# AI 生成解决方案
prompt = f"""为以下认知冲突提供解决方案:
冲突类型:{conflict.conflict_type}
描述:{conflict.description}
请提供:
1. 冲突根因分析
2. 双方都能接受的妥协方案
3. 具体的对齐步骤
以 JSON 格式返回:
{{
"root_cause": "根本原因",
"resolution_plan": ["步骤1", "步骤2"],
"compromise": "妥协方案",
"expected_outcome": "预期结果"
}}"""
try:
response = await self.llm.generate(
prompt,
db=self.db,
tenant_id=tenant_id,
)
response = response.strip()
if response.startswith('```'):
response = response.split('```')[1]
if response.startswith('json'):
response = response[4:]
resolution = json.loads(response.strip())
# 更新冲突状态
conflict.status = 'resolution_proposed'
conflict.description += f"\n\nAI 建议方案:{resolution.get('compromise', '')}"
await self.db.commit()
return resolution
except Exception as e:
print(f"[CognitiveConflict] Resolution proposal failed: {e}")
return {}
async def trigger_async_alignment(
self,
conflict_id: int,
user1_id: int,
user2_id: int,
tenant_id: int = 1
) -> Dict[str, Any]:
"""
触发异步 1v1 认知对齐
为冲突双方创建独立的对齐任务:
1. 发送对齐邀请
2. 提供背景信息
3. 收集双方观点
4. AI 生成共识方案
"""
# 获取用户信息
result1 = await self.db.execute(
select(User).where(User.id == user1_id)
)
user1 = result1.scalar_one_or_none()
result2 = await self.db.execute(
select(User).where(User.id == user2_id)
)
user2 = result2.scalar_one_or_none()
if not user1 or not user2:
raise ValueError("Users not found")
# 获取冲突详情
result = await self.db.execute(
select(CognitiveConflict).where(
CognitiveConflict.id == conflict_id,
CognitiveConflict.tenant_id == tenant_id
)
)
conflict = result.scalar_one_or_none()
# TODO: 实际实现需要:
# 1. 发送飞书消息/邮件通知双方
# 2. 创建对齐任务
# 3. 记录对齐过程
return {
'alignment_session_id': f"align_{conflict_id}",
'user1': user1.username,
'user2': user2.username,
'conflict': conflict.conflict_type,
'status': 'initiated'
}
async def _create_conflict_record(
self,
truth_node_id: int,
conflict_type: str,
description: str,
severity: str,
suggested_resolution: str = "",
related_task_id: Optional[int] = None,
tenant_id: int = 1
):
"""创建认知冲突记录"""
from sqlalchemy import text
next_conflict_id = (await self.db.execute(text("SELECT COALESCE(MAX(id),0)+1 FROM cognitive_conflicts"))).scalar() or 1
conflict = CognitiveConflict(
id=next_conflict_id,
truth_node_id=truth_node_id,
conflict_type=conflict_type,
description=description,
involved_user_ids=json.dumps([]),
status='detected',
tenant_id=tenant_id
)
self.db.add(conflict)
await self.db.commit()
async def _analyze_charter_for_conflicts(
self,
charter_content: str,
tenant_id: int,
) -> List[Dict[str, Any]]:
"""AI 分析宪章内容中的冲突"""
prompt = f"""分析以下项目宪章中是否存在潜在冲突或问题:
{charter_content}
请检查:
1. 目标是否模糊或相互矛盾?
2. 约束条件是否现实?
3. 成功指标是否可衡量?
4. 是否遗漏重要方面?
以 JSON 格式返回:
[
{{
"type": "目标模糊/约束冲突/指标不可测量",
"description": "具体问题描述",
"severity": "high/medium/low",
"suggested_resolution": "建议的改进方案"
}}
"""
try:
response = await self.llm.generate(
prompt,
db=self.db,
tenant_id=tenant_id,
)
response = response.strip()
if response.startswith('```'):
response = response.split('```')[1]
if response.startswith('json'):
response = response[4:]
return json.loads(response.strip())
except:
return []
async def get_detected_conflicts(
self,
tenant_id: int = 1
) -> List[Dict[str, Any]]:
"""获取所有检测到的冲突"""
result = await self.db.execute(
select(CognitiveConflict).where(
CognitiveConflict.tenant_id == tenant_id,
CognitiveConflict.status == 'detected'
)
)
conflicts = result.scalars().all()
return [
{
'id': str(c.id),
'type': c.conflict_type,
'description': c.description,
'severity': 'medium' if 'high' not in c.description.lower() else 'high',
'truth_node_id': str(c.truth_node_id)
}
for c in conflicts
]
# 全局服务实例
def get_cognitive_conflict_service(db: AsyncSession) -> CognitiveConflictService:
"""获取认知冲突服务实例"""
return CognitiveConflictService(db)