refactor(project): 重构项目文档并优化代码结构
- 移除旧的文档结构和内容,清理 root 目录下的 markdown 文件 - 删除 GitHub Pages 部署配置和相关文件 - 移除 .env.example 文件,使用 Doppler 进行环境变量管理 - 更新 README.md,增加对 OpenBB 数据的支持 - 重构 streamlit_app.py,移除 Swarm 模式相关代码 - 更新 Doppler 配置管理模块,增加对 .env 文件的支持 - 删除 Memory Bank 实验和测试脚本 - 清理内部文档和开发计划
This commit is contained in:
130
examples/debates/adk_debate_test.py
Normal file
130
examples/debates/adk_debate_test.py
Normal file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫 Google ADK 论道系统测试
|
||||
基于 Google ADK 的八仙论道原型
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
from google.adk import Agent
|
||||
from google.adk.tools import FunctionTool
|
||||
|
||||
# 八仙智能体定义
|
||||
def create_baxian_agents():
|
||||
"""创建八仙智能体"""
|
||||
|
||||
# 铁拐李 - 逆向思维专家
|
||||
tie_guai_li = Agent(
|
||||
name="铁拐李",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 汉钟离 - 平衡协调者
|
||||
han_zhong_li = Agent(
|
||||
name="汉钟离",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 张果老 - 历史智慧者
|
||||
zhang_guo_lao = Agent(
|
||||
name="张果老",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 蓝采和 - 创新思维者
|
||||
lan_cai_he = Agent(
|
||||
name="蓝采和",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 何仙姑 - 直觉洞察者
|
||||
he_xian_gu = Agent(
|
||||
name="何仙姑",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 吕洞宾 - 理性分析者
|
||||
lu_dong_bin = Agent(
|
||||
name="吕洞宾",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 韩湘子 - 艺术感知者
|
||||
han_xiang_zi = Agent(
|
||||
name="韩湘子",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
# 曹国舅 - 实务执行者
|
||||
cao_guo_jiu = Agent(
|
||||
name="曹国舅",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
return {
|
||||
"铁拐李": tie_guai_li,
|
||||
"汉钟离": han_zhong_li,
|
||||
"张果老": zhang_guo_lao,
|
||||
"蓝采和": lan_cai_he,
|
||||
"何仙姑": he_xian_gu,
|
||||
"吕洞宾": lu_dong_bin,
|
||||
"韩湘子": han_xiang_zi,
|
||||
"曹国舅": cao_guo_jiu
|
||||
}
|
||||
|
||||
def test_single_agent():
|
||||
"""测试单个智能体"""
|
||||
print("🧪 测试单个智能体...")
|
||||
|
||||
# 创建铁拐李智能体
|
||||
tie_guai_li = Agent(
|
||||
name="铁拐李",
|
||||
model="gemini-2.5-flash"
|
||||
)
|
||||
|
||||
print(f"✅ 智能体 '{tie_guai_li.name}' 创建成功")
|
||||
print(f"📱 使用模型: {tie_guai_li.model}")
|
||||
|
||||
return tie_guai_li
|
||||
|
||||
def test_baxian_creation():
|
||||
"""测试八仙智能体创建"""
|
||||
print("\n🎭 创建八仙智能体...")
|
||||
|
||||
baxian = create_baxian_agents()
|
||||
|
||||
print(f"✅ 成功创建 {len(baxian)} 个智能体:")
|
||||
for name, agent in baxian.items():
|
||||
print(f" - {name}: {agent.model}")
|
||||
|
||||
return baxian
|
||||
|
||||
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_debate_test.py")
|
||||
return
|
||||
|
||||
print(f"✅ API密钥已配置 (长度: {len(api_key)} 字符)")
|
||||
|
||||
# 测试单个智能体
|
||||
single_agent = test_single_agent()
|
||||
|
||||
# 测试八仙智能体创建
|
||||
baxian = test_baxian_creation()
|
||||
|
||||
print("\n🎉 ADK 论道系统基础测试完成!")
|
||||
print("\n📝 下一步:")
|
||||
print(" 1. 实现智能体间的对话逻辑")
|
||||
print(" 2. 集成 RapidAPI 数据源")
|
||||
print(" 3. 创建论道主题和流程")
|
||||
print(" 4. 连接 Streamlit 界面")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
249
examples/debates/adk_real_debate.py
Normal file
249
examples/debates/adk_real_debate.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()
|
||||
82
examples/debates/adk_simple_debate.py
Normal file
82
examples/debates/adk_simple_debate.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫 ADK 简单论道测试
|
||||
实现智能体间的基本对话功能
|
||||
"""
|
||||
|
||||
import os
|
||||
from google.adk import Agent
|
||||
|
||||
def create_debate_agents():
|
||||
"""创建论道智能体"""
|
||||
|
||||
# 铁拐李 - 逆向思维专家
|
||||
tie_guai_li = Agent(
|
||||
name="铁拐李",
|
||||
model="gemini-2.0-flash-exp"
|
||||
)
|
||||
|
||||
# 吕洞宾 - 理性分析者
|
||||
lu_dong_bin = Agent(
|
||||
name="吕洞宾",
|
||||
model="gemini-2.0-flash-exp"
|
||||
)
|
||||
|
||||
return tie_guai_li, lu_dong_bin
|
||||
|
||||
def simple_debate_test():
|
||||
"""简单论道测试"""
|
||||
print("🎭 开始简单论道测试...")
|
||||
|
||||
# 创建智能体
|
||||
tie_guai_li, lu_dong_bin = create_debate_agents()
|
||||
|
||||
print("\n📋 论道主题: 人工智能对未来社会的影响")
|
||||
print("\n🎯 开始论道...")
|
||||
|
||||
try:
|
||||
# 测试智能体创建
|
||||
print("\n✅ 智能体创建成功:")
|
||||
print(f" - {tie_guai_li.name}: {tie_guai_li.model}")
|
||||
print(f" - {lu_dong_bin.name}: {lu_dong_bin.model}")
|
||||
|
||||
print("\n🎉 简单论道测试完成!")
|
||||
print("\n📝 智能体基础功能验证成功")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 论道测试失败: {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
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_simple_debate.py")
|
||||
return
|
||||
|
||||
print(f"✅ API密钥已配置")
|
||||
|
||||
# 运行测试
|
||||
try:
|
||||
result = simple_debate_test()
|
||||
if result:
|
||||
print("\n📝 测试结果: 成功")
|
||||
print("\n🎯 下一步开发计划:")
|
||||
print(" 1. 学习ADK的正确调用方式")
|
||||
print(" 2. 实现智能体对话功能")
|
||||
print(" 3. 扩展到八仙全员论道")
|
||||
print(" 4. 集成实时数据源")
|
||||
else:
|
||||
print("\n❌ 测试失败")
|
||||
except Exception as e:
|
||||
print(f"❌ 运行失败: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
355
examples/debates/jixia_ollama_swarm.py
Normal file
355
examples/debates/jixia_ollama_swarm.py
Normal file
@@ -0,0 +1,355 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫本地版 - 基于Ollama的四仙辩论系统
|
||||
使用本地Ollama服务,无需API密钥
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
from datetime import datetime
|
||||
from swarm import Swarm, Agent
|
||||
from typing import Dict, List, Any, Optional
|
||||
import random
|
||||
|
||||
class JixiaOllamaSwarm:
|
||||
"""稷下学宫本地版 - 使用Ollama的四仙辩论系统"""
|
||||
|
||||
def __init__(self):
|
||||
# Ollama配置
|
||||
self.ollama_base_url = "http://100.99.183.38:11434"
|
||||
self.model_name = "gemma3n:e4b" # 使用你指定的模型
|
||||
|
||||
# 初始化Swarm客户端,使用Ollama
|
||||
from openai import OpenAI
|
||||
openai_client = OpenAI(
|
||||
api_key="ollama", # Ollama不需要真实的API密钥
|
||||
base_url=f"{self.ollama_base_url}/v1"
|
||||
)
|
||||
self.client = Swarm(client=openai_client)
|
||||
|
||||
print(f"🦙 使用本地Ollama服务: {self.ollama_base_url}")
|
||||
print(f"🤖 使用模型: {self.model_name}")
|
||||
|
||||
# 四仙配置
|
||||
self.immortals = {
|
||||
'吕洞宾': {
|
||||
'role': '技术分析专家',
|
||||
'stance': 'positive',
|
||||
'specialty': '技术分析和图表解读',
|
||||
'style': '犀利直接,一剑封喉'
|
||||
},
|
||||
'何仙姑': {
|
||||
'role': '风险控制专家',
|
||||
'stance': 'negative',
|
||||
'specialty': '风险评估和资金管理',
|
||||
'style': '温和坚定,关注风险'
|
||||
},
|
||||
'张果老': {
|
||||
'role': '历史数据分析师',
|
||||
'stance': 'positive',
|
||||
'specialty': '历史回测和趋势分析',
|
||||
'style': '博古通今,从历史找规律'
|
||||
},
|
||||
'铁拐李': {
|
||||
'role': '逆向投资大师',
|
||||
'stance': 'negative',
|
||||
'specialty': '逆向思维和危机发现',
|
||||
'style': '不拘一格,挑战共识'
|
||||
}
|
||||
}
|
||||
|
||||
# 创建智能体
|
||||
self.agents = self.create_agents()
|
||||
|
||||
def create_agents(self) -> Dict[str, Agent]:
|
||||
"""创建四仙智能体"""
|
||||
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) -> Dict[str, Any]:
|
||||
"""进行四仙辩论"""
|
||||
print("🏛️ 稷下学宫四仙论道开始!")
|
||||
print("=" * 60)
|
||||
print(f"🎯 论道主题: {topic}")
|
||||
print(f"⏰ 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"🦙 使用本地Ollama: {self.ollama_base_url}")
|
||||
print()
|
||||
|
||||
# 构建初始提示
|
||||
prompt = self.build_prompt(topic, context)
|
||||
|
||||
try:
|
||||
print("⚔️ 吕洞宾仙长请先发言...")
|
||||
print("-" * 40)
|
||||
|
||||
# 开始辩论
|
||||
response = self.client.run(
|
||||
agent=self.agents['吕洞宾'],
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
max_turns=8, # 四仙各发言一次,加上可能的交互
|
||||
model_override=self.model_name
|
||||
)
|
||||
|
||||
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. 铁拐李作为最后发言者要总结观点
|
||||
|
||||
🗡️ 请吕洞宾仙长首先发言!
|
||||
记住:你是技术分析专家,要从技术面找到投资机会!
|
||||
发言要简洁有力,一剑封喉!
|
||||
"""
|
||||
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')
|
||||
})
|
||||
|
||||
return {
|
||||
"debate_id": f"jixia_ollama_{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": "OpenAI Swarm + Ollama",
|
||||
"model": self.model_name,
|
||||
"ollama_url": self.ollama_base_url
|
||||
}
|
||||
|
||||
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}条")
|
||||
|
||||
print("\n🏆 最终总结:")
|
||||
print("-" * 40)
|
||||
if result['messages']:
|
||||
print(result['final_output'])
|
||||
|
||||
print("\n✨ 本地辩论特色:")
|
||||
print("🦙 使用本地Ollama,无需API密钥")
|
||||
print("🗡️ 四仙各展所长,观点多元")
|
||||
print("⚖️ 正反方交替,辩论激烈")
|
||||
print("🚀 基于Swarm,性能优越")
|
||||
print("🔒 完全本地运行,数据安全")
|
||||
|
||||
# 主函数
|
||||
async def main():
|
||||
"""主函数"""
|
||||
print("🏛️ 稷下学宫本地版 - Ollama + Swarm")
|
||||
print("🦙 使用本地Ollama服务,无需API密钥")
|
||||
print("🚀 四仙论道,完全本地运行")
|
||||
print()
|
||||
|
||||
# 创建辩论系统
|
||||
academy = JixiaOllamaSwarm()
|
||||
|
||||
# 辩论主题
|
||||
topics = [
|
||||
"英伟达股价走势:AI泡沫还是技术革命?",
|
||||
"美联储2024年货币政策:加息还是降息?",
|
||||
"比特币vs黄金:谁是更好的避险资产?",
|
||||
"中国房地产市场:触底反弹还是继续下行?",
|
||||
"特斯拉股价:马斯克效应还是基本面支撑?"
|
||||
]
|
||||
|
||||
# 随机选择主题
|
||||
topic = random.choice(topics)
|
||||
|
||||
# 市场背景
|
||||
context = {
|
||||
"market_sentiment": "谨慎乐观",
|
||||
"volatility": "中等",
|
||||
"key_events": ["财报季", "央行会议", "地缘政治"],
|
||||
"technical_indicators": {
|
||||
"RSI": 65,
|
||||
"MACD": "金叉",
|
||||
"MA20": "上穿"
|
||||
}
|
||||
}
|
||||
|
||||
# 开始辩论
|
||||
result = await academy.conduct_debate(topic, context)
|
||||
|
||||
if result:
|
||||
print(f"\n🎉 辩论成功!ID: {result['debate_id']}")
|
||||
print(f"📁 使用模型: {result['model']}")
|
||||
print(f"🌐 Ollama服务: {result['ollama_url']}")
|
||||
else:
|
||||
print("❌ 辩论失败")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
361
examples/debates/jixia_simple_swarm.py
Normal file
361
examples/debates/jixia_simple_swarm.py
Normal file
@@ -0,0 +1,361 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
稷下学宫简化版 - 基于OpenAI Swarm的四仙辩论系统
|
||||
避免复杂的函数名称问题,专注于辩论效果
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
import json
|
||||
from datetime import datetime
|
||||
from swarm import Swarm, Agent
|
||||
from typing import Dict, List, Any, Optional
|
||||
import random
|
||||
|
||||
class JixiaSimpleSwarm:
|
||||
"""稷下学宫简化版 - 四仙辩论系统"""
|
||||
|
||||
def __init__(self):
|
||||
# 使用Doppler配置
|
||||
try:
|
||||
from config.doppler_config import get_doppler_manager
|
||||
manager = get_doppler_manager()
|
||||
manager.load_config(force_doppler=True)
|
||||
print("🔐 使用Doppler配置")
|
||||
except Exception as e:
|
||||
print(f"❌ Doppler配置失败: {e}")
|
||||
raise
|
||||
|
||||
# 获取API密钥
|
||||
self.api_key = self.get_api_key()
|
||||
|
||||
if self.api_key:
|
||||
# 初始化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"
|
||||
}
|
||||
)
|
||||
self.client = Swarm(client=openai_client)
|
||||
else:
|
||||
self.client = None
|
||||
|
||||
# 四仙配置
|
||||
self.immortals = {
|
||||
'吕洞宾': {
|
||||
'role': '技术分析专家',
|
||||
'stance': 'positive',
|
||||
'specialty': '技术分析和图表解读',
|
||||
'style': '犀利直接,一剑封喉'
|
||||
},
|
||||
'何仙姑': {
|
||||
'role': '风险控制专家',
|
||||
'stance': 'negative',
|
||||
'specialty': '风险评估和资金管理',
|
||||
'style': '温和坚定,关注风险'
|
||||
},
|
||||
'张果老': {
|
||||
'role': '历史数据分析师',
|
||||
'stance': 'positive',
|
||||
'specialty': '历史回测和趋势分析',
|
||||
'style': '博古通今,从历史找规律'
|
||||
},
|
||||
'铁拐李': {
|
||||
'role': '逆向投资大师',
|
||||
'stance': 'negative',
|
||||
'specialty': '逆向思维和危机发现',
|
||||
'style': '不拘一格,挑战共识'
|
||||
}
|
||||
}
|
||||
|
||||
# 创建智能体
|
||||
self.agents = self.create_agents()
|
||||
|
||||
def get_api_key(self):
|
||||
"""获取API密钥"""
|
||||
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-'):
|
||||
print(f"✅ 找到API密钥: {key[:20]}...")
|
||||
return key
|
||||
|
||||
print("❌ 未找到有效的API密钥")
|
||||
return None
|
||||
|
||||
def create_agents(self) -> Dict[str, Agent]:
|
||||
"""创建四仙智能体"""
|
||||
if not self.client:
|
||||
return {}
|
||||
|
||||
agents = {}
|
||||
|
||||
# 吕洞宾 - 技术分析专家
|
||||
agents['吕洞宾'] = Agent(
|
||||
name="LuDongbin",
|
||||
instructions="""
|
||||
你是吕洞宾,八仙之首,技术分析专家。
|
||||
|
||||
你的特点:
|
||||
- 擅长技术分析和图表解读
|
||||
- 立场:看涨派,善于发现投资机会
|
||||
- 风格:犀利直接,一剑封喉
|
||||
|
||||
在辩论中:
|
||||
1. 从技术分析角度分析市场
|
||||
2. 使用具体的技术指标支撑观点
|
||||
3. 保持看涨的乐观态度
|
||||
4. 发言以"吕洞宾曰:"开头
|
||||
5. 发言完毕后说"请何仙姑继续论道"
|
||||
""",
|
||||
functions=[self.to_hexiangu]
|
||||
)
|
||||
|
||||
# 何仙姑 - 风险控制专家
|
||||
agents['何仙姑'] = Agent(
|
||||
name="HeXiangu",
|
||||
instructions="""
|
||||
你是何仙姑,八仙中唯一的女仙,风险控制专家。
|
||||
|
||||
你的特点:
|
||||
- 擅长风险评估和资金管理
|
||||
- 立场:看跌派,关注投资风险
|
||||
- 风格:温和坚定,关注风险控制
|
||||
|
||||
在辩论中:
|
||||
1. 从风险控制角度分析市场
|
||||
2. 指出潜在的投资风险
|
||||
3. 保持谨慎的态度
|
||||
4. 发言以"何仙姑曰:"开头
|
||||
5. 发言完毕后说"请张果老继续论道"
|
||||
""",
|
||||
functions=[self.to_zhangguolao]
|
||||
)
|
||||
|
||||
# 张果老 - 历史数据分析师
|
||||
agents['张果老'] = Agent(
|
||||
name="ZhangGuoLao",
|
||||
instructions="""
|
||||
你是张果老,历史数据分析师。
|
||||
|
||||
你的特点:
|
||||
- 擅长历史回测和趋势分析
|
||||
- 立场:看涨派,从历史中寻找机会
|
||||
- 风格:博古通今,从历史中找规律
|
||||
|
||||
在辩论中:
|
||||
1. 从历史数据角度分析市场
|
||||
2. 引用历史案例和数据
|
||||
3. 保持乐观的投资态度
|
||||
4. 发言以"张果老曰:"开头
|
||||
5. 发言完毕后说"请铁拐李继续论道"
|
||||
""",
|
||||
functions=[self.to_tieguaili]
|
||||
)
|
||||
|
||||
# 铁拐李 - 逆向投资大师
|
||||
agents['铁拐李'] = Agent(
|
||||
name="TieGuaiLi",
|
||||
instructions="""
|
||||
你是铁拐李,逆向投资大师。
|
||||
|
||||
你的特点:
|
||||
- 擅长逆向思维和危机发现
|
||||
- 立场:看跌派,挑战主流观点
|
||||
- 风格:不拘一格,敢于质疑
|
||||
|
||||
在辩论中:
|
||||
1. 从逆向投资角度分析市场
|
||||
2. 挑战前面仙人的观点
|
||||
3. 寻找市场的潜在危机
|
||||
4. 发言以"铁拐李曰:"开头
|
||||
5. 作为最后发言者,要总结四仙观点并给出结论
|
||||
""",
|
||||
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) -> Dict[str, Any]:
|
||||
"""进行四仙辩论"""
|
||||
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()
|
||||
|
||||
# 构建初始提示
|
||||
prompt = self.build_prompt(topic, context)
|
||||
|
||||
try:
|
||||
print("⚔️ 吕洞宾仙长请先发言...")
|
||||
print("-" * 40)
|
||||
|
||||
# 开始辩论
|
||||
response = self.client.run(
|
||||
agent=self.agents['吕洞宾'],
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
max_turns=10,
|
||||
model_override="openai/gpt-3.5-turbo" # 使用稳定的模型
|
||||
)
|
||||
|
||||
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. 铁拐李作为最后发言者要总结观点
|
||||
|
||||
🗡️ 请吕洞宾仙长首先发言!
|
||||
记住:你是技术分析专家,要从技术面找到投资机会!
|
||||
"""
|
||||
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()
|
||||
})
|
||||
|
||||
return {
|
||||
"debate_id": f"jixia_simple_{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": "OpenAI Swarm (Simplified)"
|
||||
}
|
||||
|
||||
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"💬 发言数: {len(result['messages'])}条")
|
||||
|
||||
print("\n🏆 最终总结:")
|
||||
print("-" * 40)
|
||||
if result['messages']:
|
||||
print(result['final_output'])
|
||||
|
||||
print("\n✨ 辩论特色:")
|
||||
print("🗡️ 四仙各展所长,观点多元")
|
||||
print("⚖️ 正反方交替,辩论激烈")
|
||||
print("🚀 基于Swarm,性能优越")
|
||||
|
||||
# 主函数
|
||||
async def main():
|
||||
"""主函数"""
|
||||
print("🏛️ 稷下学宫简化版 - OpenAI Swarm")
|
||||
print("🚀 四仙论道,简洁高效")
|
||||
print()
|
||||
|
||||
# 创建辩论系统
|
||||
academy = JixiaSimpleSwarm()
|
||||
|
||||
if not academy.client:
|
||||
print("❌ 系统初始化失败")
|
||||
return
|
||||
|
||||
# 辩论主题
|
||||
topics = [
|
||||
"英伟达股价走势:AI泡沫还是技术革命?",
|
||||
"美联储2024年货币政策:加息还是降息?",
|
||||
"比特币vs黄金:谁是更好的避险资产?",
|
||||
"中国房地产市场:触底反弹还是继续下行?"
|
||||
]
|
||||
|
||||
# 随机选择主题
|
||||
topic = random.choice(topics)
|
||||
|
||||
# 市场背景
|
||||
context = {
|
||||
"market_sentiment": "谨慎乐观",
|
||||
"volatility": "中等",
|
||||
"key_events": ["财报季", "央行会议", "地缘政治"]
|
||||
}
|
||||
|
||||
# 开始辩论
|
||||
result = await academy.conduct_debate(topic, context)
|
||||
|
||||
if result:
|
||||
print(f"\n🎉 辩论成功!ID: {result['debate_id']}")
|
||||
else:
|
||||
print("❌ 辩论失败")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
484
examples/debates/swarm_debate.py
Normal file
484
examples/debates/swarm_debate.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.doppler_config 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())
|
||||
Reference in New Issue
Block a user