liurenchaxin/examples/debates/swarm_debate_example.py

484 lines
18 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

#!/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())