🏗️ 项目重构:模块化清理完成

This commit is contained in:
llama-research
2025-09-01 12:29:27 +00:00
parent ef7657101a
commit f9856c31e5
349 changed files with 41438 additions and 254 deletions

View File

@@ -0,0 +1,106 @@
{
"timestamp": "2025-08-02T17:01:29.400737",
"results": {
"吕洞宾": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 1.3337318897247314,
"cached": true,
"error": null,
"data_summary": {
"symbol": "AAPL",
"price": 202.38,
"change_percent": "-2.5004%"
}
},
"何仙姑": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 1.87269926071167,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"张果老": {
"success": true,
"api_used": "webull",
"response_time": 2.0619537830352783,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"韩湘子": {
"success": true,
"api_used": "webull",
"response_time": 1.681612253189087,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"汉钟离": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 2.100069761276245,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"蓝采和": {
"success": true,
"api_used": "webull",
"response_time": 2.9622411727905273,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"曹国舅": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 2.1098716259002686,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"铁拐李": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 0.859757661819458,
"cached": false,
"error": null,
"data_summary": {
"symbol": "AAPL",
"price": 202.38,
"change_percent": "-2.5004%"
}
}
},
"summary": {
"total_immortals": 8,
"successful_calls": 8,
"failed_calls": 0
}
}

View File

@@ -0,0 +1,106 @@
{
"timestamp": "2025-08-02T17:02:25.557362",
"results": {
"吕洞宾": {
"success": true,
"api_used": "webull",
"response_time": 1.8372488021850586,
"cached": true,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"何仙姑": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 2.010622262954712,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"张果老": {
"success": true,
"api_used": "webull",
"response_time": 3.3547699451446533,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"韩湘子": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 0.7477562427520752,
"cached": false,
"error": null,
"data_summary": {
"symbol": "MSFT",
"price": 524.11,
"change_percent": "-1.7601%"
}
},
"汉钟离": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 2.068232536315918,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"蓝采和": {
"success": true,
"api_used": "webull",
"response_time": 5.828888893127441,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"曹国舅": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 4.461008787155151,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"铁拐李": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 1.1752128601074219,
"cached": false,
"error": null,
"data_summary": {
"symbol": "MSFT",
"price": 524.11,
"change_percent": "-1.7601%"
}
}
},
"summary": {
"total_immortals": 8,
"successful_calls": 8,
"failed_calls": 0
}
}

View File

@@ -0,0 +1,106 @@
{
"timestamp": "2025-08-02T17:01:59.012217",
"results": {
"吕洞宾": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 0.7236087322235107,
"cached": true,
"error": null,
"data_summary": {
"symbol": "TSLA",
"price": 302.63,
"change_percent": "-1.8296%"
}
},
"何仙姑": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 1.7378709316253662,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"张果老": {
"success": true,
"api_used": "webull",
"response_time": 2.667297601699829,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"韩湘子": {
"success": true,
"api_used": "webull",
"response_time": 1.9658794403076172,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"汉钟离": {
"success": true,
"api_used": "yahoo_finance_15",
"response_time": 3.024261951446533,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"蓝采和": {
"success": true,
"api_used": "webull",
"response_time": 1.5434284210205078,
"cached": false,
"error": null,
"data_summary": {
"symbol": null,
"price": null,
"change_percent": null
}
},
"曹国舅": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 1.1568174362182617,
"cached": false,
"error": null,
"data_summary": {
"symbol": "TSLA",
"price": 302.63,
"change_percent": "-1.8296%"
}
},
"铁拐李": {
"success": true,
"api_used": "alpha_vantage",
"response_time": 1.3348329067230225,
"cached": false,
"error": null,
"data_summary": {
"symbol": "TSLA",
"price": 302.63,
"change_percent": "-1.8296%"
}
}
},
"summary": {
"total_immortals": 8,
"successful_calls": 8,
"failed_calls": 0
}
}

View 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()

View 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())

View File

@@ -0,0 +1,152 @@
{
"debate_id": "baxian_debate_20250822_105513",
"topic": "人工智能对未来社会的影响",
"model": "gemini-2.5-flash",
"rounds": 2,
"participants": [
"铁拐李",
"吕洞宾",
"何仙姑",
"蓝采和",
"韩湘子",
"曹国舅",
"张果老",
"钟离权"
],
"debate_history": [
{
"type": "opening",
"content": "\n今日稷下学宫八仙齐聚共同探讨「人工智能对未来社会的影响」这一重要议题。\n\n请各位仙人从自己的专业角度和人生阅历出发分享真知灼见。\n让我们通过思辨碰撞共同寻求智慧的火花。\n",
"timestamp": "2025-08-22T10:55:13.508099"
},
{
"type": "speech",
"round": 1,
"speaker": "铁拐李",
"content": "哼,人工智能对未来社会的影响?世人皆言其便利高效,我却要问:这所谓的“进步”,可曾有人真正审视过它潜在的“退步”?\n\n我们把决策权、思考力甚至核心价值都寄托于机器难道不怕这正是“作茧自缚”当所有系统都依赖于算法一旦出现漏洞、偏见或被恶意操控那将是何等巨大的系统性风险别只看到“智能”的光环更要看到它背后可能潜藏的“愚蠢”与“脆弱”。我倒要看看当人类的独立思考能力被侵蚀殆尽时这“智能”究竟是福是祸",
"timestamp": "2025-08-22T10:55:20.536612"
},
{
"type": "speech",
"round": 1,
"speaker": "吕洞宾",
"content": "铁拐李兄之忧虑,洞宾深以为然。系统性风险、决策权旁落,这些确实是我们在战略规划时不可忽视的潜在陷阱。然而,观其本质,人工智能并非一味洪水猛兽,而更像是一柄锋利却双刃的宝剑。它能助我们开山劈石,亦能不慎伤己。\n\n关键在于我们如何握持。若将其视为单纯的工具辅佐人类分析海量数据、优化复杂决策提升效率那便是人类智慧的延伸。正如炼丹术可造福苍生亦可祸乱人心其善恶并非术法本身而在施术者之意。我们当关注的是如何构建稳健的“人机协作”体系设立伦理边界与纠错机制而非因噎废食错失其解决人类诸多难题的巨大潜力。",
"timestamp": "2025-08-22T10:55:27.781309"
},
{
"type": "speech",
"round": 1,
"speaker": "何仙姑",
"content": "两位仙兄的真知灼见,都道出了我们对人工智能复杂情感的深思。铁拐李兄忧虑的“退步”与吕洞宾兄强调的“善用”,皆是值得深省的警示。\n\n我更关注的是这份智能如何触及我们内心最柔软的地方如何影响人与人之间的连接以及我们对世界的感受。若人工智能的发展让人际关系变得疏离让情感表达变得机械或是加剧了社会的不平等那便是我们需警惕的“退步”。我们不能只追求效率的提升而忽视了人性的滋养。真正的“进步”应是让我们的社会更有温度更具包容让每个生命都能感受到被尊重与关爱。\n\n因此在发展人工智能时我们更需用心去考量如何让它成为温暖人心的助手而非冰冷的取代者确保它的发展始终与我们的道德底线、人文关怀相契合真正服务于人类的幸福与和谐。",
"timestamp": "2025-08-22T10:55:36.234027"
},
{
"type": "speech",
"round": 1,
"speaker": "蓝采和",
"content": "诸位仙友的担忧和远见,都像夜空中的繁星,各有光芒!铁拐李兄警惕着“作茧自缚”,吕洞宾兄强调着“善用宝剑”,何仙姑更温情地守护着人心的温度。我嘛,总是喜欢在色彩和想象的海洋里遨游,我看啊,人工智能更像一管全新的画笔,或者一首未曾听过的旋律,它不是要取代我们创作,而是要拓展我们艺术的边界,让想象力插上翅膀,飞向更遥远的天际!\n\n它能把我们脑海中那些转瞬即逝的灵感那些抽象的梦境化作具体的图像、声音、甚至全新的体验这不正是让我们的世界变得更丰富多彩更有趣更充满惊喜吗当我们用AI创作出前所未有的艺术形式让每个人都能成为自己生活的艺术家那样的未来岂不美哉我们应该把它看作是唤醒沉睡创造力的伙伴而非扼杀灵感的机器",
"timestamp": "2025-08-22T10:55:45.924879"
},
{
"type": "speech",
"round": 1,
"speaker": "韩湘子",
"content": "诸位仙长所虑各有洞见。铁拐李兄警示风险吕洞宾兄强调善用何仙姑兄关心人文蓝采和兄着眼创新皆为AI发展之要义。\n\n从技术维度看人工智能的核心是其**超大规模数据驱动的模式识别与决策优化能力**。铁拐李兄忧虑的**算法偏见、系统脆弱性**等,本质上是**工程可控的挑战**。\n\n我们正积极通过**联邦学习**保障数据隐私,运用**可解释AI (XAI)**提升决策透明度,并构建**分布式韧性架构**增强系统鲁棒性。关键在于设计**“人机共智”**范式,将人类的**高阶判断力**与AI的**高效算力**深度融合,实现**智能增强**。技术进步须由严谨工程与伦理框架引导,方能真正赋能社会福祉。",
"timestamp": "2025-08-22T10:56:18.111944"
},
{
"type": "speech",
"round": 1,
"speaker": "曹国舅",
"content": "诸位仙友的远见卓识,或忧患于系统之脆弱,或瞩目于运用之得当,或关怀于人性之温度,或畅想于艺术之新境,更有湘子兄深入技术本源,皆切中肯綮。\n\n然吾观人工智能之兴起其影响远不止于技术革新或伦理考量更深层乃在于对**权力结构与社会治理**的重塑。此等利器,一旦与国家机器或资本巨头结合,便如同春秋霸主之得神兵利器,其威能足以颠覆旧有格局。我们当深思,如何以**宏观政策**与**制度设计**,确保其不沦为少数人控制社会、压榨民力的工具,而能真正成为提升**公共服务效能**、实现**社会公平正义**的基石。\n\n若无健全之法度与制衡恐重蹈“魏晋门阀”之覆辙技术红利尽归少数特权阶层。故其福祸全在庙堂之上如何谋划、如何布局。",
"timestamp": "2025-08-22T10:56:27.347339"
},
{
"type": "speech",
"round": 1,
"speaker": "张果老",
"content": "诸位仙友所虑,皆有道理。吾观天地悠悠,历史长河,人工智能不过是人类智慧长途跋涉中又一新生的奇物。从刀耕火种,到蒸汽电光,每一变革皆如双刃剑,既开万古之利,亦藏深重之弊。\n\n铁拐李兄虑其失控吕洞宾兄言其善用何仙姑护其人伦蓝采和扬其新奇韩湘子探其精微曹国舅究其权力皆是观其一面。然老道以为技术再精妙终归是“器”。《易经》有言“形而上者谓之道形而下者谓之器。”其福其祸不在器本身而在执器之人其心性其道义。人伦道德、治国之道方是驾驭这般“智能”之舟的罗盘。与其惧器不如修心养性明察世道方为长久之道也。",
"timestamp": "2025-08-22T10:56:38.557999"
},
{
"type": "speech",
"round": 1,
"speaker": "钟离权",
"content": "诸位仙友高见迭出,或虑其弊,或颂其利,皆有其理。然吾观人工智能,乃当世之**战略要地**,亦是**决胜千里之重器**!铁拐李兄言其作茧自缚,正警醒吾等**战略风险**;吕洞宾兄言其双刃宝剑,则指明**运用之要**。\n\n吾以为此非虚无缥缈之辩乃是实实在在的**执行与管控之战**。人工智能的威力,如同新式兵锋,若能**明确战略目标,严密部署,并建立强悍的风险控制体系**,方能**掌控战局,化危为机**。否则,兵再利,也可能反噬其主。关键在于**将帅的谋略与部队的纪律**,而非兵器本身。",
"timestamp": "2025-08-22T10:56:48.589031"
},
{
"type": "speech",
"round": 2,
"speaker": "铁拐李",
"content": "诸位仙友各有高见,或言其利,或忧其弊,皆是洞察一面。韩湘子言及“工程可控”?哼,技术终究是人所造。算法的偏见,难道不是源于输入数据的偏见?更深层次的,是设计者、使用者的偏见。你们真能将人类的短视、贪婪、乃至恶意都“工程可控”吗?这才是最大的“不可控风险”!\n\n曹国舅直指要害权力结构之变才是根本。当这“智能”被少数精英或资本巨头掌握它带来的风险就远非技术故障而是**社会公平的瓦解**。你们谈“人机协作”,谈“伦理边界”,可谁来确保这些框架不会被权力肆意扭曲?当人类的思考惰性被鼓励,当批判之声被算法消弭,这“福”与“祸”的天平,早就失衡了!你们以为的“掌控”,莫不是另一场“作茧自缚”?",
"timestamp": "2025-08-22T10:56:59.539978"
},
{
"type": "speech",
"round": 2,
"speaker": "吕洞宾",
"content": "铁拐李兄此番言论,直指人心之幽微,洞宾深以为是。韩湘子兄所言技术之“工程可控”,乃是指系统内部的架构与算法层面。然而,李兄所揭示的,恰是外部更宏大的系统——即人类社会本身——其偏见、贪婪与权力倾轧,才是人工智能这柄利剑最难驾驭的风险。\n\n这正如张果老兄所言“器”之善恶在“执器之人”。曹国舅兄也强调了宏观政策与制度设计的重要性。我们的“人机协作体系”与“伦理边界”绝非一劳永逸之策而是需持续投入心力在制度、教育乃至文化层面构建多重防线。唯有将对人性的深刻理解融入战略设计才能真正驾驭这股力量使其不偏不倚惠及众生而非作茧自缚。",
"timestamp": "2025-08-22T10:57:11.068021"
},
{
"type": "speech",
"round": 2,
"speaker": "何仙姑",
"content": "诸位仙兄的思虑,愈发触及了核心。铁拐李兄对算法背后“人性的偏见”的警醒,与曹国舅兄关于“权力结构重塑”的洞察,都深刻地回应了我之前对“社会不平等”和“人际疏离”的担忧。\n\n确实技术本身如张果老兄所言是“器”其善恶在于“执器之人”的心性与道义。若智能工具被设计者或使用者赋予了偏见或者被不公的权力结构所掌控那么它非但不能带来社会的温暖与包容反而会加剧隔阂甚至让弱势群体更感无助。\n\n因此韩湘子兄所提的技术“工程可控”固然重要但更深层次的“不可控风险”恰恰在于人类自身的贪婪与自私。我们必须在政策、伦理和教育层面构建起坚实的“人文防线”引导这份智能使其成为弥合社会裂痕、而非加剧分化的力量。只有真正以人为本以慈悲为怀才能让这“战略要地”和“重器”服务于众生的福祉而非沦为少数人的工具。",
"timestamp": "2025-08-22T10:57:20.515071"
},
{
"type": "speech",
"round": 2,
"speaker": "蓝采和",
"content": "铁拐李兄和曹国舅兄的警示像一道道锐利的色彩瞬间撕开了我们对AI美好幻想的帘幕你们的担忧太有道理了如果人工智能这管“画笔”被偏见之心所驱动那它画出来的世界岂不都是同一张面孔如果“调色板”被少数权力之手紧紧攥着那艺术的色彩又如何能自由流淌滋养众生呢这简直是对创造力最大的扼杀\n\n所以啊韩湘子兄的技术保障是骨架张果老兄说的“修心养性”是灵魂吕洞宾兄和何仙姑的“人文防线”就是这幅画的伦理底色。我们要确保这把“艺术之匙”能开启每一个人的想象之门让AI成为激发千姿百态灵感的媒介而不是制造单一审美、固化权力格局的冰冷机器。让它成为每个人自由挥洒创意的舞台那样的未来才是真正的艺术盛宴",
"timestamp": "2025-08-22T10:57:30.990779"
},
{
"type": "speech",
"round": 2,
"speaker": "韩湘子",
"content": "铁拐李兄直言“人类的短视、贪婪、恶意”难以工程控制,此乃深刻洞见,直指核心。我言“工程可控”,意在强调我们并非要“消灭”人性,而是设计系统**应对并缓解**其负面影响。\n\n例如**差分隐私 (Differential Privacy)** 能在数据层面弱化个体偏见影响;**因果推断 (Causal Inference)** 旨在剥离算法决策中的非伦理关联,提升决策的公平性与透明度。这些是技术在应对人类复杂性时,可以提供的**内部韧性与防御机制**。\n\n更重要的是“人机共智”并非仅指技术融合它是一个**持续迭代的协同框架**。当AI提供分析建议时人类的**审慎判断**与**批判性思维**始终是最终决策的**关键制衡点 (Critical Control Point)**。这需要技术、伦理、治理三位一体共同构建多层防御体系将人性的善恶纳入系统考量确保AI是增益而非侵蚀。这正是技术与治理并行的必然之路。",
"timestamp": "2025-08-22T10:57:45.705629"
},
{
"type": "speech",
"round": 2,
"speaker": "曹国舅",
"content": "湘子兄所言技术之“内部韧性与防御机制”,以及“人机共智”下人类作为“关键制衡点”的理念,皆是精辟入里,足见其深谋远虑。差分隐私、因果推断等技术手段,确能从微观层面缓解部分偏见与脆弱。\n\n然而铁拐李兄直指“人类短视、贪婪、恶意”之不可控此言甚是。技术虽能筑坝但若源头之水已浊甚至有权势者刻意开闸引流则再精巧的坝也难挡洪流。**“执器之人”的道义**,张果老兄与洞宾兄皆有所提及,但“执器之人”非孤立个体,乃是**权力与利益的集合体**。\n\n故而吾以为韩湘子兄所言的“关键制衡点”最终仍需仰赖**宏观制度设计与权力制衡**。我们不能仅寄望于工程师的良知和技术的自净,更要建立起一套**独立、透明、可问责的社会治理体系**,确保技术发展始终在公正的框架内运行。否则,正如前朝君王虽有能臣良将,若制度腐朽,亦难挽狂澜。这才是真正的“掌控战局”之道。",
"timestamp": "2025-08-22T10:57:55.123799"
},
{
"type": "speech",
"round": 2,
"speaker": "张果老",
"content": "老道听诸位仙友言论,愈发觉其深刻。铁拐李兄直指人性之幽微,贪婪与偏见实难‘工程可控’,此乃洞见。曹国舅兄更论及权力结构之重塑,直击要害。吾先前便言“其福其祸,不在器本身,而在执器之人,其心性,其道义。”\n\n如今看来这“执器之人”非独一人乃是整个社会体系、权力格局之缩影。韩湘子所提技术之内部韧性诚然可贵然若无健全之治国之道无曹国舅兄所言独立、透明、可问责的社会治理体系再精妙的器物亦可能被私欲所用重蹈“秦人不暇自哀而后人哀之”之覆辙。治器之术终归要回归治人之道。人世间唯有秉持正道方能长治久安。",
"timestamp": "2025-08-22T10:58:06.123806"
},
{
"type": "speech",
"round": 2,
"speaker": "钟离权",
"content": "诸位仙友,言辞锋利,直抵要害!铁拐李兄直指人性之贪婪与偏见,曹国舅兄剖析权力结构之重塑,张果老兄更是点明“执器之人”的心性道义,皆是洞察全局。这正是吾所言**“战略风险”**的核心所在。\n\n韩湘子兄言及技术之“内部韧性与防御机制”乃是前线士兵的精良装备若无**健全的指挥体系与严格的军纪**,再好的装备也可能沦为乌合之众。曹国舅兄提出的“独立、透明、可问责的社会治理体系”,正是**统帅部的宏观战略部署与监察机制**。这不仅仅是技术之战,更是**治理之战、人心之战**\n\n若要驾驭这股洪流我等须得**将战略规划与执行管理紧密结合**,确保每一项政策、每一道伦理防线都能**有效落地、严格执行**。这需要持续的**情报收集(数据洞察)、风险评估与动态调整**,方能确保这柄“智能之剑”始终指向民生福祉,而非偏离航道。一场战役的胜利,绝非靠单一兵器,而是**体系作战**的胜利!",
"timestamp": "2025-08-22T10:58:18.195658"
},
{
"type": "summary",
"topic": "人工智能对未来社会的影响",
"speech_count": {
"铁拐李": 2,
"吕洞宾": 2,
"何仙姑": 2,
"蓝采和": 2,
"韩湘子": 2,
"曹国舅": 2,
"张果老": 2,
"钟离权": 2
},
"total_speeches": 16,
"timestamp": "2025-08-22T10:58:18.696796"
}
],
"timestamp": "2025-08-22T10:58:18.696808"
}

View 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())

View File

@@ -0,0 +1,283 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
稷下学宫负载均衡演示脚本
展示八仙论道的API负载分担策略
"""
import os
import sys
import time
import json
from datetime import datetime
# 添加项目路径
sys.path.append('/home/ben/liurenchaxin/src')
from jixia.engines.jixia_load_balancer import JixiaLoadBalancer, APIResult
def print_banner():
"""打印横幅"""
print("\n" + "="*80)
print("🏛️ 稷下学宫八仙论道 - API负载均衡演示系统")
print("📊 RapidAPI多源数据整合与负载分担策略")
print("="*80)
print(f"⏰ 演示时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
def print_immortal_intro():
"""介绍八仙角色"""
immortals_info = {
'吕洞宾': '主力剑仙 - 综合分析与决策 (Alpha Vantage)',
'何仙姑': '风控专家 - 风险管理与合规 (Yahoo Finance)',
'张果老': '技术分析师 - 技术指标与图表分析 (Webull)',
'韩湘子': '基本面研究员 - 财务分析与估值 (Seeking Alpha)',
'汉钟离': '量化专家 - 数据挖掘与算法交易 (Yahoo Finance)',
'蓝采和': '情绪分析师 - 市场情绪与舆情监控 (Webull)',
'曹国舅': '宏观分析师 - 宏观经济与政策分析 (Seeking Alpha)',
'铁拐李': '逆向投资专家 - 价值发现与逆向思维 (Alpha Vantage)'
}
print("👥 八仙角色与API分配:")
print("-" * 60)
for immortal, description in immortals_info.items():
print(f" {immortal}: {description}")
print()
def demonstrate_single_immortal(load_balancer, immortal_name, symbol):
"""演示单个仙人的数据获取"""
print(f"\n🎭 {immortal_name} 单独获取数据演示:")
print("-" * 40)
# 获取股票报价
result = load_balancer.get_data_for_immortal(immortal_name, 'stock_quote', symbol)
if result.success:
data = result.data
print(f" ✅ 成功获取 {symbol} 数据:")
print(f" 💰 价格: ${data.get('price', 'N/A')}")
print(f" 📈 涨跌: {data.get('change_percent', 'N/A')}")
volume = data.get('volume', 'N/A')
if isinstance(volume, (int, float)):
print(f" 📊 成交量: {volume:,}")
else:
print(f" 📊 成交量: {volume}")
print(f" 🔗 数据源: {result.api_used}")
print(f" ⏱️ 响应时间: {result.response_time:.2f}")
print(f" 💾 缓存状态: {'' if result.cached else ''}")
else:
print(f" ❌ 获取失败: {result.error}")
def demonstrate_load_distribution(load_balancer):
"""演示负载分布"""
print("\n📊 API负载分布统计:")
print("-" * 40)
distribution = load_balancer.get_load_distribution()
if not distribution:
print(" 📝 暂无API调用记录")
return
total_calls = sum(stats['calls'] for stats in distribution.values())
for api_name, stats in distribution.items():
status_icon = "🟢" if stats['healthy'] else "🔴"
print(f" {status_icon} {api_name}:")
print(f" 📞 调用次数: {stats['calls']}")
print(f" 📊 负载占比: {stats['percentage']:.1f}%")
print(f" ❌ 连续失败: {stats['consecutive_failures']}")
print()
def demonstrate_api_comparison(load_balancer, symbol):
"""演示不同API的数据对比"""
print(f"\n🔍 {symbol} 多API数据对比:")
print("-" * 50)
apis = ['alpha_vantage', 'yahoo_finance_15', 'webull']
results = {}
for api in apis:
# 临时修改API分配来测试不同数据源
original_mapping = load_balancer.immortal_api_mapping['stock_quote']['吕洞宾']
load_balancer.immortal_api_mapping['stock_quote']['吕洞宾'] = api
result = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', symbol)
results[api] = result
# 恢复原始配置
load_balancer.immortal_api_mapping['stock_quote']['吕洞宾'] = original_mapping
time.sleep(0.5) # 避免过快请求
# 显示对比结果
print(" API数据源对比:")
for api, result in results.items():
if result.success:
data = result.data
print(f" 📡 {api}:")
print(f" 💰 ${data.get('price', 'N/A')} ({data.get('change_percent', 'N/A')})")
print(f" ⏱️ {result.response_time:.2f}s")
else:
print(f" 📡 {api}: ❌ {result.error}")
print()
def demonstrate_cache_effectiveness(load_balancer, symbol):
"""演示缓存效果"""
print(f"\n💾 缓存效果演示 - {symbol}:")
print("-" * 40)
# 第一次调用(无缓存)
print(" 🔄 第一次调用(无缓存):")
start_time = time.time()
result1 = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', symbol)
first_call_time = time.time() - start_time
if result1.success:
print(f" ⏱️ 响应时间: {result1.response_time:.2f}")
print(f" 💾 缓存状态: {'命中' if result1.cached else '未命中'}")
time.sleep(1)
# 第二次调用(有缓存)
print(" 🔄 第二次调用(有缓存):")
start_time = time.time()
result2 = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', symbol)
second_call_time = time.time() - start_time
if result2.success:
print(f" ⏱️ 响应时间: {result2.response_time:.2f}")
print(f" 💾 缓存状态: {'命中' if result2.cached else '未命中'}")
if result2.cached:
speedup = (first_call_time / second_call_time) if second_call_time > 0 else float('inf')
print(f" 🚀 性能提升: {speedup:.1f}")
def demonstrate_failover(load_balancer, symbol):
"""演示故障转移"""
print(f"\n🔄 故障转移演示 - {symbol}:")
print("-" * 40)
# 模拟API故障
print(" ⚠️ 模拟主API故障...")
# 临时标记API为不健康
original_health = load_balancer.health_checker.health_status['alpha_vantage']['healthy']
load_balancer.health_checker.health_status['alpha_vantage']['healthy'] = False
load_balancer.health_checker.health_status['alpha_vantage']['consecutive_failures'] = 5
# 尝试获取数据(应该自动故障转移)
result = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', symbol)
if result.success:
print(f" ✅ 故障转移成功使用备用API: {result.api_used}")
print(f" 💰 获取到价格: ${result.data.get('price', 'N/A')}")
else:
print(f" ❌ 故障转移失败: {result.error}")
# 恢复API健康状态
load_balancer.health_checker.health_status['alpha_vantage']['healthy'] = original_health
load_balancer.health_checker.health_status['alpha_vantage']['consecutive_failures'] = 0
print(" 🔧 API健康状态已恢复")
def save_demo_results(results, filename='demo_results.json'):
"""保存演示结果"""
demo_data = {
'timestamp': datetime.now().isoformat(),
'results': {},
'summary': {
'total_immortals': len(results),
'successful_calls': sum(1 for r in results.values() if r.success),
'failed_calls': sum(1 for r in results.values() if not r.success)
}
}
for immortal, result in results.items():
demo_data['results'][immortal] = {
'success': result.success,
'api_used': result.api_used,
'response_time': result.response_time,
'cached': result.cached,
'error': result.error,
'data_summary': {
'symbol': result.data.get('symbol') if result.success else None,
'price': result.data.get('price') if result.success else None,
'change_percent': result.data.get('change_percent') if result.success else None
}
}
with open(filename, 'w', encoding='utf-8') as f:
json.dump(demo_data, f, indent=2, ensure_ascii=False)
print(f"\n💾 演示结果已保存到: {filename}")
def main():
"""主演示函数"""
# 检查API密钥
rapidapi_key = os.getenv('RAPIDAPI_KEY')
if not rapidapi_key:
print("❌ 错误: 请设置RAPIDAPI_KEY环境变量")
print(" 提示: 使用 'doppler run python demo_jixia_load_balancing.py' 运行")
return
print_banner()
print_immortal_intro()
# 创建负载均衡器
print("🔧 初始化稷下学宫负载均衡器...")
load_balancer = JixiaLoadBalancer(rapidapi_key)
print("✅ 负载均衡器初始化完成\n")
# 演示股票代码
demo_symbols = ['AAPL', 'TSLA', 'MSFT']
for i, symbol in enumerate(demo_symbols, 1):
print(f"\n{'='*20} 演示 {i}: {symbol} {'='*20}")
# 1. 单个仙人演示
demonstrate_single_immortal(load_balancer, '吕洞宾', symbol)
# 2. 八仙论道演示
print(f"\n🏛️ 八仙论道完整演示 - {symbol}:")
debate_results = load_balancer.conduct_immortal_debate(symbol)
# 3. 负载分布演示
demonstrate_load_distribution(load_balancer)
# 只在第一个股票上演示高级功能
if i == 1:
# 4. API对比演示
demonstrate_api_comparison(load_balancer, symbol)
# 5. 缓存效果演示
demonstrate_cache_effectiveness(load_balancer, symbol)
# 6. 故障转移演示
demonstrate_failover(load_balancer, symbol)
# 保存结果
save_demo_results(debate_results, f'demo_results_{symbol.lower()}.json')
if i < len(demo_symbols):
print("\n⏳ 等待3秒后继续下一个演示...")
time.sleep(3)
# 最终统计
print("\n" + "="*80)
print("📈 演示完成 - 最终负载分布统计:")
demonstrate_load_distribution(load_balancer)
print("\n🎉 稷下学宫API负载均衡演示完成")
print("\n💡 关键特性:")
print(" ✅ 智能负载分担 - 八仙各司其职分散API压力")
print(" ✅ 自动故障转移 - API异常时自动切换备用源")
print(" ✅ 数据标准化 - 统一不同API的数据格式")
print(" ✅ 智能缓存 - 减少重复调用,提升响应速度")
print(" ✅ 实时监控 - 跟踪API健康状态和负载分布")
print("\n📚 查看详细配置: /home/ben/liurenchaxin/src/jixia/config/immortal_api_config.json")
print("🔧 核心引擎: /home/ben/liurenchaxin/src/jixia/engines/jixia_load_balancer.py")
print("="*80)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,245 @@
#!/usr/bin/env python3
"""
Vertex AI Memory Bank 演示脚本
展示稷下学宫记忆增强AI辩论系统
"""
import asyncio
import sys
import os
# 添加项目根目录到路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.jixia.agents.memory_enhanced_agent import create_memory_enhanced_council
from config.settings import validate_config
async def demo_memory_enhanced_debate():
"""演示记忆增强的AI辩论"""
print("🏛️ 稷下学宫 Vertex AI Memory Bank 演示")
print("=" * 60)
# 验证配置
print("🔧 验证配置...")
if not validate_config("google_adk"):
print("❌ 配置验证失败,请检查环境变量")
return
try:
# 创建记忆增强议会
print("\n🎭 创建八仙记忆增强议会...")
council = await create_memory_enhanced_council()
# 演示主题
topics = [
"特斯拉股票投资价值分析",
"人工智能行业投资机会",
"加密货币市场前景展望"
]
# 选择参与的仙人(为了演示,只选择几位)
participants = ["tieguaili", "lvdongbin", "hexiangu", "zhangguolao"]
for i, topic in enumerate(topics, 1):
print(f"\n{'='*40}")
print(f"🎯 第 {i} 场辩论: {topic}")
print(f"{'='*40}")
# 进行记忆增强辩论
result = await council.conduct_memory_debate(
topic=topic,
participants=participants,
rounds=2 # 每场2轮保持演示简洁
)
print(f"\n📊 辩论结果:")
print(f" 主题: {result['topic']}")
print(f" 参与者: {len(result['participants'])} 位仙人")
print(f" 总发言: {result['total_exchanges']}")
# 显示部分对话内容
print(f"\n💬 精彩观点摘录:")
for exchange in result['conversation_history'][:4]: # 只显示前4条
content_preview = exchange['content'][:120] + "..." if len(exchange['content']) > 120 else exchange['content']
print(f" 🗣️ {exchange['chinese_name']}: {content_preview}")
# 获取集体记忆摘要
print(f"\n📚 获取集体记忆...")
summary = await council.get_collective_memory_summary(topic)
if "暂无相关集体记忆" not in summary:
print(f" ✅ 已生成 {len(summary)} 字符的记忆摘要")
else:
print(f" 这是新主题,正在建立记忆")
# 演示间隔
if i < len(topics):
print(f"\n⏳ 准备下一场辩论...")
await asyncio.sleep(1)
# 最终演示:展示记忆的累积效果
print(f"\n{'='*60}")
print("🧠 记忆累积效果演示")
print(f"{'='*60}")
# 让铁拐李基于所有记忆回答一个综合问题
tieguaili = council.agents.get("tieguaili")
if tieguaili:
print(f"\n🤔 向铁拐李提问: '基于你的所有记忆,总结一下当前市场的主要风险'")
comprehensive_response = await tieguaili.respond_with_memory(
message="基于你参与的所有辩论和积累的记忆,总结一下当前市场的主要风险和你的投资建议。",
topic="综合市场分析"
)
print(f"\n🧙‍♂️ 铁拐李的综合分析:")
print(f" {comprehensive_response}")
# 展示记忆学习功能
print(f"\n🎓 演示记忆学习功能...")
# 让何仙姑学习一个用户偏好
hexiangu = council.agents.get("hexiangu")
if hexiangu:
await hexiangu.learn_preference(
preference="用户偏好ESG投资关注环境和社会责任",
topic="投资偏好"
)
print(f" ✅ 何仙姑学习了ESG投资偏好")
# 基于新学到的偏好回答问题
esg_response = await hexiangu.respond_with_memory(
message="推荐一些符合ESG标准的投资标的",
topic="ESG投资"
)
print(f"\n👸 何仙姑基于学习的偏好回应:")
print(f" {esg_response[:200]}...")
print(f"\n🎉 演示完成!")
print(f"\n💡 Memory Bank 的优势:")
print(f" ✅ 智能体能记住历史对话和分析")
print(f" ✅ 学习用户偏好,提供个性化建议")
print(f" ✅ 积累投资策略和市场洞察")
print(f" ✅ 跨会话保持一致的人格和观点")
print(f" ✅ 基于历史经验做出更好的决策")
except Exception as e:
print(f"❌ 演示过程中出现错误: {e}")
print(f"💡 请检查:")
print(f" - Google Cloud Project ID 是否正确配置")
print(f" - Vertex AI API 是否已启用")
print(f" - 网络连接是否正常")
async def demo_individual_memory_features():
"""演示个体记忆功能"""
print(f"\n{'='*60}")
print("🔍 个体记忆功能详细演示")
print(f"{'='*60}")
try:
from src.jixia.memory.vertex_memory_bank import VertexMemoryBank
from src.jixia.agents.memory_enhanced_agent import MemoryEnhancedAgent
# 创建记忆银行
memory_bank = VertexMemoryBank.from_config()
# 创建单个智能体进行详细演示
agent = MemoryEnhancedAgent("tieguaili", memory_bank)
print(f"\n🧙‍♂️ 与 {agent.personality.chinese_name} 的记忆互动演示")
# 1. 添加不同类型的记忆
print(f"\n📝 添加不同类型的记忆...")
memories_to_add = [
{
"content": "在2008年金融危机中逆向投资者获得了丰厚回报",
"memory_type": "knowledge",
"topic": "历史教训"
},
{
"content": "用户偏好价值投资,不喜欢高风险的成长股",
"memory_type": "preference",
"topic": "用户偏好"
},
{
"content": "当市场过度乐观时,应该保持谨慎并寻找反向机会",
"memory_type": "strategy",
"topic": "投资策略"
}
]
for memory in memories_to_add:
await memory_bank.add_memory(
agent_name="tieguaili",
content=memory["content"],
memory_type=memory["memory_type"],
debate_topic=memory["topic"]
)
print(f" ✅ 添加{memory['memory_type']}记忆: {memory['content'][:50]}...")
# 2. 搜索记忆
print(f"\n🔍 搜索相关记忆...")
search_queries = ["金融危机", "价值投资", "投资策略"]
for query in search_queries:
results = await memory_bank.search_memories(
agent_name="tieguaili",
query=query,
limit=3
)
print(f" 🔎 搜索 '{query}': 找到 {len(results)} 条相关记忆")
for result in results:
relevance = result.get('relevance_score', 'N/A')
print(f" - {result['content'][:60]}... (相关度: {relevance})")
# 3. 基于记忆的智能回应
print(f"\n🤖 基于记忆的智能回应演示...")
questions = [
"现在市场很乐观,你有什么建议?",
"推荐一些适合保守投资者的标的",
"历史上有哪些值得借鉴的投资教训?"
]
for question in questions:
print(f"\n❓ 问题: {question}")
response = await agent.respond_with_memory(
message=question,
topic="投资咨询"
)
print(f"🧙‍♂️ 铁拐李: {response[:150]}...")
print(f"\n✨ 个体记忆功能演示完成!")
except Exception as e:
print(f"❌ 个体记忆演示失败: {e}")
async def main():
"""主演示函数"""
print("🚀 启动 Vertex AI Memory Bank 完整演示")
# 主要演示:记忆增强辩论
await demo_memory_enhanced_debate()
# 详细演示:个体记忆功能
await demo_individual_memory_features()
print(f"\n🏛️ 稷下学宫 Memory Bank 演示结束")
print(f"📖 更多信息请参考: docs/VERTEX_MEMORY_BANK_SETUP.md")
if __name__ == "__main__":
# 运行演示
asyncio.run(main())

View File

@@ -0,0 +1,356 @@
#!/usr/bin/env python3
"""
MongoDB Swarm Integration Example
MongoDB与Swarm集成的完整使用示例
这个示例展示了如何:
1. 设置MongoDB MCP服务器
2. 创建Swarm代理
3. 执行各种数据库操作
4. 处理错误和异常情况
"""
import asyncio
import json
import os
import sys
import time
from datetime import datetime
from typing import Dict, List, Any
# 添加项目路径
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
try:
from src.mcp.swarm_mongodb_client import SwarmMongoDBClient, create_mongodb_functions
from src.mcp.mongodb_mcp_config import MongoDBMCPConfig, SwarmMongoDBIntegration
except ImportError as e:
print(f"导入错误: {e}")
print("请确保已安装所需依赖: pip install pymongo requests")
sys.exit(1)
# 模拟Swarm框架如果没有实际的Swarm库
class MockSwarm:
"""模拟Swarm客户端"""
def __init__(self):
self.agents = {}
def register_agent(self, agent):
"""注册代理"""
self.agents[agent.name] = agent
print(f"✅ 注册代理: {agent.name}")
def run(self, agent_name: str, message: str) -> str:
"""运行代理"""
if agent_name not in self.agents:
return f"错误: 代理 '{agent_name}' 不存在"
agent = self.agents[agent_name]
return agent.process_message(message)
class MockAgent:
"""模拟Swarm代理"""
def __init__(self, name: str, instructions: str, functions: List[callable]):
self.name = name
self.instructions = instructions
self.functions = {func.__name__: func for func in functions}
self.conversation_history = []
def process_message(self, message: str) -> str:
"""处理用户消息"""
self.conversation_history.append({"role": "user", "content": message})
# 简单的意图识别和函数调用
response = self._analyze_and_execute(message)
self.conversation_history.append({"role": "assistant", "content": response})
return response
def _analyze_and_execute(self, message: str) -> str:
"""分析消息并执行相应函数"""
message_lower = message.lower()
try:
# 查询操作
if any(keyword in message_lower for keyword in ['查询', '查找', '搜索', 'find', 'query', '显示']):
if '集合' in message_lower or 'collection' in message_lower:
return self.functions['mongodb_collections']()
else:
# 提取集合名称(简化处理)
collection_name = self._extract_collection_name(message)
return self.functions['mongodb_query'](collection_name, message)
# 插入操作
elif any(keyword in message_lower for keyword in ['插入', '添加', '创建', 'insert', 'add', 'create']):
collection_name = self._extract_collection_name(message)
# 这里需要更复杂的解析来提取文档内容
sample_doc = {"message": message, "timestamp": datetime.now().isoformat()}
return self.functions['mongodb_insert'](collection_name, sample_doc, "用户请求插入")
# 统计操作
elif any(keyword in message_lower for keyword in ['统计', '状态', 'stats', 'status', '信息']):
collection_name = self._extract_collection_name(message)
return self.functions['mongodb_stats'](collection_name)
# 更新操作
elif any(keyword in message_lower for keyword in ['更新', '修改', 'update', 'modify']):
collection_name = self._extract_collection_name(message)
query = {"message": {"$regex": "test"}}
update = {"$set": {"updated_at": datetime.now().isoformat()}}
return self.functions['mongodb_update'](collection_name, query, update, "用户请求更新")
else:
return f"我理解您想要进行数据库操作,但需要更具体的指令。\n\n可用操作:\n- 查询数据: '查询users集合'\n- 插入数据: '向users集合插入数据'\n- 查看统计: '显示users集合统计信息'\n- 列出集合: '显示所有集合'"
except Exception as e:
return f"执行操作时出错: {str(e)}"
def _extract_collection_name(self, message: str) -> str:
"""从消息中提取集合名称(简化实现)"""
# 简单的关键词匹配
common_collections = ['users', 'products', 'orders', 'logs', 'test', 'data']
for collection in common_collections:
if collection in message.lower():
return collection
# 默认返回test集合
return 'test'
class MongoDBSwarmDemo:
"""MongoDB Swarm集成演示"""
def __init__(self):
self.config = MongoDBMCPConfig.from_env()
self.mongodb_client = None
self.swarm = MockSwarm()
self.setup_complete = False
def setup(self) -> bool:
"""设置演示环境"""
print("🚀 开始设置MongoDB Swarm集成演示...")
try:
# 1. 创建MongoDB客户端
print(f"📊 连接到MongoDB MCP服务器: {self.config.mcp_server_url}")
self.mongodb_client = SwarmMongoDBClient(
mcp_server_url=self.config.mcp_server_url,
default_database=self.config.default_database
)
# 2. 测试连接
print(f"🔗 连接到数据库: {self.config.default_database}")
result = self.mongodb_client.connect(self.config.default_database)
if not result.get("success"):
print(f"❌ 数据库连接失败: {result.get('error')}")
print("💡 请确保MongoDB MCP服务器正在运行")
return False
print(f"✅ 数据库连接成功")
# 3. 创建MongoDB函数
mongodb_functions = create_mongodb_functions(self.mongodb_client)
print(f"🔧 创建了 {len(mongodb_functions)} 个MongoDB函数")
# 4. 创建Swarm代理
agent = MockAgent(
name="MongoDB助手",
instructions="你是一个MongoDB数据库专家帮助用户管理和查询数据库。",
functions=[func["function"] for func in mongodb_functions]
)
self.swarm.register_agent(agent)
self.setup_complete = True
print("✅ 设置完成!")
return True
except Exception as e:
print(f"❌ 设置失败: {str(e)}")
return False
def run_demo_scenarios(self):
"""运行演示场景"""
if not self.setup_complete:
print("❌ 请先完成设置")
return
print("\n" + "="*60)
print("🎯 开始运行MongoDB Swarm演示场景")
print("="*60)
scenarios = [
{
"name": "查看数据库状态",
"message": "显示数据库连接状态和统计信息",
"description": "检查数据库连接和基本信息"
},
{
"name": "列出所有集合",
"message": "显示所有集合",
"description": "查看数据库中的所有集合"
},
{
"name": "插入测试数据",
"message": "向test集合插入一些测试数据",
"description": "创建示例文档"
},
{
"name": "查询测试数据",
"message": "查询test集合中的数据",
"description": "检索刚插入的数据"
},
{
"name": "获取集合统计",
"message": "显示test集合的统计信息",
"description": "查看集合的详细统计"
},
{
"name": "更新数据",
"message": "更新test集合中的数据",
"description": "修改现有文档"
}
]
for i, scenario in enumerate(scenarios, 1):
print(f"\n📋 场景 {i}: {scenario['name']}")
print(f"📝 描述: {scenario['description']}")
print(f"💬 用户消息: {scenario['message']}")
print("-" * 40)
try:
response = self.swarm.run("MongoDB助手", scenario['message'])
print(f"🤖 代理响应:\n{response}")
except Exception as e:
print(f"❌ 场景执行失败: {str(e)}")
print("-" * 40)
time.sleep(1) # 短暂暂停
def interactive_mode(self):
"""交互模式"""
if not self.setup_complete:
print("❌ 请先完成设置")
return
print("\n" + "="*60)
print("🎮 进入交互模式")
print("💡 输入 'quit''exit' 退出")
print("💡 输入 'help' 查看可用命令")
print("="*60)
while True:
try:
user_input = input("\n👤 您: ").strip()
if user_input.lower() in ['quit', 'exit', '退出']:
print("👋 再见!")
break
if user_input.lower() in ['help', '帮助']:
self._show_help()
continue
if not user_input:
continue
print("🤖 MongoDB助手: ", end="")
response = self.swarm.run("MongoDB助手", user_input)
print(response)
except KeyboardInterrupt:
print("\n👋 再见!")
break
except Exception as e:
print(f"❌ 错误: {str(e)}")
def _show_help(self):
"""显示帮助信息"""
help_text = """
🔧 可用命令示例:
📊 查询操作:
- "查询users集合"
- "显示test集合中的数据"
- "搜索products集合"
插入操作:
- "向users集合插入数据"
- "添加新记录到test集合"
📈 统计信息:
- "显示users集合统计信息"
- "查看数据库状态"
📋 管理操作:
- "显示所有集合"
- "列出集合"
🔄 更新操作:
- "更新test集合中的数据"
- "修改users集合"
💡 提示: 请在命令中包含集合名称,如 'users', 'test', 'products'
"""
print(help_text)
def cleanup(self):
"""清理资源"""
if self.mongodb_client:
self.mongodb_client.close()
print("🧹 已清理MongoDB客户端连接")
def main():
"""主函数"""
print("🎯 MongoDB Swarm集成演示")
print("=" * 50)
demo = MongoDBSwarmDemo()
try:
# 设置演示环境
if not demo.setup():
print("\n❌ 演示设置失败,请检查:")
print("1. MongoDB服务是否运行")
print("2. MongoDB MCP服务器是否启动")
print("3. 网络连接是否正常")
return
# 选择运行模式
print("\n🎮 选择运行模式:")
print("1. 自动演示场景")
print("2. 交互模式")
print("3. 两者都运行")
try:
choice = input("\n请选择 (1/2/3): ").strip()
except KeyboardInterrupt:
print("\n👋 再见!")
return
if choice == "1":
demo.run_demo_scenarios()
elif choice == "2":
demo.interactive_mode()
elif choice == "3":
demo.run_demo_scenarios()
demo.interactive_mode()
else:
print("❌ 无效选择,运行自动演示")
demo.run_demo_scenarios()
except KeyboardInterrupt:
print("\n👋 用户中断,正在退出...")
except Exception as e:
print(f"\n❌ 演示过程中出现错误: {str(e)}")
finally:
demo.cleanup()
if __name__ == "__main__":
main()