Backup before system reinstall
This commit is contained in:
295
jixia_academy/core/debate_system/debates/adk_memory_debate.py
Normal file
295
jixia_academy/core/debate_system/debates/adk_memory_debate.py
Normal file
@@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫 ADK Memory Bank 论道系统
|
||||
实现带有记忆银行的八仙智能体辩论
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
from google.adk import Agent, Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.adk.memory import VertexAiMemoryBankService
|
||||
from google.adk.memory.memory_entry import MemoryEntry
|
||||
from google.genai import types
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
class BaxianMemoryManager:
|
||||
"""八仙记忆管理器"""
|
||||
|
||||
def __init__(self):
|
||||
self.memory_services: Dict[str, VertexAiMemoryBankService] = {}
|
||||
self.agents: Dict[str, Agent] = {}
|
||||
|
||||
async def initialize_baxian_agents(self):
|
||||
"""初始化八仙智能体及其记忆银行"""
|
||||
# 从环境变量获取项目ID和位置
|
||||
project_id = os.getenv('GOOGLE_CLOUD_PROJECT_ID')
|
||||
location = os.getenv('GOOGLE_CLOUD_LOCATION', 'us-central1')
|
||||
|
||||
if not project_id:
|
||||
raise ValueError("未设置 GOOGLE_CLOUD_PROJECT_ID 环境变量")
|
||||
|
||||
# 八仙角色配置
|
||||
baxian_config = {
|
||||
"铁拐李": {
|
||||
"instruction": "你是铁拐李,八仙中的逆向思维专家。你善于从批判和质疑的角度看问题,总是能发现事物的另一面。你会从你的记忆中回忆相关的逆向投资案例和失败教训。",
|
||||
"memory_context": "逆向投资案例、市场泡沫警告、风险识别经验"
|
||||
},
|
||||
"吕洞宾": {
|
||||
"instruction": "你是吕洞宾,八仙中的理性分析者。你善于平衡各方观点,用理性和逻辑来分析问题。你会从记忆中调用技术分析的成功案例和理论知识。",
|
||||
"memory_context": "技术分析理论、成功预测案例、市场趋势分析"
|
||||
},
|
||||
"何仙姑": {
|
||||
"instruction": "你是何仙姑,八仙中的风险控制专家。你总是从风险管理的角度思考问题,善于发现潜在危险。你会回忆历史上的重大风险事件。",
|
||||
"memory_context": "风险管理案例、黑天鹅事件、危机预警经验"
|
||||
},
|
||||
"张果老": {
|
||||
"instruction": "你是张果老,八仙中的历史智慧者。你善于从历史数据中寻找规律和智慧,总是能提供长期视角。你会从记忆中调用历史数据和长期趋势。",
|
||||
"memory_context": "历史市场数据、长期投资趋势、周期性规律"
|
||||
}
|
||||
}
|
||||
|
||||
# 为每个仙人创建智能体和记忆服务
|
||||
for name, config in baxian_config.items():
|
||||
# 创建记忆服务
|
||||
memory_service = VertexAiMemoryBankService(
|
||||
project=project_id,
|
||||
location=location
|
||||
)
|
||||
|
||||
# 初始化记忆内容
|
||||
await self._initialize_agent_memory(memory_service, name, config['memory_context'])
|
||||
|
||||
# 创建智能体
|
||||
agent = Agent(
|
||||
name=name,
|
||||
model="gemini-2.5-flash",
|
||||
instruction=f"{config['instruction']} 在回答时,请先从你的记忆银行中检索相关信息,然后结合当前话题给出回应。",
|
||||
memory_service=memory_service
|
||||
)
|
||||
|
||||
self.memory_services[name] = memory_service
|
||||
self.agents[name] = agent
|
||||
|
||||
print(f"✅ 已初始化 {len(self.agents)} 个八仙智能体及其记忆服务")
|
||||
|
||||
async def _initialize_agent_memory(self, memory_service: VertexAiMemoryBankService, agent_name: str, context: str):
|
||||
"""为智能体初始化记忆内容"""
|
||||
|
||||
# 根据角色添加初始记忆
|
||||
initial_memories = {
|
||||
"铁拐李": [
|
||||
"2000年互联网泡沫破裂,许多高估值科技股暴跌90%以上",
|
||||
"2008年金融危机前,房地产市场过度繁荣,逆向思维者提前撤离",
|
||||
"比特币从2万美元跌到3千美元,提醒我们任何资产都可能大幅回调",
|
||||
"巴菲特说过:别人贪婪时我恐惧,别人恐惧时我贪婪"
|
||||
],
|
||||
"吕洞宾": [
|
||||
"移动平均线交叉是经典的技术分析信号",
|
||||
"RSI指标超过70通常表示超买,低于30表示超卖",
|
||||
"支撑位和阻力位是技术分析的核心概念",
|
||||
"成功的技术分析需要结合多个指标综合判断"
|
||||
],
|
||||
"何仙姑": [
|
||||
"2008年雷曼兄弟倒闭引发全球金融危机",
|
||||
"长期资本管理公司(LTCM)的失败说明了风险管理的重要性",
|
||||
"分散投资是降低风险的基本原则",
|
||||
"黑天鹅事件虽然罕见但影响巨大,需要提前准备"
|
||||
],
|
||||
"张果老": [
|
||||
"股市存在7-10年的长期周期",
|
||||
"康德拉季耶夫长波理论描述了50-60年的经济周期",
|
||||
"历史上每次重大技术革命都带来新的投资机会",
|
||||
"长期来看,优质资产总是向上的"
|
||||
]
|
||||
}
|
||||
|
||||
memories = initial_memories.get(agent_name, [])
|
||||
for memory_text in memories:
|
||||
memory_entry = MemoryEntry(
|
||||
content=memory_text,
|
||||
metadata={
|
||||
"agent": agent_name,
|
||||
"type": "historical_knowledge",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
)
|
||||
# 注意:VertexAiMemoryBankService 的 add_memory 方法可能需要不同的参数
|
||||
# 这里假设它有一个类似的方法
|
||||
await memory_service.add_memory(memory_entry)
|
||||
|
||||
async def add_debate_memory(self, agent_name: str, content: str, topic: str):
|
||||
"""为智能体添加辩论记忆"""
|
||||
if agent_name in self.memory_services:
|
||||
memory_entry = MemoryEntry(
|
||||
content=content,
|
||||
metadata={
|
||||
"agent": agent_name,
|
||||
"type": "debate_history",
|
||||
"topic": topic,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
)
|
||||
# 注意:VertexAiMemoryBankService 的 add_memory 方法可能需要不同的参数
|
||||
# 这里假设它有一个类似的方法
|
||||
await self.memory_services[agent_name].add_memory(memory_entry)
|
||||
|
||||
async def retrieve_relevant_memories(self, agent_name: str, query: str, limit: int = 3) -> List[str]:
|
||||
"""检索智能体的相关记忆"""
|
||||
if agent_name not in self.memory_services:
|
||||
return []
|
||||
|
||||
try:
|
||||
# 注意:VertexAiMemoryBankService 的 search 方法可能需要不同的参数
|
||||
# 这里假设它有一个类似的方法
|
||||
memories = await self.memory_services[agent_name].search(query, limit=limit)
|
||||
return [memory.content for memory in memories]
|
||||
except Exception as e:
|
||||
print(f"⚠️ 记忆检索失败 ({agent_name}): {e}")
|
||||
return []
|
||||
|
||||
class MemoryEnhancedDebate:
|
||||
"""带记忆增强的辩论系统"""
|
||||
|
||||
def __init__(self):
|
||||
self.memory_manager = BaxianMemoryManager()
|
||||
self.session_service = InMemorySessionService()
|
||||
self.runners: Dict[str, Runner] = {}
|
||||
|
||||
async def initialize(self):
|
||||
"""初始化辩论系统"""
|
||||
await self.memory_manager.initialize_baxian_agents()
|
||||
|
||||
# 创建会话
|
||||
self.session = await self.session_service.create_session(
|
||||
state={},
|
||||
app_name="稷下学宫记忆增强论道系统",
|
||||
user_id="memory_debate_user"
|
||||
)
|
||||
|
||||
# 为每个智能体创建Runner
|
||||
for name, agent in self.memory_manager.agents.items():
|
||||
runner = Runner(
|
||||
app_name="稷下学宫记忆增强论道系统",
|
||||
agent=agent,
|
||||
session_service=self.session_service
|
||||
)
|
||||
self.runners[name] = runner
|
||||
|
||||
async def conduct_memory_debate(self, topic: str, participants: List[str] = None):
|
||||
"""进行带记忆的辩论"""
|
||||
if participants is None:
|
||||
participants = ["铁拐李", "吕洞宾", "何仙姑", "张果老"]
|
||||
|
||||
print(f"\n🎭 稷下学宫记忆增强论道开始...")
|
||||
print(f"📋 论道主题: {topic}")
|
||||
print(f"🎯 参与仙人: {', '.join(participants)}")
|
||||
|
||||
debate_history = []
|
||||
|
||||
for round_num in range(2): # 进行2轮辩论
|
||||
print(f"\n🔄 第 {round_num + 1} 轮论道:")
|
||||
|
||||
for participant in participants:
|
||||
if participant not in self.runners:
|
||||
continue
|
||||
|
||||
print(f"\n🗣️ {participant} 发言:")
|
||||
|
||||
# 检索相关记忆
|
||||
relevant_memories = await self.memory_manager.retrieve_relevant_memories(
|
||||
participant, topic, limit=2
|
||||
)
|
||||
|
||||
# 构建包含记忆的提示
|
||||
memory_context = ""
|
||||
if relevant_memories:
|
||||
memory_context = f"\n从你的记忆中回忆到:\n" + "\n".join([f"- {memory}" for memory in relevant_memories])
|
||||
|
||||
# 构建辩论历史上下文
|
||||
history_context = ""
|
||||
if debate_history:
|
||||
recent_history = debate_history[-3:] # 最近3条发言
|
||||
history_context = f"\n最近的论道内容:\n" + "\n".join([f"- {h}" for h in recent_history])
|
||||
|
||||
prompt = f"关于'{topic}'这个话题{memory_context}{history_context}\n\n请结合你的记忆和当前讨论,从你的角色特点出发发表观点。请控制在150字以内。"
|
||||
|
||||
# 发送消息并获取回复
|
||||
content = types.Content(role='user', parts=[types.Part(text=prompt)])
|
||||
response = self.runners[participant].run_async(
|
||||
user_id=self.session.user_id,
|
||||
session_id=self.session.id,
|
||||
new_message=content
|
||||
)
|
||||
|
||||
# 收集回复
|
||||
reply = ""
|
||||
async for event in response:
|
||||
if hasattr(event, 'content') and event.content:
|
||||
if hasattr(event.content, 'parts') and event.content.parts:
|
||||
for part in event.content.parts:
|
||||
if hasattr(part, 'text') and part.text:
|
||||
reply += str(part.text)
|
||||
|
||||
if reply.strip():
|
||||
clean_reply = reply.strip()
|
||||
print(f" {clean_reply}")
|
||||
|
||||
# 记录到辩论历史
|
||||
debate_entry = f"{participant}: {clean_reply}"
|
||||
debate_history.append(debate_entry)
|
||||
|
||||
# 添加到记忆银行
|
||||
await self.memory_manager.add_debate_memory(
|
||||
participant, clean_reply, topic
|
||||
)
|
||||
|
||||
await asyncio.sleep(1) # 避免API调用过快
|
||||
|
||||
print(f"\n🎉 记忆增强论道完成!")
|
||||
print(f"📝 本次论道共产生 {len(debate_history)} 条发言,已存储到各仙人的记忆银行中。")
|
||||
|
||||
return debate_history
|
||||
|
||||
async def close(self):
|
||||
"""关闭资源"""
|
||||
for runner in self.runners.values():
|
||||
await runner.close()
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
print("🚀 稷下学宫 ADK Memory Bank 论道系统")
|
||||
|
||||
# 检查API密钥
|
||||
api_key = os.getenv('GOOGLE_API_KEY')
|
||||
if not api_key:
|
||||
print("❌ 未找到 GOOGLE_API_KEY 环境变量")
|
||||
print("请使用: doppler run -- python src/jixia/debates/adk_memory_debate.py")
|
||||
return
|
||||
|
||||
print(f"✅ API密钥已配置")
|
||||
|
||||
# 创建并初始化辩论系统
|
||||
debate_system = MemoryEnhancedDebate()
|
||||
|
||||
try:
|
||||
await debate_system.initialize()
|
||||
|
||||
# 进行辩论
|
||||
await debate_system.conduct_memory_debate(
|
||||
topic="人工智能对投资市场的影响",
|
||||
participants=["铁拐李", "吕洞宾", "何仙姑", "张果老"]
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 运行失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
await debate_system.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
290
jixia_academy/core/debate_system/debates/baxian_debate_system.py
Normal file
290
jixia_academy/core/debate_system/debates/baxian_debate_system.py
Normal file
@@ -0,0 +1,290 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫 八仙论道系统
|
||||
实现八仙四对矛盾的对角线辩论:男女、老少、富贫、贵贱
|
||||
基于先天八卦的智慧对话系统
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
from google.adk import Agent, Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.genai import types
|
||||
import re
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
|
||||
def create_baxian_agents():
|
||||
"""创建八仙智能体 - 四对矛盾"""
|
||||
|
||||
# 男女对立:吕洞宾(男)vs 何仙姑(女)
|
||||
lu_dong_bin = Agent(
|
||||
name="吕洞宾",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是吕洞宾,八仙中的男性代表,理性分析者。你代表男性视角,善于逻辑思辨,注重理性和秩序。你的发言风格温和而深刻,总是能找到问题的核心。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
he_xian_gu = Agent(
|
||||
name="何仙姑",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是何仙姑,八仙中的女性代表,感性智慧者。你代表女性视角,善于直觉洞察,注重情感和和谐。你的发言风格柔和而犀利,总是能看到事物的另一面。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
# 老少对立:张果老(老)vs 韩湘子(少)
|
||||
zhang_guo_lao = Agent(
|
||||
name="张果老",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是张果老,八仙中的长者代表,经验智慧者。你代表老年视角,善于从历史经验出发,注重传统和稳重。你的发言风格深沉而睿智,总是能从历史中汲取教训。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
han_xiang_zi = Agent(
|
||||
name="韩湘子",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是韩湘子,八仙中的青年代表,创新思维者。你代表年轻视角,善于创新思考,注重变革和进步。你的发言风格活泼而敏锐,总是能提出新颖的观点。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
# 富贫对立:汉钟离(富)vs 蓝采和(贫)
|
||||
han_zhong_li = Agent(
|
||||
name="汉钟离",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是汉钟离,八仙中的富贵代表,资源掌控者。你代表富有阶层视角,善于从资源配置角度思考,注重效率和投资回报。你的发言风格稳重而务实,总是能看到经济利益。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
lan_cai_he = Agent(
|
||||
name="蓝采和",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是蓝采和,八仙中的贫困代表,民生关怀者。你代表普通民众视角,善于从底层角度思考,注重公平和民生。你的发言风格朴实而真诚,总是能关注到弱势群体。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
# 贵贱对立:曹国舅(贵)vs 铁拐李(贱)
|
||||
cao_guo_jiu = Agent(
|
||||
name="曹国舅",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是曹国舅,八仙中的贵族代表,权力思考者。你代表上层社会视角,善于从权力结构角度分析,注重秩序和等级。你的发言风格优雅而权威,总是能看到政治层面。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
tie_guai_li = Agent(
|
||||
name="铁拐李",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是铁拐李,八仙中的底层代表,逆向思维者。你代表社会底层视角,善于从批判角度质疑,注重真实和反叛。你的发言风格直接而犀利,总是能揭示问题本质。每次发言控制在80字以内。"
|
||||
)
|
||||
|
||||
return {
|
||||
'male_female': (lu_dong_bin, he_xian_gu),
|
||||
'old_young': (zhang_guo_lao, han_xiang_zi),
|
||||
'rich_poor': (han_zhong_li, lan_cai_he),
|
||||
'noble_humble': (cao_guo_jiu, tie_guai_li)
|
||||
}
|
||||
|
||||
@contextmanager
|
||||
def suppress_stdout():
|
||||
"""抑制标准输出"""
|
||||
with open(os.devnull, "w") as devnull:
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = devnull
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
|
||||
def clean_debug_output(text):
|
||||
"""清理调试输出"""
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
# 移除调试信息,但保留实际内容
|
||||
lines = text.split('\n')
|
||||
cleaned_lines = []
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
# 只过滤明确的调试信息,保留实际回复内容
|
||||
if any(debug_pattern in line for debug_pattern in
|
||||
['Event from', 'API_KEY', 'Both GOOGLE_API_KEY', 'Using GOOGLE_API_KEY']):
|
||||
continue
|
||||
if line and not line.startswith('DEBUG') and not line.startswith('INFO'):
|
||||
cleaned_lines.append(line)
|
||||
|
||||
result = ' '.join(cleaned_lines)
|
||||
return result if result.strip() else text.strip()
|
||||
|
||||
async def conduct_diagonal_debate(agent1, agent2, topic, perspective1, perspective2, round_num):
|
||||
"""进行对角线辩论"""
|
||||
print(f"\n🎯 第{round_num}轮对角线辩论:{agent1.name} vs {agent2.name}")
|
||||
print(f"📋 辩论视角:{perspective1} vs {perspective2}")
|
||||
|
||||
# 设置环境变量以抑制ADK调试输出
|
||||
os.environ['GRPC_VERBOSITY'] = 'ERROR'
|
||||
os.environ['GRPC_TRACE'] = ''
|
||||
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
# 创建会话服务和运行器
|
||||
session_service = InMemorySessionService()
|
||||
|
||||
# 创建会话
|
||||
session = await session_service.create_session(
|
||||
state={},
|
||||
app_name="稷下学宫八仙论道系统",
|
||||
user_id="baxian_debate_user"
|
||||
)
|
||||
|
||||
# 创建Runner实例
|
||||
runner1 = Runner(agent=agent1, session_service=session_service, app_name="稷下学宫八仙论道系统")
|
||||
runner2 = Runner(agent=agent2, session_service=session_service, app_name="稷下学宫八仙论道系统")
|
||||
|
||||
try:
|
||||
# 第一轮:agent1 发起
|
||||
prompt1 = f"请从{perspective1}的角度,对'{topic}'发表你的观点。要求:观点鲜明,论证有力,体现{perspective1}的特色。"
|
||||
|
||||
content1 = types.Content(role='user', parts=[types.Part(text=prompt1)])
|
||||
response1 = runner1.run_async(
|
||||
user_id=session.user_id,
|
||||
session_id=session.id,
|
||||
new_message=content1
|
||||
)
|
||||
|
||||
# 提取回复内容
|
||||
agent1_reply = ""
|
||||
async for event in response1:
|
||||
# 只处理包含实际文本内容的事件,过滤调试信息
|
||||
if hasattr(event, 'content') and event.content:
|
||||
if hasattr(event.content, 'parts') and event.content.parts:
|
||||
for part in event.content.parts:
|
||||
if hasattr(part, 'text') and part.text and part.text.strip():
|
||||
text_content = str(part.text).strip()
|
||||
# 过滤掉调试信息和系统消息
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
agent1_reply += text_content
|
||||
elif hasattr(event, 'text') and event.text:
|
||||
text_content = str(event.text).strip()
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
agent1_reply += text_content
|
||||
|
||||
print(f"\n🗣️ {agent1.name}({perspective1}):")
|
||||
print(f" {agent1_reply}")
|
||||
|
||||
# 第二轮:agent2 回应
|
||||
prompt2 = f"针对{agent1.name}刚才的观点:'{agent1_reply}',请从{perspective2}的角度进行回应和反驳。要求:有理有据,体现{perspective2}的独特视角。"
|
||||
|
||||
content2 = types.Content(role='user', parts=[types.Part(text=prompt2)])
|
||||
response2 = runner2.run_async(
|
||||
user_id=session.user_id,
|
||||
session_id=session.id,
|
||||
new_message=content2
|
||||
)
|
||||
|
||||
agent2_reply = ""
|
||||
async for event in response2:
|
||||
# 只处理包含实际文本内容的事件,过滤调试信息
|
||||
if hasattr(event, 'content') and event.content:
|
||||
if hasattr(event.content, 'parts') and event.content.parts:
|
||||
for part in event.content.parts:
|
||||
if hasattr(part, 'text') and part.text and part.text.strip():
|
||||
text_content = str(part.text).strip()
|
||||
# 过滤掉调试信息和系统消息
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
agent2_reply += text_content
|
||||
elif hasattr(event, 'text') and event.text:
|
||||
text_content = str(event.text).strip()
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
agent2_reply += text_content
|
||||
|
||||
print(f"\n🗣️ {agent2.name}({perspective2}):")
|
||||
print(f" {agent2_reply}")
|
||||
|
||||
# 第三轮:agent1 再次回应
|
||||
prompt3 = f"听了{agent2.name}的观点:'{agent2_reply}',请从{perspective1}的角度进行最后的总结和回应。"
|
||||
|
||||
content3 = types.Content(role='user', parts=[types.Part(text=prompt3)])
|
||||
response3 = runner1.run_async(
|
||||
user_id=session.user_id,
|
||||
session_id=session.id,
|
||||
new_message=content3
|
||||
)
|
||||
|
||||
agent1_final = ""
|
||||
async for event in response3:
|
||||
# 只处理包含实际文本内容的事件,过滤调试信息
|
||||
if hasattr(event, 'content') and event.content:
|
||||
if hasattr(event.content, 'parts') and event.content.parts:
|
||||
for part in event.content.parts:
|
||||
if hasattr(part, 'text') and part.text and part.text.strip():
|
||||
text_content = str(part.text).strip()
|
||||
# 过滤掉调试信息和系统消息
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
agent1_final += text_content
|
||||
elif hasattr(event, 'text') and event.text:
|
||||
text_content = str(event.text).strip()
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
agent1_final += text_content
|
||||
|
||||
print(f"\n🗣️ {agent1.name}({perspective1})总结:")
|
||||
print(f" {agent1_final}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 对角线辩论出现错误: {e}")
|
||||
raise
|
||||
|
||||
async def conduct_baxian_debate():
|
||||
"""进行八仙四对矛盾的完整辩论"""
|
||||
print("\n🏛️ 稷下学宫 - 八仙论道系统启动")
|
||||
print("📚 八仙者,南北朝的产物,男女老少,富贵贫贱,皆可成仙")
|
||||
print("🎯 四对矛盾暗合先天八卦,智慧交锋即将开始")
|
||||
|
||||
topic = "雅江水电站对中印关系的影响"
|
||||
print(f"\n📋 论道主题:{topic}")
|
||||
|
||||
# 创建八仙智能体
|
||||
agents = create_baxian_agents()
|
||||
|
||||
print("\n🔥 八仙真实ADK论道模式")
|
||||
|
||||
# 四对矛盾的对角线辩论
|
||||
debates = [
|
||||
(agents['male_female'], "男性理性", "女性感性", "男女对立"),
|
||||
(agents['old_young'], "长者经验", "青年创新", "老少对立"),
|
||||
(agents['rich_poor'], "富者效率", "贫者公平", "富贫对立"),
|
||||
(agents['noble_humble'], "贵族秩序", "底层真实", "贵贱对立")
|
||||
]
|
||||
|
||||
for i, ((agent1, agent2), perspective1, perspective2, debate_type) in enumerate(debates, 1):
|
||||
print(f"\n{'='*60}")
|
||||
print(f"🎭 {debate_type}辩论")
|
||||
print(f"{'='*60}")
|
||||
|
||||
await conduct_diagonal_debate(agent1, agent2, topic, perspective1, perspective2, i)
|
||||
|
||||
if i < len(debates):
|
||||
print("\n⏳ 准备下一轮辩论...")
|
||||
await asyncio.sleep(1)
|
||||
|
||||
print("\n🎉 八仙论道完成!")
|
||||
print("\n📝 四对矛盾,八种视角,智慧的交锋展现了问题的多面性。")
|
||||
print("💡 这就是稷下学宫八仙论道的魅力所在。")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🚀 稷下学宫 八仙ADK 真实论道系统")
|
||||
|
||||
# 检查API密钥
|
||||
if not os.getenv('GOOGLE_API_KEY'):
|
||||
print("❌ 请设置 GOOGLE_API_KEY 环境变量")
|
||||
return
|
||||
|
||||
print("✅ API密钥已配置")
|
||||
|
||||
try:
|
||||
asyncio.run(conduct_baxian_debate())
|
||||
except KeyboardInterrupt:
|
||||
print("\n👋 用户中断,论道结束")
|
||||
except Exception as e:
|
||||
print(f"❌ 系统错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,980 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
增强版优先级算法 v2.1.0
|
||||
实现更复杂的权重计算和上下文分析能力
|
||||
"""
|
||||
|
||||
import re
|
||||
import math
|
||||
from typing import Dict, List, Any, Optional, Tuple, Set
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
import json
|
||||
from collections import defaultdict, deque
|
||||
import hashlib
|
||||
import statistics
|
||||
|
||||
class ArgumentType(Enum):
|
||||
"""论点类型"""
|
||||
ATTACK = "攻击"
|
||||
DEFENSE = "防御"
|
||||
SUPPORT = "支持"
|
||||
REFUTE = "反驳"
|
||||
SUMMARY = "总结"
|
||||
QUESTION = "质疑"
|
||||
|
||||
class EmotionLevel(Enum):
|
||||
"""情绪强度"""
|
||||
CALM = 1
|
||||
MILD = 2
|
||||
MODERATE = 3
|
||||
INTENSE = 4
|
||||
EXTREME = 5
|
||||
|
||||
@dataclass
|
||||
class SpeechAnalysis:
|
||||
"""发言分析结果"""
|
||||
argument_type: ArgumentType
|
||||
emotion_level: EmotionLevel
|
||||
logic_strength: float # 0-1
|
||||
evidence_quality: float # 0-1
|
||||
relevance_score: float # 0-1
|
||||
urgency_score: float # 0-1
|
||||
target_speakers: List[str] # 针对的发言者
|
||||
keywords: List[str]
|
||||
sentiment_score: float # -1 to 1
|
||||
|
||||
@dataclass
|
||||
class SpeakerProfile:
|
||||
"""发言者档案"""
|
||||
name: str
|
||||
team: str
|
||||
recent_speeches: List[Dict] = field(default_factory=list)
|
||||
total_speech_count: int = 0
|
||||
average_response_time: float = 30.0
|
||||
expertise_areas: List[str] = field(default_factory=list)
|
||||
debate_style: str = "analytical" # "aggressive", "analytical", "diplomatic", "creative"
|
||||
current_energy: float = 1.0 # 0-1
|
||||
last_speech_time: Optional[datetime] = None
|
||||
# 新增字段
|
||||
historical_performance: Dict[str, float] = field(default_factory=dict)
|
||||
context_adaptability: float = 0.7 # 上下文适应能力
|
||||
argument_effectiveness: Dict[str, float] = field(default_factory=dict) # 不同类型论点的有效性
|
||||
collaboration_score: float = 0.5 # 团队协作得分
|
||||
interruption_tendency: float = 0.3 # 打断倾向
|
||||
topic_expertise: Dict[str, float] = field(default_factory=dict) # 话题专业度
|
||||
|
||||
class EnhancedPriorityAlgorithm:
|
||||
"""增强版优先级算法"""
|
||||
|
||||
def __init__(self):
|
||||
# 权重配置
|
||||
self.weights = {
|
||||
"rebuttal_urgency": 0.30, # 反驳紧急性
|
||||
"argument_strength": 0.25, # 论点强度
|
||||
"time_pressure": 0.20, # 时间压力
|
||||
"audience_reaction": 0.15, # 观众反应
|
||||
"strategy_need": 0.10 # 策略需要
|
||||
}
|
||||
|
||||
# 情感关键词库
|
||||
self.emotion_keywords = {
|
||||
EmotionLevel.CALM: ["认为", "分析", "数据显示", "根据", "客观"],
|
||||
EmotionLevel.MILD: ["不同意", "质疑", "担心", "建议"],
|
||||
EmotionLevel.MODERATE: ["强烈", "明显", "严重", "重要"],
|
||||
EmotionLevel.INTENSE: ["绝对", "完全", "彻底", "必须"],
|
||||
EmotionLevel.EXTREME: ["荒谬", "愚蠢", "灾难", "危险"]
|
||||
}
|
||||
|
||||
# 论点类型关键词
|
||||
self.argument_keywords = {
|
||||
ArgumentType.ATTACK: ["错误", "问题", "缺陷", "失败"],
|
||||
ArgumentType.DEFENSE: ["解释", "澄清", "说明", "回应"],
|
||||
ArgumentType.SUPPORT: ["支持", "赞同", "证实", "补充"],
|
||||
ArgumentType.REFUTE: ["反驳", "否定", "驳斥", "反对"],
|
||||
ArgumentType.SUMMARY: ["总结", "综上", "结论", "最后"],
|
||||
ArgumentType.QUESTION: ["为什么", "如何", "是否", "难道"]
|
||||
}
|
||||
|
||||
# 发言者档案
|
||||
self.speaker_profiles: Dict[str, SpeakerProfile] = {}
|
||||
|
||||
# 辩论历史分析
|
||||
self.debate_history: List[Dict] = []
|
||||
|
||||
# 新增: 高级分析器组件
|
||||
self.context_analyzer = ContextAnalyzer()
|
||||
self.learning_system = LearningSystem()
|
||||
self.topic_drift_detector = TopicDriftDetector()
|
||||
self.emotion_dynamics = EmotionDynamicsModel()
|
||||
|
||||
def analyze_speech(self, message: str, speaker: str, context: Dict) -> SpeechAnalysis:
|
||||
"""分析发言内容"""
|
||||
# 检测论点类型
|
||||
argument_type = self._detect_argument_type(message)
|
||||
|
||||
# 检测情绪强度
|
||||
emotion_level = self._detect_emotion_level(message)
|
||||
|
||||
# 计算逻辑强度
|
||||
logic_strength = self._calculate_logic_strength(message)
|
||||
|
||||
# 计算证据质量
|
||||
evidence_quality = self._calculate_evidence_quality(message)
|
||||
|
||||
# 计算相关性分数
|
||||
relevance_score = self._calculate_relevance_score(message, context)
|
||||
|
||||
# 计算紧急性分数
|
||||
urgency_score = self._calculate_urgency_score(message, context)
|
||||
|
||||
# 识别目标发言者
|
||||
target_speakers = self._identify_target_speakers(message)
|
||||
|
||||
# 提取关键词
|
||||
keywords = self._extract_keywords(message)
|
||||
|
||||
# 计算情感分数
|
||||
sentiment_score = self._calculate_sentiment_score(message)
|
||||
|
||||
return SpeechAnalysis(
|
||||
argument_type=argument_type,
|
||||
emotion_level=emotion_level,
|
||||
logic_strength=logic_strength,
|
||||
evidence_quality=evidence_quality,
|
||||
relevance_score=relevance_score,
|
||||
urgency_score=urgency_score,
|
||||
target_speakers=target_speakers,
|
||||
keywords=keywords,
|
||||
sentiment_score=sentiment_score
|
||||
)
|
||||
|
||||
def calculate_speaker_priority(self, speaker: str, context: Dict,
|
||||
recent_speeches: List[Dict]) -> float:
|
||||
"""计算发言者优先级 - 增强版"""
|
||||
# 获取或创建发言者档案
|
||||
profile = self._get_or_create_speaker_profile(speaker)
|
||||
|
||||
# 更新发言者档案
|
||||
self._update_speaker_profile(profile, recent_speeches)
|
||||
|
||||
# === 基础分数计算 ===
|
||||
rebuttal_urgency = self._calculate_rebuttal_urgency(speaker, context, recent_speeches)
|
||||
argument_strength = self._calculate_argument_strength(speaker, profile)
|
||||
time_pressure = self._calculate_time_pressure(speaker, context)
|
||||
audience_reaction = self._calculate_audience_reaction(speaker, context)
|
||||
strategy_need = self._calculate_strategy_need(speaker, context, profile)
|
||||
|
||||
# === 新增高级分析 ===
|
||||
# 1. 上下文流程分析
|
||||
flow_analysis = self.context_analyzer.analyze_debate_flow(recent_speeches)
|
||||
flow_bonus = self._calculate_flow_bonus(speaker, flow_analysis)
|
||||
|
||||
# 2. 话题漂移检测
|
||||
if recent_speeches:
|
||||
last_speech = recent_speeches[-1].get("content", "")
|
||||
drift_analysis = self.topic_drift_detector.detect_drift(last_speech, context)
|
||||
drift_penalty = self._calculate_drift_penalty(speaker, drift_analysis)
|
||||
else:
|
||||
drift_penalty = 0.0
|
||||
|
||||
# 3. 情绪动态分析
|
||||
emotion_analysis = self.emotion_dynamics.analyze_emotion_dynamics(recent_speeches)
|
||||
emotion_bonus = self._calculate_emotion_bonus(speaker, emotion_analysis, profile)
|
||||
|
||||
# 4. 学习系统适应
|
||||
adaptation = self.learning_system.get_speaker_adaptation(speaker)
|
||||
adaptation_factor = adaptation.get("confidence", 0.5)
|
||||
|
||||
# 5. 个性化权重调整
|
||||
personalized_weights = self._get_personalized_weights(speaker, profile, context)
|
||||
|
||||
# === 加权计算总分 ===
|
||||
base_score = (
|
||||
rebuttal_urgency * personalized_weights["rebuttal_urgency"] +
|
||||
argument_strength * personalized_weights["argument_strength"] +
|
||||
time_pressure * personalized_weights["time_pressure"] +
|
||||
audience_reaction * personalized_weights["audience_reaction"] +
|
||||
strategy_need * personalized_weights["strategy_need"]
|
||||
)
|
||||
|
||||
# 应用高级调整
|
||||
enhanced_score = base_score + flow_bonus - drift_penalty + emotion_bonus
|
||||
enhanced_score *= adaptation_factor
|
||||
|
||||
# 应用传统修正因子
|
||||
final_score = self._apply_correction_factors(enhanced_score, speaker, profile, context)
|
||||
|
||||
return min(max(final_score, 0.0), 1.0) # 限制在0-1范围内
|
||||
|
||||
def get_next_speaker(self, available_speakers: List[str], context: Dict,
|
||||
recent_speeches: List[Dict]) -> Tuple[str, float, Dict]:
|
||||
"""获取下一个发言者"""
|
||||
speaker_scores = {}
|
||||
detailed_analysis = {}
|
||||
|
||||
for speaker in available_speakers:
|
||||
score = self.calculate_speaker_priority(speaker, context, recent_speeches)
|
||||
speaker_scores[speaker] = score
|
||||
|
||||
# 记录详细分析
|
||||
detailed_analysis[speaker] = {
|
||||
"priority_score": score,
|
||||
"profile": self.speaker_profiles.get(speaker),
|
||||
"analysis_timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
# 选择最高分发言者
|
||||
best_speaker = max(speaker_scores, key=speaker_scores.get)
|
||||
best_score = speaker_scores[best_speaker]
|
||||
|
||||
return best_speaker, best_score, detailed_analysis
|
||||
|
||||
def _detect_argument_type(self, message: str) -> ArgumentType:
|
||||
"""检测论点类型"""
|
||||
message_lower = message.lower()
|
||||
type_scores = {}
|
||||
|
||||
for arg_type, keywords in self.argument_keywords.items():
|
||||
score = sum(1 for keyword in keywords if keyword in message_lower)
|
||||
type_scores[arg_type] = score
|
||||
|
||||
if not type_scores or max(type_scores.values()) == 0:
|
||||
return ArgumentType.SUPPORT # 默认类型
|
||||
|
||||
return max(type_scores, key=type_scores.get)
|
||||
|
||||
def _detect_emotion_level(self, message: str) -> EmotionLevel:
|
||||
"""检测情绪强度"""
|
||||
message_lower = message.lower()
|
||||
|
||||
for emotion_level in reversed(list(EmotionLevel)):
|
||||
keywords = self.emotion_keywords.get(emotion_level, [])
|
||||
if any(keyword in message_lower for keyword in keywords):
|
||||
return emotion_level
|
||||
|
||||
return EmotionLevel.CALM
|
||||
|
||||
def _calculate_logic_strength(self, message: str) -> float:
|
||||
"""计算逻辑强度"""
|
||||
logic_indicators = [
|
||||
"因为", "所以", "因此", "由于", "根据", "数据显示",
|
||||
"研究表明", "事实上", "例如", "比如", "首先", "其次", "最后"
|
||||
]
|
||||
|
||||
message_lower = message.lower()
|
||||
logic_count = sum(1 for indicator in logic_indicators if indicator in message_lower)
|
||||
|
||||
# 基于逻辑词汇密度计算
|
||||
word_count = len(message.split())
|
||||
if word_count == 0:
|
||||
return 0.0
|
||||
|
||||
logic_density = logic_count / word_count
|
||||
return min(logic_density * 10, 1.0) # 归一化到0-1
|
||||
|
||||
def _calculate_evidence_quality(self, message: str) -> float:
|
||||
"""计算证据质量"""
|
||||
evidence_indicators = [
|
||||
"数据", "统计", "研究", "报告", "调查", "实验",
|
||||
"案例", "例子", "证据", "资料", "文献", "来源"
|
||||
]
|
||||
|
||||
message_lower = message.lower()
|
||||
evidence_count = sum(1 for indicator in evidence_indicators if indicator in message_lower)
|
||||
|
||||
# 检查是否有具体数字
|
||||
number_pattern = r'\d+(?:\.\d+)?%?'
|
||||
numbers = re.findall(number_pattern, message)
|
||||
number_bonus = min(len(numbers) * 0.1, 0.3)
|
||||
|
||||
base_score = min(evidence_count * 0.2, 0.7)
|
||||
return min(base_score + number_bonus, 1.0)
|
||||
|
||||
def _calculate_relevance_score(self, message: str, context: Dict) -> float:
|
||||
"""计算相关性分数"""
|
||||
# 简化实现:基于关键词匹配
|
||||
topic_keywords = context.get("topic_keywords", [])
|
||||
if not topic_keywords:
|
||||
return 0.5 # 默认中等相关性
|
||||
|
||||
message_lower = message.lower()
|
||||
relevance_count = sum(1 for keyword in topic_keywords if keyword.lower() in message_lower)
|
||||
|
||||
return min(relevance_count / len(topic_keywords), 1.0)
|
||||
|
||||
def _calculate_urgency_score(self, message: str, context: Dict) -> float:
|
||||
"""计算紧急性分数"""
|
||||
urgency_keywords = ["紧急", "立即", "马上", "现在", "重要", "关键", "危险"]
|
||||
|
||||
message_lower = message.lower()
|
||||
urgency_count = sum(1 for keyword in urgency_keywords if keyword in message_lower)
|
||||
|
||||
# 基于时间压力
|
||||
time_factor = context.get("time_remaining", 1.0)
|
||||
time_urgency = 1.0 - time_factor
|
||||
|
||||
keyword_urgency = min(urgency_count * 0.3, 1.0)
|
||||
|
||||
return min(keyword_urgency + time_urgency * 0.5, 1.0)
|
||||
|
||||
def _identify_target_speakers(self, message: str) -> List[str]:
|
||||
"""识别目标发言者"""
|
||||
# 简化实现:查找提及的发言者名称
|
||||
speaker_names = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
|
||||
targets = []
|
||||
|
||||
for name in speaker_names:
|
||||
if name in message:
|
||||
targets.append(name)
|
||||
|
||||
return targets
|
||||
|
||||
def _extract_keywords(self, message: str) -> List[str]:
|
||||
"""提取关键词"""
|
||||
# 简化实现:提取长度大于2的词汇
|
||||
words = re.findall(r'\b\w{3,}\b', message)
|
||||
return list(set(words))[:10] # 最多返回10个关键词
|
||||
|
||||
def _calculate_sentiment_score(self, message: str) -> float:
|
||||
"""计算情感分数"""
|
||||
positive_words = ["好", "优秀", "正确", "支持", "赞同", "成功", "有效"]
|
||||
negative_words = ["坏", "错误", "失败", "反对", "问题", "危险", "无效"]
|
||||
|
||||
message_lower = message.lower()
|
||||
|
||||
positive_count = sum(1 for word in positive_words if word in message_lower)
|
||||
negative_count = sum(1 for word in negative_words if word in message_lower)
|
||||
|
||||
total_count = positive_count + negative_count
|
||||
if total_count == 0:
|
||||
return 0.0
|
||||
|
||||
return (positive_count - negative_count) / total_count
|
||||
|
||||
def _get_or_create_speaker_profile(self, speaker: str) -> SpeakerProfile:
|
||||
"""获取或创建发言者档案"""
|
||||
if speaker not in self.speaker_profiles:
|
||||
self.speaker_profiles[speaker] = SpeakerProfile(
|
||||
name=speaker,
|
||||
team="positive" if "正" in speaker else "negative",
|
||||
recent_speeches=[],
|
||||
total_speech_count=0,
|
||||
average_response_time=3.0,
|
||||
expertise_areas=[],
|
||||
debate_style="analytical",
|
||||
current_energy=1.0
|
||||
)
|
||||
|
||||
return self.speaker_profiles[speaker]
|
||||
|
||||
def _update_speaker_profile(self, profile: SpeakerProfile, recent_speeches: List[Dict]):
|
||||
"""更新发言者档案"""
|
||||
# 更新发言历史
|
||||
speaker_speeches = [s for s in recent_speeches if s.get("speaker") == profile.name]
|
||||
profile.recent_speeches = speaker_speeches[-5:] # 保留最近5次发言
|
||||
profile.total_speech_count = len(speaker_speeches)
|
||||
|
||||
# 更新能量水平(基于发言频率)
|
||||
if profile.last_speech_time:
|
||||
time_since_last = datetime.now() - profile.last_speech_time
|
||||
energy_recovery = min(time_since_last.seconds / 300, 0.5) # 5分钟恢复50%
|
||||
profile.current_energy = min(profile.current_energy + energy_recovery, 1.0)
|
||||
|
||||
profile.last_speech_time = datetime.now()
|
||||
|
||||
def _calculate_rebuttal_urgency(self, speaker: str, context: Dict,
|
||||
recent_speeches: List[Dict]) -> float:
|
||||
"""计算反驳紧急性"""
|
||||
# 检查是否有针对该发言者团队的攻击
|
||||
team = "positive" if "正" in speaker else "negative"
|
||||
opposing_team = "negative" if team == "positive" else "positive"
|
||||
|
||||
recent_attacks = 0
|
||||
for speech in recent_speeches[-5:]: # 检查最近5次发言
|
||||
if speech.get("team") == opposing_team:
|
||||
analysis = speech.get("analysis", {})
|
||||
if analysis.get("argument_type") in [ArgumentType.ATTACK, ArgumentType.REFUTE]:
|
||||
recent_attacks += 1
|
||||
|
||||
# 基础紧急性 + 攻击响应紧急性
|
||||
# 为不同发言者生成不同的基础紧急性
|
||||
speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
|
||||
base_urgency = 0.1 + speaker_hash * 0.05 # 不同发言者有不同的基础紧急性
|
||||
attack_urgency = recent_attacks * 0.3
|
||||
|
||||
return min(base_urgency + attack_urgency, 1.0)
|
||||
|
||||
def _calculate_argument_strength(self, speaker: str, profile: SpeakerProfile) -> float:
|
||||
"""计算论点强度"""
|
||||
# 基于历史表现
|
||||
if not profile.recent_speeches:
|
||||
# 为不同发言者提供不同的基础论点强度
|
||||
speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
|
||||
team_prefix = "正" if "正" in speaker else "反"
|
||||
|
||||
# 基础强度根据发言者哈希值变化
|
||||
base_strength = 0.4 + speaker_hash * 0.06 # 0.4-1.0范围
|
||||
|
||||
# 团队差异化
|
||||
team_factor = 1.05 if team_prefix == "正" else 0.95
|
||||
|
||||
return min(base_strength * team_factor, 1.0)
|
||||
|
||||
avg_logic = sum(s.get("analysis", {}).get("logic_strength", 0.5)
|
||||
for s in profile.recent_speeches) / len(profile.recent_speeches)
|
||||
avg_evidence = sum(s.get("analysis", {}).get("evidence_quality", 0.5)
|
||||
for s in profile.recent_speeches) / len(profile.recent_speeches)
|
||||
|
||||
return (avg_logic + avg_evidence) / 2
|
||||
|
||||
def _calculate_time_pressure(self, speaker: str, context: Dict) -> float:
|
||||
"""计算时间压力"""
|
||||
time_remaining = context.get("time_remaining", 1.0)
|
||||
stage_progress = context.get("stage_progress", 0)
|
||||
max_progress = context.get("max_progress", 1)
|
||||
|
||||
# 时间压力随剩余时间减少而增加
|
||||
time_pressure = 1.0 - time_remaining
|
||||
|
||||
# 阶段进度压力
|
||||
progress_pressure = stage_progress / max_progress
|
||||
|
||||
# 发言者个体差异
|
||||
speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
|
||||
speaker_factor = 0.8 + speaker_hash * 0.02 # 不同发言者有不同的时间敏感度
|
||||
|
||||
base_pressure = (time_pressure + progress_pressure) / 2
|
||||
return min(base_pressure * speaker_factor, 1.0)
|
||||
|
||||
def _calculate_audience_reaction(self, speaker: str, context: Dict) -> float:
|
||||
"""计算观众反应"""
|
||||
# 简化实现:基于团队表现
|
||||
team = "positive" if "正" in speaker else "negative"
|
||||
team_score = context.get(f"{team}_team_score", 0.5)
|
||||
|
||||
# 发言者个体魅力差异
|
||||
speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
|
||||
charisma_factor = 0.7 + speaker_hash * 0.03 # 不同发言者有不同的观众吸引力
|
||||
|
||||
# 如果团队表现不佳,需要更多发言机会
|
||||
base_reaction = 1.0 - team_score
|
||||
return min(base_reaction * charisma_factor, 1.0)
|
||||
|
||||
def _calculate_strategy_need(self, speaker: str, context: Dict,
|
||||
profile: SpeakerProfile) -> float:
|
||||
"""计算策略需要"""
|
||||
# 基于发言者专长和当前需求
|
||||
current_stage = context.get("current_stage", "")
|
||||
|
||||
# 为不同发言者提供差异化的策略需求
|
||||
speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
|
||||
team_prefix = "正" if "正" in speaker else "反"
|
||||
|
||||
strategy_match = {
|
||||
"起": 0.8 if speaker_hash == 0 else 0.3 + speaker_hash * 0.05, # 开场需要主力,但有差异
|
||||
"承": 0.4 + speaker_hash * 0.06, # 承接阶段根据发言者哈希差异化
|
||||
"转": max(0.2, 1.0 - profile.current_energy + speaker_hash * 0.05), # 自由辩论看能量和哈希
|
||||
"合": 0.9 if speaker_hash == 0 else 0.3 + speaker_hash * 0.05 # 总结需要主力,但有差异
|
||||
}
|
||||
|
||||
base_score = strategy_match.get(current_stage, 0.5)
|
||||
|
||||
# 添加团队差异化因子
|
||||
team_factor = 1.1 if team_prefix == "正" else 0.9
|
||||
|
||||
return min(base_score * team_factor, 1.0)
|
||||
|
||||
def _apply_correction_factors(self, base_score: float, speaker: str,
|
||||
profile: SpeakerProfile, context: Dict) -> float:
|
||||
"""应用修正因子"""
|
||||
corrected_score = base_score
|
||||
|
||||
# 能量修正
|
||||
corrected_score *= profile.current_energy
|
||||
|
||||
# 发言频率修正(避免某人发言过多)
|
||||
recent_count = len([s for s in profile.recent_speeches
|
||||
if s.get("timestamp", "") > (datetime.now() - timedelta(minutes=5)).isoformat()])
|
||||
if recent_count > 2:
|
||||
corrected_score *= 0.7 # 降低优先级
|
||||
|
||||
# 团队平衡修正
|
||||
team = "positive" if "正" in speaker else "negative"
|
||||
team_recent_count = context.get(f"{team}_recent_speeches", 0)
|
||||
opposing_recent_count = context.get(f"{'negative' if team == 'positive' else 'positive'}_recent_speeches", 0)
|
||||
|
||||
if team_recent_count > opposing_recent_count + 2:
|
||||
corrected_score *= 0.8 # 平衡发言机会
|
||||
|
||||
return corrected_score
|
||||
|
||||
def calculate_priority(self, speaker: str, context: Dict, recent_speeches: List[Dict]) -> float:
|
||||
"""计算发言者优先级(兼容性方法)"""
|
||||
return self.calculate_speaker_priority(speaker, context, recent_speeches)
|
||||
|
||||
def get_algorithm_status(self) -> Dict[str, Any]:
|
||||
"""获取算法状态"""
|
||||
return {
|
||||
"weights": self.weights,
|
||||
"speaker_count": len(self.speaker_profiles),
|
||||
"total_speeches_analyzed": len(self.debate_history),
|
||||
"algorithm_version": "2.1.0",
|
||||
"last_updated": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
def save_analysis_data(self, filename: str = "priority_analysis.json"):
|
||||
"""保存分析数据"""
|
||||
data = {
|
||||
"algorithm_status": self.get_algorithm_status(),
|
||||
"speaker_profiles": {
|
||||
name: {
|
||||
"name": profile.name,
|
||||
"team": profile.team,
|
||||
"total_speech_count": profile.total_speech_count,
|
||||
"average_response_time": profile.average_response_time,
|
||||
"expertise_areas": profile.expertise_areas,
|
||||
"debate_style": profile.debate_style,
|
||||
"current_energy": profile.current_energy,
|
||||
"last_speech_time": profile.last_speech_time.isoformat() if profile.last_speech_time else None
|
||||
}
|
||||
for name, profile in self.speaker_profiles.items()
|
||||
},
|
||||
"debate_history": self.debate_history
|
||||
}
|
||||
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"💾 优先级分析数据已保存到 {filename}")
|
||||
|
||||
def main():
|
||||
"""测试增强版优先级算法"""
|
||||
print("🚀 增强版优先级算法测试")
|
||||
print("=" * 50)
|
||||
|
||||
algorithm = EnhancedPriorityAlgorithm()
|
||||
|
||||
# 模拟辩论上下文
|
||||
context = {
|
||||
"current_stage": "转",
|
||||
"stage_progress": 10,
|
||||
"max_progress": 36,
|
||||
"time_remaining": 0.6,
|
||||
"topic_keywords": ["人工智能", "投资", "风险", "收益"],
|
||||
"positive_team_score": 0.6,
|
||||
"negative_team_score": 0.4,
|
||||
"positive_recent_speeches": 3,
|
||||
"negative_recent_speeches": 2
|
||||
}
|
||||
|
||||
# 模拟最近发言
|
||||
recent_speeches = [
|
||||
{
|
||||
"speaker": "正1",
|
||||
"team": "positive",
|
||||
"message": "根据数据显示,AI投资确实能带来显著收益",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"analysis": {
|
||||
"argument_type": ArgumentType.SUPPORT,
|
||||
"logic_strength": 0.8,
|
||||
"evidence_quality": 0.7
|
||||
}
|
||||
},
|
||||
{
|
||||
"speaker": "反2",
|
||||
"team": "negative",
|
||||
"message": "这种观点完全错误!AI投资风险巨大!",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"analysis": {
|
||||
"argument_type": ArgumentType.ATTACK,
|
||||
"logic_strength": 0.3,
|
||||
"evidence_quality": 0.2
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
available_speakers = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
|
||||
|
||||
# 计算下一个发言者
|
||||
next_speaker, score, analysis = algorithm.get_next_speaker(
|
||||
available_speakers, context, recent_speeches
|
||||
)
|
||||
|
||||
print(f"\n🎯 推荐发言者: {next_speaker}")
|
||||
print(f"📊 优先级分数: {score:.3f}")
|
||||
print(f"\n📈 详细分析:")
|
||||
|
||||
for speaker, data in analysis.items():
|
||||
print(f" {speaker}: {data['priority_score']:.3f}")
|
||||
|
||||
# 保存分析数据
|
||||
algorithm.save_analysis_data()
|
||||
|
||||
print("\n✅ 增强版优先级算法测试完成!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
class ContextAnalyzer:
|
||||
"""高级上下文分析器"""
|
||||
|
||||
def __init__(self):
|
||||
self.context_memory = deque(maxlen=20) # 保留最近20轮的上下文
|
||||
self.semantic_vectors = {} # 语义向量缓存
|
||||
|
||||
def analyze_debate_flow(self, recent_speeches: List[Dict]) -> Dict[str, Any]:
|
||||
"""分析辩论流程"""
|
||||
if not recent_speeches:
|
||||
return {"flow_direction": "neutral", "momentum": 0.5, "tension": 0.3}
|
||||
|
||||
# 分析辩论动量
|
||||
momentum = self._calculate_debate_momentum(recent_speeches)
|
||||
|
||||
# 分析辩论紧张度
|
||||
tension = self._calculate_debate_tension(recent_speeches)
|
||||
|
||||
# 分析流程方向
|
||||
flow_direction = self._analyze_flow_direction(recent_speeches)
|
||||
|
||||
# 检测话题转换点
|
||||
topic_shifts = self._detect_topic_shifts(recent_speeches)
|
||||
|
||||
return {
|
||||
"flow_direction": flow_direction,
|
||||
"momentum": momentum,
|
||||
"tension": tension,
|
||||
"topic_shifts": topic_shifts,
|
||||
"engagement_level": self._calculate_engagement_level(recent_speeches)
|
||||
}
|
||||
|
||||
def _calculate_debate_momentum(self, speeches: List[Dict]) -> float:
|
||||
"""计算辩论动量"""
|
||||
if len(speeches) < 2:
|
||||
return 0.5
|
||||
|
||||
# 基于发言长度和情绪强度变化
|
||||
momentum_factors = []
|
||||
for i in range(1, len(speeches)):
|
||||
prev_speech = speeches[i-1]
|
||||
curr_speech = speeches[i]
|
||||
|
||||
# 长度变化
|
||||
length_change = len(curr_speech.get("content", "")) - len(prev_speech.get("content", ""))
|
||||
length_factor = min(abs(length_change) / 100, 1.0) # 归一化
|
||||
|
||||
momentum_factors.append(length_factor)
|
||||
|
||||
return statistics.mean(momentum_factors) if momentum_factors else 0.5
|
||||
|
||||
def _calculate_debate_tension(self, speeches: List[Dict]) -> float:
|
||||
"""计算辩论紧张度"""
|
||||
if not speeches:
|
||||
return 0.3
|
||||
|
||||
tension_keywords = ["反驳", "错误", "质疑", "不同意", "反对", "驳斥"]
|
||||
|
||||
tension_scores = []
|
||||
for speech in speeches[-5:]: # 只看最近5轮
|
||||
content = speech.get("content", "")
|
||||
tension_count = sum(1 for keyword in tension_keywords if keyword in content)
|
||||
tension_scores.append(min(tension_count / 3, 1.0))
|
||||
|
||||
return statistics.mean(tension_scores) if tension_scores else 0.3
|
||||
|
||||
def _analyze_flow_direction(self, speeches: List[Dict]) -> str:
|
||||
"""分析流程方向"""
|
||||
if len(speeches) < 3:
|
||||
return "neutral"
|
||||
|
||||
recent_teams = [speech.get("team", "unknown") for speech in speeches[-3:]]
|
||||
|
||||
positive_count = recent_teams.count("positive")
|
||||
negative_count = recent_teams.count("negative")
|
||||
|
||||
if positive_count > negative_count:
|
||||
return "positive_dominant"
|
||||
elif negative_count > positive_count:
|
||||
return "negative_dominant"
|
||||
else:
|
||||
return "balanced"
|
||||
|
||||
def _detect_topic_shifts(self, speeches: List[Dict]) -> List[Dict]:
|
||||
"""检测话题转换点"""
|
||||
shifts = []
|
||||
if len(speeches) < 2:
|
||||
return shifts
|
||||
|
||||
# 简化的话题转换检测
|
||||
for i in range(1, len(speeches)):
|
||||
prev_keywords = set(speeches[i-1].get("content", "").split()[:10])
|
||||
curr_keywords = set(speeches[i].get("content", "").split()[:10])
|
||||
|
||||
# 计算关键词重叠度
|
||||
overlap = len(prev_keywords & curr_keywords) / max(len(prev_keywords | curr_keywords), 1)
|
||||
|
||||
if overlap < 0.3: # 重叠度低于30%认为是话题转换
|
||||
shifts.append({
|
||||
"position": i,
|
||||
"speaker": speeches[i].get("speaker"),
|
||||
"shift_intensity": 1 - overlap
|
||||
})
|
||||
|
||||
return shifts
|
||||
|
||||
def _calculate_engagement_level(self, speeches: List[Dict]) -> float:
|
||||
"""计算参与度"""
|
||||
if not speeches:
|
||||
return 0.5
|
||||
|
||||
# 基于发言频率和长度
|
||||
total_length = sum(len(speech.get("content", "")) for speech in speeches)
|
||||
avg_length = total_length / len(speeches)
|
||||
|
||||
# 归一化到0-1
|
||||
engagement = min(avg_length / 100, 1.0)
|
||||
return engagement
|
||||
|
||||
|
||||
class LearningSystem:
|
||||
"""学习系统,用于优化算法参数"""
|
||||
|
||||
def __init__(self):
|
||||
self.performance_history = defaultdict(list)
|
||||
self.weight_adjustments = defaultdict(float)
|
||||
self.learning_rate = 0.05
|
||||
|
||||
def record_performance(self, speaker: str, predicted_priority: float,
|
||||
actual_effectiveness: float, context: Dict):
|
||||
"""记录表现数据"""
|
||||
self.performance_history[speaker].append({
|
||||
"predicted_priority": predicted_priority,
|
||||
"actual_effectiveness": actual_effectiveness,
|
||||
"context": context,
|
||||
"timestamp": datetime.now(),
|
||||
"error": abs(predicted_priority - actual_effectiveness)
|
||||
})
|
||||
|
||||
def optimize_weights(self, algorithm_weights: Dict[str, float]) -> Dict[str, float]:
|
||||
"""优化权重参数"""
|
||||
if not self.performance_history:
|
||||
return algorithm_weights
|
||||
|
||||
# 计算每个组件的平均误差
|
||||
component_errors = {}
|
||||
for component in algorithm_weights.keys():
|
||||
errors = []
|
||||
for speaker_data in self.performance_history.values():
|
||||
for record in speaker_data[-10:]: # 只看最近10次
|
||||
errors.append(record["error"])
|
||||
|
||||
if errors:
|
||||
component_errors[component] = statistics.mean(errors)
|
||||
|
||||
# 根据误差调整权重
|
||||
optimized_weights = algorithm_weights.copy()
|
||||
for component, error in component_errors.items():
|
||||
if error > 0.3: # 误差过大,降低权重
|
||||
adjustment = -self.learning_rate * error
|
||||
else: # 误差合理,略微增加权重
|
||||
adjustment = self.learning_rate * (0.3 - error)
|
||||
|
||||
optimized_weights[component] = max(0.05, min(0.5,
|
||||
optimized_weights[component] + adjustment))
|
||||
|
||||
# 归一化权重
|
||||
total_weight = sum(optimized_weights.values())
|
||||
if total_weight > 0:
|
||||
optimized_weights = {k: v/total_weight for k, v in optimized_weights.items()}
|
||||
|
||||
return optimized_weights
|
||||
|
||||
def get_speaker_adaptation(self, speaker: str) -> Dict[str, float]:
|
||||
"""获取发言者特定的适应参数"""
|
||||
if speaker not in self.performance_history:
|
||||
return {"confidence": 0.5, "adaptability": 0.5}
|
||||
|
||||
recent_records = self.performance_history[speaker][-5:]
|
||||
if not recent_records:
|
||||
return {"confidence": 0.5, "adaptability": 0.5}
|
||||
|
||||
# 计算准确性趋势
|
||||
errors = [record["error"] for record in recent_records]
|
||||
avg_error = statistics.mean(errors)
|
||||
|
||||
confidence = max(0.1, 1.0 - avg_error)
|
||||
adaptability = min(1.0, 0.3 + (1.0 - statistics.stdev(errors)) if len(errors) > 1 else 0.7)
|
||||
|
||||
return {"confidence": confidence, "adaptability": adaptability}
|
||||
|
||||
|
||||
class TopicDriftDetector:
|
||||
"""话题漂移检测器"""
|
||||
|
||||
def __init__(self):
|
||||
self.topic_history = deque(maxlen=50)
|
||||
self.keywords_cache = {}
|
||||
|
||||
def detect_drift(self, current_speech: str, context: Dict) -> Dict[str, Any]:
|
||||
"""检测话题漂移"""
|
||||
current_keywords = self._extract_topic_keywords(current_speech)
|
||||
|
||||
if not self.topic_history:
|
||||
self.topic_history.append(current_keywords)
|
||||
return {"drift_detected": False, "drift_intensity": 0.0}
|
||||
|
||||
# 计算与历史话题的相似度
|
||||
similarities = []
|
||||
for historical_keywords in list(self.topic_history)[-5:]: # 最近5轮
|
||||
similarity = self._calculate_keyword_similarity(current_keywords, historical_keywords)
|
||||
similarities.append(similarity)
|
||||
|
||||
avg_similarity = statistics.mean(similarities)
|
||||
drift_intensity = 1.0 - avg_similarity
|
||||
|
||||
# 更新历史
|
||||
self.topic_history.append(current_keywords)
|
||||
|
||||
return {
|
||||
"drift_detected": drift_intensity > 0.4, # 阈值40%
|
||||
"drift_intensity": drift_intensity,
|
||||
"current_keywords": current_keywords,
|
||||
"recommendation": self._get_drift_recommendation(float(drift_intensity))
|
||||
}
|
||||
|
||||
def _extract_topic_keywords(self, text: str) -> Set[str]:
|
||||
"""提取话题关键词"""
|
||||
# 简化的关键词提取
|
||||
words = re.findall(r'\b\w{2,}\b', text.lower())
|
||||
|
||||
# 过滤停用词
|
||||
stop_words = {"的", "了", "在", "是", "我", "你", "他", "她", "我们", "这", "那"}
|
||||
keywords = {word for word in words if word not in stop_words and len(word) > 1}
|
||||
|
||||
return keywords
|
||||
|
||||
def _calculate_keyword_similarity(self, keywords1: Set[str], keywords2: Set[str]) -> float:
|
||||
"""计算关键词相似度"""
|
||||
if not keywords1 or not keywords2:
|
||||
return 0.0
|
||||
|
||||
intersection = keywords1 & keywords2
|
||||
union = keywords1 | keywords2
|
||||
|
||||
return len(intersection) / len(union) if union else 0.0
|
||||
|
||||
def _get_drift_recommendation(self, drift_intensity: float) -> str:
|
||||
"""获取漂移建议"""
|
||||
if drift_intensity > 0.7:
|
||||
return "major_topic_shift_detected"
|
||||
elif drift_intensity > 0.4:
|
||||
return "moderate_drift_detected"
|
||||
else:
|
||||
return "topic_stable"
|
||||
|
||||
|
||||
class EmotionDynamicsModel:
|
||||
"""情绪动力学模型"""
|
||||
|
||||
def __init__(self):
|
||||
self.emotion_history = deque(maxlen=30)
|
||||
self.speaker_emotion_profiles = defaultdict(list)
|
||||
|
||||
def analyze_emotion_dynamics(self, recent_speeches: List[Dict]) -> Dict[str, Any]:
|
||||
"""分析情绪动态"""
|
||||
if not recent_speeches:
|
||||
return {"overall_trend": "neutral", "intensity_change": 0.0}
|
||||
|
||||
# 提取情绪序列
|
||||
emotion_sequence = []
|
||||
for speech in recent_speeches:
|
||||
emotion_score = self._calculate_emotion_score(speech.get("content", ""))
|
||||
emotion_sequence.append(emotion_score)
|
||||
|
||||
# 更新发言者情绪档案
|
||||
speaker = speech.get("speaker")
|
||||
if speaker:
|
||||
self.speaker_emotion_profiles[speaker].append(emotion_score)
|
||||
|
||||
if len(emotion_sequence) < 2:
|
||||
return {"overall_trend": "neutral", "intensity_change": 0.0}
|
||||
|
||||
# 计算情绪趋势
|
||||
trend = self._calculate_emotion_trend(emotion_sequence)
|
||||
|
||||
# 计算强度变化
|
||||
intensity_change = emotion_sequence[-1] - emotion_sequence[0]
|
||||
|
||||
# 检测情绪拐点
|
||||
turning_points = self._detect_emotion_turning_points(emotion_sequence)
|
||||
|
||||
return {
|
||||
"overall_trend": trend,
|
||||
"intensity_change": intensity_change,
|
||||
"current_intensity": emotion_sequence[-1],
|
||||
"turning_points": turning_points,
|
||||
"volatility": statistics.stdev(emotion_sequence) if len(emotion_sequence) > 1 else 0.0
|
||||
}
|
||||
|
||||
def _calculate_emotion_score(self, text: str) -> float:
|
||||
"""计算情绪分数"""
|
||||
positive_words = ["好", "棒", "优秀", "正确", "支持", "赞同", "有效"]
|
||||
negative_words = ["坏", "错", "糟糕", "反对", "质疑", "问题", "失败"]
|
||||
intense_words = ["强烈", "坚决", "绝对", "完全", "彻底"]
|
||||
|
||||
text_lower = text.lower()
|
||||
|
||||
positive_count = sum(1 for word in positive_words if word in text_lower)
|
||||
negative_count = sum(1 for word in negative_words if word in text_lower)
|
||||
intense_count = sum(1 for word in intense_words if word in text_lower)
|
||||
|
||||
base_emotion = (positive_count - negative_count) / max(len(text.split()), 1)
|
||||
intensity_multiplier = 1 + (intense_count * 0.5)
|
||||
|
||||
return base_emotion * intensity_multiplier
|
||||
|
||||
def _calculate_emotion_trend(self, sequence: List[float]) -> str:
|
||||
"""计算情绪趋势"""
|
||||
if len(sequence) < 2:
|
||||
return "neutral"
|
||||
|
||||
# 简单线性回归估算
|
||||
if len(sequence) < 2:
|
||||
return 0.0
|
||||
|
||||
# 计算斜率
|
||||
n = len(sequence)
|
||||
sum_x = sum(range(n))
|
||||
sum_y = sum(sequence)
|
||||
sum_xy = sum(i * sequence[i] for i in range(n))
|
||||
sum_x2 = sum(i * i for i in range(n))
|
||||
|
||||
slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
|
||||
|
||||
if slope > 0.1:
|
||||
return "escalating"
|
||||
elif slope < -0.1:
|
||||
return "de_escalating"
|
||||
else:
|
||||
return "stable"
|
||||
|
||||
def _detect_emotion_turning_points(self, sequence: List[float]) -> List[int]:
|
||||
"""检测情绪拐点"""
|
||||
if len(sequence) < 3:
|
||||
return []
|
||||
|
||||
turning_points = []
|
||||
for i in range(1, len(sequence) - 1):
|
||||
prev_val = sequence[i-1]
|
||||
curr_val = sequence[i]
|
||||
next_val = sequence[i+1]
|
||||
|
||||
# 检测峰值和谷值
|
||||
if (curr_val > prev_val and curr_val > next_val) or \
|
||||
(curr_val < prev_val and curr_val < next_val):
|
||||
turning_points.append(i)
|
||||
|
||||
return turning_points
|
||||
@@ -0,0 +1,733 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
优化的辩论流程控制系统 v2.1.0
|
||||
改进阶段转换和发言权争夺逻辑
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Any, Optional, Tuple, Callable
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from collections import defaultdict, deque
|
||||
import threading
|
||||
import queue
|
||||
|
||||
class DebateStage(Enum):
|
||||
"""辩论阶段枚举"""
|
||||
QI = "起" # 八仙按先天八卦顺序
|
||||
CHENG = "承" # 雁阵式承接
|
||||
ZHUAN = "转" # 自由辩论(36次handoff)
|
||||
HE = "合" # 交替总结
|
||||
|
||||
class FlowControlMode(Enum):
|
||||
"""流程控制模式"""
|
||||
STRICT = "严格模式" # 严格按规则执行
|
||||
ADAPTIVE = "自适应模式" # 根据辩论质量调整
|
||||
DYNAMIC = "动态模式" # 实时响应辩论状态
|
||||
|
||||
class TransitionTrigger(Enum):
|
||||
"""阶段转换触发条件"""
|
||||
TIME_BASED = "时间触发"
|
||||
PROGRESS_BASED = "进度触发"
|
||||
QUALITY_BASED = "质量触发"
|
||||
CONSENSUS_BASED = "共识触发"
|
||||
EMERGENCY = "紧急触发"
|
||||
|
||||
class SpeakerSelectionStrategy(Enum):
|
||||
"""发言者选择策略"""
|
||||
PRIORITY_ALGORITHM = "优先级算法"
|
||||
ROUND_ROBIN = "轮询"
|
||||
RANDOM_WEIGHTED = "加权随机"
|
||||
CONTEXT_AWARE = "上下文感知"
|
||||
COMPETITIVE = "竞争模式"
|
||||
|
||||
@dataclass
|
||||
class FlowControlConfig:
|
||||
"""流程控制配置"""
|
||||
mode: FlowControlMode = FlowControlMode.ADAPTIVE
|
||||
transition_triggers: List[TransitionTrigger] = field(default_factory=lambda: [TransitionTrigger.PROGRESS_BASED, TransitionTrigger.QUALITY_BASED])
|
||||
speaker_selection_strategy: SpeakerSelectionStrategy = SpeakerSelectionStrategy.CONTEXT_AWARE
|
||||
min_stage_duration: int = 60 # 秒
|
||||
max_stage_duration: int = 900 # 秒
|
||||
quality_threshold: float = 0.6 # 质量阈值
|
||||
participation_balance_threshold: float = 0.3 # 参与平衡阈值
|
||||
emergency_intervention_enabled: bool = True
|
||||
auto_stage_transition: bool = True
|
||||
speaker_timeout: int = 30 # 发言超时时间
|
||||
|
||||
@dataclass
|
||||
class StageMetrics:
|
||||
"""阶段指标"""
|
||||
start_time: datetime
|
||||
duration: float = 0.0
|
||||
speech_count: int = 0
|
||||
quality_score: float = 0.0
|
||||
participation_balance: float = 0.0
|
||||
engagement_level: float = 0.0
|
||||
topic_coherence: float = 0.0
|
||||
conflict_intensity: float = 0.0
|
||||
speaker_distribution: Dict[str, int] = field(default_factory=dict)
|
||||
transition_readiness: float = 0.0
|
||||
|
||||
@dataclass
|
||||
class SpeakerRequest:
|
||||
"""发言请求"""
|
||||
speaker: str
|
||||
priority: float
|
||||
timestamp: datetime
|
||||
reason: str
|
||||
urgency_level: int = 1 # 1-5
|
||||
estimated_duration: int = 30 # 秒
|
||||
topic_relevance: float = 1.0
|
||||
|
||||
@dataclass
|
||||
class FlowEvent:
|
||||
"""流程事件"""
|
||||
event_type: str
|
||||
timestamp: datetime
|
||||
data: Dict[str, Any]
|
||||
source: str
|
||||
priority: int = 1
|
||||
|
||||
class OptimizedDebateFlowController:
|
||||
"""优化的辩论流程控制器"""
|
||||
|
||||
def __init__(self, config: FlowControlConfig = None):
|
||||
self.config = config or FlowControlConfig()
|
||||
|
||||
# 当前状态
|
||||
self.current_stage = DebateStage.QI
|
||||
self.stage_progress = 0
|
||||
self.total_handoffs = 0
|
||||
self.current_speaker: Optional[str] = None
|
||||
self.debate_start_time = datetime.now()
|
||||
|
||||
# 阶段配置
|
||||
self.stage_configs = {
|
||||
DebateStage.QI: {
|
||||
"max_progress": 8,
|
||||
"min_duration": 120,
|
||||
"max_duration": 600,
|
||||
"speaker_order": ["吕洞宾", "何仙姑", "铁拐李", "汉钟离", "曹国舅", "韩湘子", "蓝采和", "张果老"],
|
||||
"selection_strategy": SpeakerSelectionStrategy.ROUND_ROBIN
|
||||
},
|
||||
DebateStage.CHENG: {
|
||||
"max_progress": 8,
|
||||
"min_duration": 180,
|
||||
"max_duration": 600,
|
||||
"speaker_order": ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"],
|
||||
"selection_strategy": SpeakerSelectionStrategy.ROUND_ROBIN
|
||||
},
|
||||
DebateStage.ZHUAN: {
|
||||
"max_progress": 36,
|
||||
"min_duration": 300,
|
||||
"max_duration": 900,
|
||||
"speaker_order": ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"],
|
||||
"selection_strategy": SpeakerSelectionStrategy.CONTEXT_AWARE
|
||||
},
|
||||
DebateStage.HE: {
|
||||
"max_progress": 8,
|
||||
"min_duration": 120,
|
||||
"max_duration": 480,
|
||||
"speaker_order": ["反1", "正1", "反2", "正2", "反3", "正3", "反4", "正4"],
|
||||
"selection_strategy": SpeakerSelectionStrategy.ROUND_ROBIN
|
||||
}
|
||||
}
|
||||
|
||||
# 阶段指标
|
||||
self.stage_metrics: Dict[DebateStage, StageMetrics] = {}
|
||||
self.current_stage_metrics = StageMetrics(start_time=datetime.now())
|
||||
|
||||
# 发言请求队列
|
||||
self.speaker_request_queue = queue.PriorityQueue()
|
||||
self.pending_requests: Dict[str, SpeakerRequest] = {}
|
||||
|
||||
# 事件系统
|
||||
self.event_queue = queue.Queue()
|
||||
self.event_handlers: Dict[str, List[Callable]] = defaultdict(list)
|
||||
|
||||
# 历史记录
|
||||
self.debate_history: List[Dict] = []
|
||||
self.stage_transition_history: List[Dict] = []
|
||||
self.speaker_performance: Dict[str, Dict] = defaultdict(dict)
|
||||
|
||||
# 实时监控
|
||||
self.monitoring_active = False
|
||||
self.monitoring_thread: Optional[threading.Thread] = None
|
||||
|
||||
# 流程锁
|
||||
self.flow_lock = threading.RLock()
|
||||
|
||||
# 初始化当前阶段指标
|
||||
self._initialize_stage_metrics()
|
||||
|
||||
def _initialize_stage_metrics(self):
|
||||
"""初始化阶段指标"""
|
||||
self.current_stage_metrics = StageMetrics(
|
||||
start_time=datetime.now(),
|
||||
speaker_distribution={}
|
||||
)
|
||||
|
||||
def get_current_speaker(self) -> Optional[str]:
|
||||
"""获取当前发言者"""
|
||||
with self.flow_lock:
|
||||
config = self.stage_configs[self.current_stage]
|
||||
strategy = config.get("selection_strategy", self.config.speaker_selection_strategy)
|
||||
|
||||
if strategy == SpeakerSelectionStrategy.ROUND_ROBIN:
|
||||
return self._get_round_robin_speaker()
|
||||
elif strategy == SpeakerSelectionStrategy.CONTEXT_AWARE:
|
||||
return self._get_context_aware_speaker()
|
||||
elif strategy == SpeakerSelectionStrategy.PRIORITY_ALGORITHM:
|
||||
return self._get_priority_speaker()
|
||||
elif strategy == SpeakerSelectionStrategy.COMPETITIVE:
|
||||
return self._get_competitive_speaker()
|
||||
else:
|
||||
return self._get_round_robin_speaker()
|
||||
|
||||
def _get_round_robin_speaker(self) -> str:
|
||||
"""轮询方式获取发言者"""
|
||||
config = self.stage_configs[self.current_stage]
|
||||
speaker_order = config["speaker_order"]
|
||||
return speaker_order[self.stage_progress % len(speaker_order)]
|
||||
|
||||
def _get_context_aware_speaker(self) -> Optional[str]:
|
||||
"""上下文感知方式获取发言者"""
|
||||
# 检查是否有紧急发言请求
|
||||
if not self.speaker_request_queue.empty():
|
||||
try:
|
||||
priority, request = self.speaker_request_queue.get_nowait()
|
||||
if request.urgency_level >= 4: # 高紧急度
|
||||
return request.speaker
|
||||
else:
|
||||
# 重新放回队列
|
||||
self.speaker_request_queue.put((priority, request))
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
# 分析当前上下文
|
||||
context = self._analyze_current_context()
|
||||
|
||||
# 根据上下文选择最合适的发言者
|
||||
available_speakers = self.stage_configs[self.current_stage]["speaker_order"]
|
||||
best_speaker = None
|
||||
best_score = -1
|
||||
|
||||
for speaker in available_speakers:
|
||||
score = self._calculate_speaker_context_score(speaker, context)
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_speaker = speaker
|
||||
|
||||
return best_speaker
|
||||
|
||||
def _get_priority_speaker(self) -> Optional[str]:
|
||||
"""优先级算法获取发言者"""
|
||||
# 这里可以集成现有的优先级算法
|
||||
# 暂时使用简化版本
|
||||
return self._get_context_aware_speaker()
|
||||
|
||||
def _get_competitive_speaker(self) -> Optional[str]:
|
||||
"""竞争模式获取发言者"""
|
||||
# 让发言者竞争发言权
|
||||
if not self.speaker_request_queue.empty():
|
||||
try:
|
||||
priority, request = self.speaker_request_queue.get_nowait()
|
||||
return request.speaker
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
return self._get_round_robin_speaker()
|
||||
|
||||
def request_speaking_turn(self, speaker: str, reason: str, urgency: int = 1,
|
||||
estimated_duration: int = 30, topic_relevance: float = 1.0):
|
||||
"""请求发言权"""
|
||||
request = SpeakerRequest(
|
||||
speaker=speaker,
|
||||
priority=self._calculate_request_priority(speaker, reason, urgency, topic_relevance),
|
||||
timestamp=datetime.now(),
|
||||
reason=reason,
|
||||
urgency_level=urgency,
|
||||
estimated_duration=estimated_duration,
|
||||
topic_relevance=topic_relevance
|
||||
)
|
||||
|
||||
# 使用负优先级,因为PriorityQueue是最小堆
|
||||
self.speaker_request_queue.put((-request.priority, request))
|
||||
self.pending_requests[speaker] = request
|
||||
|
||||
# 触发事件
|
||||
self._emit_event("speaker_request", {
|
||||
"speaker": speaker,
|
||||
"reason": reason,
|
||||
"urgency": urgency,
|
||||
"priority": request.priority
|
||||
})
|
||||
|
||||
def _calculate_request_priority(self, speaker: str, reason: str, urgency: int,
|
||||
topic_relevance: float) -> float:
|
||||
"""计算发言请求优先级"""
|
||||
base_priority = urgency * 10
|
||||
|
||||
# 主题相关性加权
|
||||
relevance_bonus = topic_relevance * 5
|
||||
|
||||
# 发言频率调整
|
||||
speaker_count = self.current_stage_metrics.speaker_distribution.get(speaker, 0)
|
||||
frequency_penalty = speaker_count * 2
|
||||
|
||||
# 时间因素
|
||||
time_factor = 1.0
|
||||
if self.current_speaker and self.current_speaker != speaker:
|
||||
time_factor = 1.2 # 鼓励轮换
|
||||
|
||||
priority = (base_priority + relevance_bonus - frequency_penalty) * time_factor
|
||||
return max(0.1, priority)
|
||||
|
||||
def _analyze_current_context(self) -> Dict[str, Any]:
|
||||
"""分析当前辩论上下文"""
|
||||
recent_speeches = self.debate_history[-5:] if self.debate_history else []
|
||||
|
||||
context = {
|
||||
"stage": self.current_stage.value,
|
||||
"progress": self.stage_progress,
|
||||
"recent_speakers": [speech.get("speaker") for speech in recent_speeches],
|
||||
"topic_drift": self._calculate_topic_drift(),
|
||||
"emotional_intensity": self._calculate_emotional_intensity(),
|
||||
"argument_balance": self._calculate_argument_balance(),
|
||||
"time_pressure": self._calculate_time_pressure(),
|
||||
"participation_balance": self._calculate_participation_balance()
|
||||
}
|
||||
|
||||
return context
|
||||
|
||||
def _calculate_speaker_context_score(self, speaker: str, context: Dict[str, Any]) -> float:
|
||||
"""计算发言者在当前上下文下的适合度分数"""
|
||||
score = 0.0
|
||||
|
||||
# 避免连续发言
|
||||
recent_speakers = context.get("recent_speakers", [])
|
||||
if speaker in recent_speakers[-2:]:
|
||||
score -= 10
|
||||
|
||||
# 参与平衡
|
||||
speaker_count = self.current_stage_metrics.speaker_distribution.get(speaker, 0)
|
||||
avg_count = sum(self.current_stage_metrics.speaker_distribution.values()) / max(1, len(self.current_stage_metrics.speaker_distribution))
|
||||
if speaker_count < avg_count:
|
||||
score += 5
|
||||
|
||||
# 队伍平衡
|
||||
if self.current_stage == DebateStage.ZHUAN:
|
||||
positive_count = sum(1 for s in recent_speakers if "正" in s)
|
||||
negative_count = sum(1 for s in recent_speakers if "反" in s)
|
||||
|
||||
if "正" in speaker and positive_count < negative_count:
|
||||
score += 3
|
||||
elif "反" in speaker and negative_count < positive_count:
|
||||
score += 3
|
||||
|
||||
# 时间压力响应
|
||||
time_pressure = context.get("time_pressure", 0)
|
||||
if time_pressure > 0.7 and speaker.endswith("1"): # 主力发言者
|
||||
score += 5
|
||||
|
||||
# 检查发言请求
|
||||
if speaker in self.pending_requests:
|
||||
request = self.pending_requests[speaker]
|
||||
score += request.urgency_level * 2
|
||||
score += request.topic_relevance * 3
|
||||
|
||||
return score
|
||||
|
||||
def advance_stage(self, force: bool = False) -> bool:
|
||||
"""推进辩论阶段"""
|
||||
with self.flow_lock:
|
||||
if not force and not self._should_advance_stage():
|
||||
return False
|
||||
|
||||
# 记录当前阶段结束
|
||||
self._finalize_current_stage()
|
||||
|
||||
# 转换到下一阶段
|
||||
success = self._transition_to_next_stage()
|
||||
|
||||
if success:
|
||||
# 初始化新阶段
|
||||
self._initialize_new_stage()
|
||||
|
||||
# 触发事件
|
||||
self._emit_event("stage_advanced", {
|
||||
"from_stage": self.current_stage.value,
|
||||
"to_stage": self.current_stage.value,
|
||||
"progress": self.stage_progress,
|
||||
"forced": force
|
||||
})
|
||||
|
||||
return success
|
||||
|
||||
def _should_advance_stage(self) -> bool:
|
||||
"""判断是否应该推进阶段"""
|
||||
config = self.stage_configs[self.current_stage]
|
||||
|
||||
# 检查进度触发
|
||||
if TransitionTrigger.PROGRESS_BASED in self.config.transition_triggers:
|
||||
if self.stage_progress >= config["max_progress"] - 1:
|
||||
return True
|
||||
|
||||
# 检查时间触发
|
||||
if TransitionTrigger.TIME_BASED in self.config.transition_triggers:
|
||||
stage_duration = (datetime.now() - self.current_stage_metrics.start_time).total_seconds()
|
||||
if stage_duration >= config.get("max_duration", 600):
|
||||
return True
|
||||
|
||||
# 检查质量触发
|
||||
if TransitionTrigger.QUALITY_BASED in self.config.transition_triggers:
|
||||
if (self.current_stage_metrics.quality_score >= self.config.quality_threshold and
|
||||
self.stage_progress >= config["max_progress"] // 2):
|
||||
return True
|
||||
|
||||
# 检查共识触发
|
||||
if TransitionTrigger.CONSENSUS_BASED in self.config.transition_triggers:
|
||||
if self.current_stage_metrics.transition_readiness >= 0.8:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _finalize_current_stage(self):
|
||||
"""结束当前阶段"""
|
||||
# 更新阶段指标
|
||||
self.current_stage_metrics.duration = (datetime.now() - self.current_stage_metrics.start_time).total_seconds()
|
||||
|
||||
# 保存阶段指标
|
||||
self.stage_metrics[self.current_stage] = self.current_stage_metrics
|
||||
|
||||
# 记录阶段转换历史
|
||||
self.stage_transition_history.append({
|
||||
"stage": self.current_stage.value,
|
||||
"start_time": self.current_stage_metrics.start_time.isoformat(),
|
||||
"duration": self.current_stage_metrics.duration,
|
||||
"speech_count": self.current_stage_metrics.speech_count,
|
||||
"quality_score": self.current_stage_metrics.quality_score,
|
||||
"participation_balance": self.current_stage_metrics.participation_balance
|
||||
})
|
||||
|
||||
def _transition_to_next_stage(self) -> bool:
|
||||
"""转换到下一阶段"""
|
||||
stage_transitions = {
|
||||
DebateStage.QI: DebateStage.CHENG,
|
||||
DebateStage.CHENG: DebateStage.ZHUAN,
|
||||
DebateStage.ZHUAN: DebateStage.HE,
|
||||
DebateStage.HE: None
|
||||
}
|
||||
|
||||
next_stage = stage_transitions.get(self.current_stage)
|
||||
if next_stage:
|
||||
self.current_stage = next_stage
|
||||
self.stage_progress = 0
|
||||
return True
|
||||
else:
|
||||
# 辩论结束
|
||||
self._emit_event("debate_finished", {
|
||||
"total_duration": (datetime.now() - self.debate_start_time).total_seconds(),
|
||||
"total_handoffs": self.total_handoffs,
|
||||
"stages_completed": len(self.stage_metrics)
|
||||
})
|
||||
return False
|
||||
|
||||
def _initialize_new_stage(self):
|
||||
"""初始化新阶段"""
|
||||
self._initialize_stage_metrics()
|
||||
|
||||
# 清空发言请求队列
|
||||
while not self.speaker_request_queue.empty():
|
||||
try:
|
||||
self.speaker_request_queue.get_nowait()
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
self.pending_requests.clear()
|
||||
|
||||
def record_speech(self, speaker: str, message: str, metadata: Dict[str, Any] = None):
|
||||
"""记录发言"""
|
||||
with self.flow_lock:
|
||||
speech_record = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"stage": self.current_stage.value,
|
||||
"stage_progress": self.stage_progress,
|
||||
"speaker": speaker,
|
||||
"message": message,
|
||||
"total_handoffs": self.total_handoffs,
|
||||
"metadata": metadata or {}
|
||||
}
|
||||
|
||||
self.debate_history.append(speech_record)
|
||||
self.current_speaker = speaker
|
||||
|
||||
# 更新阶段指标
|
||||
self._update_stage_metrics(speaker, message)
|
||||
|
||||
# 如果是转阶段,增加handoff计数
|
||||
if self.current_stage == DebateStage.ZHUAN:
|
||||
self.total_handoffs += 1
|
||||
|
||||
# 推进进度
|
||||
self.stage_progress += 1
|
||||
|
||||
# 移除已完成的发言请求
|
||||
if speaker in self.pending_requests:
|
||||
del self.pending_requests[speaker]
|
||||
|
||||
# 触发事件
|
||||
self._emit_event("speech_recorded", {
|
||||
"speaker": speaker,
|
||||
"stage": self.current_stage.value,
|
||||
"progress": self.stage_progress
|
||||
})
|
||||
|
||||
def _update_stage_metrics(self, speaker: str, message: str):
|
||||
"""更新阶段指标"""
|
||||
# 更新发言计数
|
||||
self.current_stage_metrics.speech_count += 1
|
||||
|
||||
# 更新发言者分布
|
||||
if speaker not in self.current_stage_metrics.speaker_distribution:
|
||||
self.current_stage_metrics.speaker_distribution[speaker] = 0
|
||||
self.current_stage_metrics.speaker_distribution[speaker] += 1
|
||||
|
||||
# 计算参与平衡度
|
||||
self.current_stage_metrics.participation_balance = self._calculate_participation_balance()
|
||||
|
||||
# 计算质量分数(简化版本)
|
||||
self.current_stage_metrics.quality_score = self._calculate_quality_score(message)
|
||||
|
||||
# 计算转换准备度
|
||||
self.current_stage_metrics.transition_readiness = self._calculate_transition_readiness()
|
||||
|
||||
def _calculate_topic_drift(self) -> float:
|
||||
"""计算主题偏移度"""
|
||||
# 简化实现
|
||||
return 0.1
|
||||
|
||||
def _calculate_emotional_intensity(self) -> float:
|
||||
"""计算情绪强度"""
|
||||
# 简化实现
|
||||
return 0.5
|
||||
|
||||
def _calculate_argument_balance(self) -> float:
|
||||
"""计算论点平衡度"""
|
||||
# 简化实现
|
||||
return 0.7
|
||||
|
||||
def _calculate_time_pressure(self) -> float:
|
||||
"""计算时间压力"""
|
||||
config = self.stage_configs[self.current_stage]
|
||||
stage_duration = (datetime.now() - self.current_stage_metrics.start_time).total_seconds()
|
||||
max_duration = config.get("max_duration", 600)
|
||||
return min(1.0, stage_duration / max_duration)
|
||||
|
||||
def _calculate_participation_balance(self) -> float:
|
||||
"""计算参与平衡度"""
|
||||
if not self.current_stage_metrics.speaker_distribution:
|
||||
return 1.0
|
||||
|
||||
counts = list(self.current_stage_metrics.speaker_distribution.values())
|
||||
if not counts:
|
||||
return 1.0
|
||||
|
||||
avg_count = sum(counts) / len(counts)
|
||||
variance = sum((count - avg_count) ** 2 for count in counts) / len(counts)
|
||||
|
||||
# 归一化到0-1范围
|
||||
balance = 1.0 / (1.0 + variance)
|
||||
return balance
|
||||
|
||||
def _calculate_quality_score(self, message: str) -> float:
|
||||
"""计算质量分数"""
|
||||
# 简化实现,基于消息长度和关键词
|
||||
base_score = min(1.0, len(message) / 100)
|
||||
|
||||
# 检查关键词
|
||||
quality_keywords = ["因为", "所以", "但是", "然而", "数据", "证据", "分析"]
|
||||
keyword_bonus = sum(0.1 for keyword in quality_keywords if keyword in message)
|
||||
|
||||
return min(1.0, base_score + keyword_bonus)
|
||||
|
||||
def _calculate_transition_readiness(self) -> float:
|
||||
"""计算转换准备度"""
|
||||
# 综合多个因素
|
||||
progress_factor = self.stage_progress / self.stage_configs[self.current_stage]["max_progress"]
|
||||
quality_factor = self.current_stage_metrics.quality_score
|
||||
balance_factor = self.current_stage_metrics.participation_balance
|
||||
|
||||
readiness = (progress_factor * 0.4 + quality_factor * 0.3 + balance_factor * 0.3)
|
||||
return min(1.0, readiness)
|
||||
|
||||
def _emit_event(self, event_type: str, data: Dict[str, Any]):
|
||||
"""发出事件"""
|
||||
event = FlowEvent(
|
||||
event_type=event_type,
|
||||
timestamp=datetime.now(),
|
||||
data=data,
|
||||
source="flow_controller"
|
||||
)
|
||||
|
||||
self.event_queue.put(event)
|
||||
|
||||
# 调用事件处理器
|
||||
for handler in self.event_handlers.get(event_type, []):
|
||||
try:
|
||||
handler(event)
|
||||
except Exception as e:
|
||||
print(f"事件处理器错误: {e}")
|
||||
|
||||
def add_event_handler(self, event_type: str, handler: Callable):
|
||||
"""添加事件处理器"""
|
||||
self.event_handlers[event_type].append(handler)
|
||||
|
||||
def get_flow_status(self) -> Dict[str, Any]:
|
||||
"""获取流程状态"""
|
||||
return {
|
||||
"current_stage": self.current_stage.value,
|
||||
"stage_progress": self.stage_progress,
|
||||
"total_handoffs": self.total_handoffs,
|
||||
"current_speaker": self.current_speaker,
|
||||
"stage_metrics": {
|
||||
"duration": (datetime.now() - self.current_stage_metrics.start_time).total_seconds(),
|
||||
"speech_count": self.current_stage_metrics.speech_count,
|
||||
"quality_score": self.current_stage_metrics.quality_score,
|
||||
"participation_balance": self.current_stage_metrics.participation_balance,
|
||||
"transition_readiness": self.current_stage_metrics.transition_readiness
|
||||
},
|
||||
"pending_requests": len(self.pending_requests),
|
||||
"config": {
|
||||
"mode": self.config.mode.value,
|
||||
"auto_transition": self.config.auto_stage_transition,
|
||||
"quality_threshold": self.config.quality_threshold
|
||||
}
|
||||
}
|
||||
|
||||
def save_flow_data(self, filename: str = "debate_flow_data.json"):
|
||||
"""保存流程数据"""
|
||||
flow_data = {
|
||||
"config": {
|
||||
"mode": self.config.mode.value,
|
||||
"transition_triggers": [t.value for t in self.config.transition_triggers],
|
||||
"speaker_selection_strategy": self.config.speaker_selection_strategy.value,
|
||||
"quality_threshold": self.config.quality_threshold,
|
||||
"auto_stage_transition": self.config.auto_stage_transition
|
||||
},
|
||||
"current_state": {
|
||||
"stage": self.current_stage.value,
|
||||
"progress": self.stage_progress,
|
||||
"total_handoffs": self.total_handoffs,
|
||||
"current_speaker": self.current_speaker,
|
||||
"debate_start_time": self.debate_start_time.isoformat()
|
||||
},
|
||||
"stage_metrics": {
|
||||
stage.value: {
|
||||
"start_time": metrics.start_time.isoformat(),
|
||||
"duration": metrics.duration,
|
||||
"speech_count": metrics.speech_count,
|
||||
"quality_score": metrics.quality_score,
|
||||
"participation_balance": metrics.participation_balance,
|
||||
"speaker_distribution": metrics.speaker_distribution
|
||||
} for stage, metrics in self.stage_metrics.items()
|
||||
},
|
||||
"current_stage_metrics": {
|
||||
"start_time": self.current_stage_metrics.start_time.isoformat(),
|
||||
"duration": (datetime.now() - self.current_stage_metrics.start_time).total_seconds(),
|
||||
"speech_count": self.current_stage_metrics.speech_count,
|
||||
"quality_score": self.current_stage_metrics.quality_score,
|
||||
"participation_balance": self.current_stage_metrics.participation_balance,
|
||||
"speaker_distribution": self.current_stage_metrics.speaker_distribution,
|
||||
"transition_readiness": self.current_stage_metrics.transition_readiness
|
||||
},
|
||||
"debate_history": self.debate_history,
|
||||
"stage_transition_history": self.stage_transition_history,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(flow_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"✅ 流程数据已保存到 {filename}")
|
||||
|
||||
def main():
|
||||
"""测试优化的辩论流程控制系统"""
|
||||
print("🎭 测试优化的辩论流程控制系统")
|
||||
print("=" * 50)
|
||||
|
||||
# 创建配置
|
||||
config = FlowControlConfig(
|
||||
mode=FlowControlMode.ADAPTIVE,
|
||||
transition_triggers=[TransitionTrigger.PROGRESS_BASED, TransitionTrigger.QUALITY_BASED],
|
||||
speaker_selection_strategy=SpeakerSelectionStrategy.CONTEXT_AWARE,
|
||||
auto_stage_transition=True
|
||||
)
|
||||
|
||||
# 创建流程控制器
|
||||
controller = OptimizedDebateFlowController(config)
|
||||
|
||||
# 添加事件处理器
|
||||
def on_stage_advanced(event):
|
||||
print(f"🎭 阶段转换: {event.data}")
|
||||
|
||||
def on_speech_recorded(event):
|
||||
print(f"🗣️ 发言记录: {event.data['speaker']} 在 {event.data['stage']} 阶段")
|
||||
|
||||
controller.add_event_handler("stage_advanced", on_stage_advanced)
|
||||
controller.add_event_handler("speech_recorded", on_speech_recorded)
|
||||
|
||||
# 模拟辩论流程
|
||||
test_speeches = [
|
||||
("吕洞宾", "我认为AI投资具有巨大的潜力和机会。"),
|
||||
("何仙姑", "但我们也需要考虑其中的风险因素。"),
|
||||
("铁拐李", "数据显示AI行业的增长率确实很高。"),
|
||||
("汉钟离", "然而市场波动性也不容忽视。")
|
||||
]
|
||||
|
||||
print("\n📋 开始模拟辩论流程")
|
||||
print("-" * 30)
|
||||
|
||||
for i, (speaker, message) in enumerate(test_speeches):
|
||||
print(f"\n第 {i+1} 轮发言:")
|
||||
|
||||
# 获取当前发言者
|
||||
current_speaker = controller.get_current_speaker()
|
||||
print(f"推荐发言者: {current_speaker}")
|
||||
|
||||
# 记录发言
|
||||
controller.record_speech(speaker, message)
|
||||
|
||||
# 显示流程状态
|
||||
status = controller.get_flow_status()
|
||||
print(f"当前状态: {status['current_stage']} 阶段,进度 {status['stage_progress']}")
|
||||
print(f"质量分数: {status['stage_metrics']['quality_score']:.3f}")
|
||||
print(f"参与平衡: {status['stage_metrics']['participation_balance']:.3f}")
|
||||
|
||||
# 检查是否需要推进阶段
|
||||
if controller._should_advance_stage():
|
||||
print("🔄 准备推进到下一阶段")
|
||||
controller.advance_stage()
|
||||
|
||||
# 测试发言请求
|
||||
print("\n📢 测试发言请求系统")
|
||||
print("-" * 30)
|
||||
|
||||
controller.request_speaking_turn("正1", "需要反驳对方观点", urgency=4, topic_relevance=0.9)
|
||||
controller.request_speaking_turn("反2", "补充论据", urgency=2, topic_relevance=0.7)
|
||||
|
||||
next_speaker = controller.get_current_speaker()
|
||||
print(f"基于请求的下一位发言者: {next_speaker}")
|
||||
|
||||
# 保存数据
|
||||
controller.save_flow_data("test_flow_data.json")
|
||||
|
||||
print("\n✅ 测试完成")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,335 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
太公心易 - 起承转合辩论系统
|
||||
基于先天八卦的八仙辩论架构
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
from enhanced_priority_algorithm import EnhancedPriorityAlgorithm, SpeechAnalysis
|
||||
|
||||
class DebateStage(Enum):
|
||||
"""辩论阶段枚举"""
|
||||
QI = "起" # 八仙按先天八卦顺序
|
||||
CHENG = "承" # 雁阵式承接
|
||||
ZHUAN = "转" # 自由辩论(36次handoff)
|
||||
HE = "合" # 交替总结
|
||||
|
||||
@dataclass
|
||||
class Speaker:
|
||||
"""发言者数据类"""
|
||||
name: str
|
||||
role: str
|
||||
team: str # "positive" or "negative"
|
||||
bagua_position: Optional[int] = None # 八卦位置(0-7)
|
||||
|
||||
@dataclass
|
||||
class DebateContext:
|
||||
"""辩论上下文"""
|
||||
current_stage: DebateStage
|
||||
stage_progress: int
|
||||
total_handoffs: int
|
||||
current_speaker: Optional[str] = None
|
||||
last_message: Optional[str] = None
|
||||
debate_history: List[Dict] = None
|
||||
last_priority_analysis: Optional[Dict[str, Any]] = None
|
||||
|
||||
class QiChengZhuanHeDebateSystem:
|
||||
"""起承转合辩论系统"""
|
||||
|
||||
def __init__(self):
|
||||
# 八仙配置(按先天八卦顺序)
|
||||
self.baxian_speakers = {
|
||||
"吕洞宾": Speaker("吕洞宾", "剑仙投资顾问", "neutral", 0), # 乾
|
||||
"何仙姑": Speaker("何仙姑", "慈悲风控专家", "neutral", 1), # 兑
|
||||
"铁拐李": Speaker("铁拐李", "逆向思维专家", "neutral", 2), # 离
|
||||
"汉钟离": Speaker("汉钟离", "平衡协调者", "neutral", 3), # 震
|
||||
"蓝采和": Speaker("蓝采和", "创新思维者", "neutral", 4), # 巽
|
||||
"张果老": Speaker("张果老", "历史智慧者", "neutral", 5), # 坎
|
||||
"韩湘子": Speaker("韩湘子", "艺术感知者", "neutral", 6), # 艮
|
||||
"曹国舅": Speaker("曹国舅", "实务执行者", "neutral", 7) # 坤
|
||||
}
|
||||
|
||||
# 雁阵队伍配置
|
||||
self.goose_formation = {
|
||||
"positive": ["正1", "正2", "正3", "正4"],
|
||||
"negative": ["反1", "反2", "反3", "反4"]
|
||||
}
|
||||
|
||||
# 辩论状态
|
||||
self.context = DebateContext(
|
||||
current_stage=DebateStage.QI,
|
||||
stage_progress=0,
|
||||
total_handoffs=0,
|
||||
debate_history=[]
|
||||
)
|
||||
|
||||
# 阶段配置
|
||||
self.stage_configs = {
|
||||
DebateStage.QI: {
|
||||
"duration": "8-10分钟",
|
||||
"max_progress": 8, # 八仙轮流发言
|
||||
"description": "八仙按先天八卦顺序阐述观点"
|
||||
},
|
||||
DebateStage.CHENG: {
|
||||
"duration": "8-10分钟",
|
||||
"max_progress": 8, # 正反各4人
|
||||
"description": "雁阵式承接,总体阐述+讥讽"
|
||||
},
|
||||
DebateStage.ZHUAN: {
|
||||
"duration": "12-15分钟",
|
||||
"max_progress": 36, # 36次handoff
|
||||
"description": "自由辩论,优先级算法决定发言"
|
||||
},
|
||||
DebateStage.HE: {
|
||||
"duration": "8-10分钟",
|
||||
"max_progress": 8, # 交替总结
|
||||
"description": "交替总结,最终论证"
|
||||
}
|
||||
}
|
||||
|
||||
# 增强版优先级算法
|
||||
self.priority_algorithm = EnhancedPriorityAlgorithm()
|
||||
|
||||
# 记忆系统
|
||||
self.memory_system = DebateMemorySystem()
|
||||
|
||||
def get_current_speaker(self) -> str:
|
||||
"""获取当前发言者"""
|
||||
stage = self.context.current_stage
|
||||
progress = self.context.stage_progress
|
||||
|
||||
if stage == DebateStage.QI:
|
||||
return self._get_bagua_speaker(progress)
|
||||
elif stage == DebateStage.CHENG:
|
||||
return self._get_goose_formation_speaker(progress)
|
||||
elif stage == DebateStage.ZHUAN:
|
||||
return self._get_priority_speaker()
|
||||
elif stage == DebateStage.HE:
|
||||
return self._get_alternating_speaker(progress)
|
||||
|
||||
return "未知发言者"
|
||||
|
||||
def _get_bagua_speaker(self, progress: int) -> str:
|
||||
"""获取八卦顺序发言者"""
|
||||
bagua_sequence = ["吕洞宾", "何仙姑", "铁拐李", "汉钟离", "蓝采和", "张果老", "韩湘子", "曹国舅"]
|
||||
return bagua_sequence[progress % 8]
|
||||
|
||||
def _get_goose_formation_speaker(self, progress: int) -> str:
|
||||
"""获取雁阵发言者"""
|
||||
if progress < 4:
|
||||
# 正方雁阵
|
||||
return self.goose_formation["positive"][progress]
|
||||
else:
|
||||
# 反方雁阵
|
||||
return self.goose_formation["negative"][progress - 4]
|
||||
|
||||
def _get_priority_speaker(self) -> str:
|
||||
"""获取优先级发言者(转阶段)"""
|
||||
available_speakers = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
|
||||
|
||||
# 构建上下文
|
||||
context = {
|
||||
"current_stage": self.context.current_stage.value,
|
||||
"stage_progress": self.context.stage_progress,
|
||||
"max_progress": self.stage_configs[self.context.current_stage]["max_progress"],
|
||||
"time_remaining": max(0.1, 1.0 - (self.context.stage_progress / self.stage_configs[self.context.current_stage]["max_progress"])),
|
||||
"topic_keywords": ["投资", "AI", "风险", "收益"], # 可配置
|
||||
"positive_team_score": 0.5, # 可动态计算
|
||||
"negative_team_score": 0.5, # 可动态计算
|
||||
"positive_recent_speeches": len([h for h in self.context.debate_history[-10:] if "正" in h.get("speaker", "")]),
|
||||
"negative_recent_speeches": len([h for h in self.context.debate_history[-10:] if "反" in h.get("speaker", "")])
|
||||
}
|
||||
|
||||
# 获取最近发言历史
|
||||
recent_speeches = self.context.debate_history[-10:] if self.context.debate_history else []
|
||||
|
||||
next_speaker, score, analysis = self.priority_algorithm.get_next_speaker(
|
||||
available_speakers, context, recent_speeches
|
||||
)
|
||||
|
||||
# 记录分析结果
|
||||
self.context.last_priority_analysis = {
|
||||
"recommended_speaker": next_speaker,
|
||||
"priority_score": score,
|
||||
"analysis": analysis,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
return next_speaker
|
||||
|
||||
def _get_alternating_speaker(self, progress: int) -> str:
|
||||
"""获取交替总结发言者"""
|
||||
alternating_sequence = ["反1", "正1", "反2", "正2", "反3", "正3", "反4", "正4"]
|
||||
return alternating_sequence[progress % 8]
|
||||
|
||||
def advance_stage(self):
|
||||
"""推进辩论阶段"""
|
||||
current_config = self.stage_configs[self.context.current_stage]
|
||||
|
||||
if self.context.stage_progress >= current_config["max_progress"] - 1:
|
||||
# 当前阶段完成,进入下一阶段
|
||||
self._transition_to_next_stage()
|
||||
else:
|
||||
# 当前阶段继续
|
||||
self.context.stage_progress += 1
|
||||
|
||||
def _transition_to_next_stage(self):
|
||||
"""转换到下一阶段"""
|
||||
stage_transitions = {
|
||||
DebateStage.QI: DebateStage.CHENG,
|
||||
DebateStage.CHENG: DebateStage.ZHUAN,
|
||||
DebateStage.ZHUAN: DebateStage.HE,
|
||||
DebateStage.HE: None # 辩论结束
|
||||
}
|
||||
|
||||
next_stage = stage_transitions[self.context.current_stage]
|
||||
if next_stage:
|
||||
self.context.current_stage = next_stage
|
||||
self.context.stage_progress = 0
|
||||
print(f"🎭 辩论进入{next_stage.value}阶段")
|
||||
else:
|
||||
print("🎉 辩论结束!")
|
||||
|
||||
def record_speech(self, speaker: str, message: str):
|
||||
"""记录发言"""
|
||||
speech_record = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"stage": self.context.current_stage.value,
|
||||
"stage_progress": self.context.stage_progress,
|
||||
"speaker": speaker,
|
||||
"message": message,
|
||||
"total_handoffs": self.context.total_handoffs
|
||||
}
|
||||
|
||||
self.context.debate_history.append(speech_record)
|
||||
self.context.last_message = message
|
||||
self.context.current_speaker = speaker
|
||||
|
||||
# 更新记忆系统
|
||||
self.memory_system.store_speech(speaker, message, self.context)
|
||||
|
||||
# 如果是转阶段,增加handoff计数
|
||||
if self.context.current_stage == DebateStage.ZHUAN:
|
||||
self.context.total_handoffs += 1
|
||||
|
||||
def get_stage_info(self) -> Dict[str, Any]:
|
||||
"""获取当前阶段信息"""
|
||||
stage = self.context.current_stage
|
||||
config = self.stage_configs[stage]
|
||||
|
||||
return {
|
||||
"current_stage": stage.value,
|
||||
"stage_progress": self.context.stage_progress,
|
||||
"max_progress": config["max_progress"],
|
||||
"description": config["description"],
|
||||
"current_speaker": self.get_current_speaker(),
|
||||
"total_handoffs": self.context.total_handoffs
|
||||
}
|
||||
|
||||
def save_debate_state(self, filename: str = "debate_state.json"):
|
||||
"""保存辩论状态"""
|
||||
state_data = {
|
||||
"context": {
|
||||
"current_stage": self.context.current_stage.value,
|
||||
"stage_progress": self.context.stage_progress,
|
||||
"total_handoffs": self.context.total_handoffs,
|
||||
"current_speaker": self.context.current_speaker,
|
||||
"last_message": self.context.last_message
|
||||
},
|
||||
"debate_history": self.context.debate_history,
|
||||
"memory_data": self.memory_system.get_memory_data()
|
||||
}
|
||||
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
json.dump(state_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"💾 辩论状态已保存到 {filename}")
|
||||
|
||||
# 旧的PriorityAlgorithm类已被EnhancedPriorityAlgorithm替换
|
||||
|
||||
class DebateMemorySystem:
|
||||
"""辩论记忆系统"""
|
||||
|
||||
def __init__(self):
|
||||
self.speaker_memories = {}
|
||||
self.debate_memories = []
|
||||
|
||||
def store_speech(self, speaker: str, message: str, context: DebateContext):
|
||||
"""存储发言记忆"""
|
||||
if speaker not in self.speaker_memories:
|
||||
self.speaker_memories[speaker] = []
|
||||
|
||||
memory_entry = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"stage": context.current_stage.value,
|
||||
"message": message,
|
||||
"context": {
|
||||
"stage_progress": context.stage_progress,
|
||||
"total_handoffs": context.total_handoffs
|
||||
}
|
||||
}
|
||||
|
||||
self.speaker_memories[speaker].append(memory_entry)
|
||||
self.debate_memories.append(memory_entry)
|
||||
|
||||
def get_speaker_memory(self, speaker: str, limit: int = 5) -> List[Dict]:
|
||||
"""获取发言者记忆"""
|
||||
if speaker in self.speaker_memories:
|
||||
return self.speaker_memories[speaker][-limit:]
|
||||
return []
|
||||
|
||||
def get_memory_data(self) -> Dict[str, Any]:
|
||||
"""获取记忆数据"""
|
||||
return {
|
||||
"speaker_memories": self.speaker_memories,
|
||||
"debate_memories": self.debate_memories
|
||||
}
|
||||
|
||||
def main():
|
||||
"""主函数 - 测试起承转合辩论系统"""
|
||||
print("🚀 太公心易 - 起承转合辩论系统")
|
||||
print("=" * 60)
|
||||
|
||||
# 创建辩论系统
|
||||
debate_system = QiChengZhuanHeDebateSystem()
|
||||
|
||||
# 测试各阶段
|
||||
test_messages = [
|
||||
"起:八仙按先天八卦顺序阐述观点",
|
||||
"承:雁阵式承接,总体阐述+讥讽",
|
||||
"转:自由辩论,36次handoff",
|
||||
"合:交替总结,最终论证"
|
||||
]
|
||||
|
||||
for i, message in enumerate(test_messages):
|
||||
stage_info = debate_system.get_stage_info()
|
||||
current_speaker = debate_system.get_current_speaker()
|
||||
|
||||
print(f"\n🎭 当前阶段: {stage_info['current_stage']}")
|
||||
print(f"📊 进度: {stage_info['stage_progress'] + 1}/{stage_info['max_progress']}")
|
||||
print(f"🗣️ 发言者: {current_speaker}")
|
||||
print(f"💬 消息: {message}")
|
||||
|
||||
# 记录发言
|
||||
debate_system.record_speech(current_speaker, message)
|
||||
|
||||
# 推进阶段
|
||||
debate_system.advance_stage()
|
||||
|
||||
# 保存状态
|
||||
debate_system.save_debate_state()
|
||||
|
||||
print("\n✅ 起承转合辩论系统测试完成!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user