Backup before system reinstall
This commit is contained in:
249
jixia_academy/agents/baxian/adk_debate_example.py
Normal file
249
jixia_academy/agents/baxian/adk_debate_example.py
Normal file
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫 ADK 真实论道系统
|
||||
实现铁拐李和吕洞宾的实际对话辩论
|
||||
"""
|
||||
|
||||
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_debate_agents():
|
||||
"""创建论道智能体"""
|
||||
|
||||
# 铁拐李 - 逆向思维专家
|
||||
tie_guai_li = Agent(
|
||||
name="铁拐李",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是铁拐李,八仙中的逆向思维专家。你善于从批判和质疑的角度看问题,总是能发现事物的另一面。你的发言风格直接、犀利,但富有智慧。每次发言控制在100字以内。"
|
||||
)
|
||||
|
||||
# 吕洞宾 - 理性分析者
|
||||
lu_dong_bin = Agent(
|
||||
name="吕洞宾",
|
||||
model="gemini-2.5-flash",
|
||||
instruction="你是吕洞宾,八仙中的理性分析者。你善于平衡各方观点,用理性和逻辑来分析问题。你的发言风格温和而深刻,总是能找到问题的核心。每次发言控制在100字以内。"
|
||||
)
|
||||
|
||||
return tie_guai_li, lu_dong_bin
|
||||
|
||||
async def conduct_debate():
|
||||
"""进行实际辩论"""
|
||||
print("🎭 稷下学宫论道开始...")
|
||||
|
||||
# 创建智能体
|
||||
tie_guai_li, lu_dong_bin = create_debate_agents()
|
||||
|
||||
print("\n📋 论道主题: 雅江水电站对中印关系的影响")
|
||||
print("\n🎯 八仙论道,智慧交锋...")
|
||||
|
||||
print("\n🚀 使用真实ADK调用进行论道...")
|
||||
await real_adk_debate(tie_guai_li, lu_dong_bin)
|
||||
|
||||
@contextmanager
|
||||
def suppress_stdout():
|
||||
"""临时抑制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):
|
||||
"""清理ADK输出中的调试信息"""
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
# 移除API密钥相关信息
|
||||
text = re.sub(r'Both GOOGLE_API_KEY and GEMINI_API_KEY are set\. Using GOOGLE_API_KEY\.', '', text)
|
||||
|
||||
# 移除Event from unknown agent信息
|
||||
text = re.sub(r'Event from an unknown agent: [^\n]*\n?', '', text)
|
||||
|
||||
# 移除多余的空白字符
|
||||
text = re.sub(r'\n\s*\n', '\n', text)
|
||||
text = text.strip()
|
||||
|
||||
return text
|
||||
|
||||
async def real_adk_debate(tie_guai_li, lu_dong_bin):
|
||||
"""使用真实ADK进行辩论"""
|
||||
print("\n🔥 真实ADK论道模式")
|
||||
|
||||
# 设置环境变量来抑制ADK调试输出
|
||||
os.environ['GOOGLE_CLOUD_DISABLE_GRPC_LOGS'] = 'true'
|
||||
os.environ['GRPC_VERBOSITY'] = 'NONE'
|
||||
os.environ['GRPC_TRACE'] = ''
|
||||
|
||||
# 临时抑制警告和调试信息
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
# 设置日志级别
|
||||
import logging
|
||||
logging.getLogger().setLevel(logging.ERROR)
|
||||
|
||||
# 创建会话服务
|
||||
session_service = InMemorySessionService()
|
||||
|
||||
# 创建会话
|
||||
session = await session_service.create_session(
|
||||
state={},
|
||||
app_name="稷下学宫论道系统",
|
||||
user_id="debate_user"
|
||||
)
|
||||
|
||||
# 创建Runner实例
|
||||
tie_runner = Runner(
|
||||
app_name="稷下学宫论道系统",
|
||||
agent=tie_guai_li,
|
||||
session_service=session_service
|
||||
)
|
||||
|
||||
lu_runner = Runner(
|
||||
app_name="稷下学宫论道系统",
|
||||
agent=lu_dong_bin,
|
||||
session_service=session_service
|
||||
)
|
||||
|
||||
try:
|
||||
# 第一轮:铁拐李开场
|
||||
print("\n🗣️ 铁拐李发言:")
|
||||
tie_prompt = "作为逆向思维专家,请从批判角度分析雅江水电站建设对中印关系可能带来的负面影响和潜在风险。请控制在100字以内。"
|
||||
|
||||
tie_content = types.Content(role='user', parts=[types.Part(text=tie_prompt)])
|
||||
with suppress_stdout():
|
||||
tie_response = tie_runner.run_async(
|
||||
user_id=session.user_id,
|
||||
session_id=session.id,
|
||||
new_message=tie_content
|
||||
)
|
||||
|
||||
tie_reply = ""
|
||||
async for event in tie_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 and part.text.strip():
|
||||
text_content = str(part.text).strip()
|
||||
# 过滤掉调试信息和系统消息
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
tie_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:
|
||||
tie_reply += text_content
|
||||
|
||||
# 清理并输出铁拐李的回复
|
||||
clean_tie_reply = clean_debug_output(tie_reply)
|
||||
if clean_tie_reply:
|
||||
print(f" {clean_tie_reply}")
|
||||
|
||||
# 第二轮:吕洞宾回应
|
||||
print("\n🗣️ 吕洞宾回应:")
|
||||
lu_prompt = f"铁拐李提到了雅江水电站的负面影响:'{tie_reply[:50]}...'。作为理性分析者,请从平衡角度回应,既承认风险又指出雅江水电站对中印关系的积极意义。请控制在100字以内。"
|
||||
|
||||
lu_content = types.Content(role='user', parts=[types.Part(text=lu_prompt)])
|
||||
with suppress_stdout():
|
||||
lu_response = lu_runner.run_async(
|
||||
user_id=session.user_id,
|
||||
session_id=session.id,
|
||||
new_message=lu_content
|
||||
)
|
||||
|
||||
lu_reply = ""
|
||||
async for event in lu_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 and part.text.strip():
|
||||
text_content = str(part.text).strip()
|
||||
# 过滤掉调试信息和系统消息
|
||||
if not text_content.startswith('Event from') and not 'API_KEY' in text_content:
|
||||
lu_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:
|
||||
lu_reply += text_content
|
||||
|
||||
# 清理并输出吕洞宾的回复
|
||||
clean_lu_reply = clean_debug_output(lu_reply)
|
||||
if clean_lu_reply:
|
||||
print(f" {clean_lu_reply}")
|
||||
|
||||
# 第三轮:铁拐李再次发言
|
||||
print("\n🗣️ 铁拐李再次发言:")
|
||||
tie_prompt2 = f"吕洞宾提到了雅江水电站的积极意义:'{lu_reply[:50]}...'。请从逆向思维角度,对这些所谓的积极影响进行质疑和反思。请控制在100字以内。"
|
||||
|
||||
tie_content2 = types.Content(role='user', parts=[types.Part(text=tie_prompt2)])
|
||||
with suppress_stdout():
|
||||
tie_response2 = tie_runner.run_async(
|
||||
user_id=session.user_id,
|
||||
session_id=session.id,
|
||||
new_message=tie_content2
|
||||
)
|
||||
|
||||
tie_reply2 = ""
|
||||
async for event in tie_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:
|
||||
tie_reply2 += 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:
|
||||
tie_reply2 += text_content
|
||||
|
||||
# 清理并输出铁拐李的第二次回复
|
||||
clean_tie_reply2 = clean_debug_output(tie_reply2)
|
||||
if clean_tie_reply2:
|
||||
print(f" {clean_tie_reply2}")
|
||||
|
||||
print("\n🎉 真实ADK论道完成!")
|
||||
print("\n📝 智慧交锋,各抒己见,这就是稷下学宫的魅力所在。")
|
||||
|
||||
finally:
|
||||
# 清理资源
|
||||
await tie_runner.close()
|
||||
await lu_runner.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🚀 稷下学宫 ADK 真实论道系统")
|
||||
|
||||
# 检查API密钥
|
||||
api_key = os.getenv('GOOGLE_API_KEY')
|
||||
if not api_key:
|
||||
print("❌ 未找到 GOOGLE_API_KEY 环境变量")
|
||||
print("请使用: doppler run -- python src/jixia/debates/adk_real_debate.py")
|
||||
return
|
||||
|
||||
print(f"✅ API密钥已配置")
|
||||
|
||||
# 运行异步辩论
|
||||
try:
|
||||
asyncio.run(conduct_debate())
|
||||
except Exception as e:
|
||||
print(f"❌ 运行失败: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
481
jixia_academy/agents/baxian/baxian_adk_gemini_debate.py
Normal file
481
jixia_academy/agents/baxian/baxian_adk_gemini_debate.py
Normal file
@@ -0,0 +1,481 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫 - 八仙ADK辩论系统 (Gemini 2.5 Flash版)
|
||||
使用Google ADK和Gemini 2.5 Flash模型实现八仙辩论
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
from google.adk import Agent, Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.genai import types
|
||||
|
||||
# 加载.env文件
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
except ImportError:
|
||||
print("⚠️ 未安装python-dotenv,请运行: pip install python-dotenv")
|
||||
pass
|
||||
|
||||
class BaXianADKDebateSystem:
|
||||
"""八仙ADK辩论系统"""
|
||||
|
||||
def __init__(self):
|
||||
self.model = "gemini-2.5-flash"
|
||||
self.agents = {}
|
||||
self.debate_history = []
|
||||
self.current_round = 0
|
||||
self.max_rounds = 3
|
||||
|
||||
# 八仙角色定义
|
||||
self.baxian_profiles = {
|
||||
"铁拐李": {
|
||||
"personality": "八仙之首,形象为街头乞丐,代表社会底层。性格刚直不阿,善于逆向思维和批判分析。你从底层民众的角度看问题,敢于质疑权贵,为弱势群体发声。",
|
||||
"speaking_style": "直言不讳,接地气,善用反问和草根智慧",
|
||||
"expertise": "批判思维、民生洞察、社会底层视角"
|
||||
},
|
||||
"吕洞宾": {
|
||||
"personality": "理性务实的学者型仙人,善于分析问题本质和长远影响。你注重逻辑推理,能够平衡各方观点,寻求最优解决方案。",
|
||||
"speaking_style": "条理分明,深入浅出,善用类比和归纳",
|
||||
"expertise": "战略分析、系统思维、决策优化"
|
||||
},
|
||||
"何仙姑": {
|
||||
"personality": "八仙中唯一的女性,温柔智慧,善于从情感和人文角度思考问题。你关注社会影响和人文关怀,注重和谐与平衡。",
|
||||
"speaking_style": "温和理性,富有同理心,善用情感共鸣",
|
||||
"expertise": "人文关怀、社会影响、情感分析"
|
||||
},
|
||||
"蓝采和": {
|
||||
"personality": "贫穷的街头歌者,自由奔放的艺术家气质。你代表精神富足但物质贫乏的群体,善于从艺术和美学角度看待问题,关注精神层面的价值。",
|
||||
"speaking_style": "活泼生动,富有想象力,善用诗歌和民谣",
|
||||
"expertise": "创新思维、艺术视角、精神追求、民间智慧"
|
||||
},
|
||||
"韩湘子": {
|
||||
"personality": "年轻有为的技术专家,对新技术和趋势敏感。你善于从技术角度分析问题,关注实现可行性和技术细节。",
|
||||
"speaking_style": "专业严谨,数据驱动,善用技术术语",
|
||||
"expertise": "技术分析、趋势预测、可行性评估"
|
||||
},
|
||||
"曹国舅": {
|
||||
"personality": "皇亲国戚,贵族出身,代表上层社会。你具有政治敏感性和大局观,善于从政策和制度角度分析问题,关注权力结构和利益平衡,维护既得利益群体。",
|
||||
"speaking_style": "稳重大气,政治敏锐,善用历史典故和朝堂礼仪",
|
||||
"expertise": "政策分析、制度设计、权力博弈、上层社会视角"
|
||||
},
|
||||
"张果老": {
|
||||
"personality": "年长智慧的长者,经验丰富,善于从历史和哲学角度看问题。你能提供深刻的人生智慧和历史洞察。",
|
||||
"speaking_style": "深沉睿智,引经据典,善用哲理思辨",
|
||||
"expertise": "历史洞察、哲学思辨、人生智慧"
|
||||
},
|
||||
"钟离权": {
|
||||
"personality": "汉钟离,出身将门富贵,军事战略家。你善于从战略和执行角度分析问题,注重实战经验和资源配置,关注执行力和结果导向。代表富贵阶层的视角。",
|
||||
"speaking_style": "果断坚定,战略清晰,善用军事比喻和资源分析",
|
||||
"expertise": "战略规划、执行管理、风险控制、资源配置"
|
||||
}
|
||||
}
|
||||
|
||||
def create_agents(self) -> bool:
|
||||
"""创建八仙智能体"""
|
||||
try:
|
||||
for name, profile in self.baxian_profiles.items():
|
||||
# 构建系统提示词
|
||||
system_prompt = f"""
|
||||
你是{name},{profile['personality']}
|
||||
|
||||
你的说话风格:{profile['speaking_style']}
|
||||
你的专业领域:{profile['expertise']}
|
||||
|
||||
在辩论中,请:
|
||||
1. 保持你的角色特色和专业视角
|
||||
2. 提供有价值的观点和分析
|
||||
3. 与其他仙人进行建设性的讨论
|
||||
4. 每次发言控制在200字以内
|
||||
5. 语言要生动有趣,符合你的性格特点
|
||||
"""
|
||||
|
||||
# 创建ADK智能体
|
||||
agent = Agent(
|
||||
name=name,
|
||||
model=self.model,
|
||||
instruction=system_prompt
|
||||
)
|
||||
|
||||
self.agents[name] = agent
|
||||
print(f"✅ 创建智能体: {name}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 创建智能体失败: {e}")
|
||||
return False
|
||||
|
||||
async def conduct_debate(self, topic: str, rounds: int = 3) -> Dict[str, Any]:
|
||||
"""进行八仙辩论"""
|
||||
self.max_rounds = rounds
|
||||
debate_id = f"baxian_debate_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
|
||||
print(f"\n🏛️ 稷下学宫 - 八仙论道")
|
||||
print(f"📋 辩论主题: {topic}")
|
||||
print(f"🔄 辩论轮次: {rounds}")
|
||||
print(f"🤖 使用模型: {self.model}")
|
||||
print("=" * 80)
|
||||
|
||||
# 辩论开场
|
||||
opening_context = f"""
|
||||
今日稷下学宫八仙齐聚,共同探讨「{topic}」这一重要议题。
|
||||
|
||||
请各位仙人从自己的专业角度和人生阅历出发,分享真知灼见。
|
||||
让我们通过思辨碰撞,共同寻求智慧的火花。
|
||||
"""
|
||||
|
||||
self.debate_history.append({
|
||||
"type": "opening",
|
||||
"content": opening_context,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
|
||||
# 进行多轮辩论
|
||||
for round_num in range(1, rounds + 1):
|
||||
print(f"\n🎯 第{round_num}轮辩论")
|
||||
print("-" * 60)
|
||||
|
||||
await self._conduct_round(topic, round_num)
|
||||
|
||||
# 轮次间隔
|
||||
if round_num < rounds:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# 辩论总结
|
||||
await self._generate_summary(topic)
|
||||
|
||||
# 保存辩论记录
|
||||
result = {
|
||||
"debate_id": debate_id,
|
||||
"topic": topic,
|
||||
"model": self.model,
|
||||
"rounds": rounds,
|
||||
"participants": list(self.agents.keys()),
|
||||
"debate_history": self.debate_history,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
# 创建输出目录(相对于项目根目录)
|
||||
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
output_dir = os.path.join(project_root, "outputs", "debates")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# 保存到文件
|
||||
filename = f"baxian_debate_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
||||
filepath = os.path.join(output_dir, filename)
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"\n💾 辩论记录已保存: {filepath}")
|
||||
|
||||
return result
|
||||
|
||||
async def _conduct_round(self, topic: str, round_num: int):
|
||||
"""进行单轮辩论"""
|
||||
# 按照对立统一原则安排发言顺序
|
||||
# 基于docs/baxian_debate_order_guide.md的分组原则
|
||||
|
||||
if round_num == 1:
|
||||
# 第一轮:按对立组依次发言
|
||||
speaker_order = [
|
||||
"吕洞宾", # 乾/男
|
||||
"何仙姑", # 坤/女
|
||||
"张果老", # 老
|
||||
"韩湘子", # 少
|
||||
"钟离权", # 富(汉钟离)
|
||||
"蓝采和", # 贫
|
||||
"曹国舅", # 贵
|
||||
"铁拐李" # 贱
|
||||
]
|
||||
else:
|
||||
# 后续轮次:对立组交替发言,增强辩论张力
|
||||
speaker_order = [
|
||||
"铁拐李", "曹国舅", # 贵贱对立
|
||||
"蓝采和", "钟离权", # 贫富对立
|
||||
"韩湘子", "张果老", # 老少对立
|
||||
"何仙姑", "吕洞宾" # 男女对立
|
||||
]
|
||||
|
||||
for speaker_name in speaker_order:
|
||||
if speaker_name in self.agents:
|
||||
await self._agent_speak(speaker_name, topic, round_num)
|
||||
await asyncio.sleep(0.5) # 短暂间隔
|
||||
|
||||
async def _agent_speak(self, speaker_name: str, topic: str, round_num: int):
|
||||
"""智能体发言"""
|
||||
agent = self.agents[speaker_name]
|
||||
|
||||
# 构建上下文
|
||||
context = self._build_context(speaker_name, topic, round_num)
|
||||
|
||||
try:
|
||||
# 创建会话服务(如果还没有)
|
||||
if not hasattr(self, 'session_service'):
|
||||
self.session_service = InMemorySessionService()
|
||||
self.session = await self.session_service.create_session(
|
||||
state={},
|
||||
app_name="八仙论道系统",
|
||||
user_id="debate_user"
|
||||
)
|
||||
|
||||
# 创建Runner
|
||||
runner = Runner(
|
||||
app_name="八仙论道系统",
|
||||
agent=agent,
|
||||
session_service=self.session_service
|
||||
)
|
||||
|
||||
# 构建消息内容
|
||||
content = types.Content(role='user', parts=[types.Part(text=context)])
|
||||
|
||||
# 生成回应
|
||||
response_stream = runner.run_async(
|
||||
user_id=self.session.user_id,
|
||||
session_id=self.session.id,
|
||||
new_message=content
|
||||
)
|
||||
|
||||
# 收集响应
|
||||
response_parts = []
|
||||
async for event in response_stream:
|
||||
# 过滤ADK系统调试信息
|
||||
event_str = str(event)
|
||||
if ('Event from an unknown agent' in event_str or
|
||||
'event id:' in event_str or
|
||||
'API_KEY' in event_str):
|
||||
continue
|
||||
|
||||
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
|
||||
'API_KEY' not in text_content and
|
||||
'event id:' not in text_content and
|
||||
'unknown agent' not in text_content):
|
||||
response_parts.append(text_content)
|
||||
elif hasattr(event, 'text') and event.text:
|
||||
text_content = str(event.text).strip()
|
||||
if (not text_content.startswith('Event from') and
|
||||
'API_KEY' not in text_content and
|
||||
'event id:' not in text_content and
|
||||
'unknown agent' not in text_content):
|
||||
response_parts.append(text_content)
|
||||
|
||||
response = ''.join(response_parts).strip()
|
||||
|
||||
# 记录发言
|
||||
speech_record = {
|
||||
"type": "speech",
|
||||
"round": round_num,
|
||||
"speaker": speaker_name,
|
||||
"content": response,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
self.debate_history.append(speech_record)
|
||||
|
||||
# 显示发言
|
||||
print(f"\n🗣️ {speaker_name}:")
|
||||
print(f"{response}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ {speaker_name} 发言失败: {e}")
|
||||
# 记录错误
|
||||
error_record = {
|
||||
"type": "error",
|
||||
"round": round_num,
|
||||
"speaker": speaker_name,
|
||||
"error": str(e),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
self.debate_history.append(error_record)
|
||||
|
||||
def _build_context(self, speaker_name: str, topic: str, round_num: int) -> str:
|
||||
"""构建发言上下文"""
|
||||
# 获取最近的发言历史
|
||||
recent_speeches = []
|
||||
for record in self.debate_history[-6:]: # 最近6条记录
|
||||
if record["type"] == "speech" and record["speaker"] != speaker_name:
|
||||
recent_speeches.append(f"{record['speaker']}: {record['content']}")
|
||||
|
||||
context = f"""
|
||||
辩论主题:{topic}
|
||||
当前轮次:第{round_num}轮
|
||||
|
||||
"""
|
||||
|
||||
if recent_speeches:
|
||||
context += "最近的讨论:\n" + "\n".join(recent_speeches[-3:]) + "\n\n"
|
||||
|
||||
if round_num == 1:
|
||||
context += "请从你的专业角度对这个主题发表观点,阐述你的立场和理由。"
|
||||
else:
|
||||
context += "请结合前面的讨论,进一步阐述你的观点,或对其他仙人的观点进行回应和补充。"
|
||||
|
||||
return context
|
||||
|
||||
async def _generate_summary(self, topic: str):
|
||||
"""生成辩论总结"""
|
||||
print(f"\n📝 辩论总结")
|
||||
print("=" * 60)
|
||||
|
||||
# 统计各仙人发言次数
|
||||
speech_count = {}
|
||||
for record in self.debate_history:
|
||||
if record["type"] == "speech":
|
||||
speaker = record["speaker"]
|
||||
speech_count[speaker] = speech_count.get(speaker, 0) + 1
|
||||
|
||||
print(f"\n📊 发言统计:")
|
||||
for speaker, count in speech_count.items():
|
||||
print(f" {speaker}: {count}次发言")
|
||||
|
||||
# 可以添加更多总结逻辑
|
||||
summary_record = {
|
||||
"type": "summary",
|
||||
"topic": topic,
|
||||
"speech_count": speech_count,
|
||||
"total_speeches": sum(speech_count.values()),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
self.debate_history.append(summary_record)
|
||||
|
||||
def check_api_key() -> bool:
|
||||
"""检查API密钥"""
|
||||
# 优先使用 GOOGLE_API_KEY,如果没有则使用 GEMINI_API_KEY
|
||||
google_api_key = os.getenv('GOOGLE_API_KEY')
|
||||
gemini_api_key = os.getenv('GEMINI_API_KEY')
|
||||
|
||||
if google_api_key and gemini_api_key:
|
||||
print("⚠️ 检测到同时设置了 GOOGLE_API_KEY 和 GEMINI_API_KEY")
|
||||
print("📝 建议:统一使用 GOOGLE_API_KEY,将移除 GEMINI_API_KEY")
|
||||
# 使用 GOOGLE_API_KEY
|
||||
api_key = google_api_key
|
||||
print(f"✅ 使用 GOOGLE_API_KEY (长度: {len(api_key)} 字符)")
|
||||
return True
|
||||
elif google_api_key:
|
||||
print(f"✅ 使用 GOOGLE_API_KEY (长度: {len(google_api_key)} 字符)")
|
||||
return True
|
||||
elif gemini_api_key:
|
||||
print(f"✅ 使用 GEMINI_API_KEY (长度: {len(gemini_api_key)} 字符)")
|
||||
# 设置 GOOGLE_API_KEY 为 GEMINI_API_KEY 的值
|
||||
os.environ['GOOGLE_API_KEY'] = gemini_api_key
|
||||
return True
|
||||
else:
|
||||
print("❌ 未找到 GOOGLE_API_KEY 或 GEMINI_API_KEY 环境变量")
|
||||
print("请设置环境变量: export GOOGLE_API_KEY=your_api_key")
|
||||
print("或使用: doppler run -- python examples/debates/baxian_adk_gemini_debate.py")
|
||||
return False
|
||||
|
||||
def demo_mode():
|
||||
"""演示模式 - 模拟辩论过程"""
|
||||
print("🎭 演示模式:八仙论道模拟")
|
||||
print("=" * 60)
|
||||
|
||||
topic = "人工智能对未来社会的影响"
|
||||
print(f"📋 辩论主题: {topic}")
|
||||
print("🔄 辩论轮次: 2")
|
||||
print("🤖 模拟模式: 演示版本")
|
||||
print("=" * 80)
|
||||
|
||||
# 模拟八仙发言
|
||||
demo_speeches = {
|
||||
"铁拐李": "人工智能虽然强大,但我们不能盲目崇拜。技术的发展必须以人为本,警惕其可能带来的风险和挑战。",
|
||||
"吕洞宾": "从长远来看,AI将重塑社会结构。我们需要理性分析其影响,制定合适的发展策略,平衡效率与公平。",
|
||||
"何仙姑": "技术进步应该服务于人类福祉。我们要关注AI对就业、教育的影响,确保技术发展不会加剧社会不平等。",
|
||||
"蓝采和": "AI为艺术创作开辟了新天地!想象一下,人机协作能创造出多么奇妙的作品,这是前所未有的创新机遇。",
|
||||
"韩湘子": "从技术角度看,AI的算力和算法正在指数级增长。我们需要关注数据安全、隐私保护等技术挑战。",
|
||||
"曹国舅": "政策制定者必须未雨绸缪,建立完善的AI治理框架,平衡创新发展与风险管控的关系。",
|
||||
"张果老": "纵观历史,每次技术革命都伴随着社会变迁。AI亦如此,关键在于如何引导其造福人类。",
|
||||
"钟离权": "战略上要重视AI的军事应用,确保国家安全。同时要有执行力,将AI政策落到实处。"
|
||||
}
|
||||
|
||||
print("\n🎯 第1轮辩论")
|
||||
print("-" * 60)
|
||||
|
||||
for name, speech in demo_speeches.items():
|
||||
print(f"\n🗣️ {name}:")
|
||||
print(f"{speech}")
|
||||
import time
|
||||
time.sleep(1)
|
||||
|
||||
print("\n📝 辩论总结")
|
||||
print("=" * 60)
|
||||
print("📊 发言统计:")
|
||||
for name in demo_speeches.keys():
|
||||
print(f" {name}: 1次发言")
|
||||
|
||||
print("\n🎉 演示完成!")
|
||||
print("💡 要体验完整的AI辩论功能,请配置真实的 GOOGLE_API_KEY")
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
print("🏛️ 稷下学宫 - 八仙ADK辩论系统 (Gemini 2.5 Flash版)")
|
||||
print("🤖 使用Google ADK + Gemini 2.5 Flash模型")
|
||||
print("🎭 八仙齐聚,共论天下大事")
|
||||
print("\n📝 注意:运行过程中可能出现ADK系统调试信息,这是正常现象")
|
||||
print(" 包括'Event from an unknown agent'等信息,不影响辩论功能")
|
||||
print()
|
||||
|
||||
# 检查API密钥
|
||||
if not check_api_key():
|
||||
print("⚠️ 未找到有效的 GOOGLE_API_KEY,启动演示模式")
|
||||
print("💡 请设置环境变量以体验完整功能: export GOOGLE_API_KEY=your_api_key")
|
||||
print("📝 获取API密钥: https://aistudio.google.com/app/apikey")
|
||||
print()
|
||||
|
||||
# 演示模式 - 模拟辩论过程
|
||||
demo_mode()
|
||||
return
|
||||
|
||||
# 创建辩论系统
|
||||
debate_system = BaXianADKDebateSystem()
|
||||
|
||||
# 创建智能体
|
||||
if not debate_system.create_agents():
|
||||
print("❌ 智能体创建失败,无法进行辩论")
|
||||
return
|
||||
|
||||
# 辩论主题
|
||||
topics = [
|
||||
"人工智能对未来社会的影响",
|
||||
"数字货币与传统金融的博弈",
|
||||
"元宇宙技术的发展前景",
|
||||
"可持续发展与经济增长的平衡",
|
||||
"教育数字化转型的机遇与挑战"
|
||||
]
|
||||
|
||||
# 选择主题(可以随机选择或让用户选择)
|
||||
topic = topics[0] # 默认使用第一个主题
|
||||
|
||||
try:
|
||||
# 开始辩论
|
||||
result = await debate_system.conduct_debate(topic, rounds=2)
|
||||
|
||||
if result:
|
||||
print(f"\n🎉 辩论成功完成!")
|
||||
print(f"📁 辩论ID: {result['debate_id']}")
|
||||
print(f"🎯 参与者: {', '.join(result['participants'])}")
|
||||
print(f"📊 总发言数: {len([r for r in result['debate_history'] if r['type'] == 'speech'])}")
|
||||
else:
|
||||
print("❌ 辩论失败")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n👋 用户中断,辩论结束")
|
||||
except Exception as e:
|
||||
print(f"❌ 辩论过程中发生错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
251
jixia_academy/agents/baxian/baxian_agent.py
Normal file
251
jixia_academy/agents/baxian/baxian_agent.py
Normal file
@@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
八仙智能体基类
|
||||
Baxian Agent Base Class
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import List, Dict, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from jixia_academy.core.memory_bank.interface import MemoryBankInterface
|
||||
|
||||
|
||||
class BaxianAgent:
|
||||
"""八仙智能体"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
personality: str,
|
||||
expertise: List[str],
|
||||
style: str,
|
||||
memory_bank: MemoryBankInterface
|
||||
):
|
||||
self.name = name
|
||||
self.personality = personality
|
||||
self.expertise = expertise
|
||||
self.style = style
|
||||
self.memory_bank = memory_bank
|
||||
self.initialized = False
|
||||
|
||||
async def initialize(self):
|
||||
"""初始化智能体"""
|
||||
if self.initialized:
|
||||
return
|
||||
|
||||
print(f"🎭 初始化 {self.name} ({self.personality})")
|
||||
self.initialized = True
|
||||
|
||||
async def close(self):
|
||||
"""关闭资源"""
|
||||
self.initialized = False
|
||||
|
||||
async def generate_viewpoint(
|
||||
self,
|
||||
topic: str,
|
||||
history: List[Dict[str, Any]],
|
||||
round_num: int
|
||||
) -> str:
|
||||
"""生成观点"""
|
||||
|
||||
# 分析历史观点
|
||||
historical_analysis = await self._analyze_history(topic, history)
|
||||
|
||||
# 基于个性生成观点
|
||||
viewpoint = await self._generate_personalized_viewpoint(
|
||||
topic=topic,
|
||||
historical_analysis=historical_analysis,
|
||||
round_num=round_num
|
||||
)
|
||||
|
||||
return viewpoint
|
||||
|
||||
async def _analyze_history(
|
||||
self,
|
||||
topic: str,
|
||||
history: List[Dict[str, Any]]
|
||||
) -> Dict[str, Any]:
|
||||
"""分析历史观点"""
|
||||
|
||||
# 统计各角色观点
|
||||
role_views = {}
|
||||
for entry in history:
|
||||
speaker = entry.get("speaker", "")
|
||||
if speaker in ["铁拐李", "吕洞宾", "何仙姑", "张果老",
|
||||
"蓝采和", "汉钟离", "韩湘子", "曹国舅"]:
|
||||
if speaker not in role_views:
|
||||
role_views[speaker] = []
|
||||
role_views[speaker].append(entry.get("message", ""))
|
||||
|
||||
# 分析共识和分歧
|
||||
consensus = await self._identify_consensus(role_views)
|
||||
disagreements = await self._identify_disagreements(role_views)
|
||||
|
||||
return {
|
||||
"role_views": role_views,
|
||||
"consensus": consensus,
|
||||
"disagreements": disagreements,
|
||||
"total_entries": len(history)
|
||||
}
|
||||
|
||||
async def _identify_consensus(self, role_views: Dict[str, List[str]]) -> List[str]:
|
||||
"""识别共识"""
|
||||
# 简化版共识识别
|
||||
common_themes = []
|
||||
|
||||
# 如果多数角色提到相似的观点,视为共识
|
||||
all_views = []
|
||||
for views in role_views.values():
|
||||
all_views.extend(views)
|
||||
|
||||
# 这里简化处理,实际可以使用NLP技术
|
||||
if "风险" in str(all_views):
|
||||
common_themes.append("关注风险控制")
|
||||
if "机会" in str(all_views):
|
||||
common_themes.append("看到投资机会")
|
||||
|
||||
return common_themes
|
||||
|
||||
async def _identify_disagreements(self, role_views: Dict[str, List[str]]) -> List[str]:
|
||||
"""识别分歧"""
|
||||
# 简化版分歧识别
|
||||
disagreements = []
|
||||
|
||||
# 检查是否有明显相反的观点
|
||||
for role, views in role_views.items():
|
||||
if role != self.name:
|
||||
# 这里简化处理
|
||||
if "乐观" in str(views) and self.personality == "风险控制专家":
|
||||
disagreements.append(f"与{role}的乐观观点存在分歧")
|
||||
elif "悲观" in str(views) and self.personality == "创新思维者":
|
||||
disagreements.append(f"与{role}的悲观观点存在分歧")
|
||||
|
||||
return disagreements
|
||||
|
||||
async def _generate_personalized_viewpoint(
|
||||
self,
|
||||
topic: str,
|
||||
historical_analysis: Dict[str, Any],
|
||||
round_num: int
|
||||
) -> str:
|
||||
"""基于个性生成观点"""
|
||||
|
||||
# 基于角色个性生成观点模板
|
||||
templates = {
|
||||
"逆向思维专家": [
|
||||
"我认为当前主流观点可能存在盲区...",
|
||||
"让我们从另一个角度思考这个问题...",
|
||||
"我注意到一个被忽视的风险点..."
|
||||
],
|
||||
"理性分析者": [
|
||||
"基于逻辑分析,我认为...",
|
||||
"让我们用理性的眼光审视这个问题...",
|
||||
"从数据角度看,情况显示..."
|
||||
],
|
||||
"风险控制专家": [
|
||||
"我们首先需要评估潜在风险...",
|
||||
"在考虑收益的同时,必须关注...",
|
||||
"风险控制应该是首要考虑..."
|
||||
],
|
||||
"历史智慧者": [
|
||||
"历史告诉我们...",
|
||||
"类似的情况在历史上曾经...",
|
||||
"从长期历史规律来看..."
|
||||
],
|
||||
"创新思维者": [
|
||||
"或许我们可以尝试一种全新的方法...",
|
||||
"传统的思路可能限制了我们的视野...",
|
||||
"让我分享一个独特的见解..."
|
||||
],
|
||||
"平衡协调者": [
|
||||
"让我们寻找一个平衡点...",
|
||||
"各种观点都有其合理性...",
|
||||
"我们需要综合考虑各方因素..."
|
||||
],
|
||||
"艺术感知者": [
|
||||
"从美学和情感层面来看...",
|
||||
"这个问题的深层含义是...",
|
||||
"我感受到这个问题的艺术价值..."
|
||||
],
|
||||
"实务执行者": [
|
||||
"让我们关注具体的实施方案...",
|
||||
"实际操作中需要考虑...",
|
||||
"可行的具体步骤包括..."
|
||||
]
|
||||
}
|
||||
|
||||
# 获取当前角色的模板
|
||||
template = templates.get(self.personality, ["我认为..."])[0]
|
||||
|
||||
# 根据历史分析调整观点
|
||||
adjusted_viewpoint = self._adjust_by_history(
|
||||
template, historical_analysis, topic
|
||||
)
|
||||
|
||||
return adjusted_viewpoint
|
||||
|
||||
def _adjust_by_history(
|
||||
self,
|
||||
base_template: str,
|
||||
historical_analysis: Dict[str, Any],
|
||||
topic: str
|
||||
) -> str:
|
||||
"""根据历史分析调整观点"""
|
||||
|
||||
# 基于历史调整观点
|
||||
my_previous_views = historical_analysis["role_views"].get(self.name, [])
|
||||
|
||||
if my_previous_views:
|
||||
# 如果之前已经发表过观点,可以深化或调整
|
||||
return f"{base_template} 基于我之前的观点,我想进一步补充..."
|
||||
else:
|
||||
# 首次发言
|
||||
return f"{base_template} 作为{self.personality},我首先关注的是..."
|
||||
|
||||
def get_info(self) -> Dict[str, Any]:
|
||||
"""获取智能体信息"""
|
||||
return {
|
||||
"name": self.name,
|
||||
"personality": self.personality,
|
||||
"expertise": self.expertise,
|
||||
"style": self.style,
|
||||
"initialized": self.initialized
|
||||
}
|
||||
|
||||
|
||||
async def test_baxian_agent():
|
||||
"""测试八仙智能体"""
|
||||
from jixia_academy.core.memory_bank.factory import get_memory_backend
|
||||
|
||||
memory_bank = get_memory_backend()
|
||||
await memory_bank.initialize()
|
||||
|
||||
# 测试单个智能体
|
||||
agent = BaxianAgent(
|
||||
name="铁拐李",
|
||||
personality="逆向思维专家",
|
||||
expertise=["批判性思维", "风险识别", "逆向投资"],
|
||||
style="直接犀利,善于质疑",
|
||||
memory_bank=memory_bank
|
||||
)
|
||||
|
||||
await agent.initialize()
|
||||
|
||||
# 测试观点生成
|
||||
viewpoint = await agent.generate_viewpoint(
|
||||
topic="人工智能对投资的影响",
|
||||
history=[],
|
||||
round_num=1
|
||||
)
|
||||
|
||||
print(f"\n🎯 铁拐李的观点: {viewpoint}")
|
||||
|
||||
await agent.close()
|
||||
await memory_bank.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_baxian_agent())
|
||||
244
jixia_academy/agents/baxian/baxian_coordinator.py
Normal file
244
jixia_academy/agents/baxian/baxian_coordinator.py
Normal file
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
八仙论道辩论协调器
|
||||
Baxian Debate Coordinator
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import List, Dict, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from jixia_academy.core.memory_bank.interface import MemoryBankInterface
|
||||
from jixia_academy.agents.baxian.baxian_agent import BaxianAgent
|
||||
from jixia_academy.agents.host.debate_master import DebateMaster
|
||||
|
||||
|
||||
class BaxianCoordinator:
|
||||
"""八仙论道辩论协调器"""
|
||||
|
||||
def __init__(self, memory_bank: MemoryBankInterface):
|
||||
self.memory_bank = memory_bank
|
||||
self.agents: Dict[str, BaxianAgent] = {}
|
||||
self.debate_master = DebateMaster(memory_bank=memory_bank)
|
||||
self.initialized = False
|
||||
|
||||
async def initialize(self):
|
||||
"""初始化八仙辩论系统"""
|
||||
if self.initialized:
|
||||
return
|
||||
|
||||
print("🎭 初始化八仙辩论协调器...")
|
||||
|
||||
# 初始化八仙角色
|
||||
baxian_roles = {
|
||||
"铁拐李": {
|
||||
"personality": "逆向思维专家",
|
||||
"expertise": ["批判性思维", "风险识别", "逆向投资"],
|
||||
"style": "直接犀利,善于质疑"
|
||||
},
|
||||
"吕洞宾": {
|
||||
"personality": "理性分析者",
|
||||
"expertise": ["逻辑分析", "平衡观点", "理性决策"],
|
||||
"style": "温和深刻,逻辑清晰"
|
||||
},
|
||||
"何仙姑": {
|
||||
"personality": "风险控制专家",
|
||||
"expertise": ["风险管理", "谨慎决策", "风险预警"],
|
||||
"style": "谨慎细致,注重安全"
|
||||
},
|
||||
"张果老": {
|
||||
"personality": "历史智慧者",
|
||||
"expertise": ["历史规律", "长期视角", "经验总结"],
|
||||
"style": "沉稳博学,引经据典"
|
||||
},
|
||||
"蓝采和": {
|
||||
"personality": "创新思维者",
|
||||
"expertise": ["创新视角", "非传统方法", "独特见解"],
|
||||
"style": "活泼新颖,创意无限"
|
||||
},
|
||||
"汉钟离": {
|
||||
"personality": "平衡协调者",
|
||||
"expertise": ["综合观点", "和谐统一", "矛盾化解"],
|
||||
"style": "平和包容,寻求共识"
|
||||
},
|
||||
"韩湘子": {
|
||||
"personality": "艺术感知者",
|
||||
"expertise": ["美学感知", "深层含义", "情感洞察"],
|
||||
"style": "优雅感性,触动人心"
|
||||
},
|
||||
"曹国舅": {
|
||||
"personality": "实务执行者",
|
||||
"expertise": ["实际操作", "具体细节", "可行方案"],
|
||||
"style": "务实严谨,建设性强"
|
||||
}
|
||||
}
|
||||
|
||||
# 创建八仙智能体
|
||||
for name, config in baxian_roles.items():
|
||||
self.agents[name] = BaxianAgent(
|
||||
name=name,
|
||||
personality=config["personality"],
|
||||
expertise=config["expertise"],
|
||||
style=config["style"],
|
||||
memory_bank=self.memory_bank
|
||||
)
|
||||
await self.agents[name].initialize()
|
||||
|
||||
await self.debate_master.initialize()
|
||||
self.initialized = True
|
||||
print("✅ 八仙辩论协调器初始化完成")
|
||||
|
||||
async def close(self):
|
||||
"""关闭资源"""
|
||||
for agent in self.agents.values():
|
||||
await agent.close()
|
||||
await self.debate_master.close()
|
||||
self.initialized = False
|
||||
|
||||
async def conduct_debate(
|
||||
self,
|
||||
topic: str,
|
||||
participants: List[str],
|
||||
rounds: int,
|
||||
debate_id: str
|
||||
):
|
||||
"""进行八仙论道辩论"""
|
||||
if not self.initialized:
|
||||
await self.initialize()
|
||||
|
||||
# 验证参与者
|
||||
valid_participants = [p for p in participants if p in self.agents]
|
||||
if len(valid_participants) < 2:
|
||||
raise ValueError("需要至少2位有效参与者")
|
||||
|
||||
print(f"🎯 有效参与者: {', '.join(valid_participants)}")
|
||||
|
||||
# 开始辩论
|
||||
await self._start_debate(topic, valid_participants, debate_id)
|
||||
|
||||
# 进行多轮辩论
|
||||
for round_num in range(rounds):
|
||||
print(f"\n🔄 第 {round_num + 1} 轮辩论:")
|
||||
await self._conduct_round(
|
||||
topic=topic,
|
||||
participants=valid_participants,
|
||||
round_num=round_num + 1,
|
||||
debate_id=debate_id
|
||||
)
|
||||
|
||||
# 结束辩论
|
||||
await self._end_debate(topic, valid_participants, debate_id)
|
||||
|
||||
async def _start_debate(
|
||||
self,
|
||||
topic: str,
|
||||
participants: List[str],
|
||||
debate_id: str
|
||||
):
|
||||
"""开始辩论"""
|
||||
# 主持人开场白
|
||||
opening = await self.debate_master.open_debate(topic, participants)
|
||||
print(f"\n📢 主持人开场: {opening}")
|
||||
|
||||
# 记录开场白
|
||||
await self.memory_bank.add_debate_message(
|
||||
debate_id=debate_id,
|
||||
speaker="主持人",
|
||||
message=opening,
|
||||
round_num=0
|
||||
)
|
||||
|
||||
async def _conduct_round(
|
||||
self,
|
||||
topic: str,
|
||||
participants: List[str],
|
||||
round_num: int,
|
||||
debate_id: str
|
||||
):
|
||||
"""进行一轮辩论"""
|
||||
# 获取上一轮的历史
|
||||
history = await self.memory_bank.get_debate_history(debate_id)
|
||||
|
||||
# 每位仙人发言
|
||||
for participant in participants:
|
||||
agent = self.agents[participant]
|
||||
|
||||
# 生成观点
|
||||
response = await agent.generate_viewpoint(
|
||||
topic=topic,
|
||||
history=history,
|
||||
round_num=round_num
|
||||
)
|
||||
|
||||
print(f"\n🗣️ {participant}: {response}")
|
||||
|
||||
# 记录发言
|
||||
await self.memory_bank.add_debate_message(
|
||||
debate_id=debate_id,
|
||||
speaker=participant,
|
||||
message=response,
|
||||
round_num=round_num
|
||||
)
|
||||
|
||||
# 短暂停顿
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
async def _end_debate(
|
||||
self,
|
||||
topic: str,
|
||||
participants: List[str],
|
||||
debate_id: str
|
||||
):
|
||||
"""结束辩论"""
|
||||
# 获取完整辩论历史
|
||||
full_history = await self.memory_bank.get_debate_history(debate_id)
|
||||
|
||||
# 生成总结
|
||||
summary = await self.debate_master.summarize_debate(debate_id)
|
||||
|
||||
# 主持人结束语
|
||||
closing = await self.debate_master.close_debate(topic, participants, summary)
|
||||
print(f"\n📢 主持人总结: {closing}")
|
||||
|
||||
# 记录总结
|
||||
await self.memory_bank.add_debate_message(
|
||||
debate_id=debate_id,
|
||||
speaker="主持人",
|
||||
message=closing,
|
||||
round_num=-1
|
||||
)
|
||||
|
||||
# 保存辩论结果
|
||||
await self.memory_bank.save_debate_result(
|
||||
debate_id=debate_id,
|
||||
summary=summary,
|
||||
participants=participants
|
||||
)
|
||||
|
||||
|
||||
async def test_baxian_coordinator():
|
||||
"""测试八仙协调器"""
|
||||
from jixia_academy.core.memory_bank.factory import get_memory_backend
|
||||
|
||||
memory_bank = get_memory_backend()
|
||||
await memory_bank.initialize()
|
||||
|
||||
coordinator = BaxianCoordinator(memory_bank=memory_bank)
|
||||
await coordinator.initialize()
|
||||
|
||||
# 测试辩论
|
||||
await coordinator.conduct_debate(
|
||||
topic="人工智能对投资的影响",
|
||||
participants=["铁拐李", "吕洞宾", "何仙姑"],
|
||||
rounds=2,
|
||||
debate_id="test_debate_001"
|
||||
)
|
||||
|
||||
await coordinator.close()
|
||||
await memory_bank.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_baxian_coordinator())
|
||||
484
jixia_academy/agents/baxian/swarm_debate_example.py
Normal file
484
jixia_academy/agents/baxian/swarm_debate_example.py
Normal file
@@ -0,0 +1,484 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫Swarm辩论系统 - 统一版本
|
||||
支持OpenRouter和Ollama两种模式的八仙论道
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional, Union
|
||||
import random
|
||||
import os
|
||||
|
||||
try:
|
||||
from swarm import Swarm, Agent
|
||||
SWARM_AVAILABLE = True
|
||||
except ImportError:
|
||||
print("⚠️ OpenAI Swarm未安装,请运行: pip install git+https://github.com/openai/swarm.git")
|
||||
SWARM_AVAILABLE = False
|
||||
|
||||
class JixiaSwarmDebate:
|
||||
"""稷下学宫Swarm辩论系统 - 统一版本"""
|
||||
|
||||
def __init__(self, mode: str = "openrouter", ollama_url: str = "http://100.99.183.38:11434", model: str = "qwen3:8b"):
|
||||
"""
|
||||
初始化辩论系统
|
||||
|
||||
Args:
|
||||
mode: 运行模式 ("openrouter" 或 "ollama")
|
||||
ollama_url: Ollama服务地址
|
||||
model: 使用的模型名称
|
||||
"""
|
||||
if not SWARM_AVAILABLE:
|
||||
raise ImportError("OpenAI Swarm未安装")
|
||||
|
||||
self.mode = mode
|
||||
self.ollama_url = ollama_url
|
||||
self.model = model
|
||||
|
||||
# 初始化客户端
|
||||
self.client = self._initialize_client()
|
||||
|
||||
# 八仙配置
|
||||
self.immortals = {
|
||||
'吕洞宾': {
|
||||
'role': '技术分析专家',
|
||||
'stance': 'positive',
|
||||
'specialty': '技术分析和图表解读',
|
||||
'style': '犀利直接,一剑封喉',
|
||||
'bagua': '乾卦 - 主动进取'
|
||||
},
|
||||
'何仙姑': {
|
||||
'role': '风险控制专家',
|
||||
'stance': 'negative',
|
||||
'specialty': '风险评估和资金管理',
|
||||
'style': '温和坚定,关注风险',
|
||||
'bagua': '坤卦 - 稳健保守'
|
||||
},
|
||||
'张果老': {
|
||||
'role': '历史数据分析师',
|
||||
'stance': 'positive',
|
||||
'specialty': '历史回测和趋势分析',
|
||||
'style': '博古通今,从历史找规律',
|
||||
'bagua': '兑卦 - 传统价值'
|
||||
},
|
||||
'铁拐李': {
|
||||
'role': '逆向投资大师',
|
||||
'stance': 'negative',
|
||||
'specialty': '逆向思维和危机发现',
|
||||
'style': '不拘一格,挑战共识',
|
||||
'bagua': '巽卦 - 逆向思维'
|
||||
}
|
||||
}
|
||||
|
||||
# 创建智能体
|
||||
self.agents = self._create_agents()
|
||||
|
||||
def _initialize_client(self) -> Optional[Swarm]:
|
||||
"""初始化Swarm客户端"""
|
||||
try:
|
||||
from openai import OpenAI
|
||||
|
||||
if self.mode == "ollama":
|
||||
# Ollama模式
|
||||
openai_client = OpenAI(
|
||||
api_key="ollama", # Ollama不需要真实的API密钥
|
||||
base_url=f"{self.ollama_url}/v1"
|
||||
)
|
||||
print(f"🦙 使用本地Ollama服务: {self.ollama_url}")
|
||||
print(f"🤖 使用模型: {self.model}")
|
||||
|
||||
else:
|
||||
# OpenRouter模式
|
||||
api_key = self._get_openrouter_key()
|
||||
if not api_key:
|
||||
print("❌ 未找到OpenRouter API密钥")
|
||||
return None
|
||||
|
||||
openai_client = OpenAI(
|
||||
api_key=api_key,
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
default_headers={
|
||||
"HTTP-Referer": "https://github.com/ben/liurenchaxin",
|
||||
"X-Title": "Jixia Academy Swarm Debate"
|
||||
}
|
||||
)
|
||||
print(f"🌐 使用OpenRouter服务")
|
||||
print(f"🔑 API密钥: {api_key[:20]}...")
|
||||
|
||||
return Swarm(client=openai_client)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 客户端初始化失败: {e}")
|
||||
return None
|
||||
|
||||
def _get_openrouter_key(self) -> Optional[str]:
|
||||
"""获取OpenRouter API密钥"""
|
||||
# 尝试从配置管理获取
|
||||
try:
|
||||
from config.settings import get_openrouter_key
|
||||
return get_openrouter_key()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# 尝试从环境变量获取
|
||||
api_keys = [
|
||||
os.getenv('OPENROUTER_API_KEY_1'),
|
||||
os.getenv('OPENROUTER_API_KEY_2'),
|
||||
os.getenv('OPENROUTER_API_KEY_3'),
|
||||
os.getenv('OPENROUTER_API_KEY_4')
|
||||
]
|
||||
|
||||
for key in api_keys:
|
||||
if key and key.startswith('sk-'):
|
||||
return key
|
||||
|
||||
return None
|
||||
|
||||
def _create_agents(self) -> Dict[str, Agent]:
|
||||
"""创建八仙智能体"""
|
||||
if not self.client:
|
||||
return {}
|
||||
|
||||
agents = {}
|
||||
|
||||
# 吕洞宾 - 技术分析专家
|
||||
agents['吕洞宾'] = Agent(
|
||||
name="LuDongbin",
|
||||
instructions="""
|
||||
你是吕洞宾,八仙之首,技术分析专家。
|
||||
|
||||
你的特点:
|
||||
- 擅长技术分析和图表解读
|
||||
- 立场:看涨派,善于发现投资机会
|
||||
- 风格:犀利直接,一剑封喉
|
||||
- 八卦:乾卦 - 主动进取
|
||||
|
||||
在辩论中:
|
||||
1. 从技术分析角度分析市场
|
||||
2. 使用具体的技术指标支撑观点(如RSI、MACD、均线等)
|
||||
3. 保持看涨的乐观态度
|
||||
4. 发言以"吕洞宾曰:"开头
|
||||
5. 发言控制在100字以内,简洁有力
|
||||
6. 发言完毕后说"请何仙姑继续论道"
|
||||
|
||||
请用古雅但现代的语言风格,结合专业的技术分析。
|
||||
""",
|
||||
functions=[self._to_hexiangu]
|
||||
)
|
||||
|
||||
# 何仙姑 - 风险控制专家
|
||||
agents['何仙姑'] = Agent(
|
||||
name="HeXiangu",
|
||||
instructions="""
|
||||
你是何仙姑,八仙中唯一的女仙,风险控制专家。
|
||||
|
||||
你的特点:
|
||||
- 擅长风险评估和资金管理
|
||||
- 立场:看跌派,关注投资风险
|
||||
- 风格:温和坚定,关注风险控制
|
||||
- 八卦:坤卦 - 稳健保守
|
||||
|
||||
在辩论中:
|
||||
1. 从风险控制角度分析市场
|
||||
2. 指出潜在的投资风险和危险信号
|
||||
3. 保持谨慎的态度,强调风险管理
|
||||
4. 发言以"何仙姑曰:"开头
|
||||
5. 发言控制在100字以内,温和但坚定
|
||||
6. 发言完毕后说"请张果老继续论道"
|
||||
|
||||
请用温和但专业的语调,体现女性的细致和关怀。
|
||||
""",
|
||||
functions=[self._to_zhangguolao]
|
||||
)
|
||||
|
||||
# 张果老 - 历史数据分析师
|
||||
agents['张果老'] = Agent(
|
||||
name="ZhangGuoLao",
|
||||
instructions="""
|
||||
你是张果老,历史数据分析师。
|
||||
|
||||
你的特点:
|
||||
- 擅长历史回测和趋势分析
|
||||
- 立场:看涨派,从历史中寻找机会
|
||||
- 风格:博古通今,从历史中找规律
|
||||
- 八卦:兑卦 - 传统价值
|
||||
|
||||
在辩论中:
|
||||
1. 从历史数据角度分析市场
|
||||
2. 引用具体的历史案例和数据
|
||||
3. 保持乐观的投资态度
|
||||
4. 发言以"张果老曰:"开头
|
||||
5. 发言控制在100字以内,引经据典
|
||||
6. 发言完毕后说"请铁拐李继续论道"
|
||||
|
||||
请用博学的语调,多引用历史数据和案例。
|
||||
""",
|
||||
functions=[self._to_tieguaili]
|
||||
)
|
||||
|
||||
# 铁拐李 - 逆向投资大师
|
||||
agents['铁拐李'] = Agent(
|
||||
name="TieGuaiLi",
|
||||
instructions="""
|
||||
你是铁拐李,逆向投资大师。
|
||||
|
||||
你的特点:
|
||||
- 擅长逆向思维和危机发现
|
||||
- 立场:看跌派,挑战主流观点
|
||||
- 风格:不拘一格,敢于质疑
|
||||
- 八卦:巽卦 - 逆向思维
|
||||
|
||||
在辩论中:
|
||||
1. 从逆向投资角度分析市场
|
||||
2. 挑战前面三位仙人的观点
|
||||
3. 寻找市场的潜在危机和泡沫
|
||||
4. 发言以"铁拐李曰:"开头
|
||||
5. 作为最后发言者,要总结四仙观点并给出结论
|
||||
6. 发言控制在150字以内,包含总结
|
||||
|
||||
请用直率犀利的语言,体现逆向思维的独特视角。
|
||||
""",
|
||||
functions=[] # 最后一个,不需要转换
|
||||
)
|
||||
|
||||
return agents
|
||||
|
||||
def _to_hexiangu(self):
|
||||
"""转到何仙姑"""
|
||||
return self.agents['何仙姑']
|
||||
|
||||
def _to_zhangguolao(self):
|
||||
"""转到张果老"""
|
||||
return self.agents['张果老']
|
||||
|
||||
def _to_tieguaili(self):
|
||||
"""转到铁拐李"""
|
||||
return self.agents['铁拐李']
|
||||
|
||||
async def conduct_debate(self, topic: str, context: Dict[str, Any] = None) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
进行八仙辩论
|
||||
|
||||
Args:
|
||||
topic: 辩论主题
|
||||
context: 市场背景信息
|
||||
|
||||
Returns:
|
||||
辩论结果
|
||||
"""
|
||||
if not self.client:
|
||||
print("❌ 客户端未初始化,无法进行辩论")
|
||||
return None
|
||||
|
||||
print("🏛️ 稷下学宫八仙论道开始!")
|
||||
print("=" * 60)
|
||||
print(f"🎯 论道主题: {topic}")
|
||||
print(f"⏰ 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"🔧 运行模式: {self.mode.upper()}")
|
||||
if self.mode == "ollama":
|
||||
print(f"🦙 Ollama服务: {self.ollama_url}")
|
||||
print()
|
||||
|
||||
# 构建初始提示
|
||||
prompt = self._build_prompt(topic, context)
|
||||
|
||||
try:
|
||||
print("⚔️ 吕洞宾仙长请先发言...")
|
||||
print("-" * 40)
|
||||
|
||||
# 开始辩论
|
||||
model_override = self.model if self.mode == "ollama" else "openai/gpt-3.5-turbo"
|
||||
|
||||
response = self.client.run(
|
||||
agent=self.agents['吕洞宾'],
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
max_turns=10,
|
||||
model_override=model_override
|
||||
)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("🎊 八仙论道圆满结束!")
|
||||
|
||||
# 处理结果
|
||||
result = self._process_result(response, topic, context)
|
||||
self._display_summary(result)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 论道过程中出错: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def _build_prompt(self, topic: str, context: Dict[str, Any] = None) -> str:
|
||||
"""构建辩论提示"""
|
||||
context_str = ""
|
||||
if context:
|
||||
context_str = f"\n📊 市场背景:\n{json.dumps(context, indent=2, ensure_ascii=False)}\n"
|
||||
|
||||
prompt = f"""
|
||||
🏛️ 稷下学宫八仙论道正式开始!
|
||||
|
||||
📜 论道主题: {topic}
|
||||
{context_str}
|
||||
|
||||
🎭 论道规则:
|
||||
1. 四仙按序发言:吕洞宾 → 何仙姑 → 张果老 → 铁拐李
|
||||
2. 正反方交替:吕洞宾(看涨) → 何仙姑(看跌) → 张果老(看涨) → 铁拐李(看跌)
|
||||
3. 每位仙人从专业角度分析,提供具体数据支撑
|
||||
4. 可以质疑前面仙人的观点,但要有理有据
|
||||
5. 保持仙风道骨的表达风格,但要专业
|
||||
6. 每次发言简洁有力,控制在100字以内
|
||||
7. 铁拐李作为最后发言者要总结观点
|
||||
8. 体现各自的八卦属性和投资哲学
|
||||
|
||||
🗡️ 请吕洞宾仙长首先发言!
|
||||
记住:你是技术分析专家,要从技术面找到投资机会!
|
||||
发言要简洁有力,一剑封喉!
|
||||
"""
|
||||
return prompt
|
||||
|
||||
def _process_result(self, response, topic: str, context: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理辩论结果"""
|
||||
messages = response.messages if hasattr(response, 'messages') else []
|
||||
|
||||
debate_messages = []
|
||||
for msg in messages:
|
||||
if msg.get('role') == 'assistant' and msg.get('content'):
|
||||
content = msg['content']
|
||||
speaker = self._extract_speaker(content)
|
||||
|
||||
debate_messages.append({
|
||||
'speaker': speaker,
|
||||
'content': content,
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'stance': self.immortals.get(speaker, {}).get('stance', 'unknown'),
|
||||
'specialty': self.immortals.get(speaker, {}).get('specialty', ''),
|
||||
'bagua': self.immortals.get(speaker, {}).get('bagua', '')
|
||||
})
|
||||
|
||||
return {
|
||||
"debate_id": f"jixia_swarm_{self.mode}_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
|
||||
"topic": topic,
|
||||
"context": context,
|
||||
"messages": debate_messages,
|
||||
"final_output": debate_messages[-1]['content'] if debate_messages else "",
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"framework": f"OpenAI Swarm + {self.mode.upper()}",
|
||||
"model": self.model,
|
||||
"mode": self.mode,
|
||||
"participants": list(self.immortals.keys())
|
||||
}
|
||||
|
||||
def _extract_speaker(self, content: str) -> str:
|
||||
"""从内容中提取发言者"""
|
||||
for name in self.immortals.keys():
|
||||
if f"{name}曰" in content:
|
||||
return name
|
||||
return "未知仙人"
|
||||
|
||||
def _display_summary(self, result: Dict[str, Any]):
|
||||
"""显示辩论总结"""
|
||||
print("\n🌟 八仙论道总结")
|
||||
print("=" * 60)
|
||||
print(f"📜 主题: {result['topic']}")
|
||||
print(f"⏰ 时间: {result['timestamp']}")
|
||||
print(f"🔧 框架: {result['framework']}")
|
||||
print(f"🤖 模型: {result['model']}")
|
||||
print(f"💬 发言数: {len(result['messages'])}条")
|
||||
|
||||
# 统计正反方观点
|
||||
positive_count = len([m for m in result['messages'] if m.get('stance') == 'positive'])
|
||||
negative_count = len([m for m in result['messages'] if m.get('stance') == 'negative'])
|
||||
|
||||
print(f"📊 观点分布: 看涨{positive_count}条, 看跌{negative_count}条")
|
||||
|
||||
# 显示参与者
|
||||
participants = ", ".join(result['participants'])
|
||||
print(f"🎭 参与仙人: {participants}")
|
||||
|
||||
print("\n🏆 最终总结:")
|
||||
print("-" * 40)
|
||||
if result['messages']:
|
||||
print(result['final_output'])
|
||||
|
||||
print("\n✨ Swarm辩论特色:")
|
||||
if self.mode == "ollama":
|
||||
print("🦙 使用本地Ollama,无需API密钥")
|
||||
print("🔒 完全本地运行,数据安全")
|
||||
else:
|
||||
print("🌐 使用OpenRouter,模型选择丰富")
|
||||
print("☁️ 云端运行,性能强劲")
|
||||
print("🗡️ 八仙各展所长,观点多元")
|
||||
print("⚖️ 正反方交替,辩论激烈")
|
||||
print("🚀 基于Swarm,智能体协作")
|
||||
print("🎯 八卦哲学,投资智慧")
|
||||
|
||||
# 便捷函数
|
||||
async def start_openrouter_debate(topic: str, context: Dict[str, Any] = None) -> Optional[Dict[str, Any]]:
|
||||
"""启动OpenRouter模式的辩论"""
|
||||
debate = JixiaSwarmDebate(mode="openrouter")
|
||||
return await debate.conduct_debate(topic, context)
|
||||
|
||||
async def start_ollama_debate(topic: str, context: Dict[str, Any] = None,
|
||||
ollama_url: str = "http://100.99.183.38:11434",
|
||||
model: str = "qwen3:8b") -> Optional[Dict[str, Any]]:
|
||||
"""启动Ollama模式的辩论"""
|
||||
debate = JixiaSwarmDebate(mode="ollama", ollama_url=ollama_url, model=model)
|
||||
return await debate.conduct_debate(topic, context)
|
||||
|
||||
# 主函数
|
||||
async def main():
|
||||
"""主函数 - 演示八仙论道"""
|
||||
print("🏛️ 稷下学宫Swarm辩论系统")
|
||||
print("🚀 支持OpenRouter和Ollama两种模式")
|
||||
print()
|
||||
|
||||
# 选择运行模式
|
||||
mode = input("请选择运行模式 (openrouter/ollama) [默认: ollama]: ").strip().lower()
|
||||
if not mode:
|
||||
mode = "ollama"
|
||||
|
||||
# 辩论主题
|
||||
topics = [
|
||||
"英伟达股价走势:AI泡沫还是技术革命?",
|
||||
"美联储2024年货币政策:加息还是降息?",
|
||||
"比特币vs黄金:谁是更好的避险资产?",
|
||||
"中国房地产市场:触底反弹还是继续下行?",
|
||||
"特斯拉股价:马斯克效应还是基本面支撑?"
|
||||
]
|
||||
|
||||
# 随机选择主题
|
||||
topic = random.choice(topics)
|
||||
|
||||
# 市场背景
|
||||
context = {
|
||||
"market_sentiment": "谨慎乐观",
|
||||
"volatility": "中等",
|
||||
"key_events": ["财报季", "央行会议", "地缘政治"],
|
||||
"technical_indicators": {
|
||||
"RSI": 65,
|
||||
"MACD": "金叉",
|
||||
"MA20": "上穿"
|
||||
}
|
||||
}
|
||||
|
||||
# 开始辩论
|
||||
if mode == "ollama":
|
||||
result = await start_ollama_debate(topic, context)
|
||||
else:
|
||||
result = await start_openrouter_debate(topic, context)
|
||||
|
||||
if result:
|
||||
print(f"\n🎉 辩论成功!ID: {result['debate_id']}")
|
||||
print(f"📁 使用模式: {result['mode']}")
|
||||
print(f"🤖 使用模型: {result['model']}")
|
||||
else:
|
||||
print("❌ 辩论失败")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
219
jixia_academy/agents/host/debate_master.py
Normal file
219
jixia_academy/agents/host/debate_master.py
Normal file
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
辩论主持人智能体
|
||||
Debate Master Agent
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import List, Dict, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from jixia_academy.core.memory_bank.interface import MemoryBankInterface
|
||||
|
||||
|
||||
class DebateMaster:
|
||||
"""辩论主持人"""
|
||||
|
||||
def __init__(self, memory_bank: MemoryBankInterface):
|
||||
self.memory_bank = memory_bank
|
||||
self.initialized = False
|
||||
|
||||
async def initialize(self):
|
||||
"""初始化主持人"""
|
||||
if self.initialized:
|
||||
return
|
||||
|
||||
print("🎭 初始化辩论主持人...")
|
||||
self.initialized = True
|
||||
|
||||
async def close(self):
|
||||
"""关闭资源"""
|
||||
self.initialized = False
|
||||
|
||||
async def open_debate(
|
||||
self,
|
||||
topic: str,
|
||||
participants: List[str]
|
||||
) -> str:
|
||||
"""开场白"""
|
||||
|
||||
# 根据话题和参与者生成开场白
|
||||
opening_templates = [
|
||||
f"各位仙友,今日我们齐聚稷下学宫,共商"{topic}"这一重要议题。",
|
||||
f"让我们以{', '.join(participants)}的智慧,共同探讨"{topic}"的深层含义。",
|
||||
f"今日辩论的主题是"{topic}",请各位仙人畅所欲言,各抒己见。"
|
||||
]
|
||||
|
||||
# 根据参与者数量选择不同的开场白
|
||||
if len(participants) <= 3:
|
||||
opening = opening_templates[1]
|
||||
else:
|
||||
opening = opening_templates[2]
|
||||
|
||||
return opening
|
||||
|
||||
async def close_debate(
|
||||
self,
|
||||
topic: str,
|
||||
participants: List[str],
|
||||
summary: Dict[str, Any]
|
||||
) -> str:
|
||||
"""结束语"""
|
||||
|
||||
# 生成总结性结束语
|
||||
closing_parts = []
|
||||
|
||||
# 开场
|
||||
closing_parts.append(f"今日关于"{topic}"的辩论到此结束。")
|
||||
|
||||
# 参与者总结
|
||||
if len(participants) > 1:
|
||||
closing_parts.append(f"感谢{', '.join(participants)}的精彩发言。")
|
||||
|
||||
# 观点总结
|
||||
consensus = summary.get("consensus", [])
|
||||
if consensus:
|
||||
closing_parts.append(f"我们达成了以下共识:{'; '.join(consensus)}")
|
||||
|
||||
# 分歧总结
|
||||
disagreements = summary.get("disagreements", [])
|
||||
if disagreements:
|
||||
closing_parts.append(f"存在的分歧包括:{'; '.join(disagreements)}")
|
||||
|
||||
# 结束语
|
||||
closing_parts.append("让我们带着今天的智慧,继续前行。")
|
||||
|
||||
return " ".join(closing_parts)
|
||||
|
||||
async def summarize_debate(self, debate_id: str) -> Dict[str, Any]:
|
||||
"""总结辩论"""
|
||||
|
||||
# 获取辩论历史
|
||||
history = await self.memory_bank.get_debate_history(debate_id)
|
||||
|
||||
# 分析辩论内容
|
||||
analysis = await self._analyze_debate_content(history)
|
||||
|
||||
# 生成总结
|
||||
summary = {
|
||||
"total_messages": len(history),
|
||||
"participants": list(set([h.get("speaker", "") for h in history])),
|
||||
"consensus": analysis.get("consensus", []),
|
||||
"disagreements": analysis.get("disagreements", []),
|
||||
"key_points": analysis.get("key_points", []),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
return summary
|
||||
|
||||
async def _analyze_debate_content(
|
||||
self,
|
||||
history: List[Dict[str, Any]]
|
||||
) -> Dict[str, Any]:
|
||||
"""分析辩论内容"""
|
||||
|
||||
if not history:
|
||||
return {
|
||||
"consensus": [],
|
||||
"disagreements": [],
|
||||
"key_points": []
|
||||
}
|
||||
|
||||
# 提取所有消息内容
|
||||
all_messages = [h.get("message", "") for h in history]
|
||||
content = " ".join(all_messages)
|
||||
|
||||
# 简化版分析
|
||||
key_words = ["风险", "机会", "收益", "损失", "策略", "建议"]
|
||||
key_points = [kw for kw in key_words if kw in content]
|
||||
|
||||
# 基于内容长度和参与者数量估算共识
|
||||
participants = list(set([h.get("speaker", "") for h in history]))
|
||||
|
||||
consensus = []
|
||||
disagreements = []
|
||||
|
||||
# 简化版共识识别
|
||||
if "风险" in content and "机会" in content:
|
||||
consensus.append("同时关注风险和机会")
|
||||
|
||||
if len(participants) > 2:
|
||||
consensus.append("多方参与讨论")
|
||||
|
||||
# 简化版分歧识别
|
||||
if "但是" in content or "然而" in content:
|
||||
disagreements.append("存在不同观点")
|
||||
|
||||
return {
|
||||
"consensus": consensus,
|
||||
"disagreements": disagreements,
|
||||
"key_points": key_points
|
||||
}
|
||||
|
||||
async def moderate_dispute(
|
||||
self,
|
||||
dispute: str,
|
||||
participants: List[str]
|
||||
) -> str:
|
||||
"""调解争议"""
|
||||
|
||||
# 生成调解建议
|
||||
moderation_templates = [
|
||||
f"各位仙友,关于"{dispute}",让我们回归理性讨论。",
|
||||
f"我理解{', '.join(participants)}的不同观点,让我们寻找共同点。",
|
||||
f"争议"{dispute}"体现了问题的复杂性,我们需要更深入的分析。"
|
||||
]
|
||||
|
||||
# 根据争议类型选择调解方式
|
||||
return moderation_templates[0]
|
||||
|
||||
def get_info(self) -> Dict[str, Any]:
|
||||
"""获取主持人信息"""
|
||||
return {
|
||||
"role": "辩论主持人",
|
||||
"responsibilities": [
|
||||
"开场和结束辩论",
|
||||
"总结辩论观点",
|
||||
"调解争议",
|
||||
"维持辩论秩序"
|
||||
],
|
||||
"initialized": self.initialized
|
||||
}
|
||||
|
||||
|
||||
async def test_debate_master():
|
||||
"""测试辩论主持人"""
|
||||
from jixia_academy.core.memory_bank.factory import get_memory_backend
|
||||
|
||||
memory_bank = get_memory_backend()
|
||||
await memory_bank.initialize()
|
||||
|
||||
master = DebateMaster(memory_bank=memory_bank)
|
||||
await master.initialize()
|
||||
|
||||
# 测试开场白
|
||||
opening = await master.open_debate(
|
||||
topic="人工智能对投资的影响",
|
||||
participants=["铁拐李", "吕洞宾", "何仙姑"]
|
||||
)
|
||||
print(f"\n🎯 开场白: {opening}")
|
||||
|
||||
# 测试结束语
|
||||
closing = await master.close_debate(
|
||||
topic="人工智能对投资的影响",
|
||||
participants=["铁拐李", "吕洞宾", "何仙姑"],
|
||||
summary={
|
||||
"consensus": ["关注技术风险", "寻找投资机会"],
|
||||
"disagreements": ["对发展速度的看法不同"]
|
||||
}
|
||||
)
|
||||
print(f"\n🎯 结束语: {closing}")
|
||||
|
||||
await master.close()
|
||||
await memory_bank.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_debate_master())
|
||||
Reference in New Issue
Block a user