🏗️ 项目重构:模块化清理完成
This commit is contained in:
106
modules/documentation-suite/examples/data/demo_results_aapl.json
Normal file
106
modules/documentation-suite/examples/data/demo_results_aapl.json
Normal 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
|
||||
}
|
||||
}
|
||||
106
modules/documentation-suite/examples/data/demo_results_msft.json
Normal file
106
modules/documentation-suite/examples/data/demo_results_msft.json
Normal 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
|
||||
}
|
||||
}
|
||||
106
modules/documentation-suite/examples/data/demo_results_tsla.json
Normal file
106
modules/documentation-suite/examples/data/demo_results_tsla.json
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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())
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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())
|
||||
@@ -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()
|
||||
245
modules/documentation-suite/examples/memory_bank_demo.py
Normal file
245
modules/documentation-suite/examples/memory_bank_demo.py
Normal 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())
|
||||
356
modules/documentation-suite/examples/mongodb_swarm_example.py
Normal file
356
modules/documentation-suite/examples/mongodb_swarm_example.py
Normal 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()
|
||||
Reference in New Issue
Block a user