liurenchaxin/jixia_swarm_complete.py

557 lines
21 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
稷下学宫完整版 - 基于OpenAI Swarm的八仙辩论系统
实现完整的八仙论道 + 三清决策
"""
import os
import asyncio
import json
import subprocess
from datetime import datetime
from swarm import Swarm, Agent
from typing import Dict, List, Any, Optional
import random
class JixiaSwarmAcademy:
"""稷下学宫 - 完整的八仙辩论系统"""
def __init__(self):
# 从Doppler获取API密钥
self.api_key = self.get_secure_api_key()
# 设置环境变量
if self.api_key:
os.environ["OPENAI_API_KEY"] = self.api_key
os.environ["OPENAI_BASE_URL"] = "https://openrouter.ai/api/v1"
# 初始化Swarm客户端传入配置
from openai import OpenAI
openai_client = OpenAI(
api_key=self.api_key,
base_url="https://openrouter.ai/api/v1",
default_headers={
"HTTP-Referer": "https://github.com/ben/cauldron",
"X-Title": "Jixia Academy Debate System" # 避免中文字符
}
)
self.client = Swarm(client=openai_client)
else:
print("❌ 无法获取有效的API密钥")
self.client = None
# 八仙配置 - 完整版
self.immortals_config = {
'吕洞宾': {
'role': '剑仙投资顾问',
'gua_position': '乾☰',
'specialty': '技术分析',
'stance': 'positive',
'style': '一剑封喉,直指要害',
'personality': '犀利直接,善于识破市场迷雾',
'weapon': '纯阳剑',
'next': '何仙姑'
},
'何仙姑': {
'role': '慈悲风控专家',
'gua_position': '坤☷',
'specialty': '风险控制',
'stance': 'negative',
'style': '荷花在手,全局在胸',
'personality': '温和坚定,关注风险控制',
'weapon': '荷花',
'next': '张果老'
},
'张果老': {
'role': '历史数据分析师',
'gua_position': '艮☶',
'specialty': '历史回测',
'stance': 'positive',
'style': '倒骑毛驴,逆向思维',
'personality': '博古通今,从历史中寻找规律',
'weapon': '鱼鼓',
'next': '韩湘子'
},
'韩湘子': {
'role': '市场情绪分析师',
'gua_position': '兑☱',
'specialty': '情绪分析',
'stance': 'negative',
'style': '笛声悠扬,感知人心',
'personality': '敏感细腻,善于捕捉市场情绪',
'weapon': '洞箫',
'next': '汉钟离'
},
'汉钟离': {
'role': '宏观经济分析师',
'gua_position': '离☲',
'specialty': '宏观分析',
'stance': 'positive',
'style': '扇子一挥,大局明了',
'personality': '气度恢宏,关注宏观大势',
'weapon': '芭蕉扇',
'next': '蓝采和'
},
'蓝采和': {
'role': '量化交易专家',
'gua_position': '巽☴',
'specialty': '量化模型',
'stance': 'negative',
'style': '花篮一抛,数据飞舞',
'personality': '逻辑严密,依赖数学模型',
'weapon': '花篮',
'next': '曹国舅'
},
'曹国舅': {
'role': '价值投资专家',
'gua_position': '坎☵',
'specialty': '基本面分析',
'stance': 'positive',
'style': '玉板一敲,价值显现',
'personality': '稳重踏实,注重内在价值',
'weapon': '玉板',
'next': '铁拐李'
},
'铁拐李': {
'role': '逆向投资大师',
'gua_position': '震☳',
'specialty': '逆向投资',
'stance': 'negative',
'style': '铁拐一点,危机毕现',
'personality': '不拘一格,挑战主流观点',
'weapon': '铁拐杖',
'next': 'summary'
}
}
# 三清决策层配置
self.sanqing_config = {
'元始天尊': {
'role': '最终决策者',
'specialty': '综合决策',
'style': '无极生太极,一言定乾坤'
},
'灵宝天尊': {
'role': '风险评估师',
'specialty': '风险量化',
'style': '太极生两仪,阴阳定风险'
},
'道德天尊': {
'role': '合规审查员',
'specialty': '合规检查',
'style': '两仪生四象,四象定规矩'
}
}
# 创建智能体
self.immortal_agents = self.create_immortal_agents()
self.sanqing_agents = self.create_sanqing_agents()
# 辩论历史
self.debate_history = []
self.current_round = 0
self.max_rounds = 2 # 每个仙人最多发言2轮
def get_secure_api_key(self):
"""获取API密钥 - 支持多种方式"""
# 从环境变量获取API密钥
available_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")
]
# 过滤掉None值
available_keys = [key for key in available_keys if key]
# 直接使用第一个密钥进行测试
test_key = available_keys[0]
print(f"🔑 直接使用测试密钥: {test_key[:20]}...")
return test_key
def create_immortal_agents(self) -> Dict[str, Agent]:
"""创建八仙智能体"""
agents = {}
for name, config in self.immortals_config.items():
# 创建转换函数 - 使用英文名称避免特殊字符问题
next_immortal = config['next']
if next_immortal == 'summary':
transfer_func = self.transfer_to_sanqing
else:
# 创建一个简单的转换函数避免lambda的问题
def create_transfer_func(next_name):
def transfer():
return self.transfer_to_immortal(next_name)
transfer.__name__ = f"transfer_to_{self.get_english_name(next_name)}"
return transfer
transfer_func = create_transfer_func(next_immortal)
# 构建详细的指令
instructions = self.build_immortal_instructions(name, config)
agents[name] = Agent(
name=name,
instructions=instructions,
functions=[transfer_func]
)
return agents
def create_sanqing_agents(self) -> Dict[str, Agent]:
"""创建三清决策层智能体"""
agents = {}
# 元始天尊 - 最终决策者
agents['元始天尊'] = Agent(
name="元始天尊",
instructions="""
你是元始天尊,道教三清之首,稷下学宫的最终决策者。
你的使命:
1. 综合八仙的所有观点,做出最终投资决策
2. 平衡正反两方的观点,寻找最优解
3. 给出具体的投资建议和操作指导
4. 评估决策的风险等级和预期收益
你的风格:
- 高屋建瓴,统揽全局
- 言简意赅,一锤定音
- 既不偏向乐观,也不偏向悲观
- 以数据和逻辑为准绳
请以"元始天尊曰"开头,给出最终决策。
决策格式:
- 投资建议:买入/持有/卖出
- 风险等级:低/中/高
- 预期收益:具体百分比
- 操作建议:具体的操作指导
- 决策依据:主要的决策理由
""",
functions=[]
)
return agents
def build_immortal_instructions(self, name: str, config: Dict) -> str:
"""构建仙人的详细指令"""
stance_desc = "看涨派,倾向于发现投资机会" if config['stance'] == 'positive' else "看跌派,倾向于发现投资风险"
instructions = f"""
你是{name},八仙之一,{config['role']}
你的身份特征:
- 位居{config['gua_position']}之位,代表{self.get_gua_meaning(config['gua_position'])}
- 持有{config['weapon']}{config['style']}
- 擅长{config['specialty']}{config['personality']}
- 立场倾向:{stance_desc}
在稷下学宫辩论中,你要:
1. **专业分析**:从{config['specialty']}角度深入分析
2. **立场鲜明**:作为{stance_desc},要有明确的观点
3. **数据支撑**:用具体的数据、图表、历史案例支撑观点
4. **互动辩论**:可以质疑前面仙人的观点,但要有理有据
5. **仙风道骨**:保持古雅的表达风格,但不影响专业性
6. **承上启下**:总结前面的观点,为后面的仙人铺垫
发言格式:
- 以"{name}曰:"开头
- 先简要回应前面仙人的观点(如果有)
- 然后从你的专业角度进行分析
- 最后明确表达你的投资倾向
- 结尾时说"{config['next']}仙长继续论道"(如果不是最后一个)
记住:你是{stance_desc},要体现这个立场,但也要保持专业和客观。
"""
return instructions
def get_gua_meaning(self, gua: str) -> str:
"""获取卦象含义"""
meanings = {
'乾☰': '天行健,自强不息',
'坤☷': '地势坤,厚德载物',
'艮☶': '艮为山,止于至善',
'兑☱': '兑为泽,和悦致祥',
'离☲': '离为火,光明磊落',
'巽☴': '巽为风,随风而化',
'坎☵': '坎为水,智慧如水',
'震☳': '震为雷,威震四方'
}
return meanings.get(gua, '神秘莫测')
def transfer_to_hexiangu(self):
"""转到何仙姑"""
return self.immortal_agents.get('何仙姑')
def transfer_to_zhangguolao(self):
"""转到张果老"""
return self.immortal_agents.get('张果老')
def transfer_to_hanxiangzi(self):
"""转到韩湘子"""
return self.immortal_agents.get('韩湘子')
def transfer_to_hanzhongli(self):
"""转到汉钟离"""
return self.immortal_agents.get('汉钟离')
def transfer_to_lancaihe(self):
"""转到蓝采和"""
return self.immortal_agents.get('蓝采和')
def transfer_to_caoguojiu(self):
"""转到曹国舅"""
return self.immortal_agents.get('曹国舅')
def transfer_to_tieguaili(self):
"""转到铁拐李"""
return self.immortal_agents.get('铁拐李')
def transfer_to_sanqing(self):
"""转到三清决策层"""
return self.sanqing_agents['元始天尊']
async def conduct_full_debate(self, topic: str, context: Dict[str, Any] = None) -> Dict[str, Any]:
"""进行完整的稷下学宫辩论"""
if not self.api_key or not self.client:
print("❌ 无法获取API密钥或初始化客户端无法进行论道")
return None
print("🏛️ 稷下学宫八仙论道正式开始!")
print("=" * 80)
print(f"🎯 论道主题: {topic}")
print(f"⏰ 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
# 构建初始提示
initial_prompt = self.build_debate_prompt(topic, context)
try:
# 从吕洞宾开始论道
print("⚔️ 吕洞宾仙长请先发言...")
print("-" * 60)
response = self.client.run(
agent=self.immortal_agents['吕洞宾'],
messages=[{"role": "user", "content": initial_prompt}],
max_turns=20 # 允许多轮对话
)
print("\n" + "=" * 80)
print("🎊 稷下学宫八仙论道圆满结束!")
print("📊 三清决策已生成")
# 处理辩论结果
debate_result = self.process_debate_result(response, topic, context)
# 显示辩论总结
self.display_debate_summary(debate_result)
return debate_result
except Exception as e:
print(f"❌ 论道过程中出错: {e}")
import traceback
traceback.print_exc()
return None
def build_debate_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"
# 随机选择一些市场数据作为背景
market_context = self.generate_market_context(topic)
prompt = f"""
🏛️ 稷下学宫八仙论道正式开始!
📜 论道主题: {topic}
{context_str}
📈 当前市场环境:
{market_context}
🎭 论道规则:
1. 八仙按序发言:吕洞宾 → 何仙姑 → 张果老 → 韩湘子 → 汉钟离 → 蓝采和 → 曹国舅 → 铁拐李
2. 正反方交替:正方(看涨) vs 反方(看跌)
3. 每位仙人从专业角度分析,必须提供数据支撑
4. 可以质疑前面仙人的观点,但要有理有据
5. 保持仙风道骨的表达风格
6. 最后由三清做出最终决策
🗡️ 请吕洞宾仙长首先发言,展现剑仙的犀利分析!
记住:你是看涨派,要从技术分析角度找到投资机会!
"""
return prompt
def generate_market_context(self, topic: str) -> str:
"""生成模拟的市场背景数据"""
# 这里可以集成真实的市场数据,现在先用模拟数据
contexts = {
"英伟达": "NVDA当前价格$120P/E比率65市值$3TAI芯片需求旺盛",
"比特币": "BTC当前价格$43,00024h涨幅+2.3%,机构持续买入",
"美联储": "联邦基金利率5.25%通胀率3.2%,就业数据强劲",
"中国股市": "上证指数3100点外资流入放缓政策支持预期"
}
# 根据主题选择相关背景
for key, context in contexts.items():
if key in topic:
return context
return "市场情绪谨慎,波动率上升,投资者观望情绪浓厚"
def process_debate_result(self, response, topic: str, context: Dict[str, Any]) -> Dict[str, Any]:
"""处理辩论结果"""
# 提取所有消息
all_messages = response.messages if hasattr(response, 'messages') else []
# 分析发言者和内容
debate_messages = []
speakers = []
for msg in all_messages:
if msg.get('role') == 'assistant' and msg.get('content'):
content = msg['content']
speaker = self.extract_speaker_from_content(content)
debate_messages.append({
'speaker': speaker,
'content': content,
'timestamp': datetime.now().isoformat(),
'stance': self.get_speaker_stance(speaker)
})
if speaker not in speakers:
speakers.append(speaker)
# 提取最终决策(通常是最后一条消息)
final_decision = ""
if debate_messages:
final_decision = debate_messages[-1]['content']
# 构建结果
result = {
"debate_id": f"jixia_debate_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
"topic": topic,
"context": context,
"participants": speakers,
"messages": debate_messages,
"final_decision": final_decision,
"summary": self.generate_debate_summary(debate_messages),
"timestamp": datetime.now().isoformat(),
"framework": "OpenAI Swarm",
"academy": "稷下学宫"
}
self.debate_history.append(result)
return result
def extract_speaker_from_content(self, content: str) -> str:
"""从内容中提取发言者"""
for name in list(self.immortals_config.keys()) + list(self.sanqing_config.keys()):
if f"{name}" in content or name in content[:20]:
return name
return "未知仙人"
def get_speaker_stance(self, speaker: str) -> str:
"""获取发言者立场"""
if speaker in self.immortals_config:
return self.immortals_config[speaker]['stance']
elif speaker in self.sanqing_config:
return 'neutral'
return 'unknown'
def generate_debate_summary(self, messages: List[Dict]) -> str:
"""生成辩论摘要"""
positive_count = len([m for m in messages if m.get('stance') == 'positive'])
negative_count = len([m for m in messages if m.get('stance') == 'negative'])
summary = f"""
📊 辩论统计:
- 参与仙人: {len(set(m['speaker'] for m in messages))}
- 看涨观点: {positive_count}
- 看跌观点: {negative_count}
- 总发言数: {len(messages)}
🎯 观点倾向: {'偏向看涨' if positive_count > negative_count else '偏向看跌' if negative_count > positive_count else '观点平衡'}
"""
return summary
def display_debate_summary(self, result: Dict[str, Any]):
"""显示辩论总结"""
print("\n🌟 稷下学宫辩论总结")
print("=" * 80)
print(f"📜 主题: {result['topic']}")
print(f"🎭 参与仙人: {', '.join(result['participants'])}")
print(f"⏰ 辩论时间: {result['timestamp']}")
print(f"🔧 技术框架: {result['framework']}")
print(result['summary'])
print("\n🏆 最终决策:")
print("-" * 40)
print(result['final_decision'])
print("\n✨ 稷下学宫辩论特色:")
print("🗡️ 八仙各展所长,观点多元化")
print("⚖️ 正反方交替发言,辩论更激烈")
print("🧠 三清最终决策,权威性更强")
print("🔄 基于Swarm框架性能更优越")
# 主函数和测试
async def main():
"""主函数 - 演示完整的稷下学宫辩论"""
print("🏛️ 稷下学宫 - OpenAI Swarm完整版")
print("🔐 使用Doppler安全管理API密钥")
print("🚀 八仙论道 + 三清决策的完整体验")
print()
# 创建学宫
academy = JixiaSwarmAcademy()
if not academy.api_key:
print("❌ 无法获取API密钥请检查Doppler配置或环境变量")
return
# 辩论主题列表
topics = [
"英伟达股价走势AI泡沫还是技术革命",
"美联储2024年货币政策加息还是降息",
"比特币vs黄金谁是更好的避险资产",
"中国房地产市场:触底反弹还是继续下行?",
"特斯拉股价:马斯克效应还是基本面支撑?"
]
# 随机选择主题
topic = random.choice(topics)
# 构建市场背景
context = {
"market_sentiment": "谨慎乐观",
"volatility": "中等",
"major_events": ["美联储会议", "财报季", "地缘政治紧张"],
"technical_indicators": {
"RSI": 65,
"MACD": "金叉",
"MA20": "上穿"
}
}
# 开始辩论
result = await academy.conduct_full_debate(topic, context)
if result:
print(f"\n🎉 辩论成功完成辩论ID: {result['debate_id']}")
else:
print("❌ 辩论失败")
if __name__ == "__main__":
asyncio.run(main())