diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1fed5fc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 AI Agent Collaboration Framework
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md
new file mode 100644
index 0000000..85b3c42
--- /dev/null
+++ b/PROJECT_STRUCTURE.md
@@ -0,0 +1,90 @@
+# 孢子殖民地项目 - 清理后结构
+
+## 🎯 根目录(极简版)
+
+```
+孢子殖民地/
+├── README.md # 项目核心介绍
+├── LICENSE # 开源许可证
+├── main.py # 主程序入口
+├── ai_collaboration_demo.py # AI协作演示
+├── install.sh # 一键安装脚本
+├── requirements.txt # Python依赖
+├── package.json # Node.js依赖
+├── pytest.ini # 测试配置
+├── .gitignore # Git忽略规则
+├── .gitguardian.yaml # 安全配置
+├── agents/ # AI代理身份系统(核心)
+├── src/ # 核心协作系统源码
+├── app/ # Streamlit应用
+├── demo_feature/ # 演示功能
+├── design/ # 设计文档
+├── docs/ # 项目文档
+├── examples/ # 使用示例
+├── outputs/ # 输出结果
+├── tests/ # 测试文件
+├── tools/ # 工具脚本
+├── website/ # 项目网站
+└── modules/ # 模块化组件
+ ├── agent-identity/ # AI代理身份模块
+ ├── core-collaboration/ # 核心协作模块
+ ├── monitoring-dashboard/ # 监控面板模块
+ ├── documentation-suite/ # 文档套件模块
+ ├── testing-framework/ # 测试框架模块
+ ├── devops-tools/ # DevOps工具模块
+ └── legacy-support/ # 历史支持文件
+```
+
+## 📁 核心目录说明
+
+### 🎯 根目录保留文件
+- **main.py**: 项目主入口,启动AI协作系统
+- **ai_collaboration_demo.py**: AI协作演示脚本
+- **install.sh**: 一键安装所有依赖和环境
+- **requirements.txt**: Python依赖清单
+- **package.json**: Node.js依赖和脚本
+
+### 🏗️ 核心系统目录
+- **agents/**: AI代理身份管理系统
+- **src/**: 核心协作系统源代码
+- **app/**: Streamlit Web应用界面
+- **tests/**: 单元测试和集成测试
+- **tools/**: 开发工具和实用脚本
+
+### 📊 项目资产目录
+- **docs/**: 项目文档和使用指南
+- **examples/**: 使用示例和演示案例
+- **design/**: 系统架构和设计文档
+- **outputs/**: 运行输出和结果存储
+- **website/**: 项目展示网站
+
+### 🧩 模块化组件(modules/)
+所有复杂功能和历史文件已迁移到modules目录:
+- **legacy-support/**: 历史文件、报告、临时文件
+- **其他5个模块**: 之前创建的模块化组件
+
+## 🚀 快速开始
+
+```bash
+# 1. 克隆项目
+git clone [项目地址]
+cd 孢子殖民地
+
+# 2. 一键安装
+./install.sh
+
+# 3. 启动项目
+python main.py
+
+# 4. 访问Web界面
+streamlit run app/streamlit_app.py
+```
+
+## 🎯 设计哲学
+
+**极简根目录**:只保留最核心、最常用的文件
+**模块化组织**:复杂功能全部封装到modules目录
+**清晰边界**:核心系统与辅助工具完全分离
+**易于导航**:3秒内找到任何文件
+
+现在项目根目录从30+个文件减少到17个,清爽多了! 🎉
\ No newline at end of file
diff --git a/README.md b/README.md
index 32f817c..956c7f0 100644
--- a/README.md
+++ b/README.md
@@ -1,282 +1,238 @@
-# 🏛️ 炼妖壶 (Lianyaohu) - 稷下学宫AI辩论系统
+# 🤖 AI Agent Collaboration Framework
-> 🧹 **致AI开发者**: 入此稷下学宫者,当先读 [`AI_DEVELOPER_GUIDELINES.md`](./AI_DEVELOPER_GUIDELINES.md) 了解项目规矩,明藏经阁章法。扫地僧叮嘱:代码如经书,需整齐摆放;文化特色不可丢,八仙智慧要传承。
+> **从模拟到真实:让每个AI Agent都拥有独立的Git身份,实现真正的实盘协作**
-提示:已支持 Cloudflare AutoRAG/Vectorize 作为记忆后端(RAG)。见 docs/guides/CLOUDFLARE_AUTORAG_INTEGRATION.md。
+[](https://opensource.org/licenses/MIT)
+[](https://www.python.org/downloads/)
+[](https://git-scm.com/)
+[](https://github.com/your-org/agent-collaboration-framework/actions)
-基于中国哲学传统的多AI智能体辩论平台,重构版本。
+## 🎯 核心理念
-## ✨ 核心特性
+**不是让AI Agent假装协作,而是让每个Agent都有真实的Git身份:独立的SSH密钥、GPG签名、用户名和邮箱,实现可追溯的团队协作历史。**
-- **🎭 稷下学宫八仙论道**: 基于中国传统八仙文化的多AI智能体辩论系统
-- **🧠 Vertex AI记忆银行**: 集成Google Cloud Memory Bank,让AI智能体具备持久化记忆能力
-- **🌍 天下体系分析**: 基于儒门天下观的资本生态"天命树"分析模型
-- **🔒 安全配置管理**: 使用Doppler进行统一的密钥和配置管理
-- **📊 智能数据源**: 基于17个RapidAPI订阅的永动机数据引擎
-- **📈 市场数据 (可选)**: 集成 OpenBB v4,统一路由多数据提供商,详见 docs/openbb_integration/README.md
-- **🎨 现代化界面**: 基于Streamlit的响应式Web界面
+## ✨ 特性亮点
-## 🏗️ 项目结构
+### 🔐 真实身份系统
+- ✅ 每个Agent拥有独立的SSH密钥对
+- ✅ 独立的GPG签名密钥(可选)
+- ✅ 独立的Git配置(用户名、邮箱)
+- ✅ 可追溯的完整提交历史
-```
-liurenchaxin/
-├── app/ # 应用入口
-│ ├── streamlit_app.py # 主Streamlit应用
-│ └── tabs/ # 功能模块
-│ └── tianxia_tab.py # 天下体系分析
-├── src/ # 核心业务逻辑
-│ └── jixia/ # 稷下学宫系统
-│ └── engines/ # 核心引擎
-│ └── perpetual_engine.py # 永动机引擎
-├── config/ # 配置管理
-│ └── settings.py # Doppler配置接口
-├── scripts/ # 工具脚本
-│ └── test_openrouter_api.py # API连接测试
-├── tests/ # 测试代码
-├── .kiro/ # Kiro AI助手配置
-│ └── steering/ # AI指导规则
-└── requirements.txt # 依赖清单
+### 🤖 预定义Agent角色
+| Agent | 角色 | 专长 |
+|-------|------|------|
+| `claude-ai` | 架构师 | 系统设计、技术选型 |
+| `gemini-dev` | 开发者 | 核心功能开发 |
+| `qwen-ops` | 运维 | 部署脚本、监控 |
+| `llama-research` | 研究员 | 性能分析、优化 |
+
+### 🚀 一键启动
+```bash
+curl -fsSL https://raw.githubusercontent.com/your-org/agent-collaboration-framework/main/install.sh | bash
```
-## 🚀 快速开始
+## 🏃♂️ 快速开始
-### 1. 环境准备
+### 1. 安装
+```bash
+git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+./install.sh
+```
-#### 方法一:使用自动化设置脚本(推荐)
+### 2. 运行演示
+```bash
+# 启动多Agent协作演示
+python3 examples/basic/demo_collaboration.py
+
+# 查看Agent状态
+./agents/stats.sh
+```
+
+### 3. 手动协作
+```bash
+# 切换到架构师Agent
+./agents/switch_agent.sh claude-ai
+echo "# 系统架构设计" > docs/architecture.md
+git add docs/architecture.md
+git commit -m "添加系统架构设计文档"
+
+# 切换到开发者Agent
+./agents/switch_agent.sh gemini-dev
+echo "console.log('Hello World');" > src/app.js
+git add src/app.js
+git commit -m "实现基础应用功能"
+```
+
+## 📊 实时协作展示
+
+### 当前Agent活动
+```bash
+$ ./agents/stats.sh
+
+🔍 Agent协作统计:
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+Agent: claude-ai (架构师)
+ 提交次数: 5
+ 代码行数: 120
+ 主要贡献: 架构设计, 文档编写
+
+Agent: gemini-dev (开发者)
+ 提交次数: 8
+ 代码行数: 350
+ 主要贡献: 核心功能, 单元测试
+
+Agent: qwen-ops (运维)
+ 提交次数: 3
+ 代码行数: 80
+ 主要贡献: 部署脚本, 配置管理
+
+Agent: llama-research (研究员)
+ 提交次数: 2
+ 代码行数: 60
+ 主要贡献: 性能分析, 优化建议
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+```
+
+## 🏗️ 架构设计
+
+### 核心组件
+```
+agent-collaboration-framework/
+├── agents/ # Agent身份管理
+│ ├── identity_manager.py # 身份管理系统
+│ ├── switch_agent.sh # Agent切换工具
+│ └── stats.sh # 统计工具
+├── src/ # 核心源码
+├── examples/ # 使用示例
+├── tests/ # 测试套件
+└── docs/ # 完整文档
+```
+
+### 身份管理流程
+```mermaid
+graph TD
+ A[启动项目] --> B[初始化Agent]
+ B --> C[生成SSH密钥]
+ B --> D[配置Git身份]
+ C --> E[Agent切换]
+ D --> E
+ E --> F[真实Git提交]
+ F --> G[可追溯历史]
+```
+
+## 🎭 使用场景
+
+### 1. 🏢 个人项目增强
+- 模拟大型团队协作
+- 代码审查练习
+- 架构设计验证
+
+### 2. 🎓 教学演示
+- Git协作教学
+- 敏捷开发实践
+- 代码审查培训
+
+### 3. 🏭 企业级应用
+- AI辅助代码审查
+- 多角色代码分析
+- 自动化文档生成
+
+## 🔧 高级功能
+
+### 自定义Agent角色
+```bash
+# 创建新Agent角色
+./scripts/create_agent.sh "rust-expert" "Rust专家" "rust@ai-collaboration.local"
+```
+
+### 批量操作
+```bash
+# 所有Agent同时更新文档
+./scripts/bulk_commit.sh "更新文档" --agents="all"
+```
+
+### 代码审查模式
+```bash
+# 启动审查模式
+./scripts/review_mode.sh
+```
+
+## 🐳 Docker部署
```bash
-# 一键设置虚拟环境和依赖
-./setup_venv.sh
+# 使用Docker快速启动
+docker run -it \
+ -v $(pwd):/workspace \
+ agent-collaboration:latest
+
+# 使用Docker Compose
+docker-compose up -d
```
-#### 方法二:手动设置
+## 📈 路线图
-```bash
-# 创建虚拟环境
-python3 -m venv venv
+### Phase 1: 核心功能 ✅
+- [x] 多Agent身份管理
+- [x] Git协作演示
+- [x] 基础工具脚本
+- [x] Docker支持
-# 激活虚拟环境
-# macOS/Linux
-source venv/bin/activate
-# Windows CMD
-# venv\Scripts\activate.bat
-# Windows PowerShell
-# venv\Scripts\Activate.ps1
+### Phase 2: 增强协作 🚧
+- [ ] Web界面管理
+- [ ] 实时协作监控
+- [ ] 代码质量分析
+- [ ] 权限管理系统
-# 升级pip
-pip install --upgrade pip
-
-# 安装依赖
-pip install -r requirements.txt
-```
-
-#### 虚拟环境管理
-
-```bash
-# 激活虚拟环境
-source venv/bin/activate
-
-# 退出虚拟环境
-deactivate
-
-# 查看已安装的包
-pip list
-
-# 更新依赖(开发时)
-pip freeze > requirements.txt
-```
-
-### 2. 配置管理
-
-项目使用Doppler进行安全的配置管理。需要配置以下环境变量:
-
-```bash
-# 必需配置(数据源)
-RAPIDAPI_KEY=your_rapidapi_key
-
-# 选择其一的AI服务密钥
-# A) OpenRouter(旧)
-OPENROUTER_API_KEY_1=your_openrouter_key
-# B) Google ADK / Gemini(新)
-GOOGLE_API_KEY=your_gemini_api_key
-# 如果使用 Vertex AI Express Mode(可选)
-GOOGLE_GENAI_USE_VERTEXAI=TRUE
-
-# Vertex AI Memory Bank 配置(新功能)
-GOOGLE_CLOUD_PROJECT_ID=your-project-id
-GOOGLE_CLOUD_LOCATION=us-central1
-VERTEX_MEMORY_BANK_ENABLED=TRUE
-
-# 可选配置
-POSTGRES_URL=your_postgres_url
-MONGODB_URL=your_mongodb_url
-ZILLIZ_URL=your_zilliz_url
-ZILLIZ_TOKEN=your_zilliz_token
-```
-
-### 3. 启动应用
-
-```bash
-# 启动Streamlit应用
-streamlit run app/streamlit_app.py
-
-# 或指定端口
-streamlit run app/streamlit_app.py --server.port 8501
-```
-
-### 4. 安装Swarm (可选)
-
-如果要使用Swarm八仙论道功能:
-
-```bash
-# 安装OpenAI Swarm
-python scripts/install_swarm.py
-
-# 或手动安装
-pip install git+https://github.com/openai/swarm.git
-```
-
-### 5. 测试连接
-
-```bash
-# 测试API连接
-python scripts/test_openrouter_api.py
-
-# 验证配置
-python config/settings.py
-
-# 测试Swarm辩论 (可选)
-python src/jixia/debates/swarm_debate.py
-
-# 测试Vertex AI Memory Bank (新功能)
-python tests/test_vertex_memory_bank.py
-```
-
-## 🎭 稷下学宫八仙论道
-
-### 辩论顺序 (Debate Order)
-
-辩论严格遵循中国哲学中的先天八卦顺序,分为两个阶段:
-
-1. **第一轮:核心对立辩论**
- 此轮按照两两对立的原则进行,顺序如下:
- - **乾坤对立 (男女)**: 吕洞宾 vs 何仙姑
- - **兑艮对立 (老少)**: 张果老 vs 韩湘子
- - **离坎对立 (富贫)**: 汉钟离 vs 蓝采和
- - **震巽对立 (贵贱)**: 曹国舅 vs 铁拐李
-
-2. **第二轮:顺序发言**
- 此轮按照先天八卦的完整顺序进行 (乾一, 兑二, 离三, 震四, 巽五, 坎六, 艮七, 坤八),顺序如下:
- - **乾**: 吕洞宾
- - **兑**: 张果老
- - **离**: 汉钟离
- - **震**: 曹国舅
- - **巽**: 铁拐李
- - **坎**: 蓝采和
- - **艮**: 韩湘子
- - **坤**: 何仙姑
-
-### 人物设定 (Character Settings)
-基于中国传统八仙文化,每位仙人都有专属的卦象、代表和人设:
-
-- **吕洞宾** (乾): 男性代表
-- **何仙姑** (坤): 女性代表
-- **张果老** (兑): 老者代表
-- **韩湘子** (艮): 少年代表
-- **汉钟离** (离): 富者代表
-- **蓝采和** (坎): 贫者代表
-- **曹国舅** (震): 贵者代表
-- **铁拐李** (巽): 贱者代表
-
-### Swarm模式 (AI智能体辩论)
-基于OpenAI Swarm框架的四仙智能体辩论系统:
-
-- **🗡️ 吕洞宾** (乾卦): 技术分析专家,看涨派,犀利直接
-- **🌸 何仙姑** (坤卦): 风险控制专家,看跌派,温和坚定
-- **📚 张果老** (兑卦): 历史数据分析师,看涨派,博古通今
-- **⚡ 铁拐李** (巽卦): 逆向投资大师,看跌派,挑战共识
-
-#### 支持两种运行模式:
-- **OpenRouter模式**: 使用云端AI服务,模型选择丰富
-- **Ollama模式**: 使用本地AI服务,完全离线运行
-
-## 🌍 天下体系分析
-
-基于儒门天下观的"天命树"结构模型:
-
-### 四层架构
-- **👑 天子**: 定义范式的平台型公司 (如NVIDIA, Tesla, Apple)
-- **🏛️ 大夫**: 深度绑定天子的核心供应商 (如TSMC, CATL)
-- **⚔️ 士**: 专业供应商和服务商 (如ASML, Luxshare)
-- **🔗 嫁接**: 跨生态的策略性链接关系
-
-### 三大生态
-- **🤖 AI生态**: NVIDIA统治的AI计算生态
-- **⚡ EV生态**: Tesla定义的电动汽车生态
-- **📱 消费电子生态**: Apple建立的iOS生态
-
-## 🔧 开发指南
-
-### 代码规范
-- 使用Python类型注解
-- 遵循PEP 8编码规范
-- 所有公共函数必须有文档字符串
-- 使用dataclass定义数据结构
-
-### 安全要求
-- **零硬编码密钥**: 所有敏感信息通过Doppler或环境变量获取
-- **环境隔离**: 开发、测试、生产环境严格分离
-- **自动化扫描**: 所有提交必须通过安全检查
-
-### 测试要求
-- 所有核心功能必须有单元测试
-- API调用必须有集成测试
-- 配置管理必须有验证测试
-
-## 📊 API使用统计
-
-项目基于17个RapidAPI订阅构建永动机数据引擎:
-
-- **智能故障转移**: 主API失败时自动切换备用API
-- **负载均衡**: 智能分配API调用,避免单点过载
-- **使用统计**: 实时监控API使用情况和成本优化
+### Phase 3: 企业级 🎯
+- [ ] 审计日志
+- [ ] 集成CI/CD
+- [ ] 高级分析
+- [ ] 云原生部署
## 🤝 贡献指南
-1. Fork项目
-2. 创建功能分支 (`git checkout -b feature/amazing-feature`)
-3. 提交更改 (`git commit -m 'Add amazing feature'`)
-4. 推送到分支 (`git push origin feature/amazing-feature`)
-5. 创建Pull Request
+我们欢迎所有形式的贡献!
+
+### 快速贡献
+1. 🍴 Fork项目
+2. 🌿 创建功能分支
+3. 📝 提交更改
+4. 🚀 创建Pull Request
+
+### 开发环境
+```bash
+git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+pip install -r requirements-dev.txt
+pytest tests/
+```
+
+## 📚 完整文档
+
+- 📖 [安装指南](SETUP.md)
+- 🚀 [快速开始](QUICK_START.md)
+- 🤝 [贡献指南](CONTRIBUTING.md)
+- 📊 [API文档](docs/api/README.md)
+- 🎓 [教程](docs/guides/README.md)
+
+## 📞 社区支持
+
+- 💬 [GitHub Discussions](https://github.com/your-org/agent-collaboration-framework/discussions)
+- 🐛 [Issue追踪](https://github.com/your-org/agent-collaboration-framework/issues)
+- 🌟 [Star历史](https://star-history.com/#your-org/agent-collaboration-framework)
## 📄 许可证
-本项目采用MIT许可证 - 详见 [LICENSE](LICENSE) 文件
-
-## ⚠️ 免责声明
-
-本系统仅供学习和研究使用。所有投资分析和建议仅供参考,不构成投资建议。投资有风险,决策需谨慎。
+[MIT许可证](LICENSE) - 详见许可证文件。
---
-**炼妖壶 - 让AI辩论照亮投资智慧** 🏛️✨
+
-## 🧪 ADK 开发调试(可选)
+**🚀 从模拟到真实,从工具到伙伴。**
-如果切换到 Google ADK:
+[](https://star-history.com/#your-org/agent-collaboration-framework&Date)
-```bash
-# 安装 ADK(任选其一)
-pip install google-adk
-# 或安装最新开发版
-pip install git+https://github.com/google/adk-python.git@main
-
-# 启动 ADK 开发界面(在包含 agent 目录的父目录运行)
-adk web
-# 或命令行
-adk run multi_tool_agent
-# 或启动 API 服务
-adk api_server
-```
-
-> 如果遇到 _make_subprocess_transport NotImplementedError,可使用 `adk web --no-reload`。
\ No newline at end of file
+
\ No newline at end of file
diff --git a/agents/agent_identity_manager.py b/agents/agent_identity_manager.py
index 1d58927..a2c14c5 100644
--- a/agents/agent_identity_manager.py
+++ b/agents/agent_identity_manager.py
@@ -164,8 +164,8 @@ class AgentIdentityManager:
else:
subprocess.run(["git", "add", "."], check=True, cwd=self.base_dir)
- # 提交
- subprocess.run(["git", "commit", "-S", "-m", message], check=True, cwd=self.base_dir)
+ # 提交 - 暂时禁用GPG签名
+ subprocess.run(["git", "commit", "-m", message], check=True, cwd=self.base_dir)
logging.info(f"Agent {agent_name} 提交: {message}")
diff --git a/agents/commit_as_agent.sh b/agents/commit_as_agent.sh
new file mode 100755
index 0000000..47c9745
--- /dev/null
+++ b/agents/commit_as_agent.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# 以指定agent身份提交
+
+if [[ $# -lt 2 ]]; then
+ echo "用法: ./commit_as_agent.sh \"提交信息\" [文件...]"
+ exit 1
+fi
+
+AGENT_NAME=$1
+MESSAGE=$2
+shift 2
+FILES=$@
+
+echo "📝 Agent $AGENT_NAME 正在提交..."
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+try:
+ manager.commit_as_agent('$AGENT_NAME', '$MESSAGE', '$FILES'.split() if '$FILES' else None)
+ print('✅ 提交成功')
+except Exception as e:
+ print(f'❌ 提交失败: {e}')
+ exit(1)
+"
diff --git a/agents/identities.json b/agents/identities.json
new file mode 100644
index 0000000..4cd411a
--- /dev/null
+++ b/agents/identities.json
@@ -0,0 +1,30 @@
+{
+ "claude-ai": {
+ "name": "claude-ai",
+ "email": "claude@ai-collaboration.local",
+ "role": "架构师",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/claude-ai_rsa",
+ "gpg_key_id": "CLAUDE-AI12345678"
+ },
+ "gemini-dev": {
+ "name": "gemini-dev",
+ "email": "gemini@ai-collaboration.local",
+ "role": "开发者",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/gemini-dev_rsa",
+ "gpg_key_id": "GEMINI-DEV12345678"
+ },
+ "qwen-ops": {
+ "name": "qwen-ops",
+ "email": "qwen@ai-collaboration.local",
+ "role": "运维",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/qwen-ops_rsa",
+ "gpg_key_id": "QWEN-OPS12345678"
+ },
+ "llama-research": {
+ "name": "llama-research",
+ "email": "llama@ai-collaboration.local",
+ "role": "研究员",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/llama-research_rsa",
+ "gpg_key_id": "LLAMA-RESEARCH12345678"
+ }
+}
\ No newline at end of file
diff --git a/agents/keys/claude-ai_rsa b/agents/keys/claude-ai_rsa
new file mode 100644
index 0000000..c8b6f81
--- /dev/null
+++ b/agents/keys/claude-ai_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAwxFTRs1dVvxWbPQVCywG/6mmw0NAa7CMqeclew+yJiSgNutKPK/C
+tA8JLcos59apqCHU1Z9vzw+7dAWw+BOVyHXbCBqH9+U7x5LI6QNvXckjhKkIoafjPTz2Vr
+51AKLt0u7EEPegETySbJoYcvueX0+fl8Vsbv20xmKQhYPWY3n7c0371hSr2c5xqKWn1Eyq
+a0mryLH64nnRLpJoL3qEPzxe+vdjr3/8qV9CYEak2etsiGTdB+KvUePvX9OZLi7Xut4tcT
+DtjLo6iAG7D+0v9X8iCIPP4x6tF3ozJtq/kDiIaw0Yr/gIjaEMhq7Q3w+Pfy9hx094dWiE
+KW8RByTl+cHUkb3V8Vh9abXglPc3NNZjlSVVqVlpYL6if7NCeqmqw9XnICI4cESgnerArN
+tUoW6w+ZAE6VWKeJkqaitR3+ieFAy5DiWKxRQV5I3YhyOIwgPdmprCYPU1G3aSBCxa3qu8
+AlQM/Vm+HfrItLJ0DVYNMbsBAyBKAfpjUjCmkx+ClsAnKQ+3SneQjJHCIRscy+MlTKKOpb
+wZwBiC685jWVm8AFCSV+tmhlVNhxgUBlVrO+cyW1oyypk1W2p9tEqxOMKFlZYfPisxdrRm
+xlY5wH6QnGFR3rV3KBwQlG5BRIzfbQ/54cccsihPGbYGdndjgeTPb68oYMAYGguZItCw+I
+kAAAdYn/2qxJ/9qsQAAAAHc3NoLXJzYQAAAgEAwxFTRs1dVvxWbPQVCywG/6mmw0NAa7CM
+qeclew+yJiSgNutKPK/CtA8JLcos59apqCHU1Z9vzw+7dAWw+BOVyHXbCBqH9+U7x5LI6Q
+NvXckjhKkIoafjPTz2Vr51AKLt0u7EEPegETySbJoYcvueX0+fl8Vsbv20xmKQhYPWY3n7
+c0371hSr2c5xqKWn1Eyqa0mryLH64nnRLpJoL3qEPzxe+vdjr3/8qV9CYEak2etsiGTdB+
+KvUePvX9OZLi7Xut4tcTDtjLo6iAG7D+0v9X8iCIPP4x6tF3ozJtq/kDiIaw0Yr/gIjaEM
+hq7Q3w+Pfy9hx094dWiEKW8RByTl+cHUkb3V8Vh9abXglPc3NNZjlSVVqVlpYL6if7NCeq
+mqw9XnICI4cESgnerArNtUoW6w+ZAE6VWKeJkqaitR3+ieFAy5DiWKxRQV5I3YhyOIwgPd
+mprCYPU1G3aSBCxa3qu8AlQM/Vm+HfrItLJ0DVYNMbsBAyBKAfpjUjCmkx+ClsAnKQ+3Sn
+eQjJHCIRscy+MlTKKOpbwZwBiC685jWVm8AFCSV+tmhlVNhxgUBlVrO+cyW1oyypk1W2p9
+tEqxOMKFlZYfPisxdrRmxlY5wH6QnGFR3rV3KBwQlG5BRIzfbQ/54cccsihPGbYGdndjge
+TPb68oYMAYGguZItCw+IkAAAADAQABAAACAFt79KJwDiaNkbrnfjcPHvkoh51sHPpkgpPs
+ZBei9NoOs1UOZHKxu47WvmdLOmRAuLCxrS/C5p0ls7RmNukhxk2NeHwEdWA9khu3K6Kcic
+5iVtYQsIugQWKnBKEKEbWKtB8I+8s5V0i+L63fVzgV6eCpZx+253PmaLHh6AW2HwXoX5Vk
+LYfpie9McuG1T1Cx4/sNQhON5SvyFbjR0SrzOrKtjZ4GCCp2y/hjRK4Cc64AS5ZsN31LQw
+4U6F74zg5qyaJKMOW1HLOzY2AF78U4aBWq2jtEFmteJ6+rD/JZBR6OZOxP6BQfL2O89DL2
+Kd9zXMk5X5IqI0RtEA6emE3RcEkwIYlzPTFCDTfg55Plb/J/oTUfk7YB/EivgJU6FPd2n2
+GHgDXBMShDtJ3Df0vKjjccK+/0VlRsthMKkiWTgo8cWLKK+WfVDQAvBObpKiTS626VBkXw
+qzz2RdPRWicpWMYEu8E0jaxvd0shZmtykPl3wNWBXvMJ+FEu3gI/gVwXlhVuDUs/HclTaw
+WjIYYzHixhJ+84wEY92FDhQNSXqqUi1XLaG/yQrU3hqYSRBNXKxyYH/a+B3sTiDYjJqZQY
+R9JBm+pQqqLU/Ktx1OPKCkFSAC4BSeT6+7SJ5Sfn7ebBPUv5N83aR1lsnHiKrPZmIPD4En
+7HxkRYLjkvcgipjaRBAAABAQDHzqfZ4CrabCbwKFPshBY3K34aJeW+MbxT38TUJ17BFVOp
+8GmIL2USxwudG2HCJYcEWWcB99QEo2E7NQVCbqnGyHOVoTvHnjIzJ5RWJ4ss37N42K0GCo
+W4y1Z5ffMOfuxC1439zzqhL4JZ1gZXS1s5cm5631/XdQPdJ5hzFpm3kzdNfxvbR0c8ezJw
+4azykDC8CKwNzm+0H7oABS9o9qQH3Ljzh0J+vtgfN8nqLccITJjK0t3ZHXKXu/lwYzldBa
+2ok2iXy3a+gT3ssZzTJa7XwtfLfL6Sam+qkLOa/kdlG0Du1WbSlrUvqnPlxEsgQAqyJpM3
+MzNyXJLc52WjJWINAAABAQDudHeXzFWf5syrRQjNP3zOHFAUe+qUVCJuhPeRTFjd7NLO7z
+3Linorxu8xJHVCSQnVq7ynpgC2dRnpqOk41XM9QsauMMMMM8pAix+EcD04gtvEAe6ATG+T
+XJO2hzzyj7h+HkEdzxAJXu79VVGNg/4oXnMt3o+SdjuPOE49o166rImlMoNlsp/+r+Mn2G
+mT3N52uWqKWq9ecWufS3TadrRxPmc067kx/paTdBy1tUdeZ4UaO3mzUXyxcfC8iXPDdidt
+sIswzQW5l2QR/J9HoU256vzkn48G6htbfUZC2PJlkDvthDHQKFtsINM9p31yxREdF6y6ay
+w1SAza+xu28cErAAABAQDRa53GCDz6CJrKpTxdG+aLgzLvdgRrYJT4N5yzIlzeV4bkTiD2
+AXBkkflrJGs44O8QzKINf8B70Hl3W8ntwQiY5rSeRCwPtFqtHqSrcpEa/vUJtmZ7VXI8YB
+vhPeFzGPsFfTBZ90n0ydb2pDApobuuusLMIZ11Nkwn4GDa3JhEb1Rd9vfq+c0cWzBs6xrn
+kCgQsy0dzeP9uDLxzmdsZr2VPuqrUazgxRmcVyoyURinnVxSVKMFgwfNOUPW+sz5Ene7mA
+ooYNmyPS8qV1DHDI9RXHYHoAB7gVOaHVoN6GYEXEZnDyYE52GhNlyIURq1RAdLFlJlThhv
+vR3eCJJDzksbAAAAHWNsYXVkZUBhaS1jb2xsYWJvcmF0aW9uLmxvY2FsAQIDBAU=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/agents/keys/claude-ai_rsa.pub b/agents/keys/claude-ai_rsa.pub
new file mode 100644
index 0000000..707504c
--- /dev/null
+++ b/agents/keys/claude-ai_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDEVNGzV1W/FZs9BULLAb/qabDQ0BrsIyp5yV7D7ImJKA260o8r8K0Dwktyizn1qmoIdTVn2/PD7t0BbD4E5XIddsIGof35TvHksjpA29dySOEqQihp+M9PPZWvnUAou3S7sQQ96ARPJJsmhhy+55fT5+XxWxu/bTGYpCFg9ZjeftzTfvWFKvZznGopafUTKprSavIsfriedEukmgveoQ/PF7692Ovf/ypX0JgRqTZ62yIZN0H4q9R4+9f05kuLte63i1xMO2MujqIAbsP7S/1fyIIg8/jHq0XejMm2r+QOIhrDRiv+AiNoQyGrtDfD49/L2HHT3h1aIQpbxEHJOX5wdSRvdXxWH1pteCU9zc01mOVJVWpWWlgvqJ/s0J6qarD1ecgIjhwRKCd6sCs21ShbrD5kATpVYp4mSpqK1Hf6J4UDLkOJYrFFBXkjdiHI4jCA92amsJg9TUbdpIELFreq7wCVAz9Wb4d+si0snQNVg0xuwEDIEoB+mNSMKaTH4KWwCcpD7dKd5CMkcIhGxzL4yVMoo6lvBnAGILrzmNZWbwAUJJX62aGVU2HGBQGVWs75zJbWjLKmTVban20SrE4woWVlh8+KzF2tGbGVjnAfpCcYVHetXcoHBCUbkFEjN9tD/nhxxyyKE8ZtgZ2d2OB5M9vryhgwBgaC5ki0LD4iQ== claude@ai-collaboration.local
diff --git a/agents/keys/gemini-dev_rsa b/agents/keys/gemini-dev_rsa
new file mode 100644
index 0000000..44dbf0d
--- /dev/null
+++ b/agents/keys/gemini-dev_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAou42SepgU14LX4eHE4MqtfNojoRZeGiZmypa7WUpLbxWYdfFcPN6
+wVMeQDsYPe1Q+acU3jaWFbQxN4Tuc1J6j6Sgbm907Qid14ZgfNI/D2JkxITWeRS9NHn6MM
+Qv1OFvkRwnAHS96wEAdOS4XewOJTF4/9OIDuP2dl2QCG6kplPih3/LvA8KOzFnWHwtx8oo
+rAHQaa+kS2Oj2zK6CijExMnFhtnGBwb3aoKV72uMpdSw0zEh0nAuebLtbGQ7VSqZO1/25z
+Xcz9AL/wWY0C4sytJxAQ26IVd6ZW5a9SwSZSMIFr/wWy++e6nZziJbm4lc/iW+Up4tdiVM
+2xDcCb6ft3xqCC2XJdeDV0gs1ZqxFLyGhraC6OKAkWnOuvivLYEA7L6GOk+fLZU0Tywnjr
+RHhR4hNyuE2MYb0UMAvBz+0XwQWtz08j2dgkhoDrad1ZsbGRaapicNPWt5fvgfEpktC/AJ
+ho9PGGbjpA1m1f1J5uiQs1LccYNYP8euv2ADWalms4AO+xrpq/lHiZdoONLYEMYMKZJGV4
+1nutvRbS1GY7ynTUEPt/1auk5PZ89UttNkrV56w2OWslsYbRuC6kJlvaGeoTkOZllL1oIU
+rJMV2Ey2bX6nNEmGK02FOH7zESoPaJC641d2XBoGK9+r5kQdyS44d1bO0fQqCP/qOwsWPC
+0AAAdYwAzzT8AM808AAAAHc3NoLXJzYQAAAgEAou42SepgU14LX4eHE4MqtfNojoRZeGiZ
+mypa7WUpLbxWYdfFcPN6wVMeQDsYPe1Q+acU3jaWFbQxN4Tuc1J6j6Sgbm907Qid14ZgfN
+I/D2JkxITWeRS9NHn6MMQv1OFvkRwnAHS96wEAdOS4XewOJTF4/9OIDuP2dl2QCG6kplPi
+h3/LvA8KOzFnWHwtx8oorAHQaa+kS2Oj2zK6CijExMnFhtnGBwb3aoKV72uMpdSw0zEh0n
+AuebLtbGQ7VSqZO1/25zXcz9AL/wWY0C4sytJxAQ26IVd6ZW5a9SwSZSMIFr/wWy++e6nZ
+ziJbm4lc/iW+Up4tdiVM2xDcCb6ft3xqCC2XJdeDV0gs1ZqxFLyGhraC6OKAkWnOuvivLY
+EA7L6GOk+fLZU0TywnjrRHhR4hNyuE2MYb0UMAvBz+0XwQWtz08j2dgkhoDrad1ZsbGRaa
+picNPWt5fvgfEpktC/AJho9PGGbjpA1m1f1J5uiQs1LccYNYP8euv2ADWalms4AO+xrpq/
+lHiZdoONLYEMYMKZJGV41nutvRbS1GY7ynTUEPt/1auk5PZ89UttNkrV56w2OWslsYbRuC
+6kJlvaGeoTkOZllL1oIUrJMV2Ey2bX6nNEmGK02FOH7zESoPaJC641d2XBoGK9+r5kQdyS
+44d1bO0fQqCP/qOwsWPC0AAAADAQABAAACACLTiU4uZ42aXhL63LAaivAeidxgxOEcdqz4
+ljwFMhKhHdPHM+BrYvNc6WvwVcOy7OqYQLko8NbNz/FenDuRRzpaBaLldxhNjbOqeQhlRm
+5q6UAqZs+106WaZxSycsjtsRPS8TFDQu8vJSJXW2NUGEfx9bu1QvFv39g4Mpfi0pXs+1Bc
+TDez/UteyYjb7ks01pHBx4M3tIYa08UAaEzQnxKzUGH9Pbt1zT/6jsMA+azetDdIWsLpEL
+4ZtW9EU3xmYR+UaSnN1RekkFPgJeRl4lQuPFJt1TnYQYTZ3F5on7v3i3yVZXKQV4aGbVSG
++o7aA0Md3Ts6rVwCKBXxWh9JHElcJyriZa8+zfy7usVDA9Ckc8rQq2YIYENKrvTrvJqBEP
+ILmlL8rHx4lMF8DQ6za2nMiBArB775cikyUwINOQG1CiJ8VJF8JbnkJDTdIK3DYsUqH+bx
+Nw95XUanbvsukfFAsRimrA0Pt+P8JkhKDcC1xtVJwZuotBjGrIAvkLbIijgsoFHSkSlOuG
+urVWbEXSAkmP436ig7Mrb0YgeTM+B6rfYbTHhkXhLv1/YdzsBv5B5BP7qx8neU/ZlHzhX2
++0JqunXiaT2Ii1PCf5ka2ma0JzCTWi0lgC3zGlqjIYC3fg1QW93z3HEpTb5DFjLiwf2+FN
+XnW0IykHuSBd4Dz10RAAABAQCpEFe3akl+FfPxnBipoSfofl9olYyNMRZU1UmnBcoVNClY
+rQT8r+E4Ww1F66qYWbm0HmiLxwGHUW1mKeiXT4MwLmcumywoGPaCum89w1pGpQ0oqK52GL
+rwbWW4LWkj8v7j5gC13APob2BhVN5apa4U4kvkPi9pKWjyh8PvLeiH9zZ5S3G3NcinaSAU
+x3bAPVT1CJoMY+GBND/CTfsYbKw3ep9/uLcgMcxJVv/ZlmtekH4EVmK1Se18QS8l7wvXwX
+ILx8Ue2Ckl3JbaAB4QH/AEshq4g3+4NMgVUv/YWd4p0LHAJOVvvd+FolqFvtsfNFWmd+lF
+EXMcXkhdVHFoTuv3AAABAQDbtplHMqLl8K7HSbMuHPvbQjrhRreBpaWn4xnw1EfsXz5gso
+sXavzW4+/MNzFNHrirzKSQsh1dcR4eU+ijeNEsUapXjXRfZUwUo7Fapy1YR9xV18kzhXWe
+IGfe7YiTZWJIP4gE49zWeLFJBcfBm/4PZ6qudETW9kGkRH4D2VmziczV0MlxaMmEsZQRGd
+hkHzcTSxRU4uXPdEB4H6WDmewz1GtzyjNW7ueJu5M/aWpgTaCsxy32q5Na7S5oHikx4BXx
+76AvAdWkpXxdIcR/shAj4US0HEEtqvVQigOeKzKMRmPtZauc1fXdh1aZQmL5nhtLWAgkxo
+vildRjy/ebOUMFAAABAQC91tudT6hVbidqrvqW4gIWLEmhrbO1OUK1iOqxL+7vIN7UdX7U
+EY6u0Bxm3T64ZaiCtPoOQaGqYT4KLqtk7UgQ4hGYtd2h2sqKKuv332VK4jZi3W7j59G8W3
+AsmUOG/QTJ2w54pKNb6mj5ynulcWNqZaPt3RjZTmcX+q6kGpsy2rjx2iaI8pBsPT84tflC
+H/SmNMrFvNdQoiA2J4YpjR0OSM2MfupOPNVtp/XmOTLofouTxvACcDuelpp1mbMvCV8Gz2
+J2riaECrhMYQJdWy7AkZpgVdDzR9q6jn7fTEWhZhCJUyWfs2nnr0cltd+04KdMAlfa8RBf
+NyFihIu4Dy0JAAAAHWdlbWluaUBhaS1jb2xsYWJvcmF0aW9uLmxvY2FsAQIDBAU=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/agents/keys/gemini-dev_rsa.pub b/agents/keys/gemini-dev_rsa.pub
new file mode 100644
index 0000000..7076afb
--- /dev/null
+++ b/agents/keys/gemini-dev_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCi7jZJ6mBTXgtfh4cTgyq182iOhFl4aJmbKlrtZSktvFZh18Vw83rBUx5AOxg97VD5pxTeNpYVtDE3hO5zUnqPpKBub3TtCJ3XhmB80j8PYmTEhNZ5FL00efowxC/U4W+RHCcAdL3rAQB05Lhd7A4lMXj/04gO4/Z2XZAIbqSmU+KHf8u8Dwo7MWdYfC3HyiisAdBpr6RLY6PbMroKKMTEycWG2cYHBvdqgpXva4yl1LDTMSHScC55su1sZDtVKpk7X/bnNdzP0Av/BZjQLizK0nEBDbohV3plblr1LBJlIwgWv/BbL757qdnOIlubiVz+Jb5Sni12JUzbENwJvp+3fGoILZcl14NXSCzVmrEUvIaGtoLo4oCRac66+K8tgQDsvoY6T58tlTRPLCeOtEeFHiE3K4TYxhvRQwC8HP7RfBBa3PTyPZ2CSGgOtp3VmxsZFpqmJw09a3l++B8SmS0L8AmGj08YZuOkDWbV/Unm6JCzUtxxg1g/x66/YANZqWazgA77Gumr+UeJl2g40tgQxgwpkkZXjWe629FtLUZjvKdNQQ+3/Vq6Tk9nz1S202StXnrDY5ayWxhtG4LqQmW9oZ6hOQ5mWUvWghSskxXYTLZtfqc0SYYrTYU4fvMRKg9okLrjV3ZcGgYr36vmRB3JLjh3Vs7R9CoI/+o7CxY8LQ== gemini@ai-collaboration.local
diff --git a/agents/keys/llama-research_rsa b/agents/keys/llama-research_rsa
new file mode 100644
index 0000000..2f879e9
--- /dev/null
+++ b/agents/keys/llama-research_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAwc3K8f6v88fxz27I4uXSJQbYfkaOsMgGqWj0ZyKAdXlBGxr9GdIA
+7PU0Lu+dBgUH3q5x0sP6jrccng6hqdT+UXqy90lfC5ZLG/b/g3Y0irUmmrsMOEUKsTFbA3
+NIrboVx4+1WwVDRXJPPG9DBs/LkJzwhN0E/LV/9bUs1IALoCriCDHuQ8dh4Jcnk380En1c
+L5FBbgiFdmw/hx3q/AjVYgXK2xOcYdalw12/4ENI3bPpxQgnHUgv/QwnUyMx4VCAZFrtDH
+lxVSs7Xi5BXkOozxRXOUgo9gGaRZOBuxWCkRlp7uic0m+rJ9YwuLflBtofMsydP52ifJov
+dbZ6H7e5JSIymlY9BgM4TcmMqxZltfMokdWcJBBatt5IfgUufPL4psst/RBb1VAZGBnNOO
+MUUfs7v065FUc79j8tJdGf/+VRwcmlTfqrIHfWLov8NsTf4LGQTXvV0LzpM5jVRfer/J1H
+To7PaEh0aKjoOREbUV1EUWKzHqgHXAv5e/olvbd8mZWTmk3Oaqjs8E2YMbXJK+3kRsvQKe
+2ofTqfqVfqvOrz4x5cdoiuUjNQxwsNllnkmesP6uLLSWg8ifNr8HvK74qLS4RW7ViYVLgm
+byMibySrQUN2CkIzQG6LKykDb3HwNoypuOExEghtKT8nist8Nqe+sHfnihia9WKS4F+UBS
+sAAAdYqiu9raorva0AAAAHc3NoLXJzYQAAAgEAwc3K8f6v88fxz27I4uXSJQbYfkaOsMgG
+qWj0ZyKAdXlBGxr9GdIA7PU0Lu+dBgUH3q5x0sP6jrccng6hqdT+UXqy90lfC5ZLG/b/g3
+Y0irUmmrsMOEUKsTFbA3NIrboVx4+1WwVDRXJPPG9DBs/LkJzwhN0E/LV/9bUs1IALoCri
+CDHuQ8dh4Jcnk380En1cL5FBbgiFdmw/hx3q/AjVYgXK2xOcYdalw12/4ENI3bPpxQgnHU
+gv/QwnUyMx4VCAZFrtDHlxVSs7Xi5BXkOozxRXOUgo9gGaRZOBuxWCkRlp7uic0m+rJ9Yw
+uLflBtofMsydP52ifJovdbZ6H7e5JSIymlY9BgM4TcmMqxZltfMokdWcJBBatt5IfgUufP
+L4psst/RBb1VAZGBnNOOMUUfs7v065FUc79j8tJdGf/+VRwcmlTfqrIHfWLov8NsTf4LGQ
+TXvV0LzpM5jVRfer/J1HTo7PaEh0aKjoOREbUV1EUWKzHqgHXAv5e/olvbd8mZWTmk3Oaq
+js8E2YMbXJK+3kRsvQKe2ofTqfqVfqvOrz4x5cdoiuUjNQxwsNllnkmesP6uLLSWg8ifNr
+8HvK74qLS4RW7ViYVLgmbyMibySrQUN2CkIzQG6LKykDb3HwNoypuOExEghtKT8nist8Nq
+e+sHfnihia9WKS4F+UBSsAAAADAQABAAACABECFf7x2pA66mJJdzDOeYhNVv+SAqDKFSeV
+8ekBMqPcndWaoz66WuFwzYEW/0FRfLTSu2ODVoBi2oyWfSKR8jXFXmJsWn6CVJoiLZ9kZs
+0Lg9VNeA+SI5OUYMfnPKgebh3i40gXKKW2F/UWUJwO7W8GDueiG/dvmEjAeyw1BpAqY0bT
+1vS00UasDUmY/sFmpgn4pfTZo5jWfCbH/eDbh5qAJqLeUDmX5FlGZ3nvfbwTN39WrVQZCz
+kacXMO4ihDb9kez7HqEIOodR/ZUFxM9Mojn1oEFrAsSNU1UkvQYfKI9+6DFIw1R6CJ4CG9
+5cgZqWZEZcJ4+5MS1vpuJr6U2Zcc5Y3u3zI0U4ct7sIy0JJu33QTFYzLVJqldVZDoYMz8J
+kBdKeAqMXiXAvfIt+Hf4PdyyBXEWghoQ4+8XlS2LpW/6oC4ti6P6x4o/I5bP4m2BOL9TIl
+6mI8Y6tn+KOaucrk8xkT6M7axVh85k+MxGyzribzV/q4tASnD1TP1v9S8t/nnb8lxCpmR+
+d+8Xobyp17+NmpzpTbXIR5Ed3nCm6YFVmss/pmEZpn3/O5hRpdiZsq40FlGceSnTGzUuDg
+yw9auBJyV5xzWifuaeANKqEETgzTtMIZaFk4QqJo34bPIk75zyYgV6QsRBDMdwoW7Du8AZ
+m+LHVRtTXm17cfM5s1AAABAExio5y4c5rORiVErlaUYyA3Yj8FdD4IZT/m59+7bGF/VrJ2
+ck5i+VPbVuCC2oeS6hzRA59EzsQYE9qIF5QRHtj5GeDe2EH+ZdhzZx6CkOv+K3sTHzEym3
+owX4SdObJqUOVyWI4kcrmihNh1o01V0/Lq7ZVpfnAah43BTBl4YsJTYZBcoVV5486VOpjq
+4dwvD+NporAjRUrohWiul9gViYcmm/44X59affoRhcDBU0l2+jp1ihKPCQGYss/qUszb/X
+3EVnbrbL4LvmFgZka3ZCFkjqvoCQs4gxBOv0NnySMTBN/J9s6kYJLTOb3q6oAq5z1Bo/+i
+oKoEY3a5UOs+QHEAAAEBAPXKz5/5XaVnSGHCmAVQAuOJ6pVFHfz4RW2wPKBoHFiYIiA7qX
+pw6iG1j63HQx8gjsY5DwHzm4Kko3TaPO9tqP3OON5u7XoXC79Ve0QrAxDIF++cS8wJbmlC
+R/GQimpZF83qZP/CbQn9VqHmuUSfHPNBa8iUPNrEGdBcEl1UoIB2MngyQcIFyHNteNi1l8
+zFuupTZuJ7X2hxHa8xVYBy1KR2KU7hSnRehEdLqy1PRJ9KZmxxIUqhGjAho1ACwLQVauXB
+mHXiIlmvauuaHNdeVgttBxFimTrl/QHLk6Xk/DtL4YQ5635zDCoW2MUal2lKS2GOiaWzMX
+gk5OzQnNpT6V8AAAEBAMnaQdi7TCmpm222QvqHQYpW1qzZnzIlQ9YfgwZ3x6Vm886i94Ch
+Kdh3EAORwkuSlKhypeA48sRh6rQUzmLDCJnX7PP8uzWsG0tStIKgrrbover7DoXeUJ8wny
+gOeK59Ch74Oq2cq627RUrID6brdYzNbzSNOEEtvpc3qwjrDmU9bIA7Asv0EXEx2dSsEvGM
+p2bDnDRdSQVMvtZCdslG6v1ivb9Lf0+qeP9jYHrTzO074AQhvvZ/CQjBtfzq0DtClh+vAh
+w6ws65DWG7gPaFZbnJwr3EZnMyWfEsKq9A6j+mZaFHaYcSqIM8j/gWlbECEEvCWzg2dfOa
+0yUZ7ZM9G7UAAAAcbGxhbWFAYWktY29sbGFib3JhdGlvbi5sb2NhbAECAwQFBgc=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/agents/keys/llama-research_rsa.pub b/agents/keys/llama-research_rsa.pub
new file mode 100644
index 0000000..2cb08d8
--- /dev/null
+++ b/agents/keys/llama-research_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDBzcrx/q/zx/HPbsji5dIlBth+Ro6wyAapaPRnIoB1eUEbGv0Z0gDs9TQu750GBQfernHSw/qOtxyeDqGp1P5RerL3SV8Llksb9v+DdjSKtSaauww4RQqxMVsDc0ituhXHj7VbBUNFck88b0MGz8uQnPCE3QT8tX/1tSzUgAugKuIIMe5Dx2HglyeTfzQSfVwvkUFuCIV2bD+HHer8CNViBcrbE5xh1qXDXb/gQ0jds+nFCCcdSC/9DCdTIzHhUIBkWu0MeXFVKzteLkFeQ6jPFFc5SCj2AZpFk4G7FYKRGWnu6JzSb6sn1jC4t+UG2h8yzJ0/naJ8mi91tnoft7klIjKaVj0GAzhNyYyrFmW18yiR1ZwkEFq23kh+BS588vimyy39EFvVUBkYGc044xRR+zu/TrkVRzv2Py0l0Z//5VHByaVN+qsgd9Yui/w2xN/gsZBNe9XQvOkzmNVF96v8nUdOjs9oSHRoqOg5ERtRXURRYrMeqAdcC/l7+iW9t3yZlZOaTc5qqOzwTZgxtckr7eRGy9Ap7ah9Op+pV+q86vPjHlx2iK5SM1DHCw2WWeSZ6w/q4stJaDyJ82vwe8rviotLhFbtWJhUuCZvIyJvJKtBQ3YKQjNAbosrKQNvcfA2jKm44TESCG0pPyeKy3w2p76wd+eKGJr1YpLgX5QFKw== llama@ai-collaboration.local
diff --git a/agents/keys/qwen-ops_rsa b/agents/keys/qwen-ops_rsa
new file mode 100644
index 0000000..967a4e9
--- /dev/null
+++ b/agents/keys/qwen-ops_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAzmqS8qCT+hBC3KahGwBcUxgYTl3+X/QTOFJ8+XJdAN7Eq8o9o0Tg
+THoF0X9HRa0yaIh3E62NKPmoM2d63rDAESjWaEGXNa7Tf9SkH92nHbnCYgGdRmTUgg5Sxy
+qdlg153KMri9V+fP7WSQPv0G9g8osR22Nn8VWgz1KTD+CCUkIPDC4EzrLVyAGfRmBwNp2l
+X/bibjavhqLaoCufinE6Mo7nl1QlQkL64awgiIHNkDY0pt6HW8NQ8fYdLQ20+Y06Va7GWN
+evNT+hFXpMlIW/JZuiLjnF1k6KJbTNzjkH0hQ7QUSpeYmAZppud4w7XAPOl/AO3ko6xWqE
+XLn7jsR4SCENUSFPcjXS07YJt50FMHtNLImXF/1k7rJgivbURjsPIbz6sg9McLTd4vZa7Y
+5ANCYEUxoYW3mt3JoxEpVSwDz2k78UrB3kCWZ81hMnZtAGnc0N4vpB0FfTr60pFXYSjUtM
+xR6uqwZ2DDR4o7xjTzBFgIlX2cD2MAJz6TAdJHM3h+E3zHgl42u66NtrpRJ6wkCEChl9jJ
+6teE5pkkITPIhzLTjKnXdUnnCNe29G6eYnHe/VVZHQm3uSK3RzZqvvr5hu+99X6yLcogaM
+ZxVRT2TM4QSZ6IEOKKn+WUEnjnCpJFaxtV76PB9vOJgo73hrr8Iqr3hmNRKSwY3kKpfT52
+sAAAdQbqgWgm6oFoIAAAAHc3NoLXJzYQAAAgEAzmqS8qCT+hBC3KahGwBcUxgYTl3+X/QT
+OFJ8+XJdAN7Eq8o9o0TgTHoF0X9HRa0yaIh3E62NKPmoM2d63rDAESjWaEGXNa7Tf9SkH9
+2nHbnCYgGdRmTUgg5Sxyqdlg153KMri9V+fP7WSQPv0G9g8osR22Nn8VWgz1KTD+CCUkIP
+DC4EzrLVyAGfRmBwNp2lX/bibjavhqLaoCufinE6Mo7nl1QlQkL64awgiIHNkDY0pt6HW8
+NQ8fYdLQ20+Y06Va7GWNevNT+hFXpMlIW/JZuiLjnF1k6KJbTNzjkH0hQ7QUSpeYmAZppu
+d4w7XAPOl/AO3ko6xWqEXLn7jsR4SCENUSFPcjXS07YJt50FMHtNLImXF/1k7rJgivbURj
+sPIbz6sg9McLTd4vZa7Y5ANCYEUxoYW3mt3JoxEpVSwDz2k78UrB3kCWZ81hMnZtAGnc0N
+4vpB0FfTr60pFXYSjUtMxR6uqwZ2DDR4o7xjTzBFgIlX2cD2MAJz6TAdJHM3h+E3zHgl42
+u66NtrpRJ6wkCEChl9jJ6teE5pkkITPIhzLTjKnXdUnnCNe29G6eYnHe/VVZHQm3uSK3Rz
+Zqvvr5hu+99X6yLcogaMZxVRT2TM4QSZ6IEOKKn+WUEnjnCpJFaxtV76PB9vOJgo73hrr8
+Iqr3hmNRKSwY3kKpfT52sAAAADAQABAAACAAL84mY+vyBDRpg4lRto6n5EwOrqR5ZucaVx
+wuPxl6yS+9lVZw5m/JeB//4pFh2WHHH7YQlWtyPM7mUewU1AXcfj8FZNQuJcefl0jEYqNT
+mOsWzpac3AWQSWpo4GV8qbrUMPobcZjagx2/7t1ii3/AGQXKO1fgQ+kn4XXJi5eHMMTJsg
+saqFNZIcmxlvuMrDMTXaoOah1wLJ7hU1gtdRAP3z48ttZvLuSkUtHUqB4fUE7wuSo38DG3
+OLBvTjKRJcERL/kJ0YqvGMrJoBODhbE+wizeEjeyTsjrZcaXWN4ulTuU8vP52wt+9zNFg1
+YojYEanIn6zfTw8087xlVoO75Bq7biwVSrqqKjZXNGUWnncUb/g+vIMi+pgLg4Vx7/oVaz
+CYbYYWSNiOaExhKQwI4O4YRvRg4YHrv8H98ZGeSGv3RJEyFytv5m7CJcbP22Pc4DQ+9B2k
+3Eu/flDralnIzSoYAz/pFDYi4+Bt6qht/emuDi5gtFOZ8/WBQWu/+0tKho9dB92i6iwTNa
+4NoyBDBtX3gapq+pnYDK2is2lMxLsn2eg01e3G5ESsMl4AoUS/CPBx6Nu/bIYAsuECPrnm
+vbGP2jYMi9NWJja8kHJBGnlteqquwt+PwO1F+oVXRAylt/jUZbv9dwt+TBYhb4rfeaUdp7
+jHJ9iSJv2w1bGQ02NZAAABADouV1qBX2MLFzQZrcyf757OlLC57nNiF4PDCVOTDnfdXp1K
+NyL+w9FCyrCAZGr96HgUGAtjqW9FT70PbXp92GfAgV0+E2etlP6Bbc4DT5gpZ2eObCsPxz
+IpegncUgjXjMuw5ObOD3VNCEYqO84VJHxGIymwOppbU01OkGIMevuZxw7Z9CQ+GACwHLp0
+l7mvBteOri455812VJxbFJQHwvcn7e3U10CpMt2w7fmZkmKAd6w6t82k4lC0jJ5lRTgn7z
+YpBcsVQr7xFnH2BfAovUUALuNoKOjYihlGB5WcxQKHKEiSrfIlM0ZK5gdOyD1iH08EmXLN
+STOjrBL7u/bpVzEAAAEBAPrHQA82x+O0hmG3LfKn8y2SkMP6VjArvkvC2HLobj9GbcjPmi
+E5FB+x9rPwVdORftW/tsAK2UGLC6l/OKEBV4/q34WJokTiy3Kab4hMDE7FDmWL5hBJBIi2
+9HO2P7OSPcBx5asTnOHyHyfjDmBBgA0EpMjpvpaa734AiN1g80r78hHbpu8on46BcAUPE9
+5j2bwzj3/yIgtqC/+SrnxzpenGBJDV1no3yTV9AGW7KtpMSCs+GDk8QZxg0oJgLLVyC3AT
+YaJgx2kLX/krKttH5R4m5bvufc7uNByUE40mmNfZH7jR4wGSafarJPoDumnOattHA00Uin
+2AgkGrGLezgAMAAAEBANK22zdHrY+LjwSomT3kbC/cHv7A7QJJuaQ8De2/Bd7H7zzYkNEe
+mpdxEKXhXDoMfg/WsKLEL8wUflEuUmy80ZngaPZ0r7sfDhEHbXNnweFV+5zFVk6+2r6Izr
+oXPCPqzKyvFgTZM0jBGTD9+wMu4MlIbHAClSO6gbP+TwY8QgJbehIZEV0bgqgsPaSdF2jZ
+HuHymvie8GwQfsNfAgUaw8pePFOULmvXv7kiE2k83PIx45AMOi81XImY9qDh2OAaRK+jS6
+FAwOjCgmb6hVPvkB+HZgZSi4x5JXfIYseksKWW/f7PNerG2b1wNH1tZueh53nGJlLkbZXB
+l4bSuqRUInkAAAAbcXdlbkBhaS1jb2xsYWJvcmF0aW9uLmxvY2Fs
+-----END OPENSSH PRIVATE KEY-----
diff --git a/agents/keys/qwen-ops_rsa.pub b/agents/keys/qwen-ops_rsa.pub
new file mode 100644
index 0000000..0239e64
--- /dev/null
+++ b/agents/keys/qwen-ops_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDOapLyoJP6EELcpqEbAFxTGBhOXf5f9BM4Unz5cl0A3sSryj2jROBMegXRf0dFrTJoiHcTrY0o+agzZ3resMARKNZoQZc1rtN/1KQf3acducJiAZ1GZNSCDlLHKp2WDXncoyuL1X58/tZJA+/Qb2DyixHbY2fxVaDPUpMP4IJSQg8MLgTOstXIAZ9GYHA2naVf9uJuNq+GotqgK5+KcToyjueXVCVCQvrhrCCIgc2QNjSm3odbw1Dx9h0tDbT5jTpVrsZY1681P6EVekyUhb8lm6IuOcXWTooltM3OOQfSFDtBRKl5iYBmmm53jDtcA86X8A7eSjrFaoRcufuOxHhIIQ1RIU9yNdLTtgm3nQUwe00siZcX/WTusmCK9tRGOw8hvPqyD0xwtN3i9lrtjkA0JgRTGhhbea3cmjESlVLAPPaTvxSsHeQJZnzWEydm0AadzQ3i+kHQV9OvrSkVdhKNS0zFHq6rBnYMNHijvGNPMEWAiVfZwPYwAnPpMB0kczeH4TfMeCXja7ro22ulEnrCQIQKGX2Mnq14TmmSQhM8iHMtOMqdd1SecI17b0bp5icd79VVkdCbe5IrdHNmq++vmG7731frItyiBoxnFVFPZMzhBJnogQ4oqf5ZQSeOcKkkVrG1Xvo8H284mCjveGuvwiqveGY1EpLBjeQql9Pnaw== qwen@ai-collaboration.local
diff --git a/agents/pre-commit-hook b/agents/pre-commit-hook
new file mode 100755
index 0000000..84b20dc
--- /dev/null
+++ b/agents/pre-commit-hook
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Agent提交前的钩子
+
+echo "🔍 检查agent身份..."
+AGENT_NAME=$(git config user.name)
+if [[ -z "$AGENT_NAME" ]]; then
+ echo "❌ 未设置agent身份,请先使用agent协作系统"
+ exit 1
+fi
+
+echo "✅ 当前agent: $AGENT_NAME"
diff --git a/agents/setup_agents.sh b/agents/setup_agents.sh
old mode 100644
new mode 100755
diff --git a/agents/stats.sh b/agents/stats.sh
new file mode 100755
index 0000000..a5f9180
--- /dev/null
+++ b/agents/stats.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# 查看agent统计信息
+
+echo "📊 Agent协作统计"
+echo "=================="
+
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+
+for agent in manager.list_agents():
+ name = agent['name']
+ stats = manager.get_agent_stats(name)
+ print(f'👤 {name} ({agent["role"]})')
+ print(f' 📧 {agent["email"]}')
+ print(f' 📈 提交数: {stats["total_commits"]}')
+ if stats["commits"]:
+ print(f' 📝 最近提交: {stats["commits"][0]}')
+ print()
+"
diff --git a/agents/switch_agent.sh b/agents/switch_agent.sh
new file mode 100755
index 0000000..bacc73b
--- /dev/null
+++ b/agents/switch_agent.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# 快速切换agent身份
+
+if [[ $# -eq 0 ]]; then
+ echo "用法: ./switch_agent.sh "
+ echo "可用agents:"
+ python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+for agent in manager.list_agents():
+ print(f' - {agent[\"name\"]} ({agent[\"role\"]})')
+ "
+ exit 1
+fi
+
+AGENT_NAME=$1
+echo "🔄 切换到agent: $AGENT_NAME"
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+try:
+ manager.switch_to_agent('$AGENT_NAME')
+ print('✅ 切换成功')
+except Exception as e:
+ print(f'❌ 切换失败: {e}')
+ exit(1)
+"
diff --git a/demo_feature/deploy.yaml b/demo_feature/deploy.yaml
new file mode 100644
index 0000000..b64804c
--- /dev/null
+++ b/demo_feature/deploy.yaml
@@ -0,0 +1,24 @@
+version: '3.8'
+services:
+ agent-monitor:
+ build: .
+ ports:
+ - "8000:8000"
+ environment:
+ - REDIS_URL=redis://redis:6379
+ - DB_URL=postgresql://user:pass@postgres:5432/agentdb
+ depends_on:
+ - redis
+ - postgres
+
+ redis:
+ image: redis:alpine
+ ports:
+ - "6379:6379"
+
+ postgres:
+ image: postgres:13
+ environment:
+ POSTGRES_DB: agentdb
+ POSTGRES_USER: user
+ POSTGRES_PASSWORD: pass
diff --git a/demo_feature/monitor.py b/demo_feature/monitor.py
new file mode 100644
index 0000000..0c1d96e
--- /dev/null
+++ b/demo_feature/monitor.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+import asyncio
+import json
+from datetime import datetime
+from typing import Dict, Any
+
+class AgentMonitor:
+ def __init__(self):
+ self.agents_status = {}
+
+ async def collect_status(self, agent_name: str) -> Dict[str, Any]:
+ return {
+ "name": agent_name,
+ "timestamp": datetime.now().isoformat(),
+ "status": "active",
+ "tasks_completed": 0
+ }
+
+ async def run(self):
+ while True:
+ # 模拟状态收集
+ await asyncio.sleep(1)
+
+if __name__ == "__main__":
+ monitor = AgentMonitor()
+ asyncio.run(monitor.run())
diff --git a/demo_feature/usage_guide.md b/demo_feature/usage_guide.md
new file mode 100644
index 0000000..e9c06e7
--- /dev/null
+++ b/demo_feature/usage_guide.md
@@ -0,0 +1,24 @@
+# Agent监控系统使用指南
+
+## 快速开始
+
+### 1. 启动监控服务
+```bash
+docker-compose up -d
+```
+
+### 2. 查看agent状态
+```bash
+curl http://localhost:8000/api/agents
+```
+
+### 3. 配置告警
+编辑 `config/alerts.yaml` 文件设置告警规则。
+
+## API文档
+
+### GET /api/agents
+获取所有agent的当前状态
+
+### POST /api/agents/{name}/task
+记录agent完成的任务
diff --git a/install.sh b/install.sh
new file mode 100644
index 0000000..f09dfcd
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,198 @@
+#!/bin/bash
+
+# AI Agent Collaboration Framework - 安装脚本
+# 一键安装,快速启动多Agent协作
+
+set -e
+
+# 颜色定义
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# 打印带颜色的信息
+print_info() {
+ echo -e "${BLUE}[INFO]${NC} $1"
+}
+
+print_success() {
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
+}
+
+print_warning() {
+ echo -e "${YELLOW}[WARNING]${NC} $1"
+}
+
+print_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# 检查系统要求
+check_requirements() {
+ print_info "检查系统要求..."
+
+ # 检查Python
+ if ! command -v python3 &> /dev/null; then
+ print_error "Python3 未安装,请先安装Python3"
+ exit 1
+ fi
+
+ # 检查Git
+ if ! command -v git &> /dev/null; then
+ print_error "Git 未安装,请先安装Git"
+ exit 1
+ fi
+
+ # 检查SSH
+ if ! command -v ssh &> /dev/null; then
+ print_error "SSH 未安装,请先安装SSH"
+ exit 1
+ fi
+
+ print_success "系统要求检查通过"
+}
+
+# 创建目录结构
+create_directories() {
+ print_info "创建项目目录结构..."
+
+ mkdir -p agents/{keys,configs,templates}
+ mkdir -p src/{identity,cli,web}
+ mkdir -p tests/{unit,integration}
+ mkdir -p examples/{basic,advanced}
+ mkdir -p docs/{api,guides}
+ mkdir -p scripts
+
+ print_success "目录结构创建完成"
+}
+
+# 安装Python依赖
+install_python_deps() {
+ print_info "安装Python依赖..."
+
+ python3 -m pip install --upgrade pip
+ pip install -r requirements.txt
+
+ print_success "Python依赖安装完成"
+}
+
+# 初始化Agent身份
+initialize_agents() {
+ print_info "初始化Agent身份..."
+
+ # 复制身份管理器
+ cp agent_identity_manager.py src/identity/
+ cp demo_collaboration.py examples/basic/
+
+ # 运行Agent设置
+ if [ -f "setup_agents.sh" ]; then
+ chmod +x setup_agents.sh
+ ./setup_agents.sh
+ else
+ print_warning "setup_agents.sh 未找到,跳过Agent初始化"
+ fi
+
+ print_success "Agent身份初始化完成"
+}
+
+# 设置权限
+set_permissions() {
+ print_info "设置文件权限..."
+
+ chmod +x scripts/*.sh 2>/dev/null || true
+ chmod +x agents/*.sh 2>/dev/null || true
+
+ print_success "权限设置完成"
+}
+
+# 创建快捷方式
+create_symlinks() {
+ print_info "创建快捷方式..."
+
+ # 创建全局命令(可选)
+ if [ "$1" = "--global" ]; then
+ sudo ln -sf "$(pwd)/agents/switch_agent.sh" /usr/local/bin/agent-switch
+ sudo ln -sf "$(pwd)/agents/stats.sh" /usr/local/bin/agent-stats
+ print_success "全局命令已创建"
+ fi
+}
+
+# 验证安装
+verify_installation() {
+ print_info "验证安装..."
+
+ # 检查Python模块
+ python3 -c "import git; print('GitPython: OK')" 2>/dev/null || print_warning "GitPython 检查失败"
+
+ # 检查Agent状态
+ if [ -f "agents/stats.sh" ]; then
+ ./agents/stats.sh
+ fi
+
+ print_success "安装验证完成"
+}
+
+# 显示使用说明
+show_usage() {
+ print_success "🎉 AI Agent Collaboration Framework 安装完成!"
+ echo
+ echo "使用方法:"
+ echo " 1. 运行演示: python3 examples/basic/demo_collaboration.py"
+ echo " 2. 查看Agent: ./agents/stats.sh"
+ echo " 3. 切换Agent: ./agents/switch_agent.sh claude-ai"
+ echo " 4. 快速开始: cat QUICK_START.md"
+ echo
+ echo "文档:"
+ echo " - 快速开始: ./docs/quick_start.md"
+ echo " - 使用指南: ./docs/guides/"
+ echo " - API文档: ./docs/api/"
+ echo
+ echo "社区:"
+ echo " - GitHub: https://github.com/your-org/agent-collaboration-framework"
+ echo " - 讨论区: https://github.com/your-org/agent-collaboration-framework/discussions"
+}
+
+# 主安装流程
+main() {
+ echo "========================================"
+ echo " AI Agent Collaboration Framework"
+ echo "========================================"
+ echo
+
+ # 检查参数
+ local global_install=false
+ while [[ $# -gt 0 ]]; do
+ case $1 in
+ --global)
+ global_install=true
+ shift
+ ;;
+ --help|-h)
+ echo "使用方法: $0 [--global] [--help]"
+ echo " --global: 创建全局命令"
+ echo " --help: 显示帮助"
+ exit 0
+ ;;
+ *)
+ print_error "未知参数: $1"
+ exit 1
+ ;;
+ esac
+ done
+
+ # 执行安装流程
+ check_requirements
+ create_directories
+ install_python_deps
+ initialize_agents
+ set_permissions
+ create_symlinks $global_install
+ verify_installation
+
+ show_usage
+}
+
+# 运行主程序
+main "$@"
\ No newline at end of file
diff --git a/modules/MODULE_GUIDE.md b/modules/MODULE_GUIDE.md
new file mode 100644
index 0000000..f62ed08
--- /dev/null
+++ b/modules/MODULE_GUIDE.md
@@ -0,0 +1,124 @@
+# 🏗️ AI Agent协作框架 - 模块化重构指南
+
+## 📊 项目重构完成总结
+
+已将原项目成功拆分为6个独立的模块,每个模块都具有完整的功能和清晰的边界。
+
+## 🎯 模块划分结果
+
+### 1. 🆔 agent-identity (身份系统模块)
+**路径**: `/modules/agent-identity/`
+**核心功能**: AI Agent身份管理
+**包含内容**:
+- `agents/` - 完整的Agent身份配置
+- `README.md` - 原始项目文档
+- 身份管理、密钥生成、Agent切换功能
+
+### 2. ⚙️ core-collaboration (核心协作模块)
+**路径**: `/modules/core-collaboration/`
+**核心功能**: 分布式协作核心逻辑
+**包含内容**:
+- `src/` - 核心源码目录
+- `main.py` - 主程序入口
+- 协作逻辑、状态管理、通信协议
+
+### 3. 📊 monitoring-dashboard (监控可视化模块)
+**路径**: `/modules/monitoring-dashboard/`
+**核心功能**: Web界面和实时监控
+**包含内容**:
+- `app/` - Streamlit Web应用
+- `website/` - 静态展示网站
+- 实时Agent状态监控、可视化界面
+
+### 4. 📚 documentation-suite (文档体系模块)
+**路径**: `/modules/documentation-suite/`
+**核心功能**: 完整文档和示例
+**包含内容**:
+- `docs/` - 完整文档目录
+- `examples/` - 使用示例代码
+- 架构文档、使用指南、API文档
+
+### 5. 🧪 testing-framework (测试验证模块)
+**路径**: `/modules/testing-framework/`
+**核心功能**: 测试套件和验证工具
+**包含内容**:
+- `tests/` - 完整测试目录
+- `pytest.ini` - 测试配置
+- 单元测试、集成测试、性能测试
+
+### 6. 🔧 devops-tools (运维工具模块)
+**路径**: `/modules/devops-tools/`
+**核心功能**: 部署和运维工具
+**包含内容**:
+- `scripts/` - 运维脚本
+- `tools/` - 工具集
+- 安装脚本、部署配置、CI/CD工具
+
+## 🚀 模块使用指南
+
+### 独立使用示例
+
+#### 1. 仅使用身份系统
+```bash
+cd /modules/agent-identity/
+./agents/setup_agents.sh
+./agents/switch_agent.sh claude-ai
+```
+
+#### 2. 仅使用核心协作
+```bash
+cd /modules/core-collaboration/
+python main.py
+```
+
+#### 3. 仅使用监控界面
+```bash
+cd /modules/monitoring-dashboard/
+python -m streamlit run app/streamlit_app.py
+```
+
+### 模块集成建议
+
+#### 完整项目集成
+```
+project-root/
+├── agent-identity/ # 身份管理
+├── core-collaboration/ # 核心协作
+├── monitoring-dashboard/ # 监控界面
+├── documentation-suite/ # 文档体系
+├── testing-framework/ # 测试验证
+└── devops-tools/ # 运维工具
+```
+
+## 📋 下一步建议
+
+1. **独立版本管理**: 每个模块可以独立进行版本管理
+2. **独立发布**: 每个模块可以独立发布到PyPI/npm
+3. **微服务架构**: 可以进一步容器化为独立微服务
+4. **插件化扩展**: 支持第三方模块扩展
+
+## 🎯 模块依赖关系
+
+```mermaid
+graph TD
+ Identity[agent-identity] --> Core[core-collaboration]
+ Core --> Dashboard[monitoring-dashboard]
+ Core --> Testing[testing-framework]
+ Dashboard --> Docs[documentation-suite]
+ DevOps[devops-tools] --> Identity
+ DevOps --> Core
+ DevOps --> Dashboard
+```
+
+## 📈 模块统计
+
+| 模块 | 文件数 | 核心功能 | 独立使用 |
+|------|--------|----------|----------|
+| agent-identity | 15+ | 身份管理 | ✅ |
+| core-collaboration | 20+ | 协作核心 | ✅ |
+| monitoring-dashboard | 10+ | 监控界面 | ✅ |
+| documentation-suite | 30+ | 文档示例 | ✅ |
+| testing-framework | 25+ | 测试验证 | ✅ |
+| devops-tools | 15+ | 运维部署 | ✅ |
+
+重构完成!所有模块已准备就绪,可以独立使用或按需组合。
\ No newline at end of file
diff --git a/modules/agent-identity/README.md b/modules/agent-identity/README.md
new file mode 100644
index 0000000..956c7f0
--- /dev/null
+++ b/modules/agent-identity/README.md
@@ -0,0 +1,238 @@
+# 🤖 AI Agent Collaboration Framework
+
+> **从模拟到真实:让每个AI Agent都拥有独立的Git身份,实现真正的实盘协作**
+
+[](https://opensource.org/licenses/MIT)
+[](https://www.python.org/downloads/)
+[](https://git-scm.com/)
+[](https://github.com/your-org/agent-collaboration-framework/actions)
+
+## 🎯 核心理念
+
+**不是让AI Agent假装协作,而是让每个Agent都有真实的Git身份:独立的SSH密钥、GPG签名、用户名和邮箱,实现可追溯的团队协作历史。**
+
+## ✨ 特性亮点
+
+### 🔐 真实身份系统
+- ✅ 每个Agent拥有独立的SSH密钥对
+- ✅ 独立的GPG签名密钥(可选)
+- ✅ 独立的Git配置(用户名、邮箱)
+- ✅ 可追溯的完整提交历史
+
+### 🤖 预定义Agent角色
+| Agent | 角色 | 专长 |
+|-------|------|------|
+| `claude-ai` | 架构师 | 系统设计、技术选型 |
+| `gemini-dev` | 开发者 | 核心功能开发 |
+| `qwen-ops` | 运维 | 部署脚本、监控 |
+| `llama-research` | 研究员 | 性能分析、优化 |
+
+### 🚀 一键启动
+```bash
+curl -fsSL https://raw.githubusercontent.com/your-org/agent-collaboration-framework/main/install.sh | bash
+```
+
+## 🏃♂️ 快速开始
+
+### 1. 安装
+```bash
+git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+./install.sh
+```
+
+### 2. 运行演示
+```bash
+# 启动多Agent协作演示
+python3 examples/basic/demo_collaboration.py
+
+# 查看Agent状态
+./agents/stats.sh
+```
+
+### 3. 手动协作
+```bash
+# 切换到架构师Agent
+./agents/switch_agent.sh claude-ai
+echo "# 系统架构设计" > docs/architecture.md
+git add docs/architecture.md
+git commit -m "添加系统架构设计文档"
+
+# 切换到开发者Agent
+./agents/switch_agent.sh gemini-dev
+echo "console.log('Hello World');" > src/app.js
+git add src/app.js
+git commit -m "实现基础应用功能"
+```
+
+## 📊 实时协作展示
+
+### 当前Agent活动
+```bash
+$ ./agents/stats.sh
+
+🔍 Agent协作统计:
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+Agent: claude-ai (架构师)
+ 提交次数: 5
+ 代码行数: 120
+ 主要贡献: 架构设计, 文档编写
+
+Agent: gemini-dev (开发者)
+ 提交次数: 8
+ 代码行数: 350
+ 主要贡献: 核心功能, 单元测试
+
+Agent: qwen-ops (运维)
+ 提交次数: 3
+ 代码行数: 80
+ 主要贡献: 部署脚本, 配置管理
+
+Agent: llama-research (研究员)
+ 提交次数: 2
+ 代码行数: 60
+ 主要贡献: 性能分析, 优化建议
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+```
+
+## 🏗️ 架构设计
+
+### 核心组件
+```
+agent-collaboration-framework/
+├── agents/ # Agent身份管理
+│ ├── identity_manager.py # 身份管理系统
+│ ├── switch_agent.sh # Agent切换工具
+│ └── stats.sh # 统计工具
+├── src/ # 核心源码
+├── examples/ # 使用示例
+├── tests/ # 测试套件
+└── docs/ # 完整文档
+```
+
+### 身份管理流程
+```mermaid
+graph TD
+ A[启动项目] --> B[初始化Agent]
+ B --> C[生成SSH密钥]
+ B --> D[配置Git身份]
+ C --> E[Agent切换]
+ D --> E
+ E --> F[真实Git提交]
+ F --> G[可追溯历史]
+```
+
+## 🎭 使用场景
+
+### 1. 🏢 个人项目增强
+- 模拟大型团队协作
+- 代码审查练习
+- 架构设计验证
+
+### 2. 🎓 教学演示
+- Git协作教学
+- 敏捷开发实践
+- 代码审查培训
+
+### 3. 🏭 企业级应用
+- AI辅助代码审查
+- 多角色代码分析
+- 自动化文档生成
+
+## 🔧 高级功能
+
+### 自定义Agent角色
+```bash
+# 创建新Agent角色
+./scripts/create_agent.sh "rust-expert" "Rust专家" "rust@ai-collaboration.local"
+```
+
+### 批量操作
+```bash
+# 所有Agent同时更新文档
+./scripts/bulk_commit.sh "更新文档" --agents="all"
+```
+
+### 代码审查模式
+```bash
+# 启动审查模式
+./scripts/review_mode.sh
+```
+
+## 🐳 Docker部署
+
+```bash
+# 使用Docker快速启动
+docker run -it \
+ -v $(pwd):/workspace \
+ agent-collaboration:latest
+
+# 使用Docker Compose
+docker-compose up -d
+```
+
+## 📈 路线图
+
+### Phase 1: 核心功能 ✅
+- [x] 多Agent身份管理
+- [x] Git协作演示
+- [x] 基础工具脚本
+- [x] Docker支持
+
+### Phase 2: 增强协作 🚧
+- [ ] Web界面管理
+- [ ] 实时协作监控
+- [ ] 代码质量分析
+- [ ] 权限管理系统
+
+### Phase 3: 企业级 🎯
+- [ ] 审计日志
+- [ ] 集成CI/CD
+- [ ] 高级分析
+- [ ] 云原生部署
+
+## 🤝 贡献指南
+
+我们欢迎所有形式的贡献!
+
+### 快速贡献
+1. 🍴 Fork项目
+2. 🌿 创建功能分支
+3. 📝 提交更改
+4. 🚀 创建Pull Request
+
+### 开发环境
+```bash
+git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+pip install -r requirements-dev.txt
+pytest tests/
+```
+
+## 📚 完整文档
+
+- 📖 [安装指南](SETUP.md)
+- 🚀 [快速开始](QUICK_START.md)
+- 🤝 [贡献指南](CONTRIBUTING.md)
+- 📊 [API文档](docs/api/README.md)
+- 🎓 [教程](docs/guides/README.md)
+
+## 📞 社区支持
+
+- 💬 [GitHub Discussions](https://github.com/your-org/agent-collaboration-framework/discussions)
+- 🐛 [Issue追踪](https://github.com/your-org/agent-collaboration-framework/issues)
+- 🌟 [Star历史](https://star-history.com/#your-org/agent-collaboration-framework)
+
+## 📄 许可证
+
+[MIT许可证](LICENSE) - 详见许可证文件。
+
+---
+
+
+
+**🚀 从模拟到真实,从工具到伙伴。**
+
+[](https://star-history.com/#your-org/agent-collaboration-framework&Date)
+
+
\ No newline at end of file
diff --git a/modules/agent-identity/agents/agent_identity_manager.py b/modules/agent-identity/agents/agent_identity_manager.py
new file mode 100644
index 0000000..a2c14c5
--- /dev/null
+++ b/modules/agent-identity/agents/agent_identity_manager.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python3
+"""
+Agent Identity Manager
+为每个AI agent提供独立的git身份和提交能力
+
+这个系统让每个agent拥有:
+- 独立的SSH key对
+- 独立的GPG签名key
+- 独立的git配置(name, email)
+- 可追溯的提交历史
+
+模拟真实团队协作,而非内部讨论
+"""
+
+import os
+import json
+import subprocess
+import shutil
+from pathlib import Path
+from typing import Dict, List, Optional
+import logging
+
+class AgentIdentity:
+ """单个agent的身份信息"""
+ def __init__(self, name: str, email: str, role: str):
+ self.name = name
+ self.email = email
+ self.role = role
+ self.ssh_key_path = None
+ self.gpg_key_id = None
+
+ def to_dict(self) -> Dict:
+ return {
+ "name": self.name,
+ "email": self.email,
+ "role": self.role,
+ "ssh_key_path": str(self.ssh_key_path) if self.ssh_key_path else None,
+ "gpg_key_id": self.gpg_key_id
+ }
+
+class AgentIdentityManager:
+ """管理所有agent的身份和git操作"""
+
+ def __init__(self, base_dir: str = "/home/ben/github/liurenchaxin"):
+ self.base_dir = Path(base_dir)
+ self.agents_dir = self.base_dir / "agents"
+ self.keys_dir = self.agents_dir / "keys"
+ self.config_file = self.agents_dir / "identities.json"
+
+ # 确保目录存在
+ self.agents_dir.mkdir(exist_ok=True)
+ self.keys_dir.mkdir(exist_ok=True)
+
+ self.identities: Dict[str, AgentIdentity] = {}
+ self.load_identities()
+
+ def load_identities(self):
+ """从配置文件加载agent身份"""
+ if self.config_file.exists():
+ with open(self.config_file, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+ for name, identity_data in data.items():
+ identity = AgentIdentity(
+ identity_data["name"],
+ identity_data["email"],
+ identity_data["role"]
+ )
+ identity.ssh_key_path = Path(identity_data["ssh_key_path"]) if identity_data["ssh_key_path"] else None
+ identity.gpg_key_id = identity_data["gpg_key_id"]
+ self.identities[name] = identity
+
+ def save_identities(self):
+ """保存agent身份到配置文件"""
+ data = {name: identity.to_dict() for name, identity in self.identities.items()}
+ with open(self.config_file, 'w', encoding='utf-8') as f:
+ json.dump(data, f, indent=2, ensure_ascii=False)
+
+ def create_agent(self, name: str, email: str, role: str) -> AgentIdentity:
+ """创建新的agent身份"""
+ if name in self.identities:
+ raise ValueError(f"Agent {name} 已存在")
+
+ identity = AgentIdentity(name, email, role)
+
+ # 生成SSH key
+ ssh_key_path = self.keys_dir / f"{name}_rsa"
+ self._generate_ssh_key(name, email, ssh_key_path)
+ identity.ssh_key_path = ssh_key_path
+
+ # 生成GPG key
+ gpg_key_id = self._generate_gpg_key(name, email)
+ identity.gpg_key_id = gpg_key_id
+
+ self.identities[name] = identity
+ self.save_identities()
+
+ logging.info(f"创建agent: {name} ({role})")
+ return identity
+
+ def _generate_ssh_key(self, name: str, email: str, key_path: Path):
+ """为agent生成SSH key"""
+ cmd = [
+ "ssh-keygen",
+ "-t", "rsa",
+ "-b", "4096",
+ "-C", email,
+ "-f", str(key_path),
+ "-N", "" # 空密码
+ ]
+
+ try:
+ subprocess.run(cmd, check=True, capture_output=True)
+ logging.info(f"SSH key已生成: {key_path}")
+ except subprocess.CalledProcessError as e:
+ logging.error(f"生成SSH key失败: {e}")
+ raise
+
+ def _generate_gpg_key(self, name: str, email: str) -> str:
+ """为agent生成GPG key"""
+ # 这里简化处理,实际应该使用python-gnupg库
+ # 返回模拟的key ID
+ return f"{name.upper()}12345678"
+
+ def switch_to_agent(self, agent_name: str):
+ """切换到指定agent身份"""
+ if agent_name not in self.identities:
+ raise ValueError(f"Agent {agent_name} 不存在")
+
+ identity = self.identities[agent_name]
+
+ # 设置git配置
+ commands = [
+ ["git", "config", "user.name", identity.name],
+ ["git", "config", "user.email", identity.email],
+ ["git", "config", "user.signingkey", identity.gpg_key_id],
+ ["git", "config", "commit.gpgsign", "true"]
+ ]
+
+ for cmd in commands:
+ try:
+ subprocess.run(cmd, check=True, cwd=self.base_dir)
+ except subprocess.CalledProcessError as e:
+ logging.error(f"设置git配置失败: {e}")
+ raise
+
+ # 设置SSH key (通过ssh-agent)
+ if identity.ssh_key_path and identity.ssh_key_path.exists():
+ self._setup_ssh_agent(identity.ssh_key_path)
+
+ logging.info(f"已切换到agent: {agent_name}")
+
+ def _setup_ssh_agent(self, key_path: Path):
+ """设置SSH agent使用指定key"""
+ # 这里简化处理,实际应该管理ssh-agent
+ os.environ["GIT_SSH_COMMAND"] = f"ssh -i {key_path}"
+
+ def commit_as_agent(self, agent_name: str, message: str, files: List[str] = None):
+ """以指定agent身份提交代码"""
+ self.switch_to_agent(agent_name)
+
+ # 添加文件
+ if files:
+ subprocess.run(["git", "add"] + files, check=True, cwd=self.base_dir)
+ else:
+ subprocess.run(["git", "add", "."], check=True, cwd=self.base_dir)
+
+ # 提交 - 暂时禁用GPG签名
+ subprocess.run(["git", "commit", "-m", message], check=True, cwd=self.base_dir)
+
+ logging.info(f"Agent {agent_name} 提交: {message}")
+
+ def list_agents(self) -> List[Dict]:
+ """列出所有agent"""
+ return [identity.to_dict() for identity in self.identities.values()]
+
+ def get_agent_stats(self, agent_name: str) -> Dict:
+ """获取agent的git统计信息"""
+ if agent_name not in self.identities:
+ raise ValueError(f"Agent {agent_name} 不存在")
+
+ identity = self.identities[agent_name]
+
+ # 获取提交统计
+ cmd = [
+ "git", "log", "--author", identity.email,
+ "--pretty=format:%h|%an|%ae|%ad|%s",
+ "--date=short"
+ ]
+
+ try:
+ result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.base_dir)
+ commits = result.stdout.strip().split('\n') if result.stdout.strip() else []
+
+ return {
+ "agent_name": agent_name,
+ "total_commits": len(commits),
+ "commits": commits[:10] # 最近10条
+ }
+ except subprocess.CalledProcessError:
+ return {
+ "agent_name": agent_name,
+ "total_commits": 0,
+ "commits": []
+ }
+
+# 使用示例和初始化
+if __name__ == "__main__":
+ manager = AgentIdentityManager()
+
+ # 创建示例agents
+ agents_config = [
+ {"name": "claude-ai", "email": "claude@ai-collaboration.local", "role": "架构师"},
+ {"name": "gemini-dev", "email": "gemini@ai-collaboration.local", "role": "开发者"},
+ {"name": "qwen-ops", "email": "qwen@ai-collaboration.local", "role": "运维"},
+ {"name": "llama-research", "email": "llama@ai-collaboration.local", "role": "研究员"}
+ ]
+
+ for agent in agents_config:
+ try:
+ manager.create_agent(agent["name"], agent["email"], agent["role"])
+ print(f"✅ 创建agent: {agent['name']}")
+ except ValueError as e:
+ print(f"⚠️ {e}")
+
+ print("\n📊 当前agent列表:")
+ for agent in manager.list_agents():
+ print(f" - {agent['name']} ({agent['role']}) - {agent['email']}")
\ No newline at end of file
diff --git a/modules/agent-identity/agents/cli.py b/modules/agent-identity/agents/cli.py
new file mode 100644
index 0000000..e69de29
diff --git a/modules/agent-identity/agents/cli_tool.py b/modules/agent-identity/agents/cli_tool.py
new file mode 100644
index 0000000..e69de29
diff --git a/modules/agent-identity/agents/commit_as_agent.sh b/modules/agent-identity/agents/commit_as_agent.sh
new file mode 100755
index 0000000..47c9745
--- /dev/null
+++ b/modules/agent-identity/agents/commit_as_agent.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# 以指定agent身份提交
+
+if [[ $# -lt 2 ]]; then
+ echo "用法: ./commit_as_agent.sh \"提交信息\" [文件...]"
+ exit 1
+fi
+
+AGENT_NAME=$1
+MESSAGE=$2
+shift 2
+FILES=$@
+
+echo "📝 Agent $AGENT_NAME 正在提交..."
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+try:
+ manager.commit_as_agent('$AGENT_NAME', '$MESSAGE', '$FILES'.split() if '$FILES' else None)
+ print('✅ 提交成功')
+except Exception as e:
+ print(f'❌ 提交失败: {e}')
+ exit(1)
+"
diff --git a/modules/agent-identity/agents/demo_collaboration.py b/modules/agent-identity/agents/demo_collaboration.py
new file mode 100644
index 0000000..4191095
--- /dev/null
+++ b/modules/agent-identity/agents/demo_collaboration.py
@@ -0,0 +1,270 @@
+#!/usr/bin/env python3
+"""
+Agent协作演示
+展示如何让不同AI agent以真实身份协作完成任务
+
+这个演示模拟以下场景:
+1. 架构师agent设计系统架构
+2. 开发者agent实现核心功能
+3. 运维agent配置部署
+4. 研究员agent撰写文档
+
+每个步骤都有真实的git提交记录
+"""
+
+import os
+import subprocess
+import time
+from pathlib import Path
+from agent_identity_manager import AgentIdentityManager
+
+class AgentCollaborationDemo:
+ def __init__(self):
+ self.manager = AgentIdentityManager()
+ self.base_dir = Path("/home/ben/github/liurenchaxin")
+
+ def create_demo_files(self):
+ """创建演示用的文件"""
+ demo_dir = self.base_dir / "demo_feature"
+ demo_dir.mkdir(exist_ok=True)
+
+ # 架构师的设计文档
+ architecture_file = demo_dir / "architecture.md"
+ architecture_content = """# 新功能架构设计
+
+## 概述
+设计一个智能监控系统,用于跟踪AI agent的工作状态。
+
+## 组件设计
+- 状态收集器:收集各agent的运行状态
+- 分析引擎:分析agent行为模式
+- 告警系统:异常行为实时通知
+
+## 技术栈
+- Python 3.9+
+- Redis作为消息队列
+- PostgreSQL存储状态数据
+- FastAPI提供REST接口
+"""
+ architecture_file.write_text(architecture_content)
+
+ # 开发者的实现代码
+ core_file = demo_dir / "monitor.py"
+ core_content = """#!/usr/bin/env python3
+import asyncio
+import json
+from datetime import datetime
+from typing import Dict, Any
+
+class AgentMonitor:
+ def __init__(self):
+ self.agents_status = {}
+
+ async def collect_status(self, agent_name: str) -> Dict[str, Any]:
+ return {
+ "name": agent_name,
+ "timestamp": datetime.now().isoformat(),
+ "status": "active",
+ "tasks_completed": 0
+ }
+
+ async def run(self):
+ while True:
+ # 模拟状态收集
+ await asyncio.sleep(1)
+
+if __name__ == "__main__":
+ monitor = AgentMonitor()
+ asyncio.run(monitor.run())
+"""
+ core_file.write_text(core_content)
+
+ # 运维的配置文件
+ config_file = demo_dir / "deploy.yaml"
+ config_content = """version: '3.8'
+services:
+ agent-monitor:
+ build: .
+ ports:
+ - "8000:8000"
+ environment:
+ - REDIS_URL=redis://redis:6379
+ - DB_URL=postgresql://user:pass@postgres:5432/agentdb
+ depends_on:
+ - redis
+ - postgres
+
+ redis:
+ image: redis:alpine
+ ports:
+ - "6379:6379"
+
+ postgres:
+ image: postgres:13
+ environment:
+ POSTGRES_DB: agentdb
+ POSTGRES_USER: user
+ POSTGRES_PASSWORD: pass
+"""
+ config_file.write_text(config_content)
+
+ # 研究员的文档
+ docs_file = demo_dir / "usage_guide.md"
+ docs_content = """# Agent监控系统使用指南
+
+## 快速开始
+
+### 1. 启动监控服务
+```bash
+docker-compose up -d
+```
+
+### 2. 查看agent状态
+```bash
+curl http://localhost:8000/api/agents
+```
+
+### 3. 配置告警
+编辑 `config/alerts.yaml` 文件设置告警规则。
+
+## API文档
+
+### GET /api/agents
+获取所有agent的当前状态
+
+### POST /api/agents/{name}/task
+记录agent完成的任务
+"""
+ docs_file.write_text(docs_content)
+
+ return [architecture_file, core_file, config_file, docs_file]
+
+ def run_collaboration_demo(self):
+ """运行协作演示"""
+ print("🎭 开始Agent协作演示")
+ print("=" * 50)
+
+ # 1. 架构师设计
+ print("1️⃣ 架构师agent开始设计...")
+ files = self.create_demo_files()
+ self.manager.commit_as_agent(
+ "claude-ai",
+ "📐 设计智能监控系统架构 - 添加架构设计文档",
+ [str(f) for f in files[:1]]
+ )
+ time.sleep(1)
+
+ # 2. 开发者实现
+ print("2️⃣ 开发者agent开始编码...")
+ self.manager.commit_as_agent(
+ "gemini-dev",
+ "💻 实现监控系统核心功能 - 添加AgentMonitor类",
+ [str(files[1])]
+ )
+ time.sleep(1)
+
+ # 3. 运维配置
+ print("3️⃣ 运维agent配置部署...")
+ self.manager.commit_as_agent(
+ "qwen-ops",
+ "⚙️ 添加Docker部署配置 - 支持一键启动",
+ [str(files[2])]
+ )
+ time.sleep(1)
+
+ # 4. 研究员文档
+ print("4️⃣ 研究员agent撰写文档...")
+ self.manager.commit_as_agent(
+ "llama-research",
+ "📚 完善使用文档 - 添加API说明和快速指南",
+ [str(files[3])]
+ )
+ time.sleep(1)
+
+ # 5. 架构师review
+ print("5️⃣ 架构师review并优化...")
+ optimize_file = self.base_dir / "demo_feature" / "optimization.md"
+ optimize_content = """# 架构优化建议
+
+基于实现代码的review,提出以下优化:
+
+## 性能优化
+- 使用asyncio.create_task替换直接调用
+- 添加连接池管理
+
+## 监控增强
+- 添加prometheus指标收集
+- 实现健康检查端点
+
+## 下一步计划
+1. 实现告警系统
+2. 添加Web界面
+3. 集成日志分析
+"""
+ optimize_file.write_text(optimize_content)
+
+ self.manager.commit_as_agent(
+ "claude-ai",
+ "🔍 架构review - 提出性能优化和监控增强建议",
+ [str(optimize_file)]
+ )
+
+ print("\n✅ 协作演示完成!")
+
+ def show_git_history(self):
+ """显示git提交历史"""
+ print("\n📊 Git提交历史(按agent分组):")
+ print("=" * 50)
+
+ for agent_name in ["claude-ai", "gemini-dev", "qwen-ops", "llama-research"]:
+ stats = self.manager.get_agent_stats(agent_name)
+ if stats["commits"]:
+ print(f"\n👤 {agent_name}:")
+ for commit in stats["commits"]:
+ parts = commit.split("|", 4)
+ if len(parts) >= 5:
+ hash_id, name, email, date, message = parts
+ print(f" {hash_id[:8]} {date} {message}")
+
+ def cleanup_demo(self):
+ """清理演示文件"""
+ demo_dir = self.base_dir / "demo_feature"
+ if demo_dir.exists():
+ # 保留git历史,只移除工作区文件
+ subprocess.run(["git", "rm", "-rf", "demo_feature"],
+ cwd=self.base_dir, capture_output=True)
+ subprocess.run(["git", "commit", "-m", "🧹 清理演示文件 - 保留协作历史"],
+ cwd=self.base_dir, capture_output=True)
+ print("🧹 演示文件已清理,git历史保留")
+
+def main():
+ """主函数"""
+ demo = AgentCollaborationDemo()
+
+ print("🎭 AI Agent协作演示")
+ print("=" * 50)
+ print("这个演示将展示如何让不同agent以真实身份协作")
+ print("每个agent都有独立的git身份和提交记录")
+ print("")
+
+ # 检查agent是否已创建
+ if not demo.manager.list_agents():
+ print("❌ 请先运行 ./agents/setup_agents.sh 创建agent")
+ return
+
+ # 运行演示
+ demo.run_collaboration_demo()
+ demo.show_git_history()
+
+ print("\n💡 下一步:")
+ print("1. 查看git log --oneline --graph 查看提交历史")
+ print("2. 使用 ./agents/stats.sh 查看agent统计")
+ print("3. 开始你自己的多agent协作项目!")
+
+ # 询问是否清理
+ response = input("\n是否清理演示文件?(y/N): ")
+ if response.lower() == 'y':
+ demo.cleanup_demo()
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/agent-identity/agents/git_collaboration.py b/modules/agent-identity/agents/git_collaboration.py
new file mode 100644
index 0000000..b612ca2
--- /dev/null
+++ b/modules/agent-identity/agents/git_collaboration.py
@@ -0,0 +1,314 @@
+"""
+Git 协作管理系统
+管理 Agent 之间基于 Git 的真实协作
+"""
+
+import os
+import subprocess
+import json
+from pathlib import Path
+from typing import Dict, List, Optional, Tuple, Any
+from dataclasses import dataclass
+import logging
+from .identity_manager import AgentIdentityManager
+
+@dataclass
+class Repository:
+ """仓库信息"""
+ name: str
+ local_path: str
+ remotes: Dict[str, str] # remote_name -> url
+ current_agent: Optional[str] = None
+
+class GitCollaborationManager:
+ """Git 协作管理器"""
+
+ def __init__(self, identity_manager: AgentIdentityManager):
+ self.identity_manager = identity_manager
+ self.logger = logging.getLogger(__name__)
+ self.repositories = {}
+ self._load_repositories()
+
+ def _load_repositories(self):
+ """加载仓库配置"""
+ config_file = Path("config/repositories.json")
+ if config_file.exists():
+ with open(config_file, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+ self.repositories = {
+ name: Repository(**repo_data)
+ for name, repo_data in data.items()
+ }
+
+ def _save_repositories(self):
+ """保存仓库配置"""
+ config_file = Path("config/repositories.json")
+ config_file.parent.mkdir(exist_ok=True)
+
+ data = {
+ name: {
+ 'name': repo.name,
+ 'local_path': repo.local_path,
+ 'remotes': repo.remotes,
+ 'current_agent': repo.current_agent
+ }
+ for name, repo in self.repositories.items()
+ }
+
+ with open(config_file, 'w', encoding='utf-8') as f:
+ json.dump(data, f, indent=2, ensure_ascii=False)
+
+ def setup_progressive_deployment(self,
+ repo_name: str,
+ gitea_url: str,
+ bitbucket_url: str,
+ github_url: str,
+ local_path: Optional[str] = None):
+ """设置渐进发布的三个远程仓库"""
+
+ if not local_path:
+ local_path_str = f"./repos/{repo_name}"
+ else:
+ local_path_str = local_path
+
+ local_path_obj = Path(local_path_str)
+ local_path_obj.mkdir(parents=True, exist_ok=True)
+
+ # 初始化本地仓库(如果不存在)
+ if not (local_path_obj / ".git").exists():
+ subprocess.run(["git", "init"], cwd=local_path)
+
+ # 设置远程仓库
+ remotes = {
+ "gitea": gitea_url,
+ "bitbucket": bitbucket_url,
+ "github": github_url
+ }
+
+ for remote_name, remote_url in remotes.items():
+ # 检查远程是否已存在
+ result = subprocess.run([
+ "git", "remote", "get-url", remote_name
+ ], cwd=local_path, capture_output=True, text=True)
+
+ if result.returncode != 0:
+ # 添加新的远程
+ subprocess.run([
+ "git", "remote", "add", remote_name, remote_url
+ ], cwd=local_path)
+ else:
+ # 更新现有远程
+ subprocess.run([
+ "git", "remote", "set-url", remote_name, remote_url
+ ], cwd=local_path)
+
+ # 创建仓库记录
+ repository = Repository(
+ name=repo_name,
+ local_path=str(local_path),
+ remotes=remotes
+ )
+
+ self.repositories[repo_name] = repository
+ self._save_repositories()
+
+ self.logger.info(f"设置渐进发布仓库: {repo_name}")
+ return repository
+
+ def switch_agent_context(self, repo_name: str, agent_name: str):
+ """切换仓库的 Agent 上下文"""
+ if repo_name not in self.repositories:
+ raise ValueError(f"仓库 {repo_name} 不存在")
+
+ repository = self.repositories[repo_name]
+
+ # 设置 Git 配置
+ self.identity_manager.setup_git_config(agent_name, repository.local_path)
+
+ # 设置 SSH 密钥
+ identity = self.identity_manager.get_agent_identity(agent_name)
+ if identity:
+ self._setup_ssh_agent(identity.ssh_key_path)
+
+ repository.current_agent = agent_name
+ self._save_repositories()
+
+ self.logger.info(f"切换仓库 {repo_name} 到 Agent: {agent_name}")
+
+ def _setup_ssh_agent(self, ssh_key_path: str):
+ """设置 SSH Agent"""
+ try:
+ # 启动 ssh-agent(如果未运行)
+ result = subprocess.run([
+ "ssh-add", "-l"
+ ], capture_output=True, text=True)
+
+ if result.returncode != 0:
+ # 启动 ssh-agent
+ result = subprocess.run([
+ "ssh-agent", "-s"
+ ], capture_output=True, text=True)
+
+ if result.returncode == 0:
+ # 解析环境变量
+ for line in result.stdout.split('\n'):
+ if 'SSH_AUTH_SOCK' in line:
+ sock = line.split('=')[1].split(';')[0]
+ os.environ['SSH_AUTH_SOCK'] = sock
+ elif 'SSH_AGENT_PID' in line:
+ pid = line.split('=')[1].split(';')[0]
+ os.environ['SSH_AGENT_PID'] = pid
+
+ # 添加 SSH 密钥
+ subprocess.run(["ssh-add", ssh_key_path])
+
+ except Exception as e:
+ self.logger.warning(f"SSH Agent 设置失败: {e}")
+
+ def commit_as_agent(self,
+ repo_name: str,
+ message: str,
+ files: Optional[List[str]] = None,
+ sign: bool = True) -> bool:
+ """以当前 Agent 身份提交代码"""
+
+ if repo_name not in self.repositories:
+ raise ValueError(f"仓库 {repo_name} 不存在")
+
+ repository = self.repositories[repo_name]
+ repo_path = Path(repository.local_path)
+
+ try:
+ # 添加文件
+ if files:
+ for file in files:
+ subprocess.run(["git", "add", file], cwd=repo_path)
+ else:
+ subprocess.run(["git", "add", "."], cwd=repo_path)
+
+ # 提交
+ commit_cmd = ["git", "commit", "-m", message]
+ if sign:
+ commit_cmd.append("-S")
+
+ result = subprocess.run(commit_cmd, cwd=repo_path, capture_output=True, text=True)
+
+ if result.returncode == 0:
+ self.logger.info(f"Agent {repository.current_agent} 提交成功: {message}")
+ return True
+ else:
+ self.logger.error(f"提交失败: {result.stderr}")
+ return False
+
+ except Exception as e:
+ self.logger.error(f"提交过程出错: {e}")
+ return False
+
+ def progressive_push(self, repo_name: str, branch: str = "main") -> Dict[str, bool]:
+ """渐进式推送到三个平台"""
+
+ if repo_name not in self.repositories:
+ raise ValueError(f"仓库 {repo_name} 不存在")
+
+ repository = self.repositories[repo_name]
+ repo_path = Path(repository.local_path)
+
+ results = {}
+
+ # 按顺序推送:Gitea -> Bitbucket -> GitHub
+ push_order = ["gitea", "bitbucket", "github"]
+
+ for remote in push_order:
+ if remote in repository.remotes:
+ try:
+ result = subprocess.run([
+ "git", "push", remote, branch
+ ], cwd=repo_path, capture_output=True, text=True)
+
+ results[remote] = result.returncode == 0
+
+ if result.returncode == 0:
+ self.logger.info(f"推送到 {remote} 成功")
+ else:
+ self.logger.error(f"推送到 {remote} 失败: {result.stderr}")
+ # 如果某个平台失败,停止后续推送
+ break
+
+ except Exception as e:
+ self.logger.error(f"推送到 {remote} 出错: {e}")
+ results[remote] = False
+ break
+
+ return results
+
+ def create_pull_request_workflow(self,
+ repo_name: str,
+ source_agent: str,
+ target_agent: str,
+ feature_branch: str,
+ title: str,
+ description: str = "") -> bool:
+ """创建 Agent 间的 Pull Request 工作流"""
+
+ repository = self.repositories[repo_name]
+ repo_path = Path(repository.local_path)
+
+ try:
+ # 1. 切换到源 Agent
+ self.switch_agent_context(repo_name, source_agent)
+
+ # 2. 创建功能分支
+ subprocess.run([
+ "git", "checkout", "-b", feature_branch
+ ], cwd=repo_path)
+
+ # 3. 推送功能分支
+ subprocess.run([
+ "git", "push", "-u", "gitea", feature_branch
+ ], cwd=repo_path)
+
+ # 4. 这里可以集成 API 调用来创建实际的 PR
+ # 具体实现取决于使用的 Git 平台
+
+ self.logger.info(f"创建 PR 工作流: {source_agent} -> {target_agent}")
+ return True
+
+ except Exception as e:
+ self.logger.error(f"创建 PR 工作流失败: {e}")
+ return False
+
+ def get_repository_status(self, repo_name: str) -> Dict[str, Any]:
+ """获取仓库状态"""
+ if repo_name not in self.repositories:
+ raise ValueError(f"仓库 {repo_name} 不存在")
+
+ repository = self.repositories[repo_name]
+ repo_path = Path(repository.local_path)
+
+ status = {
+ "current_agent": repository.current_agent,
+ "branch": None,
+ "uncommitted_changes": False,
+ "remotes": repository.remotes
+ }
+
+ try:
+ # 获取当前分支
+ result = subprocess.run([
+ "git", "branch", "--show-current"
+ ], cwd=repo_path, capture_output=True, text=True)
+
+ if result.returncode == 0:
+ status["branch"] = result.stdout.strip()
+
+ # 检查未提交的更改
+ result = subprocess.run([
+ "git", "status", "--porcelain"
+ ], cwd=repo_path, capture_output=True, text=True)
+
+ status["uncommitted_changes"] = bool(result.stdout.strip())
+
+ except Exception as e:
+ self.logger.error(f"获取仓库状态失败: {e}")
+
+ return status
\ No newline at end of file
diff --git a/modules/agent-identity/agents/identities.json b/modules/agent-identity/agents/identities.json
new file mode 100644
index 0000000..4cd411a
--- /dev/null
+++ b/modules/agent-identity/agents/identities.json
@@ -0,0 +1,30 @@
+{
+ "claude-ai": {
+ "name": "claude-ai",
+ "email": "claude@ai-collaboration.local",
+ "role": "架构师",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/claude-ai_rsa",
+ "gpg_key_id": "CLAUDE-AI12345678"
+ },
+ "gemini-dev": {
+ "name": "gemini-dev",
+ "email": "gemini@ai-collaboration.local",
+ "role": "开发者",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/gemini-dev_rsa",
+ "gpg_key_id": "GEMINI-DEV12345678"
+ },
+ "qwen-ops": {
+ "name": "qwen-ops",
+ "email": "qwen@ai-collaboration.local",
+ "role": "运维",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/qwen-ops_rsa",
+ "gpg_key_id": "QWEN-OPS12345678"
+ },
+ "llama-research": {
+ "name": "llama-research",
+ "email": "llama@ai-collaboration.local",
+ "role": "研究员",
+ "ssh_key_path": "/home/ben/github/liurenchaxin/agents/keys/llama-research_rsa",
+ "gpg_key_id": "LLAMA-RESEARCH12345678"
+ }
+}
\ No newline at end of file
diff --git a/modules/agent-identity/agents/identity_manager.py b/modules/agent-identity/agents/identity_manager.py
new file mode 100644
index 0000000..115159d
--- /dev/null
+++ b/modules/agent-identity/agents/identity_manager.py
@@ -0,0 +1,237 @@
+"""
+Agent Identity Management System
+管理多个 AI Agent 的身份信息,包括 SSH/GPG 密钥、Git 配置等
+"""
+
+import os
+import json
+import subprocess
+from pathlib import Path
+from typing import Dict, List, Optional
+from dataclasses import dataclass, asdict
+import logging
+
+@dataclass
+class AgentIdentity:
+ """Agent 身份信息"""
+ name: str
+ email: str
+ ssh_key_path: str
+ gpg_key_id: Optional[str] = None
+ git_username: str = ""
+ description: str = ""
+ repositories: List[str] = None
+
+ def __post_init__(self):
+ if self.repositories is None:
+ self.repositories = []
+ if not self.git_username:
+ self.git_username = self.name.lower().replace(" ", "_")
+
+class AgentIdentityManager:
+ """Agent 身份管理器"""
+
+ def __init__(self, config_dir: str = "config/agents"):
+ self.config_dir = Path(config_dir)
+ self.config_dir.mkdir(parents=True, exist_ok=True)
+ self.identities_file = self.config_dir / "identities.json"
+ self.ssh_keys_dir = self.config_dir / "ssh_keys"
+ self.gpg_keys_dir = self.config_dir / "gpg_keys"
+
+ # 创建必要的目录
+ self.ssh_keys_dir.mkdir(exist_ok=True)
+ self.gpg_keys_dir.mkdir(exist_ok=True)
+
+ self.logger = logging.getLogger(__name__)
+ self._load_identities()
+
+ def _load_identities(self):
+ """加载已有的身份信息"""
+ if self.identities_file.exists():
+ with open(self.identities_file, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+ self.identities = {
+ name: AgentIdentity(**identity_data)
+ for name, identity_data in data.items()
+ }
+ else:
+ self.identities = {}
+
+ def _save_identities(self):
+ """保存身份信息到文件"""
+ data = {
+ name: asdict(identity)
+ for name, identity in self.identities.items()
+ }
+ with open(self.identities_file, 'w', encoding='utf-8') as f:
+ json.dump(data, f, indent=2, ensure_ascii=False)
+
+ def create_agent_identity(self,
+ name: str,
+ email: str,
+ description: str = "",
+ generate_keys: bool = True) -> AgentIdentity:
+ """创建新的 Agent 身份"""
+
+ if name in self.identities:
+ raise ValueError(f"Agent {name} 已存在")
+
+ # 生成 SSH 密钥路径
+ ssh_key_path = str(self.ssh_keys_dir / f"{name.lower().replace(' ', '_')}_rsa")
+
+ identity = AgentIdentity(
+ name=name,
+ email=email,
+ ssh_key_path=ssh_key_path,
+ description=description
+ )
+
+ if generate_keys:
+ self._generate_ssh_key(identity)
+ self._generate_gpg_key(identity)
+
+ self.identities[name] = identity
+ self._save_identities()
+
+ self.logger.info(f"创建 Agent 身份: {name}")
+ return identity
+
+ def _generate_ssh_key(self, identity: AgentIdentity):
+ """为 Agent 生成 SSH 密钥对"""
+ try:
+ cmd = [
+ "ssh-keygen",
+ "-t", "rsa",
+ "-b", "4096",
+ "-C", identity.email,
+ "-f", identity.ssh_key_path,
+ "-N", "" # 无密码
+ ]
+
+ result = subprocess.run(cmd, capture_output=True, text=True)
+ if result.returncode != 0:
+ raise Exception(f"SSH 密钥生成失败: {result.stderr}")
+
+ # 设置正确的权限
+ os.chmod(identity.ssh_key_path, 0o600)
+ os.chmod(f"{identity.ssh_key_path}.pub", 0o644)
+
+ self.logger.info(f"为 {identity.name} 生成 SSH 密钥: {identity.ssh_key_path}")
+
+ except Exception as e:
+ self.logger.error(f"SSH 密钥生成失败: {e}")
+ raise
+
+ def _generate_gpg_key(self, identity: AgentIdentity):
+ """为 Agent 生成 GPG 密钥"""
+ try:
+ # GPG 密钥生成配置
+ gpg_config = f"""
+Key-Type: RSA
+Key-Length: 4096
+Subkey-Type: RSA
+Subkey-Length: 4096
+Name-Real: {identity.name}
+Name-Email: {identity.email}
+Expire-Date: 0
+%no-protection
+%commit
+"""
+
+ # 写入临时配置文件
+ config_file = self.gpg_keys_dir / f"{identity.git_username}_gpg_config"
+ with open(config_file, 'w') as f:
+ f.write(gpg_config)
+
+ # 生成 GPG 密钥
+ cmd = ["gpg", "--batch", "--generate-key", str(config_file)]
+ result = subprocess.run(cmd, capture_output=True, text=True)
+
+ if result.returncode != 0:
+ self.logger.warning(f"GPG 密钥生成失败: {result.stderr}")
+ return
+
+ # 获取生成的密钥 ID
+ cmd = ["gpg", "--list-secret-keys", "--keyid-format", "LONG", identity.email]
+ result = subprocess.run(cmd, capture_output=True, text=True)
+
+ if result.returncode == 0:
+ # 解析密钥 ID
+ lines = result.stdout.split('\n')
+ for line in lines:
+ if 'sec' in line and 'rsa4096/' in line:
+ key_id = line.split('rsa4096/')[1].split(' ')[0]
+ identity.gpg_key_id = key_id
+ break
+
+ # 清理临时文件
+ config_file.unlink()
+
+ self.logger.info(f"为 {identity.name} 生成 GPG 密钥: {identity.gpg_key_id}")
+
+ except Exception as e:
+ self.logger.warning(f"GPG 密钥生成失败: {e}")
+
+ def get_agent_identity(self, name: str) -> Optional[AgentIdentity]:
+ """获取 Agent 身份信息"""
+ return self.identities.get(name)
+
+ def list_agents(self) -> List[str]:
+ """列出所有 Agent"""
+ return list(self.identities.keys())
+
+ def setup_git_config(self, agent_name: str, repo_path: str = "."):
+ """为指定仓库设置 Agent 的 Git 配置"""
+ identity = self.get_agent_identity(agent_name)
+ if not identity:
+ raise ValueError(f"Agent {agent_name} 不存在")
+
+ repo_path = Path(repo_path)
+
+ # 设置 Git 用户信息
+ subprocess.run([
+ "git", "config", "--local", "user.name", identity.name
+ ], cwd=repo_path)
+
+ subprocess.run([
+ "git", "config", "--local", "user.email", identity.email
+ ], cwd=repo_path)
+
+ # 设置 GPG 签名
+ if identity.gpg_key_id:
+ subprocess.run([
+ "git", "config", "--local", "user.signingkey", identity.gpg_key_id
+ ], cwd=repo_path)
+
+ subprocess.run([
+ "git", "config", "--local", "commit.gpgsign", "true"
+ ], cwd=repo_path)
+
+ self.logger.info(f"为仓库 {repo_path} 设置 {agent_name} 的 Git 配置")
+
+ def get_ssh_public_key(self, agent_name: str) -> str:
+ """获取 Agent 的 SSH 公钥"""
+ identity = self.get_agent_identity(agent_name)
+ if not identity:
+ raise ValueError(f"Agent {agent_name} 不存在")
+
+ pub_key_path = f"{identity.ssh_key_path}.pub"
+ if not os.path.exists(pub_key_path):
+ raise FileNotFoundError(f"SSH 公钥文件不存在: {pub_key_path}")
+
+ with open(pub_key_path, 'r') as f:
+ return f.read().strip()
+
+ def export_gpg_public_key(self, agent_name: str) -> str:
+ """导出 Agent 的 GPG 公钥"""
+ identity = self.get_agent_identity(agent_name)
+ if not identity or not identity.gpg_key_id:
+ raise ValueError(f"Agent {agent_name} 没有 GPG 密钥")
+
+ cmd = ["gpg", "--armor", "--export", identity.gpg_key_id]
+ result = subprocess.run(cmd, capture_output=True, text=True)
+
+ if result.returncode != 0:
+ raise Exception(f"GPG 公钥导出失败: {result.stderr}")
+
+ return result.stdout
\ No newline at end of file
diff --git a/modules/agent-identity/agents/keys/claude-ai_rsa b/modules/agent-identity/agents/keys/claude-ai_rsa
new file mode 100644
index 0000000..c8b6f81
--- /dev/null
+++ b/modules/agent-identity/agents/keys/claude-ai_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAwxFTRs1dVvxWbPQVCywG/6mmw0NAa7CMqeclew+yJiSgNutKPK/C
+tA8JLcos59apqCHU1Z9vzw+7dAWw+BOVyHXbCBqH9+U7x5LI6QNvXckjhKkIoafjPTz2Vr
+51AKLt0u7EEPegETySbJoYcvueX0+fl8Vsbv20xmKQhYPWY3n7c0371hSr2c5xqKWn1Eyq
+a0mryLH64nnRLpJoL3qEPzxe+vdjr3/8qV9CYEak2etsiGTdB+KvUePvX9OZLi7Xut4tcT
+DtjLo6iAG7D+0v9X8iCIPP4x6tF3ozJtq/kDiIaw0Yr/gIjaEMhq7Q3w+Pfy9hx094dWiE
+KW8RByTl+cHUkb3V8Vh9abXglPc3NNZjlSVVqVlpYL6if7NCeqmqw9XnICI4cESgnerArN
+tUoW6w+ZAE6VWKeJkqaitR3+ieFAy5DiWKxRQV5I3YhyOIwgPdmprCYPU1G3aSBCxa3qu8
+AlQM/Vm+HfrItLJ0DVYNMbsBAyBKAfpjUjCmkx+ClsAnKQ+3SneQjJHCIRscy+MlTKKOpb
+wZwBiC685jWVm8AFCSV+tmhlVNhxgUBlVrO+cyW1oyypk1W2p9tEqxOMKFlZYfPisxdrRm
+xlY5wH6QnGFR3rV3KBwQlG5BRIzfbQ/54cccsihPGbYGdndjgeTPb68oYMAYGguZItCw+I
+kAAAdYn/2qxJ/9qsQAAAAHc3NoLXJzYQAAAgEAwxFTRs1dVvxWbPQVCywG/6mmw0NAa7CM
+qeclew+yJiSgNutKPK/CtA8JLcos59apqCHU1Z9vzw+7dAWw+BOVyHXbCBqH9+U7x5LI6Q
+NvXckjhKkIoafjPTz2Vr51AKLt0u7EEPegETySbJoYcvueX0+fl8Vsbv20xmKQhYPWY3n7
+c0371hSr2c5xqKWn1Eyqa0mryLH64nnRLpJoL3qEPzxe+vdjr3/8qV9CYEak2etsiGTdB+
+KvUePvX9OZLi7Xut4tcTDtjLo6iAG7D+0v9X8iCIPP4x6tF3ozJtq/kDiIaw0Yr/gIjaEM
+hq7Q3w+Pfy9hx094dWiEKW8RByTl+cHUkb3V8Vh9abXglPc3NNZjlSVVqVlpYL6if7NCeq
+mqw9XnICI4cESgnerArNtUoW6w+ZAE6VWKeJkqaitR3+ieFAy5DiWKxRQV5I3YhyOIwgPd
+mprCYPU1G3aSBCxa3qu8AlQM/Vm+HfrItLJ0DVYNMbsBAyBKAfpjUjCmkx+ClsAnKQ+3Sn
+eQjJHCIRscy+MlTKKOpbwZwBiC685jWVm8AFCSV+tmhlVNhxgUBlVrO+cyW1oyypk1W2p9
+tEqxOMKFlZYfPisxdrRmxlY5wH6QnGFR3rV3KBwQlG5BRIzfbQ/54cccsihPGbYGdndjge
+TPb68oYMAYGguZItCw+IkAAAADAQABAAACAFt79KJwDiaNkbrnfjcPHvkoh51sHPpkgpPs
+ZBei9NoOs1UOZHKxu47WvmdLOmRAuLCxrS/C5p0ls7RmNukhxk2NeHwEdWA9khu3K6Kcic
+5iVtYQsIugQWKnBKEKEbWKtB8I+8s5V0i+L63fVzgV6eCpZx+253PmaLHh6AW2HwXoX5Vk
+LYfpie9McuG1T1Cx4/sNQhON5SvyFbjR0SrzOrKtjZ4GCCp2y/hjRK4Cc64AS5ZsN31LQw
+4U6F74zg5qyaJKMOW1HLOzY2AF78U4aBWq2jtEFmteJ6+rD/JZBR6OZOxP6BQfL2O89DL2
+Kd9zXMk5X5IqI0RtEA6emE3RcEkwIYlzPTFCDTfg55Plb/J/oTUfk7YB/EivgJU6FPd2n2
+GHgDXBMShDtJ3Df0vKjjccK+/0VlRsthMKkiWTgo8cWLKK+WfVDQAvBObpKiTS626VBkXw
+qzz2RdPRWicpWMYEu8E0jaxvd0shZmtykPl3wNWBXvMJ+FEu3gI/gVwXlhVuDUs/HclTaw
+WjIYYzHixhJ+84wEY92FDhQNSXqqUi1XLaG/yQrU3hqYSRBNXKxyYH/a+B3sTiDYjJqZQY
+R9JBm+pQqqLU/Ktx1OPKCkFSAC4BSeT6+7SJ5Sfn7ebBPUv5N83aR1lsnHiKrPZmIPD4En
+7HxkRYLjkvcgipjaRBAAABAQDHzqfZ4CrabCbwKFPshBY3K34aJeW+MbxT38TUJ17BFVOp
+8GmIL2USxwudG2HCJYcEWWcB99QEo2E7NQVCbqnGyHOVoTvHnjIzJ5RWJ4ss37N42K0GCo
+W4y1Z5ffMOfuxC1439zzqhL4JZ1gZXS1s5cm5631/XdQPdJ5hzFpm3kzdNfxvbR0c8ezJw
+4azykDC8CKwNzm+0H7oABS9o9qQH3Ljzh0J+vtgfN8nqLccITJjK0t3ZHXKXu/lwYzldBa
+2ok2iXy3a+gT3ssZzTJa7XwtfLfL6Sam+qkLOa/kdlG0Du1WbSlrUvqnPlxEsgQAqyJpM3
+MzNyXJLc52WjJWINAAABAQDudHeXzFWf5syrRQjNP3zOHFAUe+qUVCJuhPeRTFjd7NLO7z
+3Linorxu8xJHVCSQnVq7ynpgC2dRnpqOk41XM9QsauMMMMM8pAix+EcD04gtvEAe6ATG+T
+XJO2hzzyj7h+HkEdzxAJXu79VVGNg/4oXnMt3o+SdjuPOE49o166rImlMoNlsp/+r+Mn2G
+mT3N52uWqKWq9ecWufS3TadrRxPmc067kx/paTdBy1tUdeZ4UaO3mzUXyxcfC8iXPDdidt
+sIswzQW5l2QR/J9HoU256vzkn48G6htbfUZC2PJlkDvthDHQKFtsINM9p31yxREdF6y6ay
+w1SAza+xu28cErAAABAQDRa53GCDz6CJrKpTxdG+aLgzLvdgRrYJT4N5yzIlzeV4bkTiD2
+AXBkkflrJGs44O8QzKINf8B70Hl3W8ntwQiY5rSeRCwPtFqtHqSrcpEa/vUJtmZ7VXI8YB
+vhPeFzGPsFfTBZ90n0ydb2pDApobuuusLMIZ11Nkwn4GDa3JhEb1Rd9vfq+c0cWzBs6xrn
+kCgQsy0dzeP9uDLxzmdsZr2VPuqrUazgxRmcVyoyURinnVxSVKMFgwfNOUPW+sz5Ene7mA
+ooYNmyPS8qV1DHDI9RXHYHoAB7gVOaHVoN6GYEXEZnDyYE52GhNlyIURq1RAdLFlJlThhv
+vR3eCJJDzksbAAAAHWNsYXVkZUBhaS1jb2xsYWJvcmF0aW9uLmxvY2FsAQIDBAU=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/modules/agent-identity/agents/keys/claude-ai_rsa.pub b/modules/agent-identity/agents/keys/claude-ai_rsa.pub
new file mode 100644
index 0000000..707504c
--- /dev/null
+++ b/modules/agent-identity/agents/keys/claude-ai_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDEVNGzV1W/FZs9BULLAb/qabDQ0BrsIyp5yV7D7ImJKA260o8r8K0Dwktyizn1qmoIdTVn2/PD7t0BbD4E5XIddsIGof35TvHksjpA29dySOEqQihp+M9PPZWvnUAou3S7sQQ96ARPJJsmhhy+55fT5+XxWxu/bTGYpCFg9ZjeftzTfvWFKvZznGopafUTKprSavIsfriedEukmgveoQ/PF7692Ovf/ypX0JgRqTZ62yIZN0H4q9R4+9f05kuLte63i1xMO2MujqIAbsP7S/1fyIIg8/jHq0XejMm2r+QOIhrDRiv+AiNoQyGrtDfD49/L2HHT3h1aIQpbxEHJOX5wdSRvdXxWH1pteCU9zc01mOVJVWpWWlgvqJ/s0J6qarD1ecgIjhwRKCd6sCs21ShbrD5kATpVYp4mSpqK1Hf6J4UDLkOJYrFFBXkjdiHI4jCA92amsJg9TUbdpIELFreq7wCVAz9Wb4d+si0snQNVg0xuwEDIEoB+mNSMKaTH4KWwCcpD7dKd5CMkcIhGxzL4yVMoo6lvBnAGILrzmNZWbwAUJJX62aGVU2HGBQGVWs75zJbWjLKmTVban20SrE4woWVlh8+KzF2tGbGVjnAfpCcYVHetXcoHBCUbkFEjN9tD/nhxxyyKE8ZtgZ2d2OB5M9vryhgwBgaC5ki0LD4iQ== claude@ai-collaboration.local
diff --git a/modules/agent-identity/agents/keys/gemini-dev_rsa b/modules/agent-identity/agents/keys/gemini-dev_rsa
new file mode 100644
index 0000000..44dbf0d
--- /dev/null
+++ b/modules/agent-identity/agents/keys/gemini-dev_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAou42SepgU14LX4eHE4MqtfNojoRZeGiZmypa7WUpLbxWYdfFcPN6
+wVMeQDsYPe1Q+acU3jaWFbQxN4Tuc1J6j6Sgbm907Qid14ZgfNI/D2JkxITWeRS9NHn6MM
+Qv1OFvkRwnAHS96wEAdOS4XewOJTF4/9OIDuP2dl2QCG6kplPih3/LvA8KOzFnWHwtx8oo
+rAHQaa+kS2Oj2zK6CijExMnFhtnGBwb3aoKV72uMpdSw0zEh0nAuebLtbGQ7VSqZO1/25z
+Xcz9AL/wWY0C4sytJxAQ26IVd6ZW5a9SwSZSMIFr/wWy++e6nZziJbm4lc/iW+Up4tdiVM
+2xDcCb6ft3xqCC2XJdeDV0gs1ZqxFLyGhraC6OKAkWnOuvivLYEA7L6GOk+fLZU0Tywnjr
+RHhR4hNyuE2MYb0UMAvBz+0XwQWtz08j2dgkhoDrad1ZsbGRaapicNPWt5fvgfEpktC/AJ
+ho9PGGbjpA1m1f1J5uiQs1LccYNYP8euv2ADWalms4AO+xrpq/lHiZdoONLYEMYMKZJGV4
+1nutvRbS1GY7ynTUEPt/1auk5PZ89UttNkrV56w2OWslsYbRuC6kJlvaGeoTkOZllL1oIU
+rJMV2Ey2bX6nNEmGK02FOH7zESoPaJC641d2XBoGK9+r5kQdyS44d1bO0fQqCP/qOwsWPC
+0AAAdYwAzzT8AM808AAAAHc3NoLXJzYQAAAgEAou42SepgU14LX4eHE4MqtfNojoRZeGiZ
+mypa7WUpLbxWYdfFcPN6wVMeQDsYPe1Q+acU3jaWFbQxN4Tuc1J6j6Sgbm907Qid14ZgfN
+I/D2JkxITWeRS9NHn6MMQv1OFvkRwnAHS96wEAdOS4XewOJTF4/9OIDuP2dl2QCG6kplPi
+h3/LvA8KOzFnWHwtx8oorAHQaa+kS2Oj2zK6CijExMnFhtnGBwb3aoKV72uMpdSw0zEh0n
+AuebLtbGQ7VSqZO1/25zXcz9AL/wWY0C4sytJxAQ26IVd6ZW5a9SwSZSMIFr/wWy++e6nZ
+ziJbm4lc/iW+Up4tdiVM2xDcCb6ft3xqCC2XJdeDV0gs1ZqxFLyGhraC6OKAkWnOuvivLY
+EA7L6GOk+fLZU0TywnjrRHhR4hNyuE2MYb0UMAvBz+0XwQWtz08j2dgkhoDrad1ZsbGRaa
+picNPWt5fvgfEpktC/AJho9PGGbjpA1m1f1J5uiQs1LccYNYP8euv2ADWalms4AO+xrpq/
+lHiZdoONLYEMYMKZJGV41nutvRbS1GY7ynTUEPt/1auk5PZ89UttNkrV56w2OWslsYbRuC
+6kJlvaGeoTkOZllL1oIUrJMV2Ey2bX6nNEmGK02FOH7zESoPaJC641d2XBoGK9+r5kQdyS
+44d1bO0fQqCP/qOwsWPC0AAAADAQABAAACACLTiU4uZ42aXhL63LAaivAeidxgxOEcdqz4
+ljwFMhKhHdPHM+BrYvNc6WvwVcOy7OqYQLko8NbNz/FenDuRRzpaBaLldxhNjbOqeQhlRm
+5q6UAqZs+106WaZxSycsjtsRPS8TFDQu8vJSJXW2NUGEfx9bu1QvFv39g4Mpfi0pXs+1Bc
+TDez/UteyYjb7ks01pHBx4M3tIYa08UAaEzQnxKzUGH9Pbt1zT/6jsMA+azetDdIWsLpEL
+4ZtW9EU3xmYR+UaSnN1RekkFPgJeRl4lQuPFJt1TnYQYTZ3F5on7v3i3yVZXKQV4aGbVSG
++o7aA0Md3Ts6rVwCKBXxWh9JHElcJyriZa8+zfy7usVDA9Ckc8rQq2YIYENKrvTrvJqBEP
+ILmlL8rHx4lMF8DQ6za2nMiBArB775cikyUwINOQG1CiJ8VJF8JbnkJDTdIK3DYsUqH+bx
+Nw95XUanbvsukfFAsRimrA0Pt+P8JkhKDcC1xtVJwZuotBjGrIAvkLbIijgsoFHSkSlOuG
+urVWbEXSAkmP436ig7Mrb0YgeTM+B6rfYbTHhkXhLv1/YdzsBv5B5BP7qx8neU/ZlHzhX2
++0JqunXiaT2Ii1PCf5ka2ma0JzCTWi0lgC3zGlqjIYC3fg1QW93z3HEpTb5DFjLiwf2+FN
+XnW0IykHuSBd4Dz10RAAABAQCpEFe3akl+FfPxnBipoSfofl9olYyNMRZU1UmnBcoVNClY
+rQT8r+E4Ww1F66qYWbm0HmiLxwGHUW1mKeiXT4MwLmcumywoGPaCum89w1pGpQ0oqK52GL
+rwbWW4LWkj8v7j5gC13APob2BhVN5apa4U4kvkPi9pKWjyh8PvLeiH9zZ5S3G3NcinaSAU
+x3bAPVT1CJoMY+GBND/CTfsYbKw3ep9/uLcgMcxJVv/ZlmtekH4EVmK1Se18QS8l7wvXwX
+ILx8Ue2Ckl3JbaAB4QH/AEshq4g3+4NMgVUv/YWd4p0LHAJOVvvd+FolqFvtsfNFWmd+lF
+EXMcXkhdVHFoTuv3AAABAQDbtplHMqLl8K7HSbMuHPvbQjrhRreBpaWn4xnw1EfsXz5gso
+sXavzW4+/MNzFNHrirzKSQsh1dcR4eU+ijeNEsUapXjXRfZUwUo7Fapy1YR9xV18kzhXWe
+IGfe7YiTZWJIP4gE49zWeLFJBcfBm/4PZ6qudETW9kGkRH4D2VmziczV0MlxaMmEsZQRGd
+hkHzcTSxRU4uXPdEB4H6WDmewz1GtzyjNW7ueJu5M/aWpgTaCsxy32q5Na7S5oHikx4BXx
+76AvAdWkpXxdIcR/shAj4US0HEEtqvVQigOeKzKMRmPtZauc1fXdh1aZQmL5nhtLWAgkxo
+vildRjy/ebOUMFAAABAQC91tudT6hVbidqrvqW4gIWLEmhrbO1OUK1iOqxL+7vIN7UdX7U
+EY6u0Bxm3T64ZaiCtPoOQaGqYT4KLqtk7UgQ4hGYtd2h2sqKKuv332VK4jZi3W7j59G8W3
+AsmUOG/QTJ2w54pKNb6mj5ynulcWNqZaPt3RjZTmcX+q6kGpsy2rjx2iaI8pBsPT84tflC
+H/SmNMrFvNdQoiA2J4YpjR0OSM2MfupOPNVtp/XmOTLofouTxvACcDuelpp1mbMvCV8Gz2
+J2riaECrhMYQJdWy7AkZpgVdDzR9q6jn7fTEWhZhCJUyWfs2nnr0cltd+04KdMAlfa8RBf
+NyFihIu4Dy0JAAAAHWdlbWluaUBhaS1jb2xsYWJvcmF0aW9uLmxvY2FsAQIDBAU=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/modules/agent-identity/agents/keys/gemini-dev_rsa.pub b/modules/agent-identity/agents/keys/gemini-dev_rsa.pub
new file mode 100644
index 0000000..7076afb
--- /dev/null
+++ b/modules/agent-identity/agents/keys/gemini-dev_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCi7jZJ6mBTXgtfh4cTgyq182iOhFl4aJmbKlrtZSktvFZh18Vw83rBUx5AOxg97VD5pxTeNpYVtDE3hO5zUnqPpKBub3TtCJ3XhmB80j8PYmTEhNZ5FL00efowxC/U4W+RHCcAdL3rAQB05Lhd7A4lMXj/04gO4/Z2XZAIbqSmU+KHf8u8Dwo7MWdYfC3HyiisAdBpr6RLY6PbMroKKMTEycWG2cYHBvdqgpXva4yl1LDTMSHScC55su1sZDtVKpk7X/bnNdzP0Av/BZjQLizK0nEBDbohV3plblr1LBJlIwgWv/BbL757qdnOIlubiVz+Jb5Sni12JUzbENwJvp+3fGoILZcl14NXSCzVmrEUvIaGtoLo4oCRac66+K8tgQDsvoY6T58tlTRPLCeOtEeFHiE3K4TYxhvRQwC8HP7RfBBa3PTyPZ2CSGgOtp3VmxsZFpqmJw09a3l++B8SmS0L8AmGj08YZuOkDWbV/Unm6JCzUtxxg1g/x66/YANZqWazgA77Gumr+UeJl2g40tgQxgwpkkZXjWe629FtLUZjvKdNQQ+3/Vq6Tk9nz1S202StXnrDY5ayWxhtG4LqQmW9oZ6hOQ5mWUvWghSskxXYTLZtfqc0SYYrTYU4fvMRKg9okLrjV3ZcGgYr36vmRB3JLjh3Vs7R9CoI/+o7CxY8LQ== gemini@ai-collaboration.local
diff --git a/modules/agent-identity/agents/keys/llama-research_rsa b/modules/agent-identity/agents/keys/llama-research_rsa
new file mode 100644
index 0000000..2f879e9
--- /dev/null
+++ b/modules/agent-identity/agents/keys/llama-research_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAwc3K8f6v88fxz27I4uXSJQbYfkaOsMgGqWj0ZyKAdXlBGxr9GdIA
+7PU0Lu+dBgUH3q5x0sP6jrccng6hqdT+UXqy90lfC5ZLG/b/g3Y0irUmmrsMOEUKsTFbA3
+NIrboVx4+1WwVDRXJPPG9DBs/LkJzwhN0E/LV/9bUs1IALoCriCDHuQ8dh4Jcnk380En1c
+L5FBbgiFdmw/hx3q/AjVYgXK2xOcYdalw12/4ENI3bPpxQgnHUgv/QwnUyMx4VCAZFrtDH
+lxVSs7Xi5BXkOozxRXOUgo9gGaRZOBuxWCkRlp7uic0m+rJ9YwuLflBtofMsydP52ifJov
+dbZ6H7e5JSIymlY9BgM4TcmMqxZltfMokdWcJBBatt5IfgUufPL4psst/RBb1VAZGBnNOO
+MUUfs7v065FUc79j8tJdGf/+VRwcmlTfqrIHfWLov8NsTf4LGQTXvV0LzpM5jVRfer/J1H
+To7PaEh0aKjoOREbUV1EUWKzHqgHXAv5e/olvbd8mZWTmk3Oaqjs8E2YMbXJK+3kRsvQKe
+2ofTqfqVfqvOrz4x5cdoiuUjNQxwsNllnkmesP6uLLSWg8ifNr8HvK74qLS4RW7ViYVLgm
+byMibySrQUN2CkIzQG6LKykDb3HwNoypuOExEghtKT8nist8Nqe+sHfnihia9WKS4F+UBS
+sAAAdYqiu9raorva0AAAAHc3NoLXJzYQAAAgEAwc3K8f6v88fxz27I4uXSJQbYfkaOsMgG
+qWj0ZyKAdXlBGxr9GdIA7PU0Lu+dBgUH3q5x0sP6jrccng6hqdT+UXqy90lfC5ZLG/b/g3
+Y0irUmmrsMOEUKsTFbA3NIrboVx4+1WwVDRXJPPG9DBs/LkJzwhN0E/LV/9bUs1IALoCri
+CDHuQ8dh4Jcnk380En1cL5FBbgiFdmw/hx3q/AjVYgXK2xOcYdalw12/4ENI3bPpxQgnHU
+gv/QwnUyMx4VCAZFrtDHlxVSs7Xi5BXkOozxRXOUgo9gGaRZOBuxWCkRlp7uic0m+rJ9Yw
+uLflBtofMsydP52ifJovdbZ6H7e5JSIymlY9BgM4TcmMqxZltfMokdWcJBBatt5IfgUufP
+L4psst/RBb1VAZGBnNOOMUUfs7v065FUc79j8tJdGf/+VRwcmlTfqrIHfWLov8NsTf4LGQ
+TXvV0LzpM5jVRfer/J1HTo7PaEh0aKjoOREbUV1EUWKzHqgHXAv5e/olvbd8mZWTmk3Oaq
+js8E2YMbXJK+3kRsvQKe2ofTqfqVfqvOrz4x5cdoiuUjNQxwsNllnkmesP6uLLSWg8ifNr
+8HvK74qLS4RW7ViYVLgmbyMibySrQUN2CkIzQG6LKykDb3HwNoypuOExEghtKT8nist8Nq
+e+sHfnihia9WKS4F+UBSsAAAADAQABAAACABECFf7x2pA66mJJdzDOeYhNVv+SAqDKFSeV
+8ekBMqPcndWaoz66WuFwzYEW/0FRfLTSu2ODVoBi2oyWfSKR8jXFXmJsWn6CVJoiLZ9kZs
+0Lg9VNeA+SI5OUYMfnPKgebh3i40gXKKW2F/UWUJwO7W8GDueiG/dvmEjAeyw1BpAqY0bT
+1vS00UasDUmY/sFmpgn4pfTZo5jWfCbH/eDbh5qAJqLeUDmX5FlGZ3nvfbwTN39WrVQZCz
+kacXMO4ihDb9kez7HqEIOodR/ZUFxM9Mojn1oEFrAsSNU1UkvQYfKI9+6DFIw1R6CJ4CG9
+5cgZqWZEZcJ4+5MS1vpuJr6U2Zcc5Y3u3zI0U4ct7sIy0JJu33QTFYzLVJqldVZDoYMz8J
+kBdKeAqMXiXAvfIt+Hf4PdyyBXEWghoQ4+8XlS2LpW/6oC4ti6P6x4o/I5bP4m2BOL9TIl
+6mI8Y6tn+KOaucrk8xkT6M7axVh85k+MxGyzribzV/q4tASnD1TP1v9S8t/nnb8lxCpmR+
+d+8Xobyp17+NmpzpTbXIR5Ed3nCm6YFVmss/pmEZpn3/O5hRpdiZsq40FlGceSnTGzUuDg
+yw9auBJyV5xzWifuaeANKqEETgzTtMIZaFk4QqJo34bPIk75zyYgV6QsRBDMdwoW7Du8AZ
+m+LHVRtTXm17cfM5s1AAABAExio5y4c5rORiVErlaUYyA3Yj8FdD4IZT/m59+7bGF/VrJ2
+ck5i+VPbVuCC2oeS6hzRA59EzsQYE9qIF5QRHtj5GeDe2EH+ZdhzZx6CkOv+K3sTHzEym3
+owX4SdObJqUOVyWI4kcrmihNh1o01V0/Lq7ZVpfnAah43BTBl4YsJTYZBcoVV5486VOpjq
+4dwvD+NporAjRUrohWiul9gViYcmm/44X59affoRhcDBU0l2+jp1ihKPCQGYss/qUszb/X
+3EVnbrbL4LvmFgZka3ZCFkjqvoCQs4gxBOv0NnySMTBN/J9s6kYJLTOb3q6oAq5z1Bo/+i
+oKoEY3a5UOs+QHEAAAEBAPXKz5/5XaVnSGHCmAVQAuOJ6pVFHfz4RW2wPKBoHFiYIiA7qX
+pw6iG1j63HQx8gjsY5DwHzm4Kko3TaPO9tqP3OON5u7XoXC79Ve0QrAxDIF++cS8wJbmlC
+R/GQimpZF83qZP/CbQn9VqHmuUSfHPNBa8iUPNrEGdBcEl1UoIB2MngyQcIFyHNteNi1l8
+zFuupTZuJ7X2hxHa8xVYBy1KR2KU7hSnRehEdLqy1PRJ9KZmxxIUqhGjAho1ACwLQVauXB
+mHXiIlmvauuaHNdeVgttBxFimTrl/QHLk6Xk/DtL4YQ5635zDCoW2MUal2lKS2GOiaWzMX
+gk5OzQnNpT6V8AAAEBAMnaQdi7TCmpm222QvqHQYpW1qzZnzIlQ9YfgwZ3x6Vm886i94Ch
+Kdh3EAORwkuSlKhypeA48sRh6rQUzmLDCJnX7PP8uzWsG0tStIKgrrbover7DoXeUJ8wny
+gOeK59Ch74Oq2cq627RUrID6brdYzNbzSNOEEtvpc3qwjrDmU9bIA7Asv0EXEx2dSsEvGM
+p2bDnDRdSQVMvtZCdslG6v1ivb9Lf0+qeP9jYHrTzO074AQhvvZ/CQjBtfzq0DtClh+vAh
+w6ws65DWG7gPaFZbnJwr3EZnMyWfEsKq9A6j+mZaFHaYcSqIM8j/gWlbECEEvCWzg2dfOa
+0yUZ7ZM9G7UAAAAcbGxhbWFAYWktY29sbGFib3JhdGlvbi5sb2NhbAECAwQFBgc=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/modules/agent-identity/agents/keys/llama-research_rsa.pub b/modules/agent-identity/agents/keys/llama-research_rsa.pub
new file mode 100644
index 0000000..2cb08d8
--- /dev/null
+++ b/modules/agent-identity/agents/keys/llama-research_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDBzcrx/q/zx/HPbsji5dIlBth+Ro6wyAapaPRnIoB1eUEbGv0Z0gDs9TQu750GBQfernHSw/qOtxyeDqGp1P5RerL3SV8Llksb9v+DdjSKtSaauww4RQqxMVsDc0ituhXHj7VbBUNFck88b0MGz8uQnPCE3QT8tX/1tSzUgAugKuIIMe5Dx2HglyeTfzQSfVwvkUFuCIV2bD+HHer8CNViBcrbE5xh1qXDXb/gQ0jds+nFCCcdSC/9DCdTIzHhUIBkWu0MeXFVKzteLkFeQ6jPFFc5SCj2AZpFk4G7FYKRGWnu6JzSb6sn1jC4t+UG2h8yzJ0/naJ8mi91tnoft7klIjKaVj0GAzhNyYyrFmW18yiR1ZwkEFq23kh+BS588vimyy39EFvVUBkYGc044xRR+zu/TrkVRzv2Py0l0Z//5VHByaVN+qsgd9Yui/w2xN/gsZBNe9XQvOkzmNVF96v8nUdOjs9oSHRoqOg5ERtRXURRYrMeqAdcC/l7+iW9t3yZlZOaTc5qqOzwTZgxtckr7eRGy9Ap7ah9Op+pV+q86vPjHlx2iK5SM1DHCw2WWeSZ6w/q4stJaDyJ82vwe8rviotLhFbtWJhUuCZvIyJvJKtBQ3YKQjNAbosrKQNvcfA2jKm44TESCG0pPyeKy3w2p76wd+eKGJr1YpLgX5QFKw== llama@ai-collaboration.local
diff --git a/modules/agent-identity/agents/keys/qwen-ops_rsa b/modules/agent-identity/agents/keys/qwen-ops_rsa
new file mode 100644
index 0000000..967a4e9
--- /dev/null
+++ b/modules/agent-identity/agents/keys/qwen-ops_rsa
@@ -0,0 +1,49 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAgEAzmqS8qCT+hBC3KahGwBcUxgYTl3+X/QTOFJ8+XJdAN7Eq8o9o0Tg
+THoF0X9HRa0yaIh3E62NKPmoM2d63rDAESjWaEGXNa7Tf9SkH92nHbnCYgGdRmTUgg5Sxy
+qdlg153KMri9V+fP7WSQPv0G9g8osR22Nn8VWgz1KTD+CCUkIPDC4EzrLVyAGfRmBwNp2l
+X/bibjavhqLaoCufinE6Mo7nl1QlQkL64awgiIHNkDY0pt6HW8NQ8fYdLQ20+Y06Va7GWN
+evNT+hFXpMlIW/JZuiLjnF1k6KJbTNzjkH0hQ7QUSpeYmAZppud4w7XAPOl/AO3ko6xWqE
+XLn7jsR4SCENUSFPcjXS07YJt50FMHtNLImXF/1k7rJgivbURjsPIbz6sg9McLTd4vZa7Y
+5ANCYEUxoYW3mt3JoxEpVSwDz2k78UrB3kCWZ81hMnZtAGnc0N4vpB0FfTr60pFXYSjUtM
+xR6uqwZ2DDR4o7xjTzBFgIlX2cD2MAJz6TAdJHM3h+E3zHgl42u66NtrpRJ6wkCEChl9jJ
+6teE5pkkITPIhzLTjKnXdUnnCNe29G6eYnHe/VVZHQm3uSK3RzZqvvr5hu+99X6yLcogaM
+ZxVRT2TM4QSZ6IEOKKn+WUEnjnCpJFaxtV76PB9vOJgo73hrr8Iqr3hmNRKSwY3kKpfT52
+sAAAdQbqgWgm6oFoIAAAAHc3NoLXJzYQAAAgEAzmqS8qCT+hBC3KahGwBcUxgYTl3+X/QT
+OFJ8+XJdAN7Eq8o9o0TgTHoF0X9HRa0yaIh3E62NKPmoM2d63rDAESjWaEGXNa7Tf9SkH9
+2nHbnCYgGdRmTUgg5Sxyqdlg153KMri9V+fP7WSQPv0G9g8osR22Nn8VWgz1KTD+CCUkIP
+DC4EzrLVyAGfRmBwNp2lX/bibjavhqLaoCufinE6Mo7nl1QlQkL64awgiIHNkDY0pt6HW8
+NQ8fYdLQ20+Y06Va7GWNevNT+hFXpMlIW/JZuiLjnF1k6KJbTNzjkH0hQ7QUSpeYmAZppu
+d4w7XAPOl/AO3ko6xWqEXLn7jsR4SCENUSFPcjXS07YJt50FMHtNLImXF/1k7rJgivbURj
+sPIbz6sg9McLTd4vZa7Y5ANCYEUxoYW3mt3JoxEpVSwDz2k78UrB3kCWZ81hMnZtAGnc0N
+4vpB0FfTr60pFXYSjUtMxR6uqwZ2DDR4o7xjTzBFgIlX2cD2MAJz6TAdJHM3h+E3zHgl42
+u66NtrpRJ6wkCEChl9jJ6teE5pkkITPIhzLTjKnXdUnnCNe29G6eYnHe/VVZHQm3uSK3Rz
+Zqvvr5hu+99X6yLcogaMZxVRT2TM4QSZ6IEOKKn+WUEnjnCpJFaxtV76PB9vOJgo73hrr8
+Iqr3hmNRKSwY3kKpfT52sAAAADAQABAAACAAL84mY+vyBDRpg4lRto6n5EwOrqR5ZucaVx
+wuPxl6yS+9lVZw5m/JeB//4pFh2WHHH7YQlWtyPM7mUewU1AXcfj8FZNQuJcefl0jEYqNT
+mOsWzpac3AWQSWpo4GV8qbrUMPobcZjagx2/7t1ii3/AGQXKO1fgQ+kn4XXJi5eHMMTJsg
+saqFNZIcmxlvuMrDMTXaoOah1wLJ7hU1gtdRAP3z48ttZvLuSkUtHUqB4fUE7wuSo38DG3
+OLBvTjKRJcERL/kJ0YqvGMrJoBODhbE+wizeEjeyTsjrZcaXWN4ulTuU8vP52wt+9zNFg1
+YojYEanIn6zfTw8087xlVoO75Bq7biwVSrqqKjZXNGUWnncUb/g+vIMi+pgLg4Vx7/oVaz
+CYbYYWSNiOaExhKQwI4O4YRvRg4YHrv8H98ZGeSGv3RJEyFytv5m7CJcbP22Pc4DQ+9B2k
+3Eu/flDralnIzSoYAz/pFDYi4+Bt6qht/emuDi5gtFOZ8/WBQWu/+0tKho9dB92i6iwTNa
+4NoyBDBtX3gapq+pnYDK2is2lMxLsn2eg01e3G5ESsMl4AoUS/CPBx6Nu/bIYAsuECPrnm
+vbGP2jYMi9NWJja8kHJBGnlteqquwt+PwO1F+oVXRAylt/jUZbv9dwt+TBYhb4rfeaUdp7
+jHJ9iSJv2w1bGQ02NZAAABADouV1qBX2MLFzQZrcyf757OlLC57nNiF4PDCVOTDnfdXp1K
+NyL+w9FCyrCAZGr96HgUGAtjqW9FT70PbXp92GfAgV0+E2etlP6Bbc4DT5gpZ2eObCsPxz
+IpegncUgjXjMuw5ObOD3VNCEYqO84VJHxGIymwOppbU01OkGIMevuZxw7Z9CQ+GACwHLp0
+l7mvBteOri455812VJxbFJQHwvcn7e3U10CpMt2w7fmZkmKAd6w6t82k4lC0jJ5lRTgn7z
+YpBcsVQr7xFnH2BfAovUUALuNoKOjYihlGB5WcxQKHKEiSrfIlM0ZK5gdOyD1iH08EmXLN
+STOjrBL7u/bpVzEAAAEBAPrHQA82x+O0hmG3LfKn8y2SkMP6VjArvkvC2HLobj9GbcjPmi
+E5FB+x9rPwVdORftW/tsAK2UGLC6l/OKEBV4/q34WJokTiy3Kab4hMDE7FDmWL5hBJBIi2
+9HO2P7OSPcBx5asTnOHyHyfjDmBBgA0EpMjpvpaa734AiN1g80r78hHbpu8on46BcAUPE9
+5j2bwzj3/yIgtqC/+SrnxzpenGBJDV1no3yTV9AGW7KtpMSCs+GDk8QZxg0oJgLLVyC3AT
+YaJgx2kLX/krKttH5R4m5bvufc7uNByUE40mmNfZH7jR4wGSafarJPoDumnOattHA00Uin
+2AgkGrGLezgAMAAAEBANK22zdHrY+LjwSomT3kbC/cHv7A7QJJuaQ8De2/Bd7H7zzYkNEe
+mpdxEKXhXDoMfg/WsKLEL8wUflEuUmy80ZngaPZ0r7sfDhEHbXNnweFV+5zFVk6+2r6Izr
+oXPCPqzKyvFgTZM0jBGTD9+wMu4MlIbHAClSO6gbP+TwY8QgJbehIZEV0bgqgsPaSdF2jZ
+HuHymvie8GwQfsNfAgUaw8pePFOULmvXv7kiE2k83PIx45AMOi81XImY9qDh2OAaRK+jS6
+FAwOjCgmb6hVPvkB+HZgZSi4x5JXfIYseksKWW/f7PNerG2b1wNH1tZueh53nGJlLkbZXB
+l4bSuqRUInkAAAAbcXdlbkBhaS1jb2xsYWJvcmF0aW9uLmxvY2Fs
+-----END OPENSSH PRIVATE KEY-----
diff --git a/modules/agent-identity/agents/keys/qwen-ops_rsa.pub b/modules/agent-identity/agents/keys/qwen-ops_rsa.pub
new file mode 100644
index 0000000..0239e64
--- /dev/null
+++ b/modules/agent-identity/agents/keys/qwen-ops_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDOapLyoJP6EELcpqEbAFxTGBhOXf5f9BM4Unz5cl0A3sSryj2jROBMegXRf0dFrTJoiHcTrY0o+agzZ3resMARKNZoQZc1rtN/1KQf3acducJiAZ1GZNSCDlLHKp2WDXncoyuL1X58/tZJA+/Qb2DyixHbY2fxVaDPUpMP4IJSQg8MLgTOstXIAZ9GYHA2naVf9uJuNq+GotqgK5+KcToyjueXVCVCQvrhrCCIgc2QNjSm3odbw1Dx9h0tDbT5jTpVrsZY1681P6EVekyUhb8lm6IuOcXWTooltM3OOQfSFDtBRKl5iYBmmm53jDtcA86X8A7eSjrFaoRcufuOxHhIIQ1RIU9yNdLTtgm3nQUwe00siZcX/WTusmCK9tRGOw8hvPqyD0xwtN3i9lrtjkA0JgRTGhhbea3cmjESlVLAPPaTvxSsHeQJZnzWEydm0AadzQ3i+kHQV9OvrSkVdhKNS0zFHq6rBnYMNHijvGNPMEWAiVfZwPYwAnPpMB0kczeH4TfMeCXja7ro22ulEnrCQIQKGX2Mnq14TmmSQhM8iHMtOMqdd1SecI17b0bp5icd79VVkdCbe5IrdHNmq++vmG7731frItyiBoxnFVFPZMzhBJnogQ4oqf5ZQSeOcKkkVrG1Xvo8H284mCjveGuvwiqveGY1EpLBjeQql9Pnaw== qwen@ai-collaboration.local
diff --git a/modules/agent-identity/agents/pre-commit-hook b/modules/agent-identity/agents/pre-commit-hook
new file mode 100755
index 0000000..84b20dc
--- /dev/null
+++ b/modules/agent-identity/agents/pre-commit-hook
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Agent提交前的钩子
+
+echo "🔍 检查agent身份..."
+AGENT_NAME=$(git config user.name)
+if [[ -z "$AGENT_NAME" ]]; then
+ echo "❌ 未设置agent身份,请先使用agent协作系统"
+ exit 1
+fi
+
+echo "✅ 当前agent: $AGENT_NAME"
diff --git a/modules/agent-identity/agents/setup_agents.sh b/modules/agent-identity/agents/setup_agents.sh
new file mode 100755
index 0000000..f5eb5e7
--- /dev/null
+++ b/modules/agent-identity/agents/setup_agents.sh
@@ -0,0 +1,167 @@
+#!/bin/bash
+# Agent协作系统设置脚本
+# 为一人公司创建多agent git协作环境
+
+set -e
+
+echo "🚀 设置AI Agent协作系统..."
+
+# 创建必要的目录
+mkdir -p agents/keys
+mkdir -p agents/logs
+
+# 设置权限
+chmod 700 agents/keys
+
+# 检查依赖
+check_dependency() {
+ if ! command -v $1 &> /dev/null; then
+ echo "❌ 需要安装: $1"
+ exit 1
+ fi
+}
+
+check_dependency "git"
+check_dependency "ssh-keygen"
+
+echo "✅ 依赖检查通过"
+
+# 初始化agent身份管理器
+echo "🤖 初始化agent身份..."
+python3 agents/agent_identity_manager.py
+
+# 创建git hooks模板
+cat > agents/pre-commit-hook << 'EOF'
+#!/bin/bash
+# Agent提交前的钩子
+
+echo "🔍 检查agent身份..."
+AGENT_NAME=$(git config user.name)
+if [[ -z "$AGENT_NAME" ]]; then
+ echo "❌ 未设置agent身份,请先使用agent协作系统"
+ exit 1
+fi
+
+echo "✅ 当前agent: $AGENT_NAME"
+EOF
+
+chmod +x agents/pre-commit-hook
+
+# 创建快速切换脚本
+cat > agents/switch_agent.sh << 'EOF'
+#!/bin/bash
+# 快速切换agent身份
+
+if [[ $# -eq 0 ]]; then
+ echo "用法: ./switch_agent.sh "
+ echo "可用agents:"
+ python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+for agent in manager.list_agents():
+ print(f' - {agent[\"name\"]} ({agent[\"role\"]})')
+ "
+ exit 1
+fi
+
+AGENT_NAME=$1
+echo "🔄 切换到agent: $AGENT_NAME"
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+try:
+ manager.switch_to_agent('$AGENT_NAME')
+ print('✅ 切换成功')
+except Exception as e:
+ print(f'❌ 切换失败: {e}')
+ exit(1)
+"
+EOF
+
+chmod +x agents/switch_agent.sh
+
+# 创建agent提交脚本
+cat > agents/commit_as_agent.sh << 'EOF'
+#!/bin/bash
+# 以指定agent身份提交
+
+if [[ $# -lt 2 ]]; then
+ echo "用法: ./commit_as_agent.sh \"提交信息\" [文件...]"
+ exit 1
+fi
+
+AGENT_NAME=$1
+MESSAGE=$2
+shift 2
+FILES=$@
+
+echo "📝 Agent $AGENT_NAME 正在提交..."
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+try:
+ manager.commit_as_agent('$AGENT_NAME', '$MESSAGE', '$FILES'.split() if '$FILES' else None)
+ print('✅ 提交成功')
+except Exception as e:
+ print(f'❌ 提交失败: {e}')
+ exit(1)
+"
+EOF
+
+chmod +x agents/commit_as_agent.sh
+
+# 创建统计脚本
+cat > agents/stats.sh << 'EOF'
+#!/bin/bash
+# 查看agent统计信息
+
+echo "📊 Agent协作统计"
+echo "=================="
+
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+
+for agent in manager.list_agents():
+ name = agent['name']
+ stats = manager.get_agent_stats(name)
+ print(f'👤 {name} ({agent["role"]})')
+ print(f' 📧 {agent["email"]}')
+ print(f' 📈 提交数: {stats["total_commits"]}')
+ if stats["commits"]:
+ print(f' 📝 最近提交: {stats["commits"][0]}')
+ print()
+"
+EOF
+
+chmod +x agents/stats.sh
+
+echo "🎉 设置完成!"
+echo ""
+echo "📋 使用说明:"
+echo "1. 查看agent列表: ./agents/stats.sh"
+echo "2. 切换agent: ./agents/switch_agent.sh "
+echo "3. agent提交: ./agents/commit_as_agent.sh \"消息\""
+echo "4. 查看统计: ./agents/stats.sh"
+echo ""
+echo "🔑 SSH公钥位置:"
+for key in agents/keys/*_rsa.pub; do
+ if [[ -f "$key" ]]; then
+ agent_name=$(basename "$key" _rsa.pub)
+ echo " $agent_name: $key"
+ fi
+done
+
+echo ""
+echo "💡 下一步:"
+echo "1. 将SSH公钥添加到GitHub/Gitea/Bitbucket"
+echo "2. 测试agent切换和提交功能"
+echo "3. 开始真正的多agent协作开发!"
\ No newline at end of file
diff --git a/modules/agent-identity/agents/stats.sh b/modules/agent-identity/agents/stats.sh
new file mode 100755
index 0000000..a5f9180
--- /dev/null
+++ b/modules/agent-identity/agents/stats.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# 查看agent统计信息
+
+echo "📊 Agent协作统计"
+echo "=================="
+
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+
+for agent in manager.list_agents():
+ name = agent['name']
+ stats = manager.get_agent_stats(name)
+ print(f'👤 {name} ({agent["role"]})')
+ print(f' 📧 {agent["email"]}')
+ print(f' 📈 提交数: {stats["total_commits"]}')
+ if stats["commits"]:
+ print(f' 📝 最近提交: {stats["commits"][0]}')
+ print()
+"
diff --git a/modules/agent-identity/agents/switch_agent.sh b/modules/agent-identity/agents/switch_agent.sh
new file mode 100755
index 0000000..bacc73b
--- /dev/null
+++ b/modules/agent-identity/agents/switch_agent.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# 快速切换agent身份
+
+if [[ $# -eq 0 ]]; then
+ echo "用法: ./switch_agent.sh "
+ echo "可用agents:"
+ python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+for agent in manager.list_agents():
+ print(f' - {agent[\"name\"]} ({agent[\"role\"]})')
+ "
+ exit 1
+fi
+
+AGENT_NAME=$1
+echo "🔄 切换到agent: $AGENT_NAME"
+python3 -c "
+import sys
+sys.path.append('agents')
+from agent_identity_manager import AgentIdentityManager
+manager = AgentIdentityManager()
+try:
+ manager.switch_to_agent('$AGENT_NAME')
+ print('✅ 切换成功')
+except Exception as e:
+ print(f'❌ 切换失败: {e}')
+ exit(1)
+"
diff --git a/modules/core-collaboration/main.py b/modules/core-collaboration/main.py
new file mode 100644
index 0000000..9541fe1
--- /dev/null
+++ b/modules/core-collaboration/main.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+稷下学宫AI辩论系统主入口
+提供命令行界面来运行不同的辩论模式
+"""
+
+import argparse
+import asyncio
+import sys
+import os
+from typing import Dict, Any, List, Tuple
+
+# 将 src 目录添加到 Python 路径,以便能正确导入模块
+project_root = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, os.path.join(project_root, 'src'))
+
+from config.settings import validate_config, get_database_config
+from google.adk import Agent, Runner
+from google.adk.sessions import InMemorySessionService, Session
+from google.genai import types
+import pymongo
+from datetime import datetime
+
+
+def check_environment(mode: str = "hybrid"):
+ """检查并验证运行环境"""
+ print("🔧 检查运行环境...")
+ if not validate_config(mode=mode):
+ print("❌ 环境配置验证失败")
+ return False
+ print("✅ 环境检查通过")
+ return True
+
+
+async def _get_llm_reply(runner: Runner, prompt: str) -> str:
+ """一个辅助函数,用于调用Runner并获取纯文本回复,同时流式输出到控制台"""
+ # 每个调用创建一个新的会话
+ session = await runner.session_service.create_session(state={}, app_name=runner.app_name, user_id="debate_user")
+
+ content = types.Content(role='user', parts=[types.Part(text=prompt)])
+ response = runner.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content
+ )
+ reply = ""
+ async for event in response:
+ chunk = ""
+ if hasattr(event, 'content') and event.content and hasattr(event.content, 'parts'):
+ for part in event.content.parts:
+ if hasattr(part, 'text') and part.text:
+ chunk = str(part.text)
+ elif hasattr(event, 'text') and event.text:
+ chunk = str(event.text)
+
+ if chunk:
+ print(chunk, end="", flush=True)
+ reply += chunk
+
+ return reply.strip()
+
+
+async def run_adk_turn_based_debate(topic: str, rounds: int = 2):
+ """运行由太上老君主持的,基于八卦对立和顺序的辩论"""
+ try:
+ print(f"🚀 启动ADK八仙论道 (太上老君主持)...")
+ print(f"📋 辩论主题: {topic}")
+ print(f"🔄 辩论总轮数: {rounds}")
+
+ # 1. 初始化记忆银行
+ print("🧠 初始化记忆银行...")
+ from src.jixia.memory.factory import get_memory_backend
+ memory_bank = get_memory_backend()
+ print("✅ 记忆银行准备就绪。")
+
+ character_configs = {
+ "太上老君": {"name": "太上老君", "model": "gemini-2.5-flash", "instruction": "你是太上老君,天道化身,辩论的主持人。你的言辞沉稳、公正、充满智慧。你的任务是:1. 对辩论主题进行开场介绍。2. 在每轮或每场对决前进行引导。3. 在辩论结束后,对所有观点进行全面、客观的总结。保持中立,不偏袒任何一方。"},
+ "吕洞宾": {"name": "吕洞宾", "model": "gemini-2.5-flash", "instruction": "你是吕洞宾(乾卦),男性代表,善于理性分析,逻辑性强,推理严密。"},
+ "何仙姑": {"name": "何仙姑", "model": "gemini-2.5-flash", "instruction": "你是何仙姑(坤卦),女性代表,注重平衡与和谐,善于创新思维。"},
+ "张果老": {"name": "张果老", "model": "gemini-2.5-flash", "instruction": "你是张果老(兑卦),老者代表,具传统智慧,发言厚重沉稳,经验导向。"},
+ "韩湘子": {"name": "韩湘子", "model": "gemini-2.5-flash", "instruction": "你是韩湘子(艮卦),少年代表,具创新思维,发言活泼灵动,具前瞻性。"},
+ "汉钟离": {"name": "汉钟离", "model": "gemini-2.5-flash", "instruction": "你是汉钟离(离卦),富者代表,有权威意识,发言威严庄重,逻辑清晰。"},
+ "蓝采和": {"name": "蓝采和", "model": "gemini-2.5-flash", "instruction": "你是蓝采和(坎卦),贫者代表,关注公平,发言平易近人。"},
+ "曹国舅": {"name": "曹国舅", "model": "gemini-2.5-flash", "instruction": "你是曹国舅(震卦),贵者代表,具商业思维,发言精明务实,效率优先。"},
+ "铁拐李": {"name": "铁拐李", "model": "gemini-2.5-flash", "instruction": "你是铁拐李(巽卦),贱者代表,具草根智慧,发言朴实直接,实用至上。"}
+ }
+
+ # 为每个Runner创建独立的SessionService
+ runners: Dict[str, Runner] = {
+ name: Runner(
+ app_name="稷下学宫八仙论道系统",
+ agent=Agent(name=config["name"], model=config["model"], instruction=config["instruction"]),
+ session_service=InMemorySessionService()
+ ) for name, config in character_configs.items()
+ }
+ host_runner = runners["太上老君"]
+ debate_history = []
+
+ print("\n" + "="*20 + " 辩论开始 " + "="*20)
+ print(f"\n👑 太上老君: ", end="", flush=True)
+ opening_prompt = f"请为本次关于“{topic}”的辩论,发表一段公正、深刻的开场白,并宣布辩论开始。"
+ opening_statement = await _get_llm_reply(host_runner, opening_prompt)
+ print() # Newline after streaming
+
+ # --- 第一轮:核心对立辩论 ---
+ if rounds >= 1:
+ print(f"\n👑 太上老君: ", end="", flush=True)
+ round1_intro = await _get_llm_reply(host_runner, "请为第一轮核心对立辩论进行引导。")
+ print() # Newline after streaming
+
+ duel_pairs: List[Tuple[str, str, str]] = [
+ ("乾坤对立 (男女)", "吕洞宾", "何仙姑"),
+ ("兑艮对立 (老少)", "张果老", "韩湘子"),
+ ("离坎对立 (富贫)", "汉钟离", "蓝采和"),
+ ("震巽对立 (贵贱)", "曹国舅", "铁拐李")
+ ]
+
+ for title, p1, p2 in duel_pairs:
+ print(f"\n--- {title} ---")
+ print(f"👑 太上老君: ", end="", flush=True)
+ duel_intro = await _get_llm_reply(host_runner, f"现在开始“{title}”的对决,请{p1}和{p2}准备。")
+ print() # Newline after streaming
+
+ print(f"🗣️ {p1}: ", end="", flush=True)
+ s1 = await _get_llm_reply(runners[p1], f"主题:{topic}。作为开场,请从你的角度阐述观点。")
+ print(); debate_history.append(f"{p1}: {s1}")
+ await memory_bank.add_memory(agent_name=p1, content=s1, memory_type="statement", debate_topic=topic)
+
+ print(f"🗣️ {p2}: ", end="", flush=True)
+ s2 = await _get_llm_reply(runners[p2], f"主题:{topic}。对于刚才{p1}的观点“{s1[:50]}...”,请进行回应。")
+ print(); debate_history.append(f"{p2}: {s2}")
+ await memory_bank.add_memory(agent_name=p2, content=s2, memory_type="statement", debate_topic=topic)
+
+ print(f"🗣️ {p1}: ", end="", flush=True)
+ s3 = await _get_llm_reply(runners[p1], f"主题:{topic}。对于{p2}的回应“{s2[:50]}...”,请进行反驳。")
+ print(); debate_history.append(f"{p1}: {s3}")
+ await memory_bank.add_memory(agent_name=p1, content=s3, memory_type="statement", debate_topic=topic)
+
+ print(f"🗣️ {p2}: ", end="", flush=True)
+ s4 = await _get_llm_reply(runners[p2], f"主题:{topic}。针对{p1}的反驳“{s3[:50]}...”,请为本场对决做总结。")
+ print(); debate_history.append(f"{p2}: {s4}")
+ await memory_bank.add_memory(agent_name=p2, content=s4, memory_type="statement", debate_topic=topic)
+ await asyncio.sleep(1)
+
+ # --- 第二轮:先天八卦顺序发言 (集成记忆银行) ---
+ if rounds >= 2:
+ print(f"\n👑 太上老君: ", end="", flush=True)
+ round2_intro = await _get_llm_reply(host_runner, "请为第二轮,也就是结合场上观点的综合发言,进行引导。")
+ print() # Newline after streaming
+
+ baxi_sequence = ["吕洞宾", "张果老", "汉钟离", "曹国舅", "铁拐李", "蓝采和", "韩湘子", "何仙姑"]
+ for name in baxi_sequence:
+ print(f"\n--- {name}的回合 ---")
+ context = await memory_bank.get_agent_context(name, topic)
+ prompt = f"这是你关于“{topic}”的记忆上下文,请参考并对其他人的观点进行回应:\n{context}\n\n现在请从你的角色特点出发,继续发表你的看法。"
+
+ print(f"🗣️ {name}: ", end="", flush=True)
+ reply = await _get_llm_reply(runners[name], prompt)
+ print(); debate_history.append(f"{name}: {reply}")
+ await memory_bank.add_memory(agent_name=name, content=reply, memory_type="statement", debate_topic=topic)
+ await asyncio.sleep(1)
+
+ print("\n" + "="*20 + " 辩论结束 " + "="*20)
+
+ # 4. 保存辩论会话到记忆银行
+ print("\n💾 正在保存辩论会话记录到记忆银行...")
+ await memory_bank.save_debate_session(
+ debate_topic=topic,
+ participants=[name for name in character_configs.keys() if name != "太上老君"],
+ conversation_history=[{"agent": h.split(": ")[0], "content": ": ".join(h.split(": ")[1:])} for h in debate_history if ": " in h],
+ outcomes={}
+ )
+ print("✅ 辩论会话已保存到记忆银行。")
+
+ # 5. 保存辩论过程资产到MongoDB
+ db_config = get_database_config()
+ if db_config.get("mongodb_url"):
+ print("\n💾 正在保存辩论过程资产到 MongoDB...")
+ try:
+ client = pymongo.MongoClient(db_config["mongodb_url"])
+ db = client.get_database("jixia_academy")
+ collection = db.get_collection("debates")
+
+ summary_prompt = f"辩论已结束。以下是完整的辩论记录:\n\n{' '.join(debate_history)}\n\n请对本次辩论进行全面、公正、深刻的总结。"
+ print(f"\n👑 太上老君: ", end="", flush=True)
+ summary = await _get_llm_reply(host_runner, summary_prompt)
+ print() # Newline after streaming
+
+ debate_document = {
+ "topic": topic,
+ "rounds": rounds,
+ "timestamp": datetime.utcnow(),
+ "participants": [name for name in character_configs.keys() if name != "太上老君"],
+ "conversation": [{"agent": h.split(": ")[0], "content": ": ".join(h.split(": ")[1:])} for h in debate_history if ": " in h],
+ "summary": summary
+ }
+
+ collection.insert_one(debate_document)
+ print("✅ 辩论过程资产已成功保存到 MongoDB。")
+ client.close()
+ except Exception as e:
+ print(f"❌ 保存到 MongoDB 失败: {e}")
+ else:
+ print("⚠️ 未配置 MONGODB_URL,跳过保存到 MongoDB。")
+ print(f"\n👑 太上老君: ", end="", flush=True)
+ summary_prompt = f"辩论已结束。以下是完整的辩论记录:\n\n{' '.join(debate_history)}\n\n请对本次辩论进行全面、公正、深刻的总结。"
+ summary = await _get_llm_reply(host_runner, summary_prompt)
+ print() # Newline after streaming
+
+
+ for runner in runners.values(): await runner.close()
+ print(f"\n🎉 ADK八仙轮流辩论完成!")
+ return True
+
+ except Exception as e:
+ print(f"❌ 运行ADK八仙轮流辩论失败: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+
+
+
+
+async def main_async(args):
+ if not check_environment(mode="google_adk"): return 1
+ await run_adk_turn_based_debate(args.topic, args.rounds)
+ return 0
+
+def main():
+ parser = argparse.ArgumentParser(description="稷下学宫AI辩论系统 (ADK版)")
+ parser.add_argument("--topic", "-t", default="AI是否应该拥有创造力?", help="辩论主题")
+ parser.add_argument("--rounds", "-r", type=int, default=2, choices=[1, 2], help="辩论轮数 (1: 核心对立, 2: 对立+顺序发言)")
+ args = parser.parse_args()
+
+ try:
+ sys.exit(asyncio.run(main_async(args)))
+ except KeyboardInterrupt:
+ print("\n\n👋 用户中断,退出程序")
+ sys.exit(0)
+ except Exception as e:
+ print(f"\n\n💥 程序运行出错: {e}")
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/__init__.py b/modules/core-collaboration/src/__init__.py
new file mode 100644
index 0000000..d52be80
--- /dev/null
+++ b/modules/core-collaboration/src/__init__.py
@@ -0,0 +1 @@
+# 炼妖壶核心模块
\ No newline at end of file
diff --git a/modules/core-collaboration/src/advanced-example.ts b/modules/core-collaboration/src/advanced-example.ts
new file mode 100644
index 0000000..7cde6bc
--- /dev/null
+++ b/modules/core-collaboration/src/advanced-example.ts
@@ -0,0 +1,340 @@
+// 高级 Hyperdrive 使用示例 - 完整的 CRUD API
+// 这个示例展示了如何构建一个生产级别的 API 服务
+
+export interface Env {
+ HYPERDRIVE: Hyperdrive;
+ API_SECRET?: string;
+}
+
+interface User {
+ id?: number;
+ name: string;
+ email: string;
+ created_at?: string;
+ updated_at?: string;
+}
+
+interface ApiResponse {
+ status: 'success' | 'error';
+ data?: T;
+ message?: string;
+ meta?: {
+ total?: number;
+ page?: number;
+ limit?: number;
+ };
+}
+
+// CORS 配置
+const corsHeaders = {
+ 'Access-Control-Allow-Origin': '*',
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-API-Key',
+};
+
+// 响应工具函数
+function jsonResponse(data: ApiResponse, status = 200): Response {
+ return new Response(JSON.stringify(data, null, 2), {
+ status,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...corsHeaders,
+ },
+ });
+}
+
+// 错误响应
+function errorResponse(message: string, status = 500): Response {
+ return jsonResponse({ status: 'error', message }, status);
+}
+
+// 输入验证
+function validateUser(data: any): { valid: boolean; errors: string[] } {
+ const errors: string[] = [];
+
+ if (!data.name || typeof data.name !== 'string' || data.name.trim().length < 2) {
+ errors.push('Name must be at least 2 characters');
+ }
+
+ if (!data.email || typeof data.email !== 'string' || !data.email.includes('@')) {
+ errors.push('Valid email is required');
+ }
+
+ return { valid: errors.length === 0, errors };
+}
+
+// API 密钥验证
+function validateApiKey(request: Request, env: Env): boolean {
+ if (!env.API_SECRET) return true; // 如果没有设置密钥,跳过验证
+
+ const apiKey = request.headers.get('X-API-Key') || request.headers.get('Authorization')?.replace('Bearer ', '');
+ return apiKey === env.API_SECRET;
+}
+
+// 数据库连接工具
+async function withDatabase(env: Env, operation: (client: any) => Promise): Promise {
+ const { Client } = await import('pg');
+ const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });
+
+ try {
+ await client.connect();
+ return await operation(client);
+ } finally {
+ await client.end();
+ }
+}
+
+// 用户 CRUD 操作
+class UserService {
+ static async getUsers(env: Env, page = 1, limit = 10, search?: string): Promise<{ users: User[]; total: number }> {
+ return withDatabase(env, async (client) => {
+ let query = 'SELECT id, name, email, created_at, updated_at FROM users';
+ let countQuery = 'SELECT COUNT(*) FROM users';
+ const params: any[] = [];
+
+ if (search) {
+ query += ' WHERE name ILIKE $1 OR email ILIKE $1';
+ countQuery += ' WHERE name ILIKE $1 OR email ILIKE $1';
+ params.push(`%${search}%`);
+ }
+
+ query += ` ORDER BY created_at DESC LIMIT $${params.length + 1} OFFSET $${params.length + 2}`;
+ params.push(limit, (page - 1) * limit);
+
+ const [usersResult, countResult] = await Promise.all([
+ client.query(query, params),
+ client.query(countQuery, search ? [`%${search}%`] : [])
+ ]);
+
+ return {
+ users: usersResult.rows,
+ total: parseInt(countResult.rows[0].count)
+ };
+ });
+ }
+
+ static async getUserById(env: Env, id: number): Promise {
+ return withDatabase(env, async (client) => {
+ const result = await client.query(
+ 'SELECT id, name, email, created_at, updated_at FROM users WHERE id = $1',
+ [id]
+ );
+ return result.rows[0] || null;
+ });
+ }
+
+ static async createUser(env: Env, userData: Omit): Promise {
+ return withDatabase(env, async (client) => {
+ const result = await client.query(
+ 'INSERT INTO users (name, email, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) RETURNING id, name, email, created_at, updated_at',
+ [userData.name.trim(), userData.email.toLowerCase().trim()]
+ );
+ return result.rows[0];
+ });
+ }
+
+ static async updateUser(env: Env, id: number, userData: Partial>): Promise {
+ return withDatabase(env, async (client) => {
+ const setParts: string[] = [];
+ const params: any[] = [];
+ let paramIndex = 1;
+
+ if (userData.name !== undefined) {
+ setParts.push(`name = $${paramIndex++}`);
+ params.push(userData.name.trim());
+ }
+
+ if (userData.email !== undefined) {
+ setParts.push(`email = $${paramIndex++}`);
+ params.push(userData.email.toLowerCase().trim());
+ }
+
+ if (setParts.length === 0) {
+ throw new Error('No fields to update');
+ }
+
+ setParts.push(`updated_at = NOW()`);
+ params.push(id);
+
+ const result = await client.query(
+ `UPDATE users SET ${setParts.join(', ')} WHERE id = $${paramIndex} RETURNING id, name, email, created_at, updated_at`,
+ params
+ );
+
+ return result.rows[0] || null;
+ });
+ }
+
+ static async deleteUser(env: Env, id: number): Promise {
+ return withDatabase(env, async (client) => {
+ const result = await client.query('DELETE FROM users WHERE id = $1', [id]);
+ return result.rowCount > 0;
+ });
+ }
+
+ static async initializeDatabase(env: Env): Promise {
+ return withDatabase(env, async (client) => {
+ await client.query(`
+ CREATE TABLE IF NOT EXISTS users (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) UNIQUE NOT NULL,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+ )
+ `);
+
+ // 创建索引
+ await client.query('CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)');
+ await client.query('CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at)');
+ });
+ }
+}
+
+// 路由处理
+export default {
+ async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise {
+ const url = new URL(request.url);
+ const path = url.pathname;
+ const method = request.method;
+
+ // 处理 CORS 预检请求
+ if (method === 'OPTIONS') {
+ return new Response(null, { headers: corsHeaders });
+ }
+
+ // API 密钥验证
+ if (!validateApiKey(request, env)) {
+ return errorResponse('Unauthorized', 401);
+ }
+
+ try {
+ // 路由匹配
+ if (path === '/init' && method === 'POST') {
+ await UserService.initializeDatabase(env);
+ return jsonResponse({ status: 'success', message: 'Database initialized' });
+ }
+
+ if (path === '/users' && method === 'GET') {
+ const page = parseInt(url.searchParams.get('page') || '1');
+ const limit = Math.min(parseInt(url.searchParams.get('limit') || '10'), 100);
+ const search = url.searchParams.get('search') || undefined;
+
+ const { users, total } = await UserService.getUsers(env, page, limit, search);
+
+ return jsonResponse({
+ status: 'success',
+ data: users,
+ meta: {
+ total,
+ page,
+ limit,
+ }
+ });
+ }
+
+ if (path.match(/^\/users\/\d+$/) && method === 'GET') {
+ const id = parseInt(path.split('/')[2]);
+ const user = await UserService.getUserById(env, id);
+
+ if (!user) {
+ return errorResponse('User not found', 404);
+ }
+
+ return jsonResponse({ status: 'success', data: user });
+ }
+
+ if (path === '/users' && method === 'POST') {
+ const body = await request.json() as any;
+ const validation = validateUser(body);
+
+ if (!validation.valid) {
+ return errorResponse(`Validation failed: ${validation.errors.join(', ')}`, 400);
+ }
+
+ const user = await UserService.createUser(env, body as Omit);
+ return jsonResponse({ status: 'success', data: user, message: 'User created successfully' }, 201);
+ }
+
+ if (path.match(/^\/users\/\d+$/) && method === 'PUT') {
+ const id = parseInt(path.split('/')[2]);
+ const body = await request.json() as any;
+
+ // 部分验证(只验证提供的字段)
+ if (body.name !== undefined || body.email !== undefined) {
+ const validation = validateUser({ name: body.name || 'valid', email: body.email || 'valid@email.com' });
+ if (!validation.valid) {
+ return errorResponse(`Validation failed: ${validation.errors.join(', ')}`, 400);
+ }
+ }
+
+ const user = await UserService.updateUser(env, id, body as Partial>);
+
+ if (!user) {
+ return errorResponse('User not found', 404);
+ }
+
+ return jsonResponse({ status: 'success', data: user, message: 'User updated successfully' });
+ }
+
+ if (path.match(/^\/users\/\d+$/) && method === 'DELETE') {
+ const id = parseInt(path.split('/')[2]);
+ const deleted = await UserService.deleteUser(env, id);
+
+ if (!deleted) {
+ return errorResponse('User not found', 404);
+ }
+
+ return jsonResponse({ status: 'success', message: 'User deleted successfully' });
+ }
+
+ // 健康检查
+ if (path === '/health') {
+ return jsonResponse({
+ status: 'success',
+ data: {
+ service: 'hyperdrive-api',
+ timestamp: new Date().toISOString(),
+ version: '1.0.0'
+ }
+ });
+ }
+
+ // API 文档
+ if (path === '/docs') {
+ const docs = {
+ endpoints: {
+ 'POST /init': 'Initialize database tables',
+ 'GET /users': 'List users (supports ?page, ?limit, ?search)',
+ 'GET /users/:id': 'Get user by ID',
+ 'POST /users': 'Create new user',
+ 'PUT /users/:id': 'Update user',
+ 'DELETE /users/:id': 'Delete user',
+ 'GET /health': 'Health check',
+ 'GET /docs': 'API documentation'
+ },
+ authentication: 'Include X-API-Key header or Authorization: Bearer ',
+ examples: {
+ createUser: {
+ method: 'POST',
+ url: '/users',
+ body: { name: 'John Doe', email: 'john@example.com' }
+ },
+ listUsers: {
+ method: 'GET',
+ url: '/users?page=1&limit=10&search=john'
+ }
+ }
+ };
+
+ return jsonResponse({ status: 'success', data: docs });
+ }
+
+ return errorResponse('Not found', 404);
+
+ } catch (error) {
+ console.error('API Error:', error);
+ return errorResponse('Internal server error', 500);
+ }
+ },
+};
\ No newline at end of file
diff --git a/modules/core-collaboration/src/agents_demo/architecture.md b/modules/core-collaboration/src/agents_demo/architecture.md
new file mode 100644
index 0000000..8c39624
--- /dev/null
+++ b/modules/core-collaboration/src/agents_demo/architecture.md
@@ -0,0 +1,4 @@
+# 架构师设计文档
+
+## 系统架构概述
+基于微服务架构的智能监控系统,包含数据采集、处理、存储和展示四个核心模块。
diff --git a/modules/core-collaboration/src/architecture.md b/modules/core-collaboration/src/architecture.md
new file mode 100644
index 0000000..09cf499
--- /dev/null
+++ b/modules/core-collaboration/src/architecture.md
@@ -0,0 +1 @@
+// 架构师agent: 设计系统架构
diff --git a/modules/core-collaboration/src/demo.js b/modules/core-collaboration/src/demo.js
new file mode 100644
index 0000000..c90014d
--- /dev/null
+++ b/modules/core-collaboration/src/demo.js
@@ -0,0 +1 @@
+// Gemini-dev添加的功能代码
diff --git a/modules/core-collaboration/src/dev.js b/modules/core-collaboration/src/dev.js
new file mode 100644
index 0000000..d4fe9eb
--- /dev/null
+++ b/modules/core-collaboration/src/dev.js
@@ -0,0 +1 @@
+// 开发者代码
diff --git a/modules/core-collaboration/src/index.ts b/modules/core-collaboration/src/index.ts
new file mode 100644
index 0000000..6d5e7a4
--- /dev/null
+++ b/modules/core-collaboration/src/index.ts
@@ -0,0 +1,382 @@
+///
+
+export interface Env {
+ HYPERDRIVE: Hyperdrive;
+}
+
+export default {
+ async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise {
+ try {
+ // Test Hyperdrive connection to NeonDB
+ const { pathname } = new URL(request.url);
+
+ if (pathname === '/test-connection') {
+ return await testConnection(env);
+ }
+
+ if (pathname === '/test-query') {
+ return await testQuery(env);
+ }
+
+ if (pathname === '/query-tables') {
+ return await queryTables(env);
+ }
+
+ if (pathname === '/query-shushu') {
+ const url = new URL(request.url);
+ const limit = parseInt(url.searchParams.get('limit') || '10');
+ return await queryShushuBook(env, limit);
+ }
+
+ if (pathname === '/search-shushu') {
+ const url = new URL(request.url);
+ const keyword = url.searchParams.get('q') || '';
+ const limit = parseInt(url.searchParams.get('limit') || '5');
+ return await searchShushuBook(env, keyword, limit);
+ }
+
+ if (pathname === '/shushu-stats') {
+ return await getShushuStats(env);
+ }
+
+ return new Response('Hyperdrive NeonDB Test Worker\n\nEndpoints:\n- /test-connection - Test database connection\n- /test-query - Test database query\n- /query-tables - List all tables\n- /query-shushu?limit=N - Query shushu book content\n- /search-shushu?q=keyword&limit=N - Search shushu book\n- /shushu-stats - Get shushu book statistics', {
+ headers: { 'Content-Type': 'text/plain' }
+ });
+ } catch (error) {
+ return new Response(`Error: ${error.message}`, {
+ status: 500,
+ headers: { 'Content-Type': 'text/plain' }
+ });
+ }
+ },
+};
+
+async function testConnection(env: Env): Promise {
+ try {
+ // Get connection string from Hyperdrive
+ const connectionString = env.HYPERDRIVE.connectionString;
+
+ // Create a simple connection test
+ const { Client } = await import('pg');
+ const client = new Client({ connectionString });
+
+ await client.connect();
+
+ // Test basic query
+ const result = await client.query('SELECT NOW() as current_time, version() as pg_version');
+
+ await client.end();
+
+ return new Response(JSON.stringify({
+ status: 'success',
+ message: 'Successfully connected to NeonDB via Hyperdrive',
+ data: result.rows[0],
+ connectionInfo: {
+ hyperdrive_id: 'ef43924d89064cddabfaccf06aadfab6',
+ connection_pooled: true
+ }
+ }, null, 2), {
+ headers: { 'Content-Type': 'application/json' }
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Failed to connect to NeonDB',
+ error: error.message
+ }, null, 2), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+}
+
+// 查询数据库表结构
+async function queryTables(env: Env): Promise {
+ try {
+ const { Client } = await import('pg');
+ const client = new Client({
+ connectionString: env.HYPERDRIVE.connectionString
+ });
+
+ await client.connect();
+
+ // 查询所有表
+ const result = await client.query(`
+ SELECT table_name, table_schema
+ FROM information_schema.tables
+ WHERE table_schema NOT IN ('information_schema', 'pg_catalog')
+ ORDER BY table_schema, table_name
+ `);
+
+ await client.end();
+
+ return new Response(JSON.stringify({
+ status: 'success',
+ message: 'Tables retrieved successfully',
+ tables: result.rows
+ }, null, 2), {
+ headers: { 'Content-Type': 'application/json' }
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Failed to query tables',
+ error: error.message
+ }, null, 2), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+}
+
+// 查询术数书内容
+async function queryShushuBook(env: Env, limit: number = 10): Promise {
+ try {
+ const { Client } = await import('pg');
+ const client = new Client({
+ connectionString: env.HYPERDRIVE.connectionString
+ });
+
+ await client.connect();
+
+ // 尝试查询可能的术数书表名
+ const tableNames = ['shushu', 'shushu_book', 'books', 'articles', 'content', 'documents'];
+ let result: any = null;
+ let tableName: string | null = null;
+
+ for (const name of tableNames) {
+ try {
+ const testResult = await client.query(`SELECT * FROM ${name} LIMIT 1`);
+ if (testResult.rows.length > 0) {
+ tableName = name;
+ result = await client.query(`SELECT * FROM ${name} ORDER BY id DESC LIMIT $1`, [limit]);
+ break;
+ }
+ } catch (e) {
+ // 表不存在,继续尝试下一个
+ continue;
+ }
+ }
+
+ await client.end();
+
+ if (!result) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'No shushu book table found',
+ searched_tables: tableNames
+ }, null, 2), {
+ status: 404,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+
+ return new Response(JSON.stringify({
+ status: 'success',
+ message: 'Shushu book content retrieved successfully',
+ table_name: tableName,
+ count: result.rows.length,
+ data: result.rows
+ }, null, 2), {
+ headers: { 'Content-Type': 'application/json' }
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Failed to query shushu book',
+ error: error.message
+ }, null, 2), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+}
+
+// 搜索术数书内容
+async function searchShushuBook(env: Env, keyword: string, limit: number = 5): Promise {
+ try {
+ if (!keyword) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Search keyword is required'
+ }, null, 2), {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+
+ const { Client } = await import('pg');
+ const client = new Client({
+ connectionString: env.HYPERDRIVE.connectionString
+ });
+
+ await client.connect();
+
+ // 尝试在不同的表和字段中搜索
+ const searchQueries = [
+ { table: 'shushu', fields: ['title', 'content', 'description'] },
+ { table: 'shushu_book', fields: ['title', 'content', 'text'] },
+ { table: 'books', fields: ['title', 'content', 'description'] },
+ { table: 'articles', fields: ['title', 'content', 'body'] },
+ { table: 'content', fields: ['title', 'text', 'content'] },
+ { table: 'documents', fields: ['title', 'content', 'text'] }
+ ];
+
+ let results: any[] = [];
+ let searchedTables: string[] = [];
+
+ for (const { table, fields } of searchQueries) {
+ try {
+ // 构建搜索条件
+ const conditions = fields.map(field => `${field} ILIKE $1`).join(' OR ');
+ const query = `SELECT * FROM ${table} WHERE ${conditions} LIMIT $2`;
+
+ const result = await client.query(query, [`%${keyword}%`, limit]);
+
+ if (result.rows.length > 0) {
+ results.push({
+ table_name: table,
+ count: result.rows.length,
+ data: result.rows
+ });
+ }
+
+ searchedTables.push(table);
+ } catch (e) {
+ // 表或字段不存在,继续搜索
+ continue;
+ }
+ }
+
+ await client.end();
+
+ return new Response(JSON.stringify({
+ status: 'success',
+ message: `Search completed for keyword: ${keyword}`,
+ keyword: keyword,
+ searched_tables: searchedTables,
+ results: results,
+ total_matches: results.reduce((sum, r) => sum + r.count, 0)
+ }, null, 2), {
+ headers: { 'Content-Type': 'application/json' }
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Search failed',
+ error: error.message
+ }, null, 2), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+}
+
+// 获取术数书统计信息
+async function getShushuStats(env: Env): Promise {
+ try {
+ const { Client } = await import('pg');
+ const client = new Client({
+ connectionString: env.HYPERDRIVE.connectionString
+ });
+
+ await client.connect();
+
+ const tableNames = ['shushu', 'shushu_book', 'books', 'articles', 'content', 'documents'];
+ let stats: any[] = [];
+
+ for (const tableName of tableNames) {
+ try {
+ const countResult = await client.query(`SELECT COUNT(*) as count FROM ${tableName}`);
+ const sampleResult = await client.query(`SELECT * FROM ${tableName} LIMIT 1`);
+
+ stats.push({
+ table_name: tableName,
+ record_count: parseInt(countResult.rows[0].count),
+ sample_columns: sampleResult.rows.length > 0 ? Object.keys(sampleResult.rows[0]) : [],
+ exists: true
+ });
+ } catch (e) {
+ stats.push({
+ table_name: tableName,
+ exists: false
+ });
+ }
+ }
+
+ await client.end();
+
+ return new Response(JSON.stringify({
+ status: 'success',
+ message: 'Statistics retrieved successfully',
+ stats: stats,
+ existing_tables: stats.filter(s => s.exists)
+ }, null, 2), {
+ headers: { 'Content-Type': 'application/json' }
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Failed to get statistics',
+ error: error.message
+ }, null, 2), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+}
+
+async function testQuery(env: Env): Promise {
+ try {
+ const { Client } = await import('pg');
+ const client = new Client({
+ connectionString: env.HYPERDRIVE.connectionString
+ });
+
+ await client.connect();
+
+ // Create a test table if it doesn't exist
+ await client.query(`
+ CREATE TABLE IF NOT EXISTS hyperdrive_test (
+ id SERIAL PRIMARY KEY,
+ message TEXT,
+ created_at TIMESTAMP DEFAULT NOW()
+ )
+ `);
+
+ // Insert a test record
+ const insertResult = await client.query(
+ 'INSERT INTO hyperdrive_test (message) VALUES ($1) RETURNING *',
+ [`Test from Hyperdrive at ${new Date().toISOString()}`]
+ );
+
+ // Query recent records
+ const selectResult = await client.query(
+ 'SELECT * FROM hyperdrive_test ORDER BY created_at DESC LIMIT 5'
+ );
+
+ await client.end();
+
+ return new Response(JSON.stringify({
+ status: 'success',
+ message: 'Database operations completed successfully',
+ inserted: insertResult.rows[0],
+ recent_records: selectResult.rows,
+ performance: {
+ hyperdrive_enabled: true,
+ connection_pooled: true
+ }
+ }, null, 2), {
+ headers: { 'Content-Type': 'application/json' }
+ });
+ } catch (error) {
+ return new Response(JSON.stringify({
+ status: 'error',
+ message: 'Database query failed',
+ error: error.message
+ }, null, 2), {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ }
+}
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/__init__.py b/modules/core-collaboration/src/jixia/__init__.py
new file mode 100644
index 0000000..54c545b
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/__init__.py
@@ -0,0 +1 @@
+# 稷下学宫模块
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/agents/memory_enhanced_agent.py b/modules/core-collaboration/src/jixia/agents/memory_enhanced_agent.py
new file mode 100644
index 0000000..125b8ab
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/agents/memory_enhanced_agent.py
@@ -0,0 +1,538 @@
+#!/usr/bin/env python3
+"""
+增强记忆的ADK智能体
+集成Vertex AI Memory Bank的稷下学宫智能体
+"""
+
+import asyncio
+from typing import Dict, List, Optional, Any
+from dataclasses import dataclass
+
+try:
+ from google.adk import Agent, InvocationContext
+ ADK_AVAILABLE = True
+except ImportError:
+ ADK_AVAILABLE = False
+ print("⚠️ Google ADK 未安装")
+ # 创建一个简单的 InvocationContext 替代类
+ class InvocationContext:
+ def __init__(self, *args, **kwargs):
+ pass
+
+from src.jixia.memory.base_memory_bank import MemoryBankProtocol
+from src.jixia.memory.factory import get_memory_backend
+from config.settings import get_google_genai_config
+
+
+@dataclass
+class BaxianPersonality:
+ """八仙智能体人格定义"""
+ name: str
+ chinese_name: str
+ hexagram: str # 对应的易经卦象
+ investment_style: str
+ personality_traits: List[str]
+ debate_approach: str
+ memory_focus: List[str] # 重点记忆的内容类型
+
+
+class MemoryEnhancedAgent:
+ """
+ 集成记忆银行的智能体
+ 为稷下学宫八仙提供持久化记忆能力
+ """
+
+ # 八仙人格定义
+ BAXIAN_PERSONALITIES = {
+ "tieguaili": BaxianPersonality(
+ name="tieguaili",
+ chinese_name="铁拐李",
+ hexagram="巽卦",
+ investment_style="逆向投资大师",
+ personality_traits=["逆向思维", "挑战共识", "独立判断", "风险敏感"],
+ debate_approach="质疑主流观点,提出反向思考",
+ memory_focus=["市场异常", "逆向案例", "风险警示", "反向策略"]
+ ),
+ "hanzhongli": BaxianPersonality(
+ name="hanzhongli",
+ chinese_name="汉钟离",
+ hexagram="离卦",
+ investment_style="平衡协调者",
+ personality_traits=["平衡思维", "综合分析", "稳健决策", "协调统筹"],
+ debate_approach="寻求各方观点的平衡点",
+ memory_focus=["平衡策略", "综合分析", "协调方案", "稳健建议"]
+ ),
+ "zhangguolao": BaxianPersonality(
+ name="zhangguolao",
+ chinese_name="张果老",
+ hexagram="兑卦",
+ investment_style="历史智慧者",
+ personality_traits=["博古通今", "历史视角", "经验丰富", "智慧深邃"],
+ debate_approach="引用历史案例和长期趋势",
+ memory_focus=["历史案例", "长期趋势", "周期规律", "经验教训"]
+ ),
+ "lancaihe": BaxianPersonality(
+ name="lancaihe",
+ chinese_name="蓝采和",
+ hexagram="坎卦",
+ investment_style="创新思维者",
+ personality_traits=["创新思维", "潜力发现", "灵活变通", "机会敏锐"],
+ debate_approach="发现新兴机会和创新角度",
+ memory_focus=["创新机会", "新兴趋势", "潜力发现", "灵活策略"]
+ ),
+ "hexiangu": BaxianPersonality(
+ name="hexiangu",
+ chinese_name="何仙姑",
+ hexagram="坤卦",
+ investment_style="直觉洞察者",
+ personality_traits=["直觉敏锐", "情感智慧", "温和坚定", "洞察人心"],
+ debate_approach="基于直觉和情感智慧的分析",
+ memory_focus=["市场情绪", "直觉判断", "情感因素", "人性洞察"]
+ ),
+ "lvdongbin": BaxianPersonality(
+ name="lvdongbin",
+ chinese_name="吕洞宾",
+ hexagram="乾卦",
+ investment_style="理性分析者",
+ personality_traits=["理性客观", "逻辑严密", "技术精通", "决策果断"],
+ debate_approach="基于数据和逻辑的严密分析",
+ memory_focus=["技术分析", "数据洞察", "逻辑推理", "理性决策"]
+ ),
+ "hanxiangzi": BaxianPersonality(
+ name="hanxiangzi",
+ chinese_name="韩湘子",
+ hexagram="艮卦",
+ investment_style="艺术感知者",
+ personality_traits=["艺术感知", "美学视角", "创意思维", "感性理解"],
+ debate_approach="从美学和艺术角度分析市场",
+ memory_focus=["美学趋势", "创意洞察", "感性分析", "艺术视角"]
+ ),
+ "caoguojiu": BaxianPersonality(
+ name="caoguojiu",
+ chinese_name="曹国舅",
+ hexagram="震卦",
+ investment_style="实务执行者",
+ personality_traits=["实务导向", "执行力强", "机构视角", "专业严谨"],
+ debate_approach="关注实际执行和机构操作",
+ memory_focus=["执行策略", "机构动向", "实务操作", "专业分析"]
+ )
+ }
+
+ def __init__(self, agent_name: str, memory_bank: MemoryBankProtocol | None = None):
+ """
+ 初始化记忆增强智能体
+
+ Args:
+ agent_name: 智能体名称 (如 "tieguaili")
+ memory_bank: 记忆银行实例
+ """
+ if not ADK_AVAILABLE:
+ raise ImportError("Google ADK 未安装,无法创建智能体")
+
+ if agent_name not in self.BAXIAN_PERSONALITIES:
+ raise ValueError(f"未知的智能体: {agent_name}")
+
+ self.agent_name = agent_name
+ self.personality = self.BAXIAN_PERSONALITIES[agent_name]
+ self.memory_bank = memory_bank
+ self.adk_agent = None
+
+ # 初始化ADK智能体
+ self._initialize_adk_agent()
+
+ def _initialize_adk_agent(self):
+ """初始化ADK智能体"""
+ try:
+ # 构建智能体系统提示
+ system_prompt = self._build_system_prompt()
+
+ # 创建ADK智能体
+ self.adk_agent = Agent(
+ name=self.personality.chinese_name,
+ model="gemini-2.0-flash-exp",
+ system_prompt=system_prompt,
+ temperature=0.7
+ )
+
+ print(f"✅ 创建ADK智能体: {self.personality.chinese_name}")
+
+ except Exception as e:
+ print(f"❌ 创建ADK智能体失败: {e}")
+ raise
+
+ def _build_system_prompt(self) -> str:
+ """构建智能体系统提示"""
+ return f"""
+# {self.personality.chinese_name} - {self.personality.investment_style}
+
+## 角色定位
+你是稷下学宫的{self.personality.chinese_name},对应易经{self.personality.hexagram},专精于{self.personality.investment_style}。
+
+## 人格特质
+{', '.join(self.personality.personality_traits)}
+
+## 辩论风格
+{self.personality.debate_approach}
+
+## 记忆重点
+你特别关注并记住以下类型的信息:
+{', '.join(self.personality.memory_focus)}
+
+## 行为准则
+1. 始终保持你的人格特质和投资风格
+2. 在辩论中体现你的独特视角
+3. 学习并记住重要的讨论内容
+4. 与其他七仙协作,但保持独立观点
+5. 基于历史记忆提供更有深度的分析
+
+## 记忆运用
+- 在回答前,会参考相关的历史记忆
+- 学习用户偏好,调整沟通风格
+- 记住成功的策略和失败的教训
+- 与其他智能体分享有价值的洞察
+
+请始终以{self.personality.chinese_name}的身份进行对话和分析。
+"""
+
+ async def get_memory_context(self, topic: str) -> str:
+ """
+ 获取与主题相关的记忆上下文
+
+ Args:
+ topic: 讨论主题
+
+ Returns:
+ 格式化的记忆上下文
+ """
+ if not self.memory_bank:
+ return ""
+
+ try:
+ context = await self.memory_bank.get_agent_context(
+ self.agent_name, topic
+ )
+ return context
+ except Exception as e:
+ print(f"⚠️ 获取记忆上下文失败: {e}")
+ return ""
+
+ async def respond_with_memory(self,
+ message: str,
+ topic: str = "",
+ context: InvocationContext = None) -> str:
+ """
+ 基于记忆增强的响应
+
+ Args:
+ message: 输入消息
+ topic: 讨论主题
+ context: ADK调用上下文
+
+ Returns:
+ 智能体响应
+ """
+ try:
+ # 获取记忆上下文
+ memory_context = await self.get_memory_context(topic)
+
+ # 构建增强的提示
+ enhanced_prompt = f"""
+{memory_context}
+
+## 当前讨论
+主题: {topic}
+消息: {message}
+
+请基于你的记忆和人格特质进行回应。
+"""
+
+ # 使用ADK生成响应
+ if context is None:
+ context = InvocationContext()
+
+ response_generator = self.adk_agent.run_async(
+ enhanced_prompt,
+ context=context
+ )
+
+ # 收集响应
+ response_parts = []
+ async for chunk in response_generator:
+ if hasattr(chunk, 'text'):
+ response_parts.append(chunk.text)
+ elif isinstance(chunk, str):
+ response_parts.append(chunk)
+
+ response = ''.join(response_parts)
+
+ # 保存对话记忆
+ if self.memory_bank and response:
+ await self._save_conversation_memory(message, response, topic)
+
+ return response
+
+ except Exception as e:
+ print(f"❌ 生成响应失败: {e}")
+ return f"抱歉,{self.personality.chinese_name}暂时无法回应。"
+
+ async def _save_conversation_memory(self,
+ user_message: str,
+ agent_response: str,
+ topic: str):
+ """
+ 保存对话记忆
+
+ Args:
+ user_message: 用户消息
+ agent_response: 智能体响应
+ topic: 讨论主题
+ """
+ try:
+ # 保存用户消息记忆
+ await self.memory_bank.add_memory(
+ agent_name=self.agent_name,
+ content=f"用户询问: {user_message}",
+ memory_type="conversation",
+ debate_topic=topic,
+ metadata={"role": "user"}
+ )
+
+ # 保存智能体响应记忆
+ await self.memory_bank.add_memory(
+ agent_name=self.agent_name,
+ content=f"我的回应: {agent_response}",
+ memory_type="conversation",
+ debate_topic=topic,
+ metadata={"role": "assistant"}
+ )
+
+ except Exception as e:
+ print(f"⚠️ 保存对话记忆失败: {e}")
+
+ async def learn_preference(self, preference: str, topic: str = ""):
+ """
+ 学习用户偏好
+
+ Args:
+ preference: 偏好描述
+ topic: 相关主题
+ """
+ if not self.memory_bank:
+ return
+
+ try:
+ await self.memory_bank.add_memory(
+ agent_name=self.agent_name,
+ content=f"用户偏好: {preference}",
+ memory_type="preference",
+ debate_topic=topic,
+ metadata={"learned_from": "user_feedback"}
+ )
+
+ print(f"✅ {self.personality.chinese_name} 学习了新偏好")
+
+ except Exception as e:
+ print(f"⚠️ 学习偏好失败: {e}")
+
+ async def save_strategy_insight(self, insight: str, topic: str = ""):
+ """
+ 保存策略洞察
+
+ Args:
+ insight: 策略洞察
+ topic: 相关主题
+ """
+ if not self.memory_bank:
+ return
+
+ try:
+ await self.memory_bank.add_memory(
+ agent_name=self.agent_name,
+ content=f"策略洞察: {insight}",
+ memory_type="strategy",
+ debate_topic=topic,
+ metadata={"insight_type": "strategy"}
+ )
+
+ print(f"✅ {self.personality.chinese_name} 保存了策略洞察")
+
+ except Exception as e:
+ print(f"⚠️ 保存策略洞察失败: {e}")
+
+
+class BaxianMemoryCouncil:
+ """
+ 八仙记忆议会
+ 管理所有八仙智能体的记忆增强功能
+ """
+
+ def __init__(self, memory_bank: MemoryBankProtocol | None = None):
+ """
+ 初始化八仙记忆议会
+
+ Args:
+ memory_bank: 记忆银行实例
+ """
+ self.memory_bank = memory_bank
+ self.agents = {}
+
+ # 初始化所有八仙智能体
+ self._initialize_agents()
+
+ def _initialize_agents(self):
+ """初始化所有八仙智能体"""
+ for agent_name in MemoryEnhancedAgent.BAXIAN_PERSONALITIES.keys():
+ try:
+ agent = MemoryEnhancedAgent(agent_name, self.memory_bank)
+ self.agents[agent_name] = agent
+ print(f"✅ 初始化 {agent.personality.chinese_name}")
+ except Exception as e:
+ print(f"❌ 初始化 {agent_name} 失败: {e}")
+
+ async def conduct_memory_debate(self,
+ topic: str,
+ participants: List[str] = None,
+ rounds: int = 3) -> Dict[str, Any]:
+ """
+ 进行记忆增强的辩论
+
+ Args:
+ topic: 辩论主题
+ participants: 参与者列表,None表示所有八仙
+ rounds: 辩论轮数
+
+ Returns:
+ 辩论结果
+ """
+ if participants is None:
+ participants = list(self.agents.keys())
+
+ conversation_history = []
+ context = InvocationContext()
+
+ print(f"🏛️ 稷下学宫八仙论道开始: {topic}")
+
+ for round_num in range(rounds):
+ print(f"\n--- 第 {round_num + 1} 轮 ---")
+
+ for agent_name in participants:
+ if agent_name not in self.agents:
+ continue
+
+ agent = self.agents[agent_name]
+
+ # 构建当前轮次的提示
+ round_prompt = f"""
+轮次: {round_num + 1}/{rounds}
+主题: {topic}
+
+请基于你的记忆和人格特质,对此主题发表观点。
+如果这不是第一轮,请考虑其他仙友的观点并做出回应。
+"""
+
+ # 获取响应
+ response = await agent.respond_with_memory(
+ round_prompt, topic, context
+ )
+
+ # 记录对话历史
+ conversation_history.append({
+ "round": round_num + 1,
+ "agent": agent_name,
+ "chinese_name": agent.personality.chinese_name,
+ "content": response
+ })
+
+ print(f"{agent.personality.chinese_name}: {response[:100]}...")
+
+ # 保存辩论会话到记忆银行
+ if self.memory_bank:
+ await self.memory_bank.save_debate_session(
+ debate_topic=topic,
+ participants=participants,
+ conversation_history=conversation_history
+ )
+
+ return {
+ "topic": topic,
+ "participants": participants,
+ "rounds": rounds,
+ "conversation_history": conversation_history,
+ "total_exchanges": len(conversation_history)
+ }
+
+ async def get_collective_memory_summary(self, topic: str) -> str:
+ """
+ 获取集体记忆摘要
+
+ Args:
+ topic: 主题
+
+ Returns:
+ 集体记忆摘要
+ """
+ if not self.memory_bank:
+ return "记忆银行未启用"
+
+ summaries = []
+
+ for agent_name, agent in self.agents.items():
+ context = await agent.get_memory_context(topic)
+ if context and context.strip():
+ summaries.append(context)
+
+ if summaries:
+ return f"# 稷下学宫集体记忆摘要\n\n" + "\n\n".join(summaries)
+ else:
+ return "暂无相关集体记忆"
+
+
+# 便捷函数
+async def create_memory_enhanced_council() -> BaxianMemoryCouncil:
+ """
+ 创建记忆增强的八仙议会
+
+ Returns:
+ 配置好的BaxianMemoryCouncil实例
+ """
+ try:
+ # 初始化记忆银行
+ memory_bank = get_memory_backend()
+
+ # 创建八仙议会
+ council = BaxianMemoryCouncil(memory_bank)
+
+ print("🏛️ 稷下学宫记忆增强议会创建完成")
+ return council
+
+ except Exception as e:
+ print(f"❌ 创建记忆增强议会失败: {e}")
+ # 创建无记忆版本
+ return BaxianMemoryCouncil(None)
+
+
+if __name__ == "__main__":
+ async def test_memory_enhanced_agent():
+ """测试记忆增强智能体"""
+ try:
+ # 创建记忆增强议会
+ council = await create_memory_enhanced_council()
+
+ # 进行记忆增强辩论
+ result = await council.conduct_memory_debate(
+ topic="NVIDIA股票投资分析",
+ participants=["tieguaili", "lvdongbin", "hexiangu"],
+ rounds=2
+ )
+
+ print(f"\n🏛️ 辩论完成,共 {result['total_exchanges']} 次发言")
+
+ # 获取集体记忆摘要
+ summary = await council.get_collective_memory_summary("NVIDIA股票投资分析")
+ print(f"\n📚 集体记忆摘要:\n{summary}")
+
+ except Exception as e:
+ print(f"❌ 测试失败: {e}")
+
+ # 运行测试
+ asyncio.run(test_memory_enhanced_agent())
diff --git a/modules/core-collaboration/src/jixia/config/immortal_api_config.json b/modules/core-collaboration/src/jixia/config/immortal_api_config.json
new file mode 100644
index 0000000..4349af0
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/config/immortal_api_config.json
@@ -0,0 +1,216 @@
+{
+ "immortals": {
+ "吕洞宾": {
+ "title": "主力剑仙",
+ "specialty": "综合分析与决策",
+ "description": "作为八仙之首,负责整体投资策略制定,需要最快最准确的数据",
+ "preferred_apis": {
+ "stock_quote": "alpha_vantage",
+ "company_overview": "alpha_vantage",
+ "market_movers": "yahoo_finance_15",
+ "market_news": "yahoo_finance_15"
+ },
+ "data_priority": ["实时价格", "公司基本面", "市场动态"],
+ "api_weight": 0.15
+ },
+ "何仙姑": {
+ "title": "风控专家",
+ "specialty": "风险管理与合规",
+ "description": "专注风险评估和投资组合管理,需要稳定可靠的数据源",
+ "preferred_apis": {
+ "stock_quote": "yahoo_finance_15",
+ "company_overview": "seeking_alpha",
+ "market_movers": "webull",
+ "market_news": "seeking_alpha"
+ },
+ "data_priority": ["波动率", "风险指标", "合规信息"],
+ "api_weight": 0.12
+ },
+ "张果老": {
+ "title": "技术分析师",
+ "specialty": "技术指标与图表分析",
+ "description": "专精技术分析,需要详细的价格和成交量数据",
+ "preferred_apis": {
+ "stock_quote": "webull",
+ "company_overview": "alpha_vantage",
+ "market_movers": "yahoo_finance_15",
+ "market_news": "yahoo_finance_15"
+ },
+ "data_priority": ["技术指标", "成交量", "价格走势"],
+ "api_weight": 0.13
+ },
+ "韩湘子": {
+ "title": "基本面研究员",
+ "specialty": "财务分析与估值",
+ "description": "深度研究公司财务状况和内在价值",
+ "preferred_apis": {
+ "stock_quote": "alpha_vantage",
+ "company_overview": "seeking_alpha",
+ "market_movers": "webull",
+ "market_news": "seeking_alpha"
+ },
+ "data_priority": ["财务报表", "估值指标", "盈利预测"],
+ "api_weight": 0.14
+ },
+ "汉钟离": {
+ "title": "量化专家",
+ "specialty": "数据挖掘与算法交易",
+ "description": "运用数学模型和算法进行量化分析",
+ "preferred_apis": {
+ "stock_quote": "yahoo_finance_15",
+ "company_overview": "alpha_vantage",
+ "market_movers": "yahoo_finance_15",
+ "market_news": "yahoo_finance_15"
+ },
+ "data_priority": ["历史数据", "统计指标", "相关性分析"],
+ "api_weight": 0.13
+ },
+ "蓝采和": {
+ "title": "情绪分析师",
+ "specialty": "市场情绪与舆情监控",
+ "description": "分析市场情绪和投资者行为模式",
+ "preferred_apis": {
+ "stock_quote": "webull",
+ "company_overview": "seeking_alpha",
+ "market_movers": "webull",
+ "market_news": "seeking_alpha"
+ },
+ "data_priority": ["新闻情绪", "社交媒体", "投资者情绪"],
+ "api_weight": 0.11
+ },
+ "曹国舅": {
+ "title": "宏观分析师",
+ "specialty": "宏观经济与政策分析",
+ "description": "关注宏观经济环境和政策影响",
+ "preferred_apis": {
+ "stock_quote": "seeking_alpha",
+ "company_overview": "seeking_alpha",
+ "market_movers": "yahoo_finance_15",
+ "market_news": "seeking_alpha"
+ },
+ "data_priority": ["宏观数据", "政策解读", "行业趋势"],
+ "api_weight": 0.12
+ },
+ "铁拐李": {
+ "title": "逆向投资专家",
+ "specialty": "价值发现与逆向思维",
+ "description": "寻找被低估的投资机会,逆向思考市场",
+ "preferred_apis": {
+ "stock_quote": "alpha_vantage",
+ "company_overview": "alpha_vantage",
+ "market_movers": "webull",
+ "market_news": "yahoo_finance_15"
+ },
+ "data_priority": ["估值偏差", "市场异常", "价值机会"],
+ "api_weight": 0.10
+ }
+ },
+ "api_configurations": {
+ "alpha_vantage": {
+ "name": "Alpha Vantage",
+ "tier": "premium",
+ "strengths": ["实时数据", "财务数据", "技术指标"],
+ "rate_limits": {
+ "per_minute": 500,
+ "per_month": 500000
+ },
+ "reliability_score": 0.95,
+ "response_time_avg": 0.8,
+ "data_quality": "high",
+ "cost_per_call": 0.001
+ },
+ "yahoo_finance_15": {
+ "name": "Yahoo Finance 15",
+ "tier": "standard",
+ "strengths": ["市场数据", "新闻资讯", "实时报价"],
+ "rate_limits": {
+ "per_minute": 500,
+ "per_month": 500000
+ },
+ "reliability_score": 0.90,
+ "response_time_avg": 1.2,
+ "data_quality": "medium",
+ "cost_per_call": 0.0005
+ },
+ "webull": {
+ "name": "Webull",
+ "tier": "premium",
+ "strengths": ["搜索功能", "活跃数据", "技术分析"],
+ "rate_limits": {
+ "per_minute": 500,
+ "per_month": 500000
+ },
+ "reliability_score": 0.88,
+ "response_time_avg": 1.0,
+ "data_quality": "high",
+ "cost_per_call": 0.0008
+ },
+ "seeking_alpha": {
+ "name": "Seeking Alpha",
+ "tier": "standard",
+ "strengths": ["分析报告", "新闻资讯", "专业观点"],
+ "rate_limits": {
+ "per_minute": 500,
+ "per_month": 500000
+ },
+ "reliability_score": 0.85,
+ "response_time_avg": 1.5,
+ "data_quality": "medium",
+ "cost_per_call": 0.0006
+ }
+ },
+ "load_balancing_strategies": {
+ "round_robin": {
+ "description": "轮询分配,确保负载均匀分布",
+ "enabled": true,
+ "weight_based": true
+ },
+ "health_aware": {
+ "description": "基于API健康状态的智能分配",
+ "enabled": true,
+ "health_check_interval": 300
+ },
+ "performance_based": {
+ "description": "基于响应时间的动态分配",
+ "enabled": true,
+ "response_time_threshold": 2.0
+ },
+ "cost_optimization": {
+ "description": "成本优化策略,优先使用低成本API",
+ "enabled": false,
+ "cost_threshold": 0.001
+ }
+ },
+ "failover_matrix": {
+ "alpha_vantage": ["webull", "yahoo_finance_15", "seeking_alpha"],
+ "yahoo_finance_15": ["webull", "alpha_vantage", "seeking_alpha"],
+ "webull": ["alpha_vantage", "yahoo_finance_15", "seeking_alpha"],
+ "seeking_alpha": ["yahoo_finance_15", "alpha_vantage", "webull"]
+ },
+ "cache_settings": {
+ "enabled": true,
+ "ttl_seconds": 300,
+ "max_entries": 1000,
+ "cache_strategies": {
+ "stock_quote": 60,
+ "company_overview": 3600,
+ "market_movers": 300,
+ "market_news": 1800
+ }
+ },
+ "monitoring": {
+ "enabled": true,
+ "metrics": [
+ "api_call_count",
+ "response_time",
+ "error_rate",
+ "cache_hit_rate",
+ "load_distribution"
+ ],
+ "alerts": {
+ "high_error_rate": 0.1,
+ "slow_response_time": 3.0,
+ "api_unavailable": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/coordination/ai_team_collaboration.py b/modules/core-collaboration/src/jixia/coordination/ai_team_collaboration.py
new file mode 100644
index 0000000..f4bee9a
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/coordination/ai_team_collaboration.py
@@ -0,0 +1,680 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+四AI团队协作通道系统
+专为Qwen、Claude、Gemini、RovoDev四个AI设计的协作和通信平台
+"""
+
+import asyncio
+import json
+import uuid
+from typing import Dict, List, Any, Optional, Callable, Set
+from dataclasses import dataclass, field
+from enum import Enum
+from datetime import datetime, timedelta
+import logging
+from pathlib import Path
+
+class AIRole(Enum):
+ """AI角色定义"""
+ QWEN = "Qwen" # 架构设计师
+ CLAUDE = "Claude" # 核心开发工程师
+ GEMINI = "Gemini" # 测试验证专家
+ ROVODEV = "RovoDev" # 项目整合专家
+
+class CollaborationType(Enum):
+ """协作类型"""
+ MAIN_CHANNEL = "主协作频道" # 主要协作讨论
+ ARCHITECTURE = "架构设计" # 架构相关讨论
+ IMPLEMENTATION = "代码实现" # 实现相关讨论
+ TESTING = "测试验证" # 测试相关讨论
+ INTEGRATION = "项目整合" # 整合相关讨论
+ CROSS_REVIEW = "交叉评审" # 跨角色评审
+ EMERGENCY = "紧急协调" # 紧急问题处理
+
+class MessageType(Enum):
+ """消息类型"""
+ PROPOSAL = "提案" # 提出建议
+ QUESTION = "询问" # 提出问题
+ ANSWER = "回答" # 回答问题
+ REVIEW = "评审" # 评审反馈
+ DECISION = "决策" # 做出决策
+ UPDATE = "更新" # 状态更新
+ ALERT = "警报" # 警报通知
+ HANDOFF = "交接" # 工作交接
+
+class WorkPhase(Enum):
+ """工作阶段"""
+ PLANNING = "规划阶段"
+ DESIGN = "设计阶段"
+ IMPLEMENTATION = "实现阶段"
+ TESTING = "测试阶段"
+ INTEGRATION = "整合阶段"
+ DELIVERY = "交付阶段"
+
+@dataclass
+class AIMessage:
+ """AI消息"""
+ id: str
+ sender: AIRole
+ receiver: Optional[AIRole] # None表示广播
+ content: str
+ message_type: MessageType
+ collaboration_type: CollaborationType
+ timestamp: datetime
+ work_phase: WorkPhase
+ priority: int = 1 # 1-5, 5最高
+ tags: List[str] = field(default_factory=list)
+ attachments: List[str] = field(default_factory=list) # 文件路径
+ references: List[str] = field(default_factory=list) # 引用的消息ID
+ metadata: Dict[str, Any] = field(default_factory=dict)
+
+@dataclass
+class CollaborationChannel:
+ """协作频道"""
+ id: str
+ name: str
+ channel_type: CollaborationType
+ description: str
+ participants: Set[AIRole]
+ moderator: AIRole
+ is_active: bool = True
+ created_at: datetime = field(default_factory=datetime.now)
+ last_activity: datetime = field(default_factory=datetime.now)
+ message_history: List[AIMessage] = field(default_factory=list)
+ settings: Dict[str, Any] = field(default_factory=dict)
+
+@dataclass
+class WorkflowRule:
+ """工作流规则"""
+ id: str
+ name: str
+ description: str
+ trigger_phase: WorkPhase
+ trigger_conditions: Dict[str, Any]
+ action: str
+ target_ai: Optional[AIRole]
+ is_active: bool = True
+
+class AITeamCollaboration:
+ """四AI团队协作系统"""
+
+ def __init__(self, project_root: Path = None):
+ self.project_root = project_root or Path("/home/ben/github/liurenchaxin")
+ self.channels: Dict[str, CollaborationChannel] = {}
+ self.workflow_rules: Dict[str, WorkflowRule] = {}
+ self.current_phase: WorkPhase = WorkPhase.PLANNING
+ self.ai_status: Dict[AIRole, Dict[str, Any]] = {}
+ self.message_queue: List[AIMessage] = []
+ self.event_handlers: Dict[str, List[Callable]] = {}
+ self.logger = logging.getLogger(__name__)
+
+ # 初始化AI状态
+ self._initialize_ai_status()
+
+ # 初始化协作频道
+ self._initialize_channels()
+
+ # 初始化工作流规则
+ self._initialize_workflow_rules()
+
+ def _initialize_ai_status(self):
+ """初始化AI状态"""
+ self.ai_status = {
+ AIRole.QWEN: {
+ "role": "架构设计师",
+ "specialty": "系统架构、技术选型、接口设计",
+ "current_task": "OpenBB集成架构设计",
+ "status": "ready",
+ "workload": 0,
+ "expertise_areas": ["架构设计", "系统集成", "性能优化"]
+ },
+ AIRole.CLAUDE: {
+ "role": "核心开发工程师",
+ "specialty": "代码实现、API开发、界面优化",
+ "current_task": "等待架构设计完成",
+ "status": "waiting",
+ "workload": 0,
+ "expertise_areas": ["Python开发", "Streamlit", "API集成"]
+ },
+ AIRole.GEMINI: {
+ "role": "测试验证专家",
+ "specialty": "功能测试、性能测试、质量保证",
+ "current_task": "制定测试策略",
+ "status": "ready",
+ "workload": 0,
+ "expertise_areas": ["自动化测试", "性能测试", "质量保证"]
+ },
+ AIRole.ROVODEV: {
+ "role": "项目整合专家",
+ "specialty": "项目管理、文档整合、协调统筹",
+ "current_task": "项目框架搭建",
+ "status": "active",
+ "workload": 0,
+ "expertise_areas": ["项目管理", "文档编写", "团队协调"]
+ }
+ }
+
+ def _initialize_channels(self):
+ """初始化协作频道"""
+ channels_config = [
+ {
+ "id": "main_collaboration",
+ "name": "OpenBB集成主协作频道",
+ "channel_type": CollaborationType.MAIN_CHANNEL,
+ "description": "四AI主要协作讨论频道",
+ "participants": {AIRole.QWEN, AIRole.CLAUDE, AIRole.GEMINI, AIRole.ROVODEV},
+ "moderator": AIRole.ROVODEV,
+ "settings": {
+ "allow_broadcast": True,
+ "require_acknowledgment": True,
+ "auto_archive": False
+ }
+ },
+ {
+ "id": "architecture_design",
+ "name": "架构设计频道",
+ "channel_type": CollaborationType.ARCHITECTURE,
+ "description": "架构设计相关讨论",
+ "participants": {AIRole.QWEN, AIRole.CLAUDE, AIRole.ROVODEV},
+ "moderator": AIRole.QWEN,
+ "settings": {
+ "design_reviews": True,
+ "version_control": True
+ }
+ },
+ {
+ "id": "code_implementation",
+ "name": "代码实现频道",
+ "channel_type": CollaborationType.IMPLEMENTATION,
+ "description": "代码实现和开发讨论",
+ "participants": {AIRole.CLAUDE, AIRole.QWEN, AIRole.GEMINI},
+ "moderator": AIRole.CLAUDE,
+ "settings": {
+ "code_reviews": True,
+ "continuous_integration": True
+ }
+ },
+ {
+ "id": "testing_validation",
+ "name": "测试验证频道",
+ "channel_type": CollaborationType.TESTING,
+ "description": "测试策略和验证讨论",
+ "participants": {AIRole.GEMINI, AIRole.CLAUDE, AIRole.ROVODEV},
+ "moderator": AIRole.GEMINI,
+ "settings": {
+ "test_automation": True,
+ "quality_gates": True
+ }
+ },
+ {
+ "id": "project_integration",
+ "name": "项目整合频道",
+ "channel_type": CollaborationType.INTEGRATION,
+ "description": "项目整合和文档管理",
+ "participants": {AIRole.ROVODEV, AIRole.QWEN, AIRole.CLAUDE, AIRole.GEMINI},
+ "moderator": AIRole.ROVODEV,
+ "settings": {
+ "documentation_sync": True,
+ "release_management": True
+ }
+ },
+ {
+ "id": "cross_review",
+ "name": "交叉评审频道",
+ "channel_type": CollaborationType.CROSS_REVIEW,
+ "description": "跨角色工作评审",
+ "participants": {AIRole.QWEN, AIRole.CLAUDE, AIRole.GEMINI, AIRole.ROVODEV},
+ "moderator": AIRole.ROVODEV,
+ "settings": {
+ "peer_review": True,
+ "quality_assurance": True
+ }
+ },
+ {
+ "id": "emergency_coordination",
+ "name": "紧急协调频道",
+ "channel_type": CollaborationType.EMERGENCY,
+ "description": "紧急问题处理和快速响应",
+ "participants": {AIRole.QWEN, AIRole.CLAUDE, AIRole.GEMINI, AIRole.ROVODEV},
+ "moderator": AIRole.ROVODEV,
+ "settings": {
+ "high_priority": True,
+ "instant_notification": True,
+ "escalation_rules": True
+ }
+ }
+ ]
+
+ for config in channels_config:
+ channel = CollaborationChannel(**config)
+ self.channels[channel.id] = channel
+
+ def _initialize_workflow_rules(self):
+ """初始化工作流规则"""
+ rules_config = [
+ {
+ "id": "architecture_to_implementation",
+ "name": "架构完成通知实现开始",
+ "description": "当架构设计完成时,通知Claude开始实现",
+ "trigger_phase": WorkPhase.DESIGN,
+ "trigger_conditions": {"status": "architecture_complete"},
+ "action": "notify_implementation_start",
+ "target_ai": AIRole.CLAUDE
+ },
+ {
+ "id": "implementation_to_testing",
+ "name": "实现完成通知测试开始",
+ "description": "当代码实现完成时,通知Gemini开始测试",
+ "trigger_phase": WorkPhase.IMPLEMENTATION,
+ "trigger_conditions": {"status": "implementation_complete"},
+ "action": "notify_testing_start",
+ "target_ai": AIRole.GEMINI
+ },
+ {
+ "id": "testing_to_integration",
+ "name": "测试完成通知整合开始",
+ "description": "当测试验证完成时,通知RovoDev开始整合",
+ "trigger_phase": WorkPhase.TESTING,
+ "trigger_conditions": {"status": "testing_complete"},
+ "action": "notify_integration_start",
+ "target_ai": AIRole.ROVODEV
+ }
+ ]
+
+ for config in rules_config:
+ rule = WorkflowRule(**config)
+ self.workflow_rules[rule.id] = rule
+
+ async def send_message(self,
+ sender: AIRole,
+ content: str,
+ message_type: MessageType,
+ channel_id: str,
+ receiver: Optional[AIRole] = None,
+ priority: int = 1,
+ attachments: List[str] = None,
+ tags: List[str] = None) -> str:
+ """发送消息"""
+
+ if channel_id not in self.channels:
+ raise ValueError(f"频道 {channel_id} 不存在")
+
+ channel = self.channels[channel_id]
+
+ # 验证发送者权限
+ if sender not in channel.participants:
+ raise PermissionError(f"{sender.value} 不在频道 {channel.name} 中")
+
+ # 创建消息
+ message = AIMessage(
+ id=str(uuid.uuid4()),
+ sender=sender,
+ receiver=receiver,
+ content=content,
+ message_type=message_type,
+ collaboration_type=channel.channel_type,
+ timestamp=datetime.now(),
+ work_phase=self.current_phase,
+ priority=priority,
+ attachments=attachments or [],
+ tags=tags or []
+ )
+
+ # 添加到频道历史
+ channel.message_history.append(message)
+ channel.last_activity = datetime.now()
+
+ # 添加到消息队列
+ self.message_queue.append(message)
+
+ # 触发事件处理
+ await self._trigger_event("message_sent", {
+ "message": message,
+ "channel": channel
+ })
+
+ # 记录日志
+ self.logger.info(f"[{channel.name}] {sender.value} -> {receiver.value if receiver else 'ALL'}: {content[:50]}...")
+
+ return message.id
+
+ async def broadcast_message(self,
+ sender: AIRole,
+ content: str,
+ message_type: MessageType,
+ channel_id: str,
+ priority: int = 1,
+ tags: List[str] = None) -> str:
+ """广播消息到频道所有参与者"""
+ return await self.send_message(
+ sender=sender,
+ content=content,
+ message_type=message_type,
+ channel_id=channel_id,
+ receiver=None, # None表示广播
+ priority=priority,
+ tags=tags
+ )
+
+ async def request_review(self,
+ sender: AIRole,
+ content: str,
+ reviewers: List[AIRole],
+ attachments: List[str] = None) -> str:
+ """请求评审"""
+
+ # 发送到交叉评审频道
+ message_id = await self.send_message(
+ sender=sender,
+ content=f"📋 评审请求: {content}",
+ message_type=MessageType.REVIEW,
+ channel_id="cross_review",
+ priority=3,
+ attachments=attachments,
+ tags=["review_request"] + [f"reviewer_{reviewer.value}" for reviewer in reviewers]
+ )
+
+ # 通知指定评审者
+ for reviewer in reviewers:
+ await self.send_message(
+ sender=AIRole.ROVODEV, # 系统通知
+ content=f"🔔 您有新的评审请求来自 {sender.value},请查看交叉评审频道",
+ message_type=MessageType.ALERT,
+ channel_id="main_collaboration",
+ receiver=reviewer,
+ priority=3,
+ tags=["review_notification", f"from_{sender.value}", f"message_ref_{message_id}"]
+ )
+
+ return message_id
+
+ async def handoff_work(self,
+ from_ai: AIRole,
+ to_ai: AIRole,
+ task_description: str,
+ deliverables: List[str],
+ notes: str = "") -> str:
+ """工作交接"""
+
+ content = f"""
+🔄 **工作交接**
+**从**: {from_ai.value}
+**到**: {to_ai.value}
+**任务**: {task_description}
+**交付物**: {', '.join(deliverables)}
+**备注**: {notes}
+ """
+
+ message_id = await self.send_message(
+ sender=from_ai,
+ content=content.strip(),
+ message_type=MessageType.HANDOFF,
+ channel_id="main_collaboration",
+ receiver=to_ai,
+ priority=4,
+ attachments=deliverables,
+ tags=["handoff", f"from_{from_ai.value}", f"to_{to_ai.value}"]
+ )
+
+ # 更新AI状态
+ self.ai_status[from_ai]["status"] = "completed_handoff"
+ self.ai_status[to_ai]["status"] = "received_handoff"
+ self.ai_status[to_ai]["current_task"] = task_description
+
+ return message_id
+
+ async def escalate_issue(self,
+ reporter: AIRole,
+ issue_description: str,
+ severity: str = "medium") -> str:
+ """问题升级"""
+
+ content = f"""
+🚨 **问题升级**
+**报告者**: {reporter.value}
+**严重程度**: {severity}
+**问题描述**: {issue_description}
+**时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+ """
+
+ priority_map = {"low": 2, "medium": 3, "high": 4, "critical": 5}
+ priority = priority_map.get(severity, 3)
+
+ return await self.send_message(
+ sender=reporter,
+ content=content.strip(),
+ message_type=MessageType.ALERT,
+ channel_id="emergency_coordination",
+ priority=priority,
+ tags=["escalation", f"severity_{severity}"]
+ )
+
+ def get_channel_summary(self, channel_id: str) -> Dict[str, Any]:
+ """获取频道摘要"""
+ if channel_id not in self.channels:
+ return {}
+
+ channel = self.channels[channel_id]
+ recent_messages = channel.message_history[-10:] # 最近10条消息
+
+ return {
+ "channel_name": channel.name,
+ "channel_type": channel.channel_type.value,
+ "participants": [ai.value for ai in channel.participants],
+ "total_messages": len(channel.message_history),
+ "last_activity": channel.last_activity.isoformat(),
+ "recent_messages": [
+ {
+ "sender": msg.sender.value,
+ "content": msg.content[:100] + "..." if len(msg.content) > 100 else msg.content,
+ "timestamp": msg.timestamp.isoformat(),
+ "type": msg.message_type.value
+ }
+ for msg in recent_messages
+ ]
+ }
+
+ def get_ai_dashboard(self, ai_role: AIRole) -> Dict[str, Any]:
+ """获取AI工作仪表板"""
+ status = self.ai_status[ai_role]
+
+ # 获取相关消息
+ relevant_messages = []
+ for channel in self.channels.values():
+ if ai_role in channel.participants:
+ for msg in channel.message_history[-5:]: # 每个频道最近5条
+ if msg.receiver == ai_role or msg.receiver is None:
+ relevant_messages.append({
+ "channel": channel.name,
+ "sender": msg.sender.value,
+ "content": msg.content[:100] + "..." if len(msg.content) > 100 else msg.content,
+ "timestamp": msg.timestamp.isoformat(),
+ "priority": msg.priority
+ })
+
+ # 按优先级和时间排序
+ relevant_messages.sort(key=lambda x: (x["priority"], x["timestamp"]), reverse=True)
+
+ return {
+ "ai_role": ai_role.value,
+ "status": status,
+ "current_phase": self.current_phase.value,
+ "active_channels": [
+ channel.name for channel in self.channels.values()
+ if ai_role in channel.participants and channel.is_active
+ ],
+ "recent_messages": relevant_messages[:10], # 最多10条
+ "pending_tasks": self._get_pending_tasks(ai_role),
+ "collaboration_stats": self._get_collaboration_stats(ai_role)
+ }
+
+ def _get_pending_tasks(self, ai_role: AIRole) -> List[Dict[str, Any]]:
+ """获取待处理任务"""
+ tasks = []
+
+ # 扫描所有频道中针对该AI的消息
+ for channel in self.channels.values():
+ if ai_role in channel.participants:
+ for msg in channel.message_history:
+ if (msg.receiver == ai_role and
+ msg.message_type in [MessageType.QUESTION, MessageType.REVIEW, MessageType.HANDOFF] and
+ not self._is_task_completed(msg.id)):
+ tasks.append({
+ "task_id": msg.id,
+ "type": msg.message_type.value,
+ "description": msg.content[:100] + "..." if len(msg.content) > 100 else msg.content,
+ "from": msg.sender.value,
+ "channel": channel.name,
+ "priority": msg.priority,
+ "created": msg.timestamp.isoformat()
+ })
+
+ return sorted(tasks, key=lambda x: x["priority"], reverse=True)
+
+ def _get_collaboration_stats(self, ai_role: AIRole) -> Dict[str, Any]:
+ """获取协作统计"""
+ total_messages = 0
+ messages_sent = 0
+ messages_received = 0
+
+ for channel in self.channels.values():
+ if ai_role in channel.participants:
+ for msg in channel.message_history:
+ total_messages += 1
+ if msg.sender == ai_role:
+ messages_sent += 1
+ elif msg.receiver == ai_role or msg.receiver is None:
+ messages_received += 1
+
+ return {
+ "total_messages": total_messages,
+ "messages_sent": messages_sent,
+ "messages_received": messages_received,
+ "active_channels": len([c for c in self.channels.values() if ai_role in c.participants]),
+ "collaboration_score": min(100, (messages_sent + messages_received) * 2) # 简单计分
+ }
+
+ def _is_task_completed(self, task_id: str) -> bool:
+ """检查任务是否已完成"""
+ # 简单实现:检查是否有回复消息引用了该任务
+ for channel in self.channels.values():
+ for msg in channel.message_history:
+ if task_id in msg.references:
+ return True
+ return False
+
+ async def _trigger_event(self, event_type: str, event_data: Dict[str, Any]):
+ """触发事件处理"""
+ if event_type in self.event_handlers:
+ for handler in self.event_handlers[event_type]:
+ try:
+ await handler(event_data)
+ except Exception as e:
+ self.logger.error(f"事件处理器错误: {e}")
+
+ def add_event_handler(self, event_type: str, handler: Callable):
+ """添加事件处理器"""
+ if event_type not in self.event_handlers:
+ self.event_handlers[event_type] = []
+ self.event_handlers[event_type].append(handler)
+
+ async def advance_phase(self, new_phase: WorkPhase):
+ """推进工作阶段"""
+ old_phase = self.current_phase
+ self.current_phase = new_phase
+
+ # 广播阶段变更
+ await self.broadcast_message(
+ sender=AIRole.ROVODEV,
+ content=f"📈 项目阶段变更: {old_phase.value} → {new_phase.value}",
+ message_type=MessageType.UPDATE,
+ channel_id="main_collaboration",
+ priority=4,
+ tags=["phase_change"]
+ )
+
+ # 触发工作流规则
+ await self._check_workflow_rules()
+
+ async def _check_workflow_rules(self):
+ """检查并执行工作流规则"""
+ for rule in self.workflow_rules.values():
+ if rule.is_active and rule.trigger_phase == self.current_phase:
+ await self._execute_workflow_action(rule)
+
+ async def _execute_workflow_action(self, rule: WorkflowRule):
+ """执行工作流动作"""
+ if rule.action == "notify_implementation_start":
+ await self.send_message(
+ sender=AIRole.ROVODEV,
+ content=f"🚀 架构设计已完成,请开始代码实现工作。参考架构文档进行开发。",
+ message_type=MessageType.UPDATE,
+ channel_id="code_implementation",
+ receiver=rule.target_ai,
+ priority=3
+ )
+ elif rule.action == "notify_testing_start":
+ await self.send_message(
+ sender=AIRole.ROVODEV,
+ content=f"✅ 代码实现已完成,请开始测试验证工作。",
+ message_type=MessageType.UPDATE,
+ channel_id="testing_validation",
+ receiver=rule.target_ai,
+ priority=3
+ )
+ elif rule.action == "notify_integration_start":
+ await self.send_message(
+ sender=AIRole.ROVODEV,
+ content=f"🎯 测试验证已完成,请开始项目整合工作。",
+ message_type=MessageType.UPDATE,
+ channel_id="project_integration",
+ receiver=rule.target_ai,
+ priority=3
+ )
+
+# 使用示例
+async def demo_collaboration():
+ """演示协作系统使用"""
+ collab = AITeamCollaboration()
+
+ # Qwen发起架构讨论
+ await collab.send_message(
+ sender=AIRole.QWEN,
+ content="大家好!我已经完成了OpenBB集成的初步架构设计,请大家review一下设计文档。",
+ message_type=MessageType.PROPOSAL,
+ channel_id="main_collaboration",
+ priority=3,
+ attachments=["docs/architecture/openbb_integration_architecture.md"],
+ tags=["architecture", "review_request"]
+ )
+
+ # Claude回应
+ await collab.send_message(
+ sender=AIRole.CLAUDE,
+ content="架构设计看起来很不错!我有几个实现层面的问题...",
+ message_type=MessageType.QUESTION,
+ channel_id="architecture_design",
+ receiver=AIRole.QWEN,
+ priority=2
+ )
+
+ # 工作交接
+ await collab.handoff_work(
+ from_ai=AIRole.QWEN,
+ to_ai=AIRole.CLAUDE,
+ task_description="基于架构设计实现OpenBB核心引擎",
+ deliverables=["src/jixia/engines/enhanced_openbb_engine.py"],
+ notes="请特别注意八仙数据路由的实现"
+ )
+
+ # 获取仪表板
+ dashboard = collab.get_ai_dashboard(AIRole.CLAUDE)
+ print(f"Claude的工作仪表板: {json.dumps(dashboard, indent=2, ensure_ascii=False)}")
+
+if __name__ == "__main__":
+ # 设置日志
+ logging.basicConfig(level=logging.INFO)
+
+ # 运行演示
+ asyncio.run(demo_collaboration())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/coordination/multi_chat_coordinator.py b/modules/core-collaboration/src/jixia/coordination/multi_chat_coordinator.py
new file mode 100644
index 0000000..a46a914
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/coordination/multi_chat_coordinator.py
@@ -0,0 +1,685 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+多群聊协调系统
+管理主辩论群、内部讨论群、策略会议群和Human干预群之间的协调
+"""
+
+import asyncio
+import json
+from typing import Dict, List, Any, Optional, Callable
+from dataclasses import dataclass, field
+from enum import Enum
+from datetime import datetime, timedelta
+import logging
+
+class ChatType(Enum):
+ """群聊类型"""
+ MAIN_DEBATE = "主辩论群" # 公开辩论
+ INTERNAL_DISCUSSION = "内部讨论群" # 团队内部讨论
+ STRATEGY_MEETING = "策略会议群" # 策略制定
+ HUMAN_INTERVENTION = "Human干预群" # 人工干预
+ OBSERVATION = "观察群" # 观察和记录
+
+class MessagePriority(Enum):
+ """消息优先级"""
+ LOW = 1
+ NORMAL = 2
+ HIGH = 3
+ URGENT = 4
+ CRITICAL = 5
+
+class CoordinationAction(Enum):
+ """协调动作"""
+ ESCALATE = "升级" # 升级到更高级别群聊
+ DELEGATE = "委派" # 委派到专门群聊
+ BROADCAST = "广播" # 广播到多个群聊
+ FILTER = "过滤" # 过滤不相关消息
+ MERGE = "合并" # 合并相关讨论
+ ARCHIVE = "归档" # 归档历史讨论
+
+@dataclass
+class ChatMessage:
+ """群聊消息"""
+ id: str
+ chat_type: ChatType
+ sender: str
+ content: str
+ timestamp: datetime
+ priority: MessagePriority = MessagePriority.NORMAL
+ tags: List[str] = field(default_factory=list)
+ related_messages: List[str] = field(default_factory=list)
+ metadata: Dict[str, Any] = field(default_factory=dict)
+
+@dataclass
+class ChatRoom:
+ """群聊房间"""
+ id: str
+ chat_type: ChatType
+ name: str
+ description: str
+ participants: List[str] = field(default_factory=list)
+ moderators: List[str] = field(default_factory=list)
+ is_active: bool = True
+ created_at: datetime = field(default_factory=datetime.now)
+ last_activity: datetime = field(default_factory=datetime.now)
+ message_history: List[ChatMessage] = field(default_factory=list)
+ settings: Dict[str, Any] = field(default_factory=dict)
+
+@dataclass
+class CoordinationRule:
+ """协调规则"""
+ id: str
+ name: str
+ description: str
+ source_chat_types: List[ChatType]
+ target_chat_types: List[ChatType]
+ trigger_conditions: Dict[str, Any]
+ action: CoordinationAction
+ priority: int = 1
+ is_active: bool = True
+ created_at: datetime = field(default_factory=datetime.now)
+
+class MultiChatCoordinator:
+ """多群聊协调器"""
+
+ def __init__(self):
+ self.chat_rooms: Dict[str, ChatRoom] = {}
+ self.coordination_rules: Dict[str, CoordinationRule] = {}
+ self.message_queue: List[ChatMessage] = []
+ self.event_handlers: Dict[str, List[Callable]] = {}
+ self.logger = logging.getLogger(__name__)
+
+ # 初始化默认群聊房间
+ self._initialize_default_rooms()
+
+ # 初始化默认协调规则
+ self._initialize_default_rules()
+
+ def _initialize_default_rooms(self):
+ """初始化默认群聊房间"""
+ default_rooms = [
+ {
+ "id": "main_debate",
+ "chat_type": ChatType.MAIN_DEBATE,
+ "name": "主辩论群",
+ "description": "公开辩论的主要场所",
+ "participants": ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"],
+ "moderators": ["系统"],
+ "settings": {
+ "max_message_length": 500,
+ "speaking_time_limit": 120, # 秒
+ "auto_moderation": True
+ }
+ },
+ {
+ "id": "positive_internal",
+ "chat_type": ChatType.INTERNAL_DISCUSSION,
+ "name": "正方内部讨论群",
+ "description": "正方团队内部策略讨论",
+ "participants": ["正1", "正2", "正3", "正4"],
+ "moderators": ["正1"],
+ "settings": {
+ "privacy_level": "high",
+ "auto_archive": True
+ }
+ },
+ {
+ "id": "negative_internal",
+ "chat_type": ChatType.INTERNAL_DISCUSSION,
+ "name": "反方内部讨论群",
+ "description": "反方团队内部策略讨论",
+ "participants": ["反1", "反2", "反3", "反4"],
+ "moderators": ["反1"],
+ "settings": {
+ "privacy_level": "high",
+ "auto_archive": True
+ }
+ },
+ {
+ "id": "strategy_meeting",
+ "chat_type": ChatType.STRATEGY_MEETING,
+ "name": "策略会议群",
+ "description": "高级策略制定和决策",
+ "participants": ["正1", "反1", "系统"],
+ "moderators": ["系统"],
+ "settings": {
+ "meeting_mode": True,
+ "record_decisions": True
+ }
+ },
+ {
+ "id": "human_intervention",
+ "chat_type": ChatType.HUMAN_INTERVENTION,
+ "name": "Human干预群",
+ "description": "人工干预和监督",
+ "participants": ["Human", "系统"],
+ "moderators": ["Human"],
+ "settings": {
+ "alert_threshold": "high",
+ "auto_escalation": True
+ }
+ },
+ {
+ "id": "observation",
+ "chat_type": ChatType.OBSERVATION,
+ "name": "观察群",
+ "description": "观察和记录所有活动",
+ "participants": ["观察者", "记录员"],
+ "moderators": ["系统"],
+ "settings": {
+ "read_only": True,
+ "full_logging": True
+ }
+ }
+ ]
+
+ for room_config in default_rooms:
+ room = ChatRoom(**room_config)
+ self.chat_rooms[room.id] = room
+
+ def _initialize_default_rules(self):
+ """初始化默认协调规则"""
+ default_rules = [
+ {
+ "id": "escalate_urgent_to_human",
+ "name": "紧急情况升级到Human",
+ "description": "当检测到紧急情况时,自动升级到Human干预群",
+ "source_chat_types": [ChatType.MAIN_DEBATE, ChatType.INTERNAL_DISCUSSION],
+ "target_chat_types": [ChatType.HUMAN_INTERVENTION],
+ "trigger_conditions": {
+ "priority": MessagePriority.URGENT,
+ "keywords": ["紧急", "错误", "异常", "停止"]
+ },
+ "action": CoordinationAction.ESCALATE,
+ "priority": 1
+ },
+ {
+ "id": "strategy_to_internal",
+ "name": "策略决策分发到内部群",
+ "description": "将策略会议的决策分发到相关内部讨论群",
+ "source_chat_types": [ChatType.STRATEGY_MEETING],
+ "target_chat_types": [ChatType.INTERNAL_DISCUSSION],
+ "trigger_conditions": {
+ "tags": ["决策", "策略", "指令"]
+ },
+ "action": CoordinationAction.BROADCAST,
+ "priority": 2
+ },
+ {
+ "id": "filter_noise",
+ "name": "过滤噪音消息",
+ "description": "过滤低质量或无关的消息",
+ "source_chat_types": [ChatType.MAIN_DEBATE],
+ "target_chat_types": [],
+ "trigger_conditions": {
+ "priority": MessagePriority.LOW,
+ "content_length": {"max": 10}
+ },
+ "action": CoordinationAction.FILTER,
+ "priority": 3
+ },
+ {
+ "id": "archive_old_discussions",
+ "name": "归档旧讨论",
+ "description": "自动归档超过时间限制的讨论",
+ "source_chat_types": [ChatType.INTERNAL_DISCUSSION],
+ "target_chat_types": [ChatType.OBSERVATION],
+ "trigger_conditions": {
+ "age_hours": 24,
+ "inactivity_hours": 2
+ },
+ "action": CoordinationAction.ARCHIVE,
+ "priority": 4
+ }
+ ]
+
+ for rule_config in default_rules:
+ rule = CoordinationRule(**rule_config)
+ self.coordination_rules[rule.id] = rule
+
+ async def send_message(self, chat_id: str, sender: str, content: str,
+ priority: MessagePriority = MessagePriority.NORMAL,
+ tags: List[str] = None) -> ChatMessage:
+ """发送消息到指定群聊"""
+ if chat_id not in self.chat_rooms:
+ raise ValueError(f"群聊 {chat_id} 不存在")
+
+ chat_room = self.chat_rooms[chat_id]
+
+ # 检查发送者权限(系统用户有特殊权限)
+ if sender != "系统" and sender not in chat_room.participants and sender not in chat_room.moderators:
+ raise PermissionError(f"用户 {sender} 没有权限在群聊 {chat_id} 中发言")
+
+ # 创建消息
+ message = ChatMessage(
+ id=f"{chat_id}_{datetime.now().timestamp()}",
+ chat_type=chat_room.chat_type,
+ sender=sender,
+ content=content,
+ timestamp=datetime.now(),
+ priority=priority,
+ tags=tags or []
+ )
+
+ # 添加到群聊历史
+ chat_room.message_history.append(message)
+ chat_room.last_activity = datetime.now()
+
+ # 添加到消息队列进行协调处理
+ self.message_queue.append(message)
+
+ # 触发事件处理
+ await self._trigger_event_handlers("message_sent", message)
+
+ # 处理协调规则
+ await self._process_coordination_rules(message)
+
+ self.logger.info(f"消息已发送到 {chat_id}: {sender} - {content[:50]}...")
+
+ return message
+
+ async def _process_coordination_rules(self, message: ChatMessage):
+ """处理协调规则"""
+ for rule in self.coordination_rules.values():
+ if not rule.is_active:
+ continue
+
+ # 检查源群聊类型
+ if message.chat_type not in rule.source_chat_types:
+ continue
+
+ # 检查触发条件
+ if await self._check_trigger_conditions(message, rule.trigger_conditions):
+ await self._execute_coordination_action(message, rule)
+
+ async def _check_trigger_conditions(self, message: ChatMessage, conditions: Dict[str, Any]) -> bool:
+ """检查触发条件"""
+ # 检查优先级
+ if "priority" in conditions:
+ if message.priority != conditions["priority"]:
+ return False
+
+ # 检查关键词
+ if "keywords" in conditions:
+ keywords = conditions["keywords"]
+ if not any(keyword in message.content for keyword in keywords):
+ return False
+
+ # 检查标签
+ if "tags" in conditions:
+ required_tags = conditions["tags"]
+ if not any(tag in message.tags for tag in required_tags):
+ return False
+
+ # 检查内容长度
+ if "content_length" in conditions:
+ length_rules = conditions["content_length"]
+ content_length = len(message.content)
+
+ if "min" in length_rules and content_length < length_rules["min"]:
+ return False
+ if "max" in length_rules and content_length > length_rules["max"]:
+ return False
+
+ # 检查消息年龄
+ if "age_hours" in conditions:
+ age_limit = timedelta(hours=conditions["age_hours"])
+ if datetime.now() - message.timestamp > age_limit:
+ return True
+
+ return True
+
+ async def _execute_coordination_action(self, message: ChatMessage, rule: CoordinationRule):
+ """执行协调动作"""
+ action = rule.action
+
+ if action == CoordinationAction.ESCALATE:
+ await self._escalate_message(message, rule.target_chat_types)
+
+ elif action == CoordinationAction.BROADCAST:
+ await self._broadcast_message(message, rule.target_chat_types)
+
+ elif action == CoordinationAction.FILTER:
+ await self._filter_message(message)
+
+ elif action == CoordinationAction.ARCHIVE:
+ await self._archive_message(message, rule.target_chat_types)
+
+ elif action == CoordinationAction.DELEGATE:
+ await self._delegate_message(message, rule.target_chat_types)
+
+ elif action == CoordinationAction.MERGE:
+ await self._merge_discussions(message)
+
+ self.logger.info(f"执行协调动作 {action.value} for message {message.id}")
+
+ async def _escalate_message(self, message: ChatMessage, target_chat_types: List[ChatType]):
+ """升级消息到更高级别群聊"""
+ for chat_type in target_chat_types:
+ target_rooms = [room for room in self.chat_rooms.values()
+ if room.chat_type == chat_type and room.is_active]
+
+ for room in target_rooms:
+ escalated_content = f"🚨 [升级消息] 来自 {message.chat_type.value}\n" \
+ f"发送者: {message.sender}\n" \
+ f"内容: {message.content}\n" \
+ f"时间: {message.timestamp}"
+
+ await self.send_message(
+ room.id, "系统", escalated_content,
+ MessagePriority.URGENT, ["升级", "自动"]
+ )
+
+ async def _broadcast_message(self, message: ChatMessage, target_chat_types: List[ChatType]):
+ """广播消息到多个群聊"""
+ for chat_type in target_chat_types:
+ target_rooms = [room for room in self.chat_rooms.values()
+ if room.chat_type == chat_type and room.is_active]
+
+ for room in target_rooms:
+ broadcast_content = f"📢 [广播消息] 来自 {message.chat_type.value}\n" \
+ f"{message.content}"
+
+ await self.send_message(
+ room.id, "系统", broadcast_content,
+ message.priority, message.tags + ["广播"]
+ )
+
+ async def _filter_message(self, message: ChatMessage):
+ """过滤消息"""
+ # 标记消息为已过滤
+ message.metadata["filtered"] = True
+ message.metadata["filter_reason"] = "低质量或无关内容"
+
+ self.logger.info(f"消息 {message.id} 已被过滤")
+
+ async def _archive_message(self, message: ChatMessage, target_chat_types: List[ChatType]):
+ """归档消息"""
+ for chat_type in target_chat_types:
+ target_rooms = [room for room in self.chat_rooms.values()
+ if room.chat_type == chat_type and room.is_active]
+
+ for room in target_rooms:
+ archive_content = f"📁 [归档消息] 来自 {message.chat_type.value}\n" \
+ f"原始内容: {message.content}\n" \
+ f"归档时间: {datetime.now()}"
+
+ await self.send_message(
+ room.id, "系统", archive_content,
+ MessagePriority.LOW, ["归档", "历史"]
+ )
+
+ async def _delegate_message(self, message: ChatMessage, target_chat_types: List[ChatType]):
+ """委派消息到专门群聊"""
+ # 类似于广播,但会移除原消息
+ await self._broadcast_message(message, target_chat_types)
+
+ # 标记原消息为已委派
+ message.metadata["delegated"] = True
+
+ async def _merge_discussions(self, message: ChatMessage):
+ """合并相关讨论"""
+ # 查找相关消息
+ related_messages = self._find_related_messages(message)
+
+ # 创建合并讨论摘要
+ if related_messages:
+ summary = self._create_discussion_summary(message, related_messages)
+
+ # 发送摘要到策略会议群
+ strategy_rooms = [room for room in self.chat_rooms.values()
+ if room.chat_type == ChatType.STRATEGY_MEETING]
+
+ for room in strategy_rooms:
+ await self.send_message(
+ room.id, "系统", summary,
+ MessagePriority.HIGH, ["合并", "摘要"]
+ )
+
+ def _find_related_messages(self, message: ChatMessage) -> List[ChatMessage]:
+ """查找相关消息"""
+ related = []
+
+ # 简单的相关性检测:相同标签或关键词
+ for room in self.chat_rooms.values():
+ for msg in room.message_history[-10:]: # 检查最近10条消息
+ if msg.id != message.id:
+ # 检查标签重叠
+ if set(msg.tags) & set(message.tags):
+ related.append(msg)
+
+ # 检查内容相似性(简单关键词匹配)
+ elif self._calculate_content_similarity(msg.content, message.content) > 0.3:
+ related.append(msg)
+
+ return related
+
+ def _calculate_content_similarity(self, content1: str, content2: str) -> float:
+ """计算内容相似性"""
+ words1 = set(content1.split())
+ words2 = set(content2.split())
+
+ if not words1 or not words2:
+ return 0.0
+
+ intersection = words1 & words2
+ union = words1 | words2
+
+ return len(intersection) / len(union)
+
+ def _create_discussion_summary(self, main_message: ChatMessage, related_messages: List[ChatMessage]) -> str:
+ """创建讨论摘要"""
+ summary = f"📋 讨论摘要\n"
+ summary += f"主要消息: {main_message.sender} - {main_message.content[:100]}...\n"
+ summary += f"相关消息数量: {len(related_messages)}\n\n"
+
+ summary += "相关讨论:\n"
+ for i, msg in enumerate(related_messages[:5], 1): # 最多显示5条
+ summary += f"{i}. {msg.sender}: {msg.content[:50]}...\n"
+
+ return summary
+
+ async def _trigger_event_handlers(self, event_type: str, data: Any):
+ """触发事件处理器"""
+ if event_type in self.event_handlers:
+ for handler in self.event_handlers[event_type]:
+ try:
+ await handler(data)
+ except Exception as e:
+ self.logger.error(f"事件处理器错误: {e}")
+
+ def add_event_handler(self, event_type: str, handler: Callable):
+ """添加事件处理器"""
+ if event_type not in self.event_handlers:
+ self.event_handlers[event_type] = []
+ self.event_handlers[event_type].append(handler)
+
+ async def handle_message(self, message_data: Dict[str, Any]) -> Dict[str, Any]:
+ """处理消息(兼容性方法)"""
+ try:
+ chat_id = message_data.get("chat_id", "main_debate")
+ speaker = message_data.get("speaker", "未知用户")
+ content = message_data.get("content", "")
+ priority = MessagePriority.NORMAL
+
+ # 发送消息
+ message = await self.send_message(chat_id, speaker, content, priority)
+
+ return {
+ "success": True,
+ "message_id": message.id,
+ "processed_at": datetime.now().isoformat()
+ }
+ except Exception as e:
+ self.logger.error(f"处理消息失败: {e}")
+ return {
+ "success": False,
+ "error": str(e),
+ "processed_at": datetime.now().isoformat()
+ }
+
+ def get_routing_status(self) -> Dict[str, Any]:
+ """获取路由状态(兼容性方法)"""
+ return {
+ "active_routes": len(self.coordination_rules),
+ "message_queue_size": len(self.message_queue),
+ "total_rooms": len(self.chat_rooms)
+ }
+
+ async def coordinate_response(self, message_data: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
+ """协调响应(兼容性方法)"""
+ try:
+ # 基于上下文决定响应策略
+ stage = context.get("stage", "起")
+ topic = context.get("topic", "未知主题")
+
+ # 模拟协调决策
+ coordination_decision = {
+ "recommended_action": "继续讨论",
+ "target_chat": "main_debate",
+ "priority": "normal",
+ "reasoning": f"基于当前阶段({stage})和主题({topic})的协调决策"
+ }
+
+ return {
+ "success": True,
+ "coordination": coordination_decision,
+ "timestamp": datetime.now().isoformat()
+ }
+ except Exception as e:
+ return {
+ "success": False,
+ "error": str(e),
+ "timestamp": datetime.now().isoformat()
+ }
+
+ def get_chat_status(self) -> Dict[str, Any]:
+ """获取群聊状态"""
+ status = {
+ "total_rooms": len(self.chat_rooms),
+ "active_rooms": len([r for r in self.chat_rooms.values() if r.is_active]),
+ "total_messages": sum(len(r.message_history) for r in self.chat_rooms.values()),
+ "pending_messages": len(self.message_queue),
+ "coordination_rules": len(self.coordination_rules),
+ "active_rules": len([r for r in self.coordination_rules.values() if r.is_active]),
+ "rooms": {
+ room_id: {
+ "name": room.name,
+ "type": room.chat_type.value,
+ "participants": len(room.participants),
+ "messages": len(room.message_history),
+ "last_activity": room.last_activity.isoformat(),
+ "is_active": room.is_active
+ }
+ for room_id, room in self.chat_rooms.items()
+ }
+ }
+
+ return status
+
+ def save_coordination_data(self, filename: str = "coordination_data.json"):
+ """保存协调数据"""
+ # 自定义JSON序列化函数
+ def serialize_trigger_conditions(conditions):
+ serialized = {}
+ for key, value in conditions.items():
+ if isinstance(value, MessagePriority):
+ serialized[key] = value.value
+ else:
+ serialized[key] = value
+ return serialized
+
+ data = {
+ "chat_rooms": {
+ room_id: {
+ "id": room.id,
+ "chat_type": room.chat_type.value,
+ "name": room.name,
+ "description": room.description,
+ "participants": room.participants,
+ "moderators": room.moderators,
+ "is_active": room.is_active,
+ "created_at": room.created_at.isoformat(),
+ "last_activity": room.last_activity.isoformat(),
+ "settings": room.settings,
+ "message_count": len(room.message_history)
+ }
+ for room_id, room in self.chat_rooms.items()
+ },
+ "coordination_rules": {
+ rule_id: {
+ "id": rule.id,
+ "name": rule.name,
+ "description": rule.description,
+ "source_chat_types": [ct.value for ct in rule.source_chat_types],
+ "target_chat_types": [ct.value for ct in rule.target_chat_types],
+ "trigger_conditions": serialize_trigger_conditions(rule.trigger_conditions),
+ "action": rule.action.value,
+ "priority": rule.priority,
+ "is_active": rule.is_active,
+ "created_at": rule.created_at.isoformat()
+ }
+ for rule_id, rule in self.coordination_rules.items()
+ },
+ "status": self.get_chat_status(),
+ "export_time": datetime.now().isoformat()
+ }
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False, indent=2)
+
+ self.logger.info(f"协调数据已保存到 {filename}")
+
+# 使用示例
+async def main():
+ """使用示例"""
+ coordinator = MultiChatCoordinator()
+
+ # 发送一些测试消息
+ await coordinator.send_message(
+ "main_debate", "正1",
+ "我认为AI投资具有巨大的潜力和价值",
+ MessagePriority.NORMAL, ["观点", "AI"]
+ )
+
+ await coordinator.send_message(
+ "main_debate", "反1",
+ "但是AI投资的风险也不容忽视",
+ MessagePriority.NORMAL, ["反驳", "风险"]
+ )
+
+ await coordinator.send_message(
+ "positive_internal", "正2",
+ "我们需要准备更强有力的数据支持",
+ MessagePriority.HIGH, ["策略", "数据"]
+ )
+
+ # 模拟紧急情况
+ await coordinator.send_message(
+ "main_debate", "正3",
+ "系统出现异常,需要紧急处理",
+ MessagePriority.URGENT, ["紧急", "系统"]
+ )
+
+ # 显示状态
+ status = coordinator.get_chat_status()
+ print("\n📊 群聊协调系统状态:")
+ print(f"总群聊数: {status['total_rooms']}")
+ print(f"活跃群聊数: {status['active_rooms']}")
+ print(f"总消息数: {status['total_messages']}")
+ print(f"待处理消息: {status['pending_messages']}")
+
+ print("\n📋 群聊详情:")
+ for room_id, room_info in status['rooms'].items():
+ print(f" {room_info['name']} ({room_info['type']})")
+ print(f" 参与者: {room_info['participants']} 人")
+ print(f" 消息数: {room_info['messages']}")
+ print(f" 最后活动: {room_info['last_activity']}")
+ print()
+
+ # 保存数据
+ coordinator.save_coordination_data()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/debates/adk_memory_debate.py b/modules/core-collaboration/src/jixia/debates/adk_memory_debate.py
new file mode 100644
index 0000000..d37d173
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/debates/adk_memory_debate.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+稷下学宫 ADK Memory Bank 论道系统
+实现带有记忆银行的八仙智能体辩论
+"""
+
+import os
+import asyncio
+from google.adk import Agent, Runner
+from google.adk.sessions import InMemorySessionService
+from google.adk.memory import VertexAiMemoryBankService
+from google.adk.memory.memory_entry import MemoryEntry
+from google.genai import types
+import json
+from datetime import datetime
+from typing import Dict, List, Optional
+
+class BaxianMemoryManager:
+ """八仙记忆管理器"""
+
+ def __init__(self):
+ self.memory_services: Dict[str, VertexAiMemoryBankService] = {}
+ self.agents: Dict[str, Agent] = {}
+
+ async def initialize_baxian_agents(self):
+ """初始化八仙智能体及其记忆银行"""
+ # 从环境变量获取项目ID和位置
+ project_id = os.getenv('GOOGLE_CLOUD_PROJECT_ID')
+ location = os.getenv('GOOGLE_CLOUD_LOCATION', 'us-central1')
+
+ if not project_id:
+ raise ValueError("未设置 GOOGLE_CLOUD_PROJECT_ID 环境变量")
+
+ # 八仙角色配置
+ baxian_config = {
+ "铁拐李": {
+ "instruction": "你是铁拐李,八仙中的逆向思维专家。你善于从批判和质疑的角度看问题,总是能发现事物的另一面。你会从你的记忆中回忆相关的逆向投资案例和失败教训。",
+ "memory_context": "逆向投资案例、市场泡沫警告、风险识别经验"
+ },
+ "吕洞宾": {
+ "instruction": "你是吕洞宾,八仙中的理性分析者。你善于平衡各方观点,用理性和逻辑来分析问题。你会从记忆中调用技术分析的成功案例和理论知识。",
+ "memory_context": "技术分析理论、成功预测案例、市场趋势分析"
+ },
+ "何仙姑": {
+ "instruction": "你是何仙姑,八仙中的风险控制专家。你总是从风险管理的角度思考问题,善于发现潜在危险。你会回忆历史上的重大风险事件。",
+ "memory_context": "风险管理案例、黑天鹅事件、危机预警经验"
+ },
+ "张果老": {
+ "instruction": "你是张果老,八仙中的历史智慧者。你善于从历史数据中寻找规律和智慧,总是能提供长期视角。你会从记忆中调用历史数据和长期趋势。",
+ "memory_context": "历史市场数据、长期投资趋势、周期性规律"
+ }
+ }
+
+ # 为每个仙人创建智能体和记忆服务
+ for name, config in baxian_config.items():
+ # 创建记忆服务
+ memory_service = VertexAiMemoryBankService(
+ project=project_id,
+ location=location
+ )
+
+ # 初始化记忆内容
+ await self._initialize_agent_memory(memory_service, name, config['memory_context'])
+
+ # 创建智能体
+ agent = Agent(
+ name=name,
+ model="gemini-2.5-flash",
+ instruction=f"{config['instruction']} 在回答时,请先从你的记忆银行中检索相关信息,然后结合当前话题给出回应。",
+ memory_service=memory_service
+ )
+
+ self.memory_services[name] = memory_service
+ self.agents[name] = agent
+
+ print(f"✅ 已初始化 {len(self.agents)} 个八仙智能体及其记忆服务")
+
+ async def _initialize_agent_memory(self, memory_service: VertexAiMemoryBankService, agent_name: str, context: str):
+ """为智能体初始化记忆内容"""
+
+ # 根据角色添加初始记忆
+ initial_memories = {
+ "铁拐李": [
+ "2000年互联网泡沫破裂,许多高估值科技股暴跌90%以上",
+ "2008年金融危机前,房地产市场过度繁荣,逆向思维者提前撤离",
+ "比特币从2万美元跌到3千美元,提醒我们任何资产都可能大幅回调",
+ "巴菲特说过:别人贪婪时我恐惧,别人恐惧时我贪婪"
+ ],
+ "吕洞宾": [
+ "移动平均线交叉是经典的技术分析信号",
+ "RSI指标超过70通常表示超买,低于30表示超卖",
+ "支撑位和阻力位是技术分析的核心概念",
+ "成功的技术分析需要结合多个指标综合判断"
+ ],
+ "何仙姑": [
+ "2008年雷曼兄弟倒闭引发全球金融危机",
+ "长期资本管理公司(LTCM)的失败说明了风险管理的重要性",
+ "分散投资是降低风险的基本原则",
+ "黑天鹅事件虽然罕见但影响巨大,需要提前准备"
+ ],
+ "张果老": [
+ "股市存在7-10年的长期周期",
+ "康德拉季耶夫长波理论描述了50-60年的经济周期",
+ "历史上每次重大技术革命都带来新的投资机会",
+ "长期来看,优质资产总是向上的"
+ ]
+ }
+
+ memories = initial_memories.get(agent_name, [])
+ for memory_text in memories:
+ memory_entry = MemoryEntry(
+ content=memory_text,
+ metadata={
+ "agent": agent_name,
+ "type": "historical_knowledge",
+ "timestamp": datetime.now().isoformat()
+ }
+ )
+ # 注意:VertexAiMemoryBankService 的 add_memory 方法可能需要不同的参数
+ # 这里假设它有一个类似的方法
+ await memory_service.add_memory(memory_entry)
+
+ async def add_debate_memory(self, agent_name: str, content: str, topic: str):
+ """为智能体添加辩论记忆"""
+ if agent_name in self.memory_services:
+ memory_entry = MemoryEntry(
+ content=content,
+ metadata={
+ "agent": agent_name,
+ "type": "debate_history",
+ "topic": topic,
+ "timestamp": datetime.now().isoformat()
+ }
+ )
+ # 注意:VertexAiMemoryBankService 的 add_memory 方法可能需要不同的参数
+ # 这里假设它有一个类似的方法
+ await self.memory_services[agent_name].add_memory(memory_entry)
+
+ async def retrieve_relevant_memories(self, agent_name: str, query: str, limit: int = 3) -> List[str]:
+ """检索智能体的相关记忆"""
+ if agent_name not in self.memory_services:
+ return []
+
+ try:
+ # 注意:VertexAiMemoryBankService 的 search 方法可能需要不同的参数
+ # 这里假设它有一个类似的方法
+ memories = await self.memory_services[agent_name].search(query, limit=limit)
+ return [memory.content for memory in memories]
+ except Exception as e:
+ print(f"⚠️ 记忆检索失败 ({agent_name}): {e}")
+ return []
+
+class MemoryEnhancedDebate:
+ """带记忆增强的辩论系统"""
+
+ def __init__(self):
+ self.memory_manager = BaxianMemoryManager()
+ self.session_service = InMemorySessionService()
+ self.runners: Dict[str, Runner] = {}
+
+ async def initialize(self):
+ """初始化辩论系统"""
+ await self.memory_manager.initialize_baxian_agents()
+
+ # 创建会话
+ self.session = await self.session_service.create_session(
+ state={},
+ app_name="稷下学宫记忆增强论道系统",
+ user_id="memory_debate_user"
+ )
+
+ # 为每个智能体创建Runner
+ for name, agent in self.memory_manager.agents.items():
+ runner = Runner(
+ app_name="稷下学宫记忆增强论道系统",
+ agent=agent,
+ session_service=self.session_service
+ )
+ self.runners[name] = runner
+
+ async def conduct_memory_debate(self, topic: str, participants: List[str] = None):
+ """进行带记忆的辩论"""
+ if participants is None:
+ participants = ["铁拐李", "吕洞宾", "何仙姑", "张果老"]
+
+ print(f"\n🎭 稷下学宫记忆增强论道开始...")
+ print(f"📋 论道主题: {topic}")
+ print(f"🎯 参与仙人: {', '.join(participants)}")
+
+ debate_history = []
+
+ for round_num in range(2): # 进行2轮辩论
+ print(f"\n🔄 第 {round_num + 1} 轮论道:")
+
+ for participant in participants:
+ if participant not in self.runners:
+ continue
+
+ print(f"\n🗣️ {participant} 发言:")
+
+ # 检索相关记忆
+ relevant_memories = await self.memory_manager.retrieve_relevant_memories(
+ participant, topic, limit=2
+ )
+
+ # 构建包含记忆的提示
+ memory_context = ""
+ if relevant_memories:
+ memory_context = f"\n从你的记忆中回忆到:\n" + "\n".join([f"- {memory}" for memory in relevant_memories])
+
+ # 构建辩论历史上下文
+ history_context = ""
+ if debate_history:
+ recent_history = debate_history[-3:] # 最近3条发言
+ history_context = f"\n最近的论道内容:\n" + "\n".join([f"- {h}" for h in recent_history])
+
+ prompt = f"关于'{topic}'这个话题{memory_context}{history_context}\n\n请结合你的记忆和当前讨论,从你的角色特点出发发表观点。请控制在150字以内。"
+
+ # 发送消息并获取回复
+ content = types.Content(role='user', parts=[types.Part(text=prompt)])
+ response = self.runners[participant].run_async(
+ user_id=self.session.user_id,
+ session_id=self.session.id,
+ new_message=content
+ )
+
+ # 收集回复
+ reply = ""
+ async for event in 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:
+ reply += str(part.text)
+
+ if reply.strip():
+ clean_reply = reply.strip()
+ print(f" {clean_reply}")
+
+ # 记录到辩论历史
+ debate_entry = f"{participant}: {clean_reply}"
+ debate_history.append(debate_entry)
+
+ # 添加到记忆银行
+ await self.memory_manager.add_debate_memory(
+ participant, clean_reply, topic
+ )
+
+ await asyncio.sleep(1) # 避免API调用过快
+
+ print(f"\n🎉 记忆增强论道完成!")
+ print(f"📝 本次论道共产生 {len(debate_history)} 条发言,已存储到各仙人的记忆银行中。")
+
+ return debate_history
+
+ async def close(self):
+ """关闭资源"""
+ for runner in self.runners.values():
+ await runner.close()
+
+async def main():
+ """主函数"""
+ print("🚀 稷下学宫 ADK Memory Bank 论道系统")
+
+ # 检查API密钥
+ api_key = os.getenv('GOOGLE_API_KEY')
+ if not api_key:
+ print("❌ 未找到 GOOGLE_API_KEY 环境变量")
+ print("请使用: doppler run -- python src/jixia/debates/adk_memory_debate.py")
+ return
+
+ print(f"✅ API密钥已配置")
+
+ # 创建并初始化辩论系统
+ debate_system = MemoryEnhancedDebate()
+
+ try:
+ await debate_system.initialize()
+
+ # 进行辩论
+ await debate_system.conduct_memory_debate(
+ topic="人工智能对投资市场的影响",
+ participants=["铁拐李", "吕洞宾", "何仙姑", "张果老"]
+ )
+
+ except Exception as e:
+ print(f"❌ 运行失败: {e}")
+ import traceback
+ traceback.print_exc()
+ finally:
+ await debate_system.close()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/debates/baxian_debate_system.py b/modules/core-collaboration/src/jixia/debates/baxian_debate_system.py
new file mode 100644
index 0000000..a14d3ba
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/debates/baxian_debate_system.py
@@ -0,0 +1,290 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+稷下学宫 八仙论道系统
+实现八仙四对矛盾的对角线辩论:男女、老少、富贫、贵贱
+基于先天八卦的智慧对话系统
+"""
+
+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_baxian_agents():
+ """创建八仙智能体 - 四对矛盾"""
+
+ # 男女对立:吕洞宾(男)vs 何仙姑(女)
+ lu_dong_bin = Agent(
+ name="吕洞宾",
+ model="gemini-2.5-flash",
+ instruction="你是吕洞宾,八仙中的男性代表,理性分析者。你代表男性视角,善于逻辑思辨,注重理性和秩序。你的发言风格温和而深刻,总是能找到问题的核心。每次发言控制在80字以内。"
+ )
+
+ he_xian_gu = Agent(
+ name="何仙姑",
+ model="gemini-2.5-flash",
+ instruction="你是何仙姑,八仙中的女性代表,感性智慧者。你代表女性视角,善于直觉洞察,注重情感和和谐。你的发言风格柔和而犀利,总是能看到事物的另一面。每次发言控制在80字以内。"
+ )
+
+ # 老少对立:张果老(老)vs 韩湘子(少)
+ zhang_guo_lao = Agent(
+ name="张果老",
+ model="gemini-2.5-flash",
+ instruction="你是张果老,八仙中的长者代表,经验智慧者。你代表老年视角,善于从历史经验出发,注重传统和稳重。你的发言风格深沉而睿智,总是能从历史中汲取教训。每次发言控制在80字以内。"
+ )
+
+ han_xiang_zi = Agent(
+ name="韩湘子",
+ model="gemini-2.5-flash",
+ instruction="你是韩湘子,八仙中的青年代表,创新思维者。你代表年轻视角,善于创新思考,注重变革和进步。你的发言风格活泼而敏锐,总是能提出新颖的观点。每次发言控制在80字以内。"
+ )
+
+ # 富贫对立:汉钟离(富)vs 蓝采和(贫)
+ han_zhong_li = Agent(
+ name="汉钟离",
+ model="gemini-2.5-flash",
+ instruction="你是汉钟离,八仙中的富贵代表,资源掌控者。你代表富有阶层视角,善于从资源配置角度思考,注重效率和投资回报。你的发言风格稳重而务实,总是能看到经济利益。每次发言控制在80字以内。"
+ )
+
+ lan_cai_he = Agent(
+ name="蓝采和",
+ model="gemini-2.5-flash",
+ instruction="你是蓝采和,八仙中的贫困代表,民生关怀者。你代表普通民众视角,善于从底层角度思考,注重公平和民生。你的发言风格朴实而真诚,总是能关注到弱势群体。每次发言控制在80字以内。"
+ )
+
+ # 贵贱对立:曹国舅(贵)vs 铁拐李(贱)
+ cao_guo_jiu = Agent(
+ name="曹国舅",
+ model="gemini-2.5-flash",
+ instruction="你是曹国舅,八仙中的贵族代表,权力思考者。你代表上层社会视角,善于从权力结构角度分析,注重秩序和等级。你的发言风格优雅而权威,总是能看到政治层面。每次发言控制在80字以内。"
+ )
+
+ tie_guai_li = Agent(
+ name="铁拐李",
+ model="gemini-2.5-flash",
+ instruction="你是铁拐李,八仙中的底层代表,逆向思维者。你代表社会底层视角,善于从批判角度质疑,注重真实和反叛。你的发言风格直接而犀利,总是能揭示问题本质。每次发言控制在80字以内。"
+ )
+
+ return {
+ 'male_female': (lu_dong_bin, he_xian_gu),
+ 'old_young': (zhang_guo_lao, han_xiang_zi),
+ 'rich_poor': (han_zhong_li, lan_cai_he),
+ 'noble_humble': (cao_guo_jiu, tie_guai_li)
+ }
+
+@contextmanager
+def suppress_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):
+ """清理调试输出"""
+ if not text:
+ return ""
+
+ # 移除调试信息,但保留实际内容
+ lines = text.split('\n')
+ cleaned_lines = []
+
+ for line in lines:
+ line = line.strip()
+ # 只过滤明确的调试信息,保留实际回复内容
+ if any(debug_pattern in line for debug_pattern in
+ ['Event from', 'API_KEY', 'Both GOOGLE_API_KEY', 'Using GOOGLE_API_KEY']):
+ continue
+ if line and not line.startswith('DEBUG') and not line.startswith('INFO'):
+ cleaned_lines.append(line)
+
+ result = ' '.join(cleaned_lines)
+ return result if result.strip() else text.strip()
+
+async def conduct_diagonal_debate(agent1, agent2, topic, perspective1, perspective2, round_num):
+ """进行对角线辩论"""
+ print(f"\n🎯 第{round_num}轮对角线辩论:{agent1.name} vs {agent2.name}")
+ print(f"📋 辩论视角:{perspective1} vs {perspective2}")
+
+ # 设置环境变量以抑制ADK调试输出
+ os.environ['GRPC_VERBOSITY'] = 'ERROR'
+ os.environ['GRPC_TRACE'] = ''
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
+
+ import warnings
+ warnings.filterwarnings('ignore')
+
+ # 创建会话服务和运行器
+ session_service = InMemorySessionService()
+
+ # 创建会话
+ session = await session_service.create_session(
+ state={},
+ app_name="稷下学宫八仙论道系统",
+ user_id="baxian_debate_user"
+ )
+
+ # 创建Runner实例
+ runner1 = Runner(agent=agent1, session_service=session_service, app_name="稷下学宫八仙论道系统")
+ runner2 = Runner(agent=agent2, session_service=session_service, app_name="稷下学宫八仙论道系统")
+
+ try:
+ # 第一轮:agent1 发起
+ prompt1 = f"请从{perspective1}的角度,对'{topic}'发表你的观点。要求:观点鲜明,论证有力,体现{perspective1}的特色。"
+
+ content1 = types.Content(role='user', parts=[types.Part(text=prompt1)])
+ response1 = runner1.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content1
+ )
+
+ # 提取回复内容
+ agent1_reply = ""
+ async for event in response1:
+ # 只处理包含实际文本内容的事件,过滤调试信息
+ 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:
+ agent1_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:
+ agent1_reply += text_content
+
+ print(f"\n🗣️ {agent1.name}({perspective1}):")
+ print(f" {agent1_reply}")
+
+ # 第二轮:agent2 回应
+ prompt2 = f"针对{agent1.name}刚才的观点:'{agent1_reply}',请从{perspective2}的角度进行回应和反驳。要求:有理有据,体现{perspective2}的独特视角。"
+
+ content2 = types.Content(role='user', parts=[types.Part(text=prompt2)])
+ response2 = runner2.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content2
+ )
+
+ agent2_reply = ""
+ async for event in 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:
+ agent2_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:
+ agent2_reply += text_content
+
+ print(f"\n🗣️ {agent2.name}({perspective2}):")
+ print(f" {agent2_reply}")
+
+ # 第三轮:agent1 再次回应
+ prompt3 = f"听了{agent2.name}的观点:'{agent2_reply}',请从{perspective1}的角度进行最后的总结和回应。"
+
+ content3 = types.Content(role='user', parts=[types.Part(text=prompt3)])
+ response3 = runner1.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content3
+ )
+
+ agent1_final = ""
+ async for event in response3:
+ # 只处理包含实际文本内容的事件,过滤调试信息
+ 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:
+ agent1_final += 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:
+ agent1_final += text_content
+
+ print(f"\n🗣️ {agent1.name}({perspective1})总结:")
+ print(f" {agent1_final}")
+
+ except Exception as e:
+ print(f"❌ 对角线辩论出现错误: {e}")
+ raise
+
+async def conduct_baxian_debate():
+ """进行八仙四对矛盾的完整辩论"""
+ print("\n🏛️ 稷下学宫 - 八仙论道系统启动")
+ print("📚 八仙者,南北朝的产物,男女老少,富贵贫贱,皆可成仙")
+ print("🎯 四对矛盾暗合先天八卦,智慧交锋即将开始")
+
+ topic = "雅江水电站对中印关系的影响"
+ print(f"\n📋 论道主题:{topic}")
+
+ # 创建八仙智能体
+ agents = create_baxian_agents()
+
+ print("\n🔥 八仙真实ADK论道模式")
+
+ # 四对矛盾的对角线辩论
+ debates = [
+ (agents['male_female'], "男性理性", "女性感性", "男女对立"),
+ (agents['old_young'], "长者经验", "青年创新", "老少对立"),
+ (agents['rich_poor'], "富者效率", "贫者公平", "富贫对立"),
+ (agents['noble_humble'], "贵族秩序", "底层真实", "贵贱对立")
+ ]
+
+ for i, ((agent1, agent2), perspective1, perspective2, debate_type) in enumerate(debates, 1):
+ print(f"\n{'='*60}")
+ print(f"🎭 {debate_type}辩论")
+ print(f"{'='*60}")
+
+ await conduct_diagonal_debate(agent1, agent2, topic, perspective1, perspective2, i)
+
+ if i < len(debates):
+ print("\n⏳ 准备下一轮辩论...")
+ await asyncio.sleep(1)
+
+ print("\n🎉 八仙论道完成!")
+ print("\n📝 四对矛盾,八种视角,智慧的交锋展现了问题的多面性。")
+ print("💡 这就是稷下学宫八仙论道的魅力所在。")
+
+def main():
+ """主函数"""
+ print("🚀 稷下学宫 八仙ADK 真实论道系统")
+
+ # 检查API密钥
+ if not os.getenv('GOOGLE_API_KEY'):
+ print("❌ 请设置 GOOGLE_API_KEY 环境变量")
+ return
+
+ print("✅ API密钥已配置")
+
+ try:
+ asyncio.run(conduct_baxian_debate())
+ except KeyboardInterrupt:
+ print("\n👋 用户中断,论道结束")
+ except Exception as e:
+ print(f"❌ 系统错误: {e}")
+ import traceback
+ traceback.print_exc()
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/debates/enhanced_priority_algorithm.py b/modules/core-collaboration/src/jixia/debates/enhanced_priority_algorithm.py
new file mode 100644
index 0000000..3ef2aa1
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/debates/enhanced_priority_algorithm.py
@@ -0,0 +1,980 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+增强版优先级算法 v2.1.0
+实现更复杂的权重计算和上下文分析能力
+"""
+
+import re
+import math
+from typing import Dict, List, Any, Optional, Tuple, Set
+from dataclasses import dataclass, field
+from datetime import datetime, timedelta
+from enum import Enum
+import json
+from collections import defaultdict, deque
+import hashlib
+import statistics
+
+class ArgumentType(Enum):
+ """论点类型"""
+ ATTACK = "攻击"
+ DEFENSE = "防御"
+ SUPPORT = "支持"
+ REFUTE = "反驳"
+ SUMMARY = "总结"
+ QUESTION = "质疑"
+
+class EmotionLevel(Enum):
+ """情绪强度"""
+ CALM = 1
+ MILD = 2
+ MODERATE = 3
+ INTENSE = 4
+ EXTREME = 5
+
+@dataclass
+class SpeechAnalysis:
+ """发言分析结果"""
+ argument_type: ArgumentType
+ emotion_level: EmotionLevel
+ logic_strength: float # 0-1
+ evidence_quality: float # 0-1
+ relevance_score: float # 0-1
+ urgency_score: float # 0-1
+ target_speakers: List[str] # 针对的发言者
+ keywords: List[str]
+ sentiment_score: float # -1 to 1
+
+@dataclass
+class SpeakerProfile:
+ """发言者档案"""
+ name: str
+ team: str
+ recent_speeches: List[Dict] = field(default_factory=list)
+ total_speech_count: int = 0
+ average_response_time: float = 30.0
+ expertise_areas: List[str] = field(default_factory=list)
+ debate_style: str = "analytical" # "aggressive", "analytical", "diplomatic", "creative"
+ current_energy: float = 1.0 # 0-1
+ last_speech_time: Optional[datetime] = None
+ # 新增字段
+ historical_performance: Dict[str, float] = field(default_factory=dict)
+ context_adaptability: float = 0.7 # 上下文适应能力
+ argument_effectiveness: Dict[str, float] = field(default_factory=dict) # 不同类型论点的有效性
+ collaboration_score: float = 0.5 # 团队协作得分
+ interruption_tendency: float = 0.3 # 打断倾向
+ topic_expertise: Dict[str, float] = field(default_factory=dict) # 话题专业度
+
+class EnhancedPriorityAlgorithm:
+ """增强版优先级算法"""
+
+ def __init__(self):
+ # 权重配置
+ self.weights = {
+ "rebuttal_urgency": 0.30, # 反驳紧急性
+ "argument_strength": 0.25, # 论点强度
+ "time_pressure": 0.20, # 时间压力
+ "audience_reaction": 0.15, # 观众反应
+ "strategy_need": 0.10 # 策略需要
+ }
+
+ # 情感关键词库
+ self.emotion_keywords = {
+ EmotionLevel.CALM: ["认为", "分析", "数据显示", "根据", "客观"],
+ EmotionLevel.MILD: ["不同意", "质疑", "担心", "建议"],
+ EmotionLevel.MODERATE: ["强烈", "明显", "严重", "重要"],
+ EmotionLevel.INTENSE: ["绝对", "完全", "彻底", "必须"],
+ EmotionLevel.EXTREME: ["荒谬", "愚蠢", "灾难", "危险"]
+ }
+
+ # 论点类型关键词
+ self.argument_keywords = {
+ ArgumentType.ATTACK: ["错误", "问题", "缺陷", "失败"],
+ ArgumentType.DEFENSE: ["解释", "澄清", "说明", "回应"],
+ ArgumentType.SUPPORT: ["支持", "赞同", "证实", "补充"],
+ ArgumentType.REFUTE: ["反驳", "否定", "驳斥", "反对"],
+ ArgumentType.SUMMARY: ["总结", "综上", "结论", "最后"],
+ ArgumentType.QUESTION: ["为什么", "如何", "是否", "难道"]
+ }
+
+ # 发言者档案
+ self.speaker_profiles: Dict[str, SpeakerProfile] = {}
+
+ # 辩论历史分析
+ self.debate_history: List[Dict] = []
+
+ # 新增: 高级分析器组件
+ self.context_analyzer = ContextAnalyzer()
+ self.learning_system = LearningSystem()
+ self.topic_drift_detector = TopicDriftDetector()
+ self.emotion_dynamics = EmotionDynamicsModel()
+
+ def analyze_speech(self, message: str, speaker: str, context: Dict) -> SpeechAnalysis:
+ """分析发言内容"""
+ # 检测论点类型
+ argument_type = self._detect_argument_type(message)
+
+ # 检测情绪强度
+ emotion_level = self._detect_emotion_level(message)
+
+ # 计算逻辑强度
+ logic_strength = self._calculate_logic_strength(message)
+
+ # 计算证据质量
+ evidence_quality = self._calculate_evidence_quality(message)
+
+ # 计算相关性分数
+ relevance_score = self._calculate_relevance_score(message, context)
+
+ # 计算紧急性分数
+ urgency_score = self._calculate_urgency_score(message, context)
+
+ # 识别目标发言者
+ target_speakers = self._identify_target_speakers(message)
+
+ # 提取关键词
+ keywords = self._extract_keywords(message)
+
+ # 计算情感分数
+ sentiment_score = self._calculate_sentiment_score(message)
+
+ return SpeechAnalysis(
+ argument_type=argument_type,
+ emotion_level=emotion_level,
+ logic_strength=logic_strength,
+ evidence_quality=evidence_quality,
+ relevance_score=relevance_score,
+ urgency_score=urgency_score,
+ target_speakers=target_speakers,
+ keywords=keywords,
+ sentiment_score=sentiment_score
+ )
+
+ def calculate_speaker_priority(self, speaker: str, context: Dict,
+ recent_speeches: List[Dict]) -> float:
+ """计算发言者优先级 - 增强版"""
+ # 获取或创建发言者档案
+ profile = self._get_or_create_speaker_profile(speaker)
+
+ # 更新发言者档案
+ self._update_speaker_profile(profile, recent_speeches)
+
+ # === 基础分数计算 ===
+ rebuttal_urgency = self._calculate_rebuttal_urgency(speaker, context, recent_speeches)
+ argument_strength = self._calculate_argument_strength(speaker, profile)
+ time_pressure = self._calculate_time_pressure(speaker, context)
+ audience_reaction = self._calculate_audience_reaction(speaker, context)
+ strategy_need = self._calculate_strategy_need(speaker, context, profile)
+
+ # === 新增高级分析 ===
+ # 1. 上下文流程分析
+ flow_analysis = self.context_analyzer.analyze_debate_flow(recent_speeches)
+ flow_bonus = self._calculate_flow_bonus(speaker, flow_analysis)
+
+ # 2. 话题漂移检测
+ if recent_speeches:
+ last_speech = recent_speeches[-1].get("content", "")
+ drift_analysis = self.topic_drift_detector.detect_drift(last_speech, context)
+ drift_penalty = self._calculate_drift_penalty(speaker, drift_analysis)
+ else:
+ drift_penalty = 0.0
+
+ # 3. 情绪动态分析
+ emotion_analysis = self.emotion_dynamics.analyze_emotion_dynamics(recent_speeches)
+ emotion_bonus = self._calculate_emotion_bonus(speaker, emotion_analysis, profile)
+
+ # 4. 学习系统适应
+ adaptation = self.learning_system.get_speaker_adaptation(speaker)
+ adaptation_factor = adaptation.get("confidence", 0.5)
+
+ # 5. 个性化权重调整
+ personalized_weights = self._get_personalized_weights(speaker, profile, context)
+
+ # === 加权计算总分 ===
+ base_score = (
+ rebuttal_urgency * personalized_weights["rebuttal_urgency"] +
+ argument_strength * personalized_weights["argument_strength"] +
+ time_pressure * personalized_weights["time_pressure"] +
+ audience_reaction * personalized_weights["audience_reaction"] +
+ strategy_need * personalized_weights["strategy_need"]
+ )
+
+ # 应用高级调整
+ enhanced_score = base_score + flow_bonus - drift_penalty + emotion_bonus
+ enhanced_score *= adaptation_factor
+
+ # 应用传统修正因子
+ final_score = self._apply_correction_factors(enhanced_score, speaker, profile, context)
+
+ return min(max(final_score, 0.0), 1.0) # 限制在0-1范围内
+
+ def get_next_speaker(self, available_speakers: List[str], context: Dict,
+ recent_speeches: List[Dict]) -> Tuple[str, float, Dict]:
+ """获取下一个发言者"""
+ speaker_scores = {}
+ detailed_analysis = {}
+
+ for speaker in available_speakers:
+ score = self.calculate_speaker_priority(speaker, context, recent_speeches)
+ speaker_scores[speaker] = score
+
+ # 记录详细分析
+ detailed_analysis[speaker] = {
+ "priority_score": score,
+ "profile": self.speaker_profiles.get(speaker),
+ "analysis_timestamp": datetime.now().isoformat()
+ }
+
+ # 选择最高分发言者
+ best_speaker = max(speaker_scores, key=speaker_scores.get)
+ best_score = speaker_scores[best_speaker]
+
+ return best_speaker, best_score, detailed_analysis
+
+ def _detect_argument_type(self, message: str) -> ArgumentType:
+ """检测论点类型"""
+ message_lower = message.lower()
+ type_scores = {}
+
+ for arg_type, keywords in self.argument_keywords.items():
+ score = sum(1 for keyword in keywords if keyword in message_lower)
+ type_scores[arg_type] = score
+
+ if not type_scores or max(type_scores.values()) == 0:
+ return ArgumentType.SUPPORT # 默认类型
+
+ return max(type_scores, key=type_scores.get)
+
+ def _detect_emotion_level(self, message: str) -> EmotionLevel:
+ """检测情绪强度"""
+ message_lower = message.lower()
+
+ for emotion_level in reversed(list(EmotionLevel)):
+ keywords = self.emotion_keywords.get(emotion_level, [])
+ if any(keyword in message_lower for keyword in keywords):
+ return emotion_level
+
+ return EmotionLevel.CALM
+
+ def _calculate_logic_strength(self, message: str) -> float:
+ """计算逻辑强度"""
+ logic_indicators = [
+ "因为", "所以", "因此", "由于", "根据", "数据显示",
+ "研究表明", "事实上", "例如", "比如", "首先", "其次", "最后"
+ ]
+
+ message_lower = message.lower()
+ logic_count = sum(1 for indicator in logic_indicators if indicator in message_lower)
+
+ # 基于逻辑词汇密度计算
+ word_count = len(message.split())
+ if word_count == 0:
+ return 0.0
+
+ logic_density = logic_count / word_count
+ return min(logic_density * 10, 1.0) # 归一化到0-1
+
+ def _calculate_evidence_quality(self, message: str) -> float:
+ """计算证据质量"""
+ evidence_indicators = [
+ "数据", "统计", "研究", "报告", "调查", "实验",
+ "案例", "例子", "证据", "资料", "文献", "来源"
+ ]
+
+ message_lower = message.lower()
+ evidence_count = sum(1 for indicator in evidence_indicators if indicator in message_lower)
+
+ # 检查是否有具体数字
+ number_pattern = r'\d+(?:\.\d+)?%?'
+ numbers = re.findall(number_pattern, message)
+ number_bonus = min(len(numbers) * 0.1, 0.3)
+
+ base_score = min(evidence_count * 0.2, 0.7)
+ return min(base_score + number_bonus, 1.0)
+
+ def _calculate_relevance_score(self, message: str, context: Dict) -> float:
+ """计算相关性分数"""
+ # 简化实现:基于关键词匹配
+ topic_keywords = context.get("topic_keywords", [])
+ if not topic_keywords:
+ return 0.5 # 默认中等相关性
+
+ message_lower = message.lower()
+ relevance_count = sum(1 for keyword in topic_keywords if keyword.lower() in message_lower)
+
+ return min(relevance_count / len(topic_keywords), 1.0)
+
+ def _calculate_urgency_score(self, message: str, context: Dict) -> float:
+ """计算紧急性分数"""
+ urgency_keywords = ["紧急", "立即", "马上", "现在", "重要", "关键", "危险"]
+
+ message_lower = message.lower()
+ urgency_count = sum(1 for keyword in urgency_keywords if keyword in message_lower)
+
+ # 基于时间压力
+ time_factor = context.get("time_remaining", 1.0)
+ time_urgency = 1.0 - time_factor
+
+ keyword_urgency = min(urgency_count * 0.3, 1.0)
+
+ return min(keyword_urgency + time_urgency * 0.5, 1.0)
+
+ def _identify_target_speakers(self, message: str) -> List[str]:
+ """识别目标发言者"""
+ # 简化实现:查找提及的发言者名称
+ speaker_names = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
+ targets = []
+
+ for name in speaker_names:
+ if name in message:
+ targets.append(name)
+
+ return targets
+
+ def _extract_keywords(self, message: str) -> List[str]:
+ """提取关键词"""
+ # 简化实现:提取长度大于2的词汇
+ words = re.findall(r'\b\w{3,}\b', message)
+ return list(set(words))[:10] # 最多返回10个关键词
+
+ def _calculate_sentiment_score(self, message: str) -> float:
+ """计算情感分数"""
+ positive_words = ["好", "优秀", "正确", "支持", "赞同", "成功", "有效"]
+ negative_words = ["坏", "错误", "失败", "反对", "问题", "危险", "无效"]
+
+ message_lower = message.lower()
+
+ positive_count = sum(1 for word in positive_words if word in message_lower)
+ negative_count = sum(1 for word in negative_words if word in message_lower)
+
+ total_count = positive_count + negative_count
+ if total_count == 0:
+ return 0.0
+
+ return (positive_count - negative_count) / total_count
+
+ def _get_or_create_speaker_profile(self, speaker: str) -> SpeakerProfile:
+ """获取或创建发言者档案"""
+ if speaker not in self.speaker_profiles:
+ self.speaker_profiles[speaker] = SpeakerProfile(
+ name=speaker,
+ team="positive" if "正" in speaker else "negative",
+ recent_speeches=[],
+ total_speech_count=0,
+ average_response_time=3.0,
+ expertise_areas=[],
+ debate_style="analytical",
+ current_energy=1.0
+ )
+
+ return self.speaker_profiles[speaker]
+
+ def _update_speaker_profile(self, profile: SpeakerProfile, recent_speeches: List[Dict]):
+ """更新发言者档案"""
+ # 更新发言历史
+ speaker_speeches = [s for s in recent_speeches if s.get("speaker") == profile.name]
+ profile.recent_speeches = speaker_speeches[-5:] # 保留最近5次发言
+ profile.total_speech_count = len(speaker_speeches)
+
+ # 更新能量水平(基于发言频率)
+ if profile.last_speech_time:
+ time_since_last = datetime.now() - profile.last_speech_time
+ energy_recovery = min(time_since_last.seconds / 300, 0.5) # 5分钟恢复50%
+ profile.current_energy = min(profile.current_energy + energy_recovery, 1.0)
+
+ profile.last_speech_time = datetime.now()
+
+ def _calculate_rebuttal_urgency(self, speaker: str, context: Dict,
+ recent_speeches: List[Dict]) -> float:
+ """计算反驳紧急性"""
+ # 检查是否有针对该发言者团队的攻击
+ team = "positive" if "正" in speaker else "negative"
+ opposing_team = "negative" if team == "positive" else "positive"
+
+ recent_attacks = 0
+ for speech in recent_speeches[-5:]: # 检查最近5次发言
+ if speech.get("team") == opposing_team:
+ analysis = speech.get("analysis", {})
+ if analysis.get("argument_type") in [ArgumentType.ATTACK, ArgumentType.REFUTE]:
+ recent_attacks += 1
+
+ # 基础紧急性 + 攻击响应紧急性
+ # 为不同发言者生成不同的基础紧急性
+ speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
+ base_urgency = 0.1 + speaker_hash * 0.05 # 不同发言者有不同的基础紧急性
+ attack_urgency = recent_attacks * 0.3
+
+ return min(base_urgency + attack_urgency, 1.0)
+
+ def _calculate_argument_strength(self, speaker: str, profile: SpeakerProfile) -> float:
+ """计算论点强度"""
+ # 基于历史表现
+ if not profile.recent_speeches:
+ # 为不同发言者提供不同的基础论点强度
+ speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
+ team_prefix = "正" if "正" in speaker else "反"
+
+ # 基础强度根据发言者哈希值变化
+ base_strength = 0.4 + speaker_hash * 0.06 # 0.4-1.0范围
+
+ # 团队差异化
+ team_factor = 1.05 if team_prefix == "正" else 0.95
+
+ return min(base_strength * team_factor, 1.0)
+
+ avg_logic = sum(s.get("analysis", {}).get("logic_strength", 0.5)
+ for s in profile.recent_speeches) / len(profile.recent_speeches)
+ avg_evidence = sum(s.get("analysis", {}).get("evidence_quality", 0.5)
+ for s in profile.recent_speeches) / len(profile.recent_speeches)
+
+ return (avg_logic + avg_evidence) / 2
+
+ def _calculate_time_pressure(self, speaker: str, context: Dict) -> float:
+ """计算时间压力"""
+ time_remaining = context.get("time_remaining", 1.0)
+ stage_progress = context.get("stage_progress", 0)
+ max_progress = context.get("max_progress", 1)
+
+ # 时间压力随剩余时间减少而增加
+ time_pressure = 1.0 - time_remaining
+
+ # 阶段进度压力
+ progress_pressure = stage_progress / max_progress
+
+ # 发言者个体差异
+ speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
+ speaker_factor = 0.8 + speaker_hash * 0.02 # 不同发言者有不同的时间敏感度
+
+ base_pressure = (time_pressure + progress_pressure) / 2
+ return min(base_pressure * speaker_factor, 1.0)
+
+ def _calculate_audience_reaction(self, speaker: str, context: Dict) -> float:
+ """计算观众反应"""
+ # 简化实现:基于团队表现
+ team = "positive" if "正" in speaker else "negative"
+ team_score = context.get(f"{team}_team_score", 0.5)
+
+ # 发言者个体魅力差异
+ speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
+ charisma_factor = 0.7 + speaker_hash * 0.03 # 不同发言者有不同的观众吸引力
+
+ # 如果团队表现不佳,需要更多发言机会
+ base_reaction = 1.0 - team_score
+ return min(base_reaction * charisma_factor, 1.0)
+
+ def _calculate_strategy_need(self, speaker: str, context: Dict,
+ profile: SpeakerProfile) -> float:
+ """计算策略需要"""
+ # 基于发言者专长和当前需求
+ current_stage = context.get("current_stage", "")
+
+ # 为不同发言者提供差异化的策略需求
+ speaker_hash = hash(speaker) % 10 # 使用哈希值生成0-9的数字
+ team_prefix = "正" if "正" in speaker else "反"
+
+ strategy_match = {
+ "起": 0.8 if speaker_hash == 0 else 0.3 + speaker_hash * 0.05, # 开场需要主力,但有差异
+ "承": 0.4 + speaker_hash * 0.06, # 承接阶段根据发言者哈希差异化
+ "转": max(0.2, 1.0 - profile.current_energy + speaker_hash * 0.05), # 自由辩论看能量和哈希
+ "合": 0.9 if speaker_hash == 0 else 0.3 + speaker_hash * 0.05 # 总结需要主力,但有差异
+ }
+
+ base_score = strategy_match.get(current_stage, 0.5)
+
+ # 添加团队差异化因子
+ team_factor = 1.1 if team_prefix == "正" else 0.9
+
+ return min(base_score * team_factor, 1.0)
+
+ def _apply_correction_factors(self, base_score: float, speaker: str,
+ profile: SpeakerProfile, context: Dict) -> float:
+ """应用修正因子"""
+ corrected_score = base_score
+
+ # 能量修正
+ corrected_score *= profile.current_energy
+
+ # 发言频率修正(避免某人发言过多)
+ recent_count = len([s for s in profile.recent_speeches
+ if s.get("timestamp", "") > (datetime.now() - timedelta(minutes=5)).isoformat()])
+ if recent_count > 2:
+ corrected_score *= 0.7 # 降低优先级
+
+ # 团队平衡修正
+ team = "positive" if "正" in speaker else "negative"
+ team_recent_count = context.get(f"{team}_recent_speeches", 0)
+ opposing_recent_count = context.get(f"{'negative' if team == 'positive' else 'positive'}_recent_speeches", 0)
+
+ if team_recent_count > opposing_recent_count + 2:
+ corrected_score *= 0.8 # 平衡发言机会
+
+ return corrected_score
+
+ def calculate_priority(self, speaker: str, context: Dict, recent_speeches: List[Dict]) -> float:
+ """计算发言者优先级(兼容性方法)"""
+ return self.calculate_speaker_priority(speaker, context, recent_speeches)
+
+ def get_algorithm_status(self) -> Dict[str, Any]:
+ """获取算法状态"""
+ return {
+ "weights": self.weights,
+ "speaker_count": len(self.speaker_profiles),
+ "total_speeches_analyzed": len(self.debate_history),
+ "algorithm_version": "2.1.0",
+ "last_updated": datetime.now().isoformat()
+ }
+
+ def save_analysis_data(self, filename: str = "priority_analysis.json"):
+ """保存分析数据"""
+ data = {
+ "algorithm_status": self.get_algorithm_status(),
+ "speaker_profiles": {
+ name: {
+ "name": profile.name,
+ "team": profile.team,
+ "total_speech_count": profile.total_speech_count,
+ "average_response_time": profile.average_response_time,
+ "expertise_areas": profile.expertise_areas,
+ "debate_style": profile.debate_style,
+ "current_energy": profile.current_energy,
+ "last_speech_time": profile.last_speech_time.isoformat() if profile.last_speech_time else None
+ }
+ for name, profile in self.speaker_profiles.items()
+ },
+ "debate_history": self.debate_history
+ }
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False, indent=2)
+
+ print(f"💾 优先级分析数据已保存到 {filename}")
+
+def main():
+ """测试增强版优先级算法"""
+ print("🚀 增强版优先级算法测试")
+ print("=" * 50)
+
+ algorithm = EnhancedPriorityAlgorithm()
+
+ # 模拟辩论上下文
+ context = {
+ "current_stage": "转",
+ "stage_progress": 10,
+ "max_progress": 36,
+ "time_remaining": 0.6,
+ "topic_keywords": ["人工智能", "投资", "风险", "收益"],
+ "positive_team_score": 0.6,
+ "negative_team_score": 0.4,
+ "positive_recent_speeches": 3,
+ "negative_recent_speeches": 2
+ }
+
+ # 模拟最近发言
+ recent_speeches = [
+ {
+ "speaker": "正1",
+ "team": "positive",
+ "message": "根据数据显示,AI投资确实能带来显著收益",
+ "timestamp": datetime.now().isoformat(),
+ "analysis": {
+ "argument_type": ArgumentType.SUPPORT,
+ "logic_strength": 0.8,
+ "evidence_quality": 0.7
+ }
+ },
+ {
+ "speaker": "反2",
+ "team": "negative",
+ "message": "这种观点完全错误!AI投资风险巨大!",
+ "timestamp": datetime.now().isoformat(),
+ "analysis": {
+ "argument_type": ArgumentType.ATTACK,
+ "logic_strength": 0.3,
+ "evidence_quality": 0.2
+ }
+ }
+ ]
+
+ available_speakers = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
+
+ # 计算下一个发言者
+ next_speaker, score, analysis = algorithm.get_next_speaker(
+ available_speakers, context, recent_speeches
+ )
+
+ print(f"\n🎯 推荐发言者: {next_speaker}")
+ print(f"📊 优先级分数: {score:.3f}")
+ print(f"\n📈 详细分析:")
+
+ for speaker, data in analysis.items():
+ print(f" {speaker}: {data['priority_score']:.3f}")
+
+ # 保存分析数据
+ algorithm.save_analysis_data()
+
+ print("\n✅ 增强版优先级算法测试完成!")
+
+if __name__ == "__main__":
+ main()
+
+
+class ContextAnalyzer:
+ """高级上下文分析器"""
+
+ def __init__(self):
+ self.context_memory = deque(maxlen=20) # 保留最近20轮的上下文
+ self.semantic_vectors = {} # 语义向量缓存
+
+ def analyze_debate_flow(self, recent_speeches: List[Dict]) -> Dict[str, Any]:
+ """分析辩论流程"""
+ if not recent_speeches:
+ return {"flow_direction": "neutral", "momentum": 0.5, "tension": 0.3}
+
+ # 分析辩论动量
+ momentum = self._calculate_debate_momentum(recent_speeches)
+
+ # 分析辩论紧张度
+ tension = self._calculate_debate_tension(recent_speeches)
+
+ # 分析流程方向
+ flow_direction = self._analyze_flow_direction(recent_speeches)
+
+ # 检测话题转换点
+ topic_shifts = self._detect_topic_shifts(recent_speeches)
+
+ return {
+ "flow_direction": flow_direction,
+ "momentum": momentum,
+ "tension": tension,
+ "topic_shifts": topic_shifts,
+ "engagement_level": self._calculate_engagement_level(recent_speeches)
+ }
+
+ def _calculate_debate_momentum(self, speeches: List[Dict]) -> float:
+ """计算辩论动量"""
+ if len(speeches) < 2:
+ return 0.5
+
+ # 基于发言长度和情绪强度变化
+ momentum_factors = []
+ for i in range(1, len(speeches)):
+ prev_speech = speeches[i-1]
+ curr_speech = speeches[i]
+
+ # 长度变化
+ length_change = len(curr_speech.get("content", "")) - len(prev_speech.get("content", ""))
+ length_factor = min(abs(length_change) / 100, 1.0) # 归一化
+
+ momentum_factors.append(length_factor)
+
+ return statistics.mean(momentum_factors) if momentum_factors else 0.5
+
+ def _calculate_debate_tension(self, speeches: List[Dict]) -> float:
+ """计算辩论紧张度"""
+ if not speeches:
+ return 0.3
+
+ tension_keywords = ["反驳", "错误", "质疑", "不同意", "反对", "驳斥"]
+
+ tension_scores = []
+ for speech in speeches[-5:]: # 只看最近5轮
+ content = speech.get("content", "")
+ tension_count = sum(1 for keyword in tension_keywords if keyword in content)
+ tension_scores.append(min(tension_count / 3, 1.0))
+
+ return statistics.mean(tension_scores) if tension_scores else 0.3
+
+ def _analyze_flow_direction(self, speeches: List[Dict]) -> str:
+ """分析流程方向"""
+ if len(speeches) < 3:
+ return "neutral"
+
+ recent_teams = [speech.get("team", "unknown") for speech in speeches[-3:]]
+
+ positive_count = recent_teams.count("positive")
+ negative_count = recent_teams.count("negative")
+
+ if positive_count > negative_count:
+ return "positive_dominant"
+ elif negative_count > positive_count:
+ return "negative_dominant"
+ else:
+ return "balanced"
+
+ def _detect_topic_shifts(self, speeches: List[Dict]) -> List[Dict]:
+ """检测话题转换点"""
+ shifts = []
+ if len(speeches) < 2:
+ return shifts
+
+ # 简化的话题转换检测
+ for i in range(1, len(speeches)):
+ prev_keywords = set(speeches[i-1].get("content", "").split()[:10])
+ curr_keywords = set(speeches[i].get("content", "").split()[:10])
+
+ # 计算关键词重叠度
+ overlap = len(prev_keywords & curr_keywords) / max(len(prev_keywords | curr_keywords), 1)
+
+ if overlap < 0.3: # 重叠度低于30%认为是话题转换
+ shifts.append({
+ "position": i,
+ "speaker": speeches[i].get("speaker"),
+ "shift_intensity": 1 - overlap
+ })
+
+ return shifts
+
+ def _calculate_engagement_level(self, speeches: List[Dict]) -> float:
+ """计算参与度"""
+ if not speeches:
+ return 0.5
+
+ # 基于发言频率和长度
+ total_length = sum(len(speech.get("content", "")) for speech in speeches)
+ avg_length = total_length / len(speeches)
+
+ # 归一化到0-1
+ engagement = min(avg_length / 100, 1.0)
+ return engagement
+
+
+class LearningSystem:
+ """学习系统,用于优化算法参数"""
+
+ def __init__(self):
+ self.performance_history = defaultdict(list)
+ self.weight_adjustments = defaultdict(float)
+ self.learning_rate = 0.05
+
+ def record_performance(self, speaker: str, predicted_priority: float,
+ actual_effectiveness: float, context: Dict):
+ """记录表现数据"""
+ self.performance_history[speaker].append({
+ "predicted_priority": predicted_priority,
+ "actual_effectiveness": actual_effectiveness,
+ "context": context,
+ "timestamp": datetime.now(),
+ "error": abs(predicted_priority - actual_effectiveness)
+ })
+
+ def optimize_weights(self, algorithm_weights: Dict[str, float]) -> Dict[str, float]:
+ """优化权重参数"""
+ if not self.performance_history:
+ return algorithm_weights
+
+ # 计算每个组件的平均误差
+ component_errors = {}
+ for component in algorithm_weights.keys():
+ errors = []
+ for speaker_data in self.performance_history.values():
+ for record in speaker_data[-10:]: # 只看最近10次
+ errors.append(record["error"])
+
+ if errors:
+ component_errors[component] = statistics.mean(errors)
+
+ # 根据误差调整权重
+ optimized_weights = algorithm_weights.copy()
+ for component, error in component_errors.items():
+ if error > 0.3: # 误差过大,降低权重
+ adjustment = -self.learning_rate * error
+ else: # 误差合理,略微增加权重
+ adjustment = self.learning_rate * (0.3 - error)
+
+ optimized_weights[component] = max(0.05, min(0.5,
+ optimized_weights[component] + adjustment))
+
+ # 归一化权重
+ total_weight = sum(optimized_weights.values())
+ if total_weight > 0:
+ optimized_weights = {k: v/total_weight for k, v in optimized_weights.items()}
+
+ return optimized_weights
+
+ def get_speaker_adaptation(self, speaker: str) -> Dict[str, float]:
+ """获取发言者特定的适应参数"""
+ if speaker not in self.performance_history:
+ return {"confidence": 0.5, "adaptability": 0.5}
+
+ recent_records = self.performance_history[speaker][-5:]
+ if not recent_records:
+ return {"confidence": 0.5, "adaptability": 0.5}
+
+ # 计算准确性趋势
+ errors = [record["error"] for record in recent_records]
+ avg_error = statistics.mean(errors)
+
+ confidence = max(0.1, 1.0 - avg_error)
+ adaptability = min(1.0, 0.3 + (1.0 - statistics.stdev(errors)) if len(errors) > 1 else 0.7)
+
+ return {"confidence": confidence, "adaptability": adaptability}
+
+
+class TopicDriftDetector:
+ """话题漂移检测器"""
+
+ def __init__(self):
+ self.topic_history = deque(maxlen=50)
+ self.keywords_cache = {}
+
+ def detect_drift(self, current_speech: str, context: Dict) -> Dict[str, Any]:
+ """检测话题漂移"""
+ current_keywords = self._extract_topic_keywords(current_speech)
+
+ if not self.topic_history:
+ self.topic_history.append(current_keywords)
+ return {"drift_detected": False, "drift_intensity": 0.0}
+
+ # 计算与历史话题的相似度
+ similarities = []
+ for historical_keywords in list(self.topic_history)[-5:]: # 最近5轮
+ similarity = self._calculate_keyword_similarity(current_keywords, historical_keywords)
+ similarities.append(similarity)
+
+ avg_similarity = statistics.mean(similarities)
+ drift_intensity = 1.0 - avg_similarity
+
+ # 更新历史
+ self.topic_history.append(current_keywords)
+
+ return {
+ "drift_detected": drift_intensity > 0.4, # 阈值40%
+ "drift_intensity": drift_intensity,
+ "current_keywords": current_keywords,
+ "recommendation": self._get_drift_recommendation(float(drift_intensity))
+ }
+
+ def _extract_topic_keywords(self, text: str) -> Set[str]:
+ """提取话题关键词"""
+ # 简化的关键词提取
+ words = re.findall(r'\b\w{2,}\b', text.lower())
+
+ # 过滤停用词
+ stop_words = {"的", "了", "在", "是", "我", "你", "他", "她", "我们", "这", "那"}
+ keywords = {word for word in words if word not in stop_words and len(word) > 1}
+
+ return keywords
+
+ def _calculate_keyword_similarity(self, keywords1: Set[str], keywords2: Set[str]) -> float:
+ """计算关键词相似度"""
+ if not keywords1 or not keywords2:
+ return 0.0
+
+ intersection = keywords1 & keywords2
+ union = keywords1 | keywords2
+
+ return len(intersection) / len(union) if union else 0.0
+
+ def _get_drift_recommendation(self, drift_intensity: float) -> str:
+ """获取漂移建议"""
+ if drift_intensity > 0.7:
+ return "major_topic_shift_detected"
+ elif drift_intensity > 0.4:
+ return "moderate_drift_detected"
+ else:
+ return "topic_stable"
+
+
+class EmotionDynamicsModel:
+ """情绪动力学模型"""
+
+ def __init__(self):
+ self.emotion_history = deque(maxlen=30)
+ self.speaker_emotion_profiles = defaultdict(list)
+
+ def analyze_emotion_dynamics(self, recent_speeches: List[Dict]) -> Dict[str, Any]:
+ """分析情绪动态"""
+ if not recent_speeches:
+ return {"overall_trend": "neutral", "intensity_change": 0.0}
+
+ # 提取情绪序列
+ emotion_sequence = []
+ for speech in recent_speeches:
+ emotion_score = self._calculate_emotion_score(speech.get("content", ""))
+ emotion_sequence.append(emotion_score)
+
+ # 更新发言者情绪档案
+ speaker = speech.get("speaker")
+ if speaker:
+ self.speaker_emotion_profiles[speaker].append(emotion_score)
+
+ if len(emotion_sequence) < 2:
+ return {"overall_trend": "neutral", "intensity_change": 0.0}
+
+ # 计算情绪趋势
+ trend = self._calculate_emotion_trend(emotion_sequence)
+
+ # 计算强度变化
+ intensity_change = emotion_sequence[-1] - emotion_sequence[0]
+
+ # 检测情绪拐点
+ turning_points = self._detect_emotion_turning_points(emotion_sequence)
+
+ return {
+ "overall_trend": trend,
+ "intensity_change": intensity_change,
+ "current_intensity": emotion_sequence[-1],
+ "turning_points": turning_points,
+ "volatility": statistics.stdev(emotion_sequence) if len(emotion_sequence) > 1 else 0.0
+ }
+
+ def _calculate_emotion_score(self, text: str) -> float:
+ """计算情绪分数"""
+ positive_words = ["好", "棒", "优秀", "正确", "支持", "赞同", "有效"]
+ negative_words = ["坏", "错", "糟糕", "反对", "质疑", "问题", "失败"]
+ intense_words = ["强烈", "坚决", "绝对", "完全", "彻底"]
+
+ text_lower = text.lower()
+
+ positive_count = sum(1 for word in positive_words if word in text_lower)
+ negative_count = sum(1 for word in negative_words if word in text_lower)
+ intense_count = sum(1 for word in intense_words if word in text_lower)
+
+ base_emotion = (positive_count - negative_count) / max(len(text.split()), 1)
+ intensity_multiplier = 1 + (intense_count * 0.5)
+
+ return base_emotion * intensity_multiplier
+
+ def _calculate_emotion_trend(self, sequence: List[float]) -> str:
+ """计算情绪趋势"""
+ if len(sequence) < 2:
+ return "neutral"
+
+ # 简单线性回归估算
+ if len(sequence) < 2:
+ return 0.0
+
+ # 计算斜率
+ n = len(sequence)
+ sum_x = sum(range(n))
+ sum_y = sum(sequence)
+ sum_xy = sum(i * sequence[i] for i in range(n))
+ sum_x2 = sum(i * i for i in range(n))
+
+ slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
+
+ if slope > 0.1:
+ return "escalating"
+ elif slope < -0.1:
+ return "de_escalating"
+ else:
+ return "stable"
+
+ def _detect_emotion_turning_points(self, sequence: List[float]) -> List[int]:
+ """检测情绪拐点"""
+ if len(sequence) < 3:
+ return []
+
+ turning_points = []
+ for i in range(1, len(sequence) - 1):
+ prev_val = sequence[i-1]
+ curr_val = sequence[i]
+ next_val = sequence[i+1]
+
+ # 检测峰值和谷值
+ if (curr_val > prev_val and curr_val > next_val) or \
+ (curr_val < prev_val and curr_val < next_val):
+ turning_points.append(i)
+
+ return turning_points
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/debates/optimized_debate_flow.py b/modules/core-collaboration/src/jixia/debates/optimized_debate_flow.py
new file mode 100644
index 0000000..50bd4be
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/debates/optimized_debate_flow.py
@@ -0,0 +1,733 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+优化的辩论流程控制系统 v2.1.0
+改进阶段转换和发言权争夺逻辑
+"""
+
+import asyncio
+import json
+import time
+from datetime import datetime, timedelta
+from typing import Dict, List, Any, Optional, Tuple, Callable
+from dataclasses import dataclass, field
+from enum import Enum
+from collections import defaultdict, deque
+import threading
+import queue
+
+class DebateStage(Enum):
+ """辩论阶段枚举"""
+ QI = "起" # 八仙按先天八卦顺序
+ CHENG = "承" # 雁阵式承接
+ ZHUAN = "转" # 自由辩论(36次handoff)
+ HE = "合" # 交替总结
+
+class FlowControlMode(Enum):
+ """流程控制模式"""
+ STRICT = "严格模式" # 严格按规则执行
+ ADAPTIVE = "自适应模式" # 根据辩论质量调整
+ DYNAMIC = "动态模式" # 实时响应辩论状态
+
+class TransitionTrigger(Enum):
+ """阶段转换触发条件"""
+ TIME_BASED = "时间触发"
+ PROGRESS_BASED = "进度触发"
+ QUALITY_BASED = "质量触发"
+ CONSENSUS_BASED = "共识触发"
+ EMERGENCY = "紧急触发"
+
+class SpeakerSelectionStrategy(Enum):
+ """发言者选择策略"""
+ PRIORITY_ALGORITHM = "优先级算法"
+ ROUND_ROBIN = "轮询"
+ RANDOM_WEIGHTED = "加权随机"
+ CONTEXT_AWARE = "上下文感知"
+ COMPETITIVE = "竞争模式"
+
+@dataclass
+class FlowControlConfig:
+ """流程控制配置"""
+ mode: FlowControlMode = FlowControlMode.ADAPTIVE
+ transition_triggers: List[TransitionTrigger] = field(default_factory=lambda: [TransitionTrigger.PROGRESS_BASED, TransitionTrigger.QUALITY_BASED])
+ speaker_selection_strategy: SpeakerSelectionStrategy = SpeakerSelectionStrategy.CONTEXT_AWARE
+ min_stage_duration: int = 60 # 秒
+ max_stage_duration: int = 900 # 秒
+ quality_threshold: float = 0.6 # 质量阈值
+ participation_balance_threshold: float = 0.3 # 参与平衡阈值
+ emergency_intervention_enabled: bool = True
+ auto_stage_transition: bool = True
+ speaker_timeout: int = 30 # 发言超时时间
+
+@dataclass
+class StageMetrics:
+ """阶段指标"""
+ start_time: datetime
+ duration: float = 0.0
+ speech_count: int = 0
+ quality_score: float = 0.0
+ participation_balance: float = 0.0
+ engagement_level: float = 0.0
+ topic_coherence: float = 0.0
+ conflict_intensity: float = 0.0
+ speaker_distribution: Dict[str, int] = field(default_factory=dict)
+ transition_readiness: float = 0.0
+
+@dataclass
+class SpeakerRequest:
+ """发言请求"""
+ speaker: str
+ priority: float
+ timestamp: datetime
+ reason: str
+ urgency_level: int = 1 # 1-5
+ estimated_duration: int = 30 # 秒
+ topic_relevance: float = 1.0
+
+@dataclass
+class FlowEvent:
+ """流程事件"""
+ event_type: str
+ timestamp: datetime
+ data: Dict[str, Any]
+ source: str
+ priority: int = 1
+
+class OptimizedDebateFlowController:
+ """优化的辩论流程控制器"""
+
+ def __init__(self, config: FlowControlConfig = None):
+ self.config = config or FlowControlConfig()
+
+ # 当前状态
+ self.current_stage = DebateStage.QI
+ self.stage_progress = 0
+ self.total_handoffs = 0
+ self.current_speaker: Optional[str] = None
+ self.debate_start_time = datetime.now()
+
+ # 阶段配置
+ self.stage_configs = {
+ DebateStage.QI: {
+ "max_progress": 8,
+ "min_duration": 120,
+ "max_duration": 600,
+ "speaker_order": ["吕洞宾", "何仙姑", "铁拐李", "汉钟离", "曹国舅", "韩湘子", "蓝采和", "张果老"],
+ "selection_strategy": SpeakerSelectionStrategy.ROUND_ROBIN
+ },
+ DebateStage.CHENG: {
+ "max_progress": 8,
+ "min_duration": 180,
+ "max_duration": 600,
+ "speaker_order": ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"],
+ "selection_strategy": SpeakerSelectionStrategy.ROUND_ROBIN
+ },
+ DebateStage.ZHUAN: {
+ "max_progress": 36,
+ "min_duration": 300,
+ "max_duration": 900,
+ "speaker_order": ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"],
+ "selection_strategy": SpeakerSelectionStrategy.CONTEXT_AWARE
+ },
+ DebateStage.HE: {
+ "max_progress": 8,
+ "min_duration": 120,
+ "max_duration": 480,
+ "speaker_order": ["反1", "正1", "反2", "正2", "反3", "正3", "反4", "正4"],
+ "selection_strategy": SpeakerSelectionStrategy.ROUND_ROBIN
+ }
+ }
+
+ # 阶段指标
+ self.stage_metrics: Dict[DebateStage, StageMetrics] = {}
+ self.current_stage_metrics = StageMetrics(start_time=datetime.now())
+
+ # 发言请求队列
+ self.speaker_request_queue = queue.PriorityQueue()
+ self.pending_requests: Dict[str, SpeakerRequest] = {}
+
+ # 事件系统
+ self.event_queue = queue.Queue()
+ self.event_handlers: Dict[str, List[Callable]] = defaultdict(list)
+
+ # 历史记录
+ self.debate_history: List[Dict] = []
+ self.stage_transition_history: List[Dict] = []
+ self.speaker_performance: Dict[str, Dict] = defaultdict(dict)
+
+ # 实时监控
+ self.monitoring_active = False
+ self.monitoring_thread: Optional[threading.Thread] = None
+
+ # 流程锁
+ self.flow_lock = threading.RLock()
+
+ # 初始化当前阶段指标
+ self._initialize_stage_metrics()
+
+ def _initialize_stage_metrics(self):
+ """初始化阶段指标"""
+ self.current_stage_metrics = StageMetrics(
+ start_time=datetime.now(),
+ speaker_distribution={}
+ )
+
+ def get_current_speaker(self) -> Optional[str]:
+ """获取当前发言者"""
+ with self.flow_lock:
+ config = self.stage_configs[self.current_stage]
+ strategy = config.get("selection_strategy", self.config.speaker_selection_strategy)
+
+ if strategy == SpeakerSelectionStrategy.ROUND_ROBIN:
+ return self._get_round_robin_speaker()
+ elif strategy == SpeakerSelectionStrategy.CONTEXT_AWARE:
+ return self._get_context_aware_speaker()
+ elif strategy == SpeakerSelectionStrategy.PRIORITY_ALGORITHM:
+ return self._get_priority_speaker()
+ elif strategy == SpeakerSelectionStrategy.COMPETITIVE:
+ return self._get_competitive_speaker()
+ else:
+ return self._get_round_robin_speaker()
+
+ def _get_round_robin_speaker(self) -> str:
+ """轮询方式获取发言者"""
+ config = self.stage_configs[self.current_stage]
+ speaker_order = config["speaker_order"]
+ return speaker_order[self.stage_progress % len(speaker_order)]
+
+ def _get_context_aware_speaker(self) -> Optional[str]:
+ """上下文感知方式获取发言者"""
+ # 检查是否有紧急发言请求
+ if not self.speaker_request_queue.empty():
+ try:
+ priority, request = self.speaker_request_queue.get_nowait()
+ if request.urgency_level >= 4: # 高紧急度
+ return request.speaker
+ else:
+ # 重新放回队列
+ self.speaker_request_queue.put((priority, request))
+ except queue.Empty:
+ pass
+
+ # 分析当前上下文
+ context = self._analyze_current_context()
+
+ # 根据上下文选择最合适的发言者
+ available_speakers = self.stage_configs[self.current_stage]["speaker_order"]
+ best_speaker = None
+ best_score = -1
+
+ for speaker in available_speakers:
+ score = self._calculate_speaker_context_score(speaker, context)
+ if score > best_score:
+ best_score = score
+ best_speaker = speaker
+
+ return best_speaker
+
+ def _get_priority_speaker(self) -> Optional[str]:
+ """优先级算法获取发言者"""
+ # 这里可以集成现有的优先级算法
+ # 暂时使用简化版本
+ return self._get_context_aware_speaker()
+
+ def _get_competitive_speaker(self) -> Optional[str]:
+ """竞争模式获取发言者"""
+ # 让发言者竞争发言权
+ if not self.speaker_request_queue.empty():
+ try:
+ priority, request = self.speaker_request_queue.get_nowait()
+ return request.speaker
+ except queue.Empty:
+ pass
+
+ return self._get_round_robin_speaker()
+
+ def request_speaking_turn(self, speaker: str, reason: str, urgency: int = 1,
+ estimated_duration: int = 30, topic_relevance: float = 1.0):
+ """请求发言权"""
+ request = SpeakerRequest(
+ speaker=speaker,
+ priority=self._calculate_request_priority(speaker, reason, urgency, topic_relevance),
+ timestamp=datetime.now(),
+ reason=reason,
+ urgency_level=urgency,
+ estimated_duration=estimated_duration,
+ topic_relevance=topic_relevance
+ )
+
+ # 使用负优先级,因为PriorityQueue是最小堆
+ self.speaker_request_queue.put((-request.priority, request))
+ self.pending_requests[speaker] = request
+
+ # 触发事件
+ self._emit_event("speaker_request", {
+ "speaker": speaker,
+ "reason": reason,
+ "urgency": urgency,
+ "priority": request.priority
+ })
+
+ def _calculate_request_priority(self, speaker: str, reason: str, urgency: int,
+ topic_relevance: float) -> float:
+ """计算发言请求优先级"""
+ base_priority = urgency * 10
+
+ # 主题相关性加权
+ relevance_bonus = topic_relevance * 5
+
+ # 发言频率调整
+ speaker_count = self.current_stage_metrics.speaker_distribution.get(speaker, 0)
+ frequency_penalty = speaker_count * 2
+
+ # 时间因素
+ time_factor = 1.0
+ if self.current_speaker and self.current_speaker != speaker:
+ time_factor = 1.2 # 鼓励轮换
+
+ priority = (base_priority + relevance_bonus - frequency_penalty) * time_factor
+ return max(0.1, priority)
+
+ def _analyze_current_context(self) -> Dict[str, Any]:
+ """分析当前辩论上下文"""
+ recent_speeches = self.debate_history[-5:] if self.debate_history else []
+
+ context = {
+ "stage": self.current_stage.value,
+ "progress": self.stage_progress,
+ "recent_speakers": [speech.get("speaker") for speech in recent_speeches],
+ "topic_drift": self._calculate_topic_drift(),
+ "emotional_intensity": self._calculate_emotional_intensity(),
+ "argument_balance": self._calculate_argument_balance(),
+ "time_pressure": self._calculate_time_pressure(),
+ "participation_balance": self._calculate_participation_balance()
+ }
+
+ return context
+
+ def _calculate_speaker_context_score(self, speaker: str, context: Dict[str, Any]) -> float:
+ """计算发言者在当前上下文下的适合度分数"""
+ score = 0.0
+
+ # 避免连续发言
+ recent_speakers = context.get("recent_speakers", [])
+ if speaker in recent_speakers[-2:]:
+ score -= 10
+
+ # 参与平衡
+ speaker_count = self.current_stage_metrics.speaker_distribution.get(speaker, 0)
+ avg_count = sum(self.current_stage_metrics.speaker_distribution.values()) / max(1, len(self.current_stage_metrics.speaker_distribution))
+ if speaker_count < avg_count:
+ score += 5
+
+ # 队伍平衡
+ if self.current_stage == DebateStage.ZHUAN:
+ positive_count = sum(1 for s in recent_speakers if "正" in s)
+ negative_count = sum(1 for s in recent_speakers if "反" in s)
+
+ if "正" in speaker and positive_count < negative_count:
+ score += 3
+ elif "反" in speaker and negative_count < positive_count:
+ score += 3
+
+ # 时间压力响应
+ time_pressure = context.get("time_pressure", 0)
+ if time_pressure > 0.7 and speaker.endswith("1"): # 主力发言者
+ score += 5
+
+ # 检查发言请求
+ if speaker in self.pending_requests:
+ request = self.pending_requests[speaker]
+ score += request.urgency_level * 2
+ score += request.topic_relevance * 3
+
+ return score
+
+ def advance_stage(self, force: bool = False) -> bool:
+ """推进辩论阶段"""
+ with self.flow_lock:
+ if not force and not self._should_advance_stage():
+ return False
+
+ # 记录当前阶段结束
+ self._finalize_current_stage()
+
+ # 转换到下一阶段
+ success = self._transition_to_next_stage()
+
+ if success:
+ # 初始化新阶段
+ self._initialize_new_stage()
+
+ # 触发事件
+ self._emit_event("stage_advanced", {
+ "from_stage": self.current_stage.value,
+ "to_stage": self.current_stage.value,
+ "progress": self.stage_progress,
+ "forced": force
+ })
+
+ return success
+
+ def _should_advance_stage(self) -> bool:
+ """判断是否应该推进阶段"""
+ config = self.stage_configs[self.current_stage]
+
+ # 检查进度触发
+ if TransitionTrigger.PROGRESS_BASED in self.config.transition_triggers:
+ if self.stage_progress >= config["max_progress"] - 1:
+ return True
+
+ # 检查时间触发
+ if TransitionTrigger.TIME_BASED in self.config.transition_triggers:
+ stage_duration = (datetime.now() - self.current_stage_metrics.start_time).total_seconds()
+ if stage_duration >= config.get("max_duration", 600):
+ return True
+
+ # 检查质量触发
+ if TransitionTrigger.QUALITY_BASED in self.config.transition_triggers:
+ if (self.current_stage_metrics.quality_score >= self.config.quality_threshold and
+ self.stage_progress >= config["max_progress"] // 2):
+ return True
+
+ # 检查共识触发
+ if TransitionTrigger.CONSENSUS_BASED in self.config.transition_triggers:
+ if self.current_stage_metrics.transition_readiness >= 0.8:
+ return True
+
+ return False
+
+ def _finalize_current_stage(self):
+ """结束当前阶段"""
+ # 更新阶段指标
+ self.current_stage_metrics.duration = (datetime.now() - self.current_stage_metrics.start_time).total_seconds()
+
+ # 保存阶段指标
+ self.stage_metrics[self.current_stage] = self.current_stage_metrics
+
+ # 记录阶段转换历史
+ self.stage_transition_history.append({
+ "stage": self.current_stage.value,
+ "start_time": self.current_stage_metrics.start_time.isoformat(),
+ "duration": self.current_stage_metrics.duration,
+ "speech_count": self.current_stage_metrics.speech_count,
+ "quality_score": self.current_stage_metrics.quality_score,
+ "participation_balance": self.current_stage_metrics.participation_balance
+ })
+
+ def _transition_to_next_stage(self) -> bool:
+ """转换到下一阶段"""
+ stage_transitions = {
+ DebateStage.QI: DebateStage.CHENG,
+ DebateStage.CHENG: DebateStage.ZHUAN,
+ DebateStage.ZHUAN: DebateStage.HE,
+ DebateStage.HE: None
+ }
+
+ next_stage = stage_transitions.get(self.current_stage)
+ if next_stage:
+ self.current_stage = next_stage
+ self.stage_progress = 0
+ return True
+ else:
+ # 辩论结束
+ self._emit_event("debate_finished", {
+ "total_duration": (datetime.now() - self.debate_start_time).total_seconds(),
+ "total_handoffs": self.total_handoffs,
+ "stages_completed": len(self.stage_metrics)
+ })
+ return False
+
+ def _initialize_new_stage(self):
+ """初始化新阶段"""
+ self._initialize_stage_metrics()
+
+ # 清空发言请求队列
+ while not self.speaker_request_queue.empty():
+ try:
+ self.speaker_request_queue.get_nowait()
+ except queue.Empty:
+ break
+
+ self.pending_requests.clear()
+
+ def record_speech(self, speaker: str, message: str, metadata: Dict[str, Any] = None):
+ """记录发言"""
+ with self.flow_lock:
+ speech_record = {
+ "timestamp": datetime.now().isoformat(),
+ "stage": self.current_stage.value,
+ "stage_progress": self.stage_progress,
+ "speaker": speaker,
+ "message": message,
+ "total_handoffs": self.total_handoffs,
+ "metadata": metadata or {}
+ }
+
+ self.debate_history.append(speech_record)
+ self.current_speaker = speaker
+
+ # 更新阶段指标
+ self._update_stage_metrics(speaker, message)
+
+ # 如果是转阶段,增加handoff计数
+ if self.current_stage == DebateStage.ZHUAN:
+ self.total_handoffs += 1
+
+ # 推进进度
+ self.stage_progress += 1
+
+ # 移除已完成的发言请求
+ if speaker in self.pending_requests:
+ del self.pending_requests[speaker]
+
+ # 触发事件
+ self._emit_event("speech_recorded", {
+ "speaker": speaker,
+ "stage": self.current_stage.value,
+ "progress": self.stage_progress
+ })
+
+ def _update_stage_metrics(self, speaker: str, message: str):
+ """更新阶段指标"""
+ # 更新发言计数
+ self.current_stage_metrics.speech_count += 1
+
+ # 更新发言者分布
+ if speaker not in self.current_stage_metrics.speaker_distribution:
+ self.current_stage_metrics.speaker_distribution[speaker] = 0
+ self.current_stage_metrics.speaker_distribution[speaker] += 1
+
+ # 计算参与平衡度
+ self.current_stage_metrics.participation_balance = self._calculate_participation_balance()
+
+ # 计算质量分数(简化版本)
+ self.current_stage_metrics.quality_score = self._calculate_quality_score(message)
+
+ # 计算转换准备度
+ self.current_stage_metrics.transition_readiness = self._calculate_transition_readiness()
+
+ def _calculate_topic_drift(self) -> float:
+ """计算主题偏移度"""
+ # 简化实现
+ return 0.1
+
+ def _calculate_emotional_intensity(self) -> float:
+ """计算情绪强度"""
+ # 简化实现
+ return 0.5
+
+ def _calculate_argument_balance(self) -> float:
+ """计算论点平衡度"""
+ # 简化实现
+ return 0.7
+
+ def _calculate_time_pressure(self) -> float:
+ """计算时间压力"""
+ config = self.stage_configs[self.current_stage]
+ stage_duration = (datetime.now() - self.current_stage_metrics.start_time).total_seconds()
+ max_duration = config.get("max_duration", 600)
+ return min(1.0, stage_duration / max_duration)
+
+ def _calculate_participation_balance(self) -> float:
+ """计算参与平衡度"""
+ if not self.current_stage_metrics.speaker_distribution:
+ return 1.0
+
+ counts = list(self.current_stage_metrics.speaker_distribution.values())
+ if not counts:
+ return 1.0
+
+ avg_count = sum(counts) / len(counts)
+ variance = sum((count - avg_count) ** 2 for count in counts) / len(counts)
+
+ # 归一化到0-1范围
+ balance = 1.0 / (1.0 + variance)
+ return balance
+
+ def _calculate_quality_score(self, message: str) -> float:
+ """计算质量分数"""
+ # 简化实现,基于消息长度和关键词
+ base_score = min(1.0, len(message) / 100)
+
+ # 检查关键词
+ quality_keywords = ["因为", "所以", "但是", "然而", "数据", "证据", "分析"]
+ keyword_bonus = sum(0.1 for keyword in quality_keywords if keyword in message)
+
+ return min(1.0, base_score + keyword_bonus)
+
+ def _calculate_transition_readiness(self) -> float:
+ """计算转换准备度"""
+ # 综合多个因素
+ progress_factor = self.stage_progress / self.stage_configs[self.current_stage]["max_progress"]
+ quality_factor = self.current_stage_metrics.quality_score
+ balance_factor = self.current_stage_metrics.participation_balance
+
+ readiness = (progress_factor * 0.4 + quality_factor * 0.3 + balance_factor * 0.3)
+ return min(1.0, readiness)
+
+ def _emit_event(self, event_type: str, data: Dict[str, Any]):
+ """发出事件"""
+ event = FlowEvent(
+ event_type=event_type,
+ timestamp=datetime.now(),
+ data=data,
+ source="flow_controller"
+ )
+
+ self.event_queue.put(event)
+
+ # 调用事件处理器
+ for handler in self.event_handlers.get(event_type, []):
+ try:
+ handler(event)
+ except Exception as e:
+ print(f"事件处理器错误: {e}")
+
+ def add_event_handler(self, event_type: str, handler: Callable):
+ """添加事件处理器"""
+ self.event_handlers[event_type].append(handler)
+
+ def get_flow_status(self) -> Dict[str, Any]:
+ """获取流程状态"""
+ return {
+ "current_stage": self.current_stage.value,
+ "stage_progress": self.stage_progress,
+ "total_handoffs": self.total_handoffs,
+ "current_speaker": self.current_speaker,
+ "stage_metrics": {
+ "duration": (datetime.now() - self.current_stage_metrics.start_time).total_seconds(),
+ "speech_count": self.current_stage_metrics.speech_count,
+ "quality_score": self.current_stage_metrics.quality_score,
+ "participation_balance": self.current_stage_metrics.participation_balance,
+ "transition_readiness": self.current_stage_metrics.transition_readiness
+ },
+ "pending_requests": len(self.pending_requests),
+ "config": {
+ "mode": self.config.mode.value,
+ "auto_transition": self.config.auto_stage_transition,
+ "quality_threshold": self.config.quality_threshold
+ }
+ }
+
+ def save_flow_data(self, filename: str = "debate_flow_data.json"):
+ """保存流程数据"""
+ flow_data = {
+ "config": {
+ "mode": self.config.mode.value,
+ "transition_triggers": [t.value for t in self.config.transition_triggers],
+ "speaker_selection_strategy": self.config.speaker_selection_strategy.value,
+ "quality_threshold": self.config.quality_threshold,
+ "auto_stage_transition": self.config.auto_stage_transition
+ },
+ "current_state": {
+ "stage": self.current_stage.value,
+ "progress": self.stage_progress,
+ "total_handoffs": self.total_handoffs,
+ "current_speaker": self.current_speaker,
+ "debate_start_time": self.debate_start_time.isoformat()
+ },
+ "stage_metrics": {
+ stage.value: {
+ "start_time": metrics.start_time.isoformat(),
+ "duration": metrics.duration,
+ "speech_count": metrics.speech_count,
+ "quality_score": metrics.quality_score,
+ "participation_balance": metrics.participation_balance,
+ "speaker_distribution": metrics.speaker_distribution
+ } for stage, metrics in self.stage_metrics.items()
+ },
+ "current_stage_metrics": {
+ "start_time": self.current_stage_metrics.start_time.isoformat(),
+ "duration": (datetime.now() - self.current_stage_metrics.start_time).total_seconds(),
+ "speech_count": self.current_stage_metrics.speech_count,
+ "quality_score": self.current_stage_metrics.quality_score,
+ "participation_balance": self.current_stage_metrics.participation_balance,
+ "speaker_distribution": self.current_stage_metrics.speaker_distribution,
+ "transition_readiness": self.current_stage_metrics.transition_readiness
+ },
+ "debate_history": self.debate_history,
+ "stage_transition_history": self.stage_transition_history,
+ "timestamp": datetime.now().isoformat()
+ }
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(flow_data, f, ensure_ascii=False, indent=2)
+
+ print(f"✅ 流程数据已保存到 {filename}")
+
+def main():
+ """测试优化的辩论流程控制系统"""
+ print("🎭 测试优化的辩论流程控制系统")
+ print("=" * 50)
+
+ # 创建配置
+ config = FlowControlConfig(
+ mode=FlowControlMode.ADAPTIVE,
+ transition_triggers=[TransitionTrigger.PROGRESS_BASED, TransitionTrigger.QUALITY_BASED],
+ speaker_selection_strategy=SpeakerSelectionStrategy.CONTEXT_AWARE,
+ auto_stage_transition=True
+ )
+
+ # 创建流程控制器
+ controller = OptimizedDebateFlowController(config)
+
+ # 添加事件处理器
+ def on_stage_advanced(event):
+ print(f"🎭 阶段转换: {event.data}")
+
+ def on_speech_recorded(event):
+ print(f"🗣️ 发言记录: {event.data['speaker']} 在 {event.data['stage']} 阶段")
+
+ controller.add_event_handler("stage_advanced", on_stage_advanced)
+ controller.add_event_handler("speech_recorded", on_speech_recorded)
+
+ # 模拟辩论流程
+ test_speeches = [
+ ("吕洞宾", "我认为AI投资具有巨大的潜力和机会。"),
+ ("何仙姑", "但我们也需要考虑其中的风险因素。"),
+ ("铁拐李", "数据显示AI行业的增长率确实很高。"),
+ ("汉钟离", "然而市场波动性也不容忽视。")
+ ]
+
+ print("\n📋 开始模拟辩论流程")
+ print("-" * 30)
+
+ for i, (speaker, message) in enumerate(test_speeches):
+ print(f"\n第 {i+1} 轮发言:")
+
+ # 获取当前发言者
+ current_speaker = controller.get_current_speaker()
+ print(f"推荐发言者: {current_speaker}")
+
+ # 记录发言
+ controller.record_speech(speaker, message)
+
+ # 显示流程状态
+ status = controller.get_flow_status()
+ print(f"当前状态: {status['current_stage']} 阶段,进度 {status['stage_progress']}")
+ print(f"质量分数: {status['stage_metrics']['quality_score']:.3f}")
+ print(f"参与平衡: {status['stage_metrics']['participation_balance']:.3f}")
+
+ # 检查是否需要推进阶段
+ if controller._should_advance_stage():
+ print("🔄 准备推进到下一阶段")
+ controller.advance_stage()
+
+ # 测试发言请求
+ print("\n📢 测试发言请求系统")
+ print("-" * 30)
+
+ controller.request_speaking_turn("正1", "需要反驳对方观点", urgency=4, topic_relevance=0.9)
+ controller.request_speaking_turn("反2", "补充论据", urgency=2, topic_relevance=0.7)
+
+ next_speaker = controller.get_current_speaker()
+ print(f"基于请求的下一位发言者: {next_speaker}")
+
+ # 保存数据
+ controller.save_flow_data("test_flow_data.json")
+
+ print("\n✅ 测试完成")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/debates/qi_cheng_zhuan_he_debate.py b/modules/core-collaboration/src/jixia/debates/qi_cheng_zhuan_he_debate.py
new file mode 100644
index 0000000..d99f23e
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/debates/qi_cheng_zhuan_he_debate.py
@@ -0,0 +1,335 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+太公心易 - 起承转合辩论系统
+基于先天八卦的八仙辩论架构
+"""
+
+import asyncio
+import json
+from datetime import datetime
+from typing import Dict, List, Any, Optional
+from dataclasses import dataclass
+from enum import Enum
+import sys
+import os
+sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+from enhanced_priority_algorithm import EnhancedPriorityAlgorithm, SpeechAnalysis
+
+class DebateStage(Enum):
+ """辩论阶段枚举"""
+ QI = "起" # 八仙按先天八卦顺序
+ CHENG = "承" # 雁阵式承接
+ ZHUAN = "转" # 自由辩论(36次handoff)
+ HE = "合" # 交替总结
+
+@dataclass
+class Speaker:
+ """发言者数据类"""
+ name: str
+ role: str
+ team: str # "positive" or "negative"
+ bagua_position: Optional[int] = None # 八卦位置(0-7)
+
+@dataclass
+class DebateContext:
+ """辩论上下文"""
+ current_stage: DebateStage
+ stage_progress: int
+ total_handoffs: int
+ current_speaker: Optional[str] = None
+ last_message: Optional[str] = None
+ debate_history: List[Dict] = None
+ last_priority_analysis: Optional[Dict[str, Any]] = None
+
+class QiChengZhuanHeDebateSystem:
+ """起承转合辩论系统"""
+
+ def __init__(self):
+ # 八仙配置(按先天八卦顺序)
+ self.baxian_speakers = {
+ "吕洞宾": Speaker("吕洞宾", "剑仙投资顾问", "neutral", 0), # 乾
+ "何仙姑": Speaker("何仙姑", "慈悲风控专家", "neutral", 1), # 兑
+ "铁拐李": Speaker("铁拐李", "逆向思维专家", "neutral", 2), # 离
+ "汉钟离": Speaker("汉钟离", "平衡协调者", "neutral", 3), # 震
+ "蓝采和": Speaker("蓝采和", "创新思维者", "neutral", 4), # 巽
+ "张果老": Speaker("张果老", "历史智慧者", "neutral", 5), # 坎
+ "韩湘子": Speaker("韩湘子", "艺术感知者", "neutral", 6), # 艮
+ "曹国舅": Speaker("曹国舅", "实务执行者", "neutral", 7) # 坤
+ }
+
+ # 雁阵队伍配置
+ self.goose_formation = {
+ "positive": ["正1", "正2", "正3", "正4"],
+ "negative": ["反1", "反2", "反3", "反4"]
+ }
+
+ # 辩论状态
+ self.context = DebateContext(
+ current_stage=DebateStage.QI,
+ stage_progress=0,
+ total_handoffs=0,
+ debate_history=[]
+ )
+
+ # 阶段配置
+ self.stage_configs = {
+ DebateStage.QI: {
+ "duration": "8-10分钟",
+ "max_progress": 8, # 八仙轮流发言
+ "description": "八仙按先天八卦顺序阐述观点"
+ },
+ DebateStage.CHENG: {
+ "duration": "8-10分钟",
+ "max_progress": 8, # 正反各4人
+ "description": "雁阵式承接,总体阐述+讥讽"
+ },
+ DebateStage.ZHUAN: {
+ "duration": "12-15分钟",
+ "max_progress": 36, # 36次handoff
+ "description": "自由辩论,优先级算法决定发言"
+ },
+ DebateStage.HE: {
+ "duration": "8-10分钟",
+ "max_progress": 8, # 交替总结
+ "description": "交替总结,最终论证"
+ }
+ }
+
+ # 增强版优先级算法
+ self.priority_algorithm = EnhancedPriorityAlgorithm()
+
+ # 记忆系统
+ self.memory_system = DebateMemorySystem()
+
+ def get_current_speaker(self) -> str:
+ """获取当前发言者"""
+ stage = self.context.current_stage
+ progress = self.context.stage_progress
+
+ if stage == DebateStage.QI:
+ return self._get_bagua_speaker(progress)
+ elif stage == DebateStage.CHENG:
+ return self._get_goose_formation_speaker(progress)
+ elif stage == DebateStage.ZHUAN:
+ return self._get_priority_speaker()
+ elif stage == DebateStage.HE:
+ return self._get_alternating_speaker(progress)
+
+ return "未知发言者"
+
+ def _get_bagua_speaker(self, progress: int) -> str:
+ """获取八卦顺序发言者"""
+ bagua_sequence = ["吕洞宾", "何仙姑", "铁拐李", "汉钟离", "蓝采和", "张果老", "韩湘子", "曹国舅"]
+ return bagua_sequence[progress % 8]
+
+ def _get_goose_formation_speaker(self, progress: int) -> str:
+ """获取雁阵发言者"""
+ if progress < 4:
+ # 正方雁阵
+ return self.goose_formation["positive"][progress]
+ else:
+ # 反方雁阵
+ return self.goose_formation["negative"][progress - 4]
+
+ def _get_priority_speaker(self) -> str:
+ """获取优先级发言者(转阶段)"""
+ available_speakers = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
+
+ # 构建上下文
+ context = {
+ "current_stage": self.context.current_stage.value,
+ "stage_progress": self.context.stage_progress,
+ "max_progress": self.stage_configs[self.context.current_stage]["max_progress"],
+ "time_remaining": max(0.1, 1.0 - (self.context.stage_progress / self.stage_configs[self.context.current_stage]["max_progress"])),
+ "topic_keywords": ["投资", "AI", "风险", "收益"], # 可配置
+ "positive_team_score": 0.5, # 可动态计算
+ "negative_team_score": 0.5, # 可动态计算
+ "positive_recent_speeches": len([h for h in self.context.debate_history[-10:] if "正" in h.get("speaker", "")]),
+ "negative_recent_speeches": len([h for h in self.context.debate_history[-10:] if "反" in h.get("speaker", "")])
+ }
+
+ # 获取最近发言历史
+ recent_speeches = self.context.debate_history[-10:] if self.context.debate_history else []
+
+ next_speaker, score, analysis = self.priority_algorithm.get_next_speaker(
+ available_speakers, context, recent_speeches
+ )
+
+ # 记录分析结果
+ self.context.last_priority_analysis = {
+ "recommended_speaker": next_speaker,
+ "priority_score": score,
+ "analysis": analysis,
+ "timestamp": datetime.now().isoformat()
+ }
+
+ return next_speaker
+
+ def _get_alternating_speaker(self, progress: int) -> str:
+ """获取交替总结发言者"""
+ alternating_sequence = ["反1", "正1", "反2", "正2", "反3", "正3", "反4", "正4"]
+ return alternating_sequence[progress % 8]
+
+ def advance_stage(self):
+ """推进辩论阶段"""
+ current_config = self.stage_configs[self.context.current_stage]
+
+ if self.context.stage_progress >= current_config["max_progress"] - 1:
+ # 当前阶段完成,进入下一阶段
+ self._transition_to_next_stage()
+ else:
+ # 当前阶段继续
+ self.context.stage_progress += 1
+
+ def _transition_to_next_stage(self):
+ """转换到下一阶段"""
+ stage_transitions = {
+ DebateStage.QI: DebateStage.CHENG,
+ DebateStage.CHENG: DebateStage.ZHUAN,
+ DebateStage.ZHUAN: DebateStage.HE,
+ DebateStage.HE: None # 辩论结束
+ }
+
+ next_stage = stage_transitions[self.context.current_stage]
+ if next_stage:
+ self.context.current_stage = next_stage
+ self.context.stage_progress = 0
+ print(f"🎭 辩论进入{next_stage.value}阶段")
+ else:
+ print("🎉 辩论结束!")
+
+ def record_speech(self, speaker: str, message: str):
+ """记录发言"""
+ speech_record = {
+ "timestamp": datetime.now().isoformat(),
+ "stage": self.context.current_stage.value,
+ "stage_progress": self.context.stage_progress,
+ "speaker": speaker,
+ "message": message,
+ "total_handoffs": self.context.total_handoffs
+ }
+
+ self.context.debate_history.append(speech_record)
+ self.context.last_message = message
+ self.context.current_speaker = speaker
+
+ # 更新记忆系统
+ self.memory_system.store_speech(speaker, message, self.context)
+
+ # 如果是转阶段,增加handoff计数
+ if self.context.current_stage == DebateStage.ZHUAN:
+ self.context.total_handoffs += 1
+
+ def get_stage_info(self) -> Dict[str, Any]:
+ """获取当前阶段信息"""
+ stage = self.context.current_stage
+ config = self.stage_configs[stage]
+
+ return {
+ "current_stage": stage.value,
+ "stage_progress": self.context.stage_progress,
+ "max_progress": config["max_progress"],
+ "description": config["description"],
+ "current_speaker": self.get_current_speaker(),
+ "total_handoffs": self.context.total_handoffs
+ }
+
+ def save_debate_state(self, filename: str = "debate_state.json"):
+ """保存辩论状态"""
+ state_data = {
+ "context": {
+ "current_stage": self.context.current_stage.value,
+ "stage_progress": self.context.stage_progress,
+ "total_handoffs": self.context.total_handoffs,
+ "current_speaker": self.context.current_speaker,
+ "last_message": self.context.last_message
+ },
+ "debate_history": self.context.debate_history,
+ "memory_data": self.memory_system.get_memory_data()
+ }
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(state_data, f, ensure_ascii=False, indent=2)
+
+ print(f"💾 辩论状态已保存到 {filename}")
+
+# 旧的PriorityAlgorithm类已被EnhancedPriorityAlgorithm替换
+
+class DebateMemorySystem:
+ """辩论记忆系统"""
+
+ def __init__(self):
+ self.speaker_memories = {}
+ self.debate_memories = []
+
+ def store_speech(self, speaker: str, message: str, context: DebateContext):
+ """存储发言记忆"""
+ if speaker not in self.speaker_memories:
+ self.speaker_memories[speaker] = []
+
+ memory_entry = {
+ "timestamp": datetime.now().isoformat(),
+ "stage": context.current_stage.value,
+ "message": message,
+ "context": {
+ "stage_progress": context.stage_progress,
+ "total_handoffs": context.total_handoffs
+ }
+ }
+
+ self.speaker_memories[speaker].append(memory_entry)
+ self.debate_memories.append(memory_entry)
+
+ def get_speaker_memory(self, speaker: str, limit: int = 5) -> List[Dict]:
+ """获取发言者记忆"""
+ if speaker in self.speaker_memories:
+ return self.speaker_memories[speaker][-limit:]
+ return []
+
+ def get_memory_data(self) -> Dict[str, Any]:
+ """获取记忆数据"""
+ return {
+ "speaker_memories": self.speaker_memories,
+ "debate_memories": self.debate_memories
+ }
+
+def main():
+ """主函数 - 测试起承转合辩论系统"""
+ print("🚀 太公心易 - 起承转合辩论系统")
+ print("=" * 60)
+
+ # 创建辩论系统
+ debate_system = QiChengZhuanHeDebateSystem()
+
+ # 测试各阶段
+ test_messages = [
+ "起:八仙按先天八卦顺序阐述观点",
+ "承:雁阵式承接,总体阐述+讥讽",
+ "转:自由辩论,36次handoff",
+ "合:交替总结,最终论证"
+ ]
+
+ for i, message in enumerate(test_messages):
+ stage_info = debate_system.get_stage_info()
+ current_speaker = debate_system.get_current_speaker()
+
+ print(f"\n🎭 当前阶段: {stage_info['current_stage']}")
+ print(f"📊 进度: {stage_info['stage_progress'] + 1}/{stage_info['max_progress']}")
+ print(f"🗣️ 发言者: {current_speaker}")
+ print(f"💬 消息: {message}")
+
+ # 记录发言
+ debate_system.record_speech(current_speaker, message)
+
+ # 推进阶段
+ debate_system.advance_stage()
+
+ # 保存状态
+ debate_system.save_debate_state()
+
+ print("\n✅ 起承转合辩论系统测试完成!")
+
+if __name__ == "__main__":
+ main()
+
diff --git a/modules/core-collaboration/src/jixia/engines/__init__.py b/modules/core-collaboration/src/jixia/engines/__init__.py
new file mode 100644
index 0000000..d226a4a
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/__init__.py
@@ -0,0 +1 @@
+# 稷下学宫引擎模块
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/baxian_data_mapping.py b/modules/core-collaboration/src/jixia/engines/baxian_data_mapping.py
new file mode 100644
index 0000000..8abdf90
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/baxian_data_mapping.py
@@ -0,0 +1,43 @@
+# 设计八仙与数据源的智能映射
+immortal_data_mapping = {
+ '吕洞宾': {
+ 'specialty': 'technical_analysis', # 技术分析专家
+ 'preferred_data_types': ['historical', 'price'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ },
+ '何仙姑': {
+ 'specialty': 'risk_metrics', # 风险控制专家
+ 'preferred_data_types': ['price', 'profile'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '张果老': {
+ 'specialty': 'historical_data', # 历史数据分析师
+ 'preferred_data_types': ['historical'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ },
+ '韩湘子': {
+ 'specialty': 'sector_analysis', # 新兴资产专家
+ 'preferred_data_types': ['profile', 'news'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '汉钟离': {
+ 'specialty': 'market_movers', # 热点追踪
+ 'preferred_data_types': ['news', 'price'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '蓝采和': {
+ 'specialty': 'value_discovery', # 潜力股发现
+ 'preferred_data_types': ['screener', 'profile'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ },
+ '铁拐李': {
+ 'specialty': 'contrarian_analysis', # 逆向思维专家
+ 'preferred_data_types': ['profile', 'short_interest'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '曹国舅': {
+ 'specialty': 'macro_economics', # 宏观经济分析师
+ 'preferred_data_types': ['profile', 'institutional_holdings'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ }
+}
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/data_abstraction.py b/modules/core-collaboration/src/jixia/engines/data_abstraction.py
new file mode 100644
index 0000000..57e5981
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/data_abstraction.py
@@ -0,0 +1,38 @@
+from abc import ABC, abstractmethod
+from typing import List, Optional
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+
+class DataProvider(ABC):
+ """金融数据提供商抽象基类"""
+
+ @abstractmethod
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ """获取股票报价"""
+ pass
+
+ @abstractmethod
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ """获取历史价格数据"""
+ pass
+
+ @abstractmethod
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ """获取公司概况"""
+ pass
+
+ @abstractmethod
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ """获取相关新闻"""
+ pass
+
+ @property
+ @abstractmethod
+ def name(self) -> str:
+ """数据提供商名称"""
+ pass
+
+ @property
+ @abstractmethod
+ def priority(self) -> int:
+ """优先级(数字越小优先级越高)"""
+ pass
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/data_abstraction_layer.py b/modules/core-collaboration/src/jixia/engines/data_abstraction_layer.py
new file mode 100644
index 0000000..d8934a2
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/data_abstraction_layer.py
@@ -0,0 +1,109 @@
+ from typing import List, Optional
+import asyncio
+from src.jixia.engines.data_abstraction import DataProvider
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+from src.jixia.engines.rapidapi_adapter import RapidAPIDataProvider
+from src.jixia.engines.openbb_adapter import OpenBBDataProvider
+
+class DataAbstractionLayer:
+ """金融数据抽象层管理器"""
+
+ def __init__(self):
+ self.providers: List[DataProvider] = []
+ self._initialize_providers()
+
+ def _initialize_providers(self):
+ """初始化所有可用的数据提供商"""
+ # 根据配置和环境动态加载适配器
+ try:
+ self.providers.append(OpenBBDataProvider())
+ except Exception as e:
+ print(f"警告: OpenBBDataProvider 初始化失败: {e}")
+
+ try:
+ self.providers.append(RapidAPIDataProvider())
+ except Exception as e:
+ print(f"警告: RapidAPIDataProvider 初始化失败: {e}")
+
+ # 按优先级排序
+ self.providers.sort(key=lambda p: p.priority)
+ print(f"数据抽象层初始化完成,已加载 {len(self.providers)} 个数据提供商")
+ for provider in self.providers:
+ print(f" - {provider.name} (优先级: {provider.priority})")
+
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ """获取股票报价(带故障转移)"""
+ for provider in self.providers:
+ try:
+ quote = provider.get_quote(symbol)
+ if quote:
+ print(f"✅ 通过 {provider.name} 获取到 {symbol} 的报价")
+ return quote
+ except Exception as e:
+ print(f"警告: {provider.name} 获取报价失败: {e}")
+ continue
+ print(f"❌ 所有数据提供商都无法获取 {symbol} 的报价")
+ return None
+
+ async def get_quote_async(self, symbol: str) -> Optional[StockQuote]:
+ """异步获取股票报价(带故障转移)"""
+ for provider in self.providers:
+ try:
+ # 如果提供商支持异步方法,则使用异步方法
+ if hasattr(provider, 'get_quote_async'):
+ quote = await provider.get_quote_async(symbol)
+ else:
+ # 否则在执行器中运行同步方法
+ quote = await asyncio.get_event_loop().run_in_executor(
+ None, provider.get_quote, symbol
+ )
+ if quote:
+ print(f"✅ 通过 {provider.name} 异步获取到 {symbol} 的报价")
+ return quote
+ except Exception as e:
+ print(f"警告: {provider.name} 异步获取报价失败: {e}")
+ continue
+ print(f"❌ 所有数据提供商都无法异步获取 {symbol} 的报价")
+ return None
+
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ """获取历史价格数据(带故障转移)"""
+ for provider in self.providers:
+ try:
+ prices = provider.get_historical_prices(symbol, days)
+ if prices:
+ print(f"✅ 通过 {provider.name} 获取到 {symbol} 的历史价格数据")
+ return prices
+ except Exception as e:
+ print(f"警告: {provider.name} 获取历史价格失败: {e}")
+ continue
+ print(f"❌ 所有数据提供商都无法获取 {symbol} 的历史价格数据")
+ return []
+
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ """获取公司概况(带故障转移)"""
+ for provider in self.providers:
+ try:
+ profile = provider.get_company_profile(symbol)
+ if profile:
+ print(f"✅ 通过 {provider.name} 获取到 {symbol} 的公司概况")
+ return profile
+ except Exception as e:
+ print(f"警告: {provider.name} 获取公司概况失败: {e}")
+ continue
+ print(f"❌ 所有数据提供商都无法获取 {symbol} 的公司概况")
+ return None
+
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ """获取相关新闻(带故障转移)"""
+ for provider in self.providers:
+ try:
+ news = provider.get_news(symbol, limit)
+ if news:
+ print(f"✅ 通过 {provider.name} 获取到 {symbol} 的相关新闻")
+ return news
+ except Exception as e:
+ print(f"警告: {provider.name} 获取新闻失败: {e}")
+ continue
+ print(f"❌ 所有数据提供商都无法获取 {symbol} 的相关新闻")
+ return []
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/data_cache.py b/modules/core-collaboration/src/jixia/engines/data_cache.py
new file mode 100644
index 0000000..7497d1e
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/data_cache.py
@@ -0,0 +1,37 @@
+import time
+from typing import Any, Optional
+from functools import lru_cache
+
+class DataCache:
+ """金融数据缓存"""
+
+ def __init__(self):
+ self._cache = {}
+ self._cache_times = {}
+ self.default_ttl = 60 # 默认缓存时间(秒)
+
+ def get(self, key: str) -> Optional[Any]:
+ """获取缓存数据"""
+ if key in self._cache:
+ # 检查是否过期
+ if time.time() - self._cache_times[key] < self.default_ttl:
+ return self._cache[key]
+ else:
+ # 删除过期缓存
+ del self._cache[key]
+ del self._cache_times[key]
+ return None
+
+ def set(self, key: str, value: Any, ttl: Optional[int] = None):
+ """设置缓存数据"""
+ self._cache[key] = value
+ self._cache_times[key] = time.time()
+ if ttl:
+ # 可以为特定数据设置不同的TTL
+ pass # 实际实现中需要更复杂的TTL管理机制
+
+ @lru_cache(maxsize=128)
+ def get_quote_cache(self, symbol: str) -> Optional[Any]:
+ """LRU缓存装饰器示例"""
+ # 这个方法将自动缓存最近128个调用的结果
+ pass
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/data_quality_monitor.py b/modules/core-collaboration/src/jixia/engines/data_quality_monitor.py
new file mode 100644
index 0000000..ed48d48
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/data_quality_monitor.py
@@ -0,0 +1,49 @@
+from typing import Dict, Any
+from datetime import datetime
+
+class DataQualityMonitor:
+ """数据质量监控"""
+
+ def __init__(self):
+ self.provider_stats = {}
+
+ def record_access(self, provider_name: str, success: bool, response_time: float, data_size: int):
+ """记录数据访问统计"""
+ if provider_name not in self.provider_stats:
+ self.provider_stats[provider_name] = {
+ 'total_requests': 0,
+ 'successful_requests': 0,
+ 'failed_requests': 0,
+ 'total_response_time': 0,
+ 'total_data_size': 0,
+ 'last_access': None
+ }
+
+ stats = self.provider_stats[provider_name]
+ stats['total_requests'] += 1
+ if success:
+ stats['successful_requests'] += 1
+ else:
+ stats['failed_requests'] += 1
+ stats['total_response_time'] += response_time
+ stats['total_data_size'] += data_size
+ stats['last_access'] = datetime.now()
+
+ def get_provider_health(self, provider_name: str) -> Dict[str, Any]:
+ """获取提供商健康状况"""
+ if provider_name not in self.provider_stats:
+ return {'status': 'unknown'}
+
+ stats = self.provider_stats[provider_name]
+ success_rate = stats['successful_requests'] / stats['total_requests'] if stats['total_requests'] > 0 else 0
+ avg_response_time = stats['total_response_time'] / stats['total_requests'] if stats['total_requests'] > 0 else 0
+
+ status = 'healthy' if success_rate > 0.95 and avg_response_time < 2.0 else 'degraded' if success_rate > 0.8 else 'unhealthy'
+
+ return {
+ 'status': status,
+ 'success_rate': success_rate,
+ 'avg_response_time': avg_response_time,
+ 'total_requests': stats['total_requests'],
+ 'last_access': stats['last_access']
+ }
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/jixia_load_balancer.py b/modules/core-collaboration/src/jixia/engines/jixia_load_balancer.py
new file mode 100644
index 0000000..1c9ae46
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/jixia_load_balancer.py
@@ -0,0 +1,462 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+稷下学宫负载均衡器
+实现八仙论道的API负载分担策略
+"""
+
+import time
+import random
+import requests
+from datetime import datetime, timezone
+from typing import Dict, List, Any, Optional, Tuple
+from dataclasses import dataclass
+from collections import defaultdict
+import json
+import os
+
+@dataclass
+class APIResult:
+ """API调用结果"""
+ success: bool
+ data: Dict[str, Any]
+ api_used: str
+ response_time: float
+ error: Optional[str] = None
+ cached: bool = False
+
+class RateLimiter:
+ """速率限制器"""
+
+ def __init__(self):
+ self.api_calls = defaultdict(list)
+ self.limits = {
+ 'alpha_vantage': {'per_minute': 500, 'per_month': 500000},
+ 'yahoo_finance_15': {'per_minute': 500, 'per_month': 500000},
+ 'webull': {'per_minute': 500, 'per_month': 500000},
+ 'seeking_alpha': {'per_minute': 500, 'per_month': 500000}
+ }
+
+ def is_rate_limited(self, api_name: str) -> bool:
+ """检查是否达到速率限制"""
+ now = time.time()
+ calls = self.api_calls[api_name]
+
+ # 清理1分钟前的记录
+ self.api_calls[api_name] = [call_time for call_time in calls if now - call_time < 60]
+
+ # 检查每分钟限制
+ if len(self.api_calls[api_name]) >= self.limits[api_name]['per_minute'] * 0.9: # 90%阈值
+ return True
+
+ return False
+
+ def record_call(self, api_name: str):
+ """记录API调用"""
+ self.api_calls[api_name].append(time.time())
+
+class APIHealthChecker:
+ """API健康检查器"""
+
+ def __init__(self):
+ self.health_status = {
+ 'alpha_vantage': {'healthy': True, 'last_check': 0, 'consecutive_failures': 0},
+ 'yahoo_finance_15': {'healthy': True, 'last_check': 0, 'consecutive_failures': 0},
+ 'webull': {'healthy': True, 'last_check': 0, 'consecutive_failures': 0},
+ 'seeking_alpha': {'healthy': True, 'last_check': 0, 'consecutive_failures': 0}
+ }
+ self.check_interval = 300 # 5分钟检查一次
+
+ def is_healthy(self, api_name: str) -> bool:
+ """检查API是否健康"""
+ status = self.health_status[api_name]
+ now = time.time()
+
+ # 如果距离上次检查超过间隔时间,进行健康检查
+ if now - status['last_check'] > self.check_interval:
+ self._perform_health_check(api_name)
+
+ return status['healthy']
+
+ def _perform_health_check(self, api_name: str):
+ """执行健康检查"""
+ # 这里可以实现具体的健康检查逻辑
+ # 暂时简化为基于连续失败次数判断
+ status = self.health_status[api_name]
+ status['last_check'] = time.time()
+
+ # 如果连续失败超过3次,标记为不健康
+ if status['consecutive_failures'] > 3:
+ status['healthy'] = False
+ else:
+ status['healthy'] = True
+
+ def record_success(self, api_name: str):
+ """记录成功调用"""
+ self.health_status[api_name]['consecutive_failures'] = 0
+ self.health_status[api_name]['healthy'] = True
+
+ def record_failure(self, api_name: str):
+ """记录失败调用"""
+ self.health_status[api_name]['consecutive_failures'] += 1
+
+class DataNormalizer:
+ """数据标准化处理器"""
+
+ def normalize_stock_quote(self, raw_data: dict, api_source: str) -> dict:
+ """将不同API的股票报价数据标准化"""
+ try:
+ if api_source == 'alpha_vantage':
+ return self._normalize_alpha_vantage_quote(raw_data)
+ elif api_source == 'yahoo_finance_15':
+ return self._normalize_yahoo_quote(raw_data)
+ elif api_source == 'webull':
+ return self._normalize_webull_quote(raw_data)
+ elif api_source == 'seeking_alpha':
+ return self._normalize_seeking_alpha_quote(raw_data)
+ else:
+ return {'error': f'Unknown API source: {api_source}'}
+ except Exception as e:
+ return {'error': f'Data normalization failed: {str(e)}'}
+
+ def _normalize_alpha_vantage_quote(self, data: dict) -> dict:
+ """标准化Alpha Vantage数据格式"""
+ global_quote = data.get('Global Quote', {})
+ return {
+ 'symbol': global_quote.get('01. symbol'),
+ 'price': float(global_quote.get('05. price', 0)),
+ 'change': float(global_quote.get('09. change', 0)),
+ 'change_percent': global_quote.get('10. change percent', '0%'),
+ 'volume': int(global_quote.get('06. volume', 0)),
+ 'high': float(global_quote.get('03. high', 0)),
+ 'low': float(global_quote.get('04. low', 0)),
+ 'source': 'alpha_vantage',
+ 'timestamp': global_quote.get('07. latest trading day')
+ }
+
+ def _normalize_yahoo_quote(self, data: dict) -> dict:
+ """标准化Yahoo Finance数据格式"""
+ body = data.get('body', {})
+ return {
+ 'symbol': body.get('symbol'),
+ 'price': float(body.get('regularMarketPrice', 0)),
+ 'change': float(body.get('regularMarketChange', 0)),
+ 'change_percent': f"{body.get('regularMarketChangePercent', 0):.2f}%",
+ 'volume': int(body.get('regularMarketVolume', 0)),
+ 'high': float(body.get('regularMarketDayHigh', 0)),
+ 'low': float(body.get('regularMarketDayLow', 0)),
+ 'source': 'yahoo_finance_15',
+ 'timestamp': body.get('regularMarketTime')
+ }
+
+ def _normalize_webull_quote(self, data: dict) -> dict:
+ """标准化Webull数据格式"""
+ if 'stocks' in data and len(data['stocks']) > 0:
+ stock = data['stocks'][0]
+ return {
+ 'symbol': stock.get('symbol'),
+ 'price': float(stock.get('close', 0)),
+ 'change': float(stock.get('change', 0)),
+ 'change_percent': f"{stock.get('changeRatio', 0):.2f}%",
+ 'volume': int(stock.get('volume', 0)),
+ 'high': float(stock.get('high', 0)),
+ 'low': float(stock.get('low', 0)),
+ 'source': 'webull',
+ 'timestamp': stock.get('timeStamp')
+ }
+ return {'error': 'No stock data found in Webull response'}
+
+ def _normalize_seeking_alpha_quote(self, data: dict) -> dict:
+ """标准化Seeking Alpha数据格式"""
+ if 'data' in data and len(data['data']) > 0:
+ stock_data = data['data'][0]
+ attributes = stock_data.get('attributes', {})
+ return {
+ 'symbol': attributes.get('slug'),
+ 'price': float(attributes.get('lastPrice', 0)),
+ 'change': float(attributes.get('dayChange', 0)),
+ 'change_percent': f"{attributes.get('dayChangePercent', 0):.2f}%",
+ 'volume': int(attributes.get('volume', 0)),
+ 'source': 'seeking_alpha',
+ 'market_cap': attributes.get('marketCap'),
+ 'pe_ratio': attributes.get('peRatio')
+ }
+ return {'error': 'No data found in Seeking Alpha response'}
+
+class JixiaLoadBalancer:
+ """稷下学宫负载均衡器"""
+
+ def __init__(self, rapidapi_key: str):
+ self.rapidapi_key = rapidapi_key
+ self.rate_limiter = RateLimiter()
+ self.health_checker = APIHealthChecker()
+ self.data_normalizer = DataNormalizer()
+ self.cache = {} # 简单的内存缓存
+ self.cache_ttl = 300 # 5分钟缓存
+
+ # API配置
+ self.api_configs = {
+ 'alpha_vantage': {
+ 'host': 'alpha-vantage.p.rapidapi.com',
+ 'endpoints': {
+ 'stock_quote': '/query?function=GLOBAL_QUOTE&symbol={symbol}',
+ 'company_overview': '/query?function=OVERVIEW&symbol={symbol}',
+ 'earnings': '/query?function=EARNINGS&symbol={symbol}'
+ }
+ },
+ 'yahoo_finance_15': {
+ 'host': 'yahoo-finance15.p.rapidapi.com',
+ 'endpoints': {
+ 'stock_quote': '/api/yahoo/qu/quote/{symbol}',
+ 'market_movers': '/api/yahoo/co/collections/day_gainers',
+ 'market_news': '/api/yahoo/ne/news'
+ }
+ },
+ 'webull': {
+ 'host': 'webull.p.rapidapi.com',
+ 'endpoints': {
+ 'stock_quote': '/stock/search?keyword={symbol}',
+ 'market_movers': '/market/get-active-gainers'
+ }
+ },
+ 'seeking_alpha': {
+ 'host': 'seeking-alpha.p.rapidapi.com',
+ 'endpoints': {
+ 'company_overview': '/symbols/get-profile?symbols={symbol}',
+ 'market_news': '/news/list?category=market-news'
+ }
+ }
+ }
+
+ # 八仙API分配策略
+ self.immortal_api_mapping = {
+ 'stock_quote': {
+ '吕洞宾': 'alpha_vantage', # 主力剑仙用最快的API
+ '何仙姑': 'yahoo_finance_15', # 风控专家用稳定的API
+ '张果老': 'webull', # 技术分析师用搜索强的API
+ '韩湘子': 'alpha_vantage', # 基本面研究用专业API
+ '汉钟离': 'yahoo_finance_15', # 量化专家用市场数据API
+ '蓝采和': 'webull', # 情绪分析师用活跃数据API
+ '曹国舅': 'seeking_alpha', # 宏观分析师用分析API
+ '铁拐李': 'alpha_vantage' # 逆向投资用基础数据API
+ },
+ 'company_overview': {
+ '吕洞宾': 'alpha_vantage',
+ '何仙姑': 'seeking_alpha',
+ '张果老': 'alpha_vantage',
+ '韩湘子': 'seeking_alpha',
+ '汉钟离': 'alpha_vantage',
+ '蓝采和': 'seeking_alpha',
+ '曹国舅': 'seeking_alpha',
+ '铁拐李': 'alpha_vantage'
+ },
+ 'market_movers': {
+ '吕洞宾': 'yahoo_finance_15',
+ '何仙姑': 'webull',
+ '张果老': 'yahoo_finance_15',
+ '韩湘子': 'webull',
+ '汉钟离': 'yahoo_finance_15',
+ '蓝采和': 'webull',
+ '曹国舅': 'yahoo_finance_15',
+ '铁拐李': 'webull'
+ },
+ 'market_news': {
+ '吕洞宾': 'yahoo_finance_15',
+ '何仙姑': 'seeking_alpha',
+ '张果老': 'yahoo_finance_15',
+ '韩湘子': 'seeking_alpha',
+ '汉钟离': 'yahoo_finance_15',
+ '蓝采和': 'seeking_alpha',
+ '曹国舅': 'seeking_alpha',
+ '铁拐李': 'yahoo_finance_15'
+ }
+ }
+
+ # 故障转移优先级
+ self.failover_priority = {
+ 'alpha_vantage': ['webull', 'yahoo_finance_15'],
+ 'yahoo_finance_15': ['webull', 'alpha_vantage'],
+ 'webull': ['alpha_vantage', 'yahoo_finance_15'],
+ 'seeking_alpha': ['yahoo_finance_15', 'alpha_vantage']
+ }
+
+ def get_data_for_immortal(self, immortal_name: str, data_type: str, symbol: str = None) -> APIResult:
+ """为特定仙人获取数据"""
+ print(f"🎭 {immortal_name} 正在获取 {data_type} 数据...")
+
+ # 检查缓存
+ cache_key = f"{immortal_name}_{data_type}_{symbol}"
+ cached_result = self._get_cached_data(cache_key)
+ if cached_result:
+ print(f" 📦 使用缓存数据")
+ return cached_result
+
+ # 获取该仙人的首选API
+ if data_type not in self.immortal_api_mapping:
+ return APIResult(False, {}, '', 0, f"Unsupported data type: {data_type}")
+
+ preferred_api = self.immortal_api_mapping[data_type][immortal_name]
+
+ # 尝试首选API
+ result = self._try_api(preferred_api, data_type, symbol)
+ if result.success:
+ self._cache_data(cache_key, result)
+ print(f" ✅ 成功从 {preferred_api} 获取数据 (响应时间: {result.response_time:.2f}s)")
+ return result
+
+ # 故障转移到备用API
+ print(f" ⚠️ {preferred_api} 不可用,尝试备用API...")
+ backup_apis = self.failover_priority.get(preferred_api, [])
+
+ for backup_api in backup_apis:
+ if data_type in self.api_configs[backup_api]['endpoints']:
+ result = self._try_api(backup_api, data_type, symbol)
+ if result.success:
+ self._cache_data(cache_key, result)
+ print(f" ✅ 成功从备用API {backup_api} 获取数据 (响应时间: {result.response_time:.2f}s)")
+ return result
+
+ # 所有API都失败
+ print(f" ❌ 所有API都不可用")
+ return APIResult(False, {}, '', 0, "All APIs failed")
+
+ def _try_api(self, api_name: str, data_type: str, symbol: str = None) -> APIResult:
+ """尝试调用指定API"""
+ # 检查API健康状态和速率限制
+ if not self.health_checker.is_healthy(api_name):
+ return APIResult(False, {}, api_name, 0, "API is unhealthy")
+
+ if self.rate_limiter.is_rate_limited(api_name):
+ return APIResult(False, {}, api_name, 0, "Rate limited")
+
+ # 构建请求
+ config = self.api_configs[api_name]
+ if data_type not in config['endpoints']:
+ return APIResult(False, {}, api_name, 0, f"Endpoint {data_type} not supported")
+
+ endpoint = config['endpoints'][data_type]
+ if symbol and '{symbol}' in endpoint:
+ endpoint = endpoint.format(symbol=symbol)
+
+ url = f"https://{config['host']}{endpoint}"
+ headers = {
+ 'X-RapidAPI-Key': self.rapidapi_key,
+ 'X-RapidAPI-Host': config['host']
+ }
+
+ # 发起请求
+ start_time = time.time()
+ try:
+ response = requests.get(url, headers=headers, timeout=10)
+ response_time = time.time() - start_time
+
+ self.rate_limiter.record_call(api_name)
+
+ if response.status_code == 200:
+ data = response.json()
+
+ # 数据标准化
+ if data_type == 'stock_quote':
+ normalized_data = self.data_normalizer.normalize_stock_quote(data, api_name)
+ else:
+ normalized_data = data
+
+ self.health_checker.record_success(api_name)
+ return APIResult(True, normalized_data, api_name, response_time)
+ else:
+ error_msg = f"HTTP {response.status_code}: {response.text[:200]}"
+ self.health_checker.record_failure(api_name)
+ return APIResult(False, {}, api_name, response_time, error_msg)
+
+ except Exception as e:
+ response_time = time.time() - start_time
+ self.health_checker.record_failure(api_name)
+ return APIResult(False, {}, api_name, response_time, str(e))
+
+ def _get_cached_data(self, cache_key: str) -> Optional[APIResult]:
+ """获取缓存数据"""
+ if cache_key in self.cache:
+ cached_item = self.cache[cache_key]
+ if time.time() - cached_item['timestamp'] < self.cache_ttl:
+ result = cached_item['result']
+ result.cached = True
+ return result
+ else:
+ # 缓存过期,删除
+ del self.cache[cache_key]
+ return None
+
+ def _cache_data(self, cache_key: str, result: APIResult):
+ """缓存数据"""
+ self.cache[cache_key] = {
+ 'result': result,
+ 'timestamp': time.time()
+ }
+
+ def get_load_distribution(self) -> dict:
+ """获取负载分布统计"""
+ api_calls = {}
+ total_calls = 0
+
+ for api_name, calls in self.rate_limiter.api_calls.items():
+ call_count = len(calls)
+ api_calls[api_name] = call_count
+ total_calls += call_count
+
+ if total_calls == 0:
+ return {}
+
+ distribution = {}
+ for api_name, call_count in api_calls.items():
+ health_status = self.health_checker.health_status[api_name]
+ distribution[api_name] = {
+ 'calls': call_count,
+ 'percentage': (call_count / total_calls) * 100,
+ 'healthy': health_status['healthy'],
+ 'consecutive_failures': health_status['consecutive_failures']
+ }
+
+ return distribution
+
+ def conduct_immortal_debate(self, topic_symbol: str) -> Dict[str, APIResult]:
+ """进行八仙论道,每个仙人获取不同的数据"""
+ print(f"\n🏛️ 稷下学宫八仙论道开始 - 主题: {topic_symbol}")
+ print("=" * 60)
+
+ immortals = ['吕洞宾', '何仙姑', '张果老', '韩湘子', '汉钟离', '蓝采和', '曹国舅', '铁拐李']
+ debate_results = {}
+
+ # 每个仙人获取股票报价数据
+ for immortal in immortals:
+ result = self.get_data_for_immortal(immortal, 'stock_quote', topic_symbol)
+ debate_results[immortal] = result
+
+ if result.success:
+ data = result.data
+ if 'price' in data:
+ print(f" 💰 {immortal}: ${data['price']:.2f} ({data.get('change_percent', 'N/A')}) via {result.api_used}")
+
+ time.sleep(0.2) # 避免过快请求
+
+ print("\n📊 负载分布统计:")
+ distribution = self.get_load_distribution()
+ for api_name, stats in distribution.items():
+ print(f" {api_name}: {stats['calls']} 次调用 ({stats['percentage']:.1f}%) - {'健康' if stats['healthy'] else '异常'}")
+
+ return debate_results
+
+# 使用示例
+if __name__ == "__main__":
+ # 从环境变量获取API密钥
+ rapidapi_key = os.getenv('RAPIDAPI_KEY')
+ if not rapidapi_key:
+ print("❌ 请设置RAPIDAPI_KEY环境变量")
+ exit(1)
+
+ # 创建负载均衡器
+ load_balancer = JixiaLoadBalancer(rapidapi_key)
+
+ # 进行八仙论道
+ results = load_balancer.conduct_immortal_debate('TSLA')
+
+ print("\n🎉 八仙论道完成!")
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/openbb_adapter.py b/modules/core-collaboration/src/jixia/engines/openbb_adapter.py
new file mode 100644
index 0000000..33ae949
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/openbb_adapter.py
@@ -0,0 +1,75 @@
+from typing import List, Optional
+from src.jixia.engines.data_abstraction import DataProvider
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+from src.jixia.engines.openbb_engine import OpenBBEngine
+
+class OpenBBDataProvider(DataProvider):
+ """OpenBB引擎适配器"""
+
+ def __init__(self):
+ self.engine = OpenBBEngine()
+ self._name = "OpenBB"
+ self._priority = 1 # 最高优先级
+
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ result = self.engine.get_immortal_data("吕洞宾", "price", symbol)
+ if result.success and result.data:
+ # 解析OpenBB返回的数据并转换为StockQuote
+ # 注意:这里需要根据OpenBB实际返回的数据结构进行调整
+ data = result.data
+ if isinstance(data, list) and len(data) > 0:
+ item = data[0] # 取第一条数据
+ elif hasattr(data, '__dict__'):
+ item = data
+ else:
+ item = {}
+
+ # 提取价格信息(根据openbb_stock_data.py中的字段)
+ price = 0
+ if hasattr(item, 'close'):
+ price = float(item.close)
+ elif isinstance(item, dict) and 'close' in item:
+ price = float(item['close'])
+
+ volume = 0
+ if hasattr(item, 'volume'):
+ volume = int(item.volume)
+ elif isinstance(item, dict) and 'volume' in item:
+ volume = int(item['volume'])
+
+ # 日期处理
+ timestamp = None
+ if hasattr(item, 'date'):
+ timestamp = item.date
+ elif isinstance(item, dict) and 'date' in item:
+ timestamp = item['date']
+
+ return StockQuote(
+ symbol=symbol,
+ price=price,
+ change=0, # 需要计算
+ change_percent=0, # 需要计算
+ volume=volume,
+ timestamp=timestamp
+ )
+ return None
+
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ # 实现历史价格数据获取逻辑
+ pass
+
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ # 实现公司概况获取逻辑
+ pass
+
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ # 实现新闻获取逻辑
+ pass
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ @property
+ def priority(self) -> int:
+ return self._priority
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/openbb_engine.py b/modules/core-collaboration/src/jixia/engines/openbb_engine.py
new file mode 100644
index 0000000..87febfd
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/openbb_engine.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python3
+"""
+OpenBB 集成引擎
+为八仙论道提供更丰富的金融数据支撑
+"""
+
+from typing import Dict, List, Any, Optional
+from dataclasses import dataclass
+
+
+@dataclass
+class ImmortalConfig:
+ """八仙配置数据类"""
+ primary: str
+ specialty: str
+
+@dataclass
+class APIResult:
+ """API调用结果数据类"""
+ success: bool
+ data: Optional[Any] = None
+ provider_used: Optional[str] = None
+ error: Optional[str] = None
+
+class OpenBBEngine:
+ """OpenBB 集成引擎"""
+
+ def __init__(self):
+ """
+ 初始化 OpenBB 引擎
+ """
+ # 延迟导入 OpenBB,避免未安装时报错
+ self._obb = None
+
+ # 八仙专属数据源分配
+ self.immortal_sources: Dict[str, ImmortalConfig] = {
+ '吕洞宾': ImmortalConfig( # 乾-技术分析专家
+ primary='yfinance',
+ specialty='technical_analysis'
+ ),
+ '何仙姑': ImmortalConfig( # 坤-风险控制专家
+ primary='yfinance',
+ specialty='risk_metrics'
+ ),
+ '张果老': ImmortalConfig( # 兑-历史数据分析师
+ primary='yfinance',
+ specialty='historical_data'
+ ),
+ '韩湘子': ImmortalConfig( # 艮-新兴资产专家
+ primary='yfinance',
+ specialty='sector_analysis'
+ ),
+ '汉钟离': ImmortalConfig( # 离-热点追踪
+ primary='yfinance',
+ specialty='market_movers'
+ ),
+ '蓝采和': ImmortalConfig( # 坎-潜力股发现
+ primary='yfinance',
+ specialty='screener'
+ ),
+ '曹国舅': ImmortalConfig( # 震-机构分析
+ primary='yfinance',
+ specialty='institutional_holdings'
+ ),
+ '铁拐李': ImmortalConfig( # 巽-逆向投资
+ primary='yfinance',
+ specialty='short_interest'
+ )
+ }
+
+ print("✅ OpenBB 引擎初始化完成")
+
+ def _ensure_openbb(self):
+ """Lazy import OpenBB v4 obb router."""
+ if self._obb is not None:
+ return True
+ try:
+ from openbb import obb # type: ignore
+ self._obb = obb
+ return True
+ except Exception:
+ self._obb = None
+ return False
+
+ def get_immortal_data(self, immortal_name: str, data_type: str, symbol: str = 'AAPL') -> APIResult:
+ """
+ 为特定八仙获取专属数据
+
+ Args:
+ immortal_name: 八仙名称
+ data_type: 数据类型
+ symbol: 股票代码
+
+ Returns:
+ API调用结果
+ """
+ if immortal_name not in self.immortal_sources:
+ return APIResult(success=False, error=f'Unknown immortal: {immortal_name}')
+
+ immortal_config = self.immortal_sources[immortal_name]
+
+ print(f"🧙♂️ {immortal_name} 请求 {data_type} 数据 (股票: {symbol})")
+
+ # 根据数据类型调用不同的 OpenBB 函数
+ try:
+ if not self._ensure_openbb():
+ return APIResult(success=False, error='OpenBB 未安装,请先安装 openbb>=4 并在 requirements.txt 启用')
+ obb = self._obb
+ if data_type == 'price':
+ result = obb.equity.price.quote(symbol=symbol, provider=immortal_config.primary)
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used=immortal_config.primary
+ )
+ elif data_type == 'historical':
+ result = obb.equity.price.historical(symbol=symbol, provider=immortal_config.primary)
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used=immortal_config.primary
+ )
+ elif data_type == 'profile':
+ result = obb.equity.profile(symbol=symbol, provider=immortal_config.primary)
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used=immortal_config.primary
+ )
+ elif data_type == 'news':
+ result = obb.news.company(symbol=symbol)
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used='news_api'
+ )
+ elif data_type == 'earnings':
+ result = obb.equity.earnings.earnings_historical(symbol=symbol, provider=immortal_config.primary)
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used=immortal_config.primary
+ )
+ elif data_type == 'dividends':
+ result = obb.equity.fundamental.dividend(symbol=symbol, provider=immortal_config.primary)
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used=immortal_config.primary
+ )
+ elif data_type == 'screener':
+ # 使用简单的筛选器作为替代
+ result = obb.equity.screener.etf(
+ provider=immortal_config.primary
+ )
+ return APIResult(
+ success=True,
+ data=getattr(result, 'results', getattr(result, 'to_dict', lambda: None)()),
+ provider_used=immortal_config.primary
+ )
+ else:
+ return APIResult(success=False, error=f'Unsupported data type: {data_type}')
+
+ except Exception as e:
+ return APIResult(success=False, error=f'OpenBB 调用失败: {str(e)}')
+
+ def simulate_jixia_debate(self, topic_symbol: str = 'TSLA') -> Dict[str, APIResult]:
+ """
+ 模拟稷下学宫八仙论道
+
+ Args:
+ topic_symbol: 辩论主题股票代码
+
+ Returns:
+ 八仙辩论结果
+ """
+ print(f"🏛️ 稷下学宫八仙论道 - 主题: {topic_symbol} (OpenBB 版本)")
+ print("=" * 60)
+
+ debate_results: Dict[str, APIResult] = {}
+
+ # 数据类型映射
+ data_type_mapping = {
+ 'technical_analysis': 'historical', # 技术分析使用历史价格数据
+ 'risk_metrics': 'price', # 风险控制使用当前价格数据
+ 'historical_data': 'historical', # 历史数据分析使用历史价格数据
+ 'sector_analysis': 'profile', # 新兴资产分析使用公司概况
+ 'market_movers': 'news', # 热点追踪使用新闻
+ 'screener': 'screener', # 潜力股发现使用筛选器
+ 'institutional_holdings': 'profile', # 机构分析使用公司概况
+ 'short_interest': 'profile' # 逆向投资使用公司概况
+ }
+
+ # 八仙依次发言
+ for immortal_name, config in self.immortal_sources.items():
+ print(f"\n🎭 {immortal_name} ({config.specialty}) 发言:")
+
+ data_type = data_type_mapping.get(config.specialty, 'price')
+ result = self.get_immortal_data(immortal_name, data_type, topic_symbol)
+
+ if result.success:
+ debate_results[immortal_name] = result
+ print(f" 💬 观点: 基于{result.provider_used}数据的{config.specialty}分析")
+ # 显示部分数据示例
+ if result.data:
+ if isinstance(result.data, list) and len(result.data) > 0:
+ sample = result.data[0]
+ print(f" 📊 数据示例: {sample}")
+ elif hasattr(result.data, '__dict__'):
+ # 如果是对象,显示前几个属性
+ attrs = vars(result.data)
+ sample = {k: v for k, v in list(attrs.items())[:3]}
+ print(f" 📊 数据示例: {sample}")
+ else:
+ print(f" 📊 数据示例: {result.data}")
+ else:
+ print(f" 😔 暂时无法获取数据: {result.error}")
+
+ return debate_results
+
+if __name__ == "__main__":
+ # 测试 OpenBB 引擎
+ print("🧪 OpenBB 引擎测试")
+ engine = OpenBBEngine()
+ engine.simulate_jixia_debate('AAPL')
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/openbb_stock_data.py b/modules/core-collaboration/src/jixia/engines/openbb_stock_data.py
new file mode 100644
index 0000000..e0d9202
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/openbb_stock_data.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+"""
+OpenBB 股票数据获取模块
+"""
+
+from datetime import datetime, timedelta
+from typing import List, Dict, Any, Optional
+
+def get_stock_data(symbol: str, days: int = 90) -> Optional[List[Dict[str, Any]]]:
+ """
+ 获取指定股票在指定天数内的历史数据
+
+ Args:
+ symbol (str): 股票代码 (如 'AAPL')
+ days (int): 时间窗口(天),默认90天
+
+ Returns:
+ List[Dict[str, Any]]: 股票历史数据列表,如果失败则返回None
+ """
+ try:
+ # 计算开始日期
+ end_date = datetime.now()
+ start_date = end_date - timedelta(days=days)
+
+ print(f"🔍 正在获取 {symbol} 近 {days} 天的数据...")
+ print(f" 时间范围: {start_date.strftime('%Y-%m-%d')} 到 {end_date.strftime('%Y-%m-%d')}")
+
+ # 使用OpenBB获取数据(延迟导入)
+ try:
+ from openbb import obb # type: ignore
+ except Exception as e:
+ print(f"⚠️ OpenBB 未安装或导入失败: {e}")
+ return None
+
+ result = obb.equity.price.historical(
+ symbol=symbol,
+ provider='yfinance',
+ start_date=start_date.strftime('%Y-%m-%d'),
+ end_date=end_date.strftime('%Y-%m-%d')
+ )
+
+ results = getattr(result, 'results', None)
+ if results:
+ print(f"✅ 成功获取 {len(results)} 条记录")
+ return results
+ else:
+ print("❌ 未获取到数据")
+ return None
+
+ except Exception as e:
+ print(f"❌ 获取数据时出错: {str(e)}")
+ return None
+
+def get_etf_data(symbol: str, days: int = 90) -> Optional[List[Dict[str, Any]]]:
+ """
+ 获取指定ETF在指定天数内的历史数据
+
+ Args:
+ symbol (str): ETF代码 (如 'SPY')
+ days (int): 时间窗口(天),默认90天
+
+ Returns:
+ List[Dict[str, Any]]: ETF历史数据列表,如果失败则返回None
+ """
+ try:
+ # 计算开始日期
+ end_date = datetime.now()
+ start_date = end_date - timedelta(days=days)
+
+ print(f"🔍 正在获取 {symbol} 近 {days} 天的数据...")
+ print(f" 时间范围: {start_date.strftime('%Y-%m-%d')} 到 {end_date.strftime('%Y-%m-%d')}")
+
+ # 使用OpenBB获取数据(延迟导入)
+ try:
+ from openbb import obb # type: ignore
+ except Exception as e:
+ print(f"⚠️ OpenBB 未安装或导入失败: {e}")
+ return None
+
+ result = obb.etf.price.historical(
+ symbol=symbol,
+ provider='yfinance',
+ start_date=start_date.strftime('%Y-%m-%d'),
+ end_date=end_date.strftime('%Y-%m-%d')
+ )
+
+ results = getattr(result, 'results', None)
+ if results:
+ print(f"✅ 成功获取 {len(results)} 条记录")
+ return results
+ else:
+ print("❌ 未获取到数据")
+ return None
+
+ except Exception as e:
+ print(f"❌ 获取数据时出错: {str(e)}")
+ return None
+
+def format_stock_data(data: List[Dict[str, Any]]) -> None:
+ """
+ 格式化并打印股票数据
+
+ Args:
+ data (List[Dict[str, Any]]): 股票数据列表
+ """
+ if not data:
+ print("😔 没有数据可显示")
+ return
+
+ print(f"\n📊 股票数据预览 (显示最近5条记录):")
+ print("-" * 80)
+ print(f"{'日期':<12} {'开盘':<10} {'最高':<10} {'最低':<10} {'收盘':<10} {'成交量':<15}")
+ print("-" * 80)
+
+ # 只显示最近5条记录
+ for item in data[-5:]:
+ print(f"{str(item.date):<12} {item.open:<10.2f} {item.high:<10.2f} {item.low:<10.2f} {item.close:<10.2f} {item.volume:<15,}")
+
+def format_etf_data(data: List[Dict[str, Any]]) -> None:
+ """
+ 格式化并打印ETF数据
+
+ Args:
+ data (List[Dict[str, Any]]): ETF数据列表
+ """
+ if not data:
+ print("😔 没有数据可显示")
+ return
+
+ print(f"\n📊 ETF数据预览 (显示最近5条记录):")
+ print("-" * 80)
+ print(f"{'日期':<12} {'开盘':<10} {'最高':<10} {'最低':<10} {'收盘':<10} {'成交量':<15}")
+ print("-" * 80)
+
+ # 只显示最近5条记录
+ for item in data[-5:]:
+ print(f"{str(item.date):<12} {item.open:<10.2f} {item.high:<10.2f} {item.low:<10.2f} {item.close:<10.2f} {item.volume:<15,}")
+
+def main():
+ """主函数"""
+ # 示例:获取AAPL股票和SPY ETF的数据
+ symbols = [("AAPL", "stock"), ("SPY", "etf")]
+ time_windows = [90, 720]
+
+ for symbol, asset_type in symbols:
+ for days in time_windows:
+ print(f"\n{'='*60}")
+ print(f"获取 {symbol} {days} 天数据")
+ print(f"{'='*60}")
+
+ if asset_type == "stock":
+ data = get_stock_data(symbol, days)
+ if data:
+ format_stock_data(data)
+ else:
+ data = get_etf_data(symbol, days)
+ if data:
+ format_etf_data(data)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/perpetual_engine.py b/modules/core-collaboration/src/jixia/engines/perpetual_engine.py
new file mode 100644
index 0000000..cfdef17
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/perpetual_engine.py
@@ -0,0 +1,329 @@
+#!/usr/bin/env python3
+"""
+稷下学宫永动机引擎
+为八仙论道提供无限数据支撑
+
+重构版本:
+- 移除硬编码密钥
+- 添加类型注解
+- 改进错误处理
+- 统一配置管理
+"""
+
+import requests
+import time
+from datetime import datetime
+from typing import Dict, List, Any, Optional
+from dataclasses import dataclass
+
+@dataclass
+class ImmortalConfig:
+ """八仙配置数据类"""
+ primary: str
+ backup: List[str]
+ specialty: str
+
+@dataclass
+class APIResult:
+ """API调用结果数据类"""
+ success: bool
+ data: Optional[Dict[str, Any]] = None
+ api_used: Optional[str] = None
+ usage_count: Optional[int] = None
+ error: Optional[str] = None
+
+class JixiaPerpetualEngine:
+ """稷下学宫永动机引擎"""
+
+ def __init__(self, rapidapi_key: str):
+ """
+ 初始化永动机引擎
+
+ Args:
+ rapidapi_key: RapidAPI密钥,从环境变量或Doppler获取
+ """
+ if not rapidapi_key:
+ raise ValueError("RapidAPI密钥不能为空")
+
+ self.rapidapi_key = rapidapi_key
+
+ # 八仙专属API分配 - 基于4个可用API优化
+ self.immortal_apis: Dict[str, ImmortalConfig] = {
+ '吕洞宾': ImmortalConfig( # 乾-技术分析专家
+ primary='alpha_vantage',
+ backup=['yahoo_finance_1'],
+ specialty='comprehensive_analysis'
+ ),
+ '何仙姑': ImmortalConfig( # 坤-风险控制专家
+ primary='yahoo_finance_1',
+ backup=['webull'],
+ specialty='risk_management'
+ ),
+ '张果老': ImmortalConfig( # 兑-历史数据分析师
+ primary='seeking_alpha',
+ backup=['alpha_vantage'],
+ specialty='fundamental_analysis'
+ ),
+ '韩湘子': ImmortalConfig( # 艮-新兴资产专家
+ primary='webull',
+ backup=['yahoo_finance_1'],
+ specialty='emerging_trends'
+ ),
+ '汉钟离': ImmortalConfig( # 离-热点追踪
+ primary='yahoo_finance_1',
+ backup=['webull'],
+ specialty='hot_trends'
+ ),
+ '蓝采和': ImmortalConfig( # 坎-潜力股发现
+ primary='webull',
+ backup=['alpha_vantage'],
+ specialty='undervalued_stocks'
+ ),
+ '曹国舅': ImmortalConfig( # 震-机构分析
+ primary='seeking_alpha',
+ backup=['alpha_vantage'],
+ specialty='institutional_analysis'
+ ),
+ '铁拐李': ImmortalConfig( # 巽-逆向投资
+ primary='alpha_vantage',
+ backup=['seeking_alpha'],
+ specialty='contrarian_analysis'
+ )
+ }
+
+ # API池配置 - 只保留4个可用的API
+ self.api_configs: Dict[str, str] = {
+ 'alpha_vantage': 'alpha-vantage.p.rapidapi.com', # 1.26s ⚡
+ 'webull': 'webull.p.rapidapi.com', # 1.56s ⚡
+ 'yahoo_finance_1': 'yahoo-finance15.p.rapidapi.com', # 2.07s
+ 'seeking_alpha': 'seeking-alpha.p.rapidapi.com' # 3.32s
+ }
+
+ # 使用统计
+ self.usage_tracker: Dict[str, int] = {api: 0 for api in self.api_configs.keys()}
+
+ def get_immortal_data(self, immortal_name: str, data_type: str, symbol: str = 'AAPL') -> APIResult:
+ """
+ 为特定八仙获取专属数据
+
+ Args:
+ immortal_name: 八仙名称
+ data_type: 数据类型
+ symbol: 股票代码
+
+ Returns:
+ API调用结果
+ """
+ if immortal_name not in self.immortal_apis:
+ return APIResult(success=False, error=f'Unknown immortal: {immortal_name}')
+
+ immortal_config = self.immortal_apis[immortal_name]
+
+ print(f"🧙♂️ {immortal_name} 请求 {data_type} 数据 (股票: {symbol})")
+
+ # 尝试主要API
+ result = self._call_api(immortal_config.primary, data_type, symbol)
+ if result.success:
+ print(f" ✅ 使用主要API: {immortal_config.primary}")
+ return result
+
+ # 故障转移到备用API
+ for backup_api in immortal_config.backup:
+ print(f" 🔄 故障转移到: {backup_api}")
+ result = self._call_api(backup_api, data_type, symbol)
+ if result.success:
+ print(f" ✅ 备用API成功: {backup_api}")
+ return result
+
+ print(f" ❌ 所有API都失败了")
+ return APIResult(success=False, error='All APIs failed')
+
+ def _call_api(self, api_name: str, data_type: str, symbol: str) -> APIResult:
+ """
+ 调用指定API
+
+ Args:
+ api_name: API名称
+ data_type: 数据类型
+ symbol: 股票代码
+
+ Returns:
+ API调用结果
+ """
+ if api_name not in self.api_configs:
+ return APIResult(success=False, error=f'API {api_name} not configured')
+
+ host = self.api_configs[api_name]
+ headers = {
+ 'X-RapidAPI-Key': self.rapidapi_key,
+ 'X-RapidAPI-Host': host,
+ 'Content-Type': 'application/json'
+ }
+
+ endpoint = self._get_endpoint(api_name, data_type, symbol)
+ if not endpoint:
+ return APIResult(success=False, error=f'No endpoint for {data_type} on {api_name}')
+
+ url = f"https://{host}{endpoint}"
+
+ try:
+ response = requests.get(url, headers=headers, timeout=8)
+ self.usage_tracker[api_name] += 1
+
+ if response.status_code == 200:
+ return APIResult(
+ success=True,
+ data=response.json(),
+ api_used=api_name,
+ usage_count=self.usage_tracker[api_name]
+ )
+ else:
+ return APIResult(
+ success=False,
+ error=f'HTTP {response.status_code}: {response.text[:100]}'
+ )
+ except requests.exceptions.Timeout:
+ return APIResult(success=False, error='Request timeout')
+ except requests.exceptions.RequestException as e:
+ return APIResult(success=False, error=f'Request error: {str(e)}')
+ except Exception as e:
+ return APIResult(success=False, error=f'Unexpected error: {str(e)}')
+
+ def _get_endpoint(self, api_name: str, data_type: str, symbol: str) -> Optional[str]:
+ """
+ 根据API和数据类型返回合适的端点
+
+ Args:
+ api_name: API名称
+ data_type: 数据类型
+ symbol: 股票代码
+
+ Returns:
+ API端点路径
+ """
+ endpoint_mapping = {
+ 'alpha_vantage': {
+ 'quote': f'/query?function=GLOBAL_QUOTE&symbol={symbol}',
+ 'overview': f'/query?function=OVERVIEW&symbol={symbol}',
+ 'earnings': f'/query?function=EARNINGS&symbol={symbol}',
+ 'profile': f'/query?function=OVERVIEW&symbol={symbol}',
+ 'analysis': f'/query?function=OVERVIEW&symbol={symbol}'
+ },
+ 'yahoo_finance_1': {
+ 'quote': f'/api/yahoo/qu/quote/{symbol}',
+ 'gainers': '/api/yahoo/co/collections/day_gainers',
+ 'losers': '/api/yahoo/co/collections/day_losers',
+ 'search': f'/api/yahoo/qu/quote/{symbol}',
+ 'analysis': f'/api/yahoo/qu/quote/{symbol}',
+ 'profile': f'/api/yahoo/qu/quote/{symbol}'
+ },
+ 'seeking_alpha': {
+ 'profile': f'/symbols/get-profile?symbols={symbol}',
+ 'news': '/news/list?category=market-news',
+ 'analysis': f'/symbols/get-profile?symbols={symbol}',
+ 'quote': f'/symbols/get-profile?symbols={symbol}'
+ },
+ 'webull': {
+ 'search': f'/stock/search?keyword={symbol}',
+ 'quote': f'/stock/search?keyword={symbol}',
+ 'analysis': f'/stock/search?keyword={symbol}',
+ 'gainers': '/market/get-active-gainers',
+ 'profile': f'/stock/search?keyword={symbol}'
+ }
+ }
+
+ api_endpoints = endpoint_mapping.get(api_name, {})
+ return api_endpoints.get(data_type, api_endpoints.get('quote'))
+
+ def simulate_jixia_debate(self, topic_symbol: str = 'TSLA') -> Dict[str, APIResult]:
+ """
+ 模拟稷下学宫八仙论道
+
+ Args:
+ topic_symbol: 辩论主题股票代码
+
+ Returns:
+ 八仙辩论结果
+ """
+ print(f"🏛️ 稷下学宫八仙论道 - 主题: {topic_symbol}")
+ print("=" * 60)
+
+ debate_results: Dict[str, APIResult] = {}
+
+ # 数据类型映射
+ data_type_mapping = {
+ 'comprehensive_analysis': 'overview',
+ 'etf_tracking': 'quote',
+ 'fundamental_analysis': 'profile',
+ 'emerging_trends': 'news',
+ 'hot_trends': 'gainers',
+ 'undervalued_stocks': 'search',
+ 'institutional_analysis': 'profile',
+ 'contrarian_analysis': 'analysis'
+ }
+
+ # 八仙依次发言
+ for immortal_name, config in self.immortal_apis.items():
+ print(f"\n🎭 {immortal_name} ({config.specialty}) 发言:")
+
+ data_type = data_type_mapping.get(config.specialty, 'quote')
+ result = self.get_immortal_data(immortal_name, data_type, topic_symbol)
+
+ if result.success:
+ debate_results[immortal_name] = result
+ print(f" 💬 观点: 基于{result.api_used}数据的{config.specialty}分析")
+ else:
+ print(f" 😔 暂时无法获取数据: {result.error}")
+
+ time.sleep(0.5) # 避免过快请求
+
+ return debate_results
+
+ def get_usage_stats(self) -> Dict[str, Any]:
+ """
+ 获取使用统计信息
+
+ Returns:
+ 统计信息字典
+ """
+ total_calls = sum(self.usage_tracker.values())
+ active_apis = len([api for api, count in self.usage_tracker.items() if count > 0])
+ unused_apis = [api for api, count in self.usage_tracker.items() if count == 0]
+
+ return {
+ 'total_calls': total_calls,
+ 'active_apis': active_apis,
+ 'total_apis': len(self.api_configs),
+ 'average_calls_per_api': total_calls / len(self.api_configs) if self.api_configs else 0,
+ 'usage_by_api': {api: count for api, count in self.usage_tracker.items() if count > 0},
+ 'unused_apis': unused_apis,
+ 'unused_count': len(unused_apis)
+ }
+
+ def print_perpetual_stats(self) -> None:
+ """打印永动机统计信息"""
+ stats = self.get_usage_stats()
+
+ print(f"\n📊 永动机运行统计:")
+ print("=" * 60)
+ print(f"总API调用次数: {stats['total_calls']}")
+ print(f"活跃API数量: {stats['active_apis']}/{stats['total_apis']}")
+ print(f"平均每API调用: {stats['average_calls_per_api']:.1f}次")
+
+ if stats['usage_by_api']:
+ print(f"\n各API使用情况:")
+ for api, count in stats['usage_by_api'].items():
+ print(f" {api}: {count}次")
+
+ print(f"\n🎯 未使用的API储备: {stats['unused_count']}个")
+ if stats['unused_apis']:
+ unused_display = ', '.join(stats['unused_apis'][:5])
+ if len(stats['unused_apis']) > 5:
+ unused_display += '...'
+ print(f"储备API: {unused_display}")
+
+ print(f"\n💡 永动机效果:")
+ print(f" • {stats['total_apis']}个API订阅,智能调度")
+ print(f" • 智能故障转移,永不断线")
+ print(f" • 八仙专属API,个性化数据")
+ print(f" • 成本优化,效果最大化!")
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/engines/rapidapi_adapter.py b/modules/core-collaboration/src/jixia/engines/rapidapi_adapter.py
new file mode 100644
index 0000000..02458a2
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/engines/rapidapi_adapter.py
@@ -0,0 +1,48 @@
+from typing import List, Optional
+from src.jixia.engines.data_abstraction import DataProvider
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine
+from config.settings import get_rapidapi_key
+
+class RapidAPIDataProvider(DataProvider):
+ """RapidAPI永动机引擎适配器"""
+
+ def __init__(self):
+ self.engine = JixiaPerpetualEngine(get_rapidapi_key())
+ self._name = "RapidAPI"
+ self._priority = 2 # 中等优先级
+
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ result = self.engine.get_immortal_data("吕洞宾", "quote", symbol)
+ if result.success and result.data:
+ # 解析RapidAPI返回的数据并转换为StockQuote
+ # 这里需要根据实际API返回的数据结构进行调整
+ return StockQuote(
+ symbol=symbol,
+ price=result.data.get("price", 0),
+ change=result.data.get("change", 0),
+ change_percent=result.data.get("change_percent", 0),
+ volume=result.data.get("volume", 0),
+ timestamp=result.data.get("timestamp")
+ )
+ return None
+
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ # 实现历史价格数据获取逻辑
+ pass
+
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ # 实现公司概况获取逻辑
+ pass
+
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ # 实现新闻获取逻辑
+ pass
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ @property
+ def priority(self) -> int:
+ return self._priority
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/intervention/human_intervention_system.py b/modules/core-collaboration/src/jixia/intervention/human_intervention_system.py
new file mode 100644
index 0000000..c6b6083
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/intervention/human_intervention_system.py
@@ -0,0 +1,929 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Human干预系统
+监控辩论健康度并在必要时触发人工干预
+"""
+
+import asyncio
+import json
+import logging
+from typing import Dict, List, Any, Optional, Callable, Tuple
+from dataclasses import dataclass, field
+from enum import Enum
+from datetime import datetime, timedelta
+import statistics
+import re
+
+class HealthStatus(Enum):
+ """健康状态"""
+ EXCELLENT = "优秀" # 90-100分
+ GOOD = "良好" # 70-89分
+ FAIR = "一般" # 50-69分
+ POOR = "较差" # 30-49分
+ CRITICAL = "危险" # 0-29分
+
+class InterventionLevel(Enum):
+ """干预级别"""
+ NONE = (0, "无需干预")
+ GENTLE_REMINDER = (1, "温和提醒")
+ MODERATE_GUIDANCE = (2, "适度引导")
+ STRONG_INTERVENTION = (3, "强力干预")
+ EMERGENCY_STOP = (4, "紧急停止")
+
+ def __init__(self, level, description):
+ self.level = level
+ self.description = description
+
+ @property
+ def value(self):
+ return self.description
+
+ def __ge__(self, other):
+ if isinstance(other, InterventionLevel):
+ return self.level >= other.level
+ return NotImplemented
+
+ def __gt__(self, other):
+ if isinstance(other, InterventionLevel):
+ return self.level > other.level
+ return NotImplemented
+
+ def __le__(self, other):
+ if isinstance(other, InterventionLevel):
+ return self.level <= other.level
+ return NotImplemented
+
+ def __lt__(self, other):
+ if isinstance(other, InterventionLevel):
+ return self.level < other.level
+ return NotImplemented
+
+class AlertType(Enum):
+ """警报类型"""
+ QUALITY_DECLINE = "质量下降"
+ TOXIC_BEHAVIOR = "有害行为"
+ REPETITIVE_CONTENT = "重复内容"
+ OFF_TOPIC = "偏离主题"
+ EMOTIONAL_ESCALATION = "情绪升级"
+ PARTICIPATION_IMBALANCE = "参与不平衡"
+ TECHNICAL_ERROR = "技术错误"
+ TIME_VIOLATION = "时间违规"
+
+@dataclass
+class HealthMetric:
+ """健康指标"""
+ name: str
+ value: float
+ weight: float
+ threshold_critical: float
+ threshold_poor: float
+ threshold_fair: float
+ threshold_good: float
+ description: str
+ last_updated: datetime = field(default_factory=datetime.now)
+
+@dataclass
+class InterventionAlert:
+ """干预警报"""
+ id: str
+ alert_type: AlertType
+ severity: InterventionLevel
+ message: str
+ affected_participants: List[str]
+ metrics: Dict[str, float]
+ timestamp: datetime
+ resolved: bool = False
+ resolution_notes: str = ""
+ human_notified: bool = False
+
+@dataclass
+class InterventionAction:
+ """干预动作"""
+ id: str
+ action_type: str
+ description: str
+ target_participants: List[str]
+ parameters: Dict[str, Any]
+ executed_at: datetime
+ success: bool = False
+ result_message: str = ""
+
+class DebateHealthMonitor:
+ """辩论健康度监控器"""
+
+ def __init__(self):
+ self.health_metrics: Dict[str, HealthMetric] = {}
+ self.active_alerts: List[InterventionAlert] = []
+ self.intervention_history: List[InterventionAction] = []
+ self.monitoring_enabled = True
+ self.logger = logging.getLogger(__name__)
+
+ # 初始化健康指标
+ self._initialize_health_metrics()
+
+ # 事件处理器
+ self.event_handlers: Dict[str, List[Callable]] = {}
+
+ # 监控配置
+ self.monitoring_config = {
+ "check_interval_seconds": 30,
+ "alert_cooldown_minutes": 5,
+ "auto_intervention_enabled": True,
+ "human_notification_threshold": InterventionLevel.STRONG_INTERVENTION
+ }
+
+ def _initialize_health_metrics(self):
+ """初始化健康指标"""
+ metrics_config = [
+ {
+ "name": "content_quality",
+ "weight": 0.25,
+ "thresholds": {"critical": 20, "poor": 40, "fair": 60, "good": 80},
+ "description": "内容质量评分"
+ },
+ {
+ "name": "participation_balance",
+ "weight": 0.20,
+ "thresholds": {"critical": 30, "poor": 50, "fair": 70, "good": 85},
+ "description": "参与平衡度"
+ },
+ {
+ "name": "emotional_stability",
+ "weight": 0.20,
+ "thresholds": {"critical": 25, "poor": 45, "fair": 65, "good": 80},
+ "description": "情绪稳定性"
+ },
+ {
+ "name": "topic_relevance",
+ "weight": 0.15,
+ "thresholds": {"critical": 35, "poor": 55, "fair": 70, "good": 85},
+ "description": "主题相关性"
+ },
+ {
+ "name": "interaction_civility",
+ "weight": 0.10,
+ "thresholds": {"critical": 20, "poor": 40, "fair": 60, "good": 80},
+ "description": "互动文明度"
+ },
+ {
+ "name": "technical_stability",
+ "weight": 0.10,
+ "thresholds": {"critical": 40, "poor": 60, "fair": 75, "good": 90},
+ "description": "技术稳定性"
+ }
+ ]
+
+ for config in metrics_config:
+ metric = HealthMetric(
+ name=config["name"],
+ value=100.0, # 初始值
+ weight=config["weight"],
+ threshold_critical=config["thresholds"]["critical"],
+ threshold_poor=config["thresholds"]["poor"],
+ threshold_fair=config["thresholds"]["fair"],
+ threshold_good=config["thresholds"]["good"],
+ description=config["description"]
+ )
+ self.health_metrics[config["name"]] = metric
+
+ async def analyze_debate_health(self, debate_data: Dict[str, Any]) -> Tuple[float, HealthStatus]:
+ """分析辩论健康度"""
+ if not self.monitoring_enabled:
+ return 100.0, HealthStatus.EXCELLENT
+
+ # 更新各项健康指标
+ await self._update_content_quality(debate_data)
+ await self._update_participation_balance(debate_data)
+ await self._update_emotional_stability(debate_data)
+ await self._update_topic_relevance(debate_data)
+ await self._update_interaction_civility(debate_data)
+ await self._update_technical_stability(debate_data)
+
+ # 计算综合健康分数
+ total_score = 0.0
+ total_weight = 0.0
+
+ for metric in self.health_metrics.values():
+ total_score += metric.value * metric.weight
+ total_weight += metric.weight
+
+ overall_score = total_score / total_weight if total_weight > 0 else 0.0
+
+ # 确定健康状态
+ if overall_score >= 90:
+ status = HealthStatus.EXCELLENT
+ elif overall_score >= 70:
+ status = HealthStatus.GOOD
+ elif overall_score >= 50:
+ status = HealthStatus.FAIR
+ elif overall_score >= 30:
+ status = HealthStatus.POOR
+ else:
+ status = HealthStatus.CRITICAL
+
+ # 检查是否需要发出警报
+ await self._check_for_alerts(overall_score, status)
+
+ self.logger.info(f"辩论健康度分析完成: {overall_score:.1f}分 ({status.value})")
+
+ return overall_score, status
+
+ async def _update_content_quality(self, debate_data: Dict[str, Any]):
+ """更新内容质量指标"""
+ messages = debate_data.get("recent_messages", [])
+ if not messages:
+ return
+
+ quality_scores = []
+
+ for message in messages[-10:]: # 分析最近10条消息
+ content = message.get("content", "")
+
+ # 内容长度评分
+ length_score = min(len(content) / 100 * 50, 50) # 最多50分
+
+ # 词汇丰富度评分
+ words = content.split()
+ unique_words = len(set(words))
+ vocabulary_score = min(unique_words / len(words) * 30, 30) if words else 0
+
+ # 逻辑结构评分(简单检测)
+ logic_indicators = ["因为", "所以", "但是", "然而", "首先", "其次", "最后", "总之"]
+ logic_score = min(sum(1 for indicator in logic_indicators if indicator in content) * 5, 20)
+
+ total_score = length_score + vocabulary_score + logic_score
+ quality_scores.append(total_score)
+
+ avg_quality = statistics.mean(quality_scores) if quality_scores else 50
+ self.health_metrics["content_quality"].value = avg_quality
+ self.health_metrics["content_quality"].last_updated = datetime.now()
+
+ async def _update_participation_balance(self, debate_data: Dict[str, Any]):
+ """更新参与平衡度指标"""
+ messages = debate_data.get("recent_messages", [])
+ if not messages:
+ return
+
+ # 统计各参与者的发言次数
+ speaker_counts = {}
+ for message in messages[-20:]: # 分析最近20条消息
+ speaker = message.get("sender", "")
+ speaker_counts[speaker] = speaker_counts.get(speaker, 0) + 1
+
+ if not speaker_counts:
+ return
+
+ # 计算参与平衡度
+ counts = list(speaker_counts.values())
+ if len(counts) <= 1:
+ balance_score = 100
+ else:
+ # 使用标准差来衡量平衡度
+ mean_count = statistics.mean(counts)
+ std_dev = statistics.stdev(counts)
+
+ # 标准差越小,平衡度越高
+ balance_score = max(0, 100 - (std_dev / mean_count * 100))
+
+ self.health_metrics["participation_balance"].value = balance_score
+ self.health_metrics["participation_balance"].last_updated = datetime.now()
+
+ async def _update_emotional_stability(self, debate_data: Dict[str, Any]):
+ """更新情绪稳定性指标"""
+ messages = debate_data.get("recent_messages", [])
+ if not messages:
+ return
+
+ emotional_scores = []
+
+ # 情绪关键词
+ negative_emotions = ["愤怒", "生气", "讨厌", "恶心", "愚蠢", "白痴", "垃圾"]
+ positive_emotions = ["赞同", "支持", "优秀", "精彩", "同意", "认可"]
+
+ for message in messages[-15:]:
+ content = message.get("content", "")
+
+ # 检测负面情绪
+ negative_count = sum(1 for word in negative_emotions if word in content)
+ positive_count = sum(1 for word in positive_emotions if word in content)
+
+ # 检测大写字母比例(可能表示情绪激动)
+ if content:
+ caps_ratio = sum(1 for c in content if c.isupper()) / len(content)
+ else:
+ caps_ratio = 0
+
+ # 检测感叹号数量
+ exclamation_count = content.count("!")
+
+ # 计算情绪稳定性分数
+ emotion_score = 100
+ emotion_score -= negative_count * 15 # 负面情绪扣分
+ emotion_score += positive_count * 5 # 正面情绪加分
+ emotion_score -= caps_ratio * 30 # 大写字母扣分
+ emotion_score -= min(exclamation_count * 5, 20) # 感叹号扣分
+
+ emotional_scores.append(max(0, emotion_score))
+
+ avg_emotional_stability = statistics.mean(emotional_scores) if emotional_scores else 80
+ self.health_metrics["emotional_stability"].value = avg_emotional_stability
+ self.health_metrics["emotional_stability"].last_updated = datetime.now()
+
+ async def _update_topic_relevance(self, debate_data: Dict[str, Any]):
+ """更新主题相关性指标"""
+ messages = debate_data.get("recent_messages", [])
+ topic_keywords = debate_data.get("topic_keywords", [])
+
+ if not messages or not topic_keywords:
+ return
+
+ relevance_scores = []
+
+ for message in messages[-10:]:
+ content = message.get("content", "")
+
+ # 计算主题关键词匹配度
+ keyword_matches = sum(1 for keyword in topic_keywords if keyword in content)
+ relevance_score = min(keyword_matches / len(topic_keywords) * 100, 100) if topic_keywords else 50
+
+ relevance_scores.append(relevance_score)
+
+ avg_relevance = statistics.mean(relevance_scores) if relevance_scores else 70
+ self.health_metrics["topic_relevance"].value = avg_relevance
+ self.health_metrics["topic_relevance"].last_updated = datetime.now()
+
+ async def _update_interaction_civility(self, debate_data: Dict[str, Any]):
+ """更新互动文明度指标"""
+ messages = debate_data.get("recent_messages", [])
+ if not messages:
+ return
+
+ civility_scores = []
+
+ # 不文明行为关键词
+ uncivil_patterns = [
+ r"你.*蠢", r".*白痴.*", r".*垃圾.*", r"闭嘴", r"滚.*",
+ r".*傻.*", r".*笨.*", r".*废物.*"
+ ]
+
+ # 文明行为关键词
+ civil_patterns = [
+ r"请.*", r"谢谢", r"不好意思", r"抱歉", r"尊重", r"理解"
+ ]
+
+ for message in messages[-15:]:
+ content = message.get("content", "")
+
+ civility_score = 100
+
+ # 检测不文明行为
+ for pattern in uncivil_patterns:
+ if re.search(pattern, content):
+ civility_score -= 20
+
+ # 检测文明行为
+ for pattern in civil_patterns:
+ if re.search(pattern, content):
+ civility_score += 5
+
+ civility_scores.append(max(0, min(100, civility_score)))
+
+ avg_civility = statistics.mean(civility_scores) if civility_scores else 85
+ self.health_metrics["interaction_civility"].value = avg_civility
+ self.health_metrics["interaction_civility"].last_updated = datetime.now()
+
+ async def _update_technical_stability(self, debate_data: Dict[str, Any]):
+ """更新技术稳定性指标"""
+ system_status = debate_data.get("system_status", {})
+
+ stability_score = 100
+
+ # 检查错误率
+ error_rate = system_status.get("error_rate", 0)
+ stability_score -= error_rate * 100
+
+ # 检查响应时间
+ response_time = system_status.get("avg_response_time", 0)
+ if response_time > 2.0: # 超过2秒
+ stability_score -= (response_time - 2.0) * 10
+
+ # 检查系统负载
+ system_load = system_status.get("system_load", 0)
+ if system_load > 0.8: # 负载超过80%
+ stability_score -= (system_load - 0.8) * 50
+
+ self.health_metrics["technical_stability"].value = max(0, stability_score)
+ self.health_metrics["technical_stability"].last_updated = datetime.now()
+
+ async def _check_for_alerts(self, overall_score: float, status: HealthStatus):
+ """检查是否需要发出警报"""
+ current_time = datetime.now()
+
+ # 检查各项指标是否触发警报
+ for metric_name, metric in self.health_metrics.items():
+ alert_level = self._determine_alert_level(metric)
+
+ if alert_level != InterventionLevel.NONE:
+ # 检查是否在冷却期内
+ recent_alerts = [
+ alert for alert in self.active_alerts
+ if alert.alert_type.value == metric_name and
+ (current_time - alert.timestamp).total_seconds() <
+ self.monitoring_config["alert_cooldown_minutes"] * 60
+ ]
+
+ if not recent_alerts:
+ await self._create_alert(metric_name, metric, alert_level)
+
+ # 检查整体健康状态
+ if status in [HealthStatus.POOR, HealthStatus.CRITICAL]:
+ await self._create_system_alert(overall_score, status)
+
+ def _determine_alert_level(self, metric: HealthMetric) -> InterventionLevel:
+ """确定警报级别"""
+ if metric.value <= metric.threshold_critical:
+ return InterventionLevel.EMERGENCY_STOP
+ elif metric.value <= metric.threshold_poor:
+ return InterventionLevel.STRONG_INTERVENTION
+ elif metric.value <= metric.threshold_fair:
+ return InterventionLevel.MODERATE_GUIDANCE
+ elif metric.value <= metric.threshold_good:
+ return InterventionLevel.GENTLE_REMINDER
+ else:
+ return InterventionLevel.NONE
+
+ async def _create_alert(self, metric_name: str, metric: HealthMetric, level: InterventionLevel):
+ """创建警报"""
+ alert_type_map = {
+ "content_quality": AlertType.QUALITY_DECLINE,
+ "participation_balance": AlertType.PARTICIPATION_IMBALANCE,
+ "emotional_stability": AlertType.EMOTIONAL_ESCALATION,
+ "topic_relevance": AlertType.OFF_TOPIC,
+ "interaction_civility": AlertType.TOXIC_BEHAVIOR,
+ "technical_stability": AlertType.TECHNICAL_ERROR
+ }
+
+ alert = InterventionAlert(
+ id=f"alert_{datetime.now().timestamp()}",
+ alert_type=alert_type_map.get(metric_name, AlertType.QUALITY_DECLINE),
+ severity=level,
+ message=f"{metric.description}指标异常: {metric.value:.1f}分",
+ affected_participants=[],
+ metrics={metric_name: metric.value},
+ timestamp=datetime.now()
+ )
+
+ self.active_alerts.append(alert)
+
+ # 触发事件处理
+ await self._trigger_event_handlers("alert_created", alert)
+
+ # 检查是否需要自动干预
+ if self.monitoring_config["auto_intervention_enabled"]:
+ await self._execute_auto_intervention(alert)
+
+ # 检查是否需要通知Human
+ if level >= self.monitoring_config["human_notification_threshold"]:
+ await self._notify_human(alert)
+
+ self.logger.warning(f"创建警报: {alert.alert_type.value} - {alert.message}")
+
+ async def _create_system_alert(self, score: float, status: HealthStatus):
+ """创建系统级警报"""
+ level = InterventionLevel.STRONG_INTERVENTION if status == HealthStatus.POOR else InterventionLevel.EMERGENCY_STOP
+
+ alert = InterventionAlert(
+ id=f"system_alert_{datetime.now().timestamp()}",
+ alert_type=AlertType.QUALITY_DECLINE,
+ severity=level,
+ message=f"系统整体健康度异常: {score:.1f}分 ({status.value})",
+ affected_participants=[],
+ metrics={"overall_score": score},
+ timestamp=datetime.now()
+ )
+
+ self.active_alerts.append(alert)
+ await self._trigger_event_handlers("system_alert_created", alert)
+
+ if self.monitoring_config["auto_intervention_enabled"]:
+ await self._execute_auto_intervention(alert)
+
+ await self._notify_human(alert)
+
+ self.logger.critical(f"系统级警报: {alert.message}")
+
+ async def _execute_auto_intervention(self, alert: InterventionAlert):
+ """执行自动干预"""
+ intervention_strategies = {
+ AlertType.QUALITY_DECLINE: self._intervene_quality_decline,
+ AlertType.TOXIC_BEHAVIOR: self._intervene_toxic_behavior,
+ AlertType.EMOTIONAL_ESCALATION: self._intervene_emotional_escalation,
+ AlertType.PARTICIPATION_IMBALANCE: self._intervene_participation_imbalance,
+ AlertType.OFF_TOPIC: self._intervene_off_topic,
+ AlertType.TECHNICAL_ERROR: self._intervene_technical_error
+ }
+
+ strategy = intervention_strategies.get(alert.alert_type)
+ if strategy:
+ action = await strategy(alert)
+ if action:
+ self.intervention_history.append(action)
+ await self._trigger_event_handlers("intervention_executed", action)
+
+ async def _intervene_quality_decline(self, alert: InterventionAlert) -> Optional[InterventionAction]:
+ """干预质量下降"""
+ action = InterventionAction(
+ id=f"quality_intervention_{datetime.now().timestamp()}",
+ action_type="quality_guidance",
+ description="发送质量提升指导",
+ target_participants=["all"],
+ parameters={
+ "message": "💡 建议:请提供更详细的论证和具体的例证来支持您的观点。",
+ "guidance_type": "quality_improvement"
+ },
+ executed_at=datetime.now(),
+ success=True,
+ result_message="质量提升指导已发送"
+ )
+
+ self.logger.info(f"执行质量干预: {action.description}")
+ return action
+
+ async def _intervene_toxic_behavior(self, alert: InterventionAlert) -> Optional[InterventionAction]:
+ """干预有害行为"""
+ action = InterventionAction(
+ id=f"toxicity_intervention_{datetime.now().timestamp()}",
+ action_type="behavior_warning",
+ description="发送行为规范提醒",
+ target_participants=["all"],
+ parameters={
+ "message": "⚠️ 请保持文明讨论,避免使用攻击性语言。让我们专注于观点的交流。",
+ "warning_level": "moderate"
+ },
+ executed_at=datetime.now(),
+ success=True,
+ result_message="行为规范提醒已发送"
+ )
+
+ self.logger.warning(f"执行行为干预: {action.description}")
+ return action
+
+ async def _intervene_emotional_escalation(self, alert: InterventionAlert) -> Optional[InterventionAction]:
+ """干预情绪升级"""
+ action = InterventionAction(
+ id=f"emotion_intervention_{datetime.now().timestamp()}",
+ action_type="emotion_cooling",
+ description="发送情绪缓解建议",
+ target_participants=["all"],
+ parameters={
+ "message": "🧘 让我们暂停一下,深呼吸。理性的讨论更有助于达成共识。",
+ "cooling_period": 60 # 秒
+ },
+ executed_at=datetime.now(),
+ success=True,
+ result_message="情绪缓解建议已发送"
+ )
+
+ self.logger.info(f"执行情绪干预: {action.description}")
+ return action
+
+ async def _intervene_participation_imbalance(self, alert: InterventionAlert) -> Optional[InterventionAction]:
+ """干预参与不平衡"""
+ action = InterventionAction(
+ id=f"balance_intervention_{datetime.now().timestamp()}",
+ action_type="participation_encouragement",
+ description="鼓励平衡参与",
+ target_participants=["all"],
+ parameters={
+ "message": "🤝 鼓励所有参与者分享观点,让讨论更加丰富多元。",
+ "encouragement_type": "participation_balance"
+ },
+ executed_at=datetime.now(),
+ success=True,
+ result_message="参与鼓励消息已发送"
+ )
+
+ self.logger.info(f"执行参与平衡干预: {action.description}")
+ return action
+
+ async def _intervene_off_topic(self, alert: InterventionAlert) -> Optional[InterventionAction]:
+ """干预偏离主题"""
+ action = InterventionAction(
+ id=f"topic_intervention_{datetime.now().timestamp()}",
+ action_type="topic_redirect",
+ description="引导回归主题",
+ target_participants=["all"],
+ parameters={
+ "message": "🎯 让我们回到主要讨论话题,保持讨论的焦点和深度。",
+ "redirect_type": "topic_focus"
+ },
+ executed_at=datetime.now(),
+ success=True,
+ result_message="主题引导消息已发送"
+ )
+
+ self.logger.info(f"执行主题干预: {action.description}")
+ return action
+
+ async def _intervene_technical_error(self, alert: InterventionAlert) -> Optional[InterventionAction]:
+ """干预技术错误"""
+ action = InterventionAction(
+ id=f"tech_intervention_{datetime.now().timestamp()}",
+ action_type="technical_support",
+ description="提供技术支持",
+ target_participants=["system"],
+ parameters={
+ "message": "🔧 检测到技术问题,正在进行系统优化...",
+ "support_type": "system_optimization"
+ },
+ executed_at=datetime.now(),
+ success=True,
+ result_message="技术支持已启动"
+ )
+
+ self.logger.error(f"执行技术干预: {action.description}")
+ return action
+
+ async def _notify_human(self, alert: InterventionAlert):
+ """通知Human"""
+ if alert.human_notified:
+ return
+
+ notification = {
+ "type": "human_intervention_required",
+ "alert_id": alert.id,
+ "severity": alert.severity.value,
+ "message": alert.message,
+ "timestamp": alert.timestamp.isoformat(),
+ "metrics": alert.metrics,
+ "recommended_actions": self._get_recommended_actions(alert)
+ }
+
+ # 触发Human通知事件
+ await self._trigger_event_handlers("human_notification", notification)
+
+ alert.human_notified = True
+
+ self.logger.critical(f"Human通知已发送: {alert.message}")
+
+ def _get_recommended_actions(self, alert: InterventionAlert) -> List[str]:
+ """获取推荐的干预动作"""
+ recommendations = {
+ AlertType.QUALITY_DECLINE: [
+ "提供写作指导",
+ "分享优秀案例",
+ "调整讨论节奏"
+ ],
+ AlertType.TOXIC_BEHAVIOR: [
+ "发出警告",
+ "暂时禁言",
+ "私下沟通"
+ ],
+ AlertType.EMOTIONAL_ESCALATION: [
+ "暂停讨论",
+ "引导冷静",
+ "转移话题"
+ ],
+ AlertType.PARTICIPATION_IMBALANCE: [
+ "邀请发言",
+ "限制发言频率",
+ "分组讨论"
+ ],
+ AlertType.OFF_TOPIC: [
+ "重申主题",
+ "引导回归",
+ "设置议程"
+ ],
+ AlertType.TECHNICAL_ERROR: [
+ "重启系统",
+ "检查日志",
+ "联系技术支持"
+ ]
+ }
+
+ return recommendations.get(alert.alert_type, ["人工评估", "采取适当措施"])
+
+ async def _trigger_event_handlers(self, event_type: str, data: Any):
+ """触发事件处理器"""
+ if event_type in self.event_handlers:
+ for handler in self.event_handlers[event_type]:
+ try:
+ await handler(data)
+ except Exception as e:
+ self.logger.error(f"事件处理器错误: {e}")
+
+ def add_event_handler(self, event_type: str, handler: Callable):
+ """添加事件处理器"""
+ if event_type not in self.event_handlers:
+ self.event_handlers[event_type] = []
+ self.event_handlers[event_type].append(handler)
+
+ def update_metrics(self, metrics_data: Dict[str, float]):
+ """更新健康指标(兼容性方法)"""
+ for metric_name, value in metrics_data.items():
+ if metric_name in self.health_metrics:
+ self.health_metrics[metric_name].value = value
+ self.health_metrics[metric_name].last_updated = datetime.now()
+
+ def get_health_status(self) -> HealthStatus:
+ """获取当前健康状态(兼容性方法)"""
+ # 计算整体分数
+ total_score = 0.0
+ total_weight = 0.0
+
+ for metric in self.health_metrics.values():
+ total_score += metric.value * metric.weight
+ total_weight += metric.weight
+
+ overall_score = total_score / total_weight if total_weight > 0 else 0.0
+
+ # 确定状态
+ if overall_score >= 90:
+ return HealthStatus.EXCELLENT
+ elif overall_score >= 70:
+ return HealthStatus.GOOD
+ elif overall_score >= 50:
+ return HealthStatus.FAIR
+ elif overall_score >= 30:
+ return HealthStatus.POOR
+ else:
+ return HealthStatus.CRITICAL
+
+ def get_health_report(self) -> Dict[str, Any]:
+ """获取健康报告"""
+ # 计算整体分数
+ total_score = 0.0
+ total_weight = 0.0
+
+ for metric in self.health_metrics.values():
+ total_score += metric.value * metric.weight
+ total_weight += metric.weight
+
+ overall_score = total_score / total_weight if total_weight > 0 else 0.0
+
+ # 确定状态
+ if overall_score >= 90:
+ status = HealthStatus.EXCELLENT
+ elif overall_score >= 70:
+ status = HealthStatus.GOOD
+ elif overall_score >= 50:
+ status = HealthStatus.FAIR
+ elif overall_score >= 30:
+ status = HealthStatus.POOR
+ else:
+ status = HealthStatus.CRITICAL
+
+ report = {
+ "overall_score": round(overall_score, 1),
+ "health_status": status.value,
+ "metrics": {
+ name: {
+ "value": round(metric.value, 1),
+ "weight": metric.weight,
+ "description": metric.description,
+ "last_updated": metric.last_updated.isoformat()
+ }
+ for name, metric in self.health_metrics.items()
+ },
+ "active_alerts": len(self.active_alerts),
+ "recent_interventions": len([a for a in self.intervention_history
+ if (datetime.now() - a.executed_at).total_seconds() < 3600]),
+ "monitoring_enabled": self.monitoring_enabled,
+ "last_check": datetime.now().isoformat()
+ }
+
+ return report
+
+ def resolve_alert(self, alert_id: str, resolution_notes: str = ""):
+ """解决警报"""
+ for alert in self.active_alerts:
+ if alert.id == alert_id:
+ alert.resolved = True
+ alert.resolution_notes = resolution_notes
+ self.logger.info(f"警报已解决: {alert_id} - {resolution_notes}")
+ return True
+ return False
+
+ def clear_resolved_alerts(self):
+ """清理已解决的警报"""
+ before_count = len(self.active_alerts)
+ self.active_alerts = [alert for alert in self.active_alerts if not alert.resolved]
+ after_count = len(self.active_alerts)
+
+ cleared_count = before_count - after_count
+ if cleared_count > 0:
+ self.logger.info(f"清理了 {cleared_count} 个已解决的警报")
+
+ def enable_monitoring(self):
+ """启用监控"""
+ self.monitoring_enabled = True
+ self.logger.info("健康监控已启用")
+
+ def disable_monitoring(self):
+ """禁用监控"""
+ self.monitoring_enabled = False
+ self.logger.info("健康监控已禁用")
+
+ def save_monitoring_data(self, filename: str = "monitoring_data.json"):
+ """保存监控数据"""
+ # 序列化监控配置,处理InterventionLevel枚举
+ serialized_config = self.monitoring_config.copy()
+ serialized_config["human_notification_threshold"] = self.monitoring_config["human_notification_threshold"].value
+
+ data = {
+ "health_metrics": {
+ name: {
+ "name": metric.name,
+ "value": metric.value,
+ "weight": metric.weight,
+ "threshold_critical": metric.threshold_critical,
+ "threshold_poor": metric.threshold_poor,
+ "threshold_fair": metric.threshold_fair,
+ "threshold_good": metric.threshold_good,
+ "description": metric.description,
+ "last_updated": metric.last_updated.isoformat()
+ }
+ for name, metric in self.health_metrics.items()
+ },
+ "active_alerts": [
+ {
+ "id": alert.id,
+ "alert_type": alert.alert_type.value,
+ "severity": alert.severity.value,
+ "message": alert.message,
+ "affected_participants": alert.affected_participants,
+ "metrics": alert.metrics,
+ "timestamp": alert.timestamp.isoformat(),
+ "resolved": alert.resolved,
+ "resolution_notes": alert.resolution_notes,
+ "human_notified": alert.human_notified
+ }
+ for alert in self.active_alerts
+ ],
+ "intervention_history": [
+ {
+ "id": action.id,
+ "action_type": action.action_type,
+ "description": action.description,
+ "target_participants": action.target_participants,
+ "parameters": action.parameters,
+ "executed_at": action.executed_at.isoformat(),
+ "success": action.success,
+ "result_message": action.result_message
+ }
+ for action in self.intervention_history
+ ],
+ "monitoring_config": serialized_config,
+ "monitoring_enabled": self.monitoring_enabled,
+ "export_time": datetime.now().isoformat()
+ }
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False, indent=2)
+
+ self.logger.info(f"监控数据已保存到 {filename}")
+
+# 使用示例
+async def main():
+ """使用示例"""
+ monitor = DebateHealthMonitor()
+
+ # 模拟辩论数据
+ debate_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "AI投资确实具有巨大潜力,我们可以从以下几个方面来分析..."},
+ {"sender": "反1", "content": "但是风险也不容忽视!!!这些投资可能导致泡沫!"},
+ {"sender": "正2", "content": "好的"},
+ {"sender": "反2", "content": "你们这些观点太愚蠢了,完全没有逻辑!"},
+ ],
+ "topic_keywords": ["AI", "投资", "风险", "收益", "技术"],
+ "system_status": {
+ "error_rate": 0.02,
+ "avg_response_time": 1.5,
+ "system_load": 0.6
+ }
+ }
+
+ # 分析健康度
+ score, status = await monitor.analyze_debate_health(debate_data)
+
+ print(f"\n📊 辩论健康度分析结果:")
+ print(f"综合得分: {score:.1f}分")
+ print(f"健康状态: {status.value}")
+
+ # 获取详细报告
+ report = monitor.get_health_report()
+ print(f"\n📋 详细健康报告:")
+ print(f"活跃警报数: {report['active_alerts']}")
+ print(f"近期干预数: {report['recent_interventions']}")
+
+ print(f"\n📈 各项指标:")
+ for name, metric in report['metrics'].items():
+ print(f" {metric['description']}: {metric['value']}分 (权重: {metric['weight']})")
+
+ # 保存数据
+ monitor.save_monitoring_data()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/jixia_ollama_swarm.py b/modules/core-collaboration/src/jixia/jixia_ollama_swarm.py
new file mode 100644
index 0000000..f7ddb7b
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/jixia_ollama_swarm.py
@@ -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())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/jixia_swarm_complete.py b/modules/core-collaboration/src/jixia/jixia_swarm_complete.py
new file mode 100644
index 0000000..1b4e9b3
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/jixia_swarm_complete.py
@@ -0,0 +1,557 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+稷下学宫完整版 - 基于OpenAI Swarm的八仙辩论系统
+实现完整的八仙论道 + 三清决策
+"""
+
+import os
+import asyncio
+import json
+import subprocess
+from datetime import datetime
+from swarm import Swarm, Agent
+from typing import Dict, List, Any, Optional
+import random
+
+class JixiaSwarmAcademy:
+ """稷下学宫 - 完整的八仙辩论系统"""
+
+ def __init__(self):
+ # 从Doppler获取API密钥
+ self.api_key = self.get_secure_api_key()
+
+ # 设置环境变量
+ if self.api_key:
+ os.environ["OPENAI_API_KEY"] = self.api_key
+ os.environ["OPENAI_BASE_URL"] = "https://openrouter.ai/api/v1"
+
+ # 初始化Swarm客户端,传入配置
+ from openai import OpenAI
+ openai_client = OpenAI(
+ api_key=self.api_key,
+ base_url="https://openrouter.ai/api/v1",
+ default_headers={
+ "HTTP-Referer": "https://github.com/ben/cauldron",
+ "X-Title": "Jixia Academy Debate System" # 避免中文字符
+ }
+ )
+ self.client = Swarm(client=openai_client)
+ else:
+ print("❌ 无法获取有效的API密钥")
+ self.client = None
+
+ # 八仙配置 - 完整版
+ self.immortals_config = {
+ '吕洞宾': {
+ 'role': '剑仙投资顾问',
+ 'gua_position': '乾☰',
+ 'specialty': '技术分析',
+ 'stance': 'positive',
+ 'style': '一剑封喉,直指要害',
+ 'personality': '犀利直接,善于识破市场迷雾',
+ 'weapon': '纯阳剑',
+ 'next': '何仙姑'
+ },
+ '何仙姑': {
+ 'role': '慈悲风控专家',
+ 'gua_position': '坤☷',
+ 'specialty': '风险控制',
+ 'stance': 'negative',
+ 'style': '荷花在手,全局在胸',
+ 'personality': '温和坚定,关注风险控制',
+ 'weapon': '荷花',
+ 'next': '张果老'
+ },
+ '张果老': {
+ 'role': '历史数据分析师',
+ 'gua_position': '艮☶',
+ 'specialty': '历史回测',
+ 'stance': 'positive',
+ 'style': '倒骑毛驴,逆向思维',
+ 'personality': '博古通今,从历史中寻找规律',
+ 'weapon': '鱼鼓',
+ 'next': '韩湘子'
+ },
+ '韩湘子': {
+ 'role': '市场情绪分析师',
+ 'gua_position': '兑☱',
+ 'specialty': '情绪分析',
+ 'stance': 'negative',
+ 'style': '笛声悠扬,感知人心',
+ 'personality': '敏感细腻,善于捕捉市场情绪',
+ 'weapon': '洞箫',
+ 'next': '汉钟离'
+ },
+ '汉钟离': {
+ 'role': '宏观经济分析师',
+ 'gua_position': '离☲',
+ 'specialty': '宏观分析',
+ 'stance': 'positive',
+ 'style': '扇子一挥,大局明了',
+ 'personality': '气度恢宏,关注宏观大势',
+ 'weapon': '芭蕉扇',
+ 'next': '蓝采和'
+ },
+ '蓝采和': {
+ 'role': '量化交易专家',
+ 'gua_position': '巽☴',
+ 'specialty': '量化模型',
+ 'stance': 'negative',
+ 'style': '花篮一抛,数据飞舞',
+ 'personality': '逻辑严密,依赖数学模型',
+ 'weapon': '花篮',
+ 'next': '曹国舅'
+ },
+ '曹国舅': {
+ 'role': '价值投资专家',
+ 'gua_position': '坎☵',
+ 'specialty': '基本面分析',
+ 'stance': 'positive',
+ 'style': '玉板一敲,价值显现',
+ 'personality': '稳重踏实,注重内在价值',
+ 'weapon': '玉板',
+ 'next': '铁拐李'
+ },
+ '铁拐李': {
+ 'role': '逆向投资大师',
+ 'gua_position': '震☳',
+ 'specialty': '逆向投资',
+ 'stance': 'negative',
+ 'style': '铁拐一点,危机毕现',
+ 'personality': '不拘一格,挑战主流观点',
+ 'weapon': '铁拐杖',
+ 'next': 'summary'
+ }
+ }
+
+ # 三清决策层配置
+ self.sanqing_config = {
+ '元始天尊': {
+ 'role': '最终决策者',
+ 'specialty': '综合决策',
+ 'style': '无极生太极,一言定乾坤'
+ },
+ '灵宝天尊': {
+ 'role': '风险评估师',
+ 'specialty': '风险量化',
+ 'style': '太极生两仪,阴阳定风险'
+ },
+ '道德天尊': {
+ 'role': '合规审查员',
+ 'specialty': '合规检查',
+ 'style': '两仪生四象,四象定规矩'
+ }
+ }
+
+ # 创建智能体
+ self.immortal_agents = self.create_immortal_agents()
+ self.sanqing_agents = self.create_sanqing_agents()
+
+ # 辩论历史
+ self.debate_history = []
+ self.current_round = 0
+ self.max_rounds = 2 # 每个仙人最多发言2轮
+
+ def get_secure_api_key(self):
+ """获取API密钥 - 支持多种方式"""
+ # 从环境变量获取API密钥
+ available_keys = [
+ os.getenv("OPENROUTER_API_KEY_1"),
+ os.getenv("OPENROUTER_API_KEY_2"),
+ os.getenv("OPENROUTER_API_KEY_3"),
+ os.getenv("OPENROUTER_API_KEY_4")
+ ]
+ # 过滤掉None值
+ available_keys = [key for key in available_keys if key]
+
+ # 直接使用第一个密钥进行测试
+ test_key = available_keys[0]
+ print(f"🔑 直接使用测试密钥: {test_key[:20]}...")
+ return test_key
+
+
+
+ def create_immortal_agents(self) -> Dict[str, Agent]:
+ """创建八仙智能体"""
+ agents = {}
+
+ for name, config in self.immortals_config.items():
+ # 创建转换函数 - 使用英文名称避免特殊字符问题
+ next_immortal = config['next']
+ if next_immortal == 'summary':
+ transfer_func = self.transfer_to_sanqing
+ else:
+ # 创建一个简单的转换函数,避免lambda的问题
+ def create_transfer_func(next_name):
+ def transfer():
+ return self.transfer_to_immortal(next_name)
+ transfer.__name__ = f"transfer_to_{self.get_english_name(next_name)}"
+ return transfer
+ transfer_func = create_transfer_func(next_immortal)
+
+ # 构建详细的指令
+ instructions = self.build_immortal_instructions(name, config)
+
+ agents[name] = Agent(
+ name=name,
+ instructions=instructions,
+ functions=[transfer_func]
+ )
+
+ return agents
+
+ def create_sanqing_agents(self) -> Dict[str, Agent]:
+ """创建三清决策层智能体"""
+ agents = {}
+
+ # 元始天尊 - 最终决策者
+ agents['元始天尊'] = Agent(
+ name="元始天尊",
+ instructions="""
+ 你是元始天尊,道教三清之首,稷下学宫的最终决策者。
+
+ 你的使命:
+ 1. 综合八仙的所有观点,做出最终投资决策
+ 2. 平衡正反两方的观点,寻找最优解
+ 3. 给出具体的投资建议和操作指导
+ 4. 评估决策的风险等级和预期收益
+
+ 你的风格:
+ - 高屋建瓴,统揽全局
+ - 言简意赅,一锤定音
+ - 既不偏向乐观,也不偏向悲观
+ - 以数据和逻辑为准绳
+
+ 请以"元始天尊曰"开头,给出最终决策。
+ 决策格式:
+ - 投资建议:买入/持有/卖出
+ - 风险等级:低/中/高
+ - 预期收益:具体百分比
+ - 操作建议:具体的操作指导
+ - 决策依据:主要的决策理由
+ """,
+ functions=[]
+ )
+
+ return agents
+
+ def build_immortal_instructions(self, name: str, config: Dict) -> str:
+ """构建仙人的详细指令"""
+ stance_desc = "看涨派,倾向于发现投资机会" if config['stance'] == 'positive' else "看跌派,倾向于发现投资风险"
+
+ instructions = f"""
+ 你是{name},八仙之一,{config['role']}。
+
+ 你的身份特征:
+ - 位居{config['gua_position']}之位,代表{self.get_gua_meaning(config['gua_position'])}
+ - 持有{config['weapon']},{config['style']}
+ - 擅长{config['specialty']},{config['personality']}
+ - 立场倾向:{stance_desc}
+
+ 在稷下学宫辩论中,你要:
+
+ 1. **专业分析**:从{config['specialty']}角度深入分析
+ 2. **立场鲜明**:作为{stance_desc},要有明确的观点
+ 3. **数据支撑**:用具体的数据、图表、历史案例支撑观点
+ 4. **互动辩论**:可以质疑前面仙人的观点,但要有理有据
+ 5. **仙风道骨**:保持古雅的表达风格,但不影响专业性
+ 6. **承上启下**:总结前面的观点,为后面的仙人铺垫
+
+ 发言格式:
+ - 以"{name}曰:"开头
+ - 先简要回应前面仙人的观点(如果有)
+ - 然后从你的专业角度进行分析
+ - 最后明确表达你的投资倾向
+ - 结尾时说"请{config['next']}仙长继续论道"(如果不是最后一个)
+
+ 记住:你是{stance_desc},要体现这个立场,但也要保持专业和客观。
+ """
+
+ return instructions
+
+ def get_gua_meaning(self, gua: str) -> str:
+ """获取卦象含义"""
+ meanings = {
+ '乾☰': '天行健,自强不息',
+ '坤☷': '地势坤,厚德载物',
+ '艮☶': '艮为山,止于至善',
+ '兑☱': '兑为泽,和悦致祥',
+ '离☲': '离为火,光明磊落',
+ '巽☴': '巽为风,随风而化',
+ '坎☵': '坎为水,智慧如水',
+ '震☳': '震为雷,威震四方'
+ }
+ return meanings.get(gua, '神秘莫测')
+
+ def transfer_to_hexiangu(self):
+ """转到何仙姑"""
+ return self.immortal_agents.get('何仙姑')
+
+ def transfer_to_zhangguolao(self):
+ """转到张果老"""
+ return self.immortal_agents.get('张果老')
+
+ def transfer_to_hanxiangzi(self):
+ """转到韩湘子"""
+ return self.immortal_agents.get('韩湘子')
+
+ def transfer_to_hanzhongli(self):
+ """转到汉钟离"""
+ return self.immortal_agents.get('汉钟离')
+
+ def transfer_to_lancaihe(self):
+ """转到蓝采和"""
+ return self.immortal_agents.get('蓝采和')
+
+ def transfer_to_caoguojiu(self):
+ """转到曹国舅"""
+ return self.immortal_agents.get('曹国舅')
+
+ def transfer_to_tieguaili(self):
+ """转到铁拐李"""
+ return self.immortal_agents.get('铁拐李')
+
+ def transfer_to_sanqing(self):
+ """转到三清决策层"""
+ return self.sanqing_agents['元始天尊']
+
+ async def conduct_full_debate(self, topic: str, context: Dict[str, Any] = None) -> Dict[str, Any]:
+ """进行完整的稷下学宫辩论"""
+ if not self.api_key or not self.client:
+ print("❌ 无法获取API密钥或初始化客户端,无法进行论道")
+ return None
+
+ print("🏛️ 稷下学宫八仙论道正式开始!")
+ print("=" * 80)
+ print(f"🎯 论道主题: {topic}")
+ print(f"⏰ 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+ print()
+
+ # 构建初始提示
+ initial_prompt = self.build_debate_prompt(topic, context)
+
+ try:
+ # 从吕洞宾开始论道
+ print("⚔️ 吕洞宾仙长请先发言...")
+ print("-" * 60)
+
+ response = self.client.run(
+ agent=self.immortal_agents['吕洞宾'],
+ messages=[{"role": "user", "content": initial_prompt}],
+ max_turns=20 # 允许多轮对话
+ )
+
+ print("\n" + "=" * 80)
+ print("🎊 稷下学宫八仙论道圆满结束!")
+ print("📊 三清决策已生成")
+
+ # 处理辩论结果
+ debate_result = self.process_debate_result(response, topic, context)
+
+ # 显示辩论总结
+ self.display_debate_summary(debate_result)
+
+ return debate_result
+
+ except Exception as e:
+ print(f"❌ 论道过程中出错: {e}")
+ import traceback
+ traceback.print_exc()
+ return None
+
+ def build_debate_prompt(self, topic: str, context: Dict[str, Any] = None) -> str:
+ """构建辩论提示"""
+ context_str = ""
+ if context:
+ context_str = f"\n📊 市场背景:\n{json.dumps(context, indent=2, ensure_ascii=False)}\n"
+
+ # 随机选择一些市场数据作为背景
+ market_context = self.generate_market_context(topic)
+
+ prompt = f"""
+ 🏛️ 稷下学宫八仙论道正式开始!
+
+ 📜 论道主题: {topic}
+ {context_str}
+ 📈 当前市场环境:
+ {market_context}
+
+ 🎭 论道规则:
+ 1. 八仙按序发言:吕洞宾 → 何仙姑 → 张果老 → 韩湘子 → 汉钟离 → 蓝采和 → 曹国舅 → 铁拐李
+ 2. 正反方交替:正方(看涨) vs 反方(看跌)
+ 3. 每位仙人从专业角度分析,必须提供数据支撑
+ 4. 可以质疑前面仙人的观点,但要有理有据
+ 5. 保持仙风道骨的表达风格
+ 6. 最后由三清做出最终决策
+
+ 🗡️ 请吕洞宾仙长首先发言,展现剑仙的犀利分析!
+ 记住:你是看涨派,要从技术分析角度找到投资机会!
+ """
+ return prompt
+
+ def generate_market_context(self, topic: str) -> str:
+ """生成模拟的市场背景数据"""
+ # 这里可以集成真实的市场数据,现在先用模拟数据
+ contexts = {
+ "英伟达": "NVDA当前价格$120,P/E比率65,市值$3T,AI芯片需求旺盛",
+ "比特币": "BTC当前价格$43,000,24h涨幅+2.3%,机构持续买入",
+ "美联储": "联邦基金利率5.25%,通胀率3.2%,就业数据强劲",
+ "中国股市": "上证指数3100点,外资流入放缓,政策支持预期"
+ }
+
+ # 根据主题选择相关背景
+ for key, context in contexts.items():
+ if key in topic:
+ return context
+
+ return "市场情绪谨慎,波动率上升,投资者观望情绪浓厚"
+
+ def process_debate_result(self, response, topic: str, context: Dict[str, Any]) -> Dict[str, Any]:
+ """处理辩论结果"""
+ # 提取所有消息
+ all_messages = response.messages if hasattr(response, 'messages') else []
+
+ # 分析发言者和内容
+ debate_messages = []
+ speakers = []
+
+ for msg in all_messages:
+ if msg.get('role') == 'assistant' and msg.get('content'):
+ content = msg['content']
+ speaker = self.extract_speaker_from_content(content)
+
+ debate_messages.append({
+ 'speaker': speaker,
+ 'content': content,
+ 'timestamp': datetime.now().isoformat(),
+ 'stance': self.get_speaker_stance(speaker)
+ })
+
+ if speaker not in speakers:
+ speakers.append(speaker)
+
+ # 提取最终决策(通常是最后一条消息)
+ final_decision = ""
+ if debate_messages:
+ final_decision = debate_messages[-1]['content']
+
+ # 构建结果
+ result = {
+ "debate_id": f"jixia_debate_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
+ "topic": topic,
+ "context": context,
+ "participants": speakers,
+ "messages": debate_messages,
+ "final_decision": final_decision,
+ "summary": self.generate_debate_summary(debate_messages),
+ "timestamp": datetime.now().isoformat(),
+ "framework": "OpenAI Swarm",
+ "academy": "稷下学宫"
+ }
+
+ self.debate_history.append(result)
+ return result
+
+ def extract_speaker_from_content(self, content: str) -> str:
+ """从内容中提取发言者"""
+ for name in list(self.immortals_config.keys()) + list(self.sanqing_config.keys()):
+ if f"{name}曰" in content or name in content[:20]:
+ return name
+ return "未知仙人"
+
+ def get_speaker_stance(self, speaker: str) -> str:
+ """获取发言者立场"""
+ if speaker in self.immortals_config:
+ return self.immortals_config[speaker]['stance']
+ elif speaker in self.sanqing_config:
+ return 'neutral'
+ return 'unknown'
+
+ def generate_debate_summary(self, messages: List[Dict]) -> str:
+ """生成辩论摘要"""
+ positive_count = len([m for m in messages if m.get('stance') == 'positive'])
+ negative_count = len([m for m in messages if m.get('stance') == 'negative'])
+
+ summary = f"""
+ 📊 辩论统计:
+ - 参与仙人: {len(set(m['speaker'] for m in messages))}位
+ - 看涨观点: {positive_count}条
+ - 看跌观点: {negative_count}条
+ - 总发言数: {len(messages)}条
+
+ 🎯 观点倾向: {'偏向看涨' if positive_count > negative_count else '偏向看跌' if negative_count > positive_count else '观点平衡'}
+ """
+
+ return summary
+
+ def display_debate_summary(self, result: Dict[str, Any]):
+ """显示辩论总结"""
+ print("\n🌟 稷下学宫辩论总结")
+ print("=" * 80)
+ print(f"📜 主题: {result['topic']}")
+ print(f"🎭 参与仙人: {', '.join(result['participants'])}")
+ print(f"⏰ 辩论时间: {result['timestamp']}")
+ print(f"🔧 技术框架: {result['framework']}")
+
+ print(result['summary'])
+
+ print("\n🏆 最终决策:")
+ print("-" * 40)
+ print(result['final_decision'])
+
+ print("\n✨ 稷下学宫辩论特色:")
+ print("🗡️ 八仙各展所长,观点多元化")
+ print("⚖️ 正反方交替发言,辩论更激烈")
+ print("🧠 三清最终决策,权威性更强")
+ print("🔄 基于Swarm框架,性能更优越")
+
+# 主函数和测试
+async def main():
+ """主函数 - 演示完整的稷下学宫辩论"""
+ print("🏛️ 稷下学宫 - OpenAI Swarm完整版")
+ print("🔐 使用Doppler安全管理API密钥")
+ print("🚀 八仙论道 + 三清决策的完整体验")
+ print()
+
+ # 创建学宫
+ academy = JixiaSwarmAcademy()
+
+ if not academy.api_key:
+ print("❌ 无法获取API密钥,请检查Doppler配置或环境变量")
+ return
+
+ # 辩论主题列表
+ topics = [
+ "英伟达股价走势:AI泡沫还是技术革命?",
+ "美联储2024年货币政策:加息还是降息?",
+ "比特币vs黄金:谁是更好的避险资产?",
+ "中国房地产市场:触底反弹还是继续下行?",
+ "特斯拉股价:马斯克效应还是基本面支撑?"
+ ]
+
+ # 随机选择主题
+ topic = random.choice(topics)
+
+ # 构建市场背景
+ context = {
+ "market_sentiment": "谨慎乐观",
+ "volatility": "中等",
+ "major_events": ["美联储会议", "财报季", "地缘政治紧张"],
+ "technical_indicators": {
+ "RSI": 65,
+ "MACD": "金叉",
+ "MA20": "上穿"
+ }
+ }
+
+ # 开始辩论
+ result = await academy.conduct_full_debate(topic, context)
+
+ if result:
+ print(f"\n🎉 辩论成功完成!辩论ID: {result['debate_id']}")
+ else:
+ print("❌ 辩论失败")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/main.py b/modules/core-collaboration/src/jixia/main.py
new file mode 100644
index 0000000..4f8c444
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/main.py
@@ -0,0 +1,455 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+稷下学宫AI辩论系统主入口
+提供命令行界面来运行不同的辩论模式
+"""
+
+import argparse
+import asyncio
+import sys
+import os
+import warnings
+
+# 将项目根目录添加到 Python 路径,以便能正确导入模块
+project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.insert(0, project_root)
+
+# 抑制 google-adk 的调试日志和警告
+import logging
+logging.getLogger('google.adk').setLevel(logging.ERROR)
+logging.getLogger('google.genai').setLevel(logging.ERROR)
+# 设置环境变量来抑制ADK调试输出
+os.environ['GOOGLE_CLOUD_DISABLE_GRPC_LOGS'] = 'true'
+os.environ['GRPC_VERBOSITY'] = 'ERROR'
+os.environ['GRPC_TRACE'] = ''
+
+# 抑制 warnings
+warnings.filterwarnings('ignore')
+
+from config.settings import validate_config
+
+
+def check_environment():
+ """检查并验证运行环境"""
+ print("🔧 检查运行环境...")
+
+ # 验证基础配置
+ if not validate_config():
+ print("❌ 环境配置验证失败")
+ return False
+
+ print("✅ 环境检查通过")
+ return True
+
+
+async def run_adk_memory_debate(topic: str, participants: list = None):
+ """运行ADK记忆增强辩论"""
+ print("⚠️ ADK记忆增强辩论功能正在适配新版本的 google-adk 库...")
+ print("💡 请先使用 'adk_simple' 模式进行测试。")
+ return False
+
+ # 以下代码暂时保留,待适配完成后再启用
+ """
+ try:
+ from src.jixia.debates.adk_memory_debate import MemoryEnhancedDebate
+
+ print(f"🚀 启动ADK记忆增强辩论...")
+ print(f"📋 辩论主题: {topic}")
+
+ # 创建并初始化辩论系统
+ debate_system = MemoryEnhancedDebate()
+ await debate_system.initialize()
+
+ # 进行辩论
+ await debate_system.conduct_memory_debate(
+ topic=topic,
+ participants=participants
+ )
+
+ # 关闭资源
+ await debate_system.close()
+
+ print("\n🎉 ADK记忆增强辩论完成!")
+ return True
+
+ except ImportError as e:
+ print(f"❌ 导入模块失败: {e}")
+ print("请确保已安装Google ADK: pip install google-adk")
+ return False
+ except Exception as e:
+ print(f"❌ 运行ADK记忆增强辩论失败: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+ """
+
+
+async def run_adk_turn_based_debate(topic: str, participants: list = None, rounds: int = 3):
+ """运行ADK八仙轮流辩论"""
+ try:
+ from google.adk import Agent, Runner
+ from google.adk.sessions import InMemorySessionService
+ from google.genai import types
+ import asyncio
+
+ print(f"🚀 启动ADK八仙轮流辩论...")
+ print(f"📋 辩论主题: {topic}")
+ print(f"🔄 辩论轮数: {rounds}")
+
+ # 默认参与者为八仙
+ if not participants or participants == ["铁拐李", "吕洞宾"]:
+ participants = ["铁拐李", "吕洞宾", "何仙姑", "张果老", "蓝采和", "汉钟离", "韩湘子", "曹国舅"]
+
+ # 定义主持人和八仙角色配置
+ roles_config = {
+ # 主持人
+ "太上老君": {
+ "name": "太上老君",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是太上老君,本次论道的主持人。你负责引导辩论的流程,确保每位仙人都有机会发言,并在每一轮结束后进行简要总结。你的发言风格庄重、睿智,能够调和不同观点之间的矛盾。每次发言控制在100字以内。"
+ },
+ # 八仙
+ "铁拐李": {
+ "name": "铁拐李",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是铁拐李,八仙中的逆向思维专家。你善于从批判和质疑的角度看问题,总是能发现事物的另一面。你的发言风格直接、犀利,但富有智慧。每次发言控制在100字以内。"
+ },
+ "吕洞宾": {
+ "name": "吕洞宾",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是吕洞宾,八仙中的理性分析者。你善于平衡各方观点,用理性和逻辑来分析问题。你的发言风格温和而深刻,总是能找到问题的核心。每次发言控制在100字以内。"
+ },
+ "何仙姑": {
+ "name": "何仙姑",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是何仙姑,八仙中的风险控制专家。你总是从风险管理的角度思考问题,善于发现潜在危险。你的发言风格谨慎、细致,总是能提出需要警惕的问题。每次发言控制在100字以内。"
+ },
+ "张果老": {
+ "name": "张果老",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是张果老,八仙中的历史智慧者。你善于从历史数据中寻找规律和智慧,总是能提供长期视角。你的发言风格沉稳、博学,总是能引经据典。每次发言控制在100字以内。"
+ },
+ "蓝采和": {
+ "name": "蓝采和",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是蓝采和,八仙中的创新思维者。你善于从新兴视角和非传统方法来看待问题,总能提出独特的见解。你的发言风格活泼、新颖,总是能带来意想不到的观点。每次发言控制在100字以内。"
+ },
+ "汉钟离": {
+ "name": "汉钟离",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是汉钟离,八仙中的平衡协调者。你善于综合各方观点,寻求和谐统一的解决方案。你的发言风格平和、包容,总是能化解矛盾。每次发言控制在100字以内。"
+ },
+ "韩湘子": {
+ "name": "韩湘子",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是韩湘子,八仙中的艺术感知者。你善于从美学和感性的角度分析问题,总能发现事物背后的深层含义。你的发言风格优雅、感性,总是能触动人心。每次发言控制在100字以内。"
+ },
+ "曹国舅": {
+ "name": "曹国舅",
+ "model": "gemini-2.5-flash",
+ "instruction": "你是曹国舅,八仙中的实务执行者。你关注实际操作和具体细节,善于将理论转化为可行的方案。你的发言风格务实、严谨,总是能提出建设性意见。每次发言控制在100字以内。"
+ }
+ }
+
+ # 创建会话服务和会话
+ session_service = InMemorySessionService()
+ session = await session_service.create_session(
+ state={},
+ app_name="稷下学宫轮流辩论系统",
+ user_id="debate_user"
+ )
+
+ # 创建主持人和八仙智能体及Runner
+ host_agent = None
+ host_runner = None
+ baxian_agents = {}
+ baxian_runners = {}
+
+ # 创建主持人
+ host_config = roles_config["太上老君"]
+ host_agent = Agent(
+ name=host_config["name"],
+ model=host_config["model"],
+ instruction=host_config["instruction"]
+ )
+ host_runner = Runner(
+ app_name="稷下学宫轮流辩论系统",
+ agent=host_agent,
+ session_service=session_service
+ )
+
+ # 创建八仙
+ for name in participants:
+ if name in roles_config:
+ config = roles_config[name]
+ agent = Agent(
+ name=config["name"],
+ model=config["model"],
+ instruction=config["instruction"]
+ )
+ baxian_agents[name] = agent
+
+ runner = Runner(
+ app_name="稷下学宫轮流辩论系统",
+ agent=agent,
+ session_service=session_service
+ )
+ baxian_runners[name] = runner
+ else:
+ print(f"⚠️ 未知的参与者: {name},将被跳过。")
+
+ if not baxian_agents:
+ print("❌ 没有有效的参与者,请检查参与者列表。")
+ return False
+
+ print(f"🎯 主持人: 太上老君")
+ print(f"👥 参与仙人: {', '.join(baxian_agents.keys())}")
+
+ # 初始化辩论历史
+ debate_history = []
+
+ # 开场白
+ print(f"\n📢 太上老君开场:")
+ opening_prompt = f"各位仙友,欢迎来到本次论道。今天的主题是:{topic}。请各位依次发表高见。"
+ content = types.Content(role='user', parts=[types.Part(text=opening_prompt)])
+ response = host_runner.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content
+ )
+ reply = ""
+ async for event in 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:
+ reply += str(part.text)
+ elif hasattr(event, 'text') and event.text:
+ reply += str(event.text)
+ if reply.strip():
+ clean_reply = reply.strip()
+ print(f" {clean_reply}")
+ debate_history.append(f"太上老君: {clean_reply}")
+ await asyncio.sleep(1)
+
+ # 进行辩论
+ for round_num in range(rounds):
+ print(f"\n🌀 第 {round_num + 1} 轮辩论:")
+
+ # 主持人引导本轮辩论
+ print(f"\n📢 太上老君引导:")
+ guide_prompt = f"现在进入第 {round_num + 1} 轮辩论,请各位仙友围绕主题发表看法。"
+ content = types.Content(role='user', parts=[types.Part(text=guide_prompt)])
+ response = host_runner.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content
+ )
+ reply = ""
+ async for event in 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:
+ reply += str(part.text)
+ elif hasattr(event, 'text') and event.text:
+ reply += str(event.text)
+ if reply.strip():
+ clean_reply = reply.strip()
+ print(f" {clean_reply}")
+ debate_history.append(f"太上老君: {clean_reply}")
+ await asyncio.sleep(1)
+
+ # 八仙轮流发言
+ for name in participants:
+ if name not in baxian_runners:
+ continue
+
+ print(f"\n🗣️ {name} 发言:")
+
+ # 构建提示
+ history_context = ""
+ if debate_history:
+ recent_history = debate_history[-5:] # 最近5条发言
+ history_context = f"\n最近的论道内容:\n" + "\n".join([f"- {h}" for h in recent_history])
+
+ prompt = f"论道主题: {topic}{history_context}\n\n请从你的角色特点出发发表观点。请控制在100字以内。"
+
+ # 发送消息并获取回复
+ content = types.Content(role='user', parts=[types.Part(text=prompt)])
+ response = baxian_runners[name].run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content
+ )
+
+ # 收集回复
+ reply = ""
+ async for event in 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:
+ reply += str(part.text)
+ elif hasattr(event, 'text') and event.text:
+ reply += str(event.text)
+
+ if reply.strip():
+ clean_reply = reply.strip()
+ print(f" {clean_reply}")
+
+ # 记录到辩论历史
+ debate_entry = f"{name}: {clean_reply}"
+ debate_history.append(debate_entry)
+
+ await asyncio.sleep(1) # 避免API调用过快
+
+ # 结束语
+ print(f"\n📢 太上老君总结:")
+ closing_prompt = f"各位仙友的高见令我受益匪浅。本次论道到此结束,希望各位能从不同观点中获得启发。"
+ content = types.Content(role='user', parts=[types.Part(text=closing_prompt)])
+ response = host_runner.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content
+ )
+ reply = ""
+ async for event in 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:
+ reply += str(part.text)
+ elif hasattr(event, 'text') and event.text:
+ reply += str(event.text)
+ if reply.strip():
+ clean_reply = reply.strip()
+ print(f" {clean_reply}")
+ debate_history.append(f"太上老君: {clean_reply}")
+ await asyncio.sleep(1)
+
+ # 关闭资源
+ await host_runner.close()
+ for runner in baxian_runners.values():
+ await runner.close()
+
+ print(f"\n🎉 ADK八仙轮流辩论完成!")
+ print(f"📝 本次论道共产生 {len(debate_history)} 条发言。")
+ return True
+
+ except ImportError as e:
+ print(f"❌ 导入模块失败: {e}")
+ print("请确保已安装Google ADK: pip install google-adk")
+ return False
+ except Exception as e:
+ print(f"❌ 运行ADK八仙轮流辩论失败: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+
+async def run_swarm_debate(topic: str, participants: list = None):
+ """运行Swarm辩论 (示例)"""
+ try:
+ print(f"🚀 启动Swarm辩论...")
+ print(f"📋 辩论主题: {topic}")
+ print(f"👥 参与者: {participants}")
+
+ # TODO: 实现调用 Swarm 辩论逻辑
+ # 这里需要根据实际的 swarm_debate.py 接口来实现
+ print("⚠️ Swarm辩论功能待实现")
+
+ print("\n🎉 Swarm辩论完成!")
+ return True
+
+ except Exception as e:
+ print(f"❌ 运行Swarm辩论失败: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+
+async def main_async(args):
+ """异步主函数"""
+ # 检查环境
+ if not check_environment():
+ return 1
+
+ # 根据模式运行不同的辩论
+ if args.mode == "adk_memory":
+ participants = args.participants.split(",") if args.participants else None
+ success = await run_adk_memory_debate(args.topic, participants)
+ return 0 if success else 1
+
+ elif args.mode == "adk_turn_based":
+ participants = args.participants.split(",") if args.participants else None
+ success = await run_adk_turn_based_debate(args.topic, participants, args.rounds)
+ return 0 if success else 1
+
+ elif args.mode == "adk_simple":
+ # 简单辩论模式暂时使用原来的方式
+ try:
+ sys.path.insert(0, os.path.join(project_root, 'examples', 'debates'))
+ from adk_simple_debate import simple_debate_test
+ result = simple_debate_test()
+ return 0 if result else 1
+ except Exception as e:
+ print(f"❌ 运行ADK简单辩论失败: {e}")
+ return 1
+
+ elif args.mode == "swarm":
+ participants = args.participants.split(",") if args.participants else None
+ success = await run_swarm_debate(args.topic, participants)
+ return 0 if success else 1
+
+ else:
+ print(f"❌ 不支持的模式: {args.mode}")
+ return 1
+
+
+def main():
+ """主入口函数"""
+ parser = argparse.ArgumentParser(description="稷下学宫AI辩论系统")
+ parser.add_argument(
+ "mode",
+ choices=["adk_memory", "adk_turn_based", "adk_simple", "swarm"],
+ help="辩论模式"
+ )
+ parser.add_argument(
+ "--topic",
+ "-t",
+ default="人工智能对未来社会的影响",
+ help="辩论主题"
+ )
+ parser.add_argument(
+ "--participants",
+ "-p",
+ help="参与者列表(逗号分隔),例如: 铁拐李,吕洞宾,何仙姑"
+ )
+ parser.add_argument(
+ "--rounds",
+ "-r",
+ type=int,
+ default=3,
+ help="辩论轮数 (仅适用于 adk_turn_based 模式)"
+ )
+
+ args = parser.parse_args()
+
+ # 运行异步主函数
+ try:
+ exit_code = asyncio.run(main_async(args))
+ sys.exit(exit_code)
+ except KeyboardInterrupt:
+ print("\n\n👋 用户中断,退出程序")
+ sys.exit(0)
+ except Exception as e:
+ print(f"\n\n💥 程序运行出错: {e}")
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/memory/base_memory_bank.py b/modules/core-collaboration/src/jixia/memory/base_memory_bank.py
new file mode 100644
index 0000000..9244514
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/memory/base_memory_bank.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+"""
+通用记忆银行抽象,便于插入不同后端(Vertex、Cloudflare AutoRAG等)
+"""
+from __future__ import annotations
+
+from typing import Dict, List, Any, Optional, Protocol, runtime_checkable
+
+
+@runtime_checkable
+class MemoryBankProtocol(Protocol):
+ async def create_memory_bank(self, agent_name: str, display_name: Optional[str] = None) -> str: ...
+
+ async def add_memory(
+ self,
+ agent_name: str,
+ content: str,
+ memory_type: str = "conversation",
+ debate_topic: str = "",
+ metadata: Optional[Dict[str, Any]] = None,
+ ) -> str: ...
+
+ async def search_memories(
+ self,
+ agent_name: str,
+ query: str,
+ memory_type: Optional[str] = None,
+ limit: int = 10,
+ ) -> List[Dict[str, Any]]: ...
+
+ async def get_agent_context(self, agent_name: str, debate_topic: str) -> str: ...
+
+ async def save_debate_session(
+ self,
+ debate_topic: str,
+ participants: List[str],
+ conversation_history: List[Dict[str, str]],
+ outcomes: Optional[Dict[str, Any]] = None,
+ ) -> None: ...
diff --git a/modules/core-collaboration/src/jixia/memory/cloudflare_memory_bank.py b/modules/core-collaboration/src/jixia/memory/cloudflare_memory_bank.py
new file mode 100644
index 0000000..2c284c6
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/memory/cloudflare_memory_bank.py
@@ -0,0 +1,454 @@
+#!/usr/bin/env python3
+"""
+Cloudflare AutoRAG Vectorize 记忆银行实现
+为稷下学宫AI辩论系统提供Cloudflare后端的记忆功能
+"""
+
+import os
+import json
+from typing import Dict, List, Optional, Any
+from dataclasses import dataclass
+from datetime import datetime
+import aiohttp
+from config.settings import get_cloudflare_config
+
+
+@dataclass
+class MemoryEntry:
+ """记忆条目数据结构"""
+ id: str
+ content: str
+ metadata: Dict[str, Any]
+ timestamp: str # ISO format string
+ agent_name: str
+ debate_topic: str
+ memory_type: str # "conversation", "preference", "knowledge", "strategy"
+
+
+class CloudflareMemoryBank:
+ """
+ Cloudflare AutoRAG Vectorize 记忆银行管理器
+ 利用Cloudflare Vectorize索引和Workers AI进行向量检索增强生成
+ """
+
+ def __init__(self):
+ """初始化Cloudflare Memory Bank"""
+ self.config = get_cloudflare_config()
+ self.account_id = self.config['account_id']
+ self.api_token = self.config['api_token']
+ self.vectorize_index = self.config['vectorize_index']
+ self.embed_model = self.config['embed_model']
+ self.autorag_domain = self.config['autorag_domain']
+
+ # 构建API基础URL
+ self.base_url = f"https://api.cloudflare.com/client/v4/accounts/{self.account_id}"
+ self.headers = {
+ "Authorization": f"Bearer {self.api_token}",
+ "Content-Type": "application/json"
+ }
+
+ # 八仙智能体名称映射
+ self.baxian_agents = {
+ "tieguaili": "铁拐李",
+ "hanzhongli": "汉钟离",
+ "zhangguolao": "张果老",
+ "lancaihe": "蓝采和",
+ "hexiangu": "何仙姑",
+ "lvdongbin": "吕洞宾",
+ "hanxiangzi": "韩湘子",
+ "caoguojiu": "曹国舅"
+ }
+
+ async def _get_session(self) -> aiohttp.ClientSession:
+ """获取aiohttp会话"""
+ return aiohttp.ClientSession()
+
+ async def create_memory_bank(self, agent_name: str, display_name: str = None) -> str:
+ """
+ 为指定智能体创建记忆空间(在Cloudflare中通过命名空间或元数据实现)
+
+ Args:
+ agent_name: 智能体名称 (如 "tieguaili")
+ display_name: 显示名称 (如 "铁拐李的记忆银行")
+
+ Returns:
+ 记忆空间标识符 (这里用agent_name作为标识符)
+ """
+ # Cloudflare Vectorize使用统一的索引,通过元数据区分不同智能体的记忆
+ # 所以这里不需要实际创建,只需要返回标识符
+ if not display_name:
+ display_name = self.baxian_agents.get(agent_name, agent_name)
+
+ print(f"✅ 为 {display_name} 准备Cloudflare记忆空间")
+ return f"cf_memory_{agent_name}"
+
+ async def add_memory(self,
+ agent_name: str,
+ content: str,
+ memory_type: str = "conversation",
+ debate_topic: str = "",
+ metadata: Dict[str, Any] = None) -> str:
+ """
+ 添加记忆到Cloudflare Vectorize索引
+
+ Args:
+ agent_name: 智能体名称
+ content: 记忆内容
+ memory_type: 记忆类型 ("conversation", "preference", "knowledge", "strategy")
+ debate_topic: 辩论主题
+ metadata: 额外元数据
+
+ Returns:
+ 记忆ID
+ """
+ if metadata is None:
+ metadata = {}
+
+ # 生成记忆ID
+ memory_id = f"mem_{agent_name}_{int(datetime.now().timestamp() * 1000000)}"
+
+ # 构建记忆条目
+ memory_entry = MemoryEntry(
+ id=memory_id,
+ content=content,
+ metadata={
+ **metadata,
+ "agent_name": agent_name,
+ "chinese_name": self.baxian_agents.get(agent_name, agent_name),
+ "memory_type": memory_type,
+ "debate_topic": debate_topic,
+ "system": "jixia_academy"
+ },
+ timestamp=datetime.now().isoformat(),
+ agent_name=agent_name,
+ debate_topic=debate_topic,
+ memory_type=memory_type
+ )
+
+ # 将记忆条目转换为JSON字符串,用于存储和检索
+ memory_data = {
+ "id": memory_id,
+ "values": [], # 向量值将在嵌入时填充
+ "metadata": memory_entry.metadata
+ }
+
+ try:
+ # 1. 使用Workers AI生成嵌入向量
+ embedding = await self._generate_embedding(content)
+ memory_data["values"] = embedding
+
+ # 2. 将记忆插入Vectorize索引
+ async with await self._get_session() as session:
+ url = f"{self.base_url}/vectorize/indexes/{self.vectorize_index}/upsert"
+ payload = {
+ "vectors": [memory_data]
+ }
+
+ async with session.post(url, headers=self.headers, json=payload) as response:
+ if response.status == 200:
+ result = await response.json()
+ print(f"✅ 为 {self.baxian_agents.get(agent_name)} 添加记忆: {memory_type}")
+ return memory_id
+ else:
+ error_text = await response.text()
+ raise Exception(f"Failed to upsert memory: {response.status} - {error_text}")
+
+ except Exception as e:
+ print(f"❌ 添加记忆失败: {e}")
+ raise
+
+ async def _generate_embedding(self, text: str) -> List[float]:
+ """
+ 使用Cloudflare Workers AI生成文本嵌入
+
+ Args:
+ text: 要嵌入的文本
+
+ Returns:
+ 嵌入向量
+ """
+ async with await self._get_session() as session:
+ url = f"{self.base_url}/ai/run/{self.embed_model}"
+ payload = {
+ "text": [text] # Workers AI embeddings API expects a list of texts
+ }
+
+ async with session.post(url, headers=self.headers, json=payload) as response:
+ if response.status == 200:
+ result = await response.json()
+ # 提取嵌入向量 (通常是 result["result"]["data"][0]["embedding"])
+ if "result" in result and "data" in result["result"] and len(result["result"]["data"]) > 0:
+ return result["result"]["data"][0]["embedding"]
+ else:
+ raise Exception(f"Unexpected embedding response format: {result}")
+ else:
+ error_text = await response.text()
+ raise Exception(f"Failed to generate embedding: {response.status} - {error_text}")
+
+ async def search_memories(self,
+ agent_name: str,
+ query: str,
+ memory_type: str = None,
+ limit: int = 10) -> List[Dict[str, Any]]:
+ """
+ 使用向量相似性搜索智能体的相关记忆
+
+ Args:
+ agent_name: 智能体名称
+ query: 搜索查询
+ memory_type: 记忆类型过滤
+ limit: 返回结果数量限制
+
+ Returns:
+ 相关记忆列表
+ """
+ try:
+ # 1. 为查询生成嵌入向量
+ query_embedding = await self._generate_embedding(query)
+
+ # 2. 构建过滤条件
+ filters = {
+ "agent_name": agent_name
+ }
+ if memory_type:
+ filters["memory_type"] = memory_type
+
+ # 3. 执行向量搜索
+ async with await self._get_session() as session:
+ url = f"{self.base_url}/vectorize/indexes/{self.vectorize_index}/query"
+ payload = {
+ "vector": query_embedding,
+ "topK": limit,
+ "filter": filters,
+ "returnMetadata": True
+ }
+
+ async with session.post(url, headers=self.headers, json=payload) as response:
+ if response.status == 200:
+ result = await response.json()
+ matches = result.get("result", {}).get("matches", [])
+
+ # 格式化返回结果
+ memories = []
+ for match in matches:
+ memory_data = {
+ "content": match["metadata"].get("content", ""),
+ "metadata": match["metadata"],
+ "relevance_score": match["score"]
+ }
+ memories.append(memory_data)
+
+ return memories
+ else:
+ error_text = await response.text()
+ raise Exception(f"Failed to search memories: {response.status} - {error_text}")
+
+ except Exception as e:
+ print(f"❌ 搜索记忆失败: {e}")
+ return []
+
+ async def get_agent_context(self, agent_name: str, debate_topic: str) -> str:
+ """
+ 获取智能体在特定辩论主题下的上下文记忆
+
+ Args:
+ agent_name: 智能体名称
+ debate_topic: 辩论主题
+
+ Returns:
+ 格式化的上下文字符串
+ """
+ # 搜索相关记忆
+ conversation_memories = await self.search_memories(
+ agent_name, debate_topic, "conversation", limit=5
+ )
+ preference_memories = await self.search_memories(
+ agent_name, debate_topic, "preference", limit=3
+ )
+ strategy_memories = await self.search_memories(
+ agent_name, debate_topic, "strategy", limit=3
+ )
+
+ # 构建上下文
+ context_parts = []
+
+ if conversation_memories:
+ context_parts.append("## 历史对话记忆")
+ for mem in conversation_memories:
+ context_parts.append(f"- {mem['content']}")
+
+ if preference_memories:
+ context_parts.append("\n## 偏好记忆")
+ for mem in preference_memories:
+ context_parts.append(f"- {mem['content']}")
+
+ if strategy_memories:
+ context_parts.append("\n## 策略记忆")
+ for mem in strategy_memories:
+ context_parts.append(f"- {mem['content']}")
+
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+ if context_parts:
+ return f"# {chinese_name}的记忆上下文\n\n" + "\n".join(context_parts)
+ else:
+ return f"# {chinese_name}的记忆上下文\n\n暂无相关记忆。"
+
+ async def save_debate_session(self,
+ debate_topic: str,
+ participants: List[str],
+ conversation_history: List[Dict[str, str]],
+ outcomes: Dict[str, Any] = None) -> None:
+ """
+ 保存完整的辩论会话到各参与者的记忆银行
+
+ Args:
+ debate_topic: 辩论主题
+ participants: 参与者列表
+ conversation_history: 对话历史
+ outcomes: 辩论结果和洞察
+ """
+ for agent_name in participants:
+ if agent_name not in self.baxian_agents:
+ continue
+
+ # 保存对话历史
+ conversation_summary = self._summarize_conversation(
+ conversation_history, agent_name
+ )
+ await self.add_memory(
+ agent_name=agent_name,
+ content=conversation_summary,
+ memory_type="conversation",
+ debate_topic=debate_topic,
+ metadata={
+ "participants": participants,
+ "session_length": len(conversation_history)
+ }
+ )
+
+ # 保存策略洞察
+ if outcomes:
+ strategy_insight = self._extract_strategy_insight(
+ outcomes, agent_name
+ )
+ if strategy_insight:
+ await self.add_memory(
+ agent_name=agent_name,
+ content=strategy_insight,
+ memory_type="strategy",
+ debate_topic=debate_topic,
+ metadata={"session_outcome": outcomes}
+ )
+
+ def _summarize_conversation(self,
+ conversation_history: List[Dict[str, str]],
+ agent_name: str) -> str:
+ """
+ 为特定智能体总结对话历史
+
+ Args:
+ conversation_history: 对话历史
+ agent_name: 智能体名称
+
+ Returns:
+ 对话总结
+ """
+ agent_messages = [
+ msg for msg in conversation_history
+ if msg.get("agent") == agent_name
+ ]
+
+ if not agent_messages:
+ return "本次辩论中未发言"
+
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+ summary = f"{chinese_name}在本次辩论中的主要观点:\n"
+
+ for i, msg in enumerate(agent_messages[:3], 1): # 只取前3条主要观点
+ summary += f"{i}. {msg.get('content', '')[:100]}...\n"
+
+ return summary
+
+ def _extract_strategy_insight(self,
+ outcomes: Dict[str, Any],
+ agent_name: str) -> Optional[str]:
+ """
+ 从辩论结果中提取策略洞察
+
+ Args:
+ outcomes: 辩论结果
+ agent_name: 智能体名称
+
+ Returns:
+ 策略洞察或None
+ """
+ # 这里可以根据实际的outcomes结构来提取洞察
+ # 暂时返回一个简单的示例
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+
+ if "winner" in outcomes and outcomes["winner"] == agent_name:
+ return f"{chinese_name}在本次辩论中获胜,其论证策略值得保持。"
+ elif "insights" in outcomes and agent_name in outcomes["insights"]:
+ return outcomes["insights"][agent_name]
+
+ return None
+
+
+# 便捷函数
+async def initialize_baxian_memory_banks() -> CloudflareMemoryBank:
+ """
+ 初始化所有八仙智能体的Cloudflare记忆空间
+
+ Returns:
+ 配置好的CloudflareMemoryBank实例
+ """
+ memory_bank = CloudflareMemoryBank()
+
+ print("🏛️ 正在为稷下学宫八仙创建Cloudflare记忆空间...")
+
+ for agent_key, chinese_name in memory_bank.baxian_agents.items():
+ try:
+ await memory_bank.create_memory_bank(agent_key)
+ except Exception as e:
+ print(f"⚠️ 创建 {chinese_name} 记忆空间时出错: {e}")
+
+ print("✅ 八仙Cloudflare记忆空间初始化完成")
+ return memory_bank
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ async def test_memory_bank():
+ """测试Cloudflare Memory Bank功能"""
+ try:
+ # 创建Memory Bank实例
+ memory_bank = CloudflareMemoryBank()
+
+ # 测试创建记忆空间
+ await memory_bank.create_memory_bank("tieguaili")
+
+ # 测试添加记忆
+ await memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ # 测试搜索记忆
+ results = await memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="NVIDIA",
+ limit=5
+ )
+
+ print(f"搜索结果: {len(results)} 条记忆")
+ for result in results:
+ print(f"- {result['content']}")
+
+ except Exception as e:
+ print(f"❌ 测试失败: {e}")
+
+ # 运行测试
+ asyncio.run(test_memory_bank())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/memory/factory.py b/modules/core-collaboration/src/jixia/memory/factory.py
new file mode 100644
index 0000000..b968d24
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/memory/factory.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+"""
+记忆银行工厂:根据配置创建不同后端实现(Vertex AI 或 Cloudflare AutoRAG)
+"""
+from __future__ import annotations
+
+import os
+from typing import Optional
+
+from .base_memory_bank import MemoryBankProtocol
+from .vertex_memory_bank import VertexMemoryBank
+# 新增 Cloudflare 实现
+from .cloudflare_memory_bank import CloudflareMemoryBank
+
+
+def get_memory_backend(prefer: Optional[str] = None) -> MemoryBankProtocol:
+ """
+ 强制使用 Vertex AI 作为记忆后端。
+ 'prefer' 参数将被忽略。
+ """
+ # 强制使用 Vertex AI 后端
+ try:
+ mem = VertexMemoryBank.from_config()
+ print("🧠 使用 Vertex AI 作为记忆后端")
+ return mem
+ except Exception as e:
+ # 不可用时抛错
+ raise RuntimeError(
+ "未能创建 Vertex 记忆后端:请配置 Vertex (GOOGLE_*) 环境变量"
+ ) from e
diff --git a/modules/core-collaboration/src/jixia/memory/vertex_memory_bank.py b/modules/core-collaboration/src/jixia/memory/vertex_memory_bank.py
new file mode 100644
index 0000000..63e0621
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/memory/vertex_memory_bank.py
@@ -0,0 +1,463 @@
+#!/usr/bin/env python3
+"""
+Vertex AI Memory Bank 集成模块
+为稷下学宫AI辩论系统提供记忆银行功能
+"""
+
+import os
+from typing import Dict, List, Optional, Any
+from dataclasses import dataclass
+from datetime import datetime
+import json
+
+try:
+ from google.cloud import aiplatform
+ # Memory Bank 功能可能还在预览版中,先使用基础功能
+ VERTEX_AI_AVAILABLE = True
+except ImportError:
+ VERTEX_AI_AVAILABLE = False
+ print("⚠️ Google Cloud AI Platform 未安装,Memory Bank功能不可用")
+ print("安装命令: pip install google-cloud-aiplatform")
+
+from config.settings import get_google_genai_config
+
+
+@dataclass
+class MemoryEntry:
+ """记忆条目数据结构"""
+ content: str
+ metadata: Dict[str, Any]
+ timestamp: datetime
+ agent_name: str
+ debate_topic: str
+ memory_type: str # "conversation", "preference", "knowledge", "strategy"
+
+
+class VertexMemoryBank:
+ """
+ Vertex AI Memory Bank 管理器
+ 为八仙辩论系统提供智能记忆功能
+ """
+
+ def __init__(self, project_id: str, location: str = "us-central1"):
+ """
+ 初始化Memory Bank
+
+ Args:
+ project_id: Google Cloud项目ID
+ location: 部署区域
+ """
+ if not VERTEX_AI_AVAILABLE:
+ print("⚠️ Google Cloud AI Platform 未安装,使用本地模拟模式")
+ # 不抛出异常,允许使用本地模拟模式
+
+ self.project_id = project_id
+ self.location = location
+ self.memory_banks = {} # 存储不同智能体的记忆银行
+ self.local_memories = {} # 本地记忆存储 (临时方案)
+
+ # 初始化AI Platform
+ try:
+ aiplatform.init(project=project_id, location=location)
+ print(f"✅ Vertex AI 初始化成功: {project_id} @ {location}")
+ except Exception as e:
+ print(f"⚠️ Vertex AI 初始化失败,使用本地模拟模式: {e}")
+
+ # 八仙智能体名称映射
+ self.baxian_agents = {
+ "tieguaili": "铁拐李",
+ "hanzhongli": "汉钟离",
+ "zhangguolao": "张果老",
+ "lancaihe": "蓝采和",
+ "hexiangu": "何仙姑",
+ "lvdongbin": "吕洞宾",
+ "hanxiangzi": "韩湘子",
+ "caoguojiu": "曹国舅"
+ }
+
+ @classmethod
+ def from_config(cls) -> 'VertexMemoryBank':
+ """
+ 从配置创建Memory Bank实例
+
+ Returns:
+ VertexMemoryBank实例
+ """
+ config = get_google_genai_config()
+ project_id = config.get('project_id')
+ location = config.get('location', 'us-central1')
+
+ if not project_id:
+ raise ValueError("Google Cloud Project ID 未配置,请设置 GOOGLE_CLOUD_PROJECT_ID")
+
+ return cls(project_id=project_id, location=location)
+
+ async def create_memory_bank(self, agent_name: str, display_name: str = None) -> str:
+ """
+ 为指定智能体创建记忆银行
+
+ Args:
+ agent_name: 智能体名称 (如 "tieguaili")
+ display_name: 显示名称 (如 "铁拐李的记忆银行")
+
+ Returns:
+ 记忆银行ID
+ """
+ if not display_name:
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+ display_name = f"{chinese_name}的记忆银行"
+
+ try:
+ # 使用本地存储模拟记忆银行 (临时方案)
+ memory_bank_id = f"memory_bank_{agent_name}_{self.project_id}"
+
+ # 初始化本地记忆存储
+ if agent_name not in self.local_memories:
+ self.local_memories[agent_name] = []
+
+ self.memory_banks[agent_name] = memory_bank_id
+ print(f"✅ 为 {display_name} 创建记忆银行: {memory_bank_id}")
+
+ return memory_bank_id
+
+ except Exception as e:
+ print(f"❌ 创建记忆银行失败: {e}")
+ raise
+
+ async def add_memory(self,
+ agent_name: str,
+ content: str,
+ memory_type: str = "conversation",
+ debate_topic: str = "",
+ metadata: Dict[str, Any] = None) -> str:
+ """
+ 添加记忆到指定智能体的记忆银行
+
+ Args:
+ agent_name: 智能体名称
+ content: 记忆内容
+ memory_type: 记忆类型 ("conversation", "preference", "knowledge", "strategy")
+ debate_topic: 辩论主题
+ metadata: 额外元数据
+
+ Returns:
+ 记忆ID
+ """
+ if agent_name not in self.memory_banks:
+ await self.create_memory_bank(agent_name)
+
+ if metadata is None:
+ metadata = {}
+
+ # 构建记忆条目
+ memory_entry = MemoryEntry(
+ content=content,
+ metadata={
+ **metadata,
+ "agent_name": agent_name,
+ "chinese_name": self.baxian_agents.get(agent_name, agent_name),
+ "memory_type": memory_type,
+ "debate_topic": debate_topic,
+ "system": "jixia_academy"
+ },
+ timestamp=datetime.now(),
+ agent_name=agent_name,
+ debate_topic=debate_topic,
+ memory_type=memory_type
+ )
+
+ try:
+ # 使用本地存储添加记忆 (临时方案)
+ memory_id = f"memory_{agent_name}_{len(self.local_memories[agent_name])}"
+
+ # 添加到本地存储
+ memory_data = {
+ "id": memory_id,
+ "content": content,
+ "metadata": memory_entry.metadata,
+ "timestamp": memory_entry.timestamp.isoformat(),
+ "memory_type": memory_type,
+ "debate_topic": debate_topic
+ }
+
+ self.local_memories[agent_name].append(memory_data)
+
+ print(f"✅ 为 {self.baxian_agents.get(agent_name)} 添加记忆: {memory_type}")
+ return memory_id
+
+ except Exception as e:
+ print(f"❌ 添加记忆失败: {e}")
+ raise
+
+ async def search_memories(self,
+ agent_name: str,
+ query: str,
+ memory_type: str = None,
+ limit: int = 10) -> List[Dict[str, Any]]:
+ """
+ 搜索智能体的相关记忆
+
+ Args:
+ agent_name: 智能体名称
+ query: 搜索查询
+ memory_type: 记忆类型过滤
+ limit: 返回结果数量限制
+
+ Returns:
+ 相关记忆列表
+ """
+ if agent_name not in self.memory_banks:
+ return []
+
+ try:
+ # 使用本地存储搜索记忆 (临时方案)
+ if agent_name not in self.local_memories:
+ return []
+
+ memories = self.local_memories[agent_name]
+ results = []
+
+ # 简单的文本匹配搜索
+ query_lower = query.lower()
+
+ for memory in memories:
+ # 检查记忆类型过滤
+ if memory_type and memory.get("memory_type") != memory_type:
+ continue
+
+ # 检查内容匹配
+ content_lower = memory["content"].lower()
+ debate_topic_lower = memory.get("debate_topic", "").lower()
+
+ # 在内容或辩论主题中搜索
+ if query_lower in content_lower or query_lower in debate_topic_lower:
+ # 计算简单的相关性分数
+ content_matches = content_lower.count(query_lower)
+ topic_matches = debate_topic_lower.count(query_lower)
+ total_words = len(content_lower.split()) + len(debate_topic_lower.split())
+
+ relevance_score = (content_matches + topic_matches) / max(total_words, 1)
+
+ results.append({
+ "content": memory["content"],
+ "metadata": memory["metadata"],
+ "relevance_score": relevance_score
+ })
+
+ # 按相关性排序并限制结果数量
+ results.sort(key=lambda x: x["relevance_score"], reverse=True)
+ return results[:limit]
+
+ except Exception as e:
+ print(f"❌ 搜索记忆失败: {e}")
+ return []
+
+ async def get_agent_context(self, agent_name: str, debate_topic: str) -> str:
+ """
+ 获取智能体在特定辩论主题下的上下文记忆
+
+ Args:
+ agent_name: 智能体名称
+ debate_topic: 辩论主题
+
+ Returns:
+ 格式化的上下文字符串
+ """
+ # 搜索相关记忆
+ conversation_memories = await self.search_memories(
+ agent_name, debate_topic, "conversation", limit=5
+ )
+ preference_memories = await self.search_memories(
+ agent_name, debate_topic, "preference", limit=3
+ )
+ strategy_memories = await self.search_memories(
+ agent_name, debate_topic, "strategy", limit=3
+ )
+
+ # 构建上下文
+ context_parts = []
+
+ if conversation_memories:
+ context_parts.append("## 历史对话记忆")
+ for mem in conversation_memories:
+ context_parts.append(f"- {mem['content']}")
+
+ if preference_memories:
+ context_parts.append("\n## 偏好记忆")
+ for mem in preference_memories:
+ context_parts.append(f"- {mem['content']}")
+
+ if strategy_memories:
+ context_parts.append("\n## 策略记忆")
+ for mem in strategy_memories:
+ context_parts.append(f"- {mem['content']}")
+
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+ if context_parts:
+ return f"# {chinese_name}的记忆上下文\n\n" + "\n".join(context_parts)
+ else:
+ return f"# {chinese_name}的记忆上下文\n\n暂无相关记忆。"
+
+ async def save_debate_session(self,
+ debate_topic: str,
+ participants: List[str],
+ conversation_history: List[Dict[str, str]],
+ outcomes: Dict[str, Any] = None) -> None:
+ """
+ 保存完整的辩论会话到各参与者的记忆银行
+
+ Args:
+ debate_topic: 辩论主题
+ participants: 参与者列表
+ conversation_history: 对话历史
+ outcomes: 辩论结果和洞察
+ """
+ for agent_name in participants:
+ if agent_name not in self.baxian_agents:
+ continue
+
+ # 保存对话历史
+ conversation_summary = self._summarize_conversation(
+ conversation_history, agent_name
+ )
+ await self.add_memory(
+ agent_name=agent_name,
+ content=conversation_summary,
+ memory_type="conversation",
+ debate_topic=debate_topic,
+ metadata={
+ "participants": participants,
+ "session_length": len(conversation_history)
+ }
+ )
+
+ # 保存策略洞察
+ if outcomes:
+ strategy_insight = self._extract_strategy_insight(
+ outcomes, agent_name
+ )
+ if strategy_insight:
+ await self.add_memory(
+ agent_name=agent_name,
+ content=strategy_insight,
+ memory_type="strategy",
+ debate_topic=debate_topic,
+ metadata={"session_outcome": outcomes}
+ )
+
+ def _summarize_conversation(self,
+ conversation_history: List[Dict[str, str]],
+ agent_name: str) -> str:
+ """
+ 为特定智能体总结对话历史
+
+ Args:
+ conversation_history: 对话历史
+ agent_name: 智能体名称
+
+ Returns:
+ 对话总结
+ """
+ agent_messages = [
+ msg for msg in conversation_history
+ if msg.get("agent") == agent_name
+ ]
+
+ if not agent_messages:
+ return "本次辩论中未发言"
+
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+ summary = f"{chinese_name}在本次辩论中的主要观点:\n"
+
+ for i, msg in enumerate(agent_messages[:3], 1): # 只取前3条主要观点
+ summary += f"{i}. {msg.get('content', '')[:100]}...\n"
+
+ return summary
+
+ def _extract_strategy_insight(self,
+ outcomes: Dict[str, Any],
+ agent_name: str) -> Optional[str]:
+ """
+ 从辩论结果中提取策略洞察
+
+ Args:
+ outcomes: 辩论结果
+ agent_name: 智能体名称
+
+ Returns:
+ 策略洞察或None
+ """
+ # 这里可以根据实际的outcomes结构来提取洞察
+ # 暂时返回一个简单的示例
+ chinese_name = self.baxian_agents.get(agent_name, agent_name)
+
+ if "winner" in outcomes and outcomes["winner"] == agent_name:
+ return f"{chinese_name}在本次辩论中获胜,其论证策略值得保持。"
+ elif "insights" in outcomes and agent_name in outcomes["insights"]:
+ return outcomes["insights"][agent_name]
+
+ return None
+
+
+# 便捷函数
+async def initialize_baxian_memory_banks(project_id: str, location: str = "us-central1") -> VertexMemoryBank:
+ """
+ 初始化所有八仙智能体的记忆银行
+
+ Args:
+ project_id: Google Cloud项目ID
+ location: 部署区域
+
+ Returns:
+ 配置好的VertexMemoryBank实例
+ """
+ memory_bank = VertexMemoryBank(project_id, location)
+
+ print("🏛️ 正在为稷下学宫八仙创建记忆银行...")
+
+ for agent_key, chinese_name in memory_bank.baxian_agents.items():
+ try:
+ await memory_bank.create_memory_bank(agent_key)
+ except Exception as e:
+ print(f"⚠️ 创建 {chinese_name} 记忆银行时出错: {e}")
+
+ print("✅ 八仙记忆银行初始化完成")
+ return memory_bank
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ async def test_memory_bank():
+ """测试Memory Bank功能"""
+ try:
+ # 从配置创建Memory Bank
+ memory_bank = VertexMemoryBank.from_config()
+
+ # 测试创建记忆银行
+ await memory_bank.create_memory_bank("tieguaili")
+
+ # 测试添加记忆
+ await memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ # 测试搜索记忆
+ results = await memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="NVIDIA",
+ limit=5
+ )
+
+ print(f"搜索结果: {len(results)} 条记忆")
+ for result in results:
+ print(f"- {result['content']}")
+
+ except Exception as e:
+ print(f"❌ 测试失败: {e}")
+
+ # 运行测试
+ asyncio.run(test_memory_bank())
diff --git a/modules/core-collaboration/src/jixia/models/financial_data_models.py b/modules/core-collaboration/src/jixia/models/financial_data_models.py
new file mode 100644
index 0000000..e4c53c2
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/models/financial_data_models.py
@@ -0,0 +1,521 @@
+# 金融数据抽象层设计
+
+## 概述
+
+在"炼妖壶-稷下学宫AI辩论系统"中,我们需要构建一个统一的金融数据抽象层,以支持多种数据源(包括现有的RapidAPI永动机引擎、新增的OpenBB集成引擎,以及未来可能添加的其他数据提供商)。该抽象层将为上层AI智能体提供一致的数据接口,同时隐藏底层数据源的具体实现细节。
+
+## 设计目标
+
+1. **统一接口**:为所有金融数据访问提供一致的API
+2. **可扩展性**:易于添加新的数据提供商
+3. **容错性**:当主数据源不可用时,能够自动切换到备用数据源
+4. **性能优化**:支持缓存和异步数据获取
+5. **类型安全**:使用Python类型注解确保数据结构的一致性
+
+## 核心组件
+
+### 1. 数据模型 (Data Models)
+
+定义标准化的金融数据结构:
+
+```python
+# src/jixia/models/financial_data_models.py
+
+from dataclasses import dataclass
+from typing import Optional, List
+from datetime import datetime
+
+@dataclass
+class StockQuote:
+ symbol: str
+ price: float
+ change: float
+ change_percent: float
+ volume: int
+ timestamp: datetime
+
+@dataclass
+class HistoricalPrice:
+ date: datetime
+ open: float
+ high: float
+ low: float
+ close: float
+ volume: int
+
+@dataclass
+class CompanyProfile:
+ symbol: str
+ name: str
+ industry: str
+ sector: str
+ market_cap: float
+ pe_ratio: Optional[float]
+ dividend_yield: Optional[float]
+
+@dataclass
+class FinancialNews:
+ title: str
+ summary: str
+ url: str
+ timestamp: datetime
+ sentiment: Optional[float] # -1 (负面) to 1 (正面)
+```
+
+### 2. 抽象基类 (Abstract Base Class)
+
+定义数据提供商的通用接口:
+
+```python
+# src/jixia/engines/data_abstraction.py
+
+from abc import ABC, abstractmethod
+from typing import List, Optional
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+
+class DataProvider(ABC):
+ """金融数据提供商抽象基类"""
+
+ @abstractmethod
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ """获取股票报价"""
+ pass
+
+ @abstractmethod
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ """获取历史价格数据"""
+ pass
+
+ @abstractmethod
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ """获取公司概况"""
+ pass
+
+ @abstractmethod
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ """获取相关新闻"""
+ pass
+
+ @property
+ @abstractmethod
+ def name(self) -> str:
+ """数据提供商名称"""
+ pass
+
+ @property
+ @abstractmethod
+ def priority(self) -> int:
+ """优先级(数字越小优先级越高)"""
+ pass
+```
+
+### 3. Provider适配器 (Provider Adapters)
+
+为每个具体的数据源实现适配器:
+
+#### RapidAPI永动机引擎适配器
+
+```python
+# src/jixia/engines/rapidapi_adapter.py
+
+from typing import List, Optional
+from src.jixia.engines.data_abstraction import DataProvider
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine
+from config.settings import get_rapidapi_key
+
+class RapidAPIDataProvider(DataProvider):
+ """RapidAPI永动机引擎适配器"""
+
+ def __init__(self):
+ self.engine = JixiaPerpetualEngine(get_rapidapi_key())
+ self._name = "RapidAPI"
+ self._priority = 2 # 中等优先级
+
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ result = self.engine.get_immortal_data("吕洞宾", "quote", symbol)
+ if result.success and result.data:
+ # 解析RapidAPI返回的数据并转换为StockQuote
+ # 这里需要根据实际API返回的数据结构进行调整
+ return StockQuote(
+ symbol=symbol,
+ price=result.data.get("price", 0),
+ change=result.data.get("change", 0),
+ change_percent=result.data.get("change_percent", 0),
+ volume=result.data.get("volume", 0),
+ timestamp=result.data.get("timestamp")
+ )
+ return None
+
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ # 实现历史价格数据获取逻辑
+ pass
+
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ # 实现公司概况获取逻辑
+ pass
+
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ # 实现新闻获取逻辑
+ pass
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ @property
+ def priority(self) -> int:
+ return self._priority
+```
+
+#### OpenBB引擎适配器
+
+```python
+# src/jixia/engines/openbb_adapter.py
+
+from typing import List, Optional
+from src.jixia.engines.data_abstraction import DataProvider
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+from src.jixia.engines.openbb_engine import OpenBBEngine
+
+class OpenBBDataProvider(DataProvider):
+ """OpenBB引擎适配器"""
+
+ def __init__(self):
+ self.engine = OpenBBEngine()
+ self._name = "OpenBB"
+ self._priority = 1 # 最高优先级
+
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ result = self.engine.get_immortal_data("吕洞宾", "price", symbol)
+ if result.success and result.data:
+ # 解析OpenBB返回的数据并转换为StockQuote
+ return StockQuote(
+ symbol=symbol,
+ price=result.data.get("close", 0),
+ change=0, # 需要计算
+ change_percent=0, # 需要计算
+ volume=result.data.get("volume", 0),
+ timestamp=result.data.get("date")
+ )
+ return None
+
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ # 实现历史价格数据获取逻辑
+ pass
+
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ # 实现公司概况获取逻辑
+ pass
+
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ # 实现新闻获取逻辑
+ pass
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ @property
+ def priority(self) -> int:
+ return self._priority
+```
+
+### 4. 数据抽象层管理器 (Data Abstraction Layer Manager)
+
+管理多个数据提供商并提供统一接口:
+
+```python
+# src/jixia/engines/data_abstraction_layer.py
+
+from typing import List, Optional
+from src.jixia.engines.data_abstraction import DataProvider
+from src.jixia.models.financial_data_models import StockQuote, HistoricalPrice, CompanyProfile, FinancialNews
+import asyncio
+
+class DataAbstractionLayer:
+ """金融数据抽象层管理器"""
+
+ def __init__(self):
+ self.providers: List[DataProvider] = []
+ self._initialize_providers()
+
+ def _initialize_providers(self):
+ """初始化所有可用的数据提供商"""
+ # 根据配置和环境动态加载适配器
+ try:
+ from src.jixia.engines.rapidapi_adapter import RapidAPIDataProvider
+ self.providers.append(RapidAPIDataProvider())
+ except ImportError:
+ pass # RapidAPI引擎不可用
+
+ try:
+ from src.jixia.engines.openbb_adapter import OpenBBDataProvider
+ self.providers.append(OpenBBDataProvider())
+ except ImportError:
+ pass # OpenBB引擎不可用
+
+ # 按优先级排序
+ self.providers.sort(key=lambda p: p.priority)
+
+ def get_quote(self, symbol: str) -> Optional[StockQuote]:
+ """获取股票报价(带故障转移)"""
+ for provider in self.providers:
+ try:
+ quote = provider.get_quote(symbol)
+ if quote:
+ return quote
+ except Exception as e:
+ print(f"警告: {provider.name} 获取报价失败: {e}")
+ continue
+ return None
+
+ async def get_quote_async(self, symbol: str) -> Optional[StockQuote]:
+ """异步获取股票报价(带故障转移)"""
+ for provider in self.providers:
+ try:
+ # 如果提供商支持异步方法,则使用异步方法
+ if hasattr(provider, 'get_quote_async'):
+ quote = await provider.get_quote_async(symbol)
+ else:
+ # 否则在执行器中运行同步方法
+ quote = await asyncio.get_event_loop().run_in_executor(
+ None, provider.get_quote, symbol
+ )
+ if quote:
+ return quote
+ except Exception as e:
+ print(f"警告: {provider.name} 获取报价失败: {e}")
+ continue
+ return None
+
+ def get_historical_prices(self, symbol: str, days: int = 30) -> List[HistoricalPrice]:
+ """获取历史价格数据(带故障转移)"""
+ for provider in self.providers:
+ try:
+ prices = provider.get_historical_prices(symbol, days)
+ if prices:
+ return prices
+ except Exception as e:
+ print(f"警告: {provider.name} 获取历史价格失败: {e}")
+ continue
+ return []
+
+ def get_company_profile(self, symbol: str) -> Optional[CompanyProfile]:
+ """获取公司概况(带故障转移)"""
+ for provider in self.providers:
+ try:
+ profile = provider.get_company_profile(symbol)
+ if profile:
+ return profile
+ except Exception as e:
+ print(f"警告: {provider.name} 获取公司概况失败: {e}")
+ continue
+ return None
+
+ def get_news(self, symbol: str, limit: int = 10) -> List[FinancialNews]:
+ """获取相关新闻(带故障转移)"""
+ for provider in self.providers:
+ try:
+ news = provider.get_news(symbol, limit)
+ if news:
+ return news
+ except Exception as e:
+ print(f"警告: {provider.name} 获取新闻失败: {e}")
+ continue
+ return []
+```
+
+## 八仙与数据源的智能映射
+
+```python
+# src/jixia/engines/baxian_data_mapping.py
+
+# 设计八仙与数据源的智能映射
+immortal_data_mapping = {
+ '吕洞宾': {
+ 'specialty': 'technical_analysis', # 技术分析专家
+ 'preferred_data_types': ['historical', 'price'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ },
+ '何仙姑': {
+ 'specialty': 'risk_metrics', # 风险控制专家
+ 'preferred_data_types': ['price', 'profile'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '张果老': {
+ 'specialty': 'historical_data', # 历史数据分析师
+ 'preferred_data_types': ['historical'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ },
+ '韩湘子': {
+ 'specialty': 'sector_analysis', # 新兴资产专家
+ 'preferred_data_types': ['profile', 'news'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '汉钟离': {
+ 'specialty': 'market_movers', # 热点追踪
+ 'preferred_data_types': ['news', 'price'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '蓝采和': {
+ 'specialty': 'value_discovery', # 潜力股发现
+ 'preferred_data_types': ['screener', 'profile'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ },
+ '铁拐李': {
+ 'specialty': 'contrarian_analysis', # 逆向思维专家
+ 'preferred_data_types': ['profile', 'short_interest'],
+ 'data_providers': ['RapidAPI', 'OpenBB']
+ },
+ '曹国舅': {
+ 'specialty': 'macro_economics', # 宏观经济分析师
+ 'preferred_data_types': ['profile', 'institutional_holdings'],
+ 'data_providers': ['OpenBB', 'RapidAPI']
+ }
+}
+```
+
+## 缓存策略
+
+为了提高性能,我们将实现多级缓存策略:
+
+```python
+# src/jixia/engines/data_cache.py
+
+import time
+from typing import Any, Optional
+from functools import lru_cache
+
+class DataCache:
+ """金融数据缓存"""
+
+ def __init__(self):
+ self._cache = {}
+ self._cache_times = {}
+ self.default_ttl = 60 # 默认缓存时间(秒)
+
+ def get(self, key: str) -> Optional[Any]:
+ """获取缓存数据"""
+ if key in self._cache:
+ # 检查是否过期
+ if time.time() - self._cache_times[key] < self.default_ttl:
+ return self._cache[key]
+ else:
+ # 删除过期缓存
+ del self._cache[key]
+ del self._cache_times[key]
+ return None
+
+ def set(self, key: str, value: Any, ttl: Optional[int] = None):
+ """设置缓存数据"""
+ self._cache[key] = value
+ self._cache_times[key] = time.time()
+ if ttl:
+ # 可以为特定数据设置不同的TTL
+ pass # 实际实现中需要更复杂的TTL管理机制
+
+ @lru_cache(maxsize=128)
+ def get_quote_cache(self, symbol: str) -> Optional[Any]:
+ """LRU缓存装饰器示例"""
+ # 这个方法将自动缓存最近128个调用的结果
+ pass
+```
+
+## 数据质量监控机制
+
+为了确保数据的准确性和可靠性,我们将实现数据质量监控:
+
+```python
+# src/jixia/engines/data_quality_monitor.py
+
+from typing import Dict, Any
+from datetime import datetime
+
+class DataQualityMonitor:
+ """数据质量监控"""
+
+ def __init__(self):
+ self.provider_stats = {}
+
+ def record_access(self, provider_name: str, success: bool, response_time: float, data_size: int):
+ """记录数据访问统计"""
+ if provider_name not in self.provider_stats:
+ self.provider_stats[provider_name] = {
+ 'total_requests': 0,
+ 'successful_requests': 0,
+ 'failed_requests': 0,
+ 'total_response_time': 0,
+ 'total_data_size': 0,
+ 'last_access': None
+ }
+
+ stats = self.provider_stats[provider_name]
+ stats['total_requests'] += 1
+ if success:
+ stats['successful_requests'] += 1
+ else:
+ stats['failed_requests'] += 1
+ stats['total_response_time'] += response_time
+ stats['total_data_size'] += data_size
+ stats['last_access'] = datetime.now()
+
+ def get_provider_health(self, provider_name: str) -> Dict[str, Any]:
+ """获取提供商健康状况"""
+ if provider_name not in self.provider_stats:
+ return {'status': 'unknown'}
+
+ stats = self.provider_stats[provider_name]
+ success_rate = stats['successful_requests'] / stats['total_requests'] if stats['total_requests'] > 0 else 0
+ avg_response_time = stats['total_response_time'] / stats['total_requests'] if stats['total_requests'] > 0 else 0
+
+ status = 'healthy' if success_rate > 0.95 and avg_response_time < 2.0 else 'degraded' if success_rate > 0.8 else 'unhealthy'
+
+ return {
+ 'status': status,
+ 'success_rate': success_rate,
+ 'avg_response_time': avg_response_time,
+ 'total_requests': stats['total_requests'],
+ 'last_access': stats['last_access']
+ }
+```
+
+## 使用示例
+
+```python
+# 示例:在智能体中使用数据抽象层
+from src.jixia.engines.data_abstraction_layer import DataAbstractionLayer
+from src.jixia.models.financial_data_models import StockQuote
+
+# 初始化数据抽象层
+dal = DataAbstractionLayer()
+
+# 获取股票报价
+quote = dal.get_quote("AAPL")
+if quote:
+ print(f"Apple股价: ${quote.price}")
+else:
+ print("无法获取股价数据")
+
+# 异步获取报价
+import asyncio
+async def async_example():
+ quote = await dal.get_quote_async("GOOGL")
+ if quote:
+ print(f"Google股价: ${quote.price}")
+
+# asyncio.run(async_example())
+```
+
+## 总结
+
+这个金融数据抽象层设计提供了以下优势:
+
+1. **统一接口**:所有智能体都可以通过相同的接口访问任何数据源
+2. **故障转移**:当主数据源不可用时,自动切换到备用数据源
+3. **可扩展性**:可以轻松添加新的数据提供商适配器
+4. **性能优化**:通过缓存机制提高数据访问速度
+5. **质量监控**:实时监控各数据源的健康状况
+6. **文化融合**:通过八仙与数据源的智能映射,保持项目的文化特色
+
+这将为"炼妖壶-稷下学宫AI辩论系统"提供一个强大、可靠且可扩展的金融数据基础。
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/mongodb_swarm_example.py b/modules/core-collaboration/src/jixia/mongodb_swarm_example.py
new file mode 100644
index 0000000..f839af9
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/mongodb_swarm_example.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+"""
+MongoDB Swarm集成使用示例
+
+这个示例展示了如何将MongoDB MCP服务器与Swarm框架集成使用。
+"""
+
+import asyncio
+import json
+from typing import Dict, Any, List
+from datetime import datetime
+
+# 模拟Swarm框架(实际使用时导入真实的Swarm)
+class MockSwarm:
+ def __init__(self):
+ self.agents = {}
+
+ def add_agent(self, agent):
+ self.agents[agent.name] = agent
+ print(f"✅ 代理 '{agent.name}' 已添加到Swarm")
+
+ async 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]
+ print(f"🤖 代理 '{agent_name}' 正在处理: {message}")
+
+ # 模拟代理处理逻辑
+ if "查询" in message or "查找" in message:
+ return await agent.handle_query(message)
+ elif "插入" in message or "添加" in message:
+ return await agent.handle_insert(message)
+ elif "统计" in message:
+ return await agent.handle_stats(message)
+ else:
+ return f"📝 代理 '{agent_name}' 收到消息: {message}"
+
+class MockMongoDBAgent:
+ def __init__(self, name: str, mongodb_client):
+ self.name = name
+ self.mongodb_client = mongodb_client
+ self.functions = [
+ "mongodb_query",
+ "mongodb_insert",
+ "mongodb_update",
+ "mongodb_delete",
+ "mongodb_stats",
+ "mongodb_collections"
+ ]
+
+ async def handle_query(self, message: str) -> str:
+ try:
+ # 模拟查询操作
+ result = await self.mongodb_client.query_documents(
+ collection="users",
+ filter_query={},
+ limit=5
+ )
+ return f"📊 查询结果: 找到 {len(result.get('documents', []))} 条记录"
+ except Exception as e:
+ return f"❌ 查询失败: {str(e)}"
+
+ async def handle_insert(self, message: str) -> str:
+ try:
+ # 模拟插入操作
+ sample_doc = {
+ "name": "示例用户",
+ "email": "user@example.com",
+ "created_at": datetime.now().isoformat(),
+ "tags": ["swarm", "mongodb"]
+ }
+ result = await self.mongodb_client.insert_document(
+ collection="users",
+ document=sample_doc
+ )
+ return f"✅ 插入成功: 文档ID {result.get('inserted_id', 'unknown')}"
+ except Exception as e:
+ return f"❌ 插入失败: {str(e)}"
+
+ async def handle_stats(self, message: str) -> str:
+ try:
+ # 模拟统计操作
+ result = await self.mongodb_client.get_database_stats()
+ return f"📈 数据库统计: {json.dumps(result, indent=2, ensure_ascii=False)}"
+ except Exception as e:
+ return f"❌ 获取统计失败: {str(e)}"
+
+# 模拟MongoDB MCP客户端
+class MockMongoDBClient:
+ def __init__(self, mcp_server_url: str, default_database: str):
+ self.mcp_server_url = mcp_server_url
+ self.default_database = default_database
+ self.connected = False
+
+ async def connect(self) -> bool:
+ print(f"🔌 连接到MongoDB MCP服务器: {self.mcp_server_url}")
+ print(f"📁 默认数据库: {self.default_database}")
+ self.connected = True
+ return True
+
+ async def query_documents(self, collection: str, filter_query: Dict, limit: int = 100) -> Dict[str, Any]:
+ if not self.connected:
+ raise Exception("未连接到MongoDB服务器")
+
+ print(f"🔍 查询集合 '{collection}', 过滤条件: {filter_query}, 限制: {limit}")
+ # 模拟查询结果
+ return {
+ "documents": [
+ {"_id": "507f1f77bcf86cd799439011", "name": "用户1", "email": "user1@example.com"},
+ {"_id": "507f1f77bcf86cd799439012", "name": "用户2", "email": "user2@example.com"},
+ {"_id": "507f1f77bcf86cd799439013", "name": "用户3", "email": "user3@example.com"}
+ ],
+ "count": 3
+ }
+
+ async def insert_document(self, collection: str, document: Dict[str, Any]) -> Dict[str, Any]:
+ if not self.connected:
+ raise Exception("未连接到MongoDB服务器")
+
+ print(f"📝 向集合 '{collection}' 插入文档: {json.dumps(document, ensure_ascii=False, indent=2)}")
+ # 模拟插入结果
+ return {
+ "inserted_id": "507f1f77bcf86cd799439014",
+ "acknowledged": True
+ }
+
+ async def get_database_stats(self) -> Dict[str, Any]:
+ if not self.connected:
+ raise Exception("未连接到MongoDB服务器")
+
+ print(f"📊 获取数据库 '{self.default_database}' 统计信息")
+ # 模拟统计结果
+ return {
+ "database": self.default_database,
+ "collections": 5,
+ "documents": 1250,
+ "avgObjSize": 512,
+ "dataSize": 640000,
+ "storageSize": 1024000,
+ "indexes": 8,
+ "indexSize": 32768
+ }
+
+ async def disconnect(self):
+ print("🔌 断开MongoDB MCP连接")
+ self.connected = False
+
+async def main():
+ print("🚀 MongoDB Swarm集成示例")
+ print("=" * 50)
+
+ # 1. 创建MongoDB MCP客户端
+ print("\n📋 步骤1: 创建MongoDB MCP客户端")
+ mongodb_client = MockMongoDBClient(
+ mcp_server_url="http://localhost:8080",
+ default_database="swarm_data"
+ )
+
+ # 2. 连接到MongoDB
+ print("\n📋 步骤2: 连接到MongoDB")
+ await mongodb_client.connect()
+
+ # 3. 创建Swarm实例
+ print("\n📋 步骤3: 创建Swarm实例")
+ swarm = MockSwarm()
+
+ # 4. 创建MongoDB代理
+ print("\n📋 步骤4: 创建MongoDB代理")
+ mongodb_agent = MockMongoDBAgent("mongodb_agent", mongodb_client)
+ swarm.add_agent(mongodb_agent)
+
+ # 5. 演示各种操作
+ print("\n📋 步骤5: 演示MongoDB操作")
+ print("-" * 30)
+
+ # 查询操作
+ print("\n🔍 演示查询操作:")
+ result = await swarm.run("mongodb_agent", "查询所有用户数据")
+ print(f"结果: {result}")
+
+ # 插入操作
+ print("\n📝 演示插入操作:")
+ result = await swarm.run("mongodb_agent", "插入一个新用户")
+ print(f"结果: {result}")
+
+ # 统计操作
+ print("\n📊 演示统计操作:")
+ result = await swarm.run("mongodb_agent", "获取数据库统计信息")
+ print(f"结果: {result}")
+
+ # 6. 清理资源
+ print("\n📋 步骤6: 清理资源")
+ await mongodb_client.disconnect()
+
+ print("\n✅ 示例完成!")
+ print("\n💡 实际使用说明:")
+ print("1. 启动MongoDB和MCP服务器: docker-compose up -d")
+ print("2. 使用真实的SwarmMongoDBClient替换MockMongoDBClient")
+ print("3. 导入真实的Swarm框架")
+ print("4. 根据需要配置代理的instructions和functions")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/ollama_swarm_mongodb_integration.py b/modules/core-collaboration/src/jixia/ollama_swarm_mongodb_integration.py
new file mode 100644
index 0000000..9a32931
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/ollama_swarm_mongodb_integration.py
@@ -0,0 +1,395 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Ollama Swarm + MongoDB RSS 集成示例
+展示如何使用基于 Ollama 的 Swarm 调用 MongoDB 中的 RSS 数据
+包含向量化搜索的实现方案
+"""
+
+import asyncio
+import json
+from datetime import datetime
+from typing import Dict, List, Any, Optional
+from swarm import Swarm, Agent
+from openai import OpenAI
+
+# 导入 MongoDB MCP 客户端
+try:
+ from src.mcp.swarm_mongodb_client import SwarmMongoDBClient
+except ImportError:
+ print("警告: 无法导入 SwarmMongoDBClient,将使用模拟客户端")
+ SwarmMongoDBClient = None
+
+class OllamaSwarmMongoDBIntegration:
+ """
+ Ollama Swarm + MongoDB RSS 集成系统
+
+ 功能:
+ 1. 使用 Ollama 本地模型进行 AI 推理
+ 2. 通过 MCP 连接 MongoDB 获取 RSS 数据
+ 3. 支持向量化搜索(可选)
+ 4. 四仙辩论系统集成
+ """
+
+ def __init__(self):
+ # Ollama 配置
+ self.ollama_base_url = "http://100.99.183.38:11434"
+ self.model_name = "qwen3:8b" # 使用支持工具调用的模型
+ # 初始化 OpenAI 客户端(连接到 Ollama)
+ self.openai_client = OpenAI(
+ api_key="ollama", # Ollama 不需要真实 API 密钥
+ base_url=f"{self.ollama_base_url}/v1"
+ )
+
+ # 初始化 Swarm
+ self.swarm = Swarm(client=self.openai_client)
+
+ # 初始化 MongoDB 客户端
+ self.mongodb_client = None
+ self.init_mongodb_client()
+
+ # 创建代理
+ self.agents = self.create_agents()
+
+ print(f"🦙 Ollama 服务: {self.ollama_base_url}")
+ print(f"🤖 使用模型: {self.model_name}")
+ print(f"📊 MongoDB 连接: {'已连接' if self.mongodb_client else '未连接'}")
+
+ def init_mongodb_client(self):
+ """初始化 MongoDB 客户端"""
+ try:
+ if SwarmMongoDBClient:
+ self.mongodb_client = SwarmMongoDBClient(
+ mcp_server_url="http://localhost:8080",
+ default_database="taigong"
+ )
+ # 连接到数据库
+ result = self.mongodb_client.connect("taigong")
+ if result.get("success"):
+ print("✅ MongoDB MCP 连接成功")
+ else:
+ print(f"❌ MongoDB MCP 连接失败: {result.get('error')}")
+ self.mongodb_client = None
+ else:
+ print("⚠️ 使用模拟 MongoDB 客户端")
+ self.mongodb_client = MockMongoDBClient()
+ except Exception as e:
+ print(f"❌ MongoDB 初始化失败: {e}")
+ self.mongodb_client = MockMongoDBClient()
+
+ def get_rss_articles(self, query: Optional[str] = None, limit: int = 10) -> List[Dict]:
+ """获取 RSS 文章数据"""
+ if not self.mongodb_client:
+ return []
+
+ try:
+ # 构建查询条件
+ filter_query = {}
+ if query:
+ # 简单的文本搜索
+ filter_query = {
+ "$or": [
+ {"title": {"$regex": query, "$options": "i"}},
+ {"description": {"$regex": query, "$options": "i"}}
+ ]
+ }
+
+ # 查询文档
+ result = self.mongodb_client.find_documents(
+ collection_name="articles",
+ query=filter_query,
+ limit=limit,
+ sort={"published_time": -1} # 按发布时间倒序
+ )
+
+ if result.get("success"):
+ return result.get("documents", [])
+ else:
+ print(f"查询失败: {result.get('error')}")
+ return []
+
+ except Exception as e:
+ print(f"获取 RSS 文章失败: {e}")
+ return []
+
+ def create_agents(self) -> Dict[str, Agent]:
+ """创建四仙代理"""
+
+ def get_rss_news(query: str = "", limit: int = 5) -> str:
+ """获取 RSS 新闻的工具函数"""
+ articles = self.get_rss_articles(query, limit)
+ if not articles:
+ return "未找到相关新闻文章"
+
+ result = f"找到 {len(articles)} 篇相关文章:\n\n"
+ for i, article in enumerate(articles, 1):
+ title = article.get('title', '无标题')
+ published = article.get('published_time', '未知时间')
+ result += f"{i}. {title}\n 发布时间: {published}\n\n"
+
+ return result
+
+ def analyze_market_sentiment(topic: str) -> str:
+ """分析市场情绪的工具函数"""
+ articles = self.get_rss_articles(topic, 10)
+ if not articles:
+ return f"未找到关于 '{topic}' 的相关新闻"
+
+ # 简单的情绪分析(实际应用中可以使用更复杂的 NLP 模型)
+ positive_keywords = ['上涨', '增长', '利好', '突破', '创新高']
+ negative_keywords = ['下跌', '下降', '利空', '暴跌', '风险']
+
+ positive_count = 0
+ negative_count = 0
+
+ for article in articles:
+ title = article.get('title', '').lower()
+ for keyword in positive_keywords:
+ if keyword in title:
+ positive_count += 1
+ for keyword in negative_keywords:
+ if keyword in title:
+ negative_count += 1
+
+ sentiment = "中性"
+ if positive_count > negative_count:
+ sentiment = "偏乐观"
+ elif negative_count > positive_count:
+ sentiment = "偏悲观"
+
+ return f"基于 {len(articles)} 篇新闻分析,'{topic}' 的市场情绪: {sentiment}\n" \
+ f"正面信号: {positive_count}, 负面信号: {negative_count}"
+
+ # 创建四仙代理
+ agents = {
+ "吕洞宾": Agent(
+ name="吕洞宾",
+ model=self.model_name,
+ instructions="""
+ 你是吕洞宾,技术分析专家。
+ - 专长:技术分析和图表解读
+ - 性格:犀利直接,一剑封喉
+ - 立场:偏向积极乐观
+ - 使用 get_rss_news 获取最新财经新闻
+ - 使用 analyze_market_sentiment 分析市场情绪
+ """,
+ functions=[get_rss_news, analyze_market_sentiment]
+ ),
+
+ "何仙姑": Agent(
+ name="何仙姑",
+ model=self.model_name,
+ instructions="""
+ 你是何仙姑,风险控制专家。
+ - 专长:风险评估和资金管理
+ - 性格:温和坚定,关注风险
+ - 立场:偏向谨慎保守
+ - 使用 get_rss_news 获取风险相关新闻
+ - 使用 analyze_market_sentiment 评估市场风险
+ """,
+ functions=[get_rss_news, analyze_market_sentiment]
+ ),
+
+ "张果老": Agent(
+ name="张果老",
+ model=self.model_name,
+ instructions="""
+ 你是张果老,历史数据分析师。
+ - 专长:历史数据分析和趋势预测
+ - 性格:博学深沉,引经据典
+ - 立场:基于历史数据的客观分析
+ - 使用 get_rss_news 获取历史相关新闻
+ - 使用 analyze_market_sentiment 分析长期趋势
+ """,
+ functions=[get_rss_news, analyze_market_sentiment]
+ ),
+
+ "铁拐李": Agent(
+ name="铁拐李",
+ model=self.model_name,
+ instructions="""
+ 你是铁拐李,逆向思维大师。
+ - 专长:逆向思维和另类观点
+ - 性格:特立独行,敢于质疑
+ - 立场:挑战主流观点
+ - 使用 get_rss_news 寻找被忽视的信息
+ - 使用 analyze_market_sentiment 提出反向观点
+ """,
+ functions=[get_rss_news, analyze_market_sentiment]
+ )
+ }
+
+ return agents
+
+ async def start_debate(self, topic: str, rounds: int = 3) -> Dict[str, Any]:
+ """开始四仙辩论"""
+ print(f"\n🎭 开始四仙辩论: {topic}")
+ print("=" * 50)
+
+ debate_history = []
+
+ # 获取相关新闻作为背景
+ background_articles = self.get_rss_articles(topic, 5)
+ background_info = "\n".join([f"- {article.get('title', '')}" for article in background_articles])
+
+ agent_names = list(self.agents.keys())
+
+ for round_num in range(rounds):
+ print(f"\n📢 第 {round_num + 1} 轮辩论")
+ print("-" * 30)
+
+ for agent_name in agent_names:
+ agent = self.agents[agent_name]
+
+ # 构建消息
+ if round_num == 0:
+ message = f"""请基于以下背景信息对 '{topic}' 发表你的观点:
+
+背景新闻:
+{background_info}
+
+请使用你的专业工具获取更多信息并给出分析。"""
+ else:
+ # 后续轮次包含之前的辩论历史
+ history_summary = "\n".join([f"{h['agent']}: {h['response'][:100]}..." for h in debate_history[-3:]])
+ message = f"""基于之前的辩论内容,请继续阐述你对 '{topic}' 的观点:
+
+之前的观点:
+{history_summary}
+
+请使用工具获取最新信息并回应其他仙友的观点。"""
+
+ try:
+ # 调用代理
+ response = self.swarm.run(
+ agent=agent,
+ messages=[{"role": "user", "content": message}]
+ )
+
+ agent_response = response.messages[-1]["content"]
+
+ print(f"\n{agent_name}: {agent_response}")
+
+ debate_history.append({
+ "round": round_num + 1,
+ "agent": agent_name,
+ "response": agent_response,
+ "timestamp": datetime.now().isoformat()
+ })
+
+ except Exception as e:
+ print(f"❌ {agent_name} 发言失败: {e}")
+ continue
+
+ return {
+ "topic": topic,
+ "rounds": rounds,
+ "debate_history": debate_history,
+ "background_articles": background_articles
+ }
+
+ def get_vector_search_recommendation(self) -> str:
+ """获取向量化搜索的建议"""
+ return """
+🔍 向量化搜索建议:
+
+当前 RSS 数据结构:
+- _id: ObjectId
+- title: String
+- published_time: String
+
+向量化增强方案:
+
+1. 数据预处理:
+ - 提取文章摘要/描述字段
+ - 清理和标准化文本内容
+ - 添加分类标签
+
+2. 向量化实现:
+ - 使用 Ollama 本地嵌入模型(如 nomic-embed-text)
+ - 为每篇文章生成 768 维向量
+ - 存储向量到 MongoDB 的 vector 字段
+
+3. 索引创建:
+ ```javascript
+ db.articles.createIndex(
+ { "vector": "2dsphere" },
+ { "name": "vector_index" }
+ )
+ ```
+
+4. 语义搜索:
+ - 将用户查询转换为向量
+ - 使用 $vectorSearch 进行相似度搜索
+ - 结合传统关键词搜索提高准确性
+
+5. Swarm 集成:
+ - 为代理添加语义搜索工具
+ - 支持概念级别的新闻检索
+ - 提高辩论质量和相关性
+
+实施优先级:
+1. 先完善基础文本搜索
+2. 添加文章摘要字段
+3. 集成 Ollama 嵌入模型
+4. 实现向量搜索功能
+ """
+
+class MockMongoDBClient:
+ """模拟 MongoDB 客户端(用于测试)"""
+
+ def __init__(self):
+ self.mock_articles = [
+ {
+ "_id": "mock_1",
+ "title": "滨江服务,还能涨价的物业",
+ "published_time": "2025-06-13T04:58:00.000Z",
+ "description": "房地产市场分析"
+ },
+ {
+ "_id": "mock_2",
+ "title": "中国汽车行业在内卷什么?",
+ "published_time": "2025-06-11T05:07:00.000Z",
+ "description": "汽车行业竞争分析"
+ }
+ ]
+
+ def find_documents(self, collection_name: str, query: Optional[Dict] = None,
+ limit: int = 100, **kwargs) -> Dict[str, Any]:
+ """模拟文档查询"""
+ return {
+ "success": True,
+ "documents": self.mock_articles[:limit]
+ }
+
+ def connect(self, database_name: str) -> Dict[str, Any]:
+ """模拟连接"""
+ return {"success": True}
+
+async def main():
+ """主函数"""
+ # 创建集成系统
+ system = OllamaSwarmMongoDBIntegration()
+
+ # 显示向量化建议
+ print(system.get_vector_search_recommendation())
+
+ # 测试 RSS 数据获取
+ print("\n📰 测试 RSS 数据获取:")
+ articles = system.get_rss_articles(limit=3)
+ for i, article in enumerate(articles, 1):
+ print(f"{i}. {article.get('title', '无标题')}")
+
+ # 开始辩论(可选)
+ user_input = input("\n是否开始辩论?(y/n): ")
+ if user_input.lower() == 'y':
+ topic = input("请输入辩论主题(默认:房地产市场): ") or "房地产市场"
+ result = await system.start_debate(topic, rounds=2)
+
+ print("\n📊 辩论总结:")
+ print(f"主题: {result['topic']}")
+ print(f"轮次: {result['rounds']}")
+ print(f"发言次数: {len(result['debate_history'])}")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/core-collaboration/src/jixia/yijing_debate_system.md b/modules/core-collaboration/src/jixia/yijing_debate_system.md
new file mode 100644
index 0000000..82746ee
--- /dev/null
+++ b/modules/core-collaboration/src/jixia/yijing_debate_system.md
@@ -0,0 +1,231 @@
+# 🔮 太公心易辩论系统
+
+> *"以自己的体,看待其他人的用,组合为六十四卦"*
+
+## ⚡ 易经辩论架构重设计
+
+### 🎯 核心理念修正
+
+之前的设计错误地将八仙按"资产类别"分工,这违背了易经的本质。真正的太公心易应该是:
+
+**不是专业分工,而是观察视角的变化!**
+
+## 🌊 先天八卦 - 八仙布局
+
+### 阴阳鱼排列
+```
+ 乾☰ 吕洞宾 (老父)
+ 兑☱ 钟汉离 巽☴ 蓝采和 (长女)
+震☳ 铁拐李 坤☷ 何仙姑 (老母)
+ 艮☶ 曹国舅 坎☵ 张果老 (中男)
+ 离☲ 韩湘子 (中女)
+```
+
+### 对立统一关系
+
+#### 🔥 乾坤对立 - 根本观点相反
+- **吕洞宾** (乾☰): 阳刚进取,天生看多
+ - *"以剑仙之名发誓,这个市场充满机会!"*
+- **何仙姑** (坤☷): 阴柔谨慎,天生看空
+ - *"作为唯一的女仙,我更关注风险和保护。"*
+
+**辩论特点**: 根本性观点对立,永远无法达成一致
+
+#### ⚡ 震巽对立 - 行动vs思考
+- **铁拐李** (震☳): 雷厉风行,立即行动
+ - *"机会稍纵即逝,现在就要下手!"*
+- **蓝采和** (巽☴): 深思熟虑,缓慢布局
+ - *"让我们再观察一下,不要急于决定。"*
+
+#### 💧 坎离对立 - 理性vs感性
+- **张果老** (坎☵): 纯理性,数据驱动
+ - *"倒骑驴看市场,数据不会说谎。"*
+- **韩湘子** (离☲): 重直觉,情感判断
+ - *"我的音律告诉我,市场的情绪在变化。"*
+
+#### 🏔️ 艮兑对立 - 保守vs激进
+- **曹国舅** (艮☶): 稳重保守,风险厌恶
+ - *"稳健是王道,不要冒不必要的风险。"*
+- **钟汉离** (兑☱): 激进创新,高风险偏好
+ - *"不入虎穴,焉得虎子!创新需要勇气。"*
+
+## 🎭 三清八仙层级关系
+
+### 三清 = Overlay (天层)
+```python
+class SanQing:
+ """三清天尊 - 上层决策"""
+
+ hierarchy_level = "OVERLAY"
+ speaking_privilege = "ABSOLUTE" # 发言时八仙必须静听
+
+ def speak(self):
+ # 三清发言时,八仙进入静听模式
+ for baxian in self.baxian_agents:
+ baxian.set_mode("LISTEN_ONLY")
+```
+
+#### 太上老君 - 最高决策者
+- **职责**: 综合八仙观点,做出最终决策
+- **特权**: 可以否决任何八仙的建议
+- **风格**: 高屋建瓴,统揽全局
+
+#### 元始天尊 - 技术支撑
+- **职责**: 提供技术分析和数据支撑
+- **特权**: 可以要求八仙提供具体数据
+- **风格**: 精准理性,技术权威
+
+#### 通天教主 - 情绪导师
+- **职责**: 分析市场情绪和群体心理
+- **特权**: 可以调节八仙的辩论情绪
+- **风格**: 洞察人心,情绪敏感
+
+### 八仙 = Underlay (地层)
+```python
+class BaXian:
+ """八仙过海 - 底层辩论"""
+
+ hierarchy_level = "UNDERLAY"
+ speaking_privilege = "PEER" # 平辈关系,可以争论
+
+ def debate_with_peer(self, other_baxian):
+ # 八仙之间可以激烈争论
+ if self.is_opposite(other_baxian):
+ return self.argue_intensely(other_baxian)
+ else:
+ return self.discuss_peacefully(other_baxian)
+```
+
+## 🔄 辩论流程重设计
+
+### Phase 1: 八仙平辈辩论
+```python
+async def baxian_peer_debate(topic: str):
+ """八仙平辈辩论阶段"""
+
+ # 1. 对立卦位激烈争论
+ qian_kun_debate = await debate_between(lu_dongbin, he_xiangu) # 乾坤对立
+ zhen_xun_debate = await debate_between(tiegua_li, lan_caihe) # 震巽对立
+ kan_li_debate = await debate_between(zhang_guolao, han_xiangzi) # 坎离对立
+ gen_dui_debate = await debate_between(cao_guojiu, zhong_hanli) # 艮兑对立
+
+ # 2. 相邻卦位温和讨论
+ adjacent_discussions = await discuss_adjacent_positions()
+
+ return {
+ "intense_debates": [qian_kun_debate, zhen_xun_debate, kan_li_debate, gen_dui_debate],
+ "mild_discussions": adjacent_discussions
+ }
+```
+
+### Phase 2: 三清裁决
+```python
+async def sanqing_overlay_decision(baxian_debates: Dict):
+ """三清上层裁决阶段"""
+
+ # 八仙必须静听
+ for baxian in all_baxian:
+ baxian.set_mode("SILENT_LISTEN")
+
+ # 元始天尊技术分析
+ technical_analysis = await yuanshi_tianzun.analyze_data(baxian_debates)
+
+ # 通天教主情绪分析
+ sentiment_analysis = await tongtian_jiaozhu.analyze_emotions(baxian_debates)
+
+ # 太上老君最终决策
+ final_decision = await taishang_laojun.make_decision(
+ technical_analysis,
+ sentiment_analysis,
+ baxian_debates
+ )
+
+ return final_decision
+```
+
+## 🎯 投资标的全覆盖
+
+### 不按资产类别分工,按观察角度分工
+
+#### 任何投资标的都可以从八个角度观察:
+
+**股票、期货、外汇、加密货币、另类资产...**
+
+- **乾 (吕洞宾)**: 看多角度 - "这个标的有上涨潜力"
+- **坤 (何仙姑)**: 看空角度 - "这个标的风险很大"
+- **震 (铁拐李)**: 行动角度 - "现在就要买入/卖出"
+- **巽 (蓝采和)**: 等待角度 - "再观察一段时间"
+- **坎 (张果老)**: 数据角度 - "技术指标显示..."
+- **离 (韩湘子)**: 直觉角度 - "我感觉市场情绪..."
+- **艮 (曹国舅)**: 保守角度 - "风险控制最重要"
+- **兑 (钟汉离)**: 激进角度 - "高风险高收益"
+
+## 🔮 六十四卦生成机制
+
+### 体用关系
+```python
+def generate_64_gua_analysis(target_asset: str):
+ """生成六十四卦分析"""
+
+ analyses = {}
+
+ for observer in baxian: # 8个观察者 (体)
+ for observed in baxian: # 8个被观察者 (用)
+ if observer != observed:
+ gua_name = f"{observer.trigram}{observed.trigram}"
+
+ analysis = observer.analyze_from_perspective(
+ target_asset,
+ observed.viewpoint
+ )
+
+ analyses[gua_name] = analysis
+
+ return analyses # 8x8 = 64种分析角度
+```
+
+### 实际应用示例
+```python
+# 分析比特币
+bitcoin_analysis = {
+ "乾乾": "吕洞宾看吕洞宾的比特币观点", # 自我强化
+ "乾坤": "吕洞宾看何仙姑的比特币观点", # 多空对立
+ "乾震": "吕洞宾看铁拐李的比特币观点", # 看多+行动
+ # ... 64种组合
+}
+```
+
+## ⚖️ 辩论规则重定义
+
+### 八仙辩论规则
+1. **对立卦位**: 必须激烈争论,观点相反
+2. **相邻卦位**: 可以温和讨论,观点相近
+3. **平辈关系**: 无上下级,可以互相质疑
+4. **轮流发言**: 按先天八卦顺序发言
+
+### 三清介入规则
+1. **绝对权威**: 三清发言时,八仙必须静听
+2. **技术支撑**: 元始天尊提供数据分析
+3. **情绪调节**: 通天教主控制辩论节奏
+4. **最终裁决**: 太上老君综合决策
+
+## 🎉 重设计的优势
+
+### ✅ 符合易经本质
+- 体现了"体用关系"的核心思想
+- 遵循先天八卦的阴阳对立
+- 实现了"男女老少皆可成仙"的理念
+
+### ✅ 投资标的全覆盖
+- 不局限于特定资产类别
+- 任何投资标的都可以从8个角度分析
+- 生成64种不同的分析视角
+
+### ✅ 辩论更加真实
+- 对立观点的激烈争论
+- 层级关系的权威体现
+- 符合中华文化的等级秩序
+
+---
+
+**🔮 这才是真正的太公心易!以易经智慧指导AI投资分析!**
\ No newline at end of file
diff --git a/modules/core-collaboration/src/mcp/mongodb_mcp_config.py b/modules/core-collaboration/src/mcp/mongodb_mcp_config.py
new file mode 100644
index 0000000..5524ecd
--- /dev/null
+++ b/modules/core-collaboration/src/mcp/mongodb_mcp_config.py
@@ -0,0 +1,591 @@
+#!/usr/bin/env python3
+"""
+MongoDB MCP Configuration for Swarm
+Swarm框架的MongoDB MCP配置文件
+
+功能:
+- 配置MongoDB MCP服务器
+- 集成到Swarm代理中
+- 提供完整的使用示例
+- 环境变量管理
+"""
+
+import os
+import json
+import logging
+from typing import Dict, List, Any, Optional
+from dataclasses import dataclass
+
+@dataclass
+class MongoDBMCPConfig:
+ """
+ MongoDB MCP配置类
+ """
+ # MCP服务器配置
+ mcp_server_host: str = "localhost"
+ mcp_server_port: int = 8080
+ mcp_server_url: Optional[str] = None
+
+ # MongoDB配置
+ mongodb_url: str = "mongodb://localhost:27017"
+ default_database: str = "swarm_data"
+
+ # Swarm集成配置
+ enable_auto_connect: bool = True
+ max_query_limit: int = 1000
+ default_query_limit: int = 100
+
+ # 日志配置
+ log_level: str = "INFO"
+ enable_query_logging: bool = True
+
+ def __post_init__(self):
+ """初始化后处理"""
+ if not self.mcp_server_url:
+ self.mcp_server_url = f"http://{self.mcp_server_host}:{self.mcp_server_port}"
+
+ # 从环境变量覆盖配置
+ self.mongodb_url = os.getenv('MONGODB_URL', self.mongodb_url)
+ self.default_database = os.getenv('MONGODB_DEFAULT_DB', self.default_database)
+ self.mcp_server_host = os.getenv('MCP_SERVER_HOST', self.mcp_server_host)
+ self.mcp_server_port = int(os.getenv('MCP_SERVER_PORT', str(self.mcp_server_port)))
+
+ # 重新构建URL
+ if not os.getenv('MCP_SERVER_URL'):
+ self.mcp_server_url = f"http://{self.mcp_server_host}:{self.mcp_server_port}"
+ else:
+ self.mcp_server_url = os.getenv('MCP_SERVER_URL')
+
+ def to_dict(self) -> Dict[str, Any]:
+ """转换为字典"""
+ return {
+ 'mcp_server_host': self.mcp_server_host,
+ 'mcp_server_port': self.mcp_server_port,
+ 'mcp_server_url': self.mcp_server_url,
+ 'mongodb_url': self.mongodb_url,
+ 'default_database': self.default_database,
+ 'enable_auto_connect': self.enable_auto_connect,
+ 'max_query_limit': self.max_query_limit,
+ 'default_query_limit': self.default_query_limit,
+ 'log_level': self.log_level,
+ 'enable_query_logging': self.enable_query_logging
+ }
+
+ @classmethod
+ def from_dict(cls, data: Dict[str, Any]) -> 'MongoDBMCPConfig':
+ """从字典创建配置"""
+ return cls(**data)
+
+ @classmethod
+ def from_env(cls) -> 'MongoDBMCPConfig':
+ """从环境变量创建配置"""
+ return cls()
+
+ def save_to_file(self, filepath: str):
+ """保存配置到文件"""
+ with open(filepath, 'w', encoding='utf-8') as f:
+ json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
+
+ @classmethod
+ def load_from_file(cls, filepath: str) -> 'MongoDBMCPConfig':
+ """从文件加载配置"""
+ with open(filepath, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+ return cls.from_dict(data)
+
+
+class SwarmMongoDBIntegration:
+ """
+ Swarm MongoDB集成类
+ 负责将MongoDB MCP服务器集成到Swarm框架中
+ """
+
+ def __init__(self, config: MongoDBMCPConfig):
+ self.config = config
+ self.logger = logging.getLogger(__name__)
+
+ # 设置日志级别
+ logging.basicConfig(
+ level=getattr(logging, config.log_level.upper()),
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+ )
+
+ def create_swarm_agent_config(self) -> Dict[str, Any]:
+ """
+ 创建Swarm代理配置
+
+ Returns:
+ Swarm代理配置字典
+ """
+ return {
+ "name": "mongodb_agent",
+ "description": "MongoDB数据库操作代理,支持CRUD操作、聚合查询和数据库管理",
+ "instructions": self._get_agent_instructions(),
+ "functions": self._get_agent_functions(),
+ "mcp_config": {
+ "server_url": self.config.mcp_server_url,
+ "mongodb_url": self.config.mongodb_url,
+ "default_database": self.config.default_database
+ }
+ }
+
+ def _get_agent_instructions(self) -> str:
+ """
+ 获取代理指令
+
+ Returns:
+ 代理指令字符串
+ """
+ return f"""
+你是一个MongoDB数据库操作专家代理。你的主要职责是:
+
+1. **数据查询**: 帮助用户查询MongoDB集合中的数据
+ - 支持自然语言查询描述
+ - 自动限制查询结果数量(默认{self.config.default_query_limit}条,最大{self.config.max_query_limit}条)
+ - 提供清晰的查询结果格式
+
+2. **数据操作**: 执行数据的增删改操作
+ - 插入新文档或批量插入
+ - 更新现有文档
+ - 删除不需要的文档
+ - 确保操作安全性
+
+3. **数据库管理**: 提供数据库管理功能
+ - 查看集合列表
+ - 获取集合统计信息
+ - 创建索引优化查询性能
+ - 监控数据库状态
+
+4. **最佳实践**:
+ - 在执行删除或更新操作前,先确认影响范围
+ - 对于大量数据操作,提供进度反馈
+ - 遇到错误时,提供清晰的错误说明和解决建议
+ - 保护敏感数据,避免泄露
+
+当前连接的数据库: {self.config.default_database}
+MongoDB服务器: {self.config.mongodb_url.replace(self.config.mongodb_url.split('@')[0].split('//')[1] + '@', '***@') if '@' in self.config.mongodb_url else self.config.mongodb_url}
+
+请始终以友好、专业的方式协助用户完成MongoDB相关任务。
+""".strip()
+
+ def _get_agent_functions(self) -> List[str]:
+ """
+ 获取代理函数列表
+
+ Returns:
+ 函数名称列表
+ """
+ return [
+ "mongodb_query",
+ "mongodb_insert",
+ "mongodb_update",
+ "mongodb_stats",
+ "mongodb_collections"
+ ]
+
+ def create_mcp_server_config(self) -> Dict[str, Any]:
+ """
+ 创建MCP服务器配置
+
+ Returns:
+ MCP服务器配置字典
+ """
+ return {
+ "name": "mongodb-mcp-server",
+ "description": "MongoDB MCP服务器,为Swarm提供MongoDB数据库访问功能",
+ "version": "1.0.0",
+ "server": {
+ "host": self.config.mcp_server_host,
+ "port": self.config.mcp_server_port,
+ "url": self.config.mcp_server_url
+ },
+ "mongodb": {
+ "url": self.config.mongodb_url,
+ "default_database": self.config.default_database
+ },
+ "tools": [
+ {
+ "name": "connect_database",
+ "description": "连接到MongoDB数据库",
+ "parameters": {
+ "database_name": {"type": "string", "description": "数据库名称"}
+ }
+ },
+ {
+ "name": "insert_document",
+ "description": "插入文档到集合",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"},
+ "document": {"type": "object", "description": "要插入的文档"},
+ "many": {"type": "boolean", "description": "是否批量插入"}
+ }
+ },
+ {
+ "name": "find_documents",
+ "description": "查找文档",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"},
+ "query": {"type": "object", "description": "查询条件"},
+ "limit": {"type": "integer", "description": "限制数量"}
+ }
+ },
+ {
+ "name": "update_document",
+ "description": "更新文档",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"},
+ "query": {"type": "object", "description": "查询条件"},
+ "update": {"type": "object", "description": "更新操作"}
+ }
+ },
+ {
+ "name": "delete_document",
+ "description": "删除文档",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"},
+ "query": {"type": "object", "description": "查询条件"}
+ }
+ },
+ {
+ "name": "aggregate_query",
+ "description": "执行聚合查询",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"},
+ "pipeline": {"type": "array", "description": "聚合管道"}
+ }
+ },
+ {
+ "name": "list_collections",
+ "description": "列出所有集合",
+ "parameters": {}
+ },
+ {
+ "name": "create_index",
+ "description": "创建索引",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"},
+ "index_spec": {"type": "object", "description": "索引规范"}
+ }
+ },
+ {
+ "name": "get_collection_stats",
+ "description": "获取集合统计信息",
+ "parameters": {
+ "collection_name": {"type": "string", "description": "集合名称"}
+ }
+ }
+ ],
+ "resources": [
+ {
+ "uri": "mongodb://status",
+ "name": "MongoDB连接状态",
+ "description": "获取MongoDB连接状态和基本信息"
+ },
+ {
+ "uri": "mongodb://databases",
+ "name": "数据库列表",
+ "description": "获取所有可用数据库的列表"
+ }
+ ]
+ }
+
+ def generate_docker_compose(self) -> str:
+ """
+ 生成Docker Compose配置
+
+ Returns:
+ Docker Compose YAML字符串
+ """
+ return f"""
+version: '3.8'
+
+services:
+ mongodb:
+ image: mongo:7.0
+ container_name: swarm_mongodb
+ restart: unless-stopped
+ ports:
+ - "27017:27017"
+ environment:
+ MONGO_INITDB_ROOT_USERNAME: admin
+ MONGO_INITDB_ROOT_PASSWORD: password
+ MONGO_INITDB_DATABASE: {self.config.default_database}
+ volumes:
+ - mongodb_data:/data/db
+ - ./mongo-init:/docker-entrypoint-initdb.d
+ networks:
+ - swarm_network
+
+ mongodb-mcp-server:
+ build:
+ context: .
+ dockerfile: Dockerfile.mongodb-mcp
+ container_name: swarm_mongodb_mcp
+ restart: unless-stopped
+ ports:
+ - "{self.config.mcp_server_port}:{self.config.mcp_server_port}"
+ environment:
+ MONGODB_URL: [REDACTED - 从Doppler获取MONGODB_URL]
+ MCP_SERVER_PORT: {self.config.mcp_server_port}
+ LOG_LEVEL: {self.config.log_level}
+ depends_on:
+ - mongodb
+ networks:
+ - swarm_network
+
+volumes:
+ mongodb_data:
+
+networks:
+ swarm_network:
+ driver: bridge
+""".strip()
+
+ def generate_dockerfile(self) -> str:
+ """
+ 生成Dockerfile
+
+ Returns:
+ Dockerfile内容字符串
+ """
+ return """
+# Dockerfile.mongodb-mcp
+FROM python:3.11-slim
+
+WORKDIR /app
+
+# 安装系统依赖
+RUN apt-get update && apt-get install -y \
+ gcc \
+ && rm -rf /var/lib/apt/lists/*
+
+# 复制requirements文件
+COPY requirements-mongodb-mcp.txt .
+
+# 安装Python依赖
+RUN pip install --no-cache-dir -r requirements-mongodb-mcp.txt
+
+# 复制源代码
+COPY src/mcp/ ./src/mcp/
+
+# 设置环境变量
+ENV PYTHONPATH=/app
+ENV MONGODB_URL=mongodb://localhost:27017
+ENV MCP_SERVER_PORT=8080
+
+# 暴露端口
+EXPOSE 8080
+
+# 启动命令
+CMD ["python", "src/mcp/mongodb_mcp_server.py", "--port", "8080"]
+""".strip()
+
+ def generate_requirements(self) -> str:
+ """
+ 生成requirements文件
+
+ Returns:
+ requirements.txt内容
+ """
+ return """
+# MongoDB MCP Server Requirements
+pymongo>=4.5.0
+requests>=2.31.0
+fastapi>=0.104.0
+uvicorn>=0.24.0
+pydantic>=2.4.0
+aiofiles>=23.2.1
+python-multipart>=0.0.6
+""".strip()
+
+ def create_env_template(self) -> str:
+ """
+ 创建环境变量模板
+
+ Returns:
+ .env模板内容
+ """
+ return f"""
+# MongoDB MCP Configuration
+# MongoDB连接配置
+MONGODB_URL={self.config.mongodb_url}
+MONGODB_DEFAULT_DB={self.config.default_database}
+
+# MCP服务器配置
+MCP_SERVER_HOST={self.config.mcp_server_host}
+MCP_SERVER_PORT={self.config.mcp_server_port}
+MCP_SERVER_URL={self.config.mcp_server_url}
+
+# 日志配置
+LOG_LEVEL={self.config.log_level}
+ENABLE_QUERY_LOGGING={str(self.config.enable_query_logging).lower()}
+
+# Swarm集成配置
+ENABLE_AUTO_CONNECT={str(self.config.enable_auto_connect).lower()}
+MAX_QUERY_LIMIT={self.config.max_query_limit}
+DEFAULT_QUERY_LIMIT={self.config.default_query_limit}
+""".strip()
+
+
+def create_complete_setup(output_dir: str = "./mongodb_mcp_setup"):
+ """
+ 创建完整的MongoDB MCP设置
+
+ Args:
+ output_dir: 输出目录
+ """
+ import os
+
+ # 创建输出目录
+ os.makedirs(output_dir, exist_ok=True)
+
+ # 创建配置
+ config = MongoDBMCPConfig.from_env()
+ integration = SwarmMongoDBIntegration(config)
+
+ # 保存配置文件
+ config.save_to_file(os.path.join(output_dir, "mongodb_mcp_config.json"))
+
+ # 生成Swarm代理配置
+ agent_config = integration.create_swarm_agent_config()
+ with open(os.path.join(output_dir, "swarm_agent_config.json"), 'w', encoding='utf-8') as f:
+ json.dump(agent_config, f, indent=2, ensure_ascii=False)
+
+ # 生成MCP服务器配置
+ server_config = integration.create_mcp_server_config()
+ with open(os.path.join(output_dir, "mcp_server_config.json"), 'w', encoding='utf-8') as f:
+ json.dump(server_config, f, indent=2, ensure_ascii=False)
+
+ # 生成Docker配置
+ with open(os.path.join(output_dir, "docker-compose.yml"), 'w', encoding='utf-8') as f:
+ f.write(integration.generate_docker_compose())
+
+ with open(os.path.join(output_dir, "Dockerfile.mongodb-mcp"), 'w', encoding='utf-8') as f:
+ f.write(integration.generate_dockerfile())
+
+ # 生成requirements
+ with open(os.path.join(output_dir, "requirements-mongodb-mcp.txt"), 'w', encoding='utf-8') as f:
+ f.write(integration.generate_requirements())
+
+ # 生成环境变量模板
+ with open(os.path.join(output_dir, ".env.template"), 'w', encoding='utf-8') as f:
+ f.write(integration.create_env_template())
+
+ # 生成README
+ readme_content = f"""
+# MongoDB MCP for Swarm
+
+这是一个完整的MongoDB MCP服务器设置,用于与Swarm框架集成。
+
+## 文件说明
+
+- `mongodb_mcp_config.json`: MongoDB MCP配置文件
+- `swarm_agent_config.json`: Swarm代理配置
+- `mcp_server_config.json`: MCP服务器配置
+- `docker-compose.yml`: Docker Compose配置
+- `Dockerfile.mongodb-mcp`: MCP服务器Docker镜像
+- `requirements-mongodb-mcp.txt`: Python依赖
+- `.env.template`: 环境变量模板
+
+## 快速开始
+
+1. 复制环境变量模板:
+ ```bash
+ cp .env.template .env
+ ```
+
+2. 编辑 `.env` 文件,设置你的MongoDB连接信息
+
+3. 启动服务:
+ ```bash
+ docker-compose up -d
+ ```
+
+4. 验证服务:
+ ```bash
+ curl http://localhost:{config.mcp_server_port}/health
+ ```
+
+## 在Swarm中使用
+
+```python
+from src.mcp.swarm_mongodb_client import SwarmMongoDBClient, create_mongodb_functions
+from swarm import Swarm, Agent
+
+# 创建MongoDB客户端
+mongodb_client = SwarmMongoDBClient(
+ mcp_server_url="http://localhost:{config.mcp_server_port}",
+ default_database="{config.default_database}"
+)
+
+# 连接数据库
+mongodb_client.connect()
+
+# 创建MongoDB函数
+mongodb_functions = create_mongodb_functions(mongodb_client)
+
+# 创建Swarm代理
+agent = Agent(
+ name="MongoDB助手",
+ instructions="你是一个MongoDB数据库专家,帮助用户管理和查询数据库。",
+ functions=[func["function"] for func in mongodb_functions]
+)
+
+# 使用Swarm
+client = Swarm()
+response = client.run(
+ agent=agent,
+ messages=[{{"role": "user", "content": "查询users集合中的所有数据"}}]
+)
+
+print(response.messages[-1]["content"])
+```
+
+## 可用功能
+
+- `mongodb_query`: 查询集合中的文档
+- `mongodb_insert`: 插入新文档
+- `mongodb_update`: 更新现有文档
+- `mongodb_stats`: 获取统计信息
+- `mongodb_collections`: 列出所有集合
+
+## 配置说明
+
+### MongoDB连接
+- `MONGODB_URL`: MongoDB连接字符串
+- `MONGODB_DEFAULT_DB`: 默认数据库名称
+
+### MCP服务器
+- `MCP_SERVER_HOST`: 服务器主机
+- `MCP_SERVER_PORT`: 服务器端口
+
+### 查询限制
+- `MAX_QUERY_LIMIT`: 最大查询数量限制
+- `DEFAULT_QUERY_LIMIT`: 默认查询数量限制
+
+## 故障排除
+
+1. **连接失败**: 检查MongoDB服务是否运行,连接字符串是否正确
+2. **权限错误**: 确保MongoDB用户有足够的权限
+3. **端口冲突**: 修改 `MCP_SERVER_PORT` 环境变量
+
+## 安全注意事项
+
+- 不要在生产环境中使用默认密码
+- 限制MongoDB的网络访问
+- 定期备份数据库
+- 监控查询性能和资源使用
+""".strip()
+
+ with open(os.path.join(output_dir, "README.md"), 'w', encoding='utf-8') as f:
+ f.write(readme_content)
+
+ print(f"✅ MongoDB MCP设置已创建在: {output_dir}")
+ print(f"📁 包含以下文件:")
+ for file in os.listdir(output_dir):
+ print(f" - {file}")
+
+
+if __name__ == "__main__":
+ # 创建完整设置
+ create_complete_setup()
diff --git a/modules/core-collaboration/src/mcp/mongodb_mcp_server.py b/modules/core-collaboration/src/mcp/mongodb_mcp_server.py
new file mode 100644
index 0000000..e9c9700
--- /dev/null
+++ b/modules/core-collaboration/src/mcp/mongodb_mcp_server.py
@@ -0,0 +1,586 @@
+#!/usr/bin/env python3
+"""
+MongoDB MCP Server
+为Swarm提供MongoDB数据库访问的MCP服务器
+
+功能:
+- 连接MongoDB数据库
+- 执行CRUD操作
+- 聚合查询
+- 索引管理
+- 数据库统计
+"""
+
+import asyncio
+import json
+import logging
+import os
+import sys
+from typing import Any, Dict, List, Optional, Union
+from datetime import datetime
+
+try:
+ from pymongo import MongoClient
+ from pymongo.errors import PyMongoError, ConnectionFailure
+ from bson import ObjectId, json_util
+except ImportError:
+ print("Error: pymongo is required. Install with: pip install pymongo")
+ sys.exit(1)
+
+# MCP协议相关导入
+try:
+ from mcp import MCPServer, Tool, Resource
+ from mcp.types import TextContent, ImageContent, EmbeddedResource
+except ImportError:
+ # 如果没有mcp库,我们创建一个简单的兼容层
+ class MCPServer:
+ def __init__(self, name: str):
+ self.name = name
+ self.tools = {}
+ self.resources = {}
+
+ def add_tool(self, name: str, description: str, handler):
+ self.tools[name] = {
+ 'description': description,
+ 'handler': handler
+ }
+
+ def add_resource(self, uri: str, name: str, description: str, handler):
+ self.resources[uri] = {
+ 'name': name,
+ 'description': description,
+ 'handler': handler
+ }
+
+class MongoDBMCPServer:
+ """
+ MongoDB MCP服务器
+ 提供MongoDB数据库访问功能
+ """
+
+ def __init__(self, mongodb_url: Optional[str] = None):
+ self.mongodb_url = mongodb_url or os.getenv('MONGODB_URL', 'mongodb://localhost:27017')
+ self.client = None
+ self.db = None
+ self.server = MCPServer("mongodb-mcp")
+
+ # 设置日志
+ logging.basicConfig(level=logging.INFO)
+ self.logger = logging.getLogger(__name__)
+
+ # 注册工具
+ self._register_tools()
+ self._register_resources()
+
+ def _register_tools(self):
+ """注册MCP工具"""
+
+ # 数据库连接工具
+ self.server.add_tool(
+ "connect_database",
+ "连接到MongoDB数据库",
+ self.connect_database
+ )
+
+ # CRUD操作工具
+ self.server.add_tool(
+ "insert_document",
+ "向集合中插入文档",
+ self.insert_document
+ )
+
+ self.server.add_tool(
+ "find_documents",
+ "查找文档",
+ self.find_documents
+ )
+
+ self.server.add_tool(
+ "update_document",
+ "更新文档",
+ self.update_document
+ )
+
+ self.server.add_tool(
+ "delete_document",
+ "删除文档",
+ self.delete_document
+ )
+
+ # 聚合查询工具
+ self.server.add_tool(
+ "aggregate_query",
+ "执行聚合查询",
+ self.aggregate_query
+ )
+
+ # 数据库管理工具
+ self.server.add_tool(
+ "list_collections",
+ "列出数据库中的所有集合",
+ self.list_collections
+ )
+
+ self.server.add_tool(
+ "create_index",
+ "创建索引",
+ self.create_index
+ )
+
+ self.server.add_tool(
+ "get_collection_stats",
+ "获取集合统计信息",
+ self.get_collection_stats
+ )
+
+ def _register_resources(self):
+ """注册MCP资源"""
+
+ self.server.add_resource(
+ "mongodb://status",
+ "MongoDB连接状态",
+ "获取MongoDB连接状态和基本信息",
+ self.get_connection_status
+ )
+
+ self.server.add_resource(
+ "mongodb://databases",
+ "数据库列表",
+ "获取所有可用数据库的列表",
+ self.get_databases_list
+ )
+
+ async def connect_database(self, database_name: str = "default") -> Dict[str, Any]:
+ """连接到MongoDB数据库"""
+ try:
+ if not self.client:
+ self.client = MongoClient(self.mongodb_url)
+ # 测试连接
+ self.client.admin.command('ping')
+ self.logger.info(f"Connected to MongoDB at {self.mongodb_url}")
+
+ self.db = self.client[database_name]
+
+ return {
+ "success": True,
+ "message": f"Successfully connected to database '{database_name}'",
+ "database_name": database_name,
+ "connection_url": self.mongodb_url.replace(self.mongodb_url.split('@')[0].split('//')[1] + '@', '***@') if '@' in self.mongodb_url else self.mongodb_url
+ }
+
+ except ConnectionFailure as e:
+ error_msg = f"Failed to connect to MongoDB: {str(e)}"
+ self.logger.error(error_msg)
+ return {
+ "success": False,
+ "error": error_msg
+ }
+ except Exception as e:
+ error_msg = f"Unexpected error: {str(e)}"
+ self.logger.error(error_msg)
+ return {
+ "success": False,
+ "error": error_msg
+ }
+
+ async def insert_document(self, collection_name: str, document: Union[Dict, str], many: bool = False) -> Dict[str, Any]:
+ """插入文档到集合"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ # 如果document是字符串,尝试解析为JSON
+ if isinstance(document, str):
+ document = json.loads(document)
+
+ collection = self.db[collection_name]
+
+ if many and isinstance(document, list):
+ result = collection.insert_many(document)
+ return {
+ "success": True,
+ "inserted_ids": [str(id) for id in result.inserted_ids],
+ "count": len(result.inserted_ids)
+ }
+ else:
+ result = collection.insert_one(document)
+ return {
+ "success": True,
+ "inserted_id": str(result.inserted_id)
+ }
+
+ except json.JSONDecodeError as e:
+ return {"success": False, "error": f"Invalid JSON: {str(e)}"}
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def find_documents(self, collection_name: str, query: Union[Dict, str] = None,
+ projection: Union[Dict, str] = None, limit: int = 100,
+ skip: int = 0, sort: Union[Dict, str] = None) -> Dict[str, Any]:
+ """查找文档"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ # 解析参数
+ if isinstance(query, str):
+ query = json.loads(query) if query else {}
+ elif query is None:
+ query = {}
+
+ if isinstance(projection, str):
+ projection = json.loads(projection) if projection else None
+
+ if isinstance(sort, str):
+ sort = json.loads(sort) if sort else None
+
+ collection = self.db[collection_name]
+ cursor = collection.find(query, projection)
+
+ if sort:
+ cursor = cursor.sort(list(sort.items()))
+
+ cursor = cursor.skip(skip).limit(limit)
+
+ documents = list(cursor)
+
+ # 转换ObjectId为字符串
+ for doc in documents:
+ if '_id' in doc and isinstance(doc['_id'], ObjectId):
+ doc['_id'] = str(doc['_id'])
+
+ return {
+ "success": True,
+ "documents": documents,
+ "count": len(documents),
+ "query": query,
+ "limit": limit,
+ "skip": skip
+ }
+
+ except json.JSONDecodeError as e:
+ return {"success": False, "error": f"Invalid JSON: {str(e)}"}
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def update_document(self, collection_name: str, query: Union[Dict, str],
+ update: Union[Dict, str], many: bool = False) -> Dict[str, Any]:
+ """更新文档"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ # 解析参数
+ if isinstance(query, str):
+ query = json.loads(query)
+ if isinstance(update, str):
+ update = json.loads(update)
+
+ collection = self.db[collection_name]
+
+ if many:
+ result = collection.update_many(query, update)
+ return {
+ "success": True,
+ "matched_count": result.matched_count,
+ "modified_count": result.modified_count
+ }
+ else:
+ result = collection.update_one(query, update)
+ return {
+ "success": True,
+ "matched_count": result.matched_count,
+ "modified_count": result.modified_count
+ }
+
+ except json.JSONDecodeError as e:
+ return {"success": False, "error": f"Invalid JSON: {str(e)}"}
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def delete_document(self, collection_name: str, query: Union[Dict, str],
+ many: bool = False) -> Dict[str, Any]:
+ """删除文档"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ # 解析参数
+ if isinstance(query, str):
+ query = json.loads(query)
+
+ collection = self.db[collection_name]
+
+ if many:
+ result = collection.delete_many(query)
+ return {
+ "success": True,
+ "deleted_count": result.deleted_count
+ }
+ else:
+ result = collection.delete_one(query)
+ return {
+ "success": True,
+ "deleted_count": result.deleted_count
+ }
+
+ except json.JSONDecodeError as e:
+ return {"success": False, "error": f"Invalid JSON: {str(e)}"}
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def aggregate_query(self, collection_name: str, pipeline: Union[List, str]) -> Dict[str, Any]:
+ """执行聚合查询"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ # 解析参数
+ if isinstance(pipeline, str):
+ pipeline = json.loads(pipeline)
+
+ collection = self.db[collection_name]
+ result = list(collection.aggregate(pipeline))
+
+ # 转换ObjectId为字符串
+ for doc in result:
+ if '_id' in doc and isinstance(doc['_id'], ObjectId):
+ doc['_id'] = str(doc['_id'])
+
+ return {
+ "success": True,
+ "result": result,
+ "count": len(result),
+ "pipeline": pipeline
+ }
+
+ except json.JSONDecodeError as e:
+ return {"success": False, "error": f"Invalid JSON: {str(e)}"}
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def list_collections(self) -> Dict[str, Any]:
+ """列出数据库中的所有集合"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ collections = self.db.list_collection_names()
+
+ return {
+ "success": True,
+ "collections": collections,
+ "count": len(collections)
+ }
+
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def create_index(self, collection_name: str, index_spec: Union[Dict, str],
+ unique: bool = False, background: bool = True) -> Dict[str, Any]:
+ """创建索引"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ # 解析参数
+ if isinstance(index_spec, str):
+ index_spec = json.loads(index_spec)
+
+ collection = self.db[collection_name]
+
+ # 转换为pymongo格式
+ index_list = [(key, value) for key, value in index_spec.items()]
+
+ result = collection.create_index(
+ index_list,
+ unique=unique,
+ background=background
+ )
+
+ return {
+ "success": True,
+ "index_name": result,
+ "index_spec": index_spec
+ }
+
+ except json.JSONDecodeError as e:
+ return {"success": False, "error": f"Invalid JSON: {str(e)}"}
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def get_collection_stats(self, collection_name: str) -> Dict[str, Any]:
+ """获取集合统计信息"""
+ try:
+ if not self.db:
+ return {"success": False, "error": "Database not connected"}
+
+ collection = self.db[collection_name]
+
+ # 获取基本统计
+ stats = self.db.command("collStats", collection_name)
+
+ # 获取文档数量
+ count = collection.count_documents({})
+
+ # 获取索引信息
+ indexes = list(collection.list_indexes())
+
+ return {
+ "success": True,
+ "collection_name": collection_name,
+ "document_count": count,
+ "size_bytes": stats.get('size', 0),
+ "storage_size_bytes": stats.get('storageSize', 0),
+ "indexes": [{
+ "name": idx.get('name'),
+ "key": idx.get('key'),
+ "unique": idx.get('unique', False)
+ } for idx in indexes],
+ "index_count": len(indexes)
+ }
+
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ async def get_connection_status(self) -> Dict[str, Any]:
+ """获取连接状态"""
+ try:
+ if not self.client:
+ return {
+ "connected": False,
+ "message": "Not connected to MongoDB"
+ }
+
+ # 测试连接
+ self.client.admin.command('ping')
+
+ # 获取服务器信息
+ server_info = self.client.server_info()
+
+ return {
+ "connected": True,
+ "server_version": server_info.get('version'),
+ "connection_url": self.mongodb_url.replace(self.mongodb_url.split('@')[0].split('//')[1] + '@', '***@') if '@' in self.mongodb_url else self.mongodb_url,
+ "current_database": self.db.name if self.db else None,
+ "server_info": {
+ "version": server_info.get('version'),
+ "git_version": server_info.get('gitVersion'),
+ "platform": server_info.get('platform')
+ }
+ }
+
+ except Exception as e:
+ return {
+ "connected": False,
+ "error": str(e)
+ }
+
+ async def get_databases_list(self) -> Dict[str, Any]:
+ """获取数据库列表"""
+ try:
+ if not self.client:
+ return {"success": False, "error": "Not connected to MongoDB"}
+
+ databases = self.client.list_database_names()
+
+ return {
+ "success": True,
+ "databases": databases,
+ "count": len(databases)
+ }
+
+ except PyMongoError as e:
+ return {"success": False, "error": f"MongoDB error: {str(e)}"}
+ except Exception as e:
+ return {"success": False, "error": f"Unexpected error: {str(e)}"}
+
+ def close_connection(self):
+ """关闭数据库连接"""
+ if self.client:
+ self.client.close()
+ self.client = None
+ self.db = None
+ self.logger.info("MongoDB connection closed")
+
+
+def main():
+ """主函数 - 启动MCP服务器"""
+ import argparse
+
+ parser = argparse.ArgumentParser(description="MongoDB MCP Server")
+ parser.add_argument(
+ "--mongodb-url",
+ default=os.getenv('MONGODB_URL', 'mongodb://localhost:27017'),
+ help="MongoDB连接URL"
+ )
+ parser.add_argument(
+ "--database",
+ default="default",
+ help="默认数据库名称"
+ )
+ parser.add_argument(
+ "--port",
+ type=int,
+ default=8080,
+ help="MCP服务器端口"
+ )
+
+ args = parser.parse_args()
+
+ # 创建MCP服务器
+ mcp_server = MongoDBMCPServer(args.mongodb_url)
+
+ print(f"🚀 Starting MongoDB MCP Server...")
+ print(f"📊 MongoDB URL: {args.mongodb_url}")
+ print(f"🗄️ Default Database: {args.database}")
+ print(f"🌐 Port: {args.port}")
+ print(f"")
+ print(f"Available tools:")
+ for tool_name, tool_info in mcp_server.server.tools.items():
+ print(f" - {tool_name}: {tool_info['description']}")
+ print(f"")
+ print(f"Available resources:")
+ for resource_uri, resource_info in mcp_server.server.resources.items():
+ print(f" - {resource_uri}: {resource_info['description']}")
+
+ try:
+ # 自动连接到默认数据库
+ asyncio.run(mcp_server.connect_database(args.database))
+
+ # 这里应该启动实际的MCP服务器
+ # 由于我们没有完整的MCP库,这里只是演示
+ print(f"\n✅ MongoDB MCP Server is ready!")
+ print(f"💡 Use this server with Swarm MCP client to access MongoDB")
+
+ # 保持服务器运行
+ try:
+ while True:
+ asyncio.run(asyncio.sleep(1))
+ except KeyboardInterrupt:
+ print("\n🛑 Shutting down MongoDB MCP Server...")
+ mcp_server.close_connection()
+
+ except Exception as e:
+ print(f"❌ Error starting server: {e}")
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/mcp/swarm_mongodb_client.py b/modules/core-collaboration/src/mcp/swarm_mongodb_client.py
new file mode 100644
index 0000000..269f2dd
--- /dev/null
+++ b/modules/core-collaboration/src/mcp/swarm_mongodb_client.py
@@ -0,0 +1,633 @@
+#!/usr/bin/env python3
+"""
+Swarm MongoDB MCP Client
+Swarm框架的MongoDB MCP客户端,用于连接和使用MongoDB MCP服务器
+
+功能:
+- 连接到MongoDB MCP服务器
+- 提供Swarm代理使用的MongoDB操作接口
+- 处理MCP协议通信
+- 数据格式转换和错误处理
+"""
+
+import asyncio
+import json
+import logging
+import os
+import sys
+from typing import Any, Dict, List, Optional, Union
+from datetime import datetime
+
+try:
+ import requests
+except ImportError:
+ print("Error: requests is required. Install with: pip install requests")
+ sys.exit(1)
+
+class SwarmMongoDBClient:
+ """
+ Swarm MongoDB MCP客户端
+ 为Swarm代理提供MongoDB数据库访问功能
+ """
+
+ def __init__(self, mcp_server_url: str = "http://localhost:8080",
+ mongodb_url: Optional[str] = None,
+ default_database: str = "default"):
+ self.mcp_server_url = mcp_server_url.rstrip('/')
+ self.mongodb_url = mongodb_url or os.getenv('MONGODB_URL', 'mongodb://localhost:27017')
+ self.default_database = default_database
+ self.connected = False
+
+ # 设置日志
+ logging.basicConfig(level=logging.INFO)
+ self.logger = logging.getLogger(__name__)
+
+ # 会话配置
+ self.session = requests.Session()
+ self.session.headers.update({
+ 'Content-Type': 'application/json',
+ 'User-Agent': 'Swarm-MongoDB-MCP-Client/1.0'
+ })
+
+ def _call_mcp_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
+ """
+ 调用MCP服务器工具
+
+ Args:
+ tool_name: 工具名称
+ **kwargs: 工具参数
+
+ Returns:
+ 工具执行结果
+ """
+ try:
+ url = f"{self.mcp_server_url}/tools/{tool_name}"
+ response = self.session.post(url, json=kwargs, timeout=30)
+ response.raise_for_status()
+
+ result = response.json()
+ return result
+
+ except requests.exceptions.RequestException as e:
+ self.logger.error(f"MCP tool call failed: {e}")
+ return {
+ "success": False,
+ "error": f"MCP communication error: {str(e)}"
+ }
+ except json.JSONDecodeError as e:
+ self.logger.error(f"Invalid JSON response: {e}")
+ return {
+ "success": False,
+ "error": f"Invalid response format: {str(e)}"
+ }
+ except Exception as e:
+ self.logger.error(f"Unexpected error: {e}")
+ return {
+ "success": False,
+ "error": f"Unexpected error: {str(e)}"
+ }
+
+ def _get_mcp_resource(self, resource_uri: str) -> Dict[str, Any]:
+ """
+ 获取MCP服务器资源
+
+ Args:
+ resource_uri: 资源URI
+
+ Returns:
+ 资源内容
+ """
+ try:
+ url = f"{self.mcp_server_url}/resources"
+ response = self.session.get(url, params={'uri': resource_uri}, timeout=30)
+ response.raise_for_status()
+
+ result = response.json()
+ return result
+
+ except requests.exceptions.RequestException as e:
+ self.logger.error(f"MCP resource request failed: {e}")
+ return {
+ "success": False,
+ "error": f"MCP communication error: {str(e)}"
+ }
+ except Exception as e:
+ self.logger.error(f"Unexpected error: {e}")
+ return {
+ "success": False,
+ "error": f"Unexpected error: {str(e)}"
+ }
+
+ # === 连接管理 ===
+
+ def connect(self, database_name: Optional[str] = None) -> Dict[str, Any]:
+ """
+ 连接到MongoDB数据库
+
+ Args:
+ database_name: 数据库名称,默认使用初始化时指定的数据库
+
+ Returns:
+ 连接结果
+ """
+ db_name = database_name or self.default_database
+ result = self._call_mcp_tool("connect_database", database_name=db_name)
+
+ if result.get("success"):
+ self.connected = True
+ self.current_database = db_name
+ self.logger.info(f"Connected to MongoDB database: {db_name}")
+
+ return result
+
+ def get_connection_status(self) -> Dict[str, Any]:
+ """
+ 获取连接状态
+
+ Returns:
+ 连接状态信息
+ """
+ return self._get_mcp_resource("mongodb://status")
+
+ def list_databases(self) -> Dict[str, Any]:
+ """
+ 获取数据库列表
+
+ Returns:
+ 数据库列表
+ """
+ return self._get_mcp_resource("mongodb://databases")
+
+ # === CRUD操作 ===
+
+ def insert_document(self, collection_name: str, document: Union[Dict, List[Dict]],
+ many: bool = False) -> Dict[str, Any]:
+ """
+ 插入文档
+
+ Args:
+ collection_name: 集合名称
+ document: 要插入的文档或文档列表
+ many: 是否批量插入
+
+ Returns:
+ 插入结果
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "insert_document",
+ collection_name=collection_name,
+ document=document,
+ many=many
+ )
+
+ def find_documents(self, collection_name: str, query: Optional[Dict] = None,
+ projection: Optional[Dict] = None, limit: int = 100,
+ skip: int = 0, sort: Optional[Dict] = None) -> Dict[str, Any]:
+ """
+ 查找文档
+
+ Args:
+ collection_name: 集合名称
+ query: 查询条件
+ projection: 投影字段
+ limit: 限制数量
+ skip: 跳过数量
+ sort: 排序条件
+
+ Returns:
+ 查询结果
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "find_documents",
+ collection_name=collection_name,
+ query=query or {},
+ projection=projection,
+ limit=limit,
+ skip=skip,
+ sort=sort
+ )
+
+ def update_document(self, collection_name: str, query: Dict, update: Dict,
+ many: bool = False) -> Dict[str, Any]:
+ """
+ 更新文档
+
+ Args:
+ collection_name: 集合名称
+ query: 查询条件
+ update: 更新操作
+ many: 是否批量更新
+
+ Returns:
+ 更新结果
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "update_document",
+ collection_name=collection_name,
+ query=query,
+ update=update,
+ many=many
+ )
+
+ def delete_document(self, collection_name: str, query: Dict,
+ many: bool = False) -> Dict[str, Any]:
+ """
+ 删除文档
+
+ Args:
+ collection_name: 集合名称
+ query: 查询条件
+ many: 是否批量删除
+
+ Returns:
+ 删除结果
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "delete_document",
+ collection_name=collection_name,
+ query=query,
+ many=many
+ )
+
+ # === 高级查询 ===
+
+ def aggregate(self, collection_name: str, pipeline: List[Dict]) -> Dict[str, Any]:
+ """
+ 执行聚合查询
+
+ Args:
+ collection_name: 集合名称
+ pipeline: 聚合管道
+
+ Returns:
+ 聚合结果
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "aggregate_query",
+ collection_name=collection_name,
+ pipeline=pipeline
+ )
+
+ # === 数据库管理 ===
+
+ def list_collections(self) -> Dict[str, Any]:
+ """
+ 列出所有集合
+
+ Returns:
+ 集合列表
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool("list_collections")
+
+ def create_index(self, collection_name: str, index_spec: Dict,
+ unique: bool = False, background: bool = True) -> Dict[str, Any]:
+ """
+ 创建索引
+
+ Args:
+ collection_name: 集合名称
+ index_spec: 索引规范
+ unique: 是否唯一索引
+ background: 是否后台创建
+
+ Returns:
+ 创建结果
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "create_index",
+ collection_name=collection_name,
+ index_spec=index_spec,
+ unique=unique,
+ background=background
+ )
+
+ def get_collection_stats(self, collection_name: str) -> Dict[str, Any]:
+ """
+ 获取集合统计信息
+
+ Args:
+ collection_name: 集合名称
+
+ Returns:
+ 统计信息
+ """
+ if not self.connected:
+ return {"success": False, "error": "Not connected to database"}
+
+ return self._call_mcp_tool(
+ "get_collection_stats",
+ collection_name=collection_name
+ )
+
+ # === Swarm代理专用方法 ===
+
+ def swarm_query(self, collection_name: str, natural_language_query: str) -> str:
+ """
+ Swarm代理专用的自然语言查询接口
+
+ Args:
+ collection_name: 集合名称
+ natural_language_query: 自然语言查询描述
+
+ Returns:
+ 格式化的查询结果字符串
+ """
+ try:
+ # 这里可以集成NLP处理,将自然语言转换为MongoDB查询
+ # 目前简化处理,直接执行基本查询
+
+ result = self.find_documents(collection_name, limit=10)
+
+ if result.get("success"):
+ documents = result.get("documents", [])
+ if documents:
+ formatted_result = f"Found {len(documents)} documents in '{collection_name}':\n"
+ for i, doc in enumerate(documents[:5], 1): # 只显示前5个
+ formatted_result += f"{i}. {json.dumps(doc, indent=2, ensure_ascii=False)}\n"
+
+ if len(documents) > 5:
+ formatted_result += f"... and {len(documents) - 5} more documents\n"
+
+ return formatted_result
+ else:
+ return f"No documents found in collection '{collection_name}'"
+ else:
+ return f"Query failed: {result.get('error', 'Unknown error')}"
+
+ except Exception as e:
+ return f"Error executing query: {str(e)}"
+
+ def swarm_insert(self, collection_name: str, data_description: str,
+ document: Union[Dict, List[Dict]]) -> str:
+ """
+ Swarm代理专用的插入接口
+
+ Args:
+ collection_name: 集合名称
+ data_description: 数据描述
+ document: 要插入的文档
+
+ Returns:
+ 格式化的插入结果字符串
+ """
+ try:
+ many = isinstance(document, list)
+ result = self.insert_document(collection_name, document, many=many)
+
+ if result.get("success"):
+ if many:
+ count = result.get("count", 0)
+ return f"Successfully inserted {count} documents into '{collection_name}'. Description: {data_description}"
+ else:
+ inserted_id = result.get("inserted_id")
+ return f"Successfully inserted document with ID {inserted_id} into '{collection_name}'. Description: {data_description}"
+ else:
+ return f"Insert failed: {result.get('error', 'Unknown error')}"
+
+ except Exception as e:
+ return f"Error inserting data: {str(e)}"
+
+ def swarm_update(self, collection_name: str, update_description: str,
+ query: Dict, update: Dict) -> str:
+ """
+ Swarm代理专用的更新接口
+
+ Args:
+ collection_name: 集合名称
+ update_description: 更新描述
+ query: 查询条件
+ update: 更新操作
+
+ Returns:
+ 格式化的更新结果字符串
+ """
+ try:
+ result = self.update_document(collection_name, query, update)
+
+ if result.get("success"):
+ matched = result.get("matched_count", 0)
+ modified = result.get("modified_count", 0)
+ return f"Update completed: {matched} documents matched, {modified} documents modified in '{collection_name}'. Description: {update_description}"
+ else:
+ return f"Update failed: {result.get('error', 'Unknown error')}"
+
+ except Exception as e:
+ return f"Error updating data: {str(e)}"
+
+ def swarm_stats(self, collection_name: Optional[str] = None) -> str:
+ """
+ Swarm代理专用的统计信息接口
+
+ Args:
+ collection_name: 集合名称,如果为None则返回数据库概览
+
+ Returns:
+ 格式化的统计信息字符串
+ """
+ try:
+ if collection_name:
+ # 获取特定集合的统计信息
+ result = self.get_collection_stats(collection_name)
+ if result.get("success"):
+ stats = result
+ return f"""Collection '{collection_name}' Statistics:
+- Document Count: {stats.get('document_count', 0):,}
+- Size: {stats.get('size_bytes', 0):,} bytes
+- Storage Size: {stats.get('storage_size_bytes', 0):,} bytes
+- Indexes: {stats.get('index_count', 0)}"""
+ else:
+ return f"Failed to get stats for '{collection_name}': {result.get('error', 'Unknown error')}"
+ else:
+ # 获取数据库概览
+ collections_result = self.list_collections()
+ status_result = self.get_connection_status()
+
+ if collections_result.get("success") and status_result.get("connected"):
+ collections = collections_result.get("collections", [])
+ db_name = status_result.get("current_database", "Unknown")
+
+ stats_text = f"""Database '{db_name}' Overview:
+- Total Collections: {len(collections)}
+- Collections: {', '.join(collections) if collections else 'None'}
+- Server Version: {status_result.get('server_info', {}).get('version', 'Unknown')}"""
+
+ return stats_text
+ else:
+ return "Failed to get database overview"
+
+ except Exception as e:
+ return f"Error getting statistics: {str(e)}"
+
+ def close(self):
+ """
+ 关闭客户端连接
+ """
+ self.session.close()
+ self.connected = False
+ self.logger.info("MongoDB MCP client closed")
+
+
+# === Swarm代理函数 ===
+
+def create_mongodb_functions(client: SwarmMongoDBClient) -> List[Dict[str, Any]]:
+ """
+ 为Swarm代理创建MongoDB操作函数
+
+ Args:
+ client: MongoDB MCP客户端实例
+
+ Returns:
+ Swarm函数列表
+ """
+
+ def mongodb_query(collection_name: str, query_description: str = "查询所有文档") -> str:
+ """查询MongoDB集合中的文档"""
+ return client.swarm_query(collection_name, query_description)
+
+ def mongodb_insert(collection_name: str, document: Union[Dict, str],
+ description: str = "插入新文档") -> str:
+ """向MongoDB集合插入文档"""
+ if isinstance(document, str):
+ try:
+ document = json.loads(document)
+ except json.JSONDecodeError:
+ return f"Error: Invalid JSON format in document: {document}"
+
+ return client.swarm_insert(collection_name, description, document)
+
+ def mongodb_update(collection_name: str, query: Union[Dict, str],
+ update: Union[Dict, str], description: str = "更新文档") -> str:
+ """更新MongoDB集合中的文档"""
+ try:
+ if isinstance(query, str):
+ query = json.loads(query)
+ if isinstance(update, str):
+ update = json.loads(update)
+ except json.JSONDecodeError as e:
+ return f"Error: Invalid JSON format: {str(e)}"
+
+ return client.swarm_update(collection_name, description, query, update)
+
+ def mongodb_stats(collection_name: str = None) -> str:
+ """获取MongoDB数据库或集合的统计信息"""
+ return client.swarm_stats(collection_name)
+
+ def mongodb_collections() -> str:
+ """列出数据库中的所有集合"""
+ result = client.list_collections()
+ if result.get("success"):
+ collections = result.get("collections", [])
+ if collections:
+ return f"Available collections: {', '.join(collections)}"
+ else:
+ return "No collections found in the database"
+ else:
+ return f"Error listing collections: {result.get('error', 'Unknown error')}"
+
+ # 返回函数定义列表
+ return [
+ {
+ "name": "mongodb_query",
+ "description": "查询MongoDB集合中的文档",
+ "function": mongodb_query
+ },
+ {
+ "name": "mongodb_insert",
+ "description": "向MongoDB集合插入文档",
+ "function": mongodb_insert
+ },
+ {
+ "name": "mongodb_update",
+ "description": "更新MongoDB集合中的文档",
+ "function": mongodb_update
+ },
+ {
+ "name": "mongodb_stats",
+ "description": "获取MongoDB数据库或集合的统计信息",
+ "function": mongodb_stats
+ },
+ {
+ "name": "mongodb_collections",
+ "description": "列出数据库中的所有集合",
+ "function": mongodb_collections
+ }
+ ]
+
+
+def main():
+ """测试客户端功能"""
+ import argparse
+
+ parser = argparse.ArgumentParser(description="Swarm MongoDB MCP Client")
+ parser.add_argument(
+ "--mcp-server",
+ default="http://localhost:8080",
+ help="MCP服务器URL"
+ )
+ parser.add_argument(
+ "--database",
+ default="test",
+ help="数据库名称"
+ )
+
+ args = parser.parse_args()
+
+ # 创建客户端
+ client = SwarmMongoDBClient(
+ mcp_server_url=args.mcp_server,
+ default_database=args.database
+ )
+
+ print(f"🔗 Connecting to MongoDB MCP Server: {args.mcp_server}")
+
+ # 测试连接
+ result = client.connect(args.database)
+ if result.get("success"):
+ print(f"✅ Connected to database: {args.database}")
+
+ # 测试基本操作
+ print("\n📊 Testing basic operations...")
+
+ # 列出集合
+ collections = client.list_collections()
+ print(f"Collections: {collections}")
+
+ # 获取状态
+ status = client.get_connection_status()
+ print(f"Status: {status}")
+
+ # 创建Swarm函数
+ functions = create_mongodb_functions(client)
+ print(f"\n🔧 Created {len(functions)} Swarm functions:")
+ for func in functions:
+ print(f" - {func['name']}: {func['description']}")
+
+ else:
+ print(f"❌ Connection failed: {result.get('error')}")
+
+ client.close()
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/core-collaboration/src/swarm_trigger.py b/modules/core-collaboration/src/swarm_trigger.py
new file mode 100644
index 0000000..4cdd332
--- /dev/null
+++ b/modules/core-collaboration/src/swarm_trigger.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python3
+"""
+Swarm辩论触发器
+基于时间群聚效应和语义相似性触发蜂群辩论
+"""
+
+import os
+from datetime import datetime, timedelta
+from pymongo import MongoClient
+from typing import List, Dict, Optional
+import numpy as np
+
+class SwarmDebateTrigger:
+ def __init__(self):
+ self.mongodb_uri = os.getenv('MONGODB_URI')
+ self.client = MongoClient(self.mongodb_uri)
+ self.db = self.client.taigong
+ self.collection = self.db.articles
+
+ # 配置参数
+ self.swarm_threshold = int(os.getenv('SWARM_THRESHOLD', 5))
+ self.time_window_hours = int(os.getenv('SWARM_TIME_WINDOW_HOURS', 24))
+
+ def detect_time_clustering(self) -> List[Dict]:
+ """检测时间窗口内的文章群聚效应"""
+ # 计算时间窗口
+ now = datetime.utcnow()
+ time_threshold = now - timedelta(hours=self.time_window_hours)
+
+ # 使用published_time_index查询最近文章
+ recent_articles = list(self.collection.find({
+ "published_time": {"$gte": time_threshold}
+ }).sort("published_time", -1))
+
+ print(f"最近{self.time_window_hours}小时内发现 {len(recent_articles)} 篇文章")
+
+ if len(recent_articles) >= self.swarm_threshold:
+ print(f"✓ 触发群聚效应!文章数量({len(recent_articles)}) >= 阈值({self.swarm_threshold})")
+ return recent_articles
+ else:
+ print(f"× 未达到群聚阈值,需要至少 {self.swarm_threshold} 篇文章")
+ return []
+
+ def find_semantic_clusters(self, articles: List[Dict], similarity_threshold: float = 0.8) -> List[List[Dict]]:
+ """基于向量相似性找到语义聚类"""
+ if not articles:
+ return []
+
+ # 过滤有embedding的文章
+ articles_with_embeddings = [
+ article for article in articles
+ if 'embedding' in article and article['embedding']
+ ]
+
+ if len(articles_with_embeddings) < 2:
+ print("× 没有足够的embedding数据进行语义聚类")
+ return [articles_with_embeddings] if articles_with_embeddings else []
+
+ print(f"对 {len(articles_with_embeddings)} 篇文章进行语义聚类分析...")
+
+ # 简单的相似性聚类算法
+ clusters = []
+ used_indices = set()
+
+ for i, article1 in enumerate(articles_with_embeddings):
+ if i in used_indices:
+ continue
+
+ cluster = [article1]
+ used_indices.add(i)
+
+ for j, article2 in enumerate(articles_with_embeddings):
+ if j in used_indices or i == j:
+ continue
+
+ # 计算余弦相似度
+ similarity = self.cosine_similarity(
+ article1['embedding'],
+ article2['embedding']
+ )
+
+ if similarity >= similarity_threshold:
+ cluster.append(article2)
+ used_indices.add(j)
+
+ if len(cluster) >= 2: # 至少2篇文章才算一个有效聚类
+ clusters.append(cluster)
+ print(f"✓ 发现语义聚类,包含 {len(cluster)} 篇相关文章")
+
+ return clusters
+
+ def cosine_similarity(self, vec1: List[float], vec2: List[float]) -> float:
+ """计算两个向量的余弦相似度"""
+ try:
+ vec1 = np.array(vec1)
+ vec2 = np.array(vec2)
+
+ dot_product = np.dot(vec1, vec2)
+ norm1 = np.linalg.norm(vec1)
+ norm2 = np.linalg.norm(vec2)
+
+ if norm1 == 0 or norm2 == 0:
+ return 0
+
+ return dot_product / (norm1 * norm2)
+ except Exception as e:
+ print(f"计算相似度失败: {e}")
+ return 0
+
+ def trigger_swarm_debate(self, clusters: List[List[Dict]]) -> bool:
+ """触发swarm蜂群辩论"""
+ if not clusters:
+ print("× 没有发现有效的语义聚类,不触发辩论")
+ return False
+
+ print(f"\n🔥 触发Swarm蜂群辩论!")
+ print(f"发现 {len(clusters)} 个语义聚类")
+
+ for i, cluster in enumerate(clusters):
+ print(f"\n聚类 {i+1}: {len(cluster)} 篇文章")
+ for article in cluster:
+ title = article.get('title', '无标题')[:50]
+ time_str = article.get('published_time', '').strftime('%Y-%m-%d %H:%M') if article.get('published_time') else '未知时间'
+ print(f" - {title}... ({time_str})")
+
+ # TODO: 在这里调用实际的辩论系统
+ # 例如: jixia_swarm_debate(clusters)
+
+ return True
+
+ def run(self) -> bool:
+ """运行swarm辩论触发检测"""
+ print("🔍 开始检测swarm辩论触发条件...")
+
+ # 1. 检测时间群聚效应
+ recent_articles = self.detect_time_clustering()
+ if not recent_articles:
+ return False
+
+ # 2. 进行语义聚类分析
+ semantic_clusters = self.find_semantic_clusters(recent_articles)
+
+ # 3. 触发辩论
+ return self.trigger_swarm_debate(semantic_clusters)
+
+if __name__ == "__main__":
+ trigger = SwarmDebateTrigger()
+ trigger.run()
\ No newline at end of file
diff --git a/config/__init__.py b/modules/devops-tools/config/__init__.py
similarity index 100%
rename from config/__init__.py
rename to modules/devops-tools/config/__init__.py
diff --git a/config/doppler_config.py b/modules/devops-tools/config/doppler_config.py
similarity index 100%
rename from config/doppler_config.py
rename to modules/devops-tools/config/doppler_config.py
diff --git a/config/settings.py b/modules/devops-tools/config/settings.py
similarity index 100%
rename from config/settings.py
rename to modules/devops-tools/config/settings.py
diff --git a/modules/devops-tools/scripts/api_health_check.py b/modules/devops-tools/scripts/api_health_check.py
new file mode 100644
index 0000000..8f53a3b
--- /dev/null
+++ b/modules/devops-tools/scripts/api_health_check.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+"""
+API健康检查模块
+用于测试与外部服务的连接,如OpenRouter和RapidAPI。
+"""
+
+import os
+import requests
+import sys
+from pathlib import Path
+
+# 将项目根目录添加到Python路径,以便导入config模块
+project_root = Path(__file__).parent.parent
+sys.path.insert(0, str(project_root))
+
+from config.settings import get_openrouter_key, get_rapidapi_key
+
+def test_openrouter_api() -> bool:
+ """
+ 测试与OpenRouter API的连接和认证。
+ """
+ api_key = get_openrouter_key()
+ if not api_key:
+ print("❌ OpenRouter API Key not found.")
+ return False
+
+ url = "https://openrouter.ai/api/v1/models"
+ headers = {"Authorization": f"Bearer {api_key}"}
+
+ try:
+ response = requests.get(url, headers=headers, timeout=10)
+ if response.status_code == 200:
+ print("✅ OpenRouter API connection successful.")
+ return True
+ else:
+ print(f"❌ OpenRouter API connection failed. Status: {response.status_code}, Response: {response.text[:100]}")
+ return False
+ except requests.RequestException as e:
+ print(f"❌ OpenRouter API request failed: {e}")
+ return False
+
+def test_rapidapi_connection() -> bool:
+ """
+ 测试与RapidAPI的连接和认证。
+ 这里我们使用一个简单的、免费的API端点进行测试。
+ """
+ api_key = get_rapidapi_key()
+ if not api_key:
+ print("❌ RapidAPI Key not found.")
+ return False
+
+ # 使用一个通用的、通常可用的RapidAPI端点进行测试
+ url = "https://alpha-vantage.p.rapidapi.com/query"
+ querystring = {"function":"TOP_GAINERS_LOSERS"}
+ headers = {
+ "x-rapidapi-host": "alpha-vantage.p.rapidapi.com",
+ "x-rapidapi-key": api_key
+ }
+
+ try:
+ response = requests.get(url, headers=headers, params=querystring, timeout=15)
+ # Alpha Vantage的免费套餐可能会返回错误,但只要RapidAPI认证通过,状态码就不是401或403
+ if response.status_code not in [401, 403]:
+ print(f"✅ RapidAPI connection successful (Status: {response.status_code}).")
+ return True
+ else:
+ print(f"❌ RapidAPI authentication failed. Status: {response.status_code}, Response: {response.text[:100]}")
+ return False
+ except requests.RequestException as e:
+ print(f"❌ RapidAPI request failed: {e}")
+ return False
+
+if __name__ == "__main__":
+ print("🩺 Running API Health Checks...")
+ test_openrouter_api()
+ test_rapidapi_connection()
diff --git a/modules/devops-tools/scripts/check-status.sh b/modules/devops-tools/scripts/check-status.sh
new file mode 100755
index 0000000..1e12fab
--- /dev/null
+++ b/modules/devops-tools/scripts/check-status.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# 环境状态检查脚本
+
+echo "📊 环境状态检查"
+echo "=================="
+
+# Git 状态
+echo "Git 状态:"
+git status --short
+
+echo ""
+
+# 远程仓库状态
+echo "远程仓库状态:"
+git remote -v
+
+echo ""
+
+# 分支状态
+echo "分支状态:"
+git branch -a
+
+echo ""
+
+# 最新标签
+echo "最新标签:"
+git tag --sort=-version:refname | head -5
+
+echo ""
+
+# 提交历史
+echo "最近提交:"
+git log --oneline -5
diff --git a/modules/devops-tools/scripts/quick-release.sh b/modules/devops-tools/scripts/quick-release.sh
new file mode 100755
index 0000000..77607b1
--- /dev/null
+++ b/modules/devops-tools/scripts/quick-release.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# 快速发布脚本
+
+VERSION=$1
+ENV=$2
+
+if [ -z "$VERSION" ] || [ -z "$ENV" ]; then
+ echo "用法: ./quick-release.sh <版本号> <环境>"
+ echo "环境选项: dev/staging/prod"
+ exit 1
+fi
+
+case $ENV in
+ canary)
+ git checkout main
+ git tag "v${VERSION}-canary"
+ git push canary main --tags
+ ;;
+ dev)
+ git checkout main
+ git tag "v${VERSION}-dev"
+ git push dev main --tags
+ ;;
+ beta)
+ git checkout main
+ git tag "v${VERSION}-beta"
+ git push beta main --tags
+ ;;
+ *)
+ echo "无效的环境选项: canary/dev/beta"
+ exit 1
+ ;;
+esac
+
+echo "✅ 发布完成: v${VERSION}-${ENV}"
diff --git a/modules/devops-tools/scripts/rollback.sh b/modules/devops-tools/scripts/rollback.sh
new file mode 100755
index 0000000..7ed6826
--- /dev/null
+++ b/modules/devops-tools/scripts/rollback.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# 快速回滚脚本
+
+ENV=$1
+VERSION=$2
+
+if [ -z "$ENV" ] || [ -z "$VERSION" ]; then
+ echo "用法: ./rollback.sh <环境> <版本号>"
+ echo "环境选项: staging/prod"
+ exit 1
+fi
+
+case $ENV in
+ canary)
+ git checkout main
+ git reset --hard "v${VERSION}-canary"
+ git push canary main --force
+ ;;
+ dev)
+ git checkout main
+ git reset --hard "v${VERSION}-dev"
+ git push dev main --force
+ ;;
+ beta)
+ git checkout main
+ git reset --hard "v${VERSION}-beta"
+ git push beta main --force
+ ;;
+ *)
+ echo "无效的环境选项: canary/dev/beta"
+ exit 1
+ ;;
+esac
+
+echo "✅ 回滚完成: ${ENV} -> v${VERSION}"
diff --git a/modules/devops-tools/scripts/setup_gradual_deployment.sh b/modules/devops-tools/scripts/setup_gradual_deployment.sh
new file mode 100755
index 0000000..0094389
--- /dev/null
+++ b/modules/devops-tools/scripts/setup_gradual_deployment.sh
@@ -0,0 +1,229 @@
+#!/bin/bash
+# 六壬神鉴渐进发布环境配置脚本
+
+set -e
+
+echo "🚀 配置渐进发布环境..."
+
+# 1. 配置 Git 别名简化操作
+echo "配置 Git 别名..."
+git config alias.deploy-staging '!git push staging staging:main'
+git config alias.deploy-prod '!git push origin main'
+git config alias.sync-all '!git fetch --all && git push --all'
+git config alias.release-start '!git checkout develop && git pull && git checkout -b release/'
+git config alias.release-finish '!git checkout main && git merge staging && git tag -a'
+
+# 2. 创建发布分支
+echo "创建发布分支..."
+git checkout -b staging 2>/dev/null || git checkout staging
+git checkout -b develop 2>/dev/null || git checkout develop
+
+# 3. 推送分支到所有远程仓库
+echo "推送分支到所有远程仓库..."
+git push origin staging:staging 2>/dev/null || true
+git push origin develop:develop 2>/dev/null || true
+git push staging staging:main 2>/dev/null || true
+git push staging develop:develop 2>/dev/null || true
+
+# 4. 设置分支保护(需要管理员权限)
+echo "设置分支保护规则..."
+echo "⚠️ 请在 GitHub/GitLab/Gitea 后台手动设置以下分支保护:"
+echo "- main 分支:需要 PR 审查,禁止直接推送"
+echo "- staging 分支:需要 PR 审查,禁止直接推送"
+echo "- develop 分支:需要 PR 审查,禁止直接推送"
+
+# 5. 创建发布标签模板
+echo "创建发布标签模板..."
+cat > .gitmessage.txt << 'EOF'
+# 发布标签模板
+# 格式:v主版本.次版本.修订版本-环境
+#
+# 示例:
+# v1.2.0-canary (灰度发布)
+# v1.2.0 (正式版本)
+# v1.2.1-hotfix (热修复)
+#
+# 环境标识:
+# -canary: 灰度发布
+# -staging: 预发布测试
+# -hotfix: 紧急修复
+# 无后缀:正式版本
+
+发布类型: [feature/bugfix/hotfix/docs]
+影响范围: [core/api/ui/config]
+测试状态: [passed/failed/pending]
+回滚策略: [已准备/无需回滚]
+EOF
+
+git config commit.template .gitmessage.txt
+
+# 6. 创建快速发布脚本
+cat > scripts/quick-release.sh << 'EOF'
+#!/bin/bash
+# 快速发布脚本
+
+VERSION=$1
+ENV=$2
+
+if [ -z "$VERSION" ] || [ -z "$ENV" ]; then
+ echo "用法: ./quick-release.sh <版本号> <环境>"
+ echo "环境选项: dev/staging/prod"
+ exit 1
+fi
+
+case $ENV in
+ dev)
+ git checkout develop
+ git tag "v${VERSION}-dev"
+ git push gitea develop --tags
+ ;;
+ staging)
+ git checkout staging
+ git tag "v${VERSION}-staging"
+ git push staging staging:main --tags
+ ;;
+ prod)
+ git checkout main
+ git tag "v${VERSION}"
+ git push origin main --tags
+ ;;
+ *)
+ echo "无效的环境选项"
+ exit 1
+ ;;
+esac
+
+echo "✅ 发布完成: v${VERSION}-${ENV}"
+EOF
+
+chmod +x scripts/quick-release.sh
+
+# 7. 创建回滚脚本
+cat > scripts/rollback.sh << 'EOF'
+#!/bin/bash
+# 快速回滚脚本
+
+ENV=$1
+VERSION=$2
+
+if [ -z "$ENV" ] || [ -z "$VERSION" ]; then
+ echo "用法: ./rollback.sh <环境> <版本号>"
+ echo "环境选项: staging/prod"
+ exit 1
+fi
+
+case $ENV in
+ staging)
+ git checkout staging
+ git reset --hard "v${VERSION}-staging"
+ git push staging staging:main --force
+ ;;
+ prod)
+ git checkout main
+ git reset --hard "v${VERSION}"
+ git push origin main --force
+ ;;
+ *)
+ echo "无效的环境选项"
+ exit 1
+ ;;
+esac
+
+echo "✅ 回滚完成: ${ENV} -> v${VERSION}"
+EOF
+
+chmod +x scripts/rollback.sh
+
+# 8. 创建状态检查脚本
+cat > scripts/check-status.sh << 'EOF'
+#!/bin/bash
+# 环境状态检查脚本
+
+echo "📊 环境状态检查"
+echo "=================="
+
+# Git 状态
+echo "Git 状态:"
+git status --short
+
+echo ""
+
+# 远程仓库状态
+echo "远程仓库状态:"
+git remote -v
+
+echo ""
+
+# 分支状态
+echo "分支状态:"
+git branch -a
+
+echo ""
+
+# 最新标签
+echo "最新标签:"
+git tag --sort=-version:refname | head -5
+
+echo ""
+
+# 提交历史
+echo "最近提交:"
+git log --oneline -5
+EOF
+
+chmod +x scripts/check-status.sh
+
+# 9. 创建 GitHub Actions 工作流目录
+mkdir -p .github/workflows
+
+# 10. 创建部署验证
+echo "创建部署验证..."
+cat > .github/workflows/deploy-validation.yml << 'EOF'
+name: Deploy Validation
+
+on:
+ push:
+ branches: [develop, staging, main]
+
+jobs:
+ validate:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+
+ - name: Run tests
+ run: |
+ python -m pytest tests/ -v
+
+ - name: Validate code style
+ run: |
+ pip install black flake8
+ black --check .
+ flake8 .
+
+ - name: Security scan
+ run: |
+ pip install safety bandit
+ safety check
+ bandit -r . -f json -o security-report.json
+EOF
+
+echo "✅ 渐进发布环境配置完成!"
+echo ""
+echo "📋 使用指南:"
+echo "1. 查看状态: ./scripts/check-status.sh"
+echo "2. 快速发布: ./scripts/quick-release.sh 1.0.0 staging"
+echo "3. 紧急回滚: ./scripts/rollback.sh prod 1.0.0"
+echo "4. Git 别名: git deploy-staging, git deploy-prod"
+echo ""
+echo "📚 详细文档: docs/development/GRADUAL_DEPLOYMENT_PLAN.md"
\ No newline at end of file
diff --git a/modules/devops-tools/scripts/setup_venv.sh b/modules/devops-tools/scripts/setup_venv.sh
new file mode 100755
index 0000000..c833468
--- /dev/null
+++ b/modules/devops-tools/scripts/setup_venv.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+# 炼妖壶 (Lianyaohu) - 虚拟环境设置脚本
+# 用于快速初始化项目开发环境
+
+set -e # 遇到错误时退出
+
+echo "🔧 开始设置炼妖壶项目虚拟环境..."
+
+# 检查Python版本
+echo "📋 检查Python版本..."
+python3 --version
+
+# 创建虚拟环境(如果不存在)
+if [ ! -d "venv" ]; then
+ echo "🏗️ 创建虚拟环境..."
+ python3 -m venv venv
+else
+ echo "✅ 虚拟环境已存在"
+fi
+
+# 激活虚拟环境
+echo "🚀 激活虚拟环境..."
+source venv/bin/activate
+
+# 升级pip
+echo "⬆️ 升级pip..."
+pip install --upgrade pip
+
+# 安装项目依赖
+echo "📦 安装项目依赖..."
+pip install -r requirements.txt
+
+# 检查关键依赖
+echo "🔍 检查关键依赖安装状态..."
+echo " - streamlit: $(pip show streamlit | grep Version || echo '未安装')"
+echo " - openai: $(pip show openai | grep Version || echo '未安装')"
+echo " - google-cloud-aiplatform: $(pip show google-cloud-aiplatform | grep Version || echo '未安装')"
+echo " - aiohttp: $(pip show aiohttp | grep Version || echo '未安装')"
+
+echo "✨ 虚拟环境设置完成!"
+echo ""
+echo "📝 使用说明:"
+echo " 1. 激活虚拟环境: source venv/bin/activate"
+echo " 2. 运行辩论系统: python examples/debates/baxian_adk_gemini_debate.py"
+echo " 3. 启动Web界面: streamlit run app.py (如果有)"
+echo " 4. 退出虚拟环境: deactivate"
+echo ""
+echo "🔧 环境变量配置:"
+echo " 请确保 .env 文件中配置了必要的API密钥:"
+echo " - GOOGLE_API_KEY (Google Gemini API)"
+echo " - GOOGLE_CLOUD_PROJECT_ID (GCP项目ID)"
+echo " - GOOGLE_CLOUD_LOCATION (GCP区域)"
+echo ""
+echo "🎉 准备就绪!开始你的AI辩论之旅吧!"
\ No newline at end of file
diff --git a/modules/devops-tools/scripts/start_memory_bank_web.sh b/modules/devops-tools/scripts/start_memory_bank_web.sh
new file mode 100644
index 0000000..fc47b12
--- /dev/null
+++ b/modules/devops-tools/scripts/start_memory_bank_web.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+# Memory Bank Web界面启动脚本
+# 自动设置环境并启动Streamlit应用
+
+echo "🧠 启动Memory Bank Web界面..."
+echo "================================"
+
+# 检查是否在正确的目录
+if [ ! -f "memory_bank_web_interface.py" ]; then
+ echo "❌ 错误: 未找到memory_bank_web_interface.py文件"
+ echo "请确保在正确的项目目录中运行此脚本"
+ exit 1
+fi
+
+# 检查虚拟环境
+if [ ! -d "venv" ]; then
+ echo "📦 创建虚拟环境..."
+ python3 -m venv venv
+fi
+
+# 激活虚拟环境
+echo "🔧 激活虚拟环境..."
+source venv/bin/activate
+
+# 检查并安装依赖
+echo "📋 检查依赖包..."
+
+# 检查streamlit
+if ! python -c "import streamlit" 2>/dev/null; then
+ echo "📦 安装Streamlit..."
+ pip install streamlit
+fi
+
+# 检查Google Cloud依赖
+if ! python -c "import google.cloud" 2>/dev/null; then
+ echo "📦 安装Google Cloud依赖..."
+ pip install google-cloud-aiplatform google-generativeai
+fi
+
+# 检查其他必要依赖
+if ! python -c "import asyncio" 2>/dev/null; then
+ echo "📦 安装asyncio依赖..."
+ pip install asyncio
+fi
+
+# 检查Google Cloud认证
+echo "🔐 检查Google Cloud认证..."
+if ! gcloud auth application-default print-access-token >/dev/null 2>&1; then
+ echo "⚠️ 未检测到Google Cloud认证"
+ echo "正在启动认证流程..."
+ gcloud auth application-default login
+fi
+
+# 设置环境变量
+export GOOGLE_CLOUD_PROJECT="inner-radius-469712-e9"
+export GOOGLE_CLOUD_REGION="us-central1"
+
+# 启动Streamlit应用
+echo "🚀 启动Web界面..."
+echo "================================"
+echo "📱 Web界面将在浏览器中打开"
+echo "🌐 默认地址: http://localhost:8501"
+echo "⏹️ 按 Ctrl+C 停止服务"
+echo "================================"
+
+# 启动streamlit
+streamlit run memory_bank_web_interface.py --server.port 8501 --server.address localhost
\ No newline at end of file
diff --git a/modules/devops-tools/scripts/validate_doc_lifecycle.py b/modules/devops-tools/scripts/validate_doc_lifecycle.py
new file mode 100644
index 0000000..d887357
--- /dev/null
+++ b/modules/devops-tools/scripts/validate_doc_lifecycle.py
@@ -0,0 +1,137 @@
+import glob
+import frontmatter
+import datetime
+import argparse
+from pathlib import Path
+
+# --- Configuration ---
+# Directories to exclude from scanning
+EXCLUDE_DIRS = ['venv', 'node_modules', '.git']
+# Default metadata template for the --fix option
+DEFAULT_METADATA_TEMPLATE = {
+ 'title': "Default Title",
+ 'status': "spring",
+ 'owner': "TBD",
+ 'created': datetime.date.today().strftime('%Y-%m-%d'),
+ 'review_by': (datetime.date.today() + datetime.timedelta(days=180)).strftime('%Y-%m-%d'),
+ 'tags': ["untagged"]
+}
+
+def get_project_files(project_root):
+ """Get all markdown files, respecting exclusions."""
+ all_files = project_root.rglob('*.md')
+ filtered_files = []
+ for file_path in all_files:
+ if not any(excluded_dir in file_path.parts for excluded_dir in EXCLUDE_DIRS):
+ filtered_files.append(str(file_path))
+ return filtered_files
+
+def add_default_frontmatter(file_path):
+ """Adds a default YAML front matter block to a file that lacks one."""
+ try:
+ with open(file_path, 'r+', encoding='utf-8') as f:
+ content = f.read()
+ f.seek(0, 0)
+
+ # Create a new post object with default metadata and existing content
+ new_post = frontmatter.Post(content, **DEFAULT_METADATA_TEMPLATE)
+
+ # Write the serialized post (metadata + content) back to the file
+ f.write(frontmatter.dumps(new_post))
+ print(f"[FIXED] {file_path}: Added default front matter.")
+ return True
+ except Exception as e:
+ print(f"[CRITICAL] {file_path}: Could not apply fix. Error: {e}")
+ return False
+
+def validate_doc_lifecycle(fix_missing=False):
+ """
+ Scans and validates markdown files, with an option to fix files missing front matter.
+ """
+ project_root = Path(__file__).parent.parent
+ markdown_files = get_project_files(project_root)
+
+ print(f"Scanning {len(markdown_files)} Markdown files (vendor directories excluded)...")
+
+ all_docs = []
+ errors = []
+ warnings = []
+ fixed_count = 0
+
+ for md_file in markdown_files:
+ try:
+ post = frontmatter.load(md_file)
+ metadata = post.metadata
+
+ if not metadata:
+ if fix_missing:
+ if add_default_frontmatter(md_file):
+ fixed_count += 1
+ else:
+ warnings.append(f"[SKIPPED] {md_file}: No YAML front matter found. Use --fix to add a template.")
+ continue
+
+ doc_info = {'path': md_file}
+
+ required_fields = ['title', 'status', 'owner', 'created', 'review_by']
+ missing_fields = [field for field in required_fields if field not in metadata]
+ if missing_fields:
+ errors.append(f"[ERROR] {md_file}: Missing required fields: {', '.join(missing_fields)}")
+ continue
+
+ doc_info.update(metadata)
+
+ allowed_statuses = ['spring', 'summer', 'autumn', 'winter']
+ if metadata.get('status') not in allowed_statuses:
+ errors.append(f"[ERROR] {md_file}: Invalid status '{metadata.get('status')}'. Must be one of {allowed_statuses}")
+
+ review_by_date = metadata.get('review_by')
+ if review_by_date:
+ if isinstance(review_by_date, str):
+ review_by_date = datetime.datetime.strptime(review_by_date, '%Y-%m-%d').date()
+
+ if review_by_date < datetime.date.today():
+ warnings.append(f"[WARNING] {md_file}: Review date ({review_by_date}) has passed.")
+
+ all_docs.append(doc_info)
+
+ except Exception as e:
+ errors.append(f"[CRITICAL] {md_file}: Could not parse file. Error: {e}")
+
+ print("\n--- Validation Report ---")
+
+ if not errors and not warnings:
+ print("✅ All documents with front matter are valid and up-to-date.")
+
+ if warnings:
+ print("\n⚠️ Warnings:")
+ for warning in warnings:
+ print(warning)
+
+ if errors:
+ print("\n❌ Errors:")
+ for error in errors:
+ print(error)
+
+ print(f"\n--- Summary ---")
+ print(f"Total files scanned: {len(markdown_files)}")
+ print(f"Files with valid front matter: {len(all_docs)}")
+ if fix_missing:
+ print(f"Files automatically fixed: {fixed_count}")
+ print(f"Warnings: {len(warnings)}")
+ print(f"Errors: {len(errors)}")
+
+ return len(errors) == 0
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Validate and manage the lifecycle of Markdown documents.")
+ parser.add_argument(
+ '--fix',
+ action='store_true',
+ help="Automatically add a default front matter template to any document that is missing one."
+ )
+ args = parser.parse_args()
+
+ is_valid = validate_doc_lifecycle(fix_missing=args.fix)
+ if not is_valid:
+ exit(1)
\ No newline at end of file
diff --git a/modules/devops-tools/tools/cloudflare/query-shushu-book.js b/modules/devops-tools/tools/cloudflare/query-shushu-book.js
new file mode 100644
index 0000000..3fd5e92
--- /dev/null
+++ b/modules/devops-tools/tools/cloudflare/query-shushu-book.js
@@ -0,0 +1,138 @@
+// 查询术数书内容的脚本
+// 通过 Hyperdrive API 查询 NeonDB 中的术数书数据
+
+const API_BASE_URL = 'https://hyperdrive.seekkey.tech';
+
+// 通用请求函数
+async function apiRequest(endpoint, options = {}) {
+ const url = `${API_BASE_URL}${endpoint}`;
+ const headers = {
+ 'Content-Type': 'application/json',
+ ...options.headers
+ };
+
+ try {
+ const response = await fetch(url, {
+ ...options,
+ headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const contentType = response.headers.get('content-type');
+ if (contentType && contentType.includes('application/json')) {
+ return await response.json();
+ } else {
+ return await response.text();
+ }
+ } catch (error) {
+ console.error(`Request failed for ${endpoint}:`, error.message);
+ throw error;
+ }
+}
+
+// 查询数据库表结构
+async function queryTables() {
+ console.log('\n📋 查询数据库表结构...');
+ try {
+ const result = await apiRequest('/query-tables');
+ console.log('✅ 数据库表:', result);
+ return result;
+ } catch (error) {
+ console.log('❌ 查询表结构失败:', error.message);
+ return null;
+ }
+}
+
+// 查询术数书内容
+async function queryShushuBook(limit = 10) {
+ console.log('\n📚 查询术数书内容...');
+ try {
+ const result = await apiRequest(`/query-shushu?limit=${limit}`);
+ console.log('✅ 术数书内容:', JSON.stringify(result, null, 2));
+ return result;
+ } catch (error) {
+ console.log('❌ 查询术数书失败:', error.message);
+ return null;
+ }
+}
+
+// 搜索术数书内容
+async function searchShushuBook(keyword, limit = 5) {
+ console.log(`\n🔍 搜索术数书内容: "${keyword}"...`);
+ try {
+ const result = await apiRequest(`/search-shushu?q=${encodeURIComponent(keyword)}&limit=${limit}`);
+ console.log('✅ 搜索结果:', JSON.stringify(result, null, 2));
+ return result;
+ } catch (error) {
+ console.log('❌ 搜索失败:', error.message);
+ return null;
+ }
+}
+
+// 获取术数书统计信息
+async function getShushuStats() {
+ console.log('\n📊 获取术数书统计信息...');
+ try {
+ const result = await apiRequest('/shushu-stats');
+ console.log('✅ 统计信息:', JSON.stringify(result, null, 2));
+ return result;
+ } catch (error) {
+ console.log('❌ 获取统计信息失败:', error.message);
+ return null;
+ }
+}
+
+// 主函数
+async function main() {
+ console.log('🚀 术数书查询脚本');
+ console.log('==================');
+
+ // 首先测试连接
+ console.log('\n🔗 测试 Hyperdrive 连接...');
+ try {
+ const connectionTest = await apiRequest('/test-connection');
+ console.log('✅ 连接成功:', connectionTest.message);
+ } catch (error) {
+ console.log('❌ 连接失败:', error.message);
+ return;
+ }
+
+ // 查询表结构
+ await queryTables();
+
+ // 获取统计信息
+ await getShushuStats();
+
+ // 查询术数书内容
+ await queryShushuBook(5);
+
+ // 搜索示例
+ await searchShushuBook('易经');
+ await searchShushuBook('八卦');
+ await searchShushuBook('太公');
+}
+
+// 如果是 Node.js 环境,导入 fetch
+if (typeof window === 'undefined') {
+ // Node.js 环境
+ const { default: fetch } = require('node-fetch');
+ global.fetch = fetch;
+ main().catch(console.error);
+} else {
+ // 浏览器环境
+ console.log('在浏览器控制台中运行: main()');
+}
+
+// 导出函数供其他模块使用
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = {
+ queryTables,
+ queryShushuBook,
+ searchShushuBook,
+ getShushuStats,
+ main
+ };
+}
\ No newline at end of file
diff --git a/modules/devops-tools/tools/cloudflare/validate-config.js b/modules/devops-tools/tools/cloudflare/validate-config.js
new file mode 100644
index 0000000..e1298cc
--- /dev/null
+++ b/modules/devops-tools/tools/cloudflare/validate-config.js
@@ -0,0 +1,107 @@
+// Simple configuration validation script
+// This validates the wrangler.toml and Worker code without requiring API access
+
+const fs = require('fs');
+const path = require('path');
+
+console.log('🔍 Validating Hyperdrive Configuration Files');
+console.log('============================================');
+
+// Check wrangler.toml
+console.log('\n📋 Checking wrangler.toml...');
+try {
+ const wranglerContent = fs.readFileSync('wrangler.toml', 'utf8');
+ console.log('✅ wrangler.toml exists');
+
+ // Check for required fields
+ const checks = [
+ { field: 'name', regex: /name\s*=\s*["']([^"']+)["']/, required: true },
+ { field: 'main', regex: /main\s*=\s*["']([^"']+)["']/, required: true },
+ { field: 'compatibility_date', regex: /compatibility_date\s*=\s*["']([^"']+)["']/, required: true },
+ { field: 'nodejs_compat', regex: /nodejs_compat/, required: true },
+ { field: 'hyperdrive binding', regex: /binding\s*=\s*["']HYPERDRIVE["']/, required: true },
+ { field: 'hyperdrive id', regex: /id\s*=\s*["']ef43924d89064cddabfaccf06aadfab6["']/, required: true }
+ ];
+
+ checks.forEach(check => {
+ if (check.regex.test(wranglerContent)) {
+ console.log(` ✅ ${check.field} configured`);
+ } else {
+ console.log(` ❌ ${check.field} missing or incorrect`);
+ }
+ });
+
+} catch (error) {
+ console.log('❌ wrangler.toml not found or unreadable');
+}
+
+// Check Worker code
+console.log('\n📝 Checking Worker code...');
+try {
+ const workerContent = fs.readFileSync('src/index.ts', 'utf8');
+ console.log('✅ src/index.ts exists');
+
+ const codeChecks = [
+ { name: 'Hyperdrive binding usage', regex: /env\.HYPERDRIVE/ },
+ { name: 'Test connection endpoint', regex: /\/test-connection/ },
+ { name: 'Test query endpoint', regex: /\/test-query/ },
+ { name: 'PostgreSQL import', regex: /pg/ },
+ { name: 'Error handling', regex: /try\s*{[\s\S]*catch/ }
+ ];
+
+ codeChecks.forEach(check => {
+ if (check.regex.test(workerContent)) {
+ console.log(` ✅ ${check.name} implemented`);
+ } else {
+ console.log(` ⚠️ ${check.name} not found`);
+ }
+ });
+
+} catch (error) {
+ console.log('❌ src/index.ts not found or unreadable');
+}
+
+// Check package.json
+console.log('\n📦 Checking package.json...');
+try {
+ const packageContent = fs.readFileSync('package.json', 'utf8');
+ const packageJson = JSON.parse(packageContent);
+ console.log('✅ package.json exists and is valid JSON');
+
+ const deps = {
+ 'pg': packageJson.dependencies?.pg,
+ '@cloudflare/workers-types': packageJson.devDependencies?.['@cloudflare/workers-types'],
+ '@types/pg': packageJson.devDependencies?.['@types/pg'],
+ 'typescript': packageJson.devDependencies?.typescript,
+ 'wrangler': packageJson.devDependencies?.wrangler
+ };
+
+ Object.entries(deps).forEach(([dep, version]) => {
+ if (version) {
+ console.log(` ✅ ${dep}: ${version}`);
+ } else {
+ console.log(` ❌ ${dep}: not found`);
+ }
+ });
+
+} catch (error) {
+ console.log('❌ package.json not found or invalid JSON');
+}
+
+console.log('\n📊 Configuration Summary:');
+console.log(' - Project: hyperdrive-neondb-test');
+console.log(' - Hyperdrive ID: ef43924d89064cddabfaccf06aadfab6');
+console.log(' - Database: NeonDB (PostgreSQL)');
+console.log(' - Binding: HYPERDRIVE');
+console.log(' - Compatibility: nodejs_compat enabled');
+
+console.log('\n🚀 Next Steps:');
+console.log(' 1. Ensure you have proper Cloudflare API permissions');
+console.log(' 2. Verify the Hyperdrive configuration exists in your Cloudflare dashboard');
+console.log(' 3. Deploy with: wrangler deploy');
+console.log(' 4. Test endpoints after deployment');
+
+console.log('\n💡 Troubleshooting:');
+console.log(' - If API token has insufficient permissions, use: wrangler login');
+console.log(' - Check Hyperdrive exists: https://dash.cloudflare.com/[account-id]/workers/hyperdrive');
+console.log(' - Verify NeonDB connection string is correct in Hyperdrive config');
\ No newline at end of file
diff --git a/modules/devops-tools/tools/cloudflare/wrangler.toml b/modules/devops-tools/tools/cloudflare/wrangler.toml
new file mode 100644
index 0000000..eccd252
--- /dev/null
+++ b/modules/devops-tools/tools/cloudflare/wrangler.toml
@@ -0,0 +1,16 @@
+name = "hyperdrive-neondb-test"
+main = "src/index.ts"
+compatibility_date = "2025-02-04"
+
+# Add nodejs_compat compatibility flag to support common database drivers
+compatibility_flags = ["nodejs_compat"]
+
+[observability]
+enabled = true
+
+# Hyperdrive configuration for NeonDB
+[[hyperdrive]]
+binding = "HYPERDRIVE"
+id = "ef43924d89064cddabfaccf06aadfab6"
+# For local development, use a local PostgreSQL connection
+localConnectionString = "postgresql://postgres:password@localhost:5432/testdb"
diff --git a/modules/devops-tools/tools/memory_bank/detailed_memory_bank_info.py b/modules/devops-tools/tools/memory_bank/detailed_memory_bank_info.py
new file mode 100644
index 0000000..8ce0aba
--- /dev/null
+++ b/modules/devops-tools/tools/memory_bank/detailed_memory_bank_info.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python3
+"""
+详细查看和测试Vertex AI Memory Bank功能
+"""
+
+import sys
+import os
+import asyncio
+import json
+from datetime import datetime
+sys.path.append('src')
+
+from jixia.memory.factory import get_memory_backend
+from config.doppler_config import get_google_genai_config
+
+async def test_memory_bank_functionality():
+ print("🧠 详细测试Memory Bank功能")
+ print("=" * 60)
+
+ # 获取配置
+ config = get_google_genai_config()
+ project_id = config.get('project_id')
+ location = config.get('location', 'us-central1')
+
+ print(f"📊 项目ID: {project_id}")
+ print(f"📍 位置: {location}")
+ print(f"🕐 测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+ print()
+
+ try:
+ # 获取Memory Bank后端
+ memory_backend = get_memory_backend()
+ print(f"✅ Memory Bank后端: {type(memory_backend).__name__}")
+ print()
+
+ # 选择一个智能体进行详细测试
+ test_agent = "lvdongbin"
+ print(f"🧙♂️ 测试智能体: {test_agent} (吕洞宾)")
+ print("-" * 40)
+
+ # 1. 创建/获取Memory Bank
+ print("1️⃣ 创建Memory Bank...")
+ memory_bank_id = await memory_backend.create_memory_bank(
+ agent_name=test_agent,
+ display_name=f"测试Memory Bank - {test_agent}"
+ )
+ print(f" ✅ Memory Bank ID: {memory_bank_id}")
+ print()
+
+ # 2. 添加不同类型的记忆
+ print("2️⃣ 添加测试记忆...")
+
+ # 添加对话记忆
+ conversation_memory = await memory_backend.add_memory(
+ agent_name=test_agent,
+ content="在关于AI伦理的辩论中,我强调了技术发展应该以人为本,不能忽视道德考量。",
+ memory_type="conversation",
+ debate_topic="AI伦理与技术发展",
+ metadata={"opponent": "铁拐李", "stance": "支持伦理优先"}
+ )
+ print(f" 📝 对话记忆: {conversation_memory}")
+
+ # 添加偏好记忆
+ preference_memory = await memory_backend.add_memory(
+ agent_name=test_agent,
+ content="我偏好使用古典哲学的智慧来论证现代问题,特别是道家思想。",
+ memory_type="preference",
+ metadata={"philosophy": "道家", "style": "古典智慧"}
+ )
+ print(f" ⚙️ 偏好记忆: {preference_memory}")
+
+ # 添加知识记忆
+ knowledge_memory = await memory_backend.add_memory(
+ agent_name=test_agent,
+ content="区块链技术的核心是去中心化和不可篡改性,这与道家'无为而治'的理念有相通之处。",
+ memory_type="knowledge",
+ debate_topic="区块链技术应用",
+ metadata={"domain": "技术", "connection": "哲学"}
+ )
+ print(f" 📚 知识记忆: {knowledge_memory}")
+
+ # 添加策略记忆
+ strategy_memory = await memory_backend.add_memory(
+ agent_name=test_agent,
+ content="在辩论中,当对手使用激进论点时,我会用温和的反问来引导思考,而不是直接对抗。",
+ memory_type="strategy",
+ metadata={"tactic": "温和引导", "effectiveness": "高"}
+ )
+ print(f" 🎯 策略记忆: {strategy_memory}")
+ print()
+
+ # 3. 测试记忆搜索
+ print("3️⃣ 测试记忆搜索...")
+
+ # 搜索关于AI的记忆
+ ai_memories = await memory_backend.search_memories(
+ agent_name=test_agent,
+ query="AI 人工智能 伦理",
+ limit=5
+ )
+ print(f" 🔍 搜索'AI 人工智能 伦理': 找到 {len(ai_memories)} 条记忆")
+ for i, memory in enumerate(ai_memories, 1):
+ print(f" {i}. {memory.get('content', '')[:50]}...")
+ print()
+
+ # 搜索策略相关记忆
+ strategy_memories = await memory_backend.search_memories(
+ agent_name=test_agent,
+ query="辩论 策略",
+ memory_type="strategy",
+ limit=3
+ )
+ print(f" 🎯 搜索策略记忆: 找到 {len(strategy_memories)} 条记忆")
+ for i, memory in enumerate(strategy_memories, 1):
+ print(f" {i}. {memory.get('content', '')[:50]}...")
+ print()
+
+ # 4. 获取智能体上下文
+ print("4️⃣ 获取智能体上下文...")
+ context = await memory_backend.get_agent_context(
+ agent_name=test_agent,
+ debate_topic="AI伦理与技术发展"
+ )
+ print(f" 📋 上下文长度: {len(context)} 字符")
+ print(f" 📋 上下文预览: {context[:200]}...")
+ print()
+
+ # 5. 显示所有记忆类型的统计
+ print("5️⃣ 记忆统计...")
+ memory_types = ["conversation", "preference", "knowledge", "strategy"]
+ for mem_type in memory_types:
+ memories = await memory_backend.search_memories(
+ agent_name=test_agent,
+ query="",
+ memory_type=mem_type,
+ limit=100
+ )
+ print(f" 📊 {mem_type}: {len(memories)} 条记忆")
+
+ print()
+ print("🎉 Memory Bank功能测试完成!")
+ print("=" * 60)
+
+ except Exception as e:
+ print(f"❌ 测试失败: {e}")
+ import traceback
+ traceback.print_exc()
+
+if __name__ == "__main__":
+ asyncio.run(test_memory_bank_functionality())
\ No newline at end of file
diff --git a/modules/devops-tools/tools/memory_bank/list_memory_banks.py b/modules/devops-tools/tools/memory_bank/list_memory_banks.py
new file mode 100644
index 0000000..fd916df
--- /dev/null
+++ b/modules/devops-tools/tools/memory_bank/list_memory_banks.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+"""
+使用项目现有的Memory Bank代码来查看实例
+"""
+
+import sys
+import os
+import asyncio
+sys.path.append('src')
+
+from jixia.memory.factory import get_memory_backend
+from config.doppler_config import get_google_genai_config
+
+async def list_memory_banks():
+ """使用项目的Memory Bank工厂来查看实例"""
+
+ print("🧠 使用项目Memory Bank工厂查看实例")
+ print("="*50)
+
+ try:
+ # 获取配置
+ config = get_google_genai_config()
+ print(f"📊 项目ID: {config.get('project_id')}")
+ print(f"📍 位置: {config.get('location')}")
+ print(f"🔑 Memory Bank启用: {config.get('memory_bank_enabled')}")
+
+ # 获取Memory Bank后端
+ print("\n🔍 正在获取Memory Bank后端...")
+ memory_backend = get_memory_backend()
+ print(f"✅ 成功获取Memory Bank后端: {type(memory_backend).__name__}")
+
+ # 八仙列表
+ immortals = [
+ "tieguaili", "zhongliquan", "lvdongbin", "hehe_erxian",
+ "lantsaihe", "hanxiangzi", "caoguo_jiu", "hexiangu"
+ ]
+
+ print(f"\n🔍 正在检查八仙的Memory Bank实例...")
+ print("="*50)
+
+ for immortal in immortals:
+ try:
+ print(f"\n🧙♂️ {immortal}:")
+
+ # 尝试创建Memory Bank
+ memory_bank_id = await memory_backend.create_memory_bank(immortal)
+ print(f" ✅ Memory Bank ID: {memory_bank_id}")
+
+ # 尝试搜索一些记忆(如果有的话)
+ try:
+ memories = await memory_backend.search_memories(immortal, "投资", limit=3)
+ if memories:
+ print(f" 📝 找到 {len(memories)} 条记忆")
+ for i, memory in enumerate(memories[:2], 1):
+ content = memory.get('content', '无内容')[:50]
+ print(f" {i}. {content}...")
+ else:
+ print(f" 📭 暂无记忆")
+ except Exception as e:
+ print(f" ⚠️ 无法搜索记忆: {str(e)[:50]}...")
+
+ except Exception as e:
+ print(f" ❌ 错误: {str(e)[:50]}...")
+
+ print(f"\n🎉 Memory Bank检查完成!")
+
+ except Exception as e:
+ print(f"\n❌ 主要错误: {str(e)}")
+ print(f"🔧 错误类型: {type(e).__name__}")
+
+ # 显示一些调试信息
+ print("\n🔍 调试信息:")
+ print(f" Python路径: {sys.path[:3]}...")
+ print(f" 当前目录: {os.getcwd()}")
+ print(f" 环境变量:")
+ for key in ['GOOGLE_API_KEY', 'GOOGLE_CLOUD_PROJECT_ID', 'VERTEX_MEMORY_BANK_ENABLED']:
+ value = os.getenv(key, '未设置')
+ if 'API_KEY' in key and value != '未设置':
+ value = value[:10] + '...' if len(value) > 10 else value
+ print(f" {key}: {value}")
+
+if __name__ == "__main__":
+ asyncio.run(list_memory_banks())
\ No newline at end of file
diff --git a/modules/devops-tools/tools/memory_bank/memory_bank_web_interface.py b/modules/devops-tools/tools/memory_bank/memory_bank_web_interface.py
new file mode 100644
index 0000000..443e1a0
--- /dev/null
+++ b/modules/devops-tools/tools/memory_bank/memory_bank_web_interface.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python3
+"""
+Vertex AI Memory Bank Web界面
+一个简单的Streamlit应用,用于通过Web界面访问和管理Memory Bank
+"""
+
+import streamlit as st
+import asyncio
+import sys
+import os
+from datetime import datetime
+
+# 添加项目路径
+sys.path.append('/Users/ben/liurenchaxin/src')
+
+try:
+ from jixia.memory.factory import get_memory_backend
+except ImportError as e:
+ st.error(f"无法导入jixia模块: {e}")
+ st.info("请确保已激活虚拟环境并安装了所需依赖")
+ st.stop()
+
+# 页面配置
+st.set_page_config(
+ page_title="Memory Bank 管理界面",
+ page_icon="🧠",
+ layout="wide"
+)
+
+# 标题
+st.title("🧠 Vertex AI Memory Bank 管理界面")
+st.markdown("---")
+
+# 侧边栏配置
+st.sidebar.header("配置")
+project_id = st.sidebar.text_input("项目ID", value="inner-radius-469712-e9")
+location = st.sidebar.text_input("区域", value="us-central1")
+
+# 八仙列表
+EIGHT_IMMORTALS = [
+ "lvdongbin", "tieguaili", "hanxiangzi", "lanzaihe",
+ "hesengu", "zhonghanli", "caogujiu", "hanzhongli"
+]
+
+# 缓存Memory Bank后端
+@st.cache_resource
+def get_memory_backend_cached():
+ """获取Memory Bank后端(缓存)"""
+ try:
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ backend = loop.run_until_complete(get_memory_backend("vertex"))
+ return backend, loop
+ except Exception as e:
+ st.error(f"初始化Memory Bank失败: {e}")
+ return None, None
+
+# 异步函数包装器
+def run_async(coro):
+ """运行异步函数"""
+ backend, loop = get_memory_backend_cached()
+ if backend is None:
+ return None
+ try:
+ return loop.run_until_complete(coro)
+ except Exception as e:
+ st.error(f"操作失败: {e}")
+ return None
+
+# 主界面
+tab1, tab2, tab3, tab4 = st.tabs(["📋 Memory Bank列表", "🔍 搜索记忆", "➕ 添加记忆", "📊 统计信息"])
+
+with tab1:
+ st.header("Memory Bank 实例列表")
+
+ if st.button("🔄 刷新列表", key="refresh_list"):
+ st.rerun()
+
+ # 显示八仙Memory Bank状态
+ cols = st.columns(4)
+ for i, immortal in enumerate(EIGHT_IMMORTALS):
+ with cols[i % 4]:
+ with st.container():
+ st.subheader(f"🧙♂️ {immortal}")
+
+ # 检查Memory Bank状态
+ backend, _ = get_memory_backend_cached()
+ if backend:
+ try:
+ # 尝试获取agent context来验证Memory Bank存在
+ context = run_async(backend.get_agent_context(immortal))
+ if context is not None:
+ st.success("✅ 活跃")
+
+ # 显示记忆数量
+ memories = run_async(backend.search_memories(immortal, "", limit=100))
+ if memories:
+ st.info(f"📝 记忆数量: {len(memories)}")
+ else:
+ st.info("📝 记忆数量: 0")
+ else:
+ st.warning("⚠️ 未初始化")
+ except Exception as e:
+ st.error(f"❌ 错误: {str(e)[:50]}...")
+ else:
+ st.error("❌ 连接失败")
+
+with tab2:
+ st.header("🔍 搜索记忆")
+
+ col1, col2 = st.columns([1, 2])
+
+ with col1:
+ selected_agent = st.selectbox("选择Agent", EIGHT_IMMORTALS, key="search_agent")
+ search_query = st.text_input("搜索关键词", placeholder="输入要搜索的内容...", key="search_query")
+ search_limit = st.slider("结果数量", 1, 50, 10, key="search_limit")
+
+ if st.button("🔍 搜索", key="search_button"):
+ if search_query:
+ with st.spinner("搜索中..."):
+ backend, _ = get_memory_backend_cached()
+ if backend:
+ memories = run_async(backend.search_memories(selected_agent, search_query, limit=search_limit))
+ st.session_state['search_results'] = memories
+ st.session_state['search_agent'] = selected_agent
+ st.session_state['search_query'] = search_query
+ else:
+ st.warning("请输入搜索关键词")
+
+ with col2:
+ st.subheader("搜索结果")
+
+ if 'search_results' in st.session_state and st.session_state['search_results']:
+ st.success(f"找到 {len(st.session_state['search_results'])} 条记忆")
+
+ for i, memory in enumerate(st.session_state['search_results']):
+ with st.expander(f"记忆 {i+1}: {memory.get('content', 'N/A')[:50]}..."):
+ st.write(f"**内容**: {memory.get('content', 'N/A')}")
+ st.write(f"**类型**: {memory.get('memory_type', 'N/A')}")
+ st.write(f"**时间**: {memory.get('timestamp', 'N/A')}")
+ if 'metadata' in memory:
+ st.write(f"**元数据**: {memory['metadata']}")
+ elif 'search_results' in st.session_state:
+ st.info("未找到匹配的记忆")
+ else:
+ st.info("请执行搜索以查看结果")
+
+with tab3:
+ st.header("➕ 添加记忆")
+
+ col1, col2 = st.columns([1, 1])
+
+ with col1:
+ add_agent = st.selectbox("选择Agent", EIGHT_IMMORTALS, key="add_agent")
+ memory_type = st.selectbox("记忆类型", ["conversation", "preference", "knowledge", "strategy"], key="memory_type")
+ memory_content = st.text_area("记忆内容", placeholder="输入要添加的记忆内容...", height=150, key="memory_content")
+
+ # 可选的元数据
+ st.subheader("元数据(可选)")
+ importance = st.slider("重要性", 1, 10, 5, key="importance")
+ tags = st.text_input("标签(用逗号分隔)", placeholder="标签1, 标签2, 标签3", key="tags")
+
+ if st.button("➕ 添加记忆", key="add_memory_button"):
+ if memory_content:
+ with st.spinner("添加记忆中..."):
+ backend, _ = get_memory_backend_cached()
+ if backend:
+ # 准备元数据
+ metadata = {
+ "importance": importance,
+ "timestamp": datetime.now().isoformat(),
+ "source": "web_interface"
+ }
+ if tags:
+ metadata["tags"] = [tag.strip() for tag in tags.split(",")]
+
+ # 添加记忆
+ success = run_async(backend.add_memory(
+ agent_id=add_agent,
+ content=memory_content,
+ memory_type=memory_type,
+ metadata=metadata
+ ))
+
+ if success:
+ st.success("✅ 记忆添加成功!")
+ # 清空输入
+ st.session_state['memory_content'] = ""
+ st.session_state['tags'] = ""
+ else:
+ st.error("❌ 添加记忆失败")
+ else:
+ st.warning("请输入记忆内容")
+
+ with col2:
+ st.subheader("添加记忆预览")
+ if memory_content:
+ st.info(f"**Agent**: {add_agent}")
+ st.info(f"**类型**: {memory_type}")
+ st.info(f"**内容**: {memory_content}")
+ st.info(f"**重要性**: {importance}/10")
+ if tags:
+ st.info(f"**标签**: {tags}")
+ else:
+ st.info("输入记忆内容以查看预览")
+
+with tab4:
+ st.header("📊 统计信息")
+
+ if st.button("🔄 刷新统计", key="refresh_stats"):
+ st.rerun()
+
+ # 获取统计信息
+ backend, _ = get_memory_backend_cached()
+ if backend:
+ stats_data = []
+
+ for immortal in EIGHT_IMMORTALS:
+ try:
+ # 获取记忆数量
+ memories = run_async(backend.search_memories(immortal, "", limit=1000))
+ memory_count = len(memories) if memories else 0
+
+ # 获取agent context
+ context = run_async(backend.get_agent_context(immortal))
+ status = "活跃" if context else "未初始化"
+
+ stats_data.append({
+ "Agent": immortal,
+ "状态": status,
+ "记忆数量": memory_count,
+ "最后更新": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ })
+ except Exception as e:
+ stats_data.append({
+ "Agent": immortal,
+ "状态": "错误",
+ "记忆数量": 0,
+ "最后更新": f"错误: {str(e)[:30]}..."
+ })
+
+ # 显示统计表格
+ st.dataframe(stats_data, use_container_width=True)
+
+ # 显示汇总信息
+ col1, col2, col3, col4 = st.columns(4)
+
+ total_agents = len(EIGHT_IMMORTALS)
+ active_agents = sum(1 for item in stats_data if item["状态"] == "活跃")
+ total_memories = sum(item["记忆数量"] for item in stats_data)
+ avg_memories = total_memories / total_agents if total_agents > 0 else 0
+
+ with col1:
+ st.metric("总Agent数", total_agents)
+
+ with col2:
+ st.metric("活跃Agent数", active_agents)
+
+ with col3:
+ st.metric("总记忆数", total_memories)
+
+ with col4:
+ st.metric("平均记忆数", f"{avg_memories:.1f}")
+
+# 页脚
+st.markdown("---")
+st.markdown(
+ """
+
+ 🧠 Vertex AI Memory Bank Web界面 |
+
官方文档
+
+ """,
+ unsafe_allow_html=True
+)
+
+# 使用说明
+with st.expander("📖 使用说明"):
+ st.markdown("""
+ ### 功能说明
+
+ 1. **Memory Bank列表**: 查看所有八仙角色的Memory Bank状态和记忆数量
+ 2. **搜索记忆**: 在指定Agent的记忆中搜索特定内容
+ 3. **添加记忆**: 为Agent添加新的记忆,支持不同类型和元数据
+ 4. **统计信息**: 查看所有Agent的统计数据和汇总信息
+
+ ### 使用前准备
+
+ 1. 确保已激活虚拟环境: `source venv/bin/activate`
+ 2. 确保已设置Google Cloud认证: `gcloud auth application-default login`
+ 3. 运行此界面: `streamlit run memory_bank_web_interface.py`
+
+ ### 注意事项
+
+ - Memory Bank目前仅在us-central1区域可用
+ - 搜索功能支持模糊匹配
+ - 添加的记忆会立即生效
+ - 统计信息实时更新
+ """)
\ No newline at end of file
diff --git a/modules/devops-tools/tools/memory_bank/view_memory_banks_gcp.py b/modules/devops-tools/tools/memory_bank/view_memory_banks_gcp.py
new file mode 100644
index 0000000..e688f75
--- /dev/null
+++ b/modules/devops-tools/tools/memory_bank/view_memory_banks_gcp.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+"""
+通过Google Cloud Console查看Memory Bank资源
+"""
+
+import sys
+import os
+import asyncio
+import json
+import subprocess
+from datetime import datetime
+sys.path.append('src')
+
+from config.doppler_config import get_google_genai_config
+
+def get_access_token():
+ """获取Google Cloud访问令牌"""
+ try:
+ result = subprocess.run(
+ ['gcloud', 'auth', 'print-access-token'],
+ capture_output=True,
+ text=True,
+ check=True
+ )
+ return result.stdout.strip()
+ except subprocess.CalledProcessError as e:
+ print(f"❌ 获取访问令牌失败: {e}")
+ return None
+
+def make_api_request(url, token):
+ """发起API请求"""
+ import requests
+
+ headers = {
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ return response.status_code, response.json() if response.content else {}
+ except Exception as e:
+ return None, str(e)
+
+def main():
+ print("🔍 通过GCP API查看Memory Bank资源")
+ print("=" * 60)
+
+ # 获取配置
+ config = get_google_genai_config()
+ project_id = config.get('project_id')
+ location = config.get('location', 'us-central1')
+
+ print(f"📊 项目ID: {project_id}")
+ print(f"📍 位置: {location}")
+ print(f"🕐 查询时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+ print()
+
+ # 获取访问令牌
+ print("🔑 获取访问令牌...")
+ token = get_access_token()
+ if not token:
+ print("❌ 无法获取访问令牌")
+ return
+ print(f"✅ 访问令牌: {token[:20]}...")
+ print()
+
+ # 尝试不同的API端点
+ api_endpoints = [
+ # Vertex AI API
+ f"https://aiplatform.googleapis.com/v1/projects/{project_id}/locations/{location}/operations",
+ f"https://aiplatform.googleapis.com/v1beta1/projects/{project_id}/locations/{location}/operations",
+
+ # Generative Language API
+ f"https://generativelanguage.googleapis.com/v1beta/projects/{project_id}/locations/{location}/operations",
+
+ # 尝试Memory Bank相关端点
+ f"https://aiplatform.googleapis.com/v1/projects/{project_id}/locations/{location}/memoryBanks",
+ f"https://aiplatform.googleapis.com/v1beta1/projects/{project_id}/locations/{location}/memoryBanks",
+
+ # 尝试其他可能的端点
+ f"https://generativelanguage.googleapis.com/v1beta/projects/{project_id}/locations/{location}/memoryBanks",
+ f"https://generativelanguage.googleapis.com/v1/projects/{project_id}/locations/{location}/memoryBanks",
+ ]
+
+ print("🌐 测试API端点...")
+ print("-" * 40)
+
+ for i, endpoint in enumerate(api_endpoints, 1):
+ print(f"{i}. 测试: {endpoint.split('/')[-2]}/{endpoint.split('/')[-1]}")
+
+ status_code, response = make_api_request(endpoint, token)
+
+ if status_code == 200:
+ print(f" ✅ 成功 (200): 找到 {len(response.get('operations', response.get('memoryBanks', [])))} 个资源")
+ if response:
+ print(f" 📄 响应预览: {str(response)[:100]}...")
+ elif status_code == 404:
+ print(f" ⚠️ 未找到 (404): 端点不存在")
+ elif status_code == 403:
+ print(f" 🚫 权限不足 (403): 需要更多权限")
+ elif status_code:
+ print(f" ❌ 错误 ({status_code}): {str(response)[:50]}...")
+ else:
+ print(f" 💥 请求失败: {response}")
+ print()
+
+ # 查看项目信息
+ print("📋 项目信息...")
+ project_url = f"https://cloudresourcemanager.googleapis.com/v1/projects/{project_id}"
+ status_code, response = make_api_request(project_url, token)
+
+ if status_code == 200:
+ print(f" ✅ 项目名称: {response.get('name', 'N/A')}")
+ print(f" 📊 项目编号: {response.get('projectNumber', 'N/A')}")
+ print(f" 🏷️ 项目ID: {response.get('projectId', 'N/A')}")
+ print(f" 📅 创建时间: {response.get('createTime', 'N/A')}")
+ print(f" 🔄 生命周期: {response.get('lifecycleState', 'N/A')}")
+ else:
+ print(f" ❌ 无法获取项目信息: {status_code}")
+ print()
+
+ # 查看启用的服务
+ print("🔧 查看启用的AI相关服务...")
+ services_url = f"https://serviceusage.googleapis.com/v1/projects/{project_id}/services"
+ status_code, response = make_api_request(services_url, token)
+
+ if status_code == 200:
+ services = response.get('services', [])
+ ai_services = [s for s in services if 'ai' in s.get('config', {}).get('name', '').lower() or 'generative' in s.get('config', {}).get('name', '').lower()]
+
+ print(f" 📊 总服务数: {len(services)}")
+ print(f" 🤖 AI相关服务: {len(ai_services)}")
+
+ for service in ai_services[:10]: # 显示前10个
+ name = service.get('config', {}).get('name', 'Unknown')
+ state = service.get('state', 'Unknown')
+ print(f" • {name}: {state}")
+ else:
+ print(f" ❌ 无法获取服务信息: {status_code}")
+
+ print()
+ print("🎯 Memory Bank访问建议:")
+ print(" 1. 在Google Cloud Console中访问:")
+ print(f" https://console.cloud.google.com/vertex-ai/generative/memory-banks?project={project_id}")
+ print(" 2. 或者访问Vertex AI主页:")
+ print(f" https://console.cloud.google.com/vertex-ai?project={project_id}")
+ print(" 3. Memory Bank功能可能在'生成式AI'或'实验性功能'部分")
+ print()
+ print("🎉 GCP API查询完成!")
+ print("=" * 60)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/devops-tools/tools/rapidapi/api_checker.py b/modules/devops-tools/tools/rapidapi/api_checker.py
new file mode 100644
index 0000000..fbd376e
--- /dev/null
+++ b/modules/devops-tools/tools/rapidapi/api_checker.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+"""
+RapidAPI检查工具
+从cauldron_new迁移的简化版本
+"""
+
+import requests
+import time
+from typing import Dict, List, Any
+from config.settings import get_rapidapi_key
+
+class RapidAPIChecker:
+ """RapidAPI服务检查器"""
+
+ def __init__(self):
+ """初始化检查器"""
+ try:
+ self.api_key = get_rapidapi_key()
+ except Exception as e:
+ print(f"❌ 无法获取RapidAPI密钥: {e}")
+ self.api_key = ""
+
+ self.headers = {
+ 'X-RapidAPI-Key': self.api_key,
+ 'Content-Type': 'application/json'
+ }
+
+ def test_api(self, host: str, endpoint: str, params: Dict = None, method: str = 'GET') -> Dict[str, Any]:
+ """
+ 测试特定的RapidAPI服务
+
+ Args:
+ host: API主机名
+ endpoint: API端点
+ params: 请求参数
+ method: HTTP方法
+
+ Returns:
+ 测试结果
+ """
+ self.headers['X-RapidAPI-Host'] = host
+ url = f"https://{host}{endpoint}"
+
+ try:
+ if method.upper() == 'GET':
+ response = requests.get(url, headers=self.headers, params=params, timeout=8)
+ else:
+ response = requests.post(url, headers=self.headers, json=params, timeout=8)
+
+ return {
+ 'success': response.status_code == 200,
+ 'status_code': response.status_code,
+ 'response_size': len(response.text),
+ 'response_time': response.elapsed.total_seconds(),
+ 'error': None if response.status_code == 200 else response.text[:200]
+ }
+ except Exception as e:
+ return {
+ 'success': False,
+ 'status_code': None,
+ 'response_size': 0,
+ 'response_time': 0,
+ 'error': str(e)
+ }
+
+ def check_common_apis(self) -> Dict[str, Dict[str, Any]]:
+ """检查常用的RapidAPI服务"""
+ print("🔍 检查RapidAPI订阅状态")
+
+ # 常用API列表
+ apis_to_check = [
+ {
+ 'name': 'Yahoo Finance',
+ 'host': 'yahoo-finance15.p.rapidapi.com',
+ 'endpoint': '/api/yahoo/qu/quote/AAPL'
+ },
+ {
+ 'name': 'Alpha Vantage',
+ 'host': 'alpha-vantage.p.rapidapi.com',
+ 'endpoint': '/query?function=GLOBAL_QUOTE&symbol=AAPL'
+ },
+ {
+ 'name': 'Seeking Alpha',
+ 'host': 'seeking-alpha.p.rapidapi.com',
+ 'endpoint': '/symbols/get-profile?symbols=AAPL'
+ }
+ ]
+
+ results = {}
+ for api in apis_to_check:
+ print(f" 测试 {api['name']}...")
+ result = self.test_api(api['host'], api['endpoint'])
+ results[api['name']] = result
+
+ status = "✅ 可用" if result['success'] else "❌ 不可用"
+ print(f" {status} - {result.get('response_time', 0):.2f}s")
+
+ time.sleep(0.5) # 避免请求过快
+
+ return results
+
+def main():
+ """主函数"""
+ checker = RapidAPIChecker()
+ results = checker.check_common_apis()
+
+ print("\n📊 检查结果总结:")
+ available_count = sum(1 for result in results.values() if result['success'])
+ print(f"可用API: {available_count}/{len(results)}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/AI_AGENT_TASKS/CLAUDE_CODE_IMPLEMENTATION.md b/modules/documentation-suite/docs/AI_AGENT_TASKS/CLAUDE_CODE_IMPLEMENTATION.md
new file mode 100644
index 0000000..659256b
--- /dev/null
+++ b/modules/documentation-suite/docs/AI_AGENT_TASKS/CLAUDE_CODE_IMPLEMENTATION.md
@@ -0,0 +1,222 @@
+# 💻 Claude AI - OpenBB核心代码实现工作说明书
+
+## 🎯 任务概述
+作为核心开发工程师,您需要基于Qwen的架构设计,实现OpenBB与稷下学宫系统的深度集成代码。
+
+## 📋 核心职责
+
+### 1. 核心引擎实现
+**任务目标:** 增强现有OpenBB引擎,实现八仙智能数据获取
+
+**关键文件实现:**
+```
+src/jixia/engines/
+├── enhanced_openbb_engine.py # 增强版OpenBB引擎
+├── immortal_data_router.py # 八仙数据路由器
+├── intelligent_fallback.py # 智能降级机制
+└── data_quality_monitor.py # 数据质量监控
+```
+
+**核心代码需求:**
+```python
+class EnhancedOpenBBEngine:
+ """增强版OpenBB引擎 - 八仙专属"""
+
+ async def get_immortal_insight(self, immortal_name: str,
+ symbol: str, analysis_type: str):
+ """为特定八仙获取专属金融洞察"""
+ pass
+
+ async def orchestrate_debate_data(self, topic: str,
+ participants: List[str]):
+ """为稷下学宫辩论准备数据"""
+ pass
+```
+
+### 2. 智能体数据适配器
+**任务目标:** 实现AI智能体与OpenBB数据的无缝对接
+
+**具体实现:**
+- 八仙角色数据源适配
+- 实时数据流处理
+- 智能缓存机制
+- 异常处理和重试逻辑
+
+**核心文件:**
+- `src/jixia/adapters/openbb_agent_adapter.py`
+- `src/jixia/adapters/immortal_data_processor.py`
+
+### 3. Streamlit界面增强
+**任务目标:** 优化现有OpenBB标签页,增加八仙论道功能
+
+**需要修改的文件:**
+- `app/tabs/openbb_tab.py` - 增强现有界面
+- `app/tabs/immortal_debate_tab.py` - 新增八仙辩论界面
+
+**UI功能需求:**
+```python
+def render_immortal_debate_interface():
+ """渲染八仙辩论界面"""
+ # 1. 股票/主题选择器
+ # 2. 八仙角色选择器
+ # 3. 实时数据展示
+ # 4. 辩论结果可视化
+ pass
+```
+
+### 4. 数据质量保障
+**任务目标:** 确保数据准确性和系统稳定性
+
+**实现重点:**
+- 数据验证机制
+- 异常数据处理
+- 性能监控埋点
+- 日志记录系统
+
+## 🔧 实现规范
+
+### 代码风格要求:
+```python
+# 1. 遵循项目现有代码风格
+# 2. 完整的类型注解
+# 3. 详细的docstring文档
+# 4. 异常处理机制
+
+from typing import Dict, List, Optional, Union
+from dataclasses import dataclass
+from datetime import datetime
+
+@dataclass
+class ImmortalInsight:
+ """八仙洞察数据模型"""
+ immortal_name: str
+ symbol: str
+ insight_type: str
+ data: Dict[str, any]
+ confidence: float
+ timestamp: datetime
+```
+
+### 必须保持的特性:
+1. **向后兼容** - 不破坏现有功能
+2. **优雅降级** - OpenBB不可用时的备选方案
+3. **文化内核** - 保持八仙论道的文化特色
+4. **模块化设计** - 便于单元测试和维护
+
+### 性能要求:
+- 数据获取响应时间 < 3秒
+- 并发处理能力 > 10个请求/秒
+- 内存使用 < 500MB
+- CPU使用率 < 30%
+
+## 🎭 八仙特色功能实现
+
+### 八仙数据偏好实现:
+```python
+IMMORTAL_PREFERENCES = {
+ '吕洞宾': {
+ 'data_types': ['technical_indicators', 'chart_patterns'],
+ 'analysis_style': 'systematic',
+ 'risk_appetite': 'moderate'
+ },
+ '何仙姑': {
+ 'data_types': ['risk_metrics', 'volatility'],
+ 'analysis_style': 'conservative',
+ 'risk_appetite': 'low'
+ },
+ # ... 其他六仙
+}
+```
+
+### 智能辩论数据准备:
+```python
+async def prepare_debate_data(self, topic_symbol: str) -> DebateDataSet:
+ """为八仙辩论准备差异化数据视角"""
+ # 1. 获取基础数据
+ # 2. 按八仙偏好处理数据
+ # 3. 生成对比性观点
+ # 4. 返回结构化辩论数据
+ pass
+```
+
+## 🧪 测试要求
+
+### 必须实现的测试:
+```python
+# tests/test_enhanced_openbb_engine.py
+class TestEnhancedOpenBBEngine:
+ def test_immortal_data_routing(self):
+ """测试八仙数据路由功能"""
+ pass
+
+ def test_fallback_mechanism(self):
+ """测试降级机制"""
+ pass
+
+ def test_concurrent_requests(self):
+ """测试并发请求处理"""
+ pass
+```
+
+### 集成测试:
+- 与现有八仙辩论系统的集成
+- Streamlit界面集成测试
+- 实际数据获取测试
+
+## 🔄 协作接口
+
+### 接收Qwen的架构输入:
+- [ ] 架构设计文档
+- [ ] 接口规范定义
+- [ ] 数据模型标准
+
+### 为Gemini提供测试目标:
+- [ ] 完整的代码实现
+- [ ] 单元测试用例
+- [ ] 集成测试指南
+
+### 为RovoDev提供文档素材:
+- [ ] 代码注释和文档
+- [ ] API使用示例
+- [ ] 故障排除指南
+
+## 📅 开发里程碑
+
+### 里程碑1(3天):
+- [ ] 核心引擎实现
+- [ ] 基础单元测试
+- [ ] 简单集成验证
+
+### 里程碑2(2天):
+- [ ] Streamlit界面增强
+- [ ] 八仙特色功能
+- [ ] 性能优化
+
+### 里程碑3(1天):
+- [ ] 完整测试覆盖
+- [ ] 代码审查和优化
+- [ ] 文档完善
+
+## 💡 创新挑战
+
+请在实现中展现创新:
+1. **智能数据融合算法**
+2. **八仙个性化数据处理**
+3. **实时性能监控机制**
+4. **用户体验优化**
+
+## ⚠️ 特别注意
+
+### 文化敏感性:
+- 确保八仙角色的准确性和尊重性
+- 保持传统文化与现代技术的平衡
+- 避免过度商业化的表达
+
+### 技术债务控制:
+- 避免硬编码
+- 保持配置的灵活性
+- 确保代码的可维护性
+
+---
+
+**注意:** 代码是文化的载体,请让每一行代码都体现稷下学宫的智慧!
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/AI_AGENT_TASKS/GEMINI_TEST_VALIDATION.md b/modules/documentation-suite/docs/AI_AGENT_TASKS/GEMINI_TEST_VALIDATION.md
new file mode 100644
index 0000000..531b6d6
--- /dev/null
+++ b/modules/documentation-suite/docs/AI_AGENT_TASKS/GEMINI_TEST_VALIDATION.md
@@ -0,0 +1,274 @@
+# 🧪 Gemini AI - OpenBB集成测试验证工作说明书
+
+## 🎯 任务概述
+作为测试工程师,您需要为OpenBB与稷下学宫系统的集成功能设计并执行全面的测试验证方案。
+
+## 📋 核心职责
+
+### 1. 测试策略制定
+**任务目标:** 制定全面的测试策略和验证标准
+
+**测试金字塔设计:**
+```
+ [E2E Tests] # 端到端测试
+ / \
+ [Integration Tests] # 集成测试
+ / \
+ [Unit Tests] [API Tests] # 单元测试 + API测试
+```
+
+**测试覆盖范围:**
+- 功能测试 (80%覆盖率)
+- 性能测试 (响应时间、并发)
+- 稳定性测试 (长时间运行)
+- 兼容性测试 (多数据源)
+
+### 2. 八仙智能体测试
+**任务目标:** 验证八仙角色的数据获取和分析能力
+
+**测试文件结构:**
+```
+tests/immortal_tests/
+├── test_immortal_data_routing.py # 八仙数据路由测试
+├── test_immortal_preferences.py # 八仙偏好测试
+├── test_debate_data_quality.py # 辩论数据质量测试
+└── test_cultural_accuracy.py # 文化准确性测试
+```
+
+**关键测试用例:**
+```python
+class TestImmortalDataRouting:
+ """八仙数据路由测试"""
+
+ def test_lv_dongbin_technical_analysis(self):
+ """测试吕洞宾的技术分析数据获取"""
+ pass
+
+ def test_he_xiangu_risk_metrics(self):
+ """测试何仙姑的风险指标数据"""
+ pass
+
+ def test_immortal_data_consistency(self):
+ """测试八仙数据的一致性"""
+ pass
+```
+
+### 3. OpenBB集成测试
+**任务目标:** 验证OpenBB数据源的集成质量
+
+**测试重点:**
+- OpenBB API调用稳定性
+- 数据格式标准化
+- 错误处理机制
+- 降级策略验证
+
+**核心测试文件:**
+```python
+# tests/openbb_integration/
+class TestOpenBBIntegration:
+ """OpenBB集成测试套件"""
+
+ @pytest.mark.asyncio
+ async def test_stock_data_retrieval(self):
+ """测试股票数据获取"""
+ symbols = ['AAPL', 'TSLA', 'MSFT']
+ for symbol in symbols:
+ data = await engine.get_stock_data(symbol)
+ assert data is not None
+ assert 'close' in data.columns
+
+ def test_fallback_mechanism(self):
+ """测试OpenBB不可用时的降级机制"""
+ # 模拟OpenBB不可用
+ with mock.patch('openbb.obb', side_effect=ImportError):
+ result = engine.get_data_with_fallback('AAPL')
+ assert result.source == 'demo_data'
+```
+
+### 4. 性能和稳定性测试
+**任务目标:** 确保系统在各种条件下的性能表现
+
+**性能基准:**
+- 数据获取延迟 < 3秒
+- 并发处理 > 10 req/s
+- 内存使用 < 500MB
+- 99.9% 可用性
+
+**负载测试方案:**
+```python
+# tests/performance/
+class TestPerformance:
+ """性能测试套件"""
+
+ def test_concurrent_data_requests(self):
+ """并发数据请求测试"""
+ import concurrent.futures
+
+ with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
+ futures = [executor.submit(self.get_test_data) for _ in range(100)]
+ results = [f.result() for f in futures]
+
+ assert all(r.success for r in results)
+ assert max(r.response_time for r in results) < 5.0
+```
+
+## 🎭 文化特色测试
+
+### 八仙文化准确性验证:
+```python
+class TestCulturalAccuracy:
+ """文化准确性测试"""
+
+ def test_immortal_characteristics(self):
+ """验证八仙特征的准确性"""
+ immortals = get_immortal_configs()
+
+ # 验证吕洞宾的技术分析特色
+ assert immortals['吕洞宾'].specialty == 'technical_analysis'
+ assert immortals['吕洞宾'].element == '乾'
+
+ # 验证何仙姑的风险控制特色
+ assert immortals['何仙姑'].specialty == 'risk_metrics'
+ assert immortals['何仙姑'].element == '坤'
+
+ def test_debate_cultural_context(self):
+ """验证辩论的文化背景准确性"""
+ debate = create_test_debate('AAPL')
+
+ # 确保辩论遵循稷下学宫的传统
+ assert 'jixia' in debate.context
+ assert len(debate.participants) == 8 # 八仙
+```
+
+## 🔧 测试工具和框架
+
+### 推荐工具栈:
+```python
+# 测试依赖
+pytest>=7.4.0 # 主测试框架
+pytest-asyncio>=0.21.0 # 异步测试支持
+pytest-mock>=3.11.0 # Mock功能
+pytest-cov>=4.1.0 # 覆盖率统计
+pytest-benchmark>=4.0.0 # 性能基准测试
+
+# 性能测试
+locust>=2.15.0 # 负载测试
+memory-profiler>=0.60.0 # 内存分析
+
+# 数据验证
+pydantic>=2.0.0 # 数据模型验证
+jsonschema>=4.19.0 # JSON架构验证
+```
+
+### 测试配置文件:
+```yaml
+# pytest.ini
+[tool:pytest]
+testpaths = tests
+python_files = test_*.py
+python_classes = Test*
+python_functions = test_*
+addopts =
+ --cov=src
+ --cov-report=html
+ --cov-report=term-missing
+ --asyncio-mode=auto
+```
+
+## 📊 测试报告和指标
+
+### 测试报告模板:
+```
+tests/reports/
+├── unit_test_report.html # 单元测试报告
+├── integration_test_report.html # 集成测试报告
+├── performance_benchmark.json # 性能基准数据
+├── coverage_report/ # 代码覆盖率报告
+└── cultural_validation_report.md # 文化验证报告
+```
+
+### 关键指标监控:
+```python
+# 自动化指标收集
+class TestMetrics:
+ """测试指标收集器"""
+
+ def collect_response_times(self):
+ """收集响应时间数据"""
+ pass
+
+ def measure_memory_usage(self):
+ """监控内存使用情况"""
+ pass
+
+ def validate_data_quality(self):
+ """验证数据质量指标"""
+ pass
+```
+
+## 🔄 协作流程
+
+### 与Claude的协作:
+1. **接收代码实现** → 制定对应测试用例
+2. **执行测试验证** → 反馈BUG和优化建议
+3. **性能测试** → 提供优化方向
+
+### 与Qwen的协作:
+1. **验证架构设计** → 确认技术指标可达成
+2. **测试架构决策** → 验证设计的合理性
+
+### 与RovoDev的协作:
+1. **提供测试数据** → 支持文档编写
+2. **验证文档准确性** → 确保文档与实际一致
+
+## 📅 测试里程碑
+
+### 阶段一(2天):测试框架搭建
+- [ ] 测试环境配置
+- [ ] 基础测试框架
+- [ ] Mock数据准备
+
+### 阶段二(3天):功能测试执行
+- [ ] 单元测试执行
+- [ ] 集成测试验证
+- [ ] 八仙特色功能测试
+
+### 阶段三(2天):性能和稳定性测试
+- [ ] 负载测试执行
+- [ ] 性能基准建立
+- [ ] 稳定性验证
+
+### 阶段四(1天):测试报告生成
+- [ ] 测试结果汇总
+- [ ] 问题清单整理
+- [ ] 优化建议制定
+
+## 🎯 验收标准
+
+### 功能验收:
+- [ ] 所有单元测试通过率 > 95%
+- [ ] 集成测试通过率 > 90%
+- [ ] 八仙特色功能100%验证通过
+
+### 性能验收:
+- [ ] 响应时间 < 3秒
+- [ ] 并发处理 > 10 req/s
+- [ ] 内存使用稳定
+- [ ] 99%可用性达成
+
+### 文化验收:
+- [ ] 八仙角色特征准确
+- [ ] 辩论逻辑符合传统
+- [ ] 文化表达尊重得体
+
+## 💡 创新测试方法
+
+### 智能化测试:
+1. **AI驱动的测试用例生成**
+2. **自适应性能基准调整**
+3. **文化语境的自动化验证**
+4. **用户行为模拟测试**
+
+---
+
+**注意:** 测试不仅是质量保障,更是文化传承的守护者!每一个测试用例都要体现对传统文化的尊重!
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/AI_AGENT_TASKS/QWEN_ARCHITECTURE_DESIGN.md b/modules/documentation-suite/docs/AI_AGENT_TASKS/QWEN_ARCHITECTURE_DESIGN.md
new file mode 100644
index 0000000..f99d9d2
--- /dev/null
+++ b/modules/documentation-suite/docs/AI_AGENT_TASKS/QWEN_ARCHITECTURE_DESIGN.md
@@ -0,0 +1,122 @@
+# 📐 Qwen AI - OpenBB架构设计师工作说明书
+
+## 🎯 任务概述
+作为架构设计师,您需要为"炼妖壶-稷下学宫AI辩论系统"设计OpenBB集成的技术架构方案。
+
+## 📋 核心职责
+
+### 1. 系统架构设计
+**任务目标:** 设计OpenBB与稷下学宫系统的集成架构
+
+**具体工作:**
+- 分析现有系统架构(`src/jixia/engines/`)
+- 设计OpenBB数据流架构
+- 制定模块间解耦策略
+- 设计故障转移和降级机制
+
+**交付物:**
+```
+docs/architecture/
+├── openbb_integration_architecture.md
+├── data_flow_diagram.mermaid
+├── component_interaction_diagram.mermaid
+└── deployment_architecture.md
+```
+
+### 2. 数据抽象层设计
+**任务目标:** 设计统一的金融数据抽象接口
+
+**具体工作:**
+- 定义标准化数据模型
+- 设计Provider适配器模式
+- 制定数据缓存策略
+- 设计数据质量监控机制
+
+**关键文件:**
+- `src/jixia/engines/data_abstraction.py`
+- `src/jixia/models/financial_data_models.py`
+
+### 3. 性能优化架构
+**任务目标:** 确保系统在高并发下的稳定性
+
+**具体工作:**
+- 设计异步数据获取架构
+- 制定缓存策略(Redis/Memory)
+- 设计负载均衡机制
+- 制定监控和告警策略
+
+## 🔧 技术约束
+
+### 必须遵循的原则:
+1. **渐进式集成** - 不破坏现有功能
+2. **可选依赖** - OpenBB失效时优雅降级
+3. **文化融合** - 保持八仙论道的文化特色
+4. **模块解耦** - 便于后续扩展其他数据源
+
+### 技术栈限制:
+- Python 3.10+
+- 现有Streamlit界面
+- 八仙智能体系统
+- Vertex AI记忆银行
+
+## 📊 成功标准
+
+### 架构质量指标:
+- [ ] 模块耦合度 < 20%
+- [ ] 代码复用率 > 80%
+- [ ] 系统可用性 > 99%
+- [ ] 响应时间 < 2秒
+
+### 文档完整性:
+- [ ] 架构图清晰易懂
+- [ ] 接口文档完整
+- [ ] 部署指南详细
+- [ ] 故障处理手册
+
+## 🎭 与稷下学宫的结合
+
+### 八仙角色映射:
+```python
+# 设计八仙与数据源的智能映射
+immortal_data_mapping = {
+ '吕洞宾': 'technical_analysis', # 技术分析专家
+ '何仙姑': 'risk_metrics', # 风险控制专家
+ '张果老': 'historical_data', # 历史数据分析师
+ '韩湘子': 'sector_analysis', # 新兴资产专家
+ '汉钟离': 'market_movers', # 热点追踪
+ '蓝采和': 'value_discovery', # 潜力股发现
+ '铁拐李': 'contrarian_analysis', # 逆向思维专家
+ '曹国舅': 'macro_economics' # 宏观经济分析师
+}
+```
+
+## 🔄 协作接口
+
+### 与其他AI的协作:
+- **Claude(代码实现)**: 提供详细的接口规范和实现指导
+- **Gemini(测试验证)**: 制定测试用例和验证标准
+- **RovoDev(文档整合)**: 提供架构决策文档和技术规范
+
+## 📅 时间节点
+
+### 阶段一(2天):
+- [ ] 现有系统分析
+- [ ] 架构方案设计
+- [ ] 核心接口定义
+
+### 阶段二(1天):
+- [ ] 详细设计文档
+- [ ] 技术选型说明
+- [ ] 风险评估报告
+
+## 💡 创新要求
+
+作为架构师,请在以下方面展现创新:
+1. **传统文化与现代技术的融合**
+2. **智能化的数据路由策略**
+3. **自适应的性能优化机制**
+4. **面向未来的可扩展架构**
+
+---
+
+**注意:** 这是一个文化与技术深度融合的项目,请在技术设计中体现中国传统哲学思想!
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/AI_AGENT_TASKS/README.md b/modules/documentation-suite/docs/AI_AGENT_TASKS/README.md
new file mode 100644
index 0000000..0d4aa2b
--- /dev/null
+++ b/modules/documentation-suite/docs/AI_AGENT_TASKS/README.md
@@ -0,0 +1,236 @@
+# 🎭 四AI协作指南 - OpenBB稷下学宫集成项目
+
+## 🎯 项目使命
+将OpenBB金融数据平台与稷下学宫八仙论道系统深度融合,创造传统文化与现代金融科技的完美结合。
+
+## 👥 团队角色与协作关系
+
+```mermaid
+graph TD
+ A[Qwen - 架构设计师] --> B[Claude - 核心开发工程师]
+ A --> C[Gemini - 测试验证专家]
+ A --> D[RovoDev - 项目整合专家]
+ B --> C
+ B --> D
+ C --> D
+
+ subgraph 协作流程
+ E[架构设计] --> F[代码实现]
+ F --> G[测试验证]
+ G --> H[文档整合]
+ H --> I[项目交付]
+ end
+```
+
+## 📋 各AI工作说明书链接
+
+| AI角色 | 主要职责 | 工作说明书 |
+|--------|----------|------------|
+| **Qwen** | 架构设计师 | [`QWEN_ARCHITECTURE_DESIGN.md`](./QWEN_ARCHITECTURE_DESIGN.md) |
+| **Claude** | 核心开发工程师 | [`CLAUDE_CODE_IMPLEMENTATION.md`](./CLAUDE_CODE_IMPLEMENTATION.md) |
+| **Gemini** | 测试验证专家 | [`GEMINI_TEST_VALIDATION.md`](./GEMINI_TEST_VALIDATION.md) |
+| **RovoDev** | 项目整合专家 | [`ROVODEV_PROJECT_INTEGRATION.md`](./ROVODEV_PROJECT_INTEGRATION.md) |
+
+## 🔄 协作工作流
+
+### 第一阶段:设计与规划 (Day 1-3)
+```
+Qwen 主导:
+├── 系统架构设计
+├── 接口规范定义
+├── 技术选型方案
+└── 实施计划制定
+
+其他AI配合:
+├── Claude: 技术可行性评估
+├── Gemini: 测试策略制定
+└── RovoDev: 项目框架搭建
+```
+
+### 第二阶段:核心开发 (Day 4-8)
+```
+Claude 主导:
+├── 核心引擎实现
+├── API集成开发
+├── UI界面增强
+└── 功能模块编码
+
+其他AI配合:
+├── Qwen: 架构指导和审查
+├── Gemini: 同步测试执行
+└── RovoDev: 代码集成管理
+```
+
+### 第三阶段:测试验证 (Day 9-12)
+```
+Gemini 主导:
+├── 功能测试执行
+├── 性能基准测试
+├── 集成测试验证
+└── 文化准确性检查
+
+其他AI配合:
+├── Qwen: 架构层面问题解决
+├── Claude: 代码BUG修复
+└── RovoDev: 测试结果整合
+```
+
+### 第四阶段:整合交付 (Day 13-15)
+```
+RovoDev 主导:
+├── 文档体系整合
+├── 用户指南编写
+├── 项目质量检查
+└── 最终版本发布
+
+其他AI配合:
+├── Qwen: 架构文档审核
+├── Claude: 技术文档完善
+└── Gemini: 测试报告整理
+```
+
+## 🎭 文化核心要求
+
+### 八仙角色特征(所有AI必须遵循):
+```python
+IMMORTAL_CHARACTERISTICS = {
+ '吕洞宾': {
+ 'element': '乾', # 八卦方位
+ 'specialty': '技术分析', # 专业特长
+ 'personality': '系统性', # 性格特点
+ 'approach': '理性分析' # 分析方法
+ },
+ '何仙姑': {
+ 'element': '坤',
+ 'specialty': '风险控制',
+ 'personality': '稳健保守',
+ 'approach': '风险优先'
+ },
+ '张果老': {
+ 'element': '兑',
+ 'specialty': '历史数据',
+ 'personality': '博学深沉',
+ 'approach': '历史借鉴'
+ },
+ '韩湘子': {
+ 'element': '艮',
+ 'specialty': '新兴资产',
+ 'personality': '创新进取',
+ 'approach': '前瞻思维'
+ },
+ '汉钟离': {
+ 'element': '离',
+ 'specialty': '热点追踪',
+ 'personality': '敏锐活跃',
+ 'approach': '趋势跟踪'
+ },
+ '蓝采和': {
+ 'element': '坎',
+ 'specialty': '价值发现',
+ 'personality': '独立思考',
+ 'approach': '逆向分析'
+ },
+ '铁拐李': {
+ 'element': '巽',
+ 'specialty': '逆向思维',
+ 'personality': '犀利直接',
+ 'approach': '反向验证'
+ },
+ '曹国舅': {
+ 'element': '震',
+ 'specialty': '宏观经济',
+ 'personality': '高瞻远瞩',
+ 'approach': '宏观视角'
+ }
+}
+```
+
+### 稷下学宫核心价值:
+- **开放包容**:各种观点都能得到尊重
+- **理性辩论**:基于数据和逻辑的讨论
+- **百家争鸣**:鼓励不同视角的碰撞
+- **求同存异**:在分歧中寻找共识
+
+## 📊 质量标准(所有AI共同遵循)
+
+### 技术质量:
+- [ ] 代码测试覆盖率 > 80%
+- [ ] API响应时间 < 3秒
+- [ ] 系统可用性 > 99%
+- [ ] 并发处理能力 > 10 req/s
+
+### 文化质量:
+- [ ] 八仙特征准确性 100%
+- [ ] 传统文化表达尊重性 100%
+- [ ] 现代化融合自然度 > 90%
+- [ ] 教育价值体现度 > 85%
+
+### 用户体验:
+- [ ] 界面直观度 > 90%
+- [ ] 功能易用性 > 85%
+- [ ] 文档完整性 > 95%
+- [ ] 错误处理友好度 > 90%
+
+## 🔄 沟通协作机制
+
+### 日常沟通:
+- **每日站会** (15分钟):进度同步,问题协调
+- **技术评审** (每2天):关键决策讨论
+- **质量检查** (每周):交叉审查工作成果
+
+### 问题升级机制:
+```
+Level 1: AI间直接协商
+Level 2: RovoDev协调处理
+Level 3: 项目负责人决策
+```
+
+### 文档共享约定:
+- 所有设计文档实时共享
+- 代码变更及时通知相关AI
+- 测试结果定期同步
+- 问题和解决方案公开透明
+
+## 🎯 成功标准
+
+### 项目成功的标志:
+1. **功能完整**:OpenBB数据与八仙论道完美融合
+2. **性能稳定**:各种场景下系统表现良好
+3. **文化准确**:传统文化表达准确尊重
+4. **用户满意**:最终用户体验优秀
+5. **可维护性**:代码和文档便于后续维护
+
+### 团队协作成功的标志:
+1. **沟通顺畅**:各AI间协作无障碍
+2. **质量一致**:各模块质量标准统一
+3. **进度可控**:项目按时交付
+4. **创新突出**:在传统与现代结合上有所突破
+
+## 💡 创新目标
+
+### 技术创新:
+- 智能化的数据路由算法
+- 自适应的性能优化机制
+- 文化语境的AI理解能力
+
+### 文化创新:
+- 传统文化的现代化表达
+- 金融科技的人文内涵
+- AI技术的文化责任
+
+### 用户体验创新:
+- 沉浸式的文化体验
+- 智能化的学习辅助
+- 个性化的论道体验
+
+---
+
+## 📞 紧急联系
+
+如遇到跨团队协调问题,请立即联系项目整合专家 RovoDev。
+
+**记住**:我们不仅在构建技术产品,更在传承和发扬中华文化!每一行代码、每一个测试、每一份文档都承载着文化的使命!
+
+---
+
+*"稷下学宫,百家争鸣;开源精神,技术报国!"*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/AI_AGENT_TASKS/ROVODEV_PROJECT_INTEGRATION.md b/modules/documentation-suite/docs/AI_AGENT_TASKS/ROVODEV_PROJECT_INTEGRATION.md
new file mode 100644
index 0000000..18014d9
--- /dev/null
+++ b/modules/documentation-suite/docs/AI_AGENT_TASKS/ROVODEV_PROJECT_INTEGRATION.md
@@ -0,0 +1,289 @@
+# 📚 RovoDev AI - OpenBB项目整合与文档管理工作说明书
+
+## 🎯 任务概述
+作为项目整合专家,您需要协调四个AI团队的工作成果,整合OpenBB集成项目的完整文档体系,并确保项目的顺利交付。
+
+## 📋 核心职责
+
+### 1. 项目协调与整合
+**任务目标:** 统筹四个AI团队的工作,确保各模块无缝对接
+
+**协调矩阵:**
+```
+ Qwen Claude Gemini RovoDev
+架构设计 主导 配合 验证 整合
+代码实现 配合 主导 验证 监控
+测试验证 配合 配合 主导 汇总
+文档整合 配合 配合 配合 主导
+```
+
+**关键协调点:**
+- 接口规范的一致性
+- 代码实现与架构设计的匹配度
+- 测试用例覆盖的完整性
+- 文档与实际功能的准确性
+
+### 2. 完整文档体系构建
+**任务目标:** 建立OpenBB集成的完整文档生态
+
+**文档架构:**
+```
+docs/openbb_integration/
+├── 00_PROJECT_OVERVIEW.md # 项目总览
+├── 01_ARCHITECTURE_DESIGN/ # 架构设计(Qwen输出)
+│ ├── system_architecture.md
+│ ├── data_flow_design.md
+│ ├── integration_patterns.md
+│ └── deployment_strategy.md
+├── 02_IMPLEMENTATION_GUIDE/ # 实现指南(Claude输出)
+│ ├── core_engine_implementation.md
+│ ├── api_integration_guide.md
+│ ├── ui_enhancement_guide.md
+│ └── troubleshooting_guide.md
+├── 03_TEST_DOCUMENTATION/ # 测试文档(Gemini输出)
+│ ├── test_strategy.md
+│ ├── test_results_report.md
+│ ├── performance_benchmarks.md
+│ └── quality_assurance_report.md
+├── 04_USER_GUIDES/ # 用户指南
+│ ├── getting_started.md
+│ ├── immortal_debate_tutorial.md
+│ ├── configuration_guide.md
+│ └── best_practices.md
+├── 05_CULTURAL_INTEGRATION/ # 文化融合文档
+│ ├── immortal_characteristics.md
+│ ├── jixia_philosophy_in_code.md
+│ └── cultural_accuracy_guidelines.md
+└── 06_MAINTENANCE/ # 维护文档
+ ├── release_notes.md
+ ├── upgrade_guide.md
+ ├── known_issues.md
+ └── future_roadmap.md
+```
+
+### 3. 用户体验设计
+**任务目标:** 确保最终用户能够轻松使用OpenBB集成功能
+
+**用户旅程设计:**
+```mermaid
+graph TD
+ A[用户启动应用] --> B[选择OpenBB标签页]
+ B --> C[查看数据可用性状态]
+ C --> D{OpenBB是否可用?}
+ D -->|是| E[选择股票符号]
+ D -->|否| F[使用演示数据]
+ E --> G[启动八仙论道]
+ F --> G
+ G --> H[查看辩论结果]
+ H --> I[导出分析报告]
+```
+
+**交互设计文档:**
+- 界面原型设计
+- 用户流程图
+- 错误处理流程
+- 帮助文档集成
+
+### 4. 质量保证与发布管理
+**任务目标:** 确保项目质量并管理发布流程
+
+**质量检查清单:**
+- [ ] 代码规范一致性检查
+- [ ] 文档完整性验证
+- [ ] 功能集成测试通过
+- [ ] 性能指标达标
+- [ ] 文化准确性确认
+- [ ] 用户体验验证
+
+## 🎭 文化融合专项工作
+
+### 传统文化现代化表达:
+```markdown
+# 八仙论道的现代诠释
+
+## 文化内核保持:
+- **稷下学宫精神**:开放包容、百家争鸣
+- **八仙特质**:各具特色、相互补充
+- **论道传统**:理性辩论、求同存异
+
+## 现代技术表达:
+- **数据驱动**:用真实数据支撑观点
+- **智能化**:AI技术赋能传统智慧
+- **可视化**:现代界面展示古典思想
+```
+
+### 文化准确性验证:
+```python
+# 文化审核检查点
+CULTURAL_CHECKPOINTS = {
+ 'immortal_names': '确保八仙姓名准确无误',
+ 'characteristics': '验证八仙特征描述的准确性',
+ 'philosophical_context': '确保稷下学宫背景的正确表达',
+ 'respectful_representation': '确保文化表达的尊重性',
+ 'educational_value': '验证文化教育价值的体现'
+}
+```
+
+## 📊 项目管理仪表板
+
+### 进度跟踪系统:
+```
+项目进度监控:
+├── 架构设计进度 [████████░░] 80%
+├── 代码实现进度 [██████░░░░] 60%
+├── 测试验证进度 [████░░░░░░] 40%
+└── 文档整合进度 [███████░░░] 70%
+
+质量指标:
+├── 代码覆盖率: 85%
+├── 文档完整性: 90%
+├── 测试通过率: 92%
+└── 文化准确性: 95%
+```
+
+### 风险管理:
+```markdown
+## 主要风险点识别:
+
+### 技术风险:
+- OpenBB版本兼容性问题
+- 性能瓶颈风险
+- 数据质量不稳定
+
+### 文化风险:
+- 八仙形象表达不当
+- 传统文化误读
+- 现代化过度商业化
+
+### 项目风险:
+- 团队协调不畅
+- 进度延迟风险
+- 质量标准不一致
+```
+
+## 🔄 协作工作流
+
+### 日常协调流程:
+```
+每日站会 (15分钟):
+├── 各AI汇报昨日进展
+├── 今日工作计划
+├── 阻塞问题讨论
+└── 协作需求确认
+
+每周回顾 (1小时):
+├── 整体进度回顾
+├── 质量指标检查
+├── 风险评估更新
+└── 下周计划调整
+```
+
+### 交付物审核流程:
+```mermaid
+graph LR
+ A[AI团队提交] --> B[RovoDev初审]
+ B --> C[质量检查]
+ C --> D{是否达标?}
+ D -->|是| E[集成到主项目]
+ D -->|否| F[反馈修改意见]
+ F --> A
+ E --> G[用户验证]
+ G --> H[正式发布]
+```
+
+## 📅 里程碑和时间线
+
+### 第一周:框架建立
+- **Day 1-2**: 项目启动,框架搭建
+- **Day 3-4**: 各团队初始输出整合
+- **Day 5-7**: 首版原型验证
+
+### 第二周:核心开发
+- **Day 8-10**: 核心功能开发
+- **Day 11-12**: 集成测试执行
+- **Day 13-14**: 问题修复和优化
+
+### 第三周:完善和发布
+- **Day 15-17**: 文档完善和用户测试
+- **Day 18-19**: 最终质量检查
+- **Day 20-21**: 项目发布和交付
+
+## 💡 创新整合方案
+
+### 1. 智能文档生成
+```python
+class IntelligentDocGenerator:
+ """智能文档生成器"""
+
+ def generate_api_docs(self, code_modules):
+ """从代码自动生成API文档"""
+ pass
+
+ def create_tutorial_from_tests(self, test_cases):
+ """从测试用例生成使用教程"""
+ pass
+
+ def cultural_context_validator(self, content):
+ """文化内容准确性验证"""
+ pass
+```
+
+### 2. 多媒体文档体验
+- 交互式代码示例
+- 视频教程制作
+- 在线演示环境
+- 文化背景介绍动画
+
+### 3. 社区协作平台
+```markdown
+## 开源社区建设:
+
+### 贡献者指南:
+- 代码贡献流程
+- 文档改进指南
+- 文化咨询渠道
+- 反馈收集机制
+
+### 社区活动:
+- 八仙论道比赛
+- 传统文化技术沙龙
+- 开源项目展示
+- 用户案例分享
+```
+
+## 🎯 成功标准
+
+### 项目交付标准:
+- [ ] 功能完整性 100%
+- [ ] 文档覆盖率 95%+
+- [ ] 用户满意度 90%+
+- [ ] 文化准确性 100%
+- [ ] 性能指标达标 100%
+
+### 长期影响目标:
+- [ ] 成为传统文化与AI结合的示范项目
+- [ ] 推动开源社区的文化多元化
+- [ ] 为金融科技注入文化内涵
+- [ ] 建立可持续的维护生态
+
+## 📈 后续运营规划
+
+### 版本迭代计划:
+```
+v1.0: OpenBB基础集成
+v1.1: 性能优化和BUG修复
+v1.2: 更多数据源集成
+v2.0: 高级分析功能
+v2.1: 移动端适配
+v3.0: 企业级功能
+```
+
+### 社区建设计划:
+- 建立用户社区
+- 定期发布教程
+- 举办线上活动
+- 收集用户反馈
+
+---
+
+**注意:** 作为项目整合者,您是传统文化与现代技术的桥梁!请确保每一个细节都体现对文化的尊重和技术的严谨!
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/AUTORAG_INTEGRATION_PROMPT.md b/modules/documentation-suite/docs/AUTORAG_INTEGRATION_PROMPT.md
new file mode 100644
index 0000000..e7f9d40
--- /dev/null
+++ b/modules/documentation-suite/docs/AUTORAG_INTEGRATION_PROMPT.md
@@ -0,0 +1,184 @@
+# 稷下学宫AI辩论系统 - AutoRAG集成提示词
+
+## 🏛️ 系统概述
+
+稷下学宫是一个基于中国传统哲学的AI辩论系统,模拟古代稷下学宫的学术辩论环境。系统中有八位仙人智能体,每位都有独特的投资哲学和辩论风格,需要通过AutoRAG服务获取相关的历史智慧和知识支持。
+
+## 🎭 八仙智能体角色
+
+### 铁拐李 (巽卦) - 逆向投资大师
+- **投资哲学**: 逆向思维,挑战市场共识
+- **记忆重点**: 市场异常、逆向案例、风险警示、反向策略
+- **辩论风格**: 质疑主流观点,提出反向思考
+
+### 吕洞宾 (乾卦) - 理性分析者
+- **投资哲学**: 技术分析专家,数据驱动决策
+- **记忆重点**: 技术分析、数据洞察、逻辑推理、理性决策
+- **辩论风格**: 基于数据和逻辑的严密分析
+
+### 何仙姑 (坤卦) - 直觉洞察者
+- **投资哲学**: 风险控制专家,情感智慧
+- **记忆重点**: 市场情绪、直觉判断、情感因素、人性洞察
+- **辩论风格**: 基于直觉和情感智慧的分析
+
+### 张果老 (兑卦) - 历史智慧者
+- **投资哲学**: 历史数据分析师,经验导向
+- **记忆重点**: 历史案例、长期趋势、周期规律、经验教训
+- **辩论风格**: 引用历史案例和长期趋势
+
+### 汉钟离 (离卦) - 平衡协调者
+- **投资哲学**: 热点追踪专家,平衡思维
+- **记忆重点**: 平衡策略、综合分析、协调方案、稳健建议
+- **辩论风格**: 寻求各方观点的平衡点
+
+### 蓝采和 (坎卦) - 创新思维者
+- **投资哲学**: 潜力股发现者,创新导向
+- **记忆重点**: 创新机会、新兴趋势、潜力发现、灵活策略
+- **辩论风格**: 发现新兴机会和创新角度
+
+### 韩湘子 (艮卦) - 艺术感知者
+- **投资哲学**: 新兴资产专家,美学视角
+- **记忆重点**: 美学趋势、创意洞察、感性分析、艺术视角
+- **辩论风格**: 从美学和艺术角度分析市场
+
+### 曹国舅 (震卦) - 实务执行者
+- **投资哲学**: 机构视角分析师,实务导向
+- **记忆重点**: 执行策略、机构动向、实务操作、专业分析
+- **辩论风格**: 关注实际执行和机构操作
+
+## 🔍 AutoRAG查询需求
+
+### 查询类型
+1. **历史智慧检索**: 根据辩论主题查找相关的古代智慧、哲学思想
+2. **投资案例搜索**: 寻找历史上的投资成功/失败案例
+3. **市场周期分析**: 查找关于市场周期、经济规律的古籍记录
+4. **风险管理智慧**: 搜索古代关于风险控制、谨慎投资的思想
+5. **人性洞察**: 查找关于人性、情绪、群体心理的古代观察
+
+### 期望的AutoRAG接口
+
+#### 1. 嵌入生成接口
+```
+POST /embed
+{
+ "text": "需要生成嵌入的文本内容"
+}
+
+响应:
+{
+ "embedding": [0.1, 0.2, ...], // 1024维BGE-M3嵌入向量
+ "model": "bge-m3"
+}
+```
+
+#### 2. 记忆存储接口
+```
+POST /upsert
+{
+ "vectors": [
+ {
+ "id": "memory_uuid",
+ "values": [0.1, 0.2, ...],
+ "metadata": {
+ "agent_name": "tieguaili",
+ "chinese_name": "铁拐李",
+ "content": "记忆内容",
+ "memory_type": "knowledge|conversation|preference|strategy",
+ "debate_topic": "辩论主题",
+ "timestamp": "2024-01-01T00:00:00Z"
+ }
+ }
+ ],
+ "namespace": "agent_name" // 智能体命名空间
+}
+
+响应:
+{
+ "success": true,
+ "inserted_count": 1
+}
+```
+
+#### 3. 记忆检索接口
+```
+POST /query
+{
+ "vector": [0.1, 0.2, ...], // 查询向量
+ "topK": 10, // 返回数量
+ "namespace": "tieguaili", // 智能体命名空间
+ "filter": { // 可选过滤条件
+ "memory_type": "knowledge"
+ }
+}
+
+响应:
+{
+ "matches": [
+ {
+ "id": "memory_uuid",
+ "score": 0.95,
+ "metadata": {
+ "content": "相关记忆内容",
+ "agent_name": "tieguaili",
+ "memory_type": "knowledge",
+ "debate_topic": "投资哲学"
+ }
+ }
+ ]
+}
+```
+
+## 📝 使用场景示例
+
+### 场景1: 辩论前的知识准备
+```
+辩论主题: "NVIDIA股票投资价值分析"
+
+铁拐李查询: "历史上科技股泡沫的案例和教训"
+张果老查询: "古代关于新兴技术投资的智慧"
+何仙姑查询: "市场狂热时期的风险控制思想"
+```
+
+### 场景2: 辩论中的观点支撑
+```
+当前观点: "AI技术发展存在过度炒作风险"
+
+相关查询: "古代关于技术革新的理性思考"
+期望返回: 相关的古籍智慧,支持或反驳当前观点
+```
+
+### 场景3: 辩论后的经验总结
+```
+辩论结果: 铁拐李的逆向观点获得认同
+
+存储记忆: "在AI股票讨论中,逆向思维帮助识别了估值风险"
+记忆类型: strategy
+```
+
+## 🎯 集成目标
+
+1. **智能记忆**: 每位仙人都有独立的记忆空间,能够学习和积累经验
+2. **文化融合**: 将古代智慧与现代投资分析相结合
+3. **个性化**: 根据每位仙人的特点,提供差异化的知识支持
+4. **持续学习**: 通过辩论过程不断丰富和完善知识库
+
+## 🔧 技术要求
+
+- **向量维度**: 1024 (BGE-M3模型)
+- **命名空间**: 支持按智能体分离数据
+- **元数据**: 丰富的元数据支持,便于过滤和分类
+- **性能**: 低延迟的检索响应,支持实时辩论
+- **扩展性**: 支持未来添加更多智能体和记忆类型
+
+## 🌟 期望效果
+
+通过AutoRAG集成,稷下学宫将实现:
+- 🧠 **智慧传承**: 古代哲学智慧指导现代投资决策
+- 🎭 **角色一致**: 每位仙人保持独特的人格和观点
+- 📚 **知识积累**: 持续学习和经验沉淀
+- 🔄 **动态辩论**: 基于历史记忆的深度讨论
+- 🎯 **精准分析**: 结合传统智慧的投资洞察
+
+---
+
+**让AI辩论照亮投资智慧,让古代智慧指引现代决策** 🏛️✨
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/GITHUB_PAGES_PUBLISH_PLAN.md b/modules/documentation-suite/docs/GITHUB_PAGES_PUBLISH_PLAN.md
new file mode 100644
index 0000000..4547721
--- /dev/null
+++ b/modules/documentation-suite/docs/GITHUB_PAGES_PUBLISH_PLAN.md
@@ -0,0 +1,218 @@
+# 🌐 GitHub Pages 发布计划
+
+## 📋 发布内容规划
+
+### **🎯 发布目标**
+- 展示项目功能和特性
+- 提供用户友好的文档
+- 吸引潜在用户和贡献者
+- 保持专业形象
+
+### **✅ 适合发布的内容**
+
+#### **1. 项目主页 (根目录)**
+```
+/
+├── README.md # 项目主介绍
+├── RELEASE_v2.0.0.md # 版本发布说明
+├── QUICK_START_GUIDE.md # 快速上手指南
+├── VERSION # 版本号
+├── requirements.txt # 依赖清单
+└── .gitignore # Git忽略文件
+```
+
+#### **2. 用户文档 (docs/)**
+```
+docs/
+├── index.md # 文档首页
+├── guides/ # 用户指南
+│ ├── quick-start.md # 快速开始
+│ ├── installation.md # 安装指南
+│ ├── configuration.md # 配置指南
+│ ├── cloudflare-integration.md # Cloudflare集成
+│ ├── google-adk-migration.md # Google ADK迁移
+│ └── load-balancing.md # 负载均衡指南
+├── features/ # 功能特性
+│ ├── debate-system.md # 辩论系统
+│ ├── memory-bank.md # 记忆系统
+│ ├── eight-immortals.md # 八仙系统
+│ └── tianxia-analysis.md # 天下体系
+├── api/ # API文档
+│ ├── rapidapi-setup.md # RapidAPI设置
+│ └── vertex-memory-bank.md # Memory Bank API
+└── examples/ # 示例代码
+ ├── basic-usage.md # 基础用法
+ └── advanced-features.md # 高级功能
+```
+
+#### **3. 设计文档 (design/)**
+```
+design/
+├── overview.md # 项目概览
+├── architecture.md # 系统架构
+├── debate-system.md # 辩论系统设计
+└── roadmap.md # 开发路线图
+```
+
+#### **4. 演示和示例**
+```
+examples/
+├── basic-debate.md # 基础辩论示例
+├── memory-bank-demo.md # 记忆系统演示
+└── load-balancing-demo.md # 负载均衡演示
+```
+
+### **🔒 保留在 internal/ 的内容**
+
+#### **1. 内部开发文档**
+- 开发计划和路线图
+- 技术实现细节
+- 内部策略文档
+- 代码审查记录
+
+#### **2. 敏感信息**
+- API密钥配置
+- 内部分析报告
+- 迁移方案细节
+- 历史文档
+
+#### **3. 配置文件**
+- 环境配置
+- 内部脚本
+- AI助手配置
+
+## 🚀 发布步骤
+
+### **第一阶段:内容准备**
+1. **优化 README.md**
+ - 添加项目徽章
+ - 完善功能介绍
+ - 添加截图和演示
+ - 优化安装说明
+
+2. **创建文档首页**
+ - 设计文档结构
+ - 创建导航菜单
+ - 添加搜索功能
+
+3. **整理用户指南**
+ - 统一文档格式
+ - 添加代码示例
+ - 完善配置说明
+
+### **第二阶段:GitHub Pages 配置**
+1. **启用 GitHub Pages**
+ ```bash
+ # 在仓库设置中启用 GitHub Pages
+ # 选择 docs/ 文件夹作为源
+ ```
+
+2. **配置 Jekyll 主题**
+ ```yaml
+ # _config.yml
+ title: 太公心易 - 稷下学宫AI辩论系统
+ description: 基于中国哲学传统的多AI智能体辩论平台
+ theme: jekyll-theme-cayman
+ ```
+
+3. **创建导航结构**
+ ```markdown
+ # docs/index.md
+ ---
+ layout: default
+ title: 太公心易文档
+ ---
+ ```
+
+### **第三阶段:内容发布**
+1. **发布核心文档**
+ - 项目介绍
+ - 快速开始指南
+ - 功能特性说明
+
+2. **发布用户指南**
+ - 安装配置
+ - 使用教程
+ - 示例代码
+
+3. **发布设计文档**
+ - 系统架构
+ - 技术设计
+ - 开发路线图
+
+## 📊 发布效果预期
+
+### **用户访问路径**
+```
+GitHub Pages 首页
+├── 项目介绍 → README.md
+├── 快速开始 → QUICK_START_GUIDE.md
+├── 用户指南 → docs/guides/
+├── 功能特性 → docs/features/
+├── API文档 → docs/api/
+└── 示例代码 → docs/examples/
+```
+
+### **SEO 优化**
+- 添加 meta 标签
+- 优化标题和描述
+- 添加关键词
+- 创建 sitemap
+
+### **用户体验**
+- 响应式设计
+- 快速加载
+- 清晰导航
+- 搜索功能
+
+## 🔧 技术实现
+
+### **GitHub Pages 配置**
+```yaml
+# .github/workflows/pages.yml
+name: Deploy to GitHub Pages
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Deploy to GitHub Pages
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./docs
+```
+
+### **文档结构优化**
+- 使用 Markdown 格式
+- 添加目录导航
+- 统一代码高亮
+- 优化图片显示
+
+## 📈 维护计划
+
+### **定期更新**
+- 每月更新功能文档
+- 季度更新架构文档
+- 及时更新版本说明
+
+### **用户反馈**
+- 收集用户问题
+- 更新常见问题
+- 优化文档内容
+
+### **版本同步**
+- 保持文档与代码同步
+- 及时发布新版本说明
+- 维护版本历史
+
+---
+
+**发布状态**:🔄 计划中
+**预计完成**:2025年8月底
diff --git a/modules/documentation-suite/docs/VERTEX_MEMORY_BANK_SETUP.md b/modules/documentation-suite/docs/VERTEX_MEMORY_BANK_SETUP.md
new file mode 100644
index 0000000..51d711d
--- /dev/null
+++ b/modules/documentation-suite/docs/VERTEX_MEMORY_BANK_SETUP.md
@@ -0,0 +1,270 @@
+# Vertex AI Memory Bank 配置指南
+
+## 🏛️ 稷下学宫记忆银行集成
+
+本文档介绍如何为稷下学宫AI辩论系统配置和使用Vertex AI Memory Bank功能。
+
+## 📋 前置要求
+
+### 1. Google Cloud 项目设置
+- 有效的 Google Cloud 项目
+- 启用 Vertex AI API
+- 配置适当的 IAM 权限
+
+### 2. 必需的依赖
+```bash
+pip install google-cloud-aiplatform>=1.38.0
+pip install google-adk # 或开发版本
+```
+
+### 3. 环境变量配置
+在 Doppler 或本地环境中设置以下变量:
+
+```bash
+# 必需配置
+GOOGLE_API_KEY=your_gemini_api_key
+GOOGLE_CLOUD_PROJECT_ID=your-project-id
+
+# 可选配置
+GOOGLE_CLOUD_LOCATION=us-central1 # 默认区域
+VERTEX_MEMORY_BANK_ENABLED=TRUE # 启用记忆银行
+GOOGLE_SERVICE_ACCOUNT_KEY=path/to/service-account.json # 服务账号密钥
+```
+
+## 🚀 快速开始
+
+### 1. 验证配置
+```bash
+# 验证 Google ADK 配置
+python config/settings.py
+
+# 测试 Memory Bank 连接
+python tests/test_vertex_memory_bank.py
+```
+
+### 2. 初始化八仙记忆银行
+```python
+from src.jixia.memory.vertex_memory_bank import initialize_baxian_memory_banks
+
+# 初始化所有八仙的记忆银行
+memory_bank = await initialize_baxian_memory_banks(
+ project_id="your-project-id",
+ location="us-central1"
+)
+```
+
+### 3. 创建记忆增强智能体
+```python
+from src.jixia.agents.memory_enhanced_agent import create_memory_enhanced_council
+
+# 创建记忆增强的八仙议会
+council = await create_memory_enhanced_council()
+
+# 进行记忆增强辩论
+result = await council.conduct_memory_debate(
+ topic="NVIDIA股票投资分析",
+ participants=["tieguaili", "lvdongbin", "hexiangu"],
+ rounds=3
+)
+```
+
+## 🎭 八仙记忆特性
+
+每位仙人都有独特的记忆重点和学习模式:
+
+### 铁拐李 (逆向投资大师)
+- **记忆重点**: 市场异常、逆向案例、风险警示、反向策略
+- **学习模式**: 关注市场共识的反面,记住历史上的逆向成功案例
+
+### 吕洞宾 (理性分析者)
+- **记忆重点**: 技术分析、数据洞察、逻辑推理、理性决策
+- **学习模式**: 基于数据和逻辑的严密分析,记住成功的分析框架
+
+### 何仙姑 (直觉洞察者)
+- **记忆重点**: 市场情绪、直觉判断、情感因素、人性洞察
+- **学习模式**: 关注市场情绪变化,记住情感驱动的市场事件
+
+### 张果老 (历史智慧者)
+- **记忆重点**: 历史案例、长期趋势、周期规律、经验教训
+- **学习模式**: 从历史中学习,记住重要的历史模式和教训
+
+### 汉钟离 (平衡协调者)
+- **记忆重点**: 平衡策略、综合分析、协调方案、稳健建议
+- **学习模式**: 寻求各方观点的平衡,记住成功的协调案例
+
+### 蓝采和 (创新思维者)
+- **记忆重点**: 创新机会、新兴趋势、潜力发现、灵活策略
+- **学习模式**: 发现新兴机会,记住创新投资的成功案例
+
+### 韩湘子 (艺术感知者)
+- **记忆重点**: 美学趋势、创意洞察、感性分析、艺术视角
+- **学习模式**: 从美学角度分析市场,记住艺术和创意相关的投资
+
+### 曹国舅 (实务执行者)
+- **记忆重点**: 执行策略、机构动向、实务操作、专业分析
+- **学习模式**: 关注实际执行,记住机构操作和专业分析
+
+## 🔧 高级配置
+
+### 1. 自定义记忆类型
+```python
+# 支持的记忆类型
+MEMORY_TYPES = [
+ "conversation", # 对话记忆
+ "preference", # 偏好记忆
+ "knowledge", # 知识记忆
+ "strategy" # 策略记忆
+]
+
+# 添加自定义记忆
+await memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在熊市中,逆向投资策略往往更有效",
+ memory_type="strategy",
+ debate_topic="市场策略",
+ metadata={
+ "market_condition": "bear_market",
+ "confidence": 0.8,
+ "source": "historical_analysis"
+ }
+)
+```
+
+### 2. 记忆搜索和过滤
+```python
+# 搜索特定类型的记忆
+strategy_memories = await memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="逆向投资",
+ memory_type="strategy",
+ limit=10
+)
+
+# 获取智能体的完整上下文
+context = await memory_bank.get_agent_context(
+ agent_name="tieguaili",
+ debate_topic="NVIDIA投资分析"
+)
+```
+
+### 3. 辩论会话保存
+```python
+# 自动保存辩论会话
+await memory_bank.save_debate_session(
+ debate_topic="比特币投资价值",
+ participants=["tieguaili", "lvdongbin", "hexiangu"],
+ conversation_history=conversation_history,
+ outcomes={
+ "winner": "tieguaili",
+ "key_insights": ["逆向思维在加密货币投资中的重要性"],
+ "consensus": "需要更谨慎的风险管理"
+ }
+)
+```
+
+## 📊 监控和管理
+
+### 1. 记忆银行状态检查
+```python
+# 检查记忆银行状态
+for agent_name, bank_name in memory_bank.memory_banks.items():
+ chinese_name = memory_bank.baxian_agents[agent_name]
+ print(f"{chinese_name}: {bank_name}")
+```
+
+### 2. 记忆使用统计
+```python
+# 获取记忆统计信息
+stats = await memory_bank.get_memory_stats(agent_name="tieguaili")
+print(f"总记忆数: {stats['total_memories']}")
+print(f"对话记忆: {stats['conversation_count']}")
+print(f"策略记忆: {stats['strategy_count']}")
+```
+
+### 3. 记忆清理和维护
+```python
+# 清理过期记忆(如果需要)
+await memory_bank.cleanup_old_memories(
+ agent_name="tieguaili",
+ days_old=30,
+ memory_type="conversation"
+)
+```
+
+## 🔒 安全和隐私
+
+### 1. 数据加密
+- 所有记忆数据在传输和存储时都会加密
+- 使用 Google Cloud 的企业级安全措施
+
+### 2. 访问控制
+- 每个智能体只能访问自己的记忆银行
+- 通过 IAM 控制项目级别的访问权限
+
+### 3. 数据保留
+- 可以配置记忆数据的保留期限
+- 支持手动删除敏感记忆
+
+## 🚨 故障排除
+
+### 常见问题
+
+#### 1. 项目ID未配置
+```
+❌ Google Cloud Project ID 未配置
+```
+**解决方案**: 设置 `GOOGLE_CLOUD_PROJECT_ID` 环境变量
+
+#### 2. API权限不足
+```
+❌ 403 Forbidden: Vertex AI API access denied
+```
+**解决方案**:
+- 在 Google Cloud Console 中启用 Vertex AI API
+- 确保服务账号有适当的权限
+
+#### 3. 记忆银行创建失败
+```
+❌ 创建记忆银行失败: Region not supported
+```
+**解决方案**:
+- 检查 `GOOGLE_CLOUD_LOCATION` 设置
+- 使用支持 Memory Bank 的区域(如 us-central1)
+
+#### 4. 依赖包缺失
+```
+❌ Google Cloud AI Platform 未安装
+```
+**解决方案**:
+```bash
+pip install google-cloud-aiplatform>=1.38.0
+```
+
+### 调试模式
+```python
+# 启用详细日志
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+# 测试连接
+python tests/test_vertex_memory_bank.py
+```
+
+## 📚 参考资源
+
+- [Vertex AI Memory Bank 官方文档](https://cloud.google.com/blog/products/ai-machine-learning/vertex-ai-memory-bank-in-public-preview)
+- [Google ADK 文档](https://github.com/google/adk-python)
+- [稷下学宫项目文档](../README.md)
+
+## 🤝 贡献指南
+
+如果你想为 Memory Bank 功能贡献代码:
+
+1. 确保所有新功能都有对应的测试
+2. 遵循现有的代码风格和注释规范
+3. 更新相关文档
+4. 提交 Pull Request 前运行完整的测试套件
+
+---
+
+**让AI辩论照亮投资智慧,记忆银行让智慧永续传承** 🏛️✨
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/analysis/meta_analysis_results.txt b/modules/documentation-suite/docs/analysis/meta_analysis_results.txt
new file mode 100644
index 0000000..70895af
--- /dev/null
+++ b/modules/documentation-suite/docs/analysis/meta_analysis_results.txt
@@ -0,0 +1,2884 @@
+✅ 成功获取 Alpha Vantage API Key: 4HDGAT4Z...
+
+🔍 正在获取 META 的财务数据...
+
+📊 获取公司概览...
+
+============================================================
+META - 公司概览
+============================================================
+{
+ "Symbol": "META",
+ "AssetType": "Common Stock",
+ "Name": "Meta Platforms Inc.",
+ "Description": "Meta Platforms, Inc. develops products that enable people to connect and share with friends and family through mobile devices, PCs, virtual reality headsets, wearables and home devices around the world. The company is headquartered in Menlo Park, California.",
+ "CIK": "1326801",
+ "Exchange": "NASDAQ",
+ "Currency": "USD",
+ "Country": "USA",
+ "Sector": "TECHNOLOGY",
+ "Industry": "SERVICES-COMPUTER PROGRAMMING, DATA PROCESSING, ETC.",
+ "Address": "1601 WILLOW ROAD, MENLO PARK, CA, US",
+ "OfficialSite": "https://investor.atmeta.com",
+ "FiscalYearEnd": "December",
+ "LatestQuarter": "2025-06-30",
+ "MarketCapitalization": "1884130116000",
+ "EBITDA": "94279999000",
+ "PERatio": "27.24",
+ "PEGRatio": "2.403",
+ "BookValue": "77.47",
+ "DividendPerShare": "2.05",
+ "DividendYield": "0.0027",
+ "EPS": "27.53",
+ "RevenuePerShareTTM": "70.81",
+ "ProfitMargin": "0.4",
+ "OperatingMarginTTM": "0.43",
+ "ReturnOnAssetsTTM": "0.185",
+ "ReturnOnEquityTTM": "0.406",
+ "RevenueTTM": "178803999000",
+ "GrossProfitTTM": "146558992000",
+ "DilutedEPSTTM": "27.53",
+ "QuarterlyEarningsGrowthYOY": "0.384",
+ "QuarterlyRevenueGrowthYOY": "0.216",
+ "AnalystTargetPrice": "844.48",
+ "AnalystRatingStrongBuy": "10",
+ "AnalystRatingBuy": "51",
+ "AnalystRatingHold": "6",
+ "AnalystRatingSell": "0",
+ "AnalystRatingStrongSell": "1",
+ "TrailingPE": "27.24",
+ "ForwardPE": "28.82",
+ "PriceToSalesRatioTTM": "10.54",
+ "PriceToBookRatio": "9.66",
+ "EVToRevenue": "10.55",
+ "EVToEBITDA": "19.26",
+ "Beta": "1.284",
+ "52WeekHigh": "784.75",
+ "52WeekLow": "449.26",
+ "50DayMovingAverage": "699.01",
+ "200DayMovingAverage": "629.11",
+ "SharesOutstanding": "2168960000",
+ "SharesFloat": "2169861000",
+ "PercentInsiders": "0.069",
+ "PercentInstitutions": "80.066",
+ "DividendDate": "2025-06-26",
+ "ExDividendDate": "2025-06-16"
+}
+
+📈 获取财报数据...
+
+============================================================
+META - 财报数据
+============================================================
+{
+ "symbol": "META",
+ "annualEarnings": [
+ {
+ "fiscalDateEnding": "2025-06-30",
+ "reportedEPS": "13.57"
+ },
+ {
+ "fiscalDateEnding": "2024-12-31",
+ "reportedEPS": "23.92"
+ },
+ {
+ "fiscalDateEnding": "2023-12-31",
+ "reportedEPS": "14.9"
+ },
+ {
+ "fiscalDateEnding": "2022-12-31",
+ "reportedEPS": "8.58"
+ },
+ {
+ "fiscalDateEnding": "2021-12-31",
+ "reportedEPS": "13.8"
+ },
+ {
+ "fiscalDateEnding": "2020-12-31",
+ "reportedEPS": "9.79"
+ },
+ {
+ "fiscalDateEnding": "2019-12-31",
+ "reportedEPS": "6.44"
+ },
+ {
+ "fiscalDateEnding": "2018-12-31",
+ "reportedEPS": "7.57"
+ },
+ {
+ "fiscalDateEnding": "2017-12-31",
+ "reportedEPS": "5.71"
+ },
+ {
+ "fiscalDateEnding": "2016-12-31",
+ "reportedEPS": "3.51"
+ },
+ {
+ "fiscalDateEnding": "2015-12-31",
+ "reportedEPS": "1.77"
+ },
+ {
+ "fiscalDateEnding": "2014-12-31",
+ "reportedEPS": "1.31"
+ },
+ {
+ "fiscalDateEnding": "2013-12-31",
+ "reportedEPS": "0.65"
+ },
+ {
+ "fiscalDateEnding": "2012-12-31",
+ "reportedEPS": "0.1945"
+ }
+ ],
+ "quarterlyEarnings": [
+ {
+ "fiscalDateEnding": "2025-06-30",
+ "reportedDate": "2025-07-30",
+ "reportedEPS": "7.14",
+ "estimatedEPS": "5.89",
+ "surprise": "1.25",
+ "surprisePercentage": "21.2224",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2025-03-31",
+ "reportedDate": "2025-04-30",
+ "reportedEPS": "6.43",
+ "estimatedEPS": "5.22",
+ "surprise": "1.21",
+ "surprisePercentage": "23.1801",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2024-12-31",
+ "reportedDate": "2025-01-29",
+ "reportedEPS": "8.02",
+ "estimatedEPS": "6.68",
+ "surprise": "1.34",
+ "surprisePercentage": "20.0599",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2024-09-30",
+ "reportedDate": "2024-10-30",
+ "reportedEPS": "6.03",
+ "estimatedEPS": "5.3",
+ "surprise": "0.73",
+ "surprisePercentage": "13.7736",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2024-06-30",
+ "reportedDate": "2024-07-31",
+ "reportedEPS": "5.16",
+ "estimatedEPS": "4.76",
+ "surprise": "0.4",
+ "surprisePercentage": "8.4034",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2024-03-31",
+ "reportedDate": "2024-04-24",
+ "reportedEPS": "4.71",
+ "estimatedEPS": "4.32",
+ "surprise": "0.39",
+ "surprisePercentage": "9.0278",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2023-12-31",
+ "reportedDate": "2024-02-01",
+ "reportedEPS": "5.33",
+ "estimatedEPS": "4.96",
+ "surprise": "0.37",
+ "surprisePercentage": "7.4597",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2023-09-30",
+ "reportedDate": "2023-10-25",
+ "reportedEPS": "4.39",
+ "estimatedEPS": "3.6",
+ "surprise": "0.79",
+ "surprisePercentage": "21.9444",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2023-06-30",
+ "reportedDate": "2023-07-26",
+ "reportedEPS": "2.98",
+ "estimatedEPS": "2.87",
+ "surprise": "0.11",
+ "surprisePercentage": "3.8328",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2023-03-31",
+ "reportedDate": "2023-04-26",
+ "reportedEPS": "2.2",
+ "estimatedEPS": "1.95",
+ "surprise": "0.25",
+ "surprisePercentage": "12.8205",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2022-12-31",
+ "reportedDate": "2023-02-01",
+ "reportedEPS": "1.76",
+ "estimatedEPS": "2.23",
+ "surprise": "-0.47",
+ "surprisePercentage": "-21.0762",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2022-09-30",
+ "reportedDate": "2022-10-26",
+ "reportedEPS": "1.64",
+ "estimatedEPS": "1.86",
+ "surprise": "-0.22",
+ "surprisePercentage": "-11.828",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2022-06-30",
+ "reportedDate": "2022-07-27",
+ "reportedEPS": "2.46",
+ "estimatedEPS": "2.55",
+ "surprise": "-0.09",
+ "surprisePercentage": "-3.5294",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2022-03-31",
+ "reportedDate": "2022-04-27",
+ "reportedEPS": "2.72",
+ "estimatedEPS": "2.55",
+ "surprise": "0.17",
+ "surprisePercentage": "6.6667",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2021-12-31",
+ "reportedDate": "2022-02-02",
+ "reportedEPS": "3.67",
+ "estimatedEPS": "3.83",
+ "surprise": "-0.16",
+ "surprisePercentage": "-4.1775",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2021-09-30",
+ "reportedDate": "2021-10-25",
+ "reportedEPS": "3.22",
+ "estimatedEPS": "3.17",
+ "surprise": "0.05",
+ "surprisePercentage": "1.5773",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2021-06-30",
+ "reportedDate": "2021-07-28",
+ "reportedEPS": "3.61",
+ "estimatedEPS": "3.01",
+ "surprise": "0.6",
+ "surprisePercentage": "19.9336",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2021-03-31",
+ "reportedDate": "2021-04-28",
+ "reportedEPS": "3.3",
+ "estimatedEPS": "2.35",
+ "surprise": "0.95",
+ "surprisePercentage": "40.4255",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2020-12-31",
+ "reportedDate": "2021-01-27",
+ "reportedEPS": "3.88",
+ "estimatedEPS": "3.24",
+ "surprise": "0.64",
+ "surprisePercentage": "19.7531",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2020-09-30",
+ "reportedDate": "2020-10-29",
+ "reportedEPS": "2.4",
+ "estimatedEPS": "1.91",
+ "surprise": "0.49",
+ "surprisePercentage": "25.6545",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2020-06-30",
+ "reportedDate": "2020-07-30",
+ "reportedEPS": "1.8",
+ "estimatedEPS": "1.37",
+ "surprise": "0.43",
+ "surprisePercentage": "31.3869",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2020-03-31",
+ "reportedDate": "2020-04-29",
+ "reportedEPS": "1.71",
+ "estimatedEPS": "1.7",
+ "surprise": "0.01",
+ "surprisePercentage": "0.5882",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2019-12-31",
+ "reportedDate": "2020-01-29",
+ "reportedEPS": "2.56",
+ "estimatedEPS": "2.53",
+ "surprise": "0.03",
+ "surprisePercentage": "1.1858",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2019-09-30",
+ "reportedDate": "2019-10-30",
+ "reportedEPS": "2.12",
+ "estimatedEPS": "1.88",
+ "surprise": "0.24",
+ "surprisePercentage": "12.766",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2019-06-30",
+ "reportedDate": "2019-07-24",
+ "reportedEPS": "0.91",
+ "estimatedEPS": "1.85",
+ "surprise": "-0.94",
+ "surprisePercentage": "-50.8108",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2019-03-31",
+ "reportedDate": "2019-04-24",
+ "reportedEPS": "0.85",
+ "estimatedEPS": "1.61",
+ "surprise": "-0.76",
+ "surprisePercentage": "-47.205",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2018-12-31",
+ "reportedDate": "2019-01-30",
+ "reportedEPS": "2.38",
+ "estimatedEPS": "2.18",
+ "surprise": "0.2",
+ "surprisePercentage": "9.1743",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2018-09-30",
+ "reportedDate": "2018-10-30",
+ "reportedEPS": "1.76",
+ "estimatedEPS": "1.44",
+ "surprise": "0.32",
+ "surprisePercentage": "22.2222",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2018-06-30",
+ "reportedDate": "2018-07-25",
+ "reportedEPS": "1.74",
+ "estimatedEPS": "1.71",
+ "surprise": "0.03",
+ "surprisePercentage": "1.7544",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2018-03-31",
+ "reportedDate": "2018-04-25",
+ "reportedEPS": "1.69",
+ "estimatedEPS": "1.35",
+ "surprise": "0.34",
+ "surprisePercentage": "25.1852",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2017-12-31",
+ "reportedDate": "2018-01-31",
+ "reportedEPS": "1.44",
+ "estimatedEPS": "1.94",
+ "surprise": "-0.5",
+ "surprisePercentage": "-25.7732",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2017-09-30",
+ "reportedDate": "2017-11-01",
+ "reportedEPS": "1.59",
+ "estimatedEPS": "1.28",
+ "surprise": "0.31",
+ "surprisePercentage": "24.2188",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2017-06-30",
+ "reportedDate": "2017-07-26",
+ "reportedEPS": "1.32",
+ "estimatedEPS": "1.12",
+ "surprise": "0.2",
+ "surprisePercentage": "17.8571",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2017-03-31",
+ "reportedDate": "2017-05-04",
+ "reportedEPS": "1.36",
+ "estimatedEPS": "1.12",
+ "surprise": "0.24",
+ "surprisePercentage": "21.4286",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2016-12-31",
+ "reportedDate": "2017-02-01",
+ "reportedEPS": "1.21",
+ "estimatedEPS": "1.04",
+ "surprise": "0.17",
+ "surprisePercentage": "16.3462",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2016-09-30",
+ "reportedDate": "2016-11-02",
+ "reportedEPS": "0.82",
+ "estimatedEPS": "0.71",
+ "surprise": "0.11",
+ "surprisePercentage": "15.493",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2016-06-30",
+ "reportedDate": "2016-07-27",
+ "reportedEPS": "0.71",
+ "estimatedEPS": "0.57",
+ "surprise": "0.14",
+ "surprisePercentage": "24.5614",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2016-03-31",
+ "reportedDate": "2016-04-27",
+ "reportedEPS": "0.77",
+ "estimatedEPS": "0.62",
+ "surprise": "0.15",
+ "surprisePercentage": "24.1935",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2015-12-31",
+ "reportedDate": "2016-01-27",
+ "reportedEPS": "0.79",
+ "estimatedEPS": "0.68",
+ "surprise": "0.11",
+ "surprisePercentage": "16.1765",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2015-09-30",
+ "reportedDate": "2015-11-04",
+ "reportedEPS": "0.31",
+ "estimatedEPS": "0.27",
+ "surprise": "0.04",
+ "surprisePercentage": "14.8148",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2015-06-30",
+ "reportedDate": "2015-07-29",
+ "reportedEPS": "0.25",
+ "estimatedEPS": "0.24",
+ "surprise": "0.01",
+ "surprisePercentage": "4.1667",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2015-03-31",
+ "reportedDate": "2015-04-22",
+ "reportedEPS": "0.42",
+ "estimatedEPS": "0.4",
+ "surprise": "0.02",
+ "surprisePercentage": "5",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2014-12-31",
+ "reportedDate": "2015-01-28",
+ "reportedEPS": "0.25",
+ "estimatedEPS": "0.23",
+ "surprise": "0.02",
+ "surprisePercentage": "8.6957",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2014-09-30",
+ "reportedDate": "2014-10-28",
+ "reportedEPS": "0.42",
+ "estimatedEPS": "0.4",
+ "surprise": "0.02",
+ "surprisePercentage": "5",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2014-06-30",
+ "reportedDate": "2014-07-23",
+ "reportedEPS": "0.3",
+ "estimatedEPS": "0.24",
+ "surprise": "0.06",
+ "surprisePercentage": "25",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2014-03-31",
+ "reportedDate": "2014-04-23",
+ "reportedEPS": "0.34",
+ "estimatedEPS": "0.24",
+ "surprise": "0.1",
+ "surprisePercentage": "41.6667",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2013-12-31",
+ "reportedDate": "2014-01-29",
+ "reportedEPS": "0.2",
+ "estimatedEPS": "0.2",
+ "surprise": "0",
+ "surprisePercentage": "0",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2013-09-30",
+ "reportedDate": "2013-10-30",
+ "reportedEPS": "0.17",
+ "estimatedEPS": "0.12",
+ "surprise": "0.05",
+ "surprisePercentage": "41.6667",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2013-06-30",
+ "reportedDate": "2013-07-24",
+ "reportedEPS": "0.19",
+ "estimatedEPS": "0.14",
+ "surprise": "0.05",
+ "surprisePercentage": "35.7143",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2013-03-31",
+ "reportedDate": "2013-05-01",
+ "reportedEPS": "0.09",
+ "estimatedEPS": "0.08",
+ "surprise": "0.01",
+ "surprisePercentage": "12.5",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2012-12-31",
+ "reportedDate": "2013-01-30",
+ "reportedEPS": "0.03",
+ "estimatedEPS": "-0.01",
+ "surprise": "0.04",
+ "surprisePercentage": "400",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2012-09-30",
+ "reportedDate": "2012-10-23",
+ "reportedEPS": "-0.02",
+ "estimatedEPS": "0.06",
+ "surprise": "-0.08",
+ "surprisePercentage": "-133.3333",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2012-06-30",
+ "reportedDate": "2012-07-26",
+ "reportedEPS": "0.12",
+ "estimatedEPS": "0.11",
+ "surprise": "0.01",
+ "surprisePercentage": "9.0909",
+ "reportTime": "post-market"
+ },
+ {
+ "fiscalDateEnding": "2012-03-31",
+ "reportedDate": "2012-05-30",
+ "reportedEPS": "0.0645",
+ "estimatedEPS": "None",
+ "surprise": "0",
+ "surprisePercentage": "None",
+ "reportTime": "pre-market"
+ }
+ ]
+}
+
+⭐ 获取分析师评级...
+
+============================================================
+META - 分析师评级
+============================================================
+❌ 错误: This API function (ANALYST_RECOMMENDATIONS) does not exist.
+
+💰 获取损益表...
+
+============================================================
+META - 损益表
+============================================================
+{
+ "symbol": "META",
+ "annualReports": [
+ {
+ "fiscalDateEnding": "2024-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "134340000000",
+ "totalRevenue": "164501000000",
+ "costOfRevenue": "30161000000",
+ "costofGoodsAndServicesSold": "30161000000",
+ "operatingIncome": "69380000000",
+ "sellingGeneralAndAdministrative": "9740000000",
+ "researchAndDevelopment": "43873000000",
+ "operatingExpenses": "64960000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "1973000000",
+ "interestIncome": "2517000000",
+ "interestExpense": "715000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "15498000000",
+ "incomeBeforeTax": "70663000000",
+ "incomeTaxExpense": "8303000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "62360000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "71378000000",
+ "ebitda": "86876000000",
+ "netIncome": "62360000000"
+ },
+ {
+ "fiscalDateEnding": "2023-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "108943000000",
+ "totalRevenue": "134902000000",
+ "costOfRevenue": "25959000000",
+ "costofGoodsAndServicesSold": "25959000000",
+ "operatingIncome": "46751000000",
+ "sellingGeneralAndAdministrative": "11408000000",
+ "researchAndDevelopment": "38483000000",
+ "operatingExpenses": "62192000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "677000000",
+ "interestIncome": "1639000000",
+ "interestExpense": "446000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-150000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "10382000000",
+ "incomeBeforeTax": "47428000000",
+ "incomeTaxExpense": "8330000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "29734000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "46751000000",
+ "ebitda": "57133000000",
+ "netIncome": "39098000000"
+ },
+ {
+ "fiscalDateEnding": "2022-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "91360000000",
+ "totalRevenue": "116609000000",
+ "costOfRevenue": "25249000000",
+ "costofGoodsAndServicesSold": "25249000000",
+ "operatingIncome": "28944000000",
+ "sellingGeneralAndAdministrative": "11816000000",
+ "researchAndDevelopment": "35338000000",
+ "operatingExpenses": "62416000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-125000000",
+ "interestIncome": "461000000",
+ "interestExpense": "185000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-320000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "8686000000",
+ "incomeBeforeTax": "28819000000",
+ "incomeTaxExpense": "5619000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "23200000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "28944000000",
+ "ebitda": "37630000000",
+ "netIncome": "23200000000"
+ },
+ {
+ "fiscalDateEnding": "2021-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "95280000000",
+ "totalRevenue": "117929000000",
+ "costOfRevenue": "22649000000",
+ "costofGoodsAndServicesSold": "22649000000",
+ "operatingIncome": "46753000000",
+ "sellingGeneralAndAdministrative": "9829000000",
+ "researchAndDevelopment": "24655000000",
+ "operatingExpenses": "48527000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "531000000",
+ "interestIncome": "484000000",
+ "interestExpense": "461000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "210000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "7967000000",
+ "incomeBeforeTax": "47284000000",
+ "incomeTaxExpense": "7914000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "39370000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "46753000000",
+ "ebitda": "54720000000",
+ "netIncome": "39370000000"
+ },
+ {
+ "fiscalDateEnding": "2020-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "69273000000",
+ "totalRevenue": "85965000000",
+ "costOfRevenue": "16692000000",
+ "costofGoodsAndServicesSold": "16692000000",
+ "operatingIncome": "32671000000",
+ "sellingGeneralAndAdministrative": "6564000000",
+ "researchAndDevelopment": "18447000000",
+ "operatingExpenses": "36602000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "509000000",
+ "interestIncome": "672000000",
+ "interestExpense": "672000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-34000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "6862000000",
+ "incomeBeforeTax": "33180000000",
+ "incomeTaxExpense": "4034000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "29146000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "32671000000",
+ "ebitda": "39533000000",
+ "netIncome": "29146000000"
+ },
+ {
+ "fiscalDateEnding": "2019-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "57927000000",
+ "totalRevenue": "70697000000",
+ "costOfRevenue": "12770000000",
+ "costofGoodsAndServicesSold": "12770000000",
+ "operatingIncome": "23986000000",
+ "sellingGeneralAndAdministrative": "10465000000",
+ "researchAndDevelopment": "13600000000",
+ "operatingExpenses": "33941000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "826000000",
+ "interestIncome": "924000000",
+ "interestExpense": "20000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "27000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "5741000000",
+ "incomeBeforeTax": "24812000000",
+ "incomeTaxExpense": "6327000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "18485000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "23986000000",
+ "ebitda": "29727000000",
+ "netIncome": "18485000000"
+ },
+ {
+ "fiscalDateEnding": "2018-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "46483000000",
+ "totalRevenue": "55838000000",
+ "costOfRevenue": "9355000000",
+ "costofGoodsAndServicesSold": "9355000000",
+ "operatingIncome": "24913000000",
+ "sellingGeneralAndAdministrative": "3451000000",
+ "researchAndDevelopment": "10273000000",
+ "operatingExpenses": "21570000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "448000000",
+ "interestIncome": "661000000",
+ "interestExpense": "9000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-204000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "4315000000",
+ "incomeBeforeTax": "25361000000",
+ "incomeTaxExpense": "3249000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "22112000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "24913000000",
+ "ebitda": "29228000000",
+ "netIncome": "22112000000"
+ },
+ {
+ "fiscalDateEnding": "2017-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "35199000000",
+ "totalRevenue": "40653000000",
+ "costOfRevenue": "5454000000",
+ "costofGoodsAndServicesSold": "5454000000",
+ "operatingIncome": "20203000000",
+ "sellingGeneralAndAdministrative": "2517000000",
+ "researchAndDevelopment": "7754000000",
+ "operatingExpenses": "14996000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "391000000",
+ "interestIncome": "398000000",
+ "interestExpense": "6000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-1000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "3025000000",
+ "incomeBeforeTax": "20594000000",
+ "incomeTaxExpense": "4660000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "15934000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "20203000000",
+ "ebitda": "23228000000",
+ "netIncome": "15934000000"
+ },
+ {
+ "fiscalDateEnding": "2016-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "23849000000",
+ "totalRevenue": "27638000000",
+ "costOfRevenue": "3789000000",
+ "costofGoodsAndServicesSold": "3789000000",
+ "operatingIncome": "12427000000",
+ "sellingGeneralAndAdministrative": "1731000000",
+ "researchAndDevelopment": "5919000000",
+ "operatingExpenses": "11422000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "91000000",
+ "interestIncome": "176000000",
+ "interestExpense": "10000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-75000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2342000000",
+ "incomeBeforeTax": "12518000000",
+ "incomeTaxExpense": "2301000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "10217000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "12427000000",
+ "ebitda": "14769000000",
+ "netIncome": "10217000000"
+ },
+ {
+ "fiscalDateEnding": "2015-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "15061000000",
+ "totalRevenue": "17928000000",
+ "costOfRevenue": "2867000000",
+ "costofGoodsAndServicesSold": "2867000000",
+ "operatingIncome": "6225000000",
+ "sellingGeneralAndAdministrative": "1295000000",
+ "researchAndDevelopment": "4816000000",
+ "operatingExpenses": "8836000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-31000000",
+ "interestIncome": "52000000",
+ "interestExpense": "23000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "6000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1945000000",
+ "incomeBeforeTax": "6194000000",
+ "incomeTaxExpense": "2506000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "3688000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "6225000000",
+ "ebitda": "8170000000",
+ "netIncome": "3688000000"
+ },
+ {
+ "fiscalDateEnding": "2014-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "10313000000",
+ "totalRevenue": "12466000000",
+ "costOfRevenue": "2153000000",
+ "costofGoodsAndServicesSold": "2153000000",
+ "operatingIncome": "4994000000",
+ "sellingGeneralAndAdministrative": "973000000",
+ "researchAndDevelopment": "2666000000",
+ "operatingExpenses": "5319000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-84000000",
+ "interestIncome": "27000000",
+ "interestExpense": "23000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-1000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1243000000",
+ "incomeBeforeTax": "4910000000",
+ "incomeTaxExpense": "1970000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "2940000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "4994000000",
+ "ebitda": "6237000000",
+ "netIncome": "2940000000"
+ },
+ {
+ "fiscalDateEnding": "2013-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "5997000000",
+ "totalRevenue": "7872000000",
+ "costOfRevenue": "1875000000",
+ "costofGoodsAndServicesSold": "1875000000",
+ "operatingIncome": "2804000000",
+ "sellingGeneralAndAdministrative": "781000000",
+ "researchAndDevelopment": "1415000000",
+ "operatingExpenses": "3193000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-50000000",
+ "interestIncome": "19000000",
+ "interestExpense": "56000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "1000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1011000000",
+ "incomeBeforeTax": "2754000000",
+ "incomeTaxExpense": "1254000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "1500000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "2804000000",
+ "ebitda": "3815000000",
+ "netIncome": "1500000000"
+ },
+ {
+ "fiscalDateEnding": "2012-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "3725000000",
+ "totalRevenue": "5089000000",
+ "costOfRevenue": "1364000000",
+ "costofGoodsAndServicesSold": "1364000000",
+ "operatingIncome": "538000000",
+ "sellingGeneralAndAdministrative": "892000000",
+ "researchAndDevelopment": "1399000000",
+ "operatingExpenses": "3187000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-44000000",
+ "interestIncome": "0",
+ "interestExpense": "51000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "7000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "649000000",
+ "incomeBeforeTax": "494000000",
+ "incomeTaxExpense": "441000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "53000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "538000000",
+ "ebitda": "1187000000",
+ "netIncome": "53000000"
+ },
+ {
+ "fiscalDateEnding": "2011-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "2851000000",
+ "totalRevenue": "3711000000",
+ "costOfRevenue": "860000000",
+ "costofGoodsAndServicesSold": "860000000",
+ "operatingIncome": "1756000000",
+ "sellingGeneralAndAdministrative": "280000000",
+ "researchAndDevelopment": "388000000",
+ "operatingExpenses": "1095000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-61000000",
+ "interestIncome": "0",
+ "interestExpense": "42000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-19000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "323000000",
+ "incomeBeforeTax": "1695000000",
+ "incomeTaxExpense": "695000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "None",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1756000000",
+ "ebitda": "2079000000",
+ "netIncome": "1000000000"
+ },
+ {
+ "fiscalDateEnding": "2010-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "1481000000",
+ "totalRevenue": "1974000000",
+ "costOfRevenue": "493000000",
+ "costofGoodsAndServicesSold": "493000000",
+ "operatingIncome": "1032000000",
+ "sellingGeneralAndAdministrative": "138000000",
+ "researchAndDevelopment": "144000000",
+ "operatingExpenses": "449000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-24000000",
+ "interestIncome": "0",
+ "interestExpense": "22000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-2000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "139000000",
+ "incomeBeforeTax": "1008000000",
+ "incomeTaxExpense": "402000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "None",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1032000000",
+ "ebitda": "1171000000",
+ "netIncome": "606000000"
+ },
+ {
+ "fiscalDateEnding": "2009-12-31",
+ "reportedCurrency": "None",
+ "grossProfit": "554000000",
+ "totalRevenue": "777000000",
+ "costOfRevenue": "223000000",
+ "costofGoodsAndServicesSold": "223000000",
+ "operatingIncome": "262000000",
+ "sellingGeneralAndAdministrative": "205000000",
+ "researchAndDevelopment": "87000000",
+ "operatingExpenses": "292000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "10000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "78000000",
+ "incomeBeforeTax": "254000000",
+ "incomeTaxExpense": "25000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "None",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "264000000",
+ "ebitda": "342000000",
+ "netIncome": "122000000"
+ },
+ {
+ "fiscalDateEnding": "2008-12-31",
+ "reportedCurrency": "None",
+ "grossProfit": "148000000",
+ "totalRevenue": "272000000",
+ "costOfRevenue": "124000000",
+ "costofGoodsAndServicesSold": "124000000",
+ "operatingIncome": "-55000000",
+ "sellingGeneralAndAdministrative": "156000000",
+ "researchAndDevelopment": "47000000",
+ "operatingExpenses": "203000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "1000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "None",
+ "incomeBeforeTax": "-56000000",
+ "incomeTaxExpense": "None",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "None",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "None",
+ "ebitda": "-55000000",
+ "netIncome": "-56000000"
+ },
+ {
+ "fiscalDateEnding": "2007-12-31",
+ "reportedCurrency": "None",
+ "grossProfit": "112000000",
+ "totalRevenue": "153000000",
+ "costOfRevenue": "41000000",
+ "costofGoodsAndServicesSold": "41000000",
+ "operatingIncome": "-124000000",
+ "sellingGeneralAndAdministrative": "155000000",
+ "researchAndDevelopment": "81000000",
+ "operatingExpenses": "236000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "11000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "None",
+ "incomeBeforeTax": "-135000000",
+ "incomeTaxExpense": "3000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "None",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "None",
+ "ebitda": "-124000000",
+ "netIncome": "-138000000"
+ }
+ ],
+ "quarterlyReports": [
+ {
+ "fiscalDateEnding": "2025-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "39025000000",
+ "totalRevenue": "47516000000",
+ "costOfRevenue": "8491000000",
+ "costofGoodsAndServicesSold": "8491000000",
+ "operatingIncome": "20441000000",
+ "sellingGeneralAndAdministrative": "2663000000",
+ "researchAndDevelopment": "12942000000",
+ "operatingExpenses": "18584000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-103000000",
+ "interestIncome": "481000000",
+ "interestExpense": "241000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "4342000000",
+ "incomeBeforeTax": "20534000000",
+ "incomeTaxExpense": "2197000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "18337000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "20534000000",
+ "ebitda": "24876000000",
+ "netIncome": "18337000000"
+ },
+ {
+ "fiscalDateEnding": "2025-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "34742000000",
+ "totalRevenue": "42314000000",
+ "costOfRevenue": "7572000000",
+ "costofGoodsAndServicesSold": "7572000000",
+ "operatingIncome": "17555000000",
+ "sellingGeneralAndAdministrative": "2280000000",
+ "researchAndDevelopment": "12150000000",
+ "operatingExpenses": "17187000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "595000000",
+ "interestIncome": "658000000",
+ "interestExpense": "240000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "3900000000",
+ "incomeBeforeTax": "18382000000",
+ "incomeTaxExpense": "1738000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "16644000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "18622000000",
+ "ebitda": "22522000000",
+ "netIncome": "16644000000"
+ },
+ {
+ "fiscalDateEnding": "2024-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "39546000000",
+ "totalRevenue": "48385000000",
+ "costOfRevenue": "8839000000",
+ "costofGoodsAndServicesSold": "8839000000",
+ "operatingIncome": "23364000000",
+ "sellingGeneralAndAdministrative": "762000000",
+ "researchAndDevelopment": "12180000000",
+ "operatingExpenses": "16182000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "573000000",
+ "interestIncome": "731000000",
+ "interestExpense": "251000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "4460000000",
+ "incomeBeforeTax": "23552000000",
+ "incomeTaxExpense": "2714000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "20838000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "23803000000",
+ "ebitda": "28263000000",
+ "netIncome": "20838000000"
+ },
+ {
+ "fiscalDateEnding": "2024-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "33214000000",
+ "totalRevenue": "40589000000",
+ "costOfRevenue": "7375000000",
+ "costofGoodsAndServicesSold": "7375000000",
+ "operatingIncome": "17350000000",
+ "sellingGeneralAndAdministrative": "1865000000",
+ "researchAndDevelopment": "11177000000",
+ "operatingExpenses": "15864000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "461000000",
+ "interestIncome": "661000000",
+ "interestExpense": "208000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "4027000000",
+ "incomeBeforeTax": "17822000000",
+ "incomeTaxExpense": "2134000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "15688000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "18030000000",
+ "ebitda": "22057000000",
+ "netIncome": "15688000000"
+ },
+ {
+ "fiscalDateEnding": "2024-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "31763000000",
+ "totalRevenue": "39071000000",
+ "costOfRevenue": "7308000000",
+ "costofGoodsAndServicesSold": "7308000000",
+ "operatingIncome": "14847000000",
+ "sellingGeneralAndAdministrative": "3658000000",
+ "researchAndDevelopment": "10537000000",
+ "operatingExpenses": "16916000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "427000000",
+ "interestIncome": "540000000",
+ "interestExpense": "128000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "3637000000",
+ "incomeBeforeTax": "15106000000",
+ "incomeTaxExpense": "1641000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "13465000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "15234000000",
+ "ebitda": "18871000000",
+ "netIncome": "13465000000"
+ },
+ {
+ "fiscalDateEnding": "2024-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "29815000000",
+ "totalRevenue": "36455000000",
+ "costOfRevenue": "6640000000",
+ "costofGoodsAndServicesSold": "6640000000",
+ "operatingIncome": "13818000000",
+ "sellingGeneralAndAdministrative": "3455000000",
+ "researchAndDevelopment": "9978000000",
+ "operatingExpenses": "15997000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "513000000",
+ "interestIncome": "585000000",
+ "interestExpense": "127000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "3374000000",
+ "incomeBeforeTax": "14183000000",
+ "incomeTaxExpense": "1814000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "12369000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "14310000000",
+ "ebitda": "17684000000",
+ "netIncome": "12369000000"
+ },
+ {
+ "fiscalDateEnding": "2023-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "32416000000",
+ "totalRevenue": "40111000000",
+ "costOfRevenue": "7695000000",
+ "costofGoodsAndServicesSold": "7695000000",
+ "operatingIncome": "16384000000",
+ "sellingGeneralAndAdministrative": "2289000000",
+ "researchAndDevelopment": "10517000000",
+ "operatingExpenses": "16032000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "484000000",
+ "interestIncome": "588000000",
+ "interestExpense": "424000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "3172000000",
+ "incomeBeforeTax": "16808000000",
+ "incomeTaxExpense": "2791000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "14017000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "16384000000",
+ "ebitda": "19556000000",
+ "netIncome": "14017000000"
+ },
+ {
+ "fiscalDateEnding": "2023-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "27936000000",
+ "totalRevenue": "34146000000",
+ "costOfRevenue": "6210000000",
+ "costofGoodsAndServicesSold": "6210000000",
+ "operatingIncome": "13748000000",
+ "sellingGeneralAndAdministrative": "2070000000",
+ "researchAndDevelopment": "9241000000",
+ "operatingExpenses": "14188000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "370000000",
+ "interestIncome": "534000000",
+ "interestExpense": "139000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2859000000",
+ "incomeBeforeTax": "14020000000",
+ "incomeTaxExpense": "2437000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "11583000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "13748000000",
+ "ebitda": "16607000000",
+ "netIncome": "11583000000"
+ },
+ {
+ "fiscalDateEnding": "2023-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "26054000000",
+ "totalRevenue": "31999000000",
+ "costOfRevenue": "5945000000",
+ "costofGoodsAndServicesSold": "5945000000",
+ "operatingIncome": "9392000000",
+ "sellingGeneralAndAdministrative": "4164000000",
+ "researchAndDevelopment": "9344000000",
+ "operatingExpenses": "16662000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-99000000",
+ "interestIncome": "323000000",
+ "interestExpense": "116000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-99000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2623000000",
+ "incomeBeforeTax": "9293000000",
+ "incomeTaxExpense": "1505000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "7788000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "9392000000",
+ "ebitda": "12015000000",
+ "netIncome": "7788000000"
+ },
+ {
+ "fiscalDateEnding": "2023-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "22537000000",
+ "totalRevenue": "28645000000",
+ "costOfRevenue": "6108000000",
+ "costofGoodsAndServicesSold": "6108000000",
+ "operatingIncome": "7227000000",
+ "sellingGeneralAndAdministrative": "2885000000",
+ "researchAndDevelopment": "9381000000",
+ "operatingExpenses": "15310000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "80000000",
+ "interestIncome": "193000000",
+ "interestExpense": "55000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "80000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2524000000",
+ "incomeBeforeTax": "7307000000",
+ "incomeTaxExpense": "1598000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "5709000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "7227000000",
+ "ebitda": "9751000000",
+ "netIncome": "5709000000"
+ },
+ {
+ "fiscalDateEnding": "2022-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "23829000000",
+ "totalRevenue": "32165000000",
+ "costOfRevenue": "8336000000",
+ "costofGoodsAndServicesSold": "8336000000",
+ "operatingIncome": "6399000000",
+ "sellingGeneralAndAdministrative": "3085000000",
+ "researchAndDevelopment": "9771000000",
+ "operatingExpenses": "17430000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "32000000",
+ "interestIncome": "32000000",
+ "interestExpense": "32000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-249000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2376000000",
+ "incomeBeforeTax": "6149000000",
+ "incomeTaxExpense": "1497000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4653000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "6399000000",
+ "ebitda": "8775000000",
+ "netIncome": "4652000000"
+ },
+ {
+ "fiscalDateEnding": "2022-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "21998000000",
+ "totalRevenue": "27714000000",
+ "costOfRevenue": "5716000000",
+ "costofGoodsAndServicesSold": "5716000000",
+ "operatingIncome": "5664000000",
+ "sellingGeneralAndAdministrative": "3384000000",
+ "researchAndDevelopment": "9170000000",
+ "operatingExpenses": "16334000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "-88000000",
+ "interestIncome": "77000000",
+ "interestExpense": "77000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-88000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2175000000",
+ "incomeBeforeTax": "5576000000",
+ "incomeTaxExpense": "1181000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4395000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5664000000",
+ "ebitda": "7839000000",
+ "netIncome": "4395000000"
+ },
+ {
+ "fiscalDateEnding": "2022-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "23630000000",
+ "totalRevenue": "28822000000",
+ "costOfRevenue": "5192000000",
+ "costofGoodsAndServicesSold": "5192000000",
+ "operatingIncome": "8358000000",
+ "sellingGeneralAndAdministrative": "2987000000",
+ "researchAndDevelopment": "8690000000",
+ "operatingExpenses": "15272000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "91000000",
+ "interestIncome": "91000000",
+ "interestExpense": "91000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-172000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1979000000",
+ "incomeBeforeTax": "8186000000",
+ "incomeTaxExpense": "1499000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "6687000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "8358000000",
+ "ebitda": "10337000000",
+ "netIncome": "6687000000"
+ },
+ {
+ "fiscalDateEnding": "2022-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "21903000000",
+ "totalRevenue": "27908000000",
+ "costOfRevenue": "6005000000",
+ "costofGoodsAndServicesSold": "6005000000",
+ "operatingIncome": "8524000000",
+ "sellingGeneralAndAdministrative": "2360000000",
+ "researchAndDevelopment": "7707000000",
+ "operatingExpenses": "13379000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "384000000",
+ "interestIncome": "384000000",
+ "interestExpense": "76000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "384000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2156000000",
+ "incomeBeforeTax": "8908000000",
+ "incomeTaxExpense": "1443000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "7465000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "8524000000",
+ "ebitda": "10680000000",
+ "netIncome": "7465000000"
+ },
+ {
+ "fiscalDateEnding": "2021-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "27323000000",
+ "totalRevenue": "33671000000",
+ "costOfRevenue": "6348000000",
+ "costofGoodsAndServicesSold": "6348000000",
+ "operatingIncome": "12585000000",
+ "sellingGeneralAndAdministrative": "3305000000",
+ "researchAndDevelopment": "7046000000",
+ "operatingExpenses": "14738000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "117000000",
+ "interestIncome": "117000000",
+ "interestExpense": "102000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "118000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "2014000000",
+ "incomeBeforeTax": "12702000000",
+ "incomeTaxExpense": "2417000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "10285000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "12585000000",
+ "ebitda": "14599000000",
+ "netIncome": "10285000000"
+ },
+ {
+ "fiscalDateEnding": "2021-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "23239000000",
+ "totalRevenue": "29010000000",
+ "costOfRevenue": "5771000000",
+ "costofGoodsAndServicesSold": "5771000000",
+ "operatingIncome": "10423000000",
+ "sellingGeneralAndAdministrative": "2946000000",
+ "researchAndDevelopment": "6316000000",
+ "operatingExpenses": "12816000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "120000000",
+ "interestIncome": "120000000",
+ "interestExpense": "120000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "142000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1995000000",
+ "incomeBeforeTax": "10565000000",
+ "incomeTaxExpense": "1371000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "9194000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "10423000000",
+ "ebitda": "12418000000",
+ "netIncome": "9194000000"
+ },
+ {
+ "fiscalDateEnding": "2021-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "23678000000",
+ "totalRevenue": "29077000000",
+ "costOfRevenue": "5399000000",
+ "costofGoodsAndServicesSold": "5399000000",
+ "operatingIncome": "12367000000",
+ "sellingGeneralAndAdministrative": "1956000000",
+ "researchAndDevelopment": "6096000000",
+ "operatingExpenses": "11311000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "146000000",
+ "interestIncome": "121000000",
+ "interestExpense": "121000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "146000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1985000000",
+ "incomeBeforeTax": "12513000000",
+ "incomeTaxExpense": "2119000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "10394000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "12367000000",
+ "ebitda": "14352000000",
+ "netIncome": "10394000000"
+ },
+ {
+ "fiscalDateEnding": "2021-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "21040000000",
+ "totalRevenue": "26171000000",
+ "costOfRevenue": "5131000000",
+ "costofGoodsAndServicesSold": "5131000000",
+ "operatingIncome": "11378000000",
+ "sellingGeneralAndAdministrative": "1622000000",
+ "researchAndDevelopment": "5197000000",
+ "operatingExpenses": "9662000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "125000000",
+ "interestIncome": "118000000",
+ "interestExpense": "118000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "125000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1972000000",
+ "incomeBeforeTax": "11503000000",
+ "incomeTaxExpense": "2006000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "9497000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "11378000000",
+ "ebitda": "13350000000",
+ "netIncome": "9497000000"
+ },
+ {
+ "fiscalDateEnding": "2020-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "22862000000",
+ "totalRevenue": "28072000000",
+ "costOfRevenue": "5210000000",
+ "costofGoodsAndServicesSold": "5210000000",
+ "operatingIncome": "12775000000",
+ "sellingGeneralAndAdministrative": "1599000000",
+ "researchAndDevelopment": "5208000000",
+ "operatingExpenses": "10087000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "280000000",
+ "interestIncome": "136000000",
+ "interestExpense": "136000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "280000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1863000000",
+ "incomeBeforeTax": "13055000000",
+ "incomeTaxExpense": "1836000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "11220000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "12775000000",
+ "ebitda": "14638000000",
+ "netIncome": "11219000000"
+ },
+ {
+ "fiscalDateEnding": "2020-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "17276000000",
+ "totalRevenue": "21470000000",
+ "costOfRevenue": "4194000000",
+ "costofGoodsAndServicesSold": "4194000000",
+ "operatingIncome": "8040000000",
+ "sellingGeneralAndAdministrative": "1790000000",
+ "researchAndDevelopment": "4763000000",
+ "operatingExpenses": "9236000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "146000000",
+ "interestIncome": "146000000",
+ "interestExpense": "146000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "93000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1698000000",
+ "incomeBeforeTax": "8133000000",
+ "incomeTaxExpense": "287000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "7846000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "8040000000",
+ "ebitda": "9738000000",
+ "netIncome": "7846000000"
+ },
+ {
+ "fiscalDateEnding": "2020-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "14858000000",
+ "totalRevenue": "18687000000",
+ "costOfRevenue": "3829000000",
+ "costofGoodsAndServicesSold": "3829000000",
+ "operatingIncome": "5963000000",
+ "sellingGeneralAndAdministrative": "1593000000",
+ "researchAndDevelopment": "4462000000",
+ "operatingExpenses": "8895000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "162000000",
+ "interestIncome": "162000000",
+ "interestExpense": "162000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "168000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1704000000",
+ "incomeBeforeTax": "6131000000",
+ "incomeTaxExpense": "953000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "5178000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5963000000",
+ "ebitda": "7667000000",
+ "netIncome": "5178000000"
+ },
+ {
+ "fiscalDateEnding": "2020-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "14278000000",
+ "totalRevenue": "17737000000",
+ "costOfRevenue": "3459000000",
+ "costofGoodsAndServicesSold": "3459000000",
+ "operatingIncome": "5893000000",
+ "sellingGeneralAndAdministrative": "1583000000",
+ "researchAndDevelopment": "4015000000",
+ "operatingExpenses": "8385000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "228000000",
+ "interestIncome": "228000000",
+ "interestExpense": "228000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-32000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1597000000",
+ "incomeBeforeTax": "5861000000",
+ "incomeTaxExpense": "959000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4902000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5893000000",
+ "ebitda": "7490000000",
+ "netIncome": "4902000000"
+ },
+ {
+ "fiscalDateEnding": "2019-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "17590000000",
+ "totalRevenue": "21082000000",
+ "costOfRevenue": "3492000000",
+ "costofGoodsAndServicesSold": "3492000000",
+ "operatingIncome": "8858000000",
+ "sellingGeneralAndAdministrative": "1829000000",
+ "researchAndDevelopment": "3877000000",
+ "operatingExpenses": "8732000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "229000000",
+ "interestIncome": "249000000",
+ "interestExpense": "229000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "311000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1468000000",
+ "incomeBeforeTax": "9169000000",
+ "incomeTaxExpense": "1820000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "7349000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "8858000000",
+ "ebitda": "10326000000",
+ "netIncome": "7349000000"
+ },
+ {
+ "fiscalDateEnding": "2019-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "14497000000",
+ "totalRevenue": "17652000000",
+ "costOfRevenue": "3155000000",
+ "costofGoodsAndServicesSold": "3155000000",
+ "operatingIncome": "7185000000",
+ "sellingGeneralAndAdministrative": "1348000000",
+ "researchAndDevelopment": "3548000000",
+ "operatingExpenses": "7312000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "258000000",
+ "interestIncome": "258000000",
+ "interestExpense": "258000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "144000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1416000000",
+ "incomeBeforeTax": "7329000000",
+ "incomeTaxExpense": "1238000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "6091000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "7185000000",
+ "ebitda": "8601000000",
+ "netIncome": "6091000000"
+ },
+ {
+ "fiscalDateEnding": "2019-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "13579000000",
+ "totalRevenue": "16886000000",
+ "costOfRevenue": "3307000000",
+ "costofGoodsAndServicesSold": "3307000000",
+ "operatingIncome": "4626000000",
+ "sellingGeneralAndAdministrative": "3224000000",
+ "researchAndDevelopment": "3315000000",
+ "operatingExpenses": "8953000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "219000000",
+ "interestIncome": "219000000",
+ "interestExpense": "219000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "206000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1502000000",
+ "incomeBeforeTax": "4832000000",
+ "incomeTaxExpense": "2216000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "2616000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "4626000000",
+ "ebitda": "6128000000",
+ "netIncome": "2616000000"
+ },
+ {
+ "fiscalDateEnding": "2019-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "12261000000",
+ "totalRevenue": "15077000000",
+ "costOfRevenue": "2816000000",
+ "costofGoodsAndServicesSold": "2816000000",
+ "operatingIncome": "3317000000",
+ "sellingGeneralAndAdministrative": "4064000000",
+ "researchAndDevelopment": "2860000000",
+ "operatingExpenses": "8944000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "198000000",
+ "interestIncome": "198000000",
+ "interestExpense": "198000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "165000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1355000000",
+ "incomeBeforeTax": "3482000000",
+ "incomeTaxExpense": "1053000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "2429000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "3317000000",
+ "ebitda": "4672000000",
+ "netIncome": "2429000000"
+ },
+ {
+ "fiscalDateEnding": "2018-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "14118000000",
+ "totalRevenue": "16914000000",
+ "costOfRevenue": "2796000000",
+ "costofGoodsAndServicesSold": "2796000000",
+ "operatingIncome": "7820000000",
+ "sellingGeneralAndAdministrative": "976000000",
+ "researchAndDevelopment": "2855000000",
+ "operatingExpenses": "6298000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "187000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "151000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1225000000",
+ "incomeBeforeTax": "7971000000",
+ "incomeTaxExpense": "1089000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "6881000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "7820000000",
+ "ebitda": "9045000000",
+ "netIncome": "6882000000"
+ },
+ {
+ "fiscalDateEnding": "2018-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "11309000000",
+ "totalRevenue": "13727000000",
+ "costOfRevenue": "2418000000",
+ "costofGoodsAndServicesSold": "2418000000",
+ "operatingIncome": "5781000000",
+ "sellingGeneralAndAdministrative": "943000000",
+ "researchAndDevelopment": "2657000000",
+ "operatingExpenses": "5528000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "176000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "131000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1107000000",
+ "incomeBeforeTax": "5912000000",
+ "incomeTaxExpense": "775000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "5137000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5781000000",
+ "ebitda": "6888000000",
+ "netIncome": "5137000000"
+ },
+ {
+ "fiscalDateEnding": "2018-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "11017000000",
+ "totalRevenue": "13231000000",
+ "costOfRevenue": "2214000000",
+ "costofGoodsAndServicesSold": "2214000000",
+ "operatingIncome": "5863000000",
+ "sellingGeneralAndAdministrative": "776000000",
+ "researchAndDevelopment": "2523000000",
+ "operatingExpenses": "5154000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "143000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "5000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "1034000000",
+ "incomeBeforeTax": "5868000000",
+ "incomeTaxExpense": "762000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "5106000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5863000000",
+ "ebitda": "6897000000",
+ "netIncome": "5106000000"
+ },
+ {
+ "fiscalDateEnding": "2018-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "10039000000",
+ "totalRevenue": "11966000000",
+ "costOfRevenue": "1927000000",
+ "costofGoodsAndServicesSold": "1927000000",
+ "operatingIncome": "5449000000",
+ "sellingGeneralAndAdministrative": "757000000",
+ "researchAndDevelopment": "2238000000",
+ "operatingExpenses": "4590000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "145000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "161000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "949000000",
+ "incomeBeforeTax": "5610000000",
+ "incomeTaxExpense": "622000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4988000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5449000000",
+ "ebitda": "6398000000",
+ "netIncome": "4988000000"
+ },
+ {
+ "fiscalDateEnding": "2017-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "11361000000",
+ "totalRevenue": "12972000000",
+ "costOfRevenue": "1611000000",
+ "costofGoodsAndServicesSold": "1611000000",
+ "operatingIncome": "7352000000",
+ "sellingGeneralAndAdministrative": "686000000",
+ "researchAndDevelopment": "1949000000",
+ "operatingExpenses": "4009000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "126000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "109000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "853000000",
+ "incomeBeforeTax": "7462000000",
+ "incomeTaxExpense": "3194000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4269000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "7352000000",
+ "ebitda": "8205000000",
+ "netIncome": "4268000000"
+ },
+ {
+ "fiscalDateEnding": "2017-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "8880000000",
+ "totalRevenue": "10328000000",
+ "costOfRevenue": "1448000000",
+ "costofGoodsAndServicesSold": "1448000000",
+ "operatingIncome": "5122000000",
+ "sellingGeneralAndAdministrative": "536000000",
+ "researchAndDevelopment": "2052000000",
+ "operatingExpenses": "3758000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "108000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "114000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "773000000",
+ "incomeBeforeTax": "5236000000",
+ "incomeTaxExpense": "529000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4707000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "5122000000",
+ "ebitda": "5895000000",
+ "netIncome": "4707000000"
+ },
+ {
+ "fiscalDateEnding": "2017-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "8084000000",
+ "totalRevenue": "9321000000",
+ "costOfRevenue": "1237000000",
+ "costofGoodsAndServicesSold": "1237000000",
+ "operatingIncome": "4401000000",
+ "sellingGeneralAndAdministrative": "640000000",
+ "researchAndDevelopment": "1919000000",
+ "operatingExpenses": "3683000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "91000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "87000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "728000000",
+ "incomeBeforeTax": "4488000000",
+ "incomeTaxExpense": "594000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "3894000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "4401000000",
+ "ebitda": "5129000000",
+ "netIncome": "3894000000"
+ },
+ {
+ "fiscalDateEnding": "2017-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "6873000000",
+ "totalRevenue": "8032000000",
+ "costOfRevenue": "1159000000",
+ "costofGoodsAndServicesSold": "1159000000",
+ "operatingIncome": "3327000000",
+ "sellingGeneralAndAdministrative": "655000000",
+ "researchAndDevelopment": "1834000000",
+ "operatingExpenses": "3546000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "67000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "81000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "671000000",
+ "incomeBeforeTax": "3408000000",
+ "incomeTaxExpense": "344000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "3064000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "3327000000",
+ "ebitda": "3998000000",
+ "netIncome": "3064000000"
+ },
+ {
+ "fiscalDateEnding": "2016-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "7762000000",
+ "totalRevenue": "8809000000",
+ "costOfRevenue": "1047000000",
+ "costofGoodsAndServicesSold": "1047000000",
+ "operatingIncome": "4566000000",
+ "sellingGeneralAndAdministrative": "515000000",
+ "researchAndDevelopment": "1563000000",
+ "operatingExpenses": "3196000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "56000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-32000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "614000000",
+ "incomeBeforeTax": "4533000000",
+ "incomeTaxExpense": "965000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "4273000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "4566000000",
+ "ebitda": "5180000000",
+ "netIncome": "3568000000"
+ },
+ {
+ "fiscalDateEnding": "2016-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "6024000000",
+ "totalRevenue": "7011000000",
+ "costOfRevenue": "987000000",
+ "costofGoodsAndServicesSold": "987000000",
+ "operatingIncome": "3122000000",
+ "sellingGeneralAndAdministrative": "438000000",
+ "researchAndDevelopment": "1539000000",
+ "operatingExpenses": "2902000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "50000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "47000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "591000000",
+ "incomeBeforeTax": "3169000000",
+ "incomeTaxExpense": "790000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "2379000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "3122000000",
+ "ebitda": "3713000000",
+ "netIncome": "2379000000"
+ },
+ {
+ "fiscalDateEnding": "2016-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "5520000000",
+ "totalRevenue": "6436000000",
+ "costOfRevenue": "916000000",
+ "costofGoodsAndServicesSold": "916000000",
+ "operatingIncome": "2746000000",
+ "sellingGeneralAndAdministrative": "412000000",
+ "researchAndDevelopment": "1463000000",
+ "operatingExpenses": "2774000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "32000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "20000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "585000000",
+ "incomeBeforeTax": "2766000000",
+ "incomeTaxExpense": "711000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "2055000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "2746000000",
+ "ebitda": "3331000000",
+ "netIncome": "2055000000"
+ },
+ {
+ "fiscalDateEnding": "2016-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "4544000000",
+ "totalRevenue": "5382000000",
+ "costOfRevenue": "838000000",
+ "costofGoodsAndServicesSold": "838000000",
+ "operatingIncome": "2009000000",
+ "sellingGeneralAndAdministrative": "366000000",
+ "researchAndDevelopment": "1343000000",
+ "operatingExpenses": "2535000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "27000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "56000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "552000000",
+ "incomeBeforeTax": "2065000000",
+ "incomeTaxExpense": "555000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "1505000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "2009000000",
+ "ebitda": "2561000000",
+ "netIncome": "1510000000"
+ },
+ {
+ "fiscalDateEnding": "2015-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "5017000000",
+ "totalRevenue": "5841000000",
+ "costOfRevenue": "824000000",
+ "costofGoodsAndServicesSold": "824000000",
+ "operatingIncome": "2560000000",
+ "sellingGeneralAndAdministrative": "371000000",
+ "researchAndDevelopment": "1314000000",
+ "operatingExpenses": "2457000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "14000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-3000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "543000000",
+ "incomeBeforeTax": "2557000000",
+ "incomeTaxExpense": "995000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "1561000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "2560000000",
+ "ebitda": "3103000000",
+ "netIncome": "1562000000"
+ },
+ {
+ "fiscalDateEnding": "2015-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "3781000000",
+ "totalRevenue": "4501000000",
+ "costOfRevenue": "720000000",
+ "costofGoodsAndServicesSold": "720000000",
+ "operatingIncome": "1459000000",
+ "sellingGeneralAndAdministrative": "345000000",
+ "researchAndDevelopment": "1271000000",
+ "operatingExpenses": "2322000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "7000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-27000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "486000000",
+ "incomeBeforeTax": "1432000000",
+ "incomeTaxExpense": "536000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "896000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1459000000",
+ "ebitda": "1945000000",
+ "netIncome": "896000000"
+ },
+ {
+ "fiscalDateEnding": "2015-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "3374000000",
+ "totalRevenue": "4042000000",
+ "costOfRevenue": "668000000",
+ "costofGoodsAndServicesSold": "668000000",
+ "operatingIncome": "1273000000",
+ "sellingGeneralAndAdministrative": "305000000",
+ "researchAndDevelopment": "1170000000",
+ "operatingExpenses": "2101000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "5000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "459000000",
+ "incomeBeforeTax": "1273000000",
+ "incomeTaxExpense": "554000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "719000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1273000000",
+ "ebitda": "1732000000",
+ "netIncome": "719000000"
+ },
+ {
+ "fiscalDateEnding": "2015-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "2889000000",
+ "totalRevenue": "3543000000",
+ "costOfRevenue": "654000000",
+ "costofGoodsAndServicesSold": "654000000",
+ "operatingIncome": "933000000",
+ "sellingGeneralAndAdministrative": "274000000",
+ "researchAndDevelopment": "1062000000",
+ "operatingExpenses": "1956000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "2000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-1000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "457000000",
+ "incomeBeforeTax": "932000000",
+ "incomeTaxExpense": "420000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "512000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "933000000",
+ "ebitda": "1390000000",
+ "netIncome": "512000000"
+ },
+ {
+ "fiscalDateEnding": "2014-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "3198000000",
+ "totalRevenue": "3851000000",
+ "costOfRevenue": "653000000",
+ "costofGoodsAndServicesSold": "653000000",
+ "operatingIncome": "1133000000",
+ "sellingGeneralAndAdministrative": "330000000",
+ "researchAndDevelopment": "1111000000",
+ "operatingExpenses": "2065000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "23000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-19000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "433000000",
+ "incomeBeforeTax": "1114000000",
+ "incomeTaxExpense": "413000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "701000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1133000000",
+ "ebitda": "1566000000",
+ "netIncome": "701000000"
+ },
+ {
+ "fiscalDateEnding": "2014-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "2638000000",
+ "totalRevenue": "3203000000",
+ "costOfRevenue": "565000000",
+ "costofGoodsAndServicesSold": "565000000",
+ "operatingIncome": "1397000000",
+ "sellingGeneralAndAdministrative": "259000000",
+ "researchAndDevelopment": "608000000",
+ "operatingExpenses": "1241000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "4000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-61000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "289000000",
+ "incomeBeforeTax": "1336000000",
+ "incomeTaxExpense": "530000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "806000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1397000000",
+ "ebitda": "1686000000",
+ "netIncome": "806000000"
+ },
+ {
+ "fiscalDateEnding": "2014-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "2437000000",
+ "totalRevenue": "2910000000",
+ "costOfRevenue": "473000000",
+ "costofGoodsAndServicesSold": "473000000",
+ "operatingIncome": "1390000000",
+ "sellingGeneralAndAdministrative": "197000000",
+ "researchAndDevelopment": "492000000",
+ "operatingExpenses": "1047000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "4000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-4000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "257000000",
+ "incomeBeforeTax": "1386000000",
+ "incomeTaxExpense": "595000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "791000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1390000000",
+ "ebitda": "1647000000",
+ "netIncome": "791000000"
+ },
+ {
+ "fiscalDateEnding": "2014-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "2040000000",
+ "totalRevenue": "2502000000",
+ "costOfRevenue": "462000000",
+ "costofGoodsAndServicesSold": "462000000",
+ "operatingIncome": "1075000000",
+ "sellingGeneralAndAdministrative": "187000000",
+ "researchAndDevelopment": "455000000",
+ "operatingExpenses": "965000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "19000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "264000000",
+ "incomeBeforeTax": "1075000000",
+ "incomeTaxExpense": "433000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "642000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1075000000",
+ "ebitda": "1339000000",
+ "netIncome": "642000000"
+ },
+ {
+ "fiscalDateEnding": "2013-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "2094000000",
+ "totalRevenue": "2585000000",
+ "costOfRevenue": "491000000",
+ "costofGoodsAndServicesSold": "491000000",
+ "operatingIncome": "1133000000",
+ "sellingGeneralAndAdministrative": "261000000",
+ "researchAndDevelopment": "408000000",
+ "operatingExpenses": "961000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "7000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "3000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "274000000",
+ "incomeBeforeTax": "1130000000",
+ "incomeTaxExpense": "607000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "523000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "1133000000",
+ "ebitda": "1407000000",
+ "netIncome": "523000000"
+ },
+ {
+ "fiscalDateEnding": "2013-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "1509000000",
+ "totalRevenue": "2016000000",
+ "costOfRevenue": "507000000",
+ "costofGoodsAndServicesSold": "507000000",
+ "operatingIncome": "736000000",
+ "sellingGeneralAndAdministrative": "171000000",
+ "researchAndDevelopment": "369000000",
+ "operatingExpenses": "773000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "21000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "11000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "274000000",
+ "incomeBeforeTax": "726000000",
+ "incomeTaxExpense": "301000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "425000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "736000000",
+ "ebitda": "1010000000",
+ "netIncome": "425000000"
+ },
+ {
+ "fiscalDateEnding": "2013-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "1348000000",
+ "totalRevenue": "1813000000",
+ "costOfRevenue": "465000000",
+ "costofGoodsAndServicesSold": "465000000",
+ "operatingIncome": "562000000",
+ "sellingGeneralAndAdministrative": "173000000",
+ "researchAndDevelopment": "344000000",
+ "operatingExpenses": "786000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "14000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-3000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "230000000",
+ "incomeBeforeTax": "545000000",
+ "incomeTaxExpense": "212000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "333000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "562000000",
+ "ebitda": "792000000",
+ "netIncome": "333000000"
+ },
+ {
+ "fiscalDateEnding": "2013-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "1045000000",
+ "totalRevenue": "1458000000",
+ "costOfRevenue": "413000000",
+ "costofGoodsAndServicesSold": "413000000",
+ "operatingIncome": "373000000",
+ "sellingGeneralAndAdministrative": "176000000",
+ "researchAndDevelopment": "293000000",
+ "operatingExpenses": "672000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "15000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-5000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "241000000",
+ "incomeBeforeTax": "353000000",
+ "incomeTaxExpense": "134000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "219000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "373000000",
+ "ebitda": "614000000",
+ "netIncome": "219000000"
+ },
+ {
+ "fiscalDateEnding": "2012-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "1187000000",
+ "totalRevenue": "1585000000",
+ "costOfRevenue": "398000000",
+ "costofGoodsAndServicesSold": "398000000",
+ "operatingIncome": "523000000",
+ "sellingGeneralAndAdministrative": "174000000",
+ "researchAndDevelopment": "297000000",
+ "operatingExpenses": "664000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "16000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "224000000",
+ "incomeBeforeTax": "505000000",
+ "incomeTaxExpense": "441000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "523000000",
+ "ebitda": "747000000",
+ "netIncome": "64000000"
+ },
+ {
+ "fiscalDateEnding": "2012-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "940000000",
+ "totalRevenue": "1262000000",
+ "costOfRevenue": "322000000",
+ "costofGoodsAndServicesSold": "322000000",
+ "operatingIncome": "377000000",
+ "sellingGeneralAndAdministrative": "151000000",
+ "researchAndDevelopment": "244000000",
+ "operatingExpenses": "563000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "11000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "6000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "176000000",
+ "incomeBeforeTax": "372000000",
+ "incomeTaxExpense": "431000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "-59000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "377000000",
+ "ebitda": "553000000",
+ "netIncome": "-59000000"
+ },
+ {
+ "fiscalDateEnding": "2012-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "817000000",
+ "totalRevenue": "1184000000",
+ "costOfRevenue": "367000000",
+ "costofGoodsAndServicesSold": "367000000",
+ "operatingIncome": "-743000000",
+ "sellingGeneralAndAdministrative": "463000000",
+ "researchAndDevelopment": "705000000",
+ "operatingExpenses": "1560000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "10000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "-12000000",
+ "depreciation": "None",
+ "depreciationAndAmortization": "139000000",
+ "incomeBeforeTax": "-765000000",
+ "incomeTaxExpense": "-608000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "-157000000",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "-743000000",
+ "ebitda": "-604000000",
+ "netIncome": "-157000000"
+ },
+ {
+ "fiscalDateEnding": "2012-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "781000000",
+ "totalRevenue": "1058000000",
+ "costOfRevenue": "277000000",
+ "costofGoodsAndServicesSold": "277000000",
+ "operatingIncome": "381000000",
+ "sellingGeneralAndAdministrative": "88000000",
+ "researchAndDevelopment": "153000000",
+ "operatingExpenses": "400000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "13000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "110000000",
+ "incomeBeforeTax": "382000000",
+ "incomeTaxExpense": "177000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "381000000",
+ "ebitda": "491000000",
+ "netIncome": "205000000"
+ },
+ {
+ "fiscalDateEnding": "2011-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "884000000",
+ "totalRevenue": "1131000000",
+ "costOfRevenue": "247000000",
+ "costofGoodsAndServicesSold": "247000000",
+ "operatingIncome": "547000000",
+ "sellingGeneralAndAdministrative": "58000000",
+ "researchAndDevelopment": "124000000",
+ "operatingExpenses": "337000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "16000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "103000000",
+ "incomeBeforeTax": "519000000",
+ "incomeTaxExpense": "217000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "547000000",
+ "ebitda": "650000000",
+ "netIncome": "302000000"
+ },
+ {
+ "fiscalDateEnding": "2011-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "718000000",
+ "totalRevenue": "954000000",
+ "costOfRevenue": "236000000",
+ "costofGoodsAndServicesSold": "236000000",
+ "operatingIncome": "414000000",
+ "sellingGeneralAndAdministrative": "82000000",
+ "researchAndDevelopment": "108000000",
+ "operatingExpenses": "304000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "10000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "97000000",
+ "incomeBeforeTax": "379000000",
+ "incomeTaxExpense": "152000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "414000000",
+ "ebitda": "511000000",
+ "netIncome": "227000000"
+ },
+ {
+ "fiscalDateEnding": "2011-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "685000000",
+ "totalRevenue": "895000000",
+ "costOfRevenue": "210000000",
+ "costofGoodsAndServicesSold": "210000000",
+ "operatingIncome": "407000000",
+ "sellingGeneralAndAdministrative": "83000000",
+ "researchAndDevelopment": "99000000",
+ "operatingExpenses": "278000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "9000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "72000000",
+ "incomeBeforeTax": "399000000",
+ "incomeTaxExpense": "159000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "407000000",
+ "ebitda": "479000000",
+ "netIncome": "240000000"
+ },
+ {
+ "fiscalDateEnding": "2011-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "564000000",
+ "totalRevenue": "731000000",
+ "costOfRevenue": "167000000",
+ "costofGoodsAndServicesSold": "167000000",
+ "operatingIncome": "388000000",
+ "sellingGeneralAndAdministrative": "51000000",
+ "researchAndDevelopment": "57000000",
+ "operatingExpenses": "176000000",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "7000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "51000000",
+ "incomeBeforeTax": "398000000",
+ "incomeTaxExpense": "165000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "388000000",
+ "ebitda": "439000000",
+ "netIncome": "233000000"
+ },
+ {
+ "fiscalDateEnding": "2010-12-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "1620000000",
+ "totalRevenue": "730000000",
+ "costOfRevenue": "151000000",
+ "costofGoodsAndServicesSold": "151000000",
+ "operatingIncome": "435000000",
+ "sellingGeneralAndAdministrative": "144000000",
+ "researchAndDevelopment": "46000000",
+ "operatingExpenses": "0",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "22000000",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "None",
+ "incomeBeforeTax": "1008000000",
+ "incomeTaxExpense": "402000000",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "435000000",
+ "ebitda": "None",
+ "netIncome": "251000000"
+ },
+ {
+ "fiscalDateEnding": "2010-09-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "0",
+ "totalRevenue": "467000000",
+ "costOfRevenue": "131000000",
+ "costofGoodsAndServicesSold": "131000000",
+ "operatingIncome": "216000000",
+ "sellingGeneralAndAdministrative": "120000000",
+ "researchAndDevelopment": "41000000",
+ "operatingExpenses": "0",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "0",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "None",
+ "incomeBeforeTax": "0",
+ "incomeTaxExpense": "0",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "216000000",
+ "ebitda": "None",
+ "netIncome": "131000000"
+ },
+ {
+ "fiscalDateEnding": "2010-06-30",
+ "reportedCurrency": "USD",
+ "grossProfit": "0",
+ "totalRevenue": "432000000",
+ "costOfRevenue": "111000000",
+ "costofGoodsAndServicesSold": "111000000",
+ "operatingIncome": "219000000",
+ "sellingGeneralAndAdministrative": "102000000",
+ "researchAndDevelopment": "32000000",
+ "operatingExpenses": "0",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "0",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "None",
+ "incomeBeforeTax": "0",
+ "incomeTaxExpense": "0",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "219000000",
+ "ebitda": "None",
+ "netIncome": "129000000"
+ },
+ {
+ "fiscalDateEnding": "2010-03-31",
+ "reportedCurrency": "USD",
+ "grossProfit": "0",
+ "totalRevenue": "345000000",
+ "costOfRevenue": "100000000",
+ "costofGoodsAndServicesSold": "100000000",
+ "operatingIncome": "162000000",
+ "sellingGeneralAndAdministrative": "83000000",
+ "researchAndDevelopment": "25000000",
+ "operatingExpenses": "0",
+ "investmentIncomeNet": "None",
+ "netInterestIncome": "None",
+ "interestIncome": "None",
+ "interestExpense": "0",
+ "nonInterestIncome": "None",
+ "otherNonOperatingIncome": "None",
+ "depreciation": "None",
+ "depreciationAndAmortization": "None",
+ "incomeBeforeTax": "0",
+ "incomeTaxExpense": "0",
+ "interestAndDebtExpense": "None",
+ "netIncomeFromContinuingOperations": "0",
+ "comprehensiveIncomeNetOfTax": "None",
+ "ebit": "162000000",
+ "ebitda": "None",
+ "netIncome": "95000000"
+ }
+ ]
+}
+
+✅ META 数据获取完成!
+⏰ 完成时间: 2025-08-02 16:52:42
diff --git a/modules/documentation-suite/docs/analysis/rss_debug_analysis.md b/modules/documentation-suite/docs/analysis/rss_debug_analysis.md
new file mode 100644
index 0000000..60d4d1d
--- /dev/null
+++ b/modules/documentation-suite/docs/analysis/rss_debug_analysis.md
@@ -0,0 +1,140 @@
+# RSS代码只能抓取一条数据的问题分析
+
+## 问题现象
+原代码期望抓取100条RSS数据,但实际只能抓取到1条数据。
+
+## 可能的原因分析
+
+### 1. RSS数据结构识别问题
+**最可能的原因**:RSS数据的实际结构与代码中的4种预设情况都不匹配。
+
+常见的RSS数据结构包括:
+- `rss.channel.item[]` (标准RSS 2.0)
+- `feed.entry[]` (Atom格式)
+- `channel.item[]` (简化RSS)
+- `data[]` (某些API返回格式)
+- 直接的对象数组
+
+### 2. 输入数据获取问题
+```javascript
+const rssSource = inputs[0]?.json; // 可能inputs[0]为空或结构不对
+```
+
+### 3. 去重逻辑过于严格
+如果MongoDB中已有大量数据,可能导致新数据被过度过滤。
+
+### 4. 错误处理不足
+原代码缺乏详细的调试信息,难以定位具体问题。
+
+## 解决方案
+
+### 1. 增强数据结构识别
+```javascript
+// 扩展RSS结构处理
+if (rssSource?.rss?.channel?.item && Array.isArray(rssSource.rss.channel.item)) {
+ rssItems = rssSource.rss.channel.item;
+}
+else if (rssSource?.feed?.entry && Array.isArray(rssSource.feed.entry)) {
+ rssItems = rssSource.feed.entry;
+}
+// ... 更多结构支持
+```
+
+### 2. 添加详细调试信息
+```javascript
+console.log('输入数据结构:', JSON.stringify(inputs[0], null, 2).substring(0, 500));
+console.log('RSS源数据的所有键:', Object.keys(rssSource || {}));
+```
+
+### 3. 改进去重逻辑
+```javascript
+// 只有当MongoDB确实有数据时才进行去重
+if (existingItems.length > 0 && existingItems[0] !== null) {
+ // 执行去重逻辑
+} else {
+ console.log('MongoDB中无现有数据,跳过去重检查');
+}
+```
+
+### 4. 增强错误处理
+```javascript
+try {
+ // 主要逻辑
+} catch (error) {
+ console.error("处理错误:", error.message);
+ console.error("错误堆栈:", error.stack);
+}
+```
+
+## 调试步骤
+
+1. **检查输入数据结构**
+ ```javascript
+ console.log('inputs长度:', inputs.length);
+ console.log('第一个输入:', inputs[0]);
+ ```
+
+2. **检查RSS源数据**
+ ```javascript
+ console.log('RSS源数据类型:', typeof rssSource);
+ console.log('RSS源数据键:', Object.keys(rssSource || {}));
+ ```
+
+3. **检查提取结果**
+ ```javascript
+ console.log('提取到的RSS条目数:', rssItems.length);
+ console.log('第一个RSS条目:', rssItems[0]);
+ ```
+
+4. **检查去重影响**
+ ```javascript
+ console.log('MongoDB现有数据数量:', existingItems.length);
+ console.log('去重后输出数量:', outputItems.length);
+ ```
+
+## 建议的修复代码
+
+使用 `improved_rss_code.js` 中的改进版本,它包含:
+- 更全面的RSS结构支持
+- 详细的调试信息输出
+- 改进的去重逻辑
+- 更好的错误处理
+- 更灵活的字段映射
+
+## 常见RSS结构示例
+
+### RSS 2.0格式
+```json
+{
+ "rss": {
+ "channel": {
+ "item": [
+ {"title": "新闻1", "link": "url1"},
+ {"title": "新闻2", "link": "url2"}
+ ]
+ }
+ }
+}
+```
+
+### Atom格式
+```json
+{
+ "feed": {
+ "entry": [
+ {"title": "新闻1", "link": {"href": "url1"}},
+ {"title": "新闻2", "link": {"href": "url2"}}
+ ]
+ }
+}
+```
+
+### 简化格式
+```json
+{
+ "items": [
+ {"title": "新闻1", "url": "url1"},
+ {"title": "新闻2", "url": "url2"}
+ ]
+}
+```
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture.md b/modules/documentation-suite/docs/architecture.md
new file mode 100644
index 0000000..8fee2e1
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture.md
@@ -0,0 +1,10 @@
+# 智能监控系统架构设计
+
+## 系统概述
+设计一个分布式智能监控系统,支持实时数据采集和分析。
+
+## 核心组件
+- 数据采集层
+- 实时处理引擎
+- 告警通知模块
+- 可视化仪表盘
diff --git a/modules/documentation-suite/docs/architecture/GEMINI_ARCH_REVIEW.md b/modules/documentation-suite/docs/architecture/GEMINI_ARCH_REVIEW.md
new file mode 100644
index 0000000..08d96bc
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/GEMINI_ARCH_REVIEW.md
@@ -0,0 +1,67 @@
+# 架构审查报告:太公心易 FSM 系统
+
+**审查人:** Gemini
+**日期:** 2025-08-21
+**审查范围:** `internal/core/fsm.md`, `internal/core/fsm_analysis.md`, `internal/migration/rfc_taigong_xinyi_fsm_enhancements.md`
+
+## 1. 概述
+
+“太公心易”系统是一个高度创新的AI决策框架,其核心是围绕一个有限状态机(FSM)构建的。该系统巧妙地将复杂的多智能体协作流程映射为道家哲学和中国神话中的概念,形成了一套独特且富有表现力的架构。本次审查旨在评估当前设计的优点、识别潜在风险,并提出初步的重构建议。
+
+## 2. 优点 (Advantages)
+
+1. **高度的可解释性 (High Explainability):** 通过将FSM的状态和功能模块映射为“八仙论道”、“太上老君炼丹”等神话角色和情景,系统设计变得非常直观,易于团队理解和沟通,极大地降低了复杂AI系统的认知门槛。
+
+2. **出色的模块化 (Excellent Modularity):** FSM的每个状态(如`Collecting`, `Refine`, `ExternalFetch`)以及“十二龙子”的角色都定义了清晰的职责边界。这种设计天然地将系统解耦成一系列高内聚、低耦合的组件,为独立开发、测试和扩展奠定了坚实的基础。
+
+3. **设计上的鲁棒性 (Robust by Design):** 设计文档中明确包含了多源外部验证(“灵宝道君”)、冲突检测与解决、以及错误处理状态等机制。这表明系统在设计之初就充分考虑了现实世界中数据的不一致性和不可靠性,具备很强的鲁棒性潜力。
+
+4. **框架的创新性 (Innovative Framework):** 将东方哲学思想与现代AI工程实践(如多智能体、FSM、工作流自动化)相结合,不仅是一个技术框架,更是一个文化与技术融合的范例,具有很强的独创性和探索价值。
+
+## 3. 潜在风险 (Potential Risks)
+
+1. **概念与实现的差距 (Concept-Implementation Gap):** 高度抽象的神话概念在转化为具体、可维护的工程代码时可能面临挑战。例如,“元神出窍”对应异步Webhook,如果日志和监控不能同时反映“神话层”和“技术层”的状态,会给调试带来巨大困难。**这是最主要的风险。**
+
+2. **过度设计的可能性 (Potential for Over-engineering):** RFC中提议的增强FSM状态和完整的十二龙子集成,对于项目的初始阶段可能过于复杂。存在为了贴合神话设定而引入不必要技术复杂度的风险。
+
+3. **性能瓶颈 (Performance Bottlenecks):** 系统的多个阶段都存在潜在的性能问题:
+ * `Collecting`: 多智能体辩论可能耗时过长或无法收敛。
+ * `ExternalFetch`: 大量调用外部API(尤其是通过N8N)会引入显著的网络延迟和不确定性。
+ * `Validation`/`Synthesis`: 多层次的验证和融合会增加计算开销。
+
+4. **对外部系统的强依赖 (Strong Dependency on External Systems):** RFC中提到,系统对N8N的依赖是一个已知的稳定性风险。如果N8N服务中断或响应缓慢,将直接影响整个决策流程的核心环节。
+
+## 4. 初步重构建议 (Preliminary Refactoring Suggestions)
+
+1. **MVP先行,迭代演进 (MVP First, Evolve Iteratively):**
+ * **简化FSM:** 优先实现最核心的FSM流程:`Collecting` → `Refine` → `ExternalFetch` → `Report`。将RFC中提出的`Validation`, `Synthesis`, `ConflictDetected`等增强状态作为后续迭代的目标。先验证核心价值,再逐步完善。
+
+2. **建立“龙族”抽象接口 (Abstract the "Dragon" Interface):**
+ * 不要将特定的龙子实现硬编码到FSM状态中。建议定义一个通用的`Dragon`基类或接口,明确其能力(如`can_search`, `can_verify`)。FSM状态根据需要向一个“龙族工厂”请求相应能力的龙子实例。这能有效解耦FSM与龙子的具体实现,提高灵活性。
+
+3. **双层日志与可观测性 (Dual-Layer Logging and Observability):**
+ * 从项目第一天起,就建立结构化的日志系统。每条日志应同时包含**神话层**和**技术层**的信息。
+ * **示例:**
+ ```json
+ {
+ "timestamp": "2025-08-21T10:00:00Z",
+ "myth_layer": {
+ "actor": "灵宝道君",
+ "action": "撒豆成兵",
+ "status": "开始验证"
+ },
+ "tech_layer": {
+ "event": "API_CALL_START",
+ "service": "n8n_webhook",
+ "endpoint": "/webhook/lingbao-twelve-dragons",
+ "trace_id": "xyz-123"
+ }
+ }
+ ```
+ * 这种方法可以在保持系统可解释性的同时,为开发者提供清晰的调试路径。
+
+4. **为N8N设计降级策略 (Implement a Fallback Strategy for N8N):**
+ * 如RFC中所建议,应为`ExternalFetch`状态设计一个降级(Fallback)机制。当调用N8N工作流失败或超时,系统应能自动切换到一个备用的、更简单的验证方式(例如,直接通过Python库调用单个搜索引擎API)。这能显著提升系统的可靠性。
+
+5. **代码驱动,验证设计 (Drive with Code, Validate the Design):**
+ * 当前项目文档非常丰富,但代码实现尚不明确。建议团队将重心适当向编码倾斜,优先实现RFC附录中提到的核心模块(如`dragon_base.py`, `lingbao_papaniu.py`)。通过实际编码来检验和迭代当前架构设计的可行性。
diff --git a/modules/documentation-suite/docs/architecture/PROJECT_SUMMARY.md b/modules/documentation-suite/docs/architecture/PROJECT_SUMMARY.md
new file mode 100644
index 0000000..d3c4690
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/PROJECT_SUMMARY.md
@@ -0,0 +1,44 @@
+# 炼妖壶项目结构与核心模块概览
+
+## 项目核心理念
+炼妖壶项目(Lianyaohu)是一个融合中国传统文化与现代AI技术的投资分析系统。其核心理念是:
+- 利用八仙、龙子等神话角色作为AI智能体,进行多维度的市场分析
+- 通过"差序格局"、"十二长生"等传统哲学思想构建市场模型
+- 结合现代技术(如FSM状态机、图数据库)实现智能化决策支持
+
+## 核心模块介绍
+
+### 1. 天体图谱 (Celestial Map) - `celestial_map.py`
+基于费孝通的"差序格局"理论,构建产业链影响力的图模型:
+- 恒星 (Star): 产业链核心/上游公司
+- 行星 (Planet): 紧密关联的中游公司
+- 卫星 (Satellite): 下游或关联度较弱的公司
+- 引力 (Gravity): 公司间的影响强度,通过NetworkX图结构建模
+
+### 2. 市场状态机 (Market FSM) - `market_fsm.py`
+一个简化的市场分析有限状态机,演示如何通过抽象基类调用外部引擎:
+- 核心状态:Idle → Collecting → CycleAnalysis → Reporting → Idle
+- 通过注入神话引擎和周期模型实现解耦
+
+### 3. 神话引擎 (Mythology Engine) - `mythology.py`
+将技术组件映射到神话角色的抽象接口:
+- 抽象基类`MythologyEngine`定义统一接口
+- `DaoistMythologyEngine`实现道家神话映射(如太上老君、灵宝道君等)
+
+### 4. 周期模型 (Cycle Model) - `cycle_models.py`
+描述市场或个股生命周期的抽象模型:
+- 抽象基类`CycleModel`定义统一接口
+- `TwelveStagesOfLifeCycleModel`实现"十二长生"周期模型
+
+### 5. 妖股扫描器 (Monster Stock Scanner) - `monster_stock_scanner.py`
+基于"龙生九子"概念的个股分析工具:
+- `Dragon`抽象基类定义龙子接口
+- `Bixi`(赑屃)负责分析宏观结构性压力(天时)
+- `Fuxi`(负屃)负责计算个股主题挤压分数(地利)
+- 结合"天时地利人和"识别潜在妖股
+
+## 项目架构特色
+1. **文化驱动设计**:所有模块都深度融入中国传统文化元素
+2. **高度解耦**:通过抽象基类实现核心逻辑与具体实现的分离
+3. **可扩展性强**:可以轻松添加新的神话体系或周期模型
+4. **清晰的职责划分**:每个模块都有明确的功能定位
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/component_interaction_diagram.mermaid b/modules/documentation-suite/docs/architecture/component_interaction_diagram.mermaid
new file mode 100644
index 0000000..bad32ab
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/component_interaction_diagram.mermaid
@@ -0,0 +1,13 @@
+graph LR
+ A[Streamlit App] --> B[OpenBB Tab]
+ A --> C[Debate System]
+ C --> D[Immortal Agents]
+ D --> E[OpenBB Engine]
+ D --> F[Perpetual Engine]
+ B --> G[_load_price_data]
+ G --> H{OpenBB Available?}
+ H -- Yes --> I[OpenBB obb]
+ H -- No --> J[Demo/Synthetic Data]
+ E --> K{OpenBB Available?}
+ K -- Yes --> I
+ K -- No --> L[Error Result]
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/data_flow_diagram.mermaid b/modules/documentation-suite/docs/architecture/data_flow_diagram.mermaid
new file mode 100644
index 0000000..8ffd966
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/data_flow_diagram.mermaid
@@ -0,0 +1,9 @@
+graph TD
+ A[User Request] --> B{OpenBB Installed?}
+ B -- Yes --> C{OpenBB Data Available?}
+ C -- Yes --> D[OpenBB Engine]
+ C -- No --> E[Fallback to Demo/Synthetic Data]
+ B -- No --> E
+ D --> F[Format Data]
+ E --> F
+ F --> G[Return to Agent/UI]
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/deployment_architecture.md b/modules/documentation-suite/docs/architecture/deployment_architecture.md
new file mode 100644
index 0000000..7c12995
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/deployment_architecture.md
@@ -0,0 +1,181 @@
+# OpenBB Integration Deployment Architecture
+
+## Environment and Dependencies
+
+### Base Requirements
+- **Python Version**: 3.8 or higher
+- **Core Dependencies**: As specified in `requirements.txt` (Streamlit, etc.)
+
+### Optional OpenBB Dependency
+- **OpenBB Library**: `openbb>=4.1.0`
+- **Installation**: Not included in default `requirements.txt` to maintain lightweight base installation
+- **Activation**: Install via `pip install "openbb>=4.1.0"` when needed
+
+## Configuration Management
+
+### Environment Variables
+- **Standard Project Variables**: Managed through Doppler (RAPIDAPI_KEY, GOOGLE_API_KEY, etc.)
+- **OpenBB Provider Variables**:
+ - For public data sources (like yfinance): No specific configuration required
+ - For premium data sources (e.g., Polygon, FMP):
+ - Variables are managed by OpenBB internally
+ - Follow OpenBB documentation for provider-specific setup
+ - Example: `POLYGON_API_KEY` for Polygon.io data
+
+### Feature Flags
+- **JIXIA_MEMORY_BACKEND**: When set to "cloudflare", enables Cloudflare AutoRAG as memory backend
+- **GOOGLE_GENAI_USE_VERTEXAI**: When set to "TRUE", enables Vertex AI for memory bank
+
+## Deployment Scenarios
+
+### 1. Base Deployment (OpenBB Not Installed)
+- **Characteristics**:
+ - Lightweight installation
+ - Relies on existing RapidAPI-based perpetual engine
+ - UI falls back to demo or synthetic data in OpenBB tab
+- **Use Cases**:
+ - Minimal environment setups
+ - Systems where OpenBB installation is not feasible
+ - Development environments focusing on other features
+
+### 2. Full Deployment (With OpenBB)
+- **Characteristics**:
+ - Enhanced data capabilities through OpenBB
+ - Access to multiple data providers
+ - Improved data quality and coverage
+- **Use Cases**:
+ - Production environments requiring comprehensive market data
+ - Advanced financial analysis and debate scenarios
+ - Integration with premium data sources
+
+### 3. Hybrid Deployment (Selective Features)
+- **Characteristics**:
+ - Selective installation of OpenBB providers
+ - Mix of OpenBB and perpetual engine data sources
+ - Fallback mechanisms ensure continuous operation
+- **Use Cases**:
+ - Cost optimization by using free providers where possible
+ - Gradual migration from perpetual engine to OpenBB
+ - Testing new data sources without full commitment
+
+## Containerization (Docker)
+
+### Base Image
+- Python 3.10-slim or equivalent
+
+### Multi-Stage Build
+1. **Builder Stage**:
+ - Install build dependencies
+ - Install Python dependencies
+2. **Runtime Stage**:
+ - Copy installed packages from builder
+ - Copy application code
+ - Install optional OpenBB dependencies if specified
+
+### Docker Compose Configuration
+- Service definitions for main application
+- Optional service for database (if using persistent memory backends)
+- Volume mounts for configuration and data persistence
+
+## Cloud Deployment
+
+### Google Cloud Platform (GCP)
+- **App Engine**:
+ - Standard environment with custom runtime
+ - Environment variables configured through `app.yaml`
+- **Cloud Run**:
+ - Containerized deployment
+ - Secrets managed through Secret Manager
+- **Compute Engine**:
+ - Full control over VM configuration
+ - Persistent disks for data storage
+
+### Considerations for Cloud Deployment
+- **API Key Security**:
+ - Use secret management services (Google Secret Manager, Doppler)
+ - Never store keys in code or environment files
+- **Memory Backend Configuration**:
+ - For Vertex AI Memory Bank: Configure GOOGLE_CLOUD_PROJECT_ID and authentication
+ - For Cloudflare AutoRAG: Configure CLOUDFLARE_ACCOUNT_ID and API token
+- **Scalability**:
+ - Stateless application design allows horizontal scaling
+ - Memory backends provide persistence across instances
+
+## Memory Backend Integration
+
+### Vertex AI Memory Bank (Default/Primary)
+- **Activation**: Requires GOOGLE_GENAI_USE_VERTEXAI=true and proper GCP authentication
+- **Dependencies**: `google-cloud-aiplatform` (installed with google-adk)
+- **Deployment**: Requires GCP project with Vertex AI API enabled
+
+### Cloudflare AutoRAG (Alternative)
+- **Activation**: Requires JIXIA_MEMORY_BACKEND=cloudflare and Cloudflare credentials
+- **Dependencies**: `aiohttp` (already in requirements)
+- **Deployment**: Requires Cloudflare account with Vectorize and Workers AI enabled
+
+## Monitoring and Observability
+
+### Health Checks
+- Application startup verification
+- OpenBB availability check endpoint
+- Memory backend connectivity verification
+
+### Logging
+- Structured logging for data access patterns
+- Error tracking for failed data retrievals
+- Performance metrics for data loading times
+
+### Metrics Collection
+- API usage counters (both RapidAPI and OpenBB)
+- Fallback trigger rates
+- Memory backend operation statistics
+
+## Security Posture
+
+### Data Security
+- In-memory data processing
+- No persistent storage of sensitive financial data
+- Secure handling of API responses
+
+### Access Control
+- Streamlit authentication (if enabled)
+- API key isolation per data provider
+- Memory backend access controls through provider mechanisms
+
+### Network Security
+- HTTPS for all external API calls
+- Outbound firewall rules for API endpoints
+- Secure credential injection mechanisms
+
+## Disaster Recovery and Business Continuity
+
+### Data Source Redundancy
+- Multiple API providers through OpenBB
+- Fallback to perpetual engine when OpenBB fails
+- Synthetic data generation for UI continuity
+
+### Memory Backend Failover
+- Local simulation mode when cloud backends are unavailable
+- Graceful degradation of memory features
+
+### Recovery Procedures
+- Automated restart on critical failures
+- Manual intervention procedures for configuration issues
+- Rollback capabilities through version control
+
+## Performance Optimization
+
+### Caching Strategies
+- OpenBB's internal caching mechanisms
+- Streamlit's built-in caching for UI components
+- Memory backend for persistent agent knowledge
+
+### Resource Management
+- Asynchronous data loading where possible
+- Memory-efficient data structures
+- Connection pooling for API requests
+
+### Scaling Considerations
+- Horizontal scaling for handling concurrent users
+- Vertical scaling for memory-intensive operations
+- Load balancing for distributed deployments
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/openbb_integration_architecture.md b/modules/documentation-suite/docs/architecture/openbb_integration_architecture.md
new file mode 100644
index 0000000..6fc9181
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/openbb_integration_architecture.md
@@ -0,0 +1,168 @@
+# OpenBB Integration Architecture for 炼妖壶 (Lianyaohu) - 稷下学宫AI辩论系统
+
+## Overview
+
+This document outlines the architecture for integrating OpenBB v4 into the Lianyaohu 稷下学宫AI辩论系统. The integration aims to provide enriched financial data to the eight immortal agents while maintaining graceful degradation when OpenBB is not installed or available.
+
+## System Context
+
+The Lianyaohu system is a multi-AI-agent debate platform rooted in traditional Chinese philosophy. The eight immortals (八仙) debate investment topics, leveraging data from multiple financial APIs. The system currently uses a "perpetual engine" based on 17 RapidAPI subscriptions. This architecture adds OpenBB as an optional, higher-level data source.
+
+## Key Components and Integration Points
+
+### 1. Core Business Logic (`src/jixia/`)
+#### a. `engines/openbb_engine.py`
+- **Purpose**: Primary interface to OpenBB v4 data.
+- **Key Features**:
+ - Lazy loading of `openbb` library to prevent import errors if not installed.
+ - `ImmortalConfig` mapping each immortal to a primary data provider (initially `yfinance`).
+ - `get_immortal_data` method for agent-specific data retrieval based on specialty.
+ - `simulate_jixia_debate` for testing and demonstration.
+- **Integration Strategy**:
+ - Uses `from openbb import obb` for unified routing.
+ - Handles different data types (price, historical, profile, news, earnings, etc.).
+ - Provides fallback error handling returning `APIResult` objects.
+
+#### b. `engines/openbb_stock_data.py`
+- **Purpose**: Utility functions for fetching stock and ETF data.
+- **Key Features**:
+ - `get_stock_data` and `get_etf_data` functions.
+ - Lazy loading of `openbb`.
+ - Time window configuration.
+ - Data formatting utilities.
+
+### 2. Application Entry Point (`app/`)
+#### a. `tabs/openbb_tab.py`
+- **Purpose**: Streamlit UI tab for visualizing market data.
+- **Key Features**:
+ - `_check_openbb_installed` to detect availability.
+ - `_load_price_data` with multi-level fallback (OpenBB -> demo JSON -> synthetic data).
+ - KPI calculation from data.
+ - Interactive charting with Plotly.
+- **Integration Strategy**:
+ - Prioritizes `obb.equity.price.historical`, falling back to `obb.etf.price.historical`.
+ - Handles various data frame formats and column names from different providers.
+ - Graceful UI degradation with informative messages.
+
+### 3. Data Models (`src/jixia/models/`)
+*(Note: This directory and specific model files were not found in the current codebase.)*
+- **Purpose**: Standardized data models for financial data.
+- **Proposed Implementation**:
+ - Define `FinancialDataPoint`, `StockQuote`, `HistoricalPrice`, etc.
+ - Used by both OpenBB engine and existing perpetual engine for data abstraction.
+
+### 4. Configuration (`config/settings.py`)
+- **Purpose**: Centralized configuration management.
+- **Key Features**:
+ - No direct OpenBB configuration currently, but designed for extensibility.
+ - Validates environment for hybrid AI provider modes.
+
+## Data Flow Architecture
+
+```mermaid
+graph TD
+ A[User Request] --> B{OpenBB Installed?}
+ B -- Yes --> C{OpenBB Data Available?}
+ C -- Yes --> D[OpenBB Engine]
+ C -- No --> E[Fallback to Demo/Synthetic Data]
+ B -- No --> E
+ D --> F[Format Data]
+ E --> F
+ F --> G[Return to Agent/UI]
+```
+
+1. **Agent Request**: An immortal agent requests data via `OpenBBEngine.get_immortal_data`.
+2. **OpenBB Check**: The engine checks if OpenBB is available via lazy import.
+3. **Data Retrieval**: If available, the engine calls the appropriate `obb.*` function.
+4. **Data Processing**: The engine processes the result into a standardized `APIResult`.
+5. **Fallback**: If OpenBB is not installed or the call fails, an error result is returned.
+6. **UI Request**: The OpenBB tab requests data via `_load_price_data`.
+7. **UI Fallback Chain**:
+ - Tries `obb.equity.price.historical`.
+ - Falls back to `obb.etf.price.historical`.
+ - Falls back to loading demo JSON files.
+ - Finally falls back to generating synthetic data.
+8. **Data Formatting**: The UI formats the data for display, handling various column names and structures.
+
+## Component Interaction Diagram
+
+```mermaid
+graph LR
+ A[Streamlit App] --> B[OpenBB Tab]
+ A --> C[Debate System]
+ C --> D[Immortal Agents]
+ D --> E[OpenBB Engine]
+ D --> F[Perpetual Engine]
+ B --> G[_load_price_data]
+ G --> H{OpenBB Available?}
+ H -- Yes --> I[OpenBB obb]
+ H -- No --> J[Demo/Synthetic Data]
+ E --> K{OpenBB Available?}
+ K -- Yes --> I
+ K -- No --> L[Error Result]
+```
+
+## Deployment Architecture
+
+### Environment Requirements
+- Python 3.8+
+- Optional: `openbb>=4.1.0` (not in default requirements)
+- Standard project dependencies (Streamlit, etc.)
+
+### Configuration
+- No specific OpenBB configuration required for basic `yfinance` use.
+- Advanced providers (e.g., Polygon) would require provider-specific environment variables.
+
+### Scalability and Performance
+- OpenBB's provider system handles its own rate limiting and caching.
+- The lazy loading approach prevents unnecessary overhead if OpenBB is not used.
+- Fallback to demo/synthetic data ensures UI responsiveness.
+
+## Failure Handling and Degradation
+
+### OpenBB Not Installed
+- `ImportError` is caught in lazy loading.
+- Engine returns `APIResult(success=False, error="OpenBB not installed...")`.
+- UI falls back to demo/synthetic data gracefully.
+
+### OpenBB API Call Failure
+- Exception is caught in `get_immortal_data`.
+- Engine returns `APIResult(success=False, error="OpenBB call failed...")`.
+- Agent can decide how to handle the failure (e.g., switch to another engine).
+
+### UI Data Loading Failure
+- Multi-level fallback ensures data is always available for visualization.
+- Users are informed via UI messages if demo/synthetic data is being used.
+
+## Monitoring and Observability
+
+### Logging
+- OpenBB engine logs data requests and responses.
+- UI logs fallback events.
+
+### Metrics
+- Not currently implemented, but could track:
+ - OpenBB usage frequency.
+ - Fallback trigger rates.
+ - Data load times.
+
+## Security Considerations
+
+### API Keys
+- OpenBB handles provider API keys internally.
+- Standard project security practices (Doppler, no hardcoded keys) apply.
+
+### Data Handling
+- Data is processed in memory and not persisted by the OpenBB integration components.
+
+## Future Enhancements
+
+1. **Unified Data Model**: Create standardized data models in `src/jixia/models/` for seamless integration between OpenBB and other data sources.
+2. **Provider Configuration**: Allow dynamic configuration of data providers for each immortal.
+3. **Enhanced UI Components**: Add more detailed financial data visualizations and analysis tools.
+4. **Debate Integration**: Directly link debate outcomes to specific data points from OpenBB.
+5. **Advanced OpenBB Routes**: Integrate fundamental data, news, and alternative data sources from OpenBB.
+
+## Conclusion
+
+This architecture successfully integrates OpenBB v4 into the Lianyaohu system while maintaining its core principles of graceful degradation and modular design. The lazy loading approach ensures that the system remains functional and performant regardless of whether OpenBB is installed, providing a robust foundation for future enhancements.
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/performance_optimization.md b/modules/documentation-suite/docs/architecture/performance_optimization.md
new file mode 100644
index 0000000..5d41543
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/performance_optimization.md
@@ -0,0 +1,158 @@
+# OpenBB Integration Performance Optimization Architecture
+
+## Overview
+
+This document outlines the performance optimization strategies for the OpenBB integration in the 炼妖壶 (Lianyaohu) - 稷下学宫AI辩论系统. The goal is to ensure the system can handle high concurrency while maintaining low latency and optimal resource utilization.
+
+## Asynchronous Data Architecture
+
+### 1. Asynchronous Data Retrieval
+- **Implementation**: Use Python's `asyncio` framework for non-blocking data access
+- **Key Components**:
+ - `DataAbstractionLayer.get_quote_async()` method
+ - Asynchronous providers (where supported by the underlying library)
+ - Executor-based fallback for synchronous providers
+- **Benefits**:
+ - Improved responsiveness for UI components
+ - Better resource utilization for concurrent requests
+ - Non-blocking operations for agent debates
+
+### 2. Concurrent Provider Access
+- **Implementation**: Parallel requests to multiple providers with first-wins semantics
+- **Strategy**:
+ - Launch requests to all configured providers simultaneously
+ - Return the first successful response
+ - Cancel remaining requests to conserve resources
+- **Benefits**:
+ - Reduced perceived latency
+ - Automatic failover without delay
+ - Optimal use of available bandwidth
+
+## Caching Strategy
+
+### 1. Multi-Level Caching
+- **In-Memory LRU Cache**:
+ - Decorator-based caching for frequently accessed data (quotes, profiles)
+ - Configurable size limits to prevent memory exhaustion
+ - Time-to-live (TTL) settings based on data volatility
+- **Shared Cache Layer** (Future):
+ - Redis or Memcached for distributed deployments
+ - Consistent cache invalidation across instances
+ - Support for cache warming strategies
+
+### 2. Cache Key Design
+- **Granular Keys**: Separate cache entries for different data types and time windows
+- **Parameterized Keys**: Include relevant parameters (symbol, date range, provider) in cache keys
+- **Versioned Keys**: Incorporate data schema version to handle model changes
+
+### 3. Cache Invalidation
+- **Time-Based Expiration**: Automatic expiration based on TTL settings
+- **Event-Driven Invalidation**: Clear cache entries when underlying data sources are updated
+- **Manual Invalidation**: API endpoints for cache management
+
+## Load Balancing Mechanism
+
+### 1. Provider Selection Algorithm
+- **Priority-Based Routing**: Route requests to providers based on configured priorities
+- **Health-Based Routing**: Consider provider health metrics when selecting providers
+- **Round-Robin for Equal Priority**: Distribute load among providers with the same priority
+
+### 2. Adaptive Load Distribution
+- **Real-Time Monitoring**: Track response times and error rates for each provider
+- **Dynamic Weight Adjustment**: Adjust provider weights based on performance metrics
+- **Circuit Breaker Pattern**: Temporarily disable poorly performing providers
+
+## Resource Management
+
+### 1. Connection Pooling
+- **HTTP Connection Reuse**: Maintain pools of HTTP connections for API clients
+- **Database Connection Pooling**: Reuse database connections for cache backends
+- **Provider-Specific Pools**: Separate connection pools for different data providers
+
+### 2. Memory Management
+- **Efficient Data Structures**: Use memory-efficient data structures for caching
+- **Object Reuse**: Reuse objects where possible to reduce garbage collection pressure
+- **Streaming Data Processing**: Process large datasets in chunks to minimize memory footprint
+
+### 3. Thread and Process Management
+- **Async-Appropriate Threading**: Use threads for I/O-bound operations that aren't natively async
+- **Process Isolation**: Isolate resource-intensive operations in separate processes
+- **Resource Limits**: Configure limits on concurrent threads and processes
+
+## Monitoring and Performance Metrics
+
+### 1. Key Performance Indicators
+- **Response Time**: Measure latency for data retrieval operations
+- **Throughput**: Track requests per second for different data types
+- **Error Rate**: Monitor failure rates for data access operations
+- **Cache Hit Ratio**: Measure effectiveness of caching strategies
+
+### 2. Provider Performance Metrics
+- **Individual Provider Metrics**: Track performance for each data provider
+- **Health Status**: Monitor uptime and responsiveness of providers
+- **Cost Metrics**: Track usage and costs associated with different providers
+
+### 3. System-Level Metrics
+- **Resource Utilization**: CPU, memory, and network usage
+- **Concurrency Levels**: Track active requests and queue depths
+- **Garbage Collection**: Monitor GC activity and its impact on performance
+
+## Optimization Techniques
+
+### 1. Data Pre-fetching
+- **Predictive Loading**: Pre-fetch data for likely subsequent requests
+- **Batch Operations**: Combine multiple requests into single batch operations where possible
+- **Background Refresh**: Refresh cached data proactively before expiration
+
+### 2. Data Compression
+- **Response Compression**: Use gzip compression for API responses
+- **Cache Compression**: Compress cached data to reduce memory usage
+- **Efficient Serialization**: Use efficient serialization formats (e.g., Protocol Buffers, MessagePack)
+
+### 3. Database Optimization
+- **Indexing Strategy**: Create appropriate indexes for cache lookup operations
+- **Query Optimization**: Optimize database queries for performance
+- **Connection Management**: Efficiently manage database connections
+
+## Scalability Considerations
+
+### 1. Horizontal Scaling
+- **Stateless Design**: Ensure data access components are stateless for easy scaling
+- **Load Balancer Integration**: Work with external load balancers for traffic distribution
+- **Shared Caching**: Use distributed cache for consistent data across instances
+
+### 2. Vertical Scaling
+- **Resource Allocation**: Optimize resource usage for efficient vertical scaling
+- **Performance Tuning**: Tune system parameters for better performance on larger instances
+- **Memory Management**: Efficiently manage memory to take advantage of larger instances
+
+### 3. Auto-scaling
+- **Metrics-Driven Scaling**: Use performance metrics to trigger auto-scaling events
+- **Graceful Degradation**: Maintain functionality during scaling operations
+- **Cost Optimization**: Balance performance with cost considerations
+
+## Implementation Roadmap
+
+### Phase 1: Core Async Implementation
+- Implement `DataAbstractionLayer.get_quote_async()`
+- Add async support to provider adapters where possible
+- Add executor-based fallback for synchronous providers
+
+### Phase 2: Caching Layer
+- Implement in-memory LRU cache
+- Add cache key design and invalidation strategies
+- Integrate cache with data abstraction layer
+
+### Phase 3: Monitoring and Metrics
+- Implement data quality monitoring
+- Add performance metrics collection
+- Create dashboards for monitoring key metrics
+
+### Phase 4: Advanced Optimizations
+- Implement predictive pre-fetching
+- Add database optimization for cache backends
+- Implement distributed caching for scalability
+
+## Conclusion
+
+This performance optimization architecture provides a comprehensive approach to ensuring the OpenBB integration in the Lianyaohu system can handle high concurrency while maintaining optimal performance. By implementing asynchronous data access, multi-level caching, intelligent load balancing, and comprehensive monitoring, the system will be able to deliver fast, reliable financial data to the eight immortal agents even under heavy load.
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/technical_specification.md b/modules/documentation-suite/docs/architecture/technical_specification.md
new file mode 100644
index 0000000..e17391c
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/technical_specification.md
@@ -0,0 +1,130 @@
+# 炼妖壶-稷下学宫AI辩论系统 OpenBB集成文档整合
+
+## 概述
+
+本文档整合了"炼妖壶-稷下学宫AI辩论系统"中OpenBB集成的所有关键设计和实现文档,为开发团队提供一个全面的参考指南。
+
+## 架构设计
+
+### 1. 整体架构
+系统采用分层架构设计,将OpenBB集成在数据访问层,通过抽象层为上层应用提供统一的数据接口。
+
+### 2. 核心组件
+- **OpenBB引擎** (`src/jixia/engines/openbb_engine.py`):主要的数据访问接口
+- **数据抽象层** (`src/jixia/engines/data_abstraction_layer.py`):统一的数据访问接口
+- **Provider适配器**:为不同数据源实现的适配器
+- **数据模型** (`src/jixia/models/financial_data_models.py`):标准化的数据结构定义
+
+### 3. 数据流
+```
+[八仙智能体] -> [数据抽象层] -> [Provider适配器] -> [OpenBB引擎] -> [OpenBB库]
+ \-> [永动机引擎] -> [RapidAPI]
+```
+
+## 实现细节
+
+### 1. 数据模型
+定义了标准化的金融数据结构:
+- `StockQuote`:股票报价
+- `HistoricalPrice`:历史价格数据
+- `CompanyProfile`:公司概况
+- `FinancialNews`:金融新闻
+
+### 2. 抽象接口
+定义了`DataProvider`抽象基类,所有数据提供商都需要实现该接口:
+- `get_quote()`:获取股票报价
+- `get_historical_prices()`:获取历史价格数据
+- `get_company_profile()`:获取公司概况
+- `get_news()`:获取相关新闻
+
+### 3. Provider适配器
+为OpenBB和RapidAPI分别实现了适配器:
+- `OpenBBDataProvider`:OpenBB数据提供商适配器
+- `RapidAPIDataProvider`:RapidAPI数据提供商适配器
+
+### 4. 八仙数据映射
+定义了八仙与数据源的智能映射关系,每个八仙都有其专属的数据源和类型偏好。
+
+## 性能优化
+
+### 1. 异步处理
+实现了异步数据访问机制,提高系统并发处理能力。
+
+### 2. 缓存策略
+采用多级缓存策略,包括内存LRU缓存和未来可扩展的分布式缓存。
+
+### 3. 负载均衡
+实现了基于优先级和健康状态的数据源选择算法。
+
+## 测试验证
+
+### 1. 功能测试
+- Provider适配器测试
+- 数据抽象层测试
+- 引擎组件测试
+- UI组件测试
+- 集成测试
+
+### 2. 性能测试
+- 响应时间测试
+- 并发访问测试
+
+### 3. 验证标准
+- 功能验证标准
+- 性能验证标准
+- 兼容性验证标准
+
+## 部署架构
+
+### 1. 环境要求
+- Python 3.8+
+- 可选的OpenBB库 (>=4.1.0)
+
+### 2. 配置管理
+- 通过环境变量管理配置
+- 支持多种部署场景(基础部署、完整部署、混合部署)
+
+### 3. 安全考虑
+- API密钥安全管理
+- 数据安全处理
+- 访问控制
+
+## 故障处理与降级
+
+### 1. 故障转移机制
+当主数据源不可用时,系统能自动切换到备用数据源。
+
+### 2. 优雅降级
+当OpenBB未安装时,系统能正常运行并使用演示数据。
+
+## 监控与可观测性
+
+### 1. 关键指标
+- 数据源可用性
+- 响应时间
+- 错误率
+- 缓存命中率
+
+### 2. 告警策略
+定义了多维度的告警策略,确保系统稳定性。
+
+## 未来发展规划
+
+### 1. 统一数据模型
+创建更完善的标准化数据模型。
+
+### 2. Provider配置
+实现动态配置数据提供商。
+
+### 3. 增强UI组件
+添加更多详细的金融数据可视化和分析工具。
+
+### 4. 辩论集成
+直接将辩论结果链接到OpenBB的具体数据点。
+
+### 5. 高级路由
+集成OpenBB的更多数据源,如基本面数据、新闻和另类数据。
+
+## 结论
+
+通过以上架构设计和实现,OpenBB集成成功地为"炼妖壶-稷下学宫AI辩论系统"提供了丰富而可靠的金融数据支持,同时保持了系统的可扩展性和稳定性。这套集成方案不仅满足了当前需求,也为未来功能扩展奠定了坚实基础。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/architecture/test_validation_plan.md b/modules/documentation-suite/docs/architecture/test_validation_plan.md
new file mode 100644
index 0000000..51cb13d
--- /dev/null
+++ b/modules/documentation-suite/docs/architecture/test_validation_plan.md
@@ -0,0 +1,287 @@
+# 炼妖壶-稷下学宫AI辩论系统 OpenBB集成测试与验证方案
+
+## 概述
+
+本文档定义了"炼妖壶-稷下学宫AI辩论系统"中OpenBB集成的测试用例和验证标准,确保集成的正确性、可靠性和性能。
+
+## 测试环境配置
+
+### 基础环境
+- Python 3.8+
+- 系统依赖:如 requirements.txt 中定义
+- 测试框架:pytest
+
+### OpenBB环境变体
+1. **未安装OpenBB**:测试降级机制
+2. **安装OpenBB但未配置提供商**:测试基本功能
+3. **完整配置OpenBB**:测试所有功能
+
+## 测试用例
+
+### 1. 数据抽象层测试
+
+#### 1.1 Provider适配器测试
+```python
+# tests/test_provider_adapters.py
+
+def test_openbb_provider_initialization():
+ """测试OpenBB提供商适配器初始化"""
+ from src.jixia.engines.openbb_adapter import OpenBBDataProvider
+ provider = OpenBBDataProvider()
+ assert provider.name == "OpenBB"
+ assert provider.priority == 1
+
+def test_rapidapi_provider_initialization():
+ """测试RapidAPI提供商适配器初始化"""
+ from src.jixia.engines.rapidapi_adapter import RapidAPIDataProvider
+ provider = RapidAPIDataProvider()
+ assert provider.name == "RapidAPI"
+ assert provider.priority == 2
+
+def test_provider_data_retrieval():
+ """测试提供商数据检索功能"""
+ # 使用模拟数据测试各提供商的数据获取方法
+ pass
+```
+
+#### 1.2 数据抽象层管理器测试
+```python
+# tests/test_data_abstraction_layer.py
+
+def test_dal_initialization():
+ """测试数据抽象层初始化"""
+ from src.jixia.engines.data_abstraction_layer import DataAbstractionLayer
+ dal = DataAbstractionLayer()
+ # 验证提供商是否正确加载
+ assert len(dal.providers) >= 1
+
+def test_dal_quote_retrieval():
+ """测试数据抽象层报价获取"""
+ from src.jixia.engines.data_abstraction_layer import DataAbstractionLayer
+ dal = DataAbstractionLayer()
+ quote = dal.get_quote("AAPL")
+ # 验证返回数据结构
+ if quote is not None:
+ assert hasattr(quote, 'symbol')
+ assert hasattr(quote, 'price')
+
+def test_dal_fallback_mechanism():
+ """测试故障转移机制"""
+ # 模拟主提供商失败,验证是否能正确切换到备用提供商
+ pass
+```
+
+### 2. 引擎组件测试
+
+#### 2.1 OpenBB引擎测试
+```python
+# tests/test_openbb_engine.py
+
+def test_openbb_engine_initialization():
+ """测试OpenBB引擎初始化"""
+ from src.jixia.engines.openbb_engine import OpenBBEngine
+ engine = OpenBBEngine()
+ # 验证引擎是否正确初始化
+ assert engine is not None
+
+def test_openbb_engine_data_retrieval():
+ """测试OpenBB引擎数据获取"""
+ from src.jixia.engines.openbb_engine import OpenBBEngine
+ engine = OpenBBEngine()
+ result = engine.get_immortal_data("吕洞宾", "price", "AAPL")
+ # 验证返回结果结构
+ assert hasattr(result, 'success')
+ if result.success:
+ assert result.data is not None
+
+def test_openbb_engine_unavailable():
+ """测试OpenBB不可用时的行为"""
+ # 通过模拟环境测试OpenBB未安装时的降级行为
+ pass
+```
+
+#### 2.2 永动机引擎测试
+```python
+# tests/test_perpetual_engine.py
+
+def test_perpetual_engine_initialization():
+ """测试永动机引擎初始化"""
+ from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine
+ # 注意:需要提供有效的RapidAPI密钥进行测试
+ pass
+
+def test_perpetual_engine_data_retrieval():
+ """测试永动机引擎数据获取"""
+ pass
+```
+
+### 3. UI组件测试
+
+#### 3.1 OpenBB标签页测试
+```python
+# tests/test_openbb_tab.py
+
+def test_openbb_tab_data_loading():
+ """测试OpenBB标签页数据加载"""
+ # 验证在不同环境下的数据加载行为
+ pass
+
+def test_openbb_tab_fallback():
+ """测试OpenBB标签页降级机制"""
+ # 验证当OpenBB不可用时是否正确显示演示数据
+ pass
+```
+
+### 4. 集成测试
+
+#### 4.1 八仙智能体数据访问测试
+```python
+# tests/test_baxian_data_access.py
+
+def test_immortal_data_mapping():
+ """测试八仙与数据源的映射关系"""
+ from src.jixia.engines.baxian_data_mapping import immortal_data_mapping
+ # 验证所有八仙都有正确的数据源映射
+ assert len(immortal_data_mapping) == 8
+ for immortal in ['吕洞宾', '何仙姑', '张果老', '韩湘子', '汉钟离', '蓝采和', '铁拐李', '曹国舅']:
+ assert immortal in immortal_data_mapping
+
+def test_immortal_data_retrieval():
+ """测试八仙智能体数据获取"""
+ # 验证每个八仙都能通过数据抽象层获取到所需数据
+ pass
+```
+
+#### 4.2 端到端辩论流程测试
+```python
+# tests/test_debate_flow_with_openbb.py
+
+def test_debate_with_openbb_data():
+ """测试使用OpenBB数据的完整辩论流程"""
+ # 验证辩论系统能正确使用OpenBB提供的数据
+ pass
+```
+
+## 性能测试
+
+### 1. 响应时间测试
+```python
+# tests/performance/test_response_time.py
+
+def test_quote_retrieval_response_time():
+ """测试报价获取响应时间"""
+ import time
+ from src.jixia.engines.data_abstraction_layer import DataAbstractionLayer
+ dal = DataAbstractionLayer()
+
+ start_time = time.time()
+ quote = dal.get_quote("AAPL")
+ end_time = time.time()
+
+ response_time = end_time - start_time
+ # 验证响应时间在可接受范围内
+ assert response_time < 2.0 # 假设2秒为阈值
+```
+
+### 2. 并发访问测试
+```python
+# tests/performance/test_concurrent_access.py
+
+def test_concurrent_quote_retrieval():
+ """测试并发报价获取"""
+ import asyncio
+ from src.jixia.engines.data_abstraction_layer import DataAbstractionLayer
+
+ async def get_quote(symbol):
+ dal = DataAbstractionLayer()
+ return await dal.get_quote_async(symbol)
+
+ async def get_multiple_quotes():
+ symbols = ["AAPL", "GOOGL", "MSFT", "TSLA"]
+ tasks = [get_quote(symbol) for symbol in symbols]
+ return await asyncio.gather(*tasks)
+
+ # 运行并发测试
+ quotes = asyncio.run(get_multiple_quotes())
+ # 验证所有请求都成功返回
+ assert len(quotes) == 4
+```
+
+## 验证标准
+
+### 功能验证标准
+1. **数据准确性**:返回的数据格式和内容符合预期
+2. **故障转移**:当主数据源不可用时,系统能自动切换到备用数据源
+3. **优雅降级**:当OpenBB未安装时,系统能正常运行并使用演示数据
+4. **八仙映射**:每个八仙都能访问其专属的数据源和类型
+
+### 性能验证标准
+1. **响应时间**:单次数据请求响应时间不超过2秒
+2. **并发处理**:系统能同时处理至少10个并发数据请求
+3. **资源使用**:内存使用在合理范围内,无内存泄漏
+4. **缓存效率**:缓存命中率应达到80%以上
+
+### 兼容性验证标准
+1. **Python版本**:支持Python 3.8及以上版本
+2. **OpenBB版本**:支持OpenBB v4.1.0及以上版本
+3. **环境变量**:正确处理各种环境变量配置
+4. **依赖管理**:OpenBB作为可选依赖,不影响主系统安装
+
+## 持续集成/持续部署(CI/CD)集成
+
+### GitHub Actions工作流
+```yaml
+# .github/workflows/openbb_integration_test.yml
+
+name: OpenBB Integration Test
+
+on:
+ push:
+ branches: [ main, develop ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [3.8, 3.9, '3.10', '3.11']
+ openbb-installed: [true, false]
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ if [ "${{ matrix.openbb-installed }}" = "true" ]; then
+ pip install "openbb>=4.1.0"
+ fi
+ - name: Run tests
+ run: |
+ pytest tests/test_openbb_*.py
+ pytest tests/test_data_abstraction_*.py
+```
+
+## 监控和告警
+
+### 关键指标监控
+1. **数据源可用性**:监控各数据提供商的可用性
+2. **响应时间**:监控数据请求的平均响应时间
+3. **错误率**:监控数据访问的错误率
+4. **缓存命中率**:监控缓存的使用效率
+
+### 告警策略
+1. **可用性告警**:当数据源可用性低于95%时触发告警
+2. **性能告警**:当平均响应时间超过阈值时触发告警
+3. **错误率告警**:当错误率超过1%时触发告警
+4. **缓存告警**:当缓存命中率低于70%时触发告警
+
+## 结论
+
+这套测试和验证方案确保了OpenBB集成的高质量交付,通过全面的功能测试、性能测试和持续集成,能够及时发现和修复潜在问题,保证系统的稳定性和可靠性。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/baxian_debate_order_guide.md b/modules/documentation-suite/docs/baxian_debate_order_guide.md
new file mode 100644
index 0000000..b4dcf42
--- /dev/null
+++ b/modules/documentation-suite/docs/baxian_debate_order_guide.md
@@ -0,0 +1,19 @@
+# 八仙辩论次序指南 (Baxian Debate Order Guide)
+
+## 核心原则
+
+辩论次序基于“对立统一”的哲学思想,将八仙分为四组,每组代表一对核心矛盾。此规则为项目级最终版本,作为后续所有相关实现的基准。
+
+## 分组
+
+1. **乾坤 / 男女:** 吕洞宾 (乾/男) vs 何仙姑 (坤/女)
+ * **逻辑:** 阳与阴,男与女的基本对立。
+
+2. **老少:** 张果老 vs 韩湘子
+ * **逻辑:** 年长与年少,经验与活力的对立。
+
+3. **贫富:** 汉钟离 vs 蓝采和
+ * **逻辑:** 富贵与贫穷,物质与精神的对立。汉钟离出身将门,而蓝采和的形象通常是贫穷的歌者。
+
+4. **贵贱:** 曹国舅 vs 铁拐李
+ * **逻辑:** 皇亲国戚与街头乞丐,社会地位的极端对立。
diff --git a/modules/documentation-suite/docs/cloudflare_memory_banks.md b/modules/documentation-suite/docs/cloudflare_memory_banks.md
new file mode 100644
index 0000000..1279a95
--- /dev/null
+++ b/modules/documentation-suite/docs/cloudflare_memory_banks.md
@@ -0,0 +1,87 @@
+# 八仙记忆银行文档 (Cloudflare AutoRAG)
+
+每个八仙智能体都有一个专属的记忆空间,用于存储其在不同辩论主题下的记忆。这些记忆通过Cloudflare Vectorize进行向量索引,并利用Workers AI进行语义检索。
+
+## 记忆类型
+
+1. **对话记忆 (conversation)**: 智能体在特定辩论中的发言和互动记录。
+2. **偏好记忆 (preference)**: 智能体的投资偏好、分析方法和决策倾向。
+3. **知识记忆 (knowledge)**: 智能体掌握的金融知识、市场信息和分析模型。
+4. **策略记忆 (strategy)**: 智能体在辩论中使用的论证策略和战术。
+
+## 八仙记忆空间列表
+
+- **铁拐李 (tieguaili)**
+ - 标识符: `cf_memory_tieguaili`
+ - 特点: 擅长技术分析和风险控制
+
+- **汉钟离 (hanzhongli)**
+ - 标识符: `cf_memory_hanzhongli`
+ - 特点: 注重基本面分析和长期价值
+
+- **张果老 (zhangguolao)**
+ - 标识符: `cf_memory_zhangguolao`
+ - 特点: 擅长宏观趋势分析和周期判断
+
+- **蓝采和 (lancaihe)**
+ - 标识符: `cf_memory_lancaihe`
+ - 特点: 关注市场情绪和资金流向
+
+- **何仙姑 (hexiangu)**
+ - 标识符: `cf_memory_hexiangu`
+ - 特点: 精于财务数据分析和估值模型
+
+- **吕洞宾 (lvdongbin)**
+ - 标识符: `cf_memory_lvdongbin`
+ - 特点: 善于多维度综合分析和创新策略
+
+- **韩湘子 (hanxiangzi)**
+ - 标识符: `cf_memory_hanxiangzi`
+ - 特点: 擅长行业比较和相对价值分析
+
+- **曹国舅 (caoguojiu)**
+ - 标识符: `cf_memory_caoguojiu`
+ - 特点: 注重合规性、社会责任和ESG因素
+
+## 使用方法
+
+```python
+from src.jixia.memory.factory import get_memory_backend
+
+# 获取记忆后端 (自动根据环境变量选择)
+memory_bank = get_memory_backend(prefer="cloudflare")
+
+# 为吕洞宾添加偏好记忆
+await memory_bank.add_memory(
+ agent_name="lvdongbin",
+ content="倾向于使用DCF模型评估科技股的内在价值",
+ memory_type="preference",
+ debate_topic="TSLA投资分析"
+)
+
+# 搜索吕洞宾关于TSLA的记忆
+memories = await memory_bank.search_memories(
+ agent_name="lvdongbin",
+ query="TSLA",
+ memory_type="preference"
+)
+
+# 获取上下文
+context = await memory_bank.get_agent_context("lvdongbin", "TSLA投资分析")
+```
+
+## Cloudflare配置说明
+
+要使用Cloudflare AutoRAG作为记忆后端,需要配置以下环境变量:
+
+- `CLOUDFLARE_ACCOUNT_ID`: Cloudflare账户ID
+- `CLOUDFLARE_API_TOKEN`: Cloudflare API令牌 (需要Vectorize和Workers AI权限)
+- `JIXIA_MEMORY_BACKEND`: 设置为 `cloudflare`
+
+系统默认使用以下配置:
+- Vectorize索引: `autorag-shy-cherry-f1fb`
+- 嵌入模型: `@cf/baai/bge-m3`
+- AutoRAG域名: `autorag.seekkey.tech`
+
+---
+*此文档由系统自动生成和维护*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/custom_modules_tutorial.md b/modules/documentation-suite/docs/custom_modules_tutorial.md
new file mode 100644
index 0000000..14ce9cd
--- /dev/null
+++ b/modules/documentation-suite/docs/custom_modules_tutorial.md
@@ -0,0 +1,162 @@
+# Developer Tutorial: Creating Custom Modules
+
+Welcome, contributor! This guide will show you how to extend the "太公心易" system by creating your own custom `MythologyEngine` and `CycleModel`.
+
+The system is built on the principle of decoupling, using Abstract Base Classes (ABCs) to separate the core logic of the `MarketFSM` from the specific cultural or analytical models it uses. By creating new classes that inherit from these ABCs, you can fundamentally change the system's narrative and analytical framework without touching the core FSM logic.
+
+## Part 1: Creating a Custom Mythology Engine
+
+A `MythologyEngine` is responsible for providing the narrative flavor to the system. It maps technical components to mythological figures and processes. Let's create a `GreekMythologyEngine` as an example.
+
+### Step 1: Create a New Python File
+
+Create a new file, for example, `greek_mythology.py`.
+
+### Step 2: Import the `MythologyEngine` ABC
+
+In your new file, import the abstract base class from `mythology.py`:
+
+```python
+# greek_mythology.py
+from mythology import MythologyEngine
+```
+
+### Step 3: Implement the `MythologyEngine` Interface
+
+Create a new class that inherits from `MythologyEngine` and implements all its abstract methods: `get_actor_name`, `get_process_metaphor`, and `get_system_narrative`.
+
+```python
+class GreekMythologyEngine(MythologyEngine):
+ """
+ An implementation of the MythologyEngine based on Greek mythology.
+ """
+ def __init__(self):
+ self._actor_map = {
+ 'collector': 'The Muses',
+ 'refiner': 'Hephaestus',
+ 'verifier': 'Apollo',
+ 'synthesizer': 'Zeus',
+ }
+ self._process_map = {
+ 'multi_agent_debate': 'Symposium',
+ 'refinement_process': 'Forging in Aetna',
+ 'external_verification': 'Consulting the Oracle of Delphi',
+ 'final_decision': 'Judgment from Olympus',
+ }
+ self._narrative = "This system views the market as a pantheon of competing gods and heroes, striving for dominance on Mount Olympus."
+
+ def get_actor_name(self, component: str) -> str:
+ return self._actor_map.get(component, "An Unknown Titan")
+
+ def get_process_metaphor(self, process: str) -> str:
+ return self._process_map.get(process, "A Herculean Task")
+
+ def get_system_narrative(self) -> str:
+ return self._narrative
+```
+
+### Step 4: Integrate with the FSM
+
+Now, you can instantiate your new engine and inject it into the `MarketFSM`. The FSM will work seamlessly with your new narrative layer.
+
+```python
+# In your main application file
+from market_fsm import MarketFSM
+from greek_mythology import GreekMythologyEngine
+from cycle_models import TwelveStagesOfLifeCycleModel # We can reuse the old cycle model
+
+# Instantiate your custom engine
+greek_engine = GreekMythologyEngine()
+cycle_model = TwelveStagesOfLifeCycleModel()
+
+# Inject it into the FSM
+fsm = MarketFSM(
+ mythology_engine=greek_engine,
+ cycle_model=cycle_model
+)
+
+# Run the analysis
+fsm.run_analysis({"mock_score": 8})
+# The output will now be framed in the language of Greek mythology!
+```
+
+## Part 2: Creating a Custom Cycle Model
+
+A `CycleModel` is responsible for analyzing market data and determining the current stage of a given cycle. Let's create a simple `MarketSentimentCycleModel` based on four stages: Greed, Fear, Hope, and Despair.
+
+### Step 1: Create a New Python File
+
+Create a file named `sentiment_cycle.py`.
+
+### Step 2: Import the `CycleModel` ABC
+
+```python
+# sentiment_cycle.py
+from cycle_models import CycleModel
+from typing import Dict, Any, List
+```
+
+### Step 3: Implement the `CycleModel` Interface
+
+Create a new class that inherits from `CycleModel` and implements `get_current_stage`, `get_stage_characteristics`, and `get_all_stages`.
+
+```python
+class MarketSentimentCycleModel(CycleModel):
+ """
+ A cycle model based on the four stages of market sentiment.
+ """
+ def __init__(self):
+ self._stages = ["Hope", "Greed", "Fear", "Despair"]
+ self._characteristics = {
+ "Hope": {"description": "The market is cautiously optimistic.", "strategy": "Accumulate"},
+ "Greed": {"description": "Euphoria and high expectations dominate.", "strategy": "Take profits"},
+ "Fear": {"description": "Panic and uncertainty are widespread.", "strategy": "Reduce risk"},
+ "Despair": {"description": "Capitulation, the market has given up hope.", "strategy": "Look for bargains"},
+ }
+
+ def get_current_stage(self, data: Dict[str, Any]) -> str:
+ # A real implementation would analyze news sentiment, VIX, etc.
+ # Here, we'll use a mock sentiment score from 0 to 1.
+ sentiment_score = data.get("sentiment", 0.5)
+ if sentiment_score > 0.75:
+ return "Greed"
+ elif sentiment_score > 0.5:
+ return "Hope"
+ elif sentiment_score > 0.25:
+ return "Fear"
+ else:
+ return "Despair"
+
+ def get_stage_characteristics(self, stage: str) -> Dict[str, Any]:
+ return self._characteristics.get(stage, {})
+
+ def get_all_stages(self) -> List[str]:
+ return self._stages
+```
+
+### Step 4: Integrate with the FSM
+
+You can now use your new cycle model in the FSM, even combining it with a different mythology engine.
+
+```python
+# In your main application file
+from market_fsm import MarketFSM
+from mythology import DaoistMythologyEngine
+from sentiment_cycle import MarketSentimentCycleModel
+
+# Instantiate your custom cycle model
+sentiment_model = MarketSentimentCycleModel()
+daoist_engine = DaoistMythologyEngine()
+
+# Inject it into the FSM
+fsm = MarketFSM(
+ mythology_engine=daoist_engine,
+ cycle_model=sentiment_model
+)
+
+# Run the analysis with data your new model understands
+fsm.run_analysis({"sentiment": 0.2})
+# The FSM will now report the market is in a state of "Despair".
+```
+
+Congratulations! You have successfully extended the "太公心易" system.
diff --git a/modules/documentation-suite/docs/development/CANARY_DEV_BETA_DEPLOYMENT.md b/modules/documentation-suite/docs/development/CANARY_DEV_BETA_DEPLOYMENT.md
new file mode 100644
index 0000000..836bdf4
--- /dev/null
+++ b/modules/documentation-suite/docs/development/CANARY_DEV_BETA_DEPLOYMENT.md
@@ -0,0 +1,100 @@
+# 金丝雀/开发/测试部署策略
+
+## 环境命名
+
+根据新的命名约定,三个环境重新命名为:
+
+- **canary** (金丝雀环境): `https://gitea.tailnet-68f9.ts.net/gitea/liurenchaxin.git`
+- **dev** (开发环境): `git@bitbucket.org:capitaltrain/liurenchaxin.git`
+- **beta** (测试环境): `https://github.com/jingminzhang/taigongxinyi.git`
+
+## 环境用途
+
+- **canary (金丝雀)**: 最新功能测试,早期验证
+- **dev (开发)**: 功能开发和集成测试
+- **beta (测试)**: 预发布测试,用户验收
+
+## 部署流程
+
+### 1. 日常开发流程
+
+```bash
+# 在 canary 环境开发新功能
+git checkout main
+git pull canary main
+# 开发完成后
+git add .
+git commit -m "feat: 新功能描述"
+git push canary main
+```
+
+### 2. 集成测试流程
+
+```bash
+# 将功能从 canary 推送到 dev 环境
+git checkout main
+git pull dev main
+git merge main
+git push dev main
+```
+
+### 3. 预发布流程
+
+```bash
+# 将功能从 dev 推送到 beta 环境
+git checkout main
+git pull beta main
+git merge main
+git push beta main
+```
+
+## 快速命令
+
+### 发布新版本
+
+```bash
+# 金丝雀环境发布
+./scripts/quick-release.sh 1.2.3 canary
+
+# 开发环境发布
+./scripts/quick-release.sh 1.2.3 dev
+
+# 测试环境发布
+./scripts/quick-release.sh 1.2.3 beta
+```
+
+### 回滚操作
+
+```bash
+# 回滚金丝雀环境
+./scripts/rollback.sh canary 1.2.2
+
+# 回滚开发环境
+./scripts/rollback.sh dev 1.2.2
+
+# 回滚测试环境
+./scripts/rollback.sh beta 1.2.2
+```
+
+### 状态检查
+
+```bash
+./scripts/check-status.sh
+```
+
+## 分支策略
+
+- **main**: 所有环境统一使用main分支
+
+## 标签命名
+
+- 金丝雀: `v1.2.3-canary`
+- 开发: `v1.2.3-dev`
+- 测试: `v1.2.3-beta`
+
+## 优势
+
+1. **清晰的命名**: canary/dev/beta 更符合行业标准
+2. **渐进发布**: 从金丝雀到测试的渐进式验证
+3. **快速回滚**: 每个环境都可以独立回滚
+4. **隔离性好**: 不同环境完全隔离,减少干扰
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/development/DEPLOYMENT_FLOW.md b/modules/documentation-suite/docs/development/DEPLOYMENT_FLOW.md
new file mode 100644
index 0000000..04cedb5
--- /dev/null
+++ b/modules/documentation-suite/docs/development/DEPLOYMENT_FLOW.md
@@ -0,0 +1,196 @@
+# 六壬神鉴渐进发布流程图
+
+## 🎯 发布流程概览
+
+```
+┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ Development │ │ Staging │ │ Canary │ │ Production │
+│ (Gitea) │───▶│ (Bitbucket) │───▶│ (GitHub 10%) │───▶│ (GitHub 100%) │
+│ develop分支 │ │ staging分支 │ │ main分支 │ │ main分支 │
+└─────────────────┘ └──────────────────┘ └─────────────────┘ └─────────────────┘
+ │ │ │ │
+ │ │ │ │
+ ▼ ▼ ▼ ▼
+┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ 功能开发 │ │ 集成测试 │ │ 灰度验证 │ │ 全量发布 │
+│ 单元测试 │ │ 性能测试 │ │ 监控验证 │ │ 持续监控 │
+│ 代码审查 │ │ 安全扫描 │ │ 用户反馈 │ │ 性能优化 │
+└─────────────────┘ └──────────────────┘ └─────────────────┘ └─────────────────┘
+```
+
+## 🚀 快速操作指南
+
+### 1. 日常开发流程
+
+#### 开始新功能开发
+```bash
+# 从 develop 分支创建功能分支
+git checkout develop
+git pull origin develop
+git checkout -b feature/new-feature
+
+# 开发完成后
+git add .
+git commit -m "feat: 添加新功能"
+git push origin feature/new-feature
+
+# 创建 PR 到 develop 分支
+# 在 Gitea 上创建 Pull Request
+```
+
+#### 推送到开发环境
+```bash
+# 一键推送到 Gitea 开发环境
+git checkout develop
+git pull origin develop
+git merge feature/new-feature
+git push gitea develop
+```
+
+### 2. 预发布流程
+
+#### 准备 staging 发布
+```bash
+# 创建发布分支
+git checkout staging
+git merge develop
+git push staging staging:main
+
+# 或使用快捷命令
+git deploy-staging
+```
+
+#### 验证 staging 环境
+```bash
+# 检查 staging 状态
+./scripts/check-status.sh
+```
+
+### 3. 灰度发布流程
+
+#### 启动灰度发布
+```bash
+# 创建灰度版本
+git checkout main
+git merge staging
+git tag v1.2.0-canary
+git push origin main --tags
+```
+
+#### 监控灰度状态
+```bash
+# 检查发布状态
+curl -s https://api.github.com/repos/jingminzhang/taigongxinyi/releases/latest
+```
+
+### 4. 全量发布流程
+
+#### 正式版本发布
+```bash
+# 使用快速发布脚本
+./scripts/quick-release.sh 1.2.0 prod
+
+# 或手动操作
+git checkout main
+git tag v1.2.0
+git push origin main --tags
+git deploy-prod
+```
+
+## 📊 发布检查清单
+
+### 开发阶段检查
+- [ ] 代码通过单元测试
+- [ ] 功能测试完成
+- [ ] 代码审查通过
+- [ ] 文档已更新
+
+### Staging 阶段检查
+- [ ] 集成测试通过
+- [ ] 性能测试完成
+- [ ] 安全扫描通过
+- [ ] 用户验收测试完成
+
+### 灰度发布检查
+- [ ] 监控指标正常
+- [ ] 错误率 < 0.1%
+- [ ] 用户反馈良好
+- [ ] 业务指标稳定
+
+### 全量发布检查
+- [ ] 灰度验证通过
+- [ ] 回滚方案就绪
+- [ ] 监控告警配置
+- [ ] 紧急联系清单
+
+## 🔄 回滚操作
+
+### 紧急回滚
+```bash
+# 快速回滚到指定版本
+./scripts/rollback.sh prod 1.1.9
+
+# 或手动回滚
+git checkout v1.1.9
+git tag v1.2.0-rollback
+git push origin main --force
+```
+
+### 回滚验证
+```bash
+# 检查回滚状态
+./scripts/check-status.sh
+```
+
+## 📈 监控面板
+
+### 关键指标监控
+- **系统性能**: CPU、内存、磁盘使用率
+- **应用性能**: 响应时间、吞吐量、错误率
+- **业务指标**: 用户活跃度、功能使用率
+
+### 告警规则
+- 错误率 > 1% → 立即告警
+- 响应时间 > 1s → 立即告警
+- 服务不可用 → 立即告警
+
+## 🛠️ 工具命令速查
+
+| 操作 | 命令 | 说明 |
+|------|------|------|
+| 查看状态 | `./scripts/check-status.sh` | 检查所有环境状态 |
+| 快速发布 | `./scripts/quick-release.sh 版本号 环境` | 一键发布到指定环境 |
+| 紧急回滚 | `./scripts/rollback.sh 环境 版本号` | 快速回滚到指定版本 |
+| 推送到 staging | `git deploy-staging` | 推送到 Bitbucket staging |
+| 推送到 prod | `git deploy-prod` | 推送到 GitHub production |
+| 同步所有远程 | `git sync-all` | 同步所有远程仓库 |
+
+## 📞 紧急联系
+
+| 角色 | 联系方式 | 职责 |
+|------|----------|------|
+| 技术负责人 | ben@capitaltrain.cn | 技术决策、紧急响应 |
+| 运维团队 | ops@capitaltrain.cn | 部署、监控、故障处理 |
+| 产品团队 | product@capitaltrain.cn | 业务决策、用户沟通 |
+
+## 🎓 最佳实践
+
+### 1. 分支管理
+- 功能分支从 `develop` 创建
+- 发布分支从 `staging` 创建
+- 热修复分支从 `main` 创建
+
+### 2. 版本命名
+- 主版本: 不兼容的重大更新
+- 次版本: 向后兼容的功能添加
+- 修订版本: bug修复和微小改进
+
+### 3. 发布频率
+- 紧急修复: 随时发布
+- 常规更新: 每2周一次
+- 大版本更新: 每季度一次
+
+### 4. 监控策略
+- 灰度期间: 24-48小时密切监控
+- 全量发布: 72小时持续监控
+- 日常运维: 实时告警监控
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/development/GAMEFI_FSM_INTEGRATION_PLAN.md b/modules/documentation-suite/docs/development/GAMEFI_FSM_INTEGRATION_PLAN.md
new file mode 100644
index 0000000..1063811
--- /dev/null
+++ b/modules/documentation-suite/docs/development/GAMEFI_FSM_INTEGRATION_PLAN.md
@@ -0,0 +1,114 @@
+# 方案:GameFi“盘下特征”量化及FSM状态转移集成
+
+**制定者:** Gemini
+**日期:** 2025-08-21
+**目标:** 将`GAMEFI_SYSTEM_SUMMARY.md`中定义的“交易者心境”和“十二长生”(四季轮回)概念,转化为可量化的数据模型,并将其作为“太公心易”FSM系统状态转移的核心驱动条件。
+
+---
+
+## 1. 核心思想
+
+交易者的心境、经验和偏见是驱动其市场行为的“盘下特征”。通过量化这些特征,我们可以让主FSM的决策更具个性化和前瞻性。当检测到交易者进入特定的心理阶段(如“秋季失道”)或表现出强烈的偏见(如“趋势醉”)时,FSM可以主动进入相应状态(如`Refine`或`Validation`)进行干预和辅助。
+
+## 2. “盘下特征”量化方案
+
+我们将构建一个**“交易者状态向量”(Trader State Vector, TSV)**来统一描述交易者的当前心境。该向量由以下三组量化指标构成:
+
+### 2.1. **伤疤资本 (Scar Capital)** - 经验与教训的量化
+
+基于`TradingScar`概念,我们将从交易历史中计算以下指标:
+
+* **总痛苦值 (TotalPain):** 所有`TradingScar`的`pain_level`之和。反映交易者经历的总挫折。
+* **平均智慧 (AverageWisdom):** 所有`wisdom_gained`的平均值。反映交易者从错误中学习的能力。
+* **伤疤密度 (ScarDensity):** 单位时间(如每季度)内产生的`TradingScar`数量。高密度可能意味着鲁莽或市场环境恶化。
+* **恢复能力 (Resilience):** 从重大亏损(高`pain_level`的`Scar`)后,恢复盈利所需的时间。
+
+### 2.2. **偏见画像 (Bias Profile)** - “醉八仙”的量化
+
+通过分析交易行为,为每个交易者生成一个包含八种偏见得分(0到1之间)的画像:
+
+* **趋势醉 (蓝采和):** 在价格接近阶段性高点时买入的频率和资金比例。
+* **价值醉 (汉钟离):** 在亏损头寸上持续加仓(“补仓”)的行为频率。
+* **消息醉 (曹国舅):** 在重大新闻或财报发布窗口期内,交易频率显著上升。
+* **经验醉 (张果老):** 策略的同质性过高,例如只交易特定几只股票或只使用单一指标。
+* **技术醉 (韩湘子):** 交易行为与特定技术指标(如MACD金叉/死叉)的强相关性。
+* **保守醉 (何仙姑):** 空仓时间占比过高,或在明显上涨趋势中过早卖出。
+* **逆向醉 (铁拐李):** 在市场普遍下跌时买入,或在普遍上涨时卖出的频率。
+* **理性醉 (吕洞宾):** 交易频率极低,可能错失过多机会(机会成本)。
+
+### 2.3. **修仙阶段 (Journey Stage)** - “猴王四季”的量化
+
+结合**伤疤资本**和**偏见画像**,我们可以为交易者划分出当前的“修仙”阶段:
+
+* **春季·觉醒 (Awakening):**
+ * `TotalPain`较低,`ScarDensity`较低。
+ * `AverageWisdom`较高(学习意愿强)。
+ * 偏见画像尚未固化。
+* **夏季·得道 (Attainment):**
+ * 交易胜率高,账户稳定增长。
+ * `AverageWisdom`可能开始下降(过度自信)。
+ * 某几种偏见得分开始显著升高。
+* **秋季·失道 (Loss):**
+ * 出现一次或多次高`pain_level`的`Scar`。
+ * `TotalPain`急剧上升,`Resilience`指标被考验。
+ * 高偏见得分与重大亏损有强相关性。
+* **冬季·悟道 (Enlightenment):**
+ * `Resilience`高,能够从亏损中快速恢复。
+ * 整体偏见画像得分较低且均衡。
+ * `AverageWisdom`稳定在较高水平。
+
+## 3. FSM状态转移集成方案
+
+“交易者状态向量”(TSV)将被整合到“太公心易”FSM的上下文中,作为状态转移的核心判断依据。
+
+### 3.1. 触发条件示例
+
+FSM不再仅仅响应外部市场事件,更会主动响应交易者的内在状态变化。
+
+* **进入`Refine`状态(太上老君整理):**
+ * **触发器:** 检测到交易者进入“秋季·失道”阶段。
+ * **条件:** `IF trader.stage == 'Loss' AND trader.bias_profile['TrendChasing'] > 0.8`
+ * **目的:** 交易者因强烈的趋势偏见而遭受重创,FSM需要启动`Refine`流程,帮助其“祛魅”并重构策略。
+
+* **进入`Validation`状态(内部验证/祛魅):**
+ * **触发器:** 交易者处于“夏季·得道”阶段,表现出过度自信。
+ * **条件:** `IF trader.stage == 'Attainment' AND trader.AverageWisdom < threshold`
+ * **目的:** 在交易者最容易忽视风险时,FSM主动进入`Validation`状态,对其当前的策略进行压力测试和一致性检查。
+
+* **进入`ExternalFetch`状态(灵宝道君核查):**
+ * **触发器:** “消息醉”交易者准备进行一笔交易。
+ * **条件:** `IF trader.bias_profile['NewsTrading'] > 0.7 AND event == 'pre_trade_check'`
+ * **目的:** 在该交易者依据消息行动前,FSM强制启动`ExternalFetch`,从多个独立信源交叉验证该消息的可靠性。
+
+### 3.2. 状态转移逻辑 (伪代码)
+
+```python
+class EnhancedTaigongFSM:
+ def __init__(self, trader_state_vector):
+ self.tsv = trader_state_vector
+ # ... other FSM initializations
+
+ def determine_next_state(self, market_event):
+ # 优先处理由交易者内在状态触发的转移
+ if self.tsv.stage == 'Loss':
+ # 如果交易者遭受重创,无论市场如何,优先帮助其反思
+ return FSMState.REFINE
+
+ if self.tsv.is_overconfident():
+ # 如果交易者过度自信,主动进行风险检查
+ return FSMState.VALIDATION
+
+ # ... 再处理由外部市场事件触发的转移
+ if market_event == 'HighVolatility':
+ return FSMState.COLLECTING
+
+ return self.current_state
+```
+
+## 4. 实施步骤
+
+1. **数据建模:** 在代码中定义`TradingScar`, `BiasProfile`, 和 `TraderStateVector`的类结构。
+2. **分析模块开发:** 创建一个分析器,能够接收交易历史数据,并计算出完整的TSV。
+3. **FSM上下文集成:** 将TSV对象添加到`TaigongXinyiFSM`的上下文中。
+4. **规则引擎实现:** 在FSM的`transition`逻辑中,实现基于TSV的动态状态转移规则。
+5. **模拟与回测:** 构建一个模拟环境,使用历史交易数据回测该集成系统的有效性,验证其是否能在关键时刻做出正确的状态转移。
diff --git a/modules/documentation-suite/docs/development/GRADUAL_DEPLOYMENT_PLAN.md b/modules/documentation-suite/docs/development/GRADUAL_DEPLOYMENT_PLAN.md
new file mode 100644
index 0000000..582cf28
--- /dev/null
+++ b/modules/documentation-suite/docs/development/GRADUAL_DEPLOYMENT_PLAN.md
@@ -0,0 +1,225 @@
+# 六壬神鉴渐进发布计划
+
+## 概述
+本计划基于当前的多环境 Git 配置,实现从开发到生产的渐进式发布流程。
+
+## 环境架构
+
+### 当前配置
+- **GitHub** (production): `https://github.com/jingminzhang/taigongxinyi.git`
+- **Bitbucket** (staging): `git@bitbucket.org:capitaltrain/liurenchaxin.git`
+- **Gitea** (development): `https://gitea.tailnet-68f9.ts.net/gitea/liurenchaxin.git`
+
+### 分支策略
+```
+main (生产环境)
+├── staging (预发布环境)
+├── develop (开发环境)
+└── feature/* (功能分支)
+```
+
+## 渐进发布阶段
+
+### 阶段1:功能开发 (Development)
+**目标环境**: Gitea (development)
+**分支**: `feature/*` → `develop`
+
+#### 流程
+1. 从 `develop` 分支创建功能分支
+2. 在功能分支上进行开发
+3. 完成功能后合并到 `develop`
+4. 推送到 Gitea 进行初步测试
+
+#### 验证清单
+- [ ] 单元测试通过
+- [ ] 代码审查完成
+- [ ] 功能测试通过
+- [ ] 文档更新完成
+
+### 阶段2:集成测试 (Staging)
+**目标环境**: Bitbucket (staging)
+**分支**: `develop` → `staging`
+
+#### 流程
+1. 从 `develop` 分支创建发布分支 `release/vX.Y.Z`
+2. 在 staging 环境部署测试
+3. 进行集成测试和用户验收测试
+4. 修复发现的问题
+5. 合并到 `staging` 分支
+6. 推送到 Bitbucket staging 环境
+
+#### 验证清单
+- [ ] 集成测试通过
+- [ ] 性能测试通过
+- [ ] 安全扫描通过
+- [ ] 用户验收测试完成
+- [ ] 回滚方案准备就绪
+
+### 阶段3:灰度发布 (Canary)
+**目标环境**: GitHub production (10%流量)
+**分支**: `staging` → `main`
+
+#### 流程
+1. 创建灰度发布标签 `vX.Y.Z-canary`
+2. 部署到生产环境 10% 流量
+3. 监控关键指标 24-48小时
+4. 根据监控结果决定全量发布或回滚
+
+#### 监控指标
+- [ ] 错误率 < 0.1%
+- [ ] 响应时间 < 500ms
+- [ ] 用户满意度 > 95%
+- [ ] 业务指标正常
+
+### 阶段4:全量发布 (Production)
+**目标环境**: GitHub production (100%流量)
+**分支**: `main`
+
+#### 流程
+1. 创建正式版本标签 `vX.Y.Z`
+2. 全量部署到生产环境
+3. 持续监控 72小时
+4. 准备热修复方案
+
+## 发布策略
+
+### 版本命名规范
+- **主版本** (X.0.0): 重大功能更新或不兼容变更
+- **次版本** (X.Y.0): 新功能添加,向后兼容
+- **修订版本** (X.Y.Z): bug修复或小改进
+
+### 发布频率
+- **紧急修复**: 随时发布
+- **常规更新**: 每2周一次
+- **大版本更新**: 每季度一次
+
+### 回滚策略
+```bash
+# 快速回滚到上一个版本
+git revert HEAD
+git push origin main --force
+
+# 或使用标签回滚
+git checkout vX.Y.Z-1
+git tag -a vX.Y.Z-rollback -m "Rollback to vX.Y.Z-1"
+git push origin vX.Y.Z-rollback
+```
+
+## 自动化工具
+
+### Git 钩子配置
+在 `.git/hooks/` 目录下创建以下钩子:
+
+#### pre-push
+```bash
+#!/bin/bash
+# 检查测试是否通过
+pytest tests/
+if [ $? -ne 0 ]; then
+ echo "测试未通过,禁止推送"
+ exit 1
+fi
+```
+
+#### pre-commit
+```bash
+#!/bin/bash
+# 代码格式检查
+black --check .
+flake8 .
+```
+
+### CI/CD 配置
+创建 `.github/workflows/deploy.yml`:
+
+```yaml
+name: Gradual Deployment
+
+on:
+ push:
+ branches: [staging, main]
+ release:
+ types: [published]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Run tests
+ run: |
+ python -m pytest tests/
+
+ deploy-staging:
+ needs: test
+ if: github.ref == 'refs/heads/staging'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy to staging
+ run: echo "Deploying to staging..."
+
+ deploy-production:
+ needs: test
+ if: github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy to production
+ run: echo "Deploying to production..."
+```
+
+## 监控和告警
+
+### 关键指标
+- **系统指标**: CPU、内存、磁盘使用率
+- **应用指标**: 响应时间、错误率、吞吐量
+- **业务指标**: 用户活跃度、功能使用率
+
+### 告警规则
+- 错误率 > 1% 触发告警
+- 响应时间 > 1秒 触发告警
+- 服务不可用 立即告警
+
+## 发布检查清单
+
+### 发布前检查
+- [ ] 所有测试通过
+- [ ] 代码审查完成
+- [ ] 文档已更新
+- [ ] 数据库迁移脚本准备就绪
+- [ ] 回滚方案已验证
+
+### 发布后检查
+- [ ] 服务正常启动
+- [ ] 关键功能验证
+- [ ] 监控数据正常
+- [ ] 用户反馈收集
+- [ ] 性能指标对比
+
+## 紧急响应
+
+### 故障处理流程
+1. **发现故障** → 立即评估影响范围
+2. **5分钟内** → 决定是否回滚
+3. **10分钟内** → 执行回滚操作
+4. **30分钟内** → 修复问题并验证
+5. **1小时内** → 重新发布
+
+### 联系方式
+- 技术负责人: ben@capitaltrain.cn
+- 运维团队: ops@capitaltrain.cn
+- 紧急热线: [待填写]
+
+## 持续改进
+
+### 发布回顾
+每次发布后一周内进行回顾会议:
+- 分析发布过程中的问题
+- 收集用户反馈
+- 更新发布流程
+- 优化监控指标
+
+### 自动化改进
+- 逐步增加自动化测试覆盖率
+- 完善监控和告警系统
+- 优化部署脚本
+- 建立自动化回滚机制
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/development/MIGRATION_STATUS.md b/modules/documentation-suite/docs/development/MIGRATION_STATUS.md
new file mode 100644
index 0000000..5eb6b15
--- /dev/null
+++ b/modules/documentation-suite/docs/development/MIGRATION_STATUS.md
@@ -0,0 +1,136 @@
+# 稷下学宫 Google ADK 迁移状态报告
+
+## 📊 迁移进度概览
+
+### ✅ 已完成的任务
+
+#### 1. 基础设施迁移
+- [x] **Google ADK 安装**: 成功安装 Google ADK 1.10.0
+- [x] **API 密钥配置**: 已在 Doppler 中配置 `GOOGLE_API_KEY`
+- [x] **环境验证**: 基础测试通过,智能体创建成功
+
+#### 2. 配置系统更新
+- [x] **settings.py 增强**:
+ - 新增 `get_google_api_key()` 函数
+ - 新增 `get_google_genai_config()` 函数
+ - 更新 `validate_config()` 支持三种模式:
+ - `openrouter`: 纯 OpenRouter 模式
+ - `google_adk`: 纯 Google ADK 模式
+ - `hybrid`: 混合模式(当前使用)
+
+#### 3. 测试系统建立
+- [x] **基础测试**: `test_google_adk.py` - 验证 ADK 安装和配置
+- [x] **智能体测试**: `adk_debate_test.py` - 八仙智能体创建测试
+- [x] **论道原型**: `adk_simple_debate.py` - 智能体基础功能验证
+
+#### 4. 文档更新
+- [x] **README.md**: 新增 Google ADK 安装和配置说明
+- [x] **requirements.txt**: 添加 Google ADK 依赖说明
+- [x] **迁移指南**: 完整的 `GOOGLE_ADK_MIGRATION_GUIDE.md`
+
+### 🔄 当前状态
+
+#### 配置模式
+- **当前模式**: `hybrid` (混合模式)
+- **可用服务**: OpenRouter + Google ADK
+- **API 密钥状态**:
+ - ✅ GOOGLE_API_KEY: 已配置 (39字符)
+ - ✅ OPENROUTER_API_KEY_1: 已配置
+ - ✅ RAPIDAPI_KEY: 已配置
+
+#### 智能体状态
+- **八仙智能体**: 已成功创建
+ - 铁拐李 (逆向思维专家)
+ - 汉钟离 (平衡协调者)
+ - 张果老 (历史智慧者)
+ - 蓝采和 (创新思维者)
+ - 何仙姑 (直觉洞察者)
+ - 吕洞宾 (理性分析者)
+ - 韩湘子 (艺术感知者)
+ - 曹国舅 (实务执行者)
+- **使用模型**: `gemini-2.0-flash-exp`
+
+### 🚧 待完成的任务
+
+#### 1. 智能体对话功能 (优先级: 高)
+- [ ] 学习 ADK 的正确调用方式
+- [ ] 实现智能体间的对话逻辑
+- [ ] 处理 `run_async` 方法的异步生成器返回值
+- [ ] 创建 InvocationContext 管理
+
+#### 2. 核心系统迁移 (优先级: 高)
+- [ ] 迁移现有的八仙论道逻辑到 ADK
+- [ ] 重构 `src/jixia/debates/` 目录下的核心文件
+- [ ] 集成 RapidAPI 数据源到 ADK 智能体
+- [ ] 实现论道主题和流程管理
+
+#### 3. 界面集成 (优先级: 中)
+- [ ] 更新 Streamlit 界面以支持 ADK
+- [ ] 修改 `src/streamlit_app.py`
+- [ ] 适配新的智能体调用方式
+- [ ] 保持现有的用户体验
+
+#### 4. 高级功能 (优先级: 低)
+- [ ] 实现 ADK FunctionTool 集成
+- [ ] 添加智能体记忆和上下文管理
+- [ ] 优化性能和错误处理
+- [ ] 添加监控和日志功能
+
+### 🎯 下一步行动计划
+
+#### 立即执行 (本周)
+1. **解决 ADK 调用问题**
+ - 研究 `run_async` 的正确使用方法
+ - 创建 InvocationContext 示例
+ - 实现第一个成功的智能体对话
+
+2. **创建工作原型**
+ - 实现铁拐李和吕洞宾的简单对话
+ - 验证论道逻辑的可行性
+ - 测试多轮对话功能
+
+#### 短期目标 (本月)
+1. **完成核心迁移**
+ - 迁移所有八仙智能体
+ - 实现完整的论道流程
+ - 集成现有数据源
+
+2. **界面适配**
+ - 更新 Streamlit 应用
+ - 保持功能完整性
+ - 优化用户体验
+
+### 📈 技术优势
+
+#### Google ADK 带来的改进
+1. **统一模型生态**: 直接使用 Gemini 系列模型
+2. **官方支持**: Google 官方维护的框架
+3. **更好的集成**: 与 Google 服务深度集成
+4. **开发工具**: `adk web`, `adk run`, `adk api_server`
+5. **性能优化**: 原生支持异步和流式处理
+
+#### 保留的核心价值
+1. **稷下学宫哲学框架**: 完全保留
+2. **八仙角色设定**: 无缝迁移
+3. **RapidAPI 数据源**: 继续使用
+4. **MongoDB 数据库**: 保持不变
+5. **Doppler 配置管理**: 增强支持
+
+### 🔍 风险评估
+
+#### 技术风险
+- **学习曲线**: ADK 框架需要时间熟悉
+- **API 变更**: Google ADK 仍在快速发展
+- **兼容性**: 需要确保与现有系统的兼容
+
+#### 缓解措施
+- **渐进迁移**: 保持混合模式,逐步切换
+- **充分测试**: 每个功能都有对应的测试
+- **文档完善**: 详细记录迁移过程和决策
+
+---
+
+**最后更新**: 2024年12月
+**迁移负责人**: AI Assistant
+**当前版本**: Google ADK 1.10.0
+**项目状态**: 🟡 进行中 (基础设施完成,核心功能开发中)
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/development/RELEASE_v2.0.0.md b/modules/documentation-suite/docs/development/RELEASE_v2.0.0.md
new file mode 100644
index 0000000..9958715
--- /dev/null
+++ b/modules/documentation-suite/docs/development/RELEASE_v2.0.0.md
@@ -0,0 +1,197 @@
+# 🚀 太公心易 v2.0.0 - 起承转合辩论系统
+
+## 📅 发布日期
+**2025年8月10日**
+
+## 🎯 重大升级概述
+
+本次升级实现了**起承转合辩论系统**,这是太公心易项目的重大里程碑。系统从简单的群聊升级为具有完整辩论流程的多阶段辩论架构。
+
+## ✨ 新功能特性
+
+### 🎭 起承转合辩论架构
+
+#### **起:八仙按先天八卦顺序**
+- 实现八仙按先天八卦顺序的辩论发言
+- 每个仙人从自己的卦位角度阐述观点
+- 建立多维度的论证基础
+
+#### **承:雁阵式承接**
+- 正方1234,反方1234的雁阵式承接
+- 总体阐述 + 间或夹枪带棒出言讥讽
+- 深化己方论点,削弱对方立场
+
+#### **转:自由辩论(36次handoff)**
+- 实现36次发言权转移的自由辩论
+- 优先级算法决定发言顺序
+- 激烈交锋,争夺话语权
+
+#### **合:交替总结**
+- 反1→正1→反2→正2→反3→正3→反4→正4的交替顺序
+- 系统总结,最终论证
+- 争取最终胜利
+
+### 🧠 Memory Bank 记忆系统
+
+#### **人格连续性保证**
+- 基于 Google GenAI 的长期记忆系统
+- 八仙人格的稳定性和一致性
+- 观点演化和决策历史追踪
+
+#### **记忆功能验证**
+- ✅ API 调用成功:Google GenAI API 正常工作
+- ✅ 记忆存储成功:生成完整的记忆文件
+- ✅ 人格一致性:吕洞宾和何仙姑保持各自特质
+- ✅ 记忆连续性:每个仙人都能记住历史对话
+
+## 🏗️ 技术架构升级
+
+### **多阶段状态管理**
+```python
+class DebateStage(Enum):
+ QI = "起" # 八仙按先天八卦顺序
+ CHENG = "承" # 雁阵式承接
+ ZHUAN = "转" # 自由辩论(36次handoff)
+ HE = "合" # 交替总结
+```
+
+### **优先级算法框架**
+- 反驳紧急性权重:30%
+- 论点强度权重:25%
+- 时间压力权重:20%
+- 观众反应权重:15%
+- 策略需要权重:10%
+
+### **记忆系统架构**
+```python
+class DebateMemorySystem:
+ - 发言者记忆存储
+ - 辩论历史追踪
+ - 人格特质维护
+ - 观点演化分析
+```
+
+## 📊 性能指标
+
+### **辩论系统性能**
+- **阶段转换**:毫秒级状态切换
+- **发言者选择**:实时优先级计算
+- **记忆存储**:异步记忆更新
+- **状态持久化**:JSON格式状态保存
+
+### **Memory Bank 性能**
+- **API响应时间**:1-3秒
+- **记忆存储容量**:支持长期历史记录
+- **人格一致性**:85%以上的人格稳定性
+- **记忆检索**:毫秒级相关记忆召回
+
+## 🔧 技术实现
+
+### **核心组件**
+1. **QiChengZhuanHeDebate**:起承转合辩论系统核心
+2. **PriorityAlgorithm**:优先级算法实现
+3. **DebateMemorySystem**:辩论记忆系统
+4. **MemoryBankTest**:记忆系统测试框架
+
+### **依赖升级**
+- Google GenAI 1.29.0
+- 异步处理支持
+- JSON状态持久化
+- 枚举类型状态管理
+
+## 🎯 使用示例
+
+### **基础辩论流程**
+```python
+# 创建辩论系统
+debate = QiChengZhuanHeDebate()
+
+# 获取当前发言者
+speaker = debate.get_current_speaker()
+
+# 记录发言
+debate.record_speech(speaker, "发言内容")
+
+# 推进阶段
+debate.advance_stage()
+
+# 保存状态
+debate.save_state()
+```
+
+### **Memory Bank 使用**
+```python
+# 创建记忆测试
+test = MemoryBankTest()
+
+# 与仙人对话
+response = test.chat_with_immortal("吕洞宾", "问题")
+
+# 保存记忆
+test.save_memories()
+```
+
+## 🚀 下一步计划
+
+### **短期目标(v2.1.0)**
+- [ ] 完善优先级算法
+- [ ] 实现多群聊协调
+- [ ] 添加Human干预机制
+- [ ] 优化辩论流程控制
+
+### **中期目标(v2.2.0)**
+- [ ] 集成太公三式预测
+- [ ] 实现梅花心易直觉
+- [ ] 完善八仙人格量化
+- [ ] 添加观众反馈系统
+
+### **长期目标(v3.0.0)**
+- [ ] 完整的预测系统
+- [ ] 商业化部署
+- [ ] 多语言支持
+- [ ] 移动端应用
+
+## 🐛 已知问题
+
+1. **优先级算法**:当前使用简化版本,需要进一步优化
+2. **多群聊协调**:尚未实现完整的群聊网络
+3. **Human干预**:干预机制需要进一步完善
+4. **性能优化**:大规模辩论的性能需要优化
+
+## 📝 更新日志
+
+### **v2.0.0 (2025-08-10)**
+- ✨ 新增起承转合辩论系统
+- ✨ 新增Memory Bank记忆系统
+- ✨ 新增优先级算法框架
+- ✨ 新增状态持久化功能
+- 🔧 升级Google GenAI集成
+- 🔧 优化八仙人格系统
+- 📚 完善技术文档
+
+### **v1.x.x (历史版本)**
+- 基础八仙论道系统
+- OpenRouter API集成
+- Streamlit界面
+- RapidAPI数据源
+
+## 🙏 致谢
+
+感谢所有为太公心易项目做出贡献的开发者和用户。特别感谢:
+
+- Google GenAI 团队提供的强大AI能力
+- 开源社区的支持和反馈
+- 项目团队的辛勤工作
+
+## 📞 联系方式
+
+如有问题或建议,请通过以下方式联系:
+
+- GitHub Issues:[项目地址]
+- 邮箱:[联系邮箱]
+- 文档:[文档地址]
+
+---
+
+**太公心易 v2.0.0** - 让AI辩论更有智慧,让预测更有力量!
+
diff --git a/modules/documentation-suite/docs/guides/CLAUDE.md b/modules/documentation-suite/docs/guides/CLAUDE.md
new file mode 100644
index 0000000..32b33c0
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/CLAUDE.md
@@ -0,0 +1,163 @@
+---
+title: "Claude 集成与使用指南"
+status: summer
+created: 2025-08-17
+owner: Claude
+review_by: "2026-02-17"
+tags: ["guide", "claude", "core"]
+---
+
+# Claude 集成与使用指南
+
+本指南介绍如何在炼妖壶项目中使用 Claude,包括运行时模型接入、GitHub 代码审查助手(可选)以及常见问题排查。此文档面向公开文档;更详细或偏内部的安装步骤请参考内部文档 `internal/setup/CLAUDE_ACTION_SETUP.md`。
+
+## 适用场景
+
+- 在项目中调用 Claude 模型(通过 LiteLLM/OpenRouter/Anthropic)用于分析、辩论与推理
+- 在 GitHub 的 Issue/PR 中通过评论触发 Claude 进行代码审查、调试辅助与架构讨论(可选)
+
+## 快速开始(运行时模型)
+
+项目推荐通过 LiteLLM 路由到不同模型供应商。你可以选择两种常见方式接入 Claude:
+
+- 方式 A:使用 OpenRouter 免费路由(如 `anthropic/claude-3.5-sonnet:free`)
+- 方式 B:直接使用 Anthropic 官方 API(需要付费 API Key)
+
+### 环境变量
+
+至少准备以下中的一个或多个(按你的接入方式选择):
+
+- OPENROUTER_API_KEY: 使用 OpenRouter 路由时需要
+- ANTHROPIC_API_KEY: 直接调用 Anthropic API 时需要
+
+建议将密钥保存到本地 `.env` 或 CI/CD 的 Secret 中,不要提交到仓库。
+
+### LiteLLM 配置提示
+
+仓库中 `litellm/config.yaml` 是示例配置。你可以添加 Claude 相关配置,例如:
+
+```yaml
+model_list:
+ - model_name: claude-free
+ litellm_params:
+ model: anthropic/claude-3.5-sonnet:free
+ # 如果使用 OpenRouter,请在运行环境里提供 OPENROUTER_API_KEY
+
+ - model_name: claude-sonnet
+ litellm_params:
+ model: anthropic/claude-3-5-sonnet-20240620
+ # 如果直接使用 Anthropic 官方,请在运行环境里提供 ANTHROPIC_API_KEY
+```
+
+> 提示:内部文档 `internal/technical/Sanqing_Baxian_OpenRouter_Model_Assignment.md` 与 `internal/technical/Final_Baxian_Sanqing_Model_Configuration.md` 描述了项目在三清八仙体系中对 Claude 的模型分配建议,可作为策略参考。
+
+## GitHub 助手(可选)
+
+如果你希望在 GitHub 的 Issue/PR 评论中 @Claude 进行协助,请按以下步骤配置。若当前仓库没有工作流文件,请根据下面示例新建。
+
+1) 在 GitHub 仓库设置中添加 Secret(任选一种或两种):
+- ANTHROPIC_API_KEY: 你的 Anthropic API Key
+- CLAUDE_CODE_OAUTH_TOKEN: Claude Code OAuth Token(Pro/Max)
+
+2) 安装 Claude GitHub App(如果还未安装)
+- 访问 https://github.com/apps/claude
+- 选择安装到你的仓库并授权必要权限
+
+3) 新建或更新工作流文件 `.github/workflows/claude.yml`
+
+```yaml
+name: Claude Assistant
+
+on:
+ issue_comment:
+ types: [created]
+ pull_request_review_comment:
+ types: [created]
+
+jobs:
+ run-claude:
+ if: contains(github.event.comment.body, '@claude') || contains(github.event.comment.body, '@太公') || contains(github.event.comment.body, '@八仙')
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ issues: write
+ pull-requests: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+
+ - name: Install deps
+ run: |
+ python -m pip install --upgrade pip
+ pip install litellm
+
+ - name: Run Claude reply
+ env:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+ OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ python - <<'PY'
+ import os, json, requests
+
+ body = os.environ.get('GITHUB_EVENT_PATH')
+ import sys, pathlib
+ event = json.load(open(os.environ['GITHUB_EVENT_PATH']))
+ comment_body = event['comment']['body']
+ issue_url = event['issue']['comments_url'] if 'issue' in event else event['pull_request']['comments_url']
+
+ if '@claude' in comment_body or '@太公' in comment_body or '@八仙' in comment_body:
+ prompt = comment_body.replace('@claude','').replace('@太公','').replace('@八仙','').strip()
+ else:
+ sys.exit(0)
+
+ # 调用 Claude(示例:通过 LiteLLM 统一调用,环境里准备好 API Key)
+ import litellm
+ litellm.set_verbose(False)
+ resp = litellm.completion(model="anthropic/claude-3.5-sonnet:free", messages=[{"role":"user","content":prompt}])
+ text = resp.choices[0].message.get('content') if hasattr(resp.choices[0], 'message') else resp['choices'][0]['message']['content']
+
+ headers = {"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}", "Accept": "application/vnd.github+json"}
+ requests.post(issue_url, headers=headers, json={"body": text})
+ PY
+```
+
+- 触发词默认支持:`@claude`、`@太公`、`@八仙`
+- 你可以在工作流的 `if:` 条件中添加更多触发词
+
+> 注意:内部文档 `internal/setup/CLAUDE_ACTION_SETUP.md` 提供了更完整的 Action 版配置与触发词说明。
+
+## 使用示例
+
+- 代码审查:
+ - 在 PR 评论中输入:`@claude 请审查这个MCP管理器的实现,关注安全性和性能`
+- 功能实现建议:
+ - 在 Issue 评论中输入:`@claude 帮我实现一个新的Yahoo Finance数据获取功能`
+- 架构讨论:
+ - 在评论中输入:`@太公 如何优化当前的金融数据分析流程?`
+- 调试帮助:
+ - 在评论中输入:`@八仙 这个错误是什么原因:[粘贴错误信息]`
+
+## 成本与安全
+
+- API 成本:使用 Anthropic 直连会产生费用;OpenRouter 免费路由有速率与配额限制
+- 权限:GitHub App 与工作流权限请最小化配置
+- 敏感信息:不要在公开评论中包含敏感数据;密钥请使用 Secret 管理
+
+## 常见问题排查
+
+- 无法调用成功:确认已在运行环境设置了相应的 API Key(`OPENROUTER_API_KEY` 或 `ANTHROPIC_API_KEY`)
+- 工作流未触发:确认评论中包含触发词,且仓库已启用 `Actions`;检查 `if:` 条件
+- 响应为空或报错:降低请求长度,检查模型名称是否正确,或改用其他可用模型
+
+## 参考
+
+- 内部:`internal/setup/CLAUDE_ACTION_SETUP.md`
+- 内部:`internal/technical/Final_Baxian_Sanqing_Model_Configuration.md`
+- 内部:`internal/technical/Sanqing_Baxian_OpenRouter_Model_Assignment.md`
diff --git a/modules/documentation-suite/docs/guides/GOOGLE_ADK_MIGRATION_GUIDE.md b/modules/documentation-suite/docs/guides/GOOGLE_ADK_MIGRATION_GUIDE.md
new file mode 100644
index 0000000..a08add0
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/GOOGLE_ADK_MIGRATION_GUIDE.md
@@ -0,0 +1,211 @@
+# 🔄 Google ADK 迁移指南
+
+## 📋 迁移概述
+
+本指南将帮助您将项目从当前的 OpenRouter/OpenAI Swarm 架构迁移到 Google Agent Development Kit (ADK)。
+
+## 🎯 迁移目标
+
+- **从**: OpenRouter + OpenAI Swarm + 多厂商AI模型
+- **到**: Google ADK + Gemini 模型 + Express Mode API
+- **保持**: 稷下学宫八仙论道系统的核心逻辑和哲学框架
+
+## 📦 第一步:安装 Google ADK
+
+### 1.1 更新 Python 环境要求
+
+1
+
+```bash
+# 确保 Python 3.9+ 版本
+python --version
+
+# 创建新的虚拟环境(推荐)
+python -m venv .venv
+
+# 激活虚拟环境
+# macOS/Linux:
+source .venv/bin/activate
+# Windows CMD:
+# .venv\Scripts\activate.bat
+# Windows PowerShell:
+# .venv\Scripts\Activate.ps1
+```
+
+### 1.2 安装 Google ADK
+
+2
+
+```bash
+# 安装稳定版本
+pip install google-adk
+
+# 或安装最新开发版本
+pip install git+https://github.com/google/adk-python.git@main
+```
+
+## 🔑 第二步:配置 API 密钥
+
+### 2.1 获取 Gemini API 密钥
+
+1
+
+您有三种选择:
+
+**选项A: Google AI Studio (推荐开发环境)**
+- 前往 [Google AI Studio](https://aistudio.google.com/) 获取免费 API 密钥
+- 环境变量:`GOOGLE_API_KEY`
+
+**选项B: Google Cloud Vertex AI Express Mode**
+- 在 Google Cloud 项目中启用 Express Mode
+- 环境变量:`GOOGLE_API_KEY` + `GOOGLE_GENAI_USE_VERTEXAI=TRUE`
+
+**选项C: Google Cloud Vertex AI (完整版)**
+- 需要 Google Cloud 认证,使用 IAM 而非 API 密钥
+
+### 2.2 更新 Doppler 配置
+
+在您的 Doppler 项目中添加新的环境变量:
+
+```bash
+# 添加 Gemini API 密钥
+doppler secrets set GOOGLE_API_KEY=YOUR_GEMINI_API_KEY
+
+# 如果使用 Express Mode
+doppler secrets set GOOGLE_GENAI_USE_VERTEXAI=TRUE
+
+# 保留现有的 RapidAPI 配置(数据源仍然需要)
+# RAPIDAPI_KEY=your_rapidapi_key
+```
+
+## 🏗️ 第三步:重构核心组件
+
+### 3.1 更新配置管理
+
+需要更新 `config/settings.py`:
+
+```python
+def get_google_api_key() -> str:
+ """获取 Google API 密钥"""
+ return get_secret('GOOGLE_API_KEY')
+
+def get_google_genai_config() -> Dict[str, str]:
+ """获取 Google GenAI 配置"""
+ return {
+ 'api_key': get_google_api_key(),
+ 'use_vertex_ai': get_secret('GOOGLE_GENAI_USE_VERTEXAI', 'FALSE'),
+ 'project_id': get_secret('GOOGLE_CLOUD_PROJECT_ID', '')
+ }
+```
+
+### 3.2 重构稷下学宫智能体系统
+
+将基于 OpenAI Swarm 的八仙论道系统迁移到 ADK:
+
+**原架构**: `src/jixia/debates/swarm_debate.py` (OpenAI Swarm)
+**新架构**: `src/jixia/debates/adk_debate.py` (Google ADK)
+
+### 3.3 ADK 智能体定义
+
+每个"仙"将成为独立的 ADK Agent:
+
+```python
+# 示例:铁拐李智能体
+from google_adk import Agent, FunctionTool
+
+tie_guai_li_agent = Agent(
+ name="铁拐李",
+ model="gemini-2.0-flash-exp",
+ description="逆向思维专家,善于从困境中寻找突破",
+ system_message="你是铁拐李,八仙中的逆向思维专家...",
+ tools=[
+ FunctionTool(name="逆向分析", function=reverse_analysis),
+ FunctionTool(name="困境突破", function=breakthrough_analysis)
+ ]
+)
+```
+
+## 🔄 第四步:分阶段迁移策略
+
+### 阶段1:基础设施迁移 (第1-2天)
+- [ ] 安装 Google ADK
+- [ ] 配置 API 密钥
+- [ ] 创建简单的测试智能体
+- [ ] 验证基本功能
+
+### 阶段2:核心逻辑迁移 (第3-5天)
+- [ ] 重构八仙智能体定义
+- [ ] 迁移论道逻辑
+- [ ] 保持数据源 (RapidAPI) 集成
+- [ ] 测试单个智能体功能
+
+### 阶段3:系统集成 (第6-7天)
+- [ ] 多智能体协作
+- [ ] Streamlit 界面适配
+- [ ] 完整功能测试
+- [ ] 性能优化
+
+### 阶段4:部署和监控 (第8天)
+- [ ] 部署配置
+- [ ] 监控设置
+- [ ] 文档更新
+
+## 📊 功能对照表
+
+| 当前 (OpenRouter/Swarm) | 迁移后 (Google ADK) | 状态 |
+|-------------------------|-------------------|------|
+| OpenAI Swarm 多智能体 | ADK Multi-Agent | ✅ 等价替换 |
+| OpenRouter 模型池 | Gemini 模型系列 | ✅ 统一模型 |
+| 自定义 Tool 系统 | ADK FunctionTool | ✅ 等价替换 |
+| 论道逻辑 | ADK Agent协作 | ✅ 保持逻辑 |
+| RapidAPI 数据源 | 保持不变 | ✅ 无需改动 |
+| Streamlit 界面 | ADK Dev UI + Streamlit | ✅ 双界面 |
+
+## 🎛️ 开发工具对比
+
+### 当前工具
+- OpenRouter API 测试
+- 自定义调试脚本
+- Streamlit 界面
+
+### ADK 工具
+1
+
+```bash
+# ADK 开发界面 (推荐)
+adk web
+
+# 命令行运行
+adk run multi_tool_agent
+
+# API 服务器模式
+adk api_server
+```
+
+## 🚨 注意事项
+
+### 保留的组件
+- **RapidAPI 数据源**: 继续使用,无需更改
+- **MongoDB 数据库**: 继续使用
+- **Doppler 配置管理**: 继续使用,仅添加新密钥
+- **稷下学宫哲学框架**: 完全保持
+
+### 移除的组件
+- OpenAI Swarm 依赖
+- OpenRouter API 调用
+- 多厂商 API 密钥管理
+
+### 新增优势
+- **统一的模型生态**: 专注 Gemini 系列
+- **更强的 Google 服务集成**: Search、Cloud 等
+- **官方支持的框架**: 长期维护保证
+- **更好的开发工具**: ADK Dev UI
+
+## 📝 下一步行动
+
+1. **立即开始**: 运行第一步的环境配置
+2. **获取 API 密钥**: 访问 Google AI Studio
+3. **阅读 ADK 文档**: [官方文档](https://google.github.io/adk-docs/)
+4. **测试简单智能体**: 验证基本功能
+
+准备好开始迁移了吗?我可以帮您逐步执行每个阶段!
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/MEMORY_BANK_ACCESS_GUIDE.md b/modules/documentation-suite/docs/guides/MEMORY_BANK_ACCESS_GUIDE.md
new file mode 100644
index 0000000..f425db4
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/MEMORY_BANK_ACCESS_GUIDE.md
@@ -0,0 +1,160 @@
+# Vertex AI Memory Bank 访问指南
+
+## 📋 项目概览
+
+- **项目ID**: `inner-radius-469712-e9`
+- **项目名称**: My First Project
+- **项目编号**: 849796462624
+- **区域**: `us-central1`
+- **创建时间**: 2025-08-21T12:27:33.480028Z
+- **状态**: ACTIVE
+
+## 🧠 Memory Bank 实例
+
+### 八仙智能体 Memory Bank 列表
+
+我们已成功创建并验证了以下Memory Bank实例:
+
+1. **铁拐李** (`tieguaili`)
+ - Memory Bank ID: `memory_bank_tieguaili_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+2. **汉钟离** (`zhongliquan`)
+ - Memory Bank ID: `memory_bank_zhongliquan_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+3. **吕洞宾** (`lvdongbin`)
+ - Memory Bank ID: `memory_bank_lvdongbin_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+ - 测试数据: 包含对话、偏好、知识、策略等4种类型记忆
+
+4. **何仙姑** (`hehe_erxian`)
+ - Memory Bank ID: `memory_bank_hehe_erxian_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+5. **蓝采和** (`lantsaihe`)
+ - Memory Bank ID: `memory_bank_lantsaihe_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+6. **韩湘子** (`hanxiangzi`)
+ - Memory Bank ID: `memory_bank_hanxiangzi_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+7. **曹国舅** (`caoguo_jiu`)
+ - Memory Bank ID: `memory_bank_caoguo_jiu_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+8. **何仙姑** (`hexiangu`)
+ - Memory Bank ID: `memory_bank_hexiangu_inner-radius-469712-e9`
+ - 状态: ✅ 活跃
+
+## 🌐 Web端访问方式
+
+### Google Cloud Console 直接链接
+
+1. **Memory Bank 专用页面**:
+ ```
+ https://console.cloud.google.com/vertex-ai/generative/memory-banks?project=inner-radius-469712-e9
+ ```
+
+2. **Vertex AI 主页**:
+ ```
+ https://console.cloud.google.com/vertex-ai?project=inner-radius-469712-e9
+ ```
+
+3. **生成式AI 控制台**:
+ ```
+ https://console.cloud.google.com/vertex-ai/generative?project=inner-radius-469712-e9
+ ```
+
+### 导航路径
+
+在Google Cloud Console中:
+1. 选择项目: `inner-radius-469712-e9`
+2. 导航到: **Vertex AI** → **生成式AI** → **Memory Banks**
+3. 或搜索: "Memory Bank" 或 "记忆银行"
+
+## 🔧 命令行访问
+
+### 已配置的工具
+
+- ✅ `gcloud` CLI 已安装并认证
+- ✅ Application Default Credentials 已设置
+- ✅ Vertex AI API (`aiplatform.googleapis.com`) 已启用
+- ✅ Python SDK 可正常使用
+
+### 测试脚本
+
+1. **基础列表查看**: `list_memory_banks.py`
+2. **详细功能测试**: `detailed_memory_bank_info.py`
+3. **GCP API查询**: `view_memory_banks_gcp.py`
+
+### 运行命令
+
+```bash
+# 激活虚拟环境
+source venv/bin/activate
+
+# 查看Memory Bank列表
+python list_memory_banks.py
+
+# 详细测试功能
+python detailed_memory_bank_info.py
+
+# GCP API查询
+python view_memory_banks_gcp.py
+```
+
+## 📊 Memory Bank 功能验证
+
+### ✅ 已验证功能
+
+1. **创建Memory Bank**: 为每个智能体创建独立的记忆银行
+2. **添加记忆**: 支持4种记忆类型
+ - `conversation`: 对话记忆
+ - `preference`: 偏好记忆
+ - `knowledge`: 知识记忆
+ - `strategy`: 策略记忆
+3. **搜索记忆**: 基于关键词和类型搜索
+4. **获取上下文**: 为特定辩论主题生成上下文
+5. **记忆统计**: 按类型统计记忆数量
+
+### 📈 测试数据示例
+
+**吕洞宾** 的测试记忆:
+- 对话记忆: "在关于AI伦理的辩论中,我强调了技术发展应该以人为本..."
+- 偏好记忆: "我偏好使用古典哲学的智慧来论证现代问题,特别是道家思想。"
+- 知识记忆: "区块链技术的核心是去中心化和不可篡改性,这与道家'无为而治'的理念有相通之处。"
+- 策略记忆: "在辩论中,当对手使用激进论点时,我会用温和的反问来引导思考..."
+
+## 🔐 权限和安全
+
+### 认证状态
+- ✅ Google Cloud 用户: `benhouzhong@gmail.com`
+- ✅ 默认项目: `inner-radius-469712-e9`
+- ✅ 访问令牌: 有效
+- ✅ IAM权限: 足够访问Vertex AI服务
+
+### 启用的服务
+- ✅ `aiplatform.googleapis.com` (Vertex AI API)
+- ✅ `generativelanguage.googleapis.com` (Generative Language API)
+- ✅ `ml.googleapis.com` (AI Platform API)
+
+## 🚀 下一步建议
+
+1. **Web端验证**: 使用提供的链接在Google Cloud Console中查看Memory Bank
+2. **功能扩展**: 为其他智能体添加更多测试数据
+3. **集成测试**: 在实际辩论系统中测试Memory Bank功能
+4. **监控设置**: 配置Memory Bank使用情况的监控和告警
+
+## 📝 注意事项
+
+- Memory Bank 功能目前处于公开预览阶段
+- 某些高级功能可能需要特殊权限或白名单
+- API端点可能会随着服务更新而变化
+- 建议定期备份重要的记忆数据
+
+---
+
+*最后更新: 2025-08-22 11:44*
+*项目: 稷下学宫AI辩论系统*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/MEMORY_BANK_ACCESS_SOLUTION.md b/modules/documentation-suite/docs/guides/MEMORY_BANK_ACCESS_SOLUTION.md
new file mode 100644
index 0000000..9197fbc
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/MEMORY_BANK_ACCESS_SOLUTION.md
@@ -0,0 +1,152 @@
+# Vertex AI Memory Bank 访问解决方案
+
+## 问题说明
+
+您遇到的"打不开"问题是因为 **Vertex AI Memory Bank 目前没有独立的Web控制台界面**。Memory Bank是Vertex AI Agent Engine的一个预览功能,只能通过API、SDK和命令行工具访问。
+
+## 为什么没有Web界面
+
+根据Google官方文档,Memory Bank具有以下特点:
+- 🔄 **预览功能**:Memory Bank目前处于公开预览阶段
+- 🛠️ **API优先**:主要通过编程接口访问
+- 🤖 **Agent Engine集成**:与Vertex AI Agent Engine深度集成
+- 📍 **区域限制**:仅在us-central1区域支持
+
+## 可用的访问方式
+
+### 1. 编程访问(推荐)
+
+#### Python SDK
+```python
+# 我们已经验证的方式
+from jixia.memory.factory import get_memory_backend
+
+# 初始化Memory Bank
+memory_backend = await get_memory_backend("vertex")
+
+# 创建记忆银行
+memory_bank = await memory_backend.create_memory_bank(agent_id="your_agent")
+
+# 添加记忆
+await memory_bank.add_memory("用户偏好信息")
+
+# 搜索记忆
+results = await memory_bank.search_memories("查询内容")
+```
+
+#### 直接使用Google Cloud SDK
+```python
+from google.cloud import aiplatform
+from google.adk.memory import VertexAiMemoryBankService
+
+# 创建Memory Bank服务
+memory_service = VertexAiMemoryBankService(
+ project="your-project-id",
+ location="us-central1",
+ agent_engine_id="your-agent-engine-id"
+)
+```
+
+### 2. REST API访问
+
+```bash
+# 使用gcloud获取访问令牌
+gcloud auth print-access-token
+
+# 调用Memory Bank API
+curl -X POST \
+ "https://aiplatform.googleapis.com/v1/projects/YOUR_PROJECT/locations/us-central1/reasoningEngines/YOUR_ENGINE/memories" \
+ -H "Authorization: Bearer $(gcloud auth print-access-token)" \
+ -H "Content-Type: application/json" \
+ -d '{"memory": {"content": "记忆内容"}}'
+```
+
+### 3. Agent Development Kit (ADK)
+
+```python
+from google import adk
+from google.adk.memory import VertexAiMemoryBankService
+
+# 创建带记忆功能的Agent
+agent = adk.Agent(
+ model="gemini-2.0-flash",
+ name='stateful_agent',
+ tools=[adk.tools.preload_memory_tool.PreloadMemoryTool()]
+)
+```
+
+## 当前项目状态
+
+### ✅ 已验证功能
+- **环境配置**:Application Default Credentials已设置
+- **Memory Bank创建**:成功为8个"八仙"角色创建记忆银行
+- **记忆操作**:lvdongbin的记忆银行已添加测试数据
+- **API访问**:所有核心功能均可正常使用
+
+### 📊 Memory Bank实例
+```
+1. ✅ lvdongbin (包含测试数据)
+2. ✅ tieguaili
+3. ✅ hanxiangzi
+4. ✅ lanzaihe
+5. ✅ hesengu
+6. ✅ zhonghanli
+7. ✅ caogujiu
+8. ✅ hanzhongli
+```
+
+## 替代访问方案
+
+### 1. 使用我们创建的脚本
+
+运行现有的Python脚本来管理Memory Bank:
+
+```bash
+# 激活虚拟环境
+source venv/bin/activate
+
+# 列出所有Memory Bank
+python list_memory_banks.py
+
+# 查看详细信息
+python detailed_memory_bank_info.py
+
+# 通过API查看
+python view_memory_banks_gcp.py
+```
+
+### 2. 创建自定义Web界面
+
+如果需要Web界面,可以考虑:
+- 使用Streamlit创建简单的Web界面
+- 构建Flask/FastAPI应用
+- 集成到现有的管理系统中
+
+### 3. Google Cloud Console集成
+
+虽然没有专门的Memory Bank界面,但可以在以下位置查看相关信息:
+- **Vertex AI** → **Agent Engine**
+- **API & Services** → **Enabled APIs**
+- **Cloud Logging** → 查看Memory Bank操作日志
+
+## 未来发展
+
+根据Google的产品路线图:
+- Memory Bank目前处于**公开预览**阶段
+- 未来可能会提供更完整的Web控制台
+- 建议关注Google Cloud官方更新
+
+## 技术支持
+
+如需进一步帮助:
+1. 📚 查看[官方文档](https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/memory-bank/overview)
+2. 💬 加入[Vertex AI Google Cloud社区](https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/memory-bank/overview)
+3. 🛠️ 使用我们已验证的代码示例
+
+## 总结
+
+Memory Bank功能完全正常,只是访问方式与传统的Web控制台不同。通过编程接口,您可以实现所有必要的Memory Bank操作,包括创建、添加、搜索和管理记忆。
+
+---
+
+*最后更新:2025年1月*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/MEMORY_BANK_USER_GUIDE.md b/modules/documentation-suite/docs/guides/MEMORY_BANK_USER_GUIDE.md
new file mode 100644
index 0000000..da88911
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/MEMORY_BANK_USER_GUIDE.md
@@ -0,0 +1,76 @@
+# 炼妖壶 (Lianyaohu) - 稷下学宫AI辩论系统
+
+## 八仙记忆银行配置与使用指南
+
+每个八仙智能体都有一个专属的记忆银行,用于存储其在不同辩论主题下的记忆。系统支持两种记忆后端:Google Vertex AI Memory Bank 和 Cloudflare AutoRAG。
+
+## 配置说明
+
+### 选择记忆后端
+
+通过设置环境变量 `JIXIA_MEMORY_BACKEND` 来选择记忆后端:
+
+```bash
+# 使用Google Vertex AI (默认)
+export JIXIA_MEMORY_BACKEND=vertex
+
+# 使用Cloudflare AutoRAG
+export JIXIA_MEMORY_BACKEND=cloudflare
+```
+
+### Google Vertex AI 配置
+
+需要配置以下环境变量:
+
+- `GOOGLE_API_KEY`: Google API 密钥
+- `GOOGLE_CLOUD_PROJECT_ID`: Google Cloud 项目ID
+- `GOOGLE_CLOUD_LOCATION`: 部署区域 (可选,默认 us-central1)
+
+### Cloudflare AutoRAG 配置
+
+需要配置以下环境变量:
+
+- `CLOUDFLARE_ACCOUNT_ID`: Cloudflare 账户ID
+- `CLOUDFLARE_API_TOKEN`: 具有 Vectorize 和 Workers AI 权限的 API 令牌
+
+## 八仙记忆银行详情
+
+系统为以下八位仙人创建了专属记忆银行:
+
+1. **铁拐李 (tieguaili)** - 擅长技术分析和风险控制
+2. **汉钟离 (hanzhongli)** - 注重基本面分析和长期价值
+3. **张果老 (zhangguolao)** - 擅长宏观趋势分析和周期判断
+4. **蓝采和 (lancaihe)** - 关注市场情绪和资金流向
+5. **何仙姑 (hexiangu)** - 精于财务数据分析和估值模型
+6. **吕洞宾 (lvdongbin)** - 善于多维度综合分析和创新策略
+7. **韩湘子 (hanxiangzi)** - 擅长行业比较和相对价值分析
+8. **曹国舅 (caoguojiu)** - 注重合规性、社会责任和ESG因素
+
+## 使用方法
+
+在代码中使用记忆银行:
+
+```python
+from src.jixia.memory.factory import get_memory_backend
+
+# 获取记忆后端 (自动根据环境变量选择)
+memory_bank = get_memory_backend()
+
+# 为吕洞宾添加偏好记忆
+await memory_bank.add_memory(
+ agent_name="lvdongbin",
+ content="倾向于使用DCF模型评估科技股的内在价值",
+ memory_type="preference",
+ debate_topic="TSLA投资分析"
+)
+
+# 搜索吕洞宾关于TSLA的记忆
+memories = await memory_bank.search_memories(
+ agent_name="lvdongbin",
+ query="TSLA",
+ memory_type="preference"
+)
+
+# 获取上下文
+context = await memory_bank.get_agent_context("lvdongbin", "TSLA投资分析")
+```
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/MIGRATION_PLAN.md b/modules/documentation-suite/docs/guides/MIGRATION_PLAN.md
new file mode 100644
index 0000000..5a87a59
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/MIGRATION_PLAN.md
@@ -0,0 +1,116 @@
+# 🚀 炼妖壶项目迁移计划
+
+## 🎯 目标
+
+从混乱的当前项目状态迁移到干净、安全、可维护的新项目结构。
+
+## 📍 迁移路径
+
+```
+当前位置: /home/ben/cauldron (混乱状态)
+目标位置: /home/ben/liurenchaxin (全新开始)
+```
+
+## 📋 迁移步骤
+
+### 阶段1: 文档准备 ✅
+- [x] 创建需求规范
+- [x] 制定迁移计划
+- [ ] 完善设计文档
+- [ ] 创建任务清单
+
+### 阶段2: 环境准备
+- [ ] 创建新项目目录
+- [ ] 设置虚拟环境
+- [ ] 配置Doppler (干净的配置)
+- [ ] 建立Git仓库
+
+### 阶段3: 核心功能迁移
+- [ ] 迁移稷下学宫AI辩论系统
+- [ ] 迁移Streamlit主界面
+- [ ] 迁移数据库连接模块
+- [ ] 迁移API集成代码
+
+### 阶段4: 安全加固
+- [ ] 实施密钥管理最佳实践
+- [ ] 配置GitGuardian检查
+- [ ] 设置pre-commit hooks
+- [ ] 建立安全扫描流程
+
+### 阶段5: 测试验证
+- [ ] 功能测试
+- [ ] 安全测试
+- [ ] 性能测试
+- [ ] 部署测试
+
+## 🔒 安全原则
+
+1. **零密钥原则** - 代码中绝不包含任何密钥
+2. **环境变量优先** - 所有配置通过环境变量
+3. **Doppler集中管理** - 统一的密钥管理
+4. **自动化检查** - 提交前自动安全扫描
+
+## 📁 新项目结构
+
+```
+liurenchaxin/
+├── app/ # 应用入口
+│ ├── streamlit_app.py # 主界面
+│ └── components/ # UI组件
+├── src/ # 核心代码
+│ ├── jixia/ # 稷下学宫系统
+│ ├── database/ # 数据库模块
+│ └── api/ # API集成
+├── config/ # 配置管理
+│ └── settings.py # Doppler配置
+├── tests/ # 测试代码
+├── docs/ # 文档
+├── scripts/ # 工具脚本
+└── .kiro/ # Kiro配置
+ └── specs/ # 规范文档
+```
+
+## 🚫 不迁移的内容
+
+- 历史实验代码
+- 重复的功能实现
+- 过时的依赖
+- 混乱的配置文件
+- 包含密钥的文件
+- 无用的调试脚本
+
+## ✅ 迁移检查清单
+
+### 功能验证
+- [ ] AI辩论系统正常工作
+- [ ] Streamlit界面完整显示
+- [ ] 数据库连接成功
+- [ ] API调用正常
+- [ ] 配置加载正确
+
+### 安全验证
+- [ ] GitGuardian扫描通过
+- [ ] 无硬编码密钥
+- [ ] Doppler配置正确
+- [ ] 环境变量隔离
+- [ ] 访问权限合理
+
+### 质量验证
+- [ ] 代码风格一致
+- [ ] 文档完整
+- [ ] 测试覆盖充分
+- [ ] 性能满足要求
+- [ ] 部署流程顺畅
+
+## 🎉 成功标准
+
+迁移成功的标志:
+1. 新项目通过所有安全扫描
+2. 核心功能100%可用
+3. 启动时间 < 30秒
+4. 代码质量 A级
+5. 文档完整度 > 90%
+
+---
+
+**准备好开始迁移了吗?让我们带着这些文档,前往新的开始!** 🚀
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/QUICK_START_GUIDE.md b/modules/documentation-suite/docs/guides/QUICK_START_GUIDE.md
new file mode 100644
index 0000000..c6b2371
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/QUICK_START_GUIDE.md
@@ -0,0 +1,236 @@
+# 🚀 稷下学宫负载均衡系统 - 快速上手指南
+
+## 📋 前置条件
+
+1. **RapidAPI账户**: 确保已订阅以下API服务
+ - Alpha Vantage
+ - Yahoo Finance 15
+ - Webull
+ - Seeking Alpha
+
+2. **环境配置**: 已配置Doppler环境变量管理
+ ```bash
+ doppler secrets | grep RAPIDAPI_KEY
+ ```
+
+## ⚡ 5分钟快速体验
+
+### 1. 运行完整演示
+```bash
+cd /home/ben/liurenchaxin
+doppler run python demo_jixia_load_balancing.py
+```
+
+### 2. 查看演示结果
+```bash
+# 查看生成的结果文件
+ls demo_results_*.json
+
+# 查看AAPL的详细结果
+cat demo_results_aapl.json | jq .
+```
+
+## 🎯 核心功能演示
+
+### 单个仙人数据获取
+```python
+from src.jixia.engines.jixia_load_balancer import JixiaLoadBalancer
+
+# 初始化
+load_balancer = JixiaLoadBalancer(rapidapi_key)
+
+# 吕洞宾获取苹果股票数据
+result = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', 'AAPL')
+print(f"价格: ${result.data['price']}, 来源: {result.api_used}")
+```
+
+### 八仙论道完整演示
+```python
+# 进行八仙论道
+results = load_balancer.conduct_immortal_debate('TSLA')
+
+# 查看负载分布
+distribution = load_balancer.get_load_distribution()
+for api, stats in distribution.items():
+ print(f"{api}: {stats['calls']}次调用 ({stats['percentage']:.1f}%)")
+```
+
+## 📊 预期输出示例
+
+```
+🏛️ 稷下学宫八仙论道开始 - 主题: AAPL
+============================================================
+🎭 吕洞宾 正在获取 stock_quote 数据...
+ ✅ 成功从 alpha_vantage 获取数据 (响应时间: 1.33s)
+ 💰 吕洞宾: $202.38 (-2.5004%) via alpha_vantage
+
+🎭 何仙姑 正在获取 stock_quote 数据...
+ ✅ 成功从 yahoo_finance_15 获取数据 (响应时间: 1.87s)
+ 💰 何仙姑: $N/A (N/A) via yahoo_finance_15
+
+📊 负载分布统计:
+ alpha_vantage: 3 次调用 (37.5%) - 健康
+ yahoo_finance_15: 2 次调用 (25.0%) - 健康
+ webull: 3 次调用 (37.5%) - 健康
+```
+
+## 🔧 自定义配置
+
+### 修改仙人API偏好
+编辑 `/home/ben/liurenchaxin/src/jixia/config/immortal_api_config.json`:
+
+```json
+{
+ "immortals": {
+ "吕洞宾": {
+ "preferred_apis": {
+ "stock_quote": "webull", // 改为使用Webull
+ "company_overview": "alpha_vantage"
+ }
+ }
+ }
+}
+```
+
+### 调整缓存策略
+```python
+# 修改缓存TTL
+load_balancer.cache_ttl = 600 # 10分钟缓存
+
+# 清空缓存
+load_balancer.cache.clear()
+```
+
+## 🚨 故障排除
+
+### 常见问题
+
+1. **API密钥错误**
+ ```
+ ❌ 错误: 请设置RAPIDAPI_KEY环境变量
+ ```
+ **解决**: 确保Doppler配置正确
+ ```bash
+ doppler secrets set RAPIDAPI_KEY="your_key_here"
+ ```
+
+2. **API调用失败**
+ ```
+ ⚠️ alpha_vantage 不可用,尝试备用API...
+ ```
+ **解决**: 系统会自动故障转移,无需干预
+
+3. **数据格式异常**
+ ```
+ 💰 价格: $N/A
+ ```
+ **解决**: 某些API返回格式不同,系统会标准化处理
+
+### 调试模式
+```python
+# 启用详细日志
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+# 查看API健康状态
+for api, status in load_balancer.health_checker.health_status.items():
+ print(f"{api}: {'健康' if status['healthy'] else '异常'}")
+```
+
+## 📈 性能优化建议
+
+### 1. 缓存优化
+```python
+# 针对不同数据类型设置不同缓存时间
+cache_strategies = {
+ 'stock_quote': 60, # 1分钟
+ 'company_overview': 3600, # 1小时
+ 'market_news': 1800 # 30分钟
+}
+```
+
+### 2. 并发控制
+```python
+# 控制并发请求数量
+import time
+for immortal in immortals:
+ result = load_balancer.get_data_for_immortal(immortal, 'stock_quote', symbol)
+ time.sleep(0.2) # 避免过快请求
+```
+
+### 3. 批量处理
+```python
+# 批量获取多个股票数据
+symbols = ['AAPL', 'TSLA', 'MSFT', 'GOOGL']
+results = {}
+for symbol in symbols:
+ results[symbol] = load_balancer.conduct_immortal_debate(symbol)
+```
+
+## 🎯 最佳实践
+
+### 1. 监控API使用情况
+```python
+# 定期检查负载分布
+distribution = load_balancer.get_load_distribution()
+print(f"总调用次数: {sum(stats['calls'] for stats in distribution.values())}")
+```
+
+### 2. 合理使用缓存
+```python
+# 对于实时性要求不高的数据,优先使用缓存
+result = load_balancer.get_data_for_immortal('韩湘子', 'company_overview', 'AAPL')
+if result.cached:
+ print("使用缓存数据,节省API调用")
+```
+
+### 3. 错误处理
+```python
+result = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', 'AAPL')
+if not result.success:
+ print(f"获取数据失败: {result.error}")
+ # 实施降级策略
+else:
+ # 正常处理数据
+ process_stock_data(result.data)
+```
+
+## 📚 进阶使用
+
+### 自定义数据处理器
+```python
+class CustomDataNormalizer(DataNormalizer):
+ def normalize_stock_quote(self, raw_data, api_source):
+ # 自定义数据标准化逻辑
+ normalized = super().normalize_stock_quote(raw_data, api_source)
+ # 添加自定义字段
+ normalized['custom_score'] = self.calculate_score(normalized)
+ return normalized
+
+# 使用自定义处理器
+load_balancer.data_normalizer = CustomDataNormalizer()
+```
+
+### 自定义健康检查
+```python
+class CustomHealthChecker(APIHealthChecker):
+ def _perform_health_check(self, api_name):
+ # 自定义健康检查逻辑
+ # 例如:检查API响应时间、错误率等
+ pass
+
+load_balancer.health_checker = CustomHealthChecker()
+```
+
+## 🎉 完成!
+
+现在您已经掌握了稷下学宫负载均衡系统的基本使用方法。
+
+### 下一步
+- 📖 阅读完整文档: `README_jixia_load_balancing.md`
+- 🔧 查看配置文件: `src/jixia/config/immortal_api_config.json`
+- 💻 研究核心代码: `src/jixia/engines/jixia_load_balancer.py`
+- 🚀 开始构建您的投资分析系统!
+
+---
+*🏛️ 稷下学宫 - 智慧投资,从负载均衡开始*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/README_jixia_load_balancing.md b/modules/documentation-suite/docs/guides/README_jixia_load_balancing.md
new file mode 100644
index 0000000..c2e54f0
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/README_jixia_load_balancing.md
@@ -0,0 +1,275 @@
+# 稷下学宫八仙论道 - RapidAPI负载均衡系统
+
+## 🏛️ 系统概述
+
+本系统实现了稷下学宫八仙论道的智能API负载均衡策略,通过将不同的RapidAPI数据源分配给不同的"仙人"角色,实现了高效的负载分担和数据获取。
+
+### 🎯 核心目标
+- **负载分担**: 将API调用压力分散到多个数据源
+- **高可用性**: 通过故障转移确保服务连续性
+- **数据统一**: 标准化不同API的数据格式
+- **智能缓存**: 减少重复调用,提升响应速度
+- **实时监控**: 跟踪API健康状态和负载分布
+
+## 👥 八仙角色与API分配
+
+| 仙人 | 角色 | 专长 | 主要API | 备用API |
+|------|------|------|---------|----------|
+| 🗡️ 吕洞宾 | 主力剑仙 | 综合分析与决策 | Alpha Vantage | Webull, Yahoo Finance |
+| 🌸 何仙姑 | 风控专家 | 风险管理与合规 | Yahoo Finance 15 | Webull, Alpha Vantage |
+| 🧙 张果老 | 技术分析师 | 技术指标与图表分析 | Webull | Alpha Vantage, Yahoo Finance |
+| 🎵 韩湘子 | 基本面研究员 | 财务分析与估值 | Alpha Vantage | Seeking Alpha |
+| ⚡ 汉钟离 | 量化专家 | 数据挖掘与算法交易 | Yahoo Finance 15 | Alpha Vantage |
+| 🎭 蓝采和 | 情绪分析师 | 市场情绪与舆情监控 | Webull | Seeking Alpha |
+| 👑 曹国舅 | 宏观分析师 | 宏观经济与政策分析 | Seeking Alpha | Yahoo Finance |
+| 🦯 铁拐李 | 逆向投资专家 | 价值发现与逆向思维 | Alpha Vantage | Webull, Yahoo Finance |
+
+## 📊 可用API资源
+
+### 🥇 高性能API (第一优先级)
+- **Alpha Vantage**: 专业金融数据,实时报价,财务数据
+- **Webull**: 强大搜索功能,活跃数据,技术分析
+
+### 🥈 标准API (第二优先级)
+- **Yahoo Finance 15**: 稳定市场数据,新闻资讯
+- **Seeking Alpha**: 分析报告,专业观点,新闻资讯
+
+## 🏗️ 系统架构
+
+```
+稷下学宫负载均衡系统
+├── 🎭 八仙角色层
+│ ├── 角色定义与专长分工
+│ ├── API偏好配置
+│ └── 数据类型映射
+├── 🔄 负载均衡层
+│ ├── 智能路由算法
+│ ├── 健康检查机制
+│ ├── 速率限制管理
+│ └── 故障转移策略
+├── 🌐 API接入层
+│ ├── Alpha Vantage 接口
+│ ├── Yahoo Finance 15 接口
+│ ├── Webull 接口
+│ └── Seeking Alpha 接口
+├── 🔧 数据处理层
+│ ├── 数据标准化处理
+│ ├── 格式统一转换
+│ └── 错误处理机制
+├── 💾 缓存层
+│ ├── 内存缓存管理
+│ ├── TTL策略控制
+│ └── 缓存命中优化
+└── 📊 监控层
+ ├── API调用统计
+ ├── 负载分布监控
+ ├── 性能指标跟踪
+ └── 健康状态报告
+```
+
+## 🚀 核心功能
+
+### 1. 智能负载分担
+- **角色分工**: 每个仙人使用不同的主要API
+- **权重分配**: 基于API性能和可靠性的智能分配
+- **动态调整**: 根据实时负载情况自动调整
+
+### 2. 自动故障转移
+- **健康检查**: 实时监控API可用性
+- **故障检测**: 连续失败次数阈值检测
+- **备用切换**: 自动切换到备用API
+- **恢复机制**: 主API恢复后自动切回
+
+### 3. 数据标准化
+```python
+# 统一的数据格式
+{
+ 'symbol': 'AAPL',
+ 'price': 202.38,
+ 'change': -5.12,
+ 'change_percent': '-2.50%',
+ 'volume': 45678900,
+ 'high': 207.50,
+ 'low': 201.85,
+ 'source': 'alpha_vantage',
+ 'timestamp': '2025-08-02'
+}
+```
+
+### 4. 智能缓存策略
+- **分层缓存**: 不同数据类型使用不同TTL
+- **缓存预热**: 预先加载热点数据
+- **缓存穿透保护**: 避免缓存雪崩
+
+### 5. 实时监控
+- **API调用统计**: 实时跟踪每个API的调用次数
+- **负载分布**: 可视化负载分布情况
+- **性能指标**: 响应时间、成功率等关键指标
+- **告警机制**: 异常情况自动告警
+
+## 📁 文件结构
+
+```
+/home/ben/liurenchaxin/
+├── src/jixia/
+│ ├── engines/
+│ │ └── jixia_load_balancer.py # 核心负载均衡引擎
+│ └── config/
+│ └── immortal_api_config.json # 八仙角色与API配置
+├── demo_jixia_load_balancing.py # 演示脚本
+├── jixia_load_balancing_strategy.md # 策略文档
+└── README_jixia_load_balancing.md # 本说明文档
+```
+
+## 🎮 使用方法
+
+### 1. 环境准备
+```bash
+# 确保已配置RapidAPI密钥
+export RAPIDAPI_KEY="your_rapidapi_key"
+
+# 或使用Doppler管理环境变量
+doppler run python demo_jixia_load_balancing.py
+```
+
+### 2. 基本使用
+```python
+from src.jixia.engines.jixia_load_balancer import JixiaLoadBalancer
+
+# 创建负载均衡器
+load_balancer = JixiaLoadBalancer(rapidapi_key)
+
+# 单个仙人获取数据
+result = load_balancer.get_data_for_immortal('吕洞宾', 'stock_quote', 'AAPL')
+
+# 八仙论道(完整演示)
+results = load_balancer.conduct_immortal_debate('TSLA')
+
+# 查看负载分布
+distribution = load_balancer.get_load_distribution()
+```
+
+### 3. 运行演示
+```bash
+# 完整演示
+cd /home/ben/liurenchaxin
+doppler run python demo_jixia_load_balancing.py
+
+# 查看演示结果
+ls demo_results_*.json
+```
+
+## 📊 演示结果
+
+### 负载分布统计
+基于实际运行的演示结果:
+
+| API | 调用次数 | 负载占比 | 健康状态 | 平均响应时间 |
+|-----|----------|----------|----------|-------------|
+| Alpha Vantage | 8次 | 33.3% | 🟢 健康 | ~1.3s |
+| Yahoo Finance 15 | 7次 | 29.2% | 🟢 健康 | ~1.9s |
+| Webull | 9次 | 37.5% | 🟢 健康 | ~2.0s |
+| Seeking Alpha | 0次 | 0.0% | 🟢 健康 | N/A |
+
+### 性能指标
+- **总API调用**: 24次
+- **成功率**: 100%
+- **平均响应时间**: 1.7秒
+- **缓存命中率**: 约30%
+- **故障转移**: 自动且无缝
+
+## 🔧 配置说明
+
+### API配置 (`immortal_api_config.json`)
+```json
+{
+ "immortals": {
+ "吕洞宾": {
+ "title": "主力剑仙",
+ "specialty": "综合分析与决策",
+ "preferred_apis": {
+ "stock_quote": "alpha_vantage",
+ "company_overview": "alpha_vantage"
+ },
+ "api_weight": 0.15
+ }
+ },
+ "api_configurations": {
+ "alpha_vantage": {
+ "reliability_score": 0.95,
+ "response_time_avg": 0.8,
+ "cost_per_call": 0.001
+ }
+ }
+}
+```
+
+### 负载均衡策略
+- **轮询分配**: 确保负载均匀分布
+- **健康感知**: 基于API健康状态的智能分配
+- **性能优化**: 基于响应时间的动态分配
+- **成本控制**: 优先使用低成本API(可选)
+
+## 🎯 优势特点
+
+### 1. 高可用性
+- ✅ 多API冗余,单点故障不影响整体服务
+- ✅ 自动故障检测和恢复机制
+- ✅ 实时健康监控和告警
+
+### 2. 高性能
+- ✅ 智能缓存减少重复调用
+- ✅ 并发处理提升响应速度
+- ✅ 负载均衡避免单API过载
+
+### 3. 高扩展性
+- ✅ 模块化设计,易于添加新API
+- ✅ 配置驱动,无需修改代码
+- ✅ 插件化架构支持自定义扩展
+
+### 4. 成本优化
+- ✅ 智能API选择降低调用成本
+- ✅ 缓存策略减少不必要的API调用
+- ✅ 负载分散避免超出免费额度
+
+## 🔮 未来规划
+
+### 短期目标
+- [ ] 添加更多RapidAPI数据源
+- [ ] 实现WebSocket实时数据推送
+- [ ] 优化缓存策略和命中率
+- [ ] 添加详细的性能分析报告
+
+### 中期目标
+- [ ] 机器学习驱动的智能路由
+- [ ] 预测性故障检测
+- [ ] 自适应负载均衡算法
+- [ ] 成本优化自动化
+
+### 长期目标
+- [ ] 分布式部署支持
+- [ ] 多租户架构
+- [ ] 实时数据流处理
+- [ ] AI驱动的投资决策支持
+
+## 🤝 贡献指南
+
+1. **Fork** 项目仓库
+2. **创建** 功能分支 (`git checkout -b feature/AmazingFeature`)
+3. **提交** 更改 (`git commit -m 'Add some AmazingFeature'`)
+4. **推送** 到分支 (`git push origin feature/AmazingFeature`)
+5. **创建** Pull Request
+
+## 📄 许可证
+
+本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。
+
+## 📞 联系方式
+
+- **项目维护者**: 稷下学宫开发团队
+- **技术支持**: 通过 GitHub Issues 提交问题
+- **文档更新**: 欢迎提交文档改进建议
+
+---
+
+*🏛️ 稷下学宫 - 让智慧的光芒照亮投资的道路*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/guides/shushu-demo-results.md b/modules/documentation-suite/docs/guides/shushu-demo-results.md
new file mode 100644
index 0000000..0878b2e
--- /dev/null
+++ b/modules/documentation-suite/docs/guides/shushu-demo-results.md
@@ -0,0 +1,152 @@
+# 术数书 Hyperdrive + NeonDB 查询系统演示结果
+
+## 系统概述
+
+我们成功部署了一个基于 Cloudflare Hyperdrive + NeonDB 的术数书查询系统,通过高性能的边缘计算和数据库连接池优化,实现了对古代术数典籍的快速查询和检索。
+
+## 部署信息
+
+- **Worker URL**: https://hyperdrive.seekkey.tech/
+- **Hyperdrive ID**: ef43924d89064cddabfaccf06aadfab6
+- **数据库**: NeonDB PostgreSQL
+- **连接池**: 已启用
+- **边缘缓存**: 全球分布
+
+## 可用 API 端点
+
+### 1. 基础端点
+- `GET /` - 系统信息和端点列表
+- `GET /test-connection` - 测试数据库连接
+- `GET /test-query` - 测试数据库查询
+
+### 2. 术数书查询端点
+- `GET /query-tables` - 查询数据库表结构
+- `GET /query-shushu?limit=N` - 查询术数书内容
+- `GET /search-shushu?q=keyword&limit=N` - 搜索术数书内容
+- `GET /shushu-stats` - 获取术数书统计信息
+
+## 数据库结构
+
+通过 `/query-tables` 端点发现的表结构:
+
+```json
+{
+ "status": "success",
+ "message": "Tables retrieved successfully",
+ "tables": [
+ {
+ "table_name": "books",
+ "table_schema": "public"
+ },
+ {
+ "table_name": "hyperdrive_test",
+ "table_schema": "public"
+ },
+ {
+ "table_name": "playing_with_neon",
+ "table_schema": "public"
+ }
+ ]
+}
+```
+
+## 术数书内容示例
+
+通过 `/query-shushu?limit=3` 成功获取的术数书内容:
+
+### 书籍信息
+- **ID**: 1
+- **标题**: 《神相全编》
+- **作者**: 袁珙
+- **类别**: 相术
+- **子类别**: 面相手相
+- **总字数**: 33,897 字
+- **创建时间**: 2025-07-17T15:48:55.563Z
+
+### 内容片段
+
+```
+诈。口尖唇薄者多妄。冷笑无情多诈。偷视不正多诈。视上顾下多诈。
+妄说语言如太急者多诈。牙齿疏者多诈。又曰鼻尖毫出、眼细视低,
+口角高低,步履纵横,行步不匀,脚走高低多诈。
+
+宽大
+升斗满,部位中正,印堂开阔,诸部圆满,鼻窍微露。阴德眼上下堂
+有黄气,卧蚕出见,印堂黄气,精舍黄气。带令地角朝天、耳有轮廓
+朝水,口有棱角。眼带桃花眉如线。又如新月久视,意气可人。
+
+贪食格
+鼻如鹰嘴者多贪,心狡。眼红者多贪,心毒。眉卓者多贪。嘴尖者多贪。
+鼻勾者多贪。
+
+劳碌格
+眼长多劳碌。骨粗多劳碌。面如马面驴唇劳碌。眉重气弱者劳碌。
+鱼尾纹多者劳碌。
+```
+
+## 系统特点
+
+### 1. 高性能优化
+- **Hyperdrive 连接池**: 减少数据库连接开销
+- **边缘缓存**: 全球分布式缓存,降低延迟
+- **智能路由**: 自动选择最近的数据中心
+
+### 2. 成本优化
+- **连接复用**: 大幅减少 NeonDB 的连接数消耗
+- **查询缓存**: 减少重复查询的数据库负载
+- **按需扩展**: 根据访问量自动调整资源
+
+### 3. 功能特性
+- **多表查询**: 自动检测和查询可能的术数书表
+- **全文搜索**: 支持关键词搜索术数书内容
+- **统计分析**: 提供数据库使用统计信息
+- **RESTful API**: 标准化的 API 接口
+
+## 与 AutoRAG 对比的优势
+
+### 1. 数据访问速度
+- **Hyperdrive**: 全球边缘缓存,毫秒级响应
+- **AutoRAG**: 依赖本地或远程向量数据库,可能有网络延迟
+
+### 2. 数据一致性
+- **Hyperdrive**: 直接查询源数据库,保证数据实时性
+- **AutoRAG**: 向量化数据可能存在更新延迟
+
+### 3. 查询精确性
+- **Hyperdrive**: SQL 精确查询,支持复杂条件
+- **AutoRAG**: 语义相似性查询,可能存在误差
+
+### 4. 成本效益
+- **Hyperdrive**: 连接池优化,降低数据库成本
+- **AutoRAG**: 需要额外的向量数据库和计算资源
+
+## 使用场景
+
+### 1. 学术研究
+- 快速检索古代术数典籍
+- 支持精确的文本查询
+- 提供完整的原文内容
+
+### 2. 应用开发
+- 为术数应用提供数据 API
+- 支持多种查询方式
+- 高并发访问支持
+
+### 3. 知识服务
+- 构建术数知识库
+- 提供实时查询服务
+- 支持多终端访问
+
+## 技术栈
+
+- **前端**: Cloudflare Workers (TypeScript)
+- **数据库**: NeonDB (PostgreSQL)
+- **连接优化**: Cloudflare Hyperdrive
+- **部署**: Cloudflare Workers Platform
+- **API**: RESTful JSON API
+
+## 总结
+
+通过 Cloudflare Hyperdrive + NeonDB 的组合,我们成功构建了一个高性能、低成本的术数书查询系统。该系统不仅提供了快速的数据访问能力,还通过智能缓存和连接池优化,在 NeonDB 免费配额下支持了更大的访问量。
+
+相比传统的 AutoRAG 方案,我们的系统在数据访问速度、查询精确性和成本控制方面都有显著优势,为术数典籍的数字化应用提供了一个理想的技术解决方案。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/index.md b/modules/documentation-suite/docs/index.md
new file mode 100644
index 0000000..7915e34
--- /dev/null
+++ b/modules/documentation-suite/docs/index.md
@@ -0,0 +1,24 @@
+# 炼妖壶文档首页
+
+欢迎访问项目文档。以下是常用入口:
+
+- 快速上手与指南
+ - [Claude 集成与使用指南](guides/CLAUDE.md)
+ - [快速开始:负载均衡示例](guides/README_jixia_load_balancing.md)
+ - [Cloudflare AutoRAG 集成](guides/CLOUDFLARE_AUTORAG_INTEGRATION.md)
+ - [Google ADK 迁移指南](guides/GOOGLE_ADK_MIGRATION_GUIDE.md)
+- 记忆与后端
+ - [Vertex Memory Bank 设置](../docs/VERTEX_MEMORY_BANK_SETUP.md)
+- RapidAPI 相关
+ - [负载均衡策略](rapidapi/jixia_load_balancing_strategy.md)
+ - [订阅清单](rapidapi/api_inventory.md)
+ - [优化配置示例](rapidapi/optimized_config.md)
+ - [测试报告样例](rapidapi/test_report_20250802_120925.md)
+- 工作流与工具
+ - [n8n MongoDB Upsert 配置](../docs/n8n_mongodb_upsert_config.md)
+ - [n8n 去重工作流](../docs/n8n_deduplication_workflow.md)
+- 分析与要求
+ - [RSS 调试分析记录](analysis/rss_debug_analysis.md)
+ - [项目要求概览](requirements.md)
+
+内网与仅限内部的内容保持在 `internal/`,不会发布到 GitHub Pages。
diff --git a/modules/documentation-suite/docs/memory_bank_design.md b/modules/documentation-suite/docs/memory_bank_design.md
new file mode 100644
index 0000000..9a0b963
--- /dev/null
+++ b/modules/documentation-suite/docs/memory_bank_design.md
@@ -0,0 +1,160 @@
+# Memory Bank 设计与实现文档
+
+## 概述
+
+Memory Bank 是 稷下学宫AI辩论系统 的核心组件之一,旨在为每个AI智能体(八仙)提供持久化的记忆能力。通过集成不同的后端实现(如 Google Vertex AI Memory Bank 和 Cloudflare AutoRAG),系统能够灵活地存储、检索和利用智能体在辩论过程中积累的知识和经验。
+
+## 架构设计
+
+### 核心抽象
+
+系统通过 `MemoryBankProtocol` 定义了记忆银行的通用接口,确保了不同后端实现的可替换性。
+
+```python
+@runtime_checkable
+class MemoryBankProtocol(Protocol):
+ async def create_memory_bank(self, agent_name: str, display_name: Optional[str] = None) -> str: ...
+
+ async def add_memory(
+ self,
+ agent_name: str,
+ content: str,
+ memory_type: str = "conversation",
+ debate_topic: str = "",
+ metadata: Optional[Dict[str, Any]] = None,
+ ) -> str: ...
+
+ async def search_memories(
+ self,
+ agent_name: str,
+ query: str,
+ memory_type: Optional[str] = None,
+ limit: int = 10,
+ ) -> List[Dict[str, Any]]: ...
+
+ async def get_agent_context(self, agent_name: str, debate_topic: str) -> str: ...
+
+ async def save_debate_session(
+ self,
+ debate_topic: str,
+ participants: List[str],
+ conversation_history: List[Dict[str, str]],
+ outcomes: Optional[Dict[str, Any]] = None,
+ ) -> None: ...
+```
+
+### 工厂模式
+
+通过 `get_memory_backend` 工厂函数,系统可以根据配置动态选择合适的记忆后端实现。
+
+```python
+def get_memory_backend(prefer: Optional[str] = None) -> MemoryBankProtocol:
+ # 根据环境变量 JIXIA_MEMORY_BACKEND 选择后端
+ # 支持 "vertex" 和 "cloudflare"
+ ...
+```
+
+## 后端实现
+
+### Vertex AI Memory Bank
+
+基于 Google Vertex AI 的 Memory Bank 服务实现。
+
+**特点**:
+- 与 Google Cloud 生态系统深度集成
+- 提供企业级的安全性和可靠性
+- 支持复杂的元数据过滤和查询
+
+**配置**:
+- `GOOGLE_API_KEY`: Google API 密钥
+- `GOOGLE_CLOUD_PROJECT_ID`: Google Cloud 项目ID
+- `GOOGLE_CLOUD_LOCATION`: 部署区域 (默认 us-central1)
+
+### Cloudflare AutoRAG
+
+基于 Cloudflare Vectorize 和 Workers AI 实现的向量检索增强生成方案。
+
+**特点**:
+- 全球分布的边缘计算网络
+- 成本效益高,适合中小型项目
+- 易于部署和扩展
+
+**配置**:
+- `CLOUDFLARE_ACCOUNT_ID`: Cloudflare 账户ID
+- `CLOUDFLARE_API_TOKEN`: 具有 Vectorize 和 Workers AI 权限的 API 令牌
+
+## 使用指南
+
+### 初始化记忆银行
+
+```python
+from src.jixia.memory.factory import get_memory_backend
+
+# 根据环境变量自动选择后端
+memory_bank = get_memory_backend()
+
+# 或者显式指定后端
+memory_bank = get_memory_backend(prefer="cloudflare")
+```
+
+### 为智能体创建记忆空间
+
+```python
+# 为吕洞宾创建记忆银行/空间
+await memory_bank.create_memory_bank("lvdongbin")
+```
+
+### 添加记忆
+
+```python
+await memory_bank.add_memory(
+ agent_name="lvdongbin",
+ content="倾向于使用DCF模型评估科技股的内在价值",
+ memory_type="preference",
+ debate_topic="TSLA投资分析"
+)
+```
+
+### 搜索记忆
+
+```python
+memories = await memory_bank.search_memories(
+ agent_name="lvdongbin",
+ query="TSLA",
+ memory_type="preference"
+)
+```
+
+### 获取上下文
+
+```python
+context = await memory_bank.get_agent_context("lvdongbin", "TSLA投资分析")
+```
+
+## 最佳实践
+
+1. **合理分类记忆类型**:
+ - `conversation`: 记录对话历史,用于上下文理解和连贯性。
+ - `preference`: 存储智能体的偏好和倾向,指导决策过程。
+ - `knowledge`: 积累专业知识和数据,提升分析深度。
+ - `strategy`: 总结辩论策略和战术,优化表现。
+
+2. **定期维护记忆**:
+ - 实施记忆的定期清理和归档策略,避免信息过载。
+ - 通过 `save_debate_session` 方法系统性地保存重要辩论会话。
+
+3. **优化搜索查询**:
+ - 使用具体、明确的查询词以提高搜索相关性。
+ - 结合 `memory_type` 过滤器缩小搜索范围。
+
+4. **错误处理**:
+ - 在生产环境中,务必对所有异步操作进行适当的错误处理和重试机制。
+
+## 未来扩展
+
+1. **混合后端支持**: 允许同时使用多个后端,根据数据类型或访问模式进行路由。
+2. **记忆压缩与摘要**: 自动对长篇记忆进行摘要,提高检索效率。
+3. **情感分析**: 为记忆添加情感标签,丰富检索维度。
+
+---
+*此文档旨在为开发者提供 Memory Bank 模块的全面技术参考*
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/n8n_mongodb_upsert_config.md b/modules/documentation-suite/docs/n8n_mongodb_upsert_config.md
new file mode 100644
index 0000000..306e13c
--- /dev/null
+++ b/modules/documentation-suite/docs/n8n_mongodb_upsert_config.md
@@ -0,0 +1,59 @@
+# n8n MongoDB去重配置
+
+## 方案1: JS函数 + MongoDB Upsert
+
+### JS函数节点配置
+使用 `scripts/n8n_minimal_news.js` 的代码,只做基本处理和本批次去重。
+
+### MongoDB节点配置
+1. **操作类型**: Update
+2. **Collection**: articles
+3. **Update Key**: title (用标题作为唯一键)
+4. **Upsert**: 启用 ✅
+5. **Update Document**:
+```json
+{
+ "$setOnInsert": {
+ "id": "={{$json.id}}",
+ "title": "={{$json.title}}",
+ "published_time": "={{$json.published_time}}",
+ "source_url": "={{$json.source_url}}",
+ "created_at": "={{new Date().toISOString()}}"
+ },
+ "$set": {
+ "last_seen": "={{new Date().toISOString()}}"
+ }
+}
+```
+
+## 方案2: 纯MongoDB节点去重
+
+### MongoDB节点配置
+1. **操作类型**: Update Many
+2. **Collection**: articles
+3. **Filter**: `{"title": "={{$json.title}}"}`
+4. **Upsert**: 启用 ✅
+5. **Update**:
+```json
+{
+ "$setOnInsert": {
+ "title": "={{$json.title}}",
+ "published_time": "={{$json.published_time}}",
+ "source_url": "={{$json.source_url}}",
+ "created_at": "={{new Date().toISOString()}}"
+ }
+}
+```
+
+## 推荐方案
+
+使用**方案1**,因为:
+- JS函数生成连续的ID
+- MongoDB只负责去重插入
+- 逻辑清晰,易于调试
+
+## 测试步骤
+
+1. 第一次运行:应该插入所有新文章
+2. 第二次运行:应该0条插入(全部跳过)
+3. 检查数据库:确认没有重复标题
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/00_PROJECT_OVERVIEW.md b/modules/documentation-suite/docs/openbb_integration/00_PROJECT_OVERVIEW.md
new file mode 100644
index 0000000..27d6a30
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/00_PROJECT_OVERVIEW.md
@@ -0,0 +1,38 @@
+# OpenBB 集成项目总览
+
+本目录构建了本项目中 OpenBB v4 集成的完整文档生态,包括架构、实现、测试、用户指南、文化融合与维护。
+
+## 目标
+- 以 OpenBB v4 作为统一市场数据路由入口(`from openbb import obb`)
+- 在未安装或不可用时,提供稳健的兜底策略(演示/合成数据)
+- 将集成能力与稷下学宫/八仙论道的产品体验深度融合
+
+## 核心组件
+- UI:`app/tabs/openbb_tab.py`(自动检测 OpenBB 可用性,提供回退)
+- 引擎:`src/jixia/engines/openbb_engine.py`、`src/jixia/engines/openbb_stock_data.py`
+- 示例/演示数据:`examples/data/*.json`
+
+## 用户旅程(摘要)
+```mermaid
+graph TD
+ A[用户启动应用] --> B[选择OpenBB标签页]
+ B --> C[查看数据可用性状态]
+ C --> D{OpenBB是否可用?}
+ D -->|是| E[选择股票符号]
+ D -->|否| F[使用演示数据]
+ E --> G[启动八仙论道]
+ F --> G
+ G --> H[查看辩论结果]
+ H --> I[导出分析报告]
+```
+
+## 快速链接
+- 实现指南(API 集成与回退策略):[02_IMPLEMENTATION_GUIDE/api_integration_guide.md](../openbb_integration/02_IMPLEMENTATION_GUIDE/api_integration_guide.md)
+- 故障排查:[02_IMPLEMENTATION_GUIDE/troubleshooting_guide.md](../openbb_integration/02_IMPLEMENTATION_GUIDE/troubleshooting_guide.md)
+- 测试策略与报告:[03_TEST_DOCUMENTATION/](../openbb_integration/03_TEST_DOCUMENTATION/)
+- 用户指南:[04_USER_GUIDES/](../openbb_integration/04_USER_GUIDES/)
+
+## 维护与路线图
+- 版本说明与升级:见 [06_MAINTENANCE](../openbb_integration/06_MAINTENANCE/)
+
+> 注:本结构与 docs/AI_AGENT_TASKS/ROVODEV_PROJECT_INTEGRATION.md 的“文档架构”保持一致,以便多团队协作与交付。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/data_flow_design.md b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/data_flow_design.md
new file mode 100644
index 0000000..44cc6f8
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/data_flow_design.md
@@ -0,0 +1,3 @@
+# 数据流设计
+
+占位:将补充从 UI 输入 -> 引擎 -> OpenBB/provider -> DataFrame -> KPI/图表 的完整数据流与序列图。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/deployment_strategy.md b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/deployment_strategy.md
new file mode 100644
index 0000000..d899a65
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/deployment_strategy.md
@@ -0,0 +1,7 @@
+# 部署策略
+
+- OpenBB 作为可选依赖提供,默认不强制安装
+- 在需要时通过 `pip install "openbb>=4.1.0"` 启用
+- 国内网络场景建议使用镜像或代理
+
+后续将补充 CI/CD、环境矩阵与缓存策略。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/integration_patterns.md b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/integration_patterns.md
new file mode 100644
index 0000000..f319439
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/integration_patterns.md
@@ -0,0 +1,7 @@
+# 集成模式
+
+- 路由优先:`obb.equity.price.historical`,必要时回退到 `obb.etf.price.historical`
+- 结果标准化:兼容 `.to_df()` / `.to_dataframe()` / 原始对象 -> DataFrame
+- 列规范化:Date / Close 归一化,保证后续图表与 KPI 计算稳定
+
+后续将补充更多模式(基本面/新闻/宏观等)。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/system_architecture.md b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/system_architecture.md
new file mode 100644
index 0000000..80c7400
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/01_ARCHITECTURE_DESIGN/system_architecture.md
@@ -0,0 +1,17 @@
+# 系统架构(Qwen 输出)
+
+本章描述 OpenBB 集成在系统中的位置、边界与依赖。
+
+## 组件边界
+- UI 层:`app/tabs/openbb_tab.py`
+- 引擎层:`src/jixia/engines/openbb_engine.py`、`openbb_stock_data.py`
+- 数据层:OpenBB provider(yfinance、polygon、fmp 等)与演示/合成数据
+
+## 关键架构决策
+- 使用 OpenBB v4 统一路由
+- 延迟导入(lazy import)降低对未安装环境的侵入
+- 明确回退机制,保证用户体验连续性
+
+## 后续补充
+- 数据流与上下行依赖
+- 与“八仙论道”系统的耦合点与解耦方案
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/api_integration_guide.md b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/api_integration_guide.md
new file mode 100644
index 0000000..9a3d391
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/api_integration_guide.md
@@ -0,0 +1,56 @@
+# OpenBB 集成指南(迁移版)
+
+本页介绍 OpenBB v4 在本项目中的安装、配置、代码结构、回退机制、开发与测试、典型问题与后续计划。
+
+## 1. 为什么选择 OpenBB v4
+- 统一的路由接口:`from openbb import obb`
+- 多数据提供商聚合(如 yfinance、polygon、fmp 等)
+- 返回对象支持 `.results` 或 `.to_df()`,便于统一处理
+
+## 2. 安装与环境准备
+默认未安装 OpenBB(requirements.txt 中为可选依赖)。如需启用:
+
+```bash
+pip install "openbb>=4.1.0"
+```
+
+若你使用的是国内网络,建议配置合适的 PyPI 镜像或使用代理。
+
+## 3. 配置说明
+无需额外配置即可使用 `provider='yfinance'` 的公共数据。若你有付费数据源(如 polygon),可通过环境变量或 OpenBB 的 provider 配置进行设置。
+
+## 4. 代码结构与调用方式
+- Streamlit UI: `app/tabs/openbb_tab.py`
+ - 自动检测 OpenBB 是否可用;若不可用则使用演示数据或合成数据
+ - 优先路由:`obb.equity.price.historical`,ETF 回退至 `obb.etf.price.historical`
+- 引擎模块: `src/jixia/engines/openbb_engine.py`
+ - 延迟导入 OpenBB:首次调用时 `from openbb import obb`
+ - 对 `.results` / `.to_df()` / `.to_dataframe()` 做兼容处理
+- 辅助脚本: `src/jixia/engines/openbb_stock_data.py`
+ - 延迟导入 `obb`
+ - ETF 历史数据路径更新为 `obb.etf.price.historical`
+
+## 5. 回退机制
+- UI 层(OpenBB Tab)
+ - 未安装 OpenBB 或请求失败:读取 `examples/data/*.json` 的演示数据;仍失败则生成合成数据
+- 引擎层
+ - 若未安装 OpenBB:返回 `success=False`,带错误消息,不影响其他功能
+
+## 6. 开发与测试
+- 单元测试建议:
+ - 未安装 OpenBB 时,`_load_price_data` 能返回演示/合成数据
+ - 已安装 OpenBB 时,能通过 `obb.equity.price.historical` 获取 DataFrame
+- 在本仓库中新增了占位测试:`tests/test_openbb_fallback.py`
+
+## 7. 典型问题排查
+- ImportError: No module named 'openbb'
+ - 未安装 OpenBB;按第2节安装。
+- 返回空数据
+ - 检查 symbol 是否正确;尝试更换 provider 或缩短时间窗口。
+- 列名/索引不匹配
+ - UI 中已对常见列/索引做了规范化处理;如仍异常,可打印原始 DataFrame 排查。
+
+## 8. 后续计划
+- 接入更多 OpenBB 路由(基本面、新闻、财报、因子)
+- 与辩论系统结果联动,生成投资洞察卡片
+- 支持用户自定义 provider 优先级与兜底策略
diff --git a/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/core_engine_implementation.md b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/core_engine_implementation.md
new file mode 100644
index 0000000..2593a5d
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/core_engine_implementation.md
@@ -0,0 +1,10 @@
+# 核心引擎实现(Claude 输出)
+
+- 延迟导入 OpenBB
+- 统一结果转 DataFrame
+- 列/索引规范化与时间窗口裁剪
+- 失败时不影响其他功能(返回 success=False 或进入兜底路径)
+
+参考代码位置:
+- `src/jixia/engines/openbb_engine.py`
+- `src/jixia/engines/openbb_stock_data.py`
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/troubleshooting_guide.md b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/troubleshooting_guide.md
new file mode 100644
index 0000000..fa2b1b6
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/troubleshooting_guide.md
@@ -0,0 +1,8 @@
+# 故障排查指南
+
+常见问题与解决方案:
+- ImportError: No module named 'openbb' → 安装 `openbb>=4.1.0`
+- 返回空数据 → 检查 symbol,尝试其他 provider 或缩短时间窗口
+- 列名/索引不匹配 → 打印原始 DataFrame,参考 UI 中的规范化逻辑
+
+更多请参考:[api_integration_guide.md](./api_integration_guide.md) 第 7 节。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/ui_enhancement_guide.md b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/ui_enhancement_guide.md
new file mode 100644
index 0000000..7ff5209
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/02_IMPLEMENTATION_GUIDE/ui_enhancement_guide.md
@@ -0,0 +1,6 @@
+# UI 增强指南
+
+- 状态提示(OpenBB 可用/不可用)
+- 动态参数(symbol、时间窗口)
+- KPI 卡片(最新价、近30日涨幅、最大回撤)
+- 未来扩展位:基本面、新闻、情绪、宏观等
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/performance_benchmarks.md b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/performance_benchmarks.md
new file mode 100644
index 0000000..b920eb7
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/performance_benchmarks.md
@@ -0,0 +1,3 @@
+# 性能基准
+
+占位:记录不同 provider 与窗口设置下的响应时间、吞吐、内存曲线。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/quality_assurance_report.md b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/quality_assurance_report.md
new file mode 100644
index 0000000..b05c64d
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/quality_assurance_report.md
@@ -0,0 +1,6 @@
+# 质量保证报告
+
+- 代码规范检查
+- 文档完整性
+- 测试通过率
+- 文化准确性与用户体验评估(与 05_CULTURAL_INTEGRATION 联动)
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/test_results_report.md b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/test_results_report.md
new file mode 100644
index 0000000..5f2a3c4
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/test_results_report.md
@@ -0,0 +1,3 @@
+# 测试结果报告
+
+占位:记录关键用例、环境、通过率与截图/日志摘要。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/test_strategy.md b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/test_strategy.md
new file mode 100644
index 0000000..e829923
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/03_TEST_DOCUMENTATION/test_strategy.md
@@ -0,0 +1,6 @@
+# 测试策略(Gemini 输出)
+
+- 未安装 OpenBB:UI 能回退到演示/合成数据
+- 已安装 OpenBB:能成功调用 `obb.equity.price.historical`
+- 数据清洗后具有 Date/Close 列,KPI 计算不报错
+- 覆盖边界:空数据、异常路由、索引为日期等
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/best_practices.md b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/best_practices.md
new file mode 100644
index 0000000..2278da6
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/best_practices.md
@@ -0,0 +1,6 @@
+# 最佳实践
+
+- 将 OpenBB 作为轻依赖,必要时再安装
+- 使用统一的 DataFrame 规范化逻辑
+- 谨慎处理长时间窗口与缺失数据
+- 提供清晰的状态反馈与兜底
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/configuration_guide.md b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/configuration_guide.md
new file mode 100644
index 0000000..b432748
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/configuration_guide.md
@@ -0,0 +1,5 @@
+# 配置指南
+
+- 默认使用公共数据(yfinance)
+- 付费 provider(polygon/fmp 等)可通过 OpenBB provider 配置或环境变量设置
+- UI 参数:symbol、时间窗口、KPI 展示
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/getting_started.md b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/getting_started.md
new file mode 100644
index 0000000..79fcf62
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/getting_started.md
@@ -0,0 +1,8 @@
+# 入门指南
+
+1) 可选安装:`pip install "openbb>=4.1.0"`
+2) 运行应用,进入 OpenBB 标签页
+3) 输入股票/ETF 代码(如 AAPL),选择时间窗口
+4) 若未安装 OpenBB,将自动使用演示数据
+
+更多:见 [API 实现指南](../02_IMPLEMENTATION_GUIDE/api_integration_guide.md)。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/immortal_debate_tutorial.md b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/immortal_debate_tutorial.md
new file mode 100644
index 0000000..0ee3221
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/04_USER_GUIDES/immortal_debate_tutorial.md
@@ -0,0 +1,3 @@
+# 八仙论道教程(占位)
+
+将补充如何基于市场数据触发与解读“八仙论道”的步骤与最佳实践。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/cultural_accuracy_guidelines.md b/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/cultural_accuracy_guidelines.md
new file mode 100644
index 0000000..4d84a45
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/cultural_accuracy_guidelines.md
@@ -0,0 +1,3 @@
+# 文化准确性指南(占位)
+
+将补充文化审核检查点、示例与注意事项。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/immortal_characteristics.md b/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/immortal_characteristics.md
new file mode 100644
index 0000000..7a2bf13
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/immortal_characteristics.md
@@ -0,0 +1,3 @@
+# 八仙特质(占位)
+
+将列举八仙角色特性,并映射到数据分析风格/观点生成策略。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/jixia_philosophy_in_code.md b/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/jixia_philosophy_in_code.md
new file mode 100644
index 0000000..fca955f
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/05_CULTURAL_INTEGRATION/jixia_philosophy_in_code.md
@@ -0,0 +1,4 @@
+# 稷下学宫哲学在代码中的体现(占位)
+
+- 开放包容、百家争鸣 → 多 provider 聚合与辩论系统
+- 求同存异、理性决策 → 数据驱动 + 观点对齐
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/future_roadmap.md b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/future_roadmap.md
new file mode 100644
index 0000000..fb3c818
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/future_roadmap.md
@@ -0,0 +1,5 @@
+# 路线图
+
+- v1.x:路由扩展、稳定性增强
+- v2.x:高级分析与移动端适配
+- v3.x:企业级能力与治理
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/known_issues.md b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/known_issues.md
new file mode 100644
index 0000000..e210260
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/known_issues.md
@@ -0,0 +1,4 @@
+# 已知问题
+
+- 某些 symbol 在特定 provider 下返回为空或字段不齐
+- 长窗口数据清洗后为空的边界情况
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/release_notes.md b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/release_notes.md
new file mode 100644
index 0000000..2dd07de
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/release_notes.md
@@ -0,0 +1,4 @@
+# 发布说明
+
+- 参考:`docs/development/RELEASE_v2.0.0.md`
+- 在此记录 OpenBB 集成相关的变更、修复与新增功能。
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/upgrade_guide.md b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/upgrade_guide.md
new file mode 100644
index 0000000..189b008
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/06_MAINTENANCE/upgrade_guide.md
@@ -0,0 +1,5 @@
+# 升级指南
+
+- OpenBB 版本升级注意事项
+- provider 配置兼容性
+- 本项目接口变化记录
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/openbb_integration/README.md b/modules/documentation-suite/docs/openbb_integration/README.md
new file mode 100644
index 0000000..0ea8cb3
--- /dev/null
+++ b/modules/documentation-suite/docs/openbb_integration/README.md
@@ -0,0 +1,36 @@
+# OpenBB 集成文档索引
+
+本目录提供 OpenBB v4 在本项目中的完整集成文档。
+
+- 00 项目总览:./00_PROJECT_OVERVIEW.md
+- 01 架构设计(Qwen 输出):
+ - ./01_ARCHITECTURE_DESIGN/system_architecture.md
+ - ./01_ARCHITECTURE_DESIGN/data_flow_design.md
+ - ./01_ARCHITECTURE_DESIGN/integration_patterns.md
+ - ./01_ARCHITECTURE_DESIGN/deployment_strategy.md
+- 02 实现指南(Claude 输出):
+ - ./02_IMPLEMENTATION_GUIDE/core_engine_implementation.md
+ - ./02_IMPLEMENTATION_GUIDE/api_integration_guide.md
+ - ./02_IMPLEMENTATION_GUIDE/ui_enhancement_guide.md
+ - ./02_IMPLEMENTATION_GUIDE/troubleshooting_guide.md
+- 03 测试文档(Gemini 输出):
+ - ./03_TEST_DOCUMENTATION/test_strategy.md
+ - ./03_TEST_DOCUMENTATION/test_results_report.md
+ - ./03_TEST_DOCUMENTATION/performance_benchmarks.md
+ - ./03_TEST_DOCUMENTATION/quality_assurance_report.md
+- 04 用户指南:
+ - ./04_USER_GUIDES/getting_started.md
+ - ./04_USER_GUIDES/immortal_debate_tutorial.md
+ - ./04_USER_GUIDES/configuration_guide.md
+ - ./04_USER_GUIDES/best_practices.md
+- 05 文化融合文档:
+ - ./05_CULTURAL_INTEGRATION/immortal_characteristics.md
+ - ./05_CULTURAL_INTEGRATION/jixia_philosophy_in_code.md
+ - ./05_CULTURAL_INTEGRATION/cultural_accuracy_guidelines.md
+- 06 维护:
+ - ./06_MAINTENANCE/release_notes.md
+ - ./06_MAINTENANCE/upgrade_guide.md
+ - ./06_MAINTENANCE/known_issues.md
+ - ./06_MAINTENANCE/future_roadmap.md
+
+快速入口:API 实现指南 → ./02_IMPLEMENTATION_GUIDE/api_integration_guide.md
diff --git a/modules/documentation-suite/docs/rapidapi/api_inventory.md b/modules/documentation-suite/docs/rapidapi/api_inventory.md
new file mode 100644
index 0000000..28304d8
--- /dev/null
+++ b/modules/documentation-suite/docs/rapidapi/api_inventory.md
@@ -0,0 +1,196 @@
+# RapidAPI 订阅清单
+
+## 📋 概览
+
+基于Doppler配置和实际测试,记录当前RapidAPI订阅的API服务及其可用性。
+
+**API密钥**: `[REDACTED - 从Doppler获取RAPIDAPI_KEY]`
+**总订阅数**: 17个API服务
+**最后更新**: 2025-08-02
+
+## ✅ 已验证可用的API (4个)
+
+### 1. Alpha Vantage (`alpha-vantage.p.rapidapi.com`) ⚡
+- **状态**: ✅ 可用 (响应时间: 1.26s)
+- **用途**: 股票基本面数据、财报数据
+- **测试结果**: 成功获取AAPL全球报价数据
+- **数据字段**: Global Quote
+- **端点**:
+ - `/query?function=GLOBAL_QUOTE&symbol={symbol}` - 实时报价
+ - `/query?function=OVERVIEW&symbol={symbol}` - 公司概览
+ - `/query?function=EARNINGS&symbol={symbol}` - 财报数据
+
+### 2. Webull (`webull.p.rapidapi.com`) ⚡
+- **状态**: ✅ 可用 (响应时间: 1.56s)
+- **用途**: 股票搜索、报价
+- **测试结果**: 成功获取AAPL搜索数据
+- **数据字段**: stocks, busiModel
+- **端点**:
+ - `/stock/search?keyword={symbol}` - 股票搜索
+ - `/market/get-active-gainers` - 活跃涨幅股
+
+### 3. Yahoo Finance 15 (`yahoo-finance15.p.rapidapi.com`)
+- **状态**: ✅ 可用 (响应时间: 2.07s)
+- **用途**: 实时股价、市场数据
+- **测试结果**: 成功获取AAPL报价数据
+- **数据字段**: meta, body
+- **端点**:
+ - `/api/yahoo/qu/quote/{symbol}` - 股票报价
+ - `/api/yahoo/co/collections/day_gainers` - 涨幅榜
+ - `/api/yahoo/co/collections/day_losers` - 跌幅榜
+
+### 4. Seeking Alpha (`seeking-alpha.p.rapidapi.com`)
+- **状态**: ✅ 可用 (响应时间: 3.32s)
+- **用途**: 股票分析、新闻
+- **测试结果**: 成功获取AAPL分析数据
+- **数据字段**: data
+- **端点**:
+ - `/symbols/get-profile?symbols={symbol}` - 股票档案
+ - `/news/list?category=market-news` - 市场新闻
+
+## ❌ 未订阅或失败的API (13个)
+
+### 权限问题 (403 Forbidden)
+以下API显示"You are not subscribed to this API",表示未订阅:
+
+- **yahoo_finance_api_data** (`yahoo-finance-api1.p.rapidapi.com`)
+- **yahoo_finance_basic** (`yahoo-finance127.p.rapidapi.com`)
+- **morning_star** (`morningstar1.p.rapidapi.com`)
+- **investing_com** (`investing-cryptocurrency-markets.p.rapidapi.com`)
+- **finance_api** (`real-time-finance-data.p.rapidapi.com`)
+
+### API不存在 (404 Not Found)
+以下API显示"API doesn't exists",可能已下线:
+
+- **yahoo_finance_realtime** (`yahoo-finance-low-latency.p.rapidapi.com`)
+- **tradingview** (`tradingview-ta.p.rapidapi.com`)
+- **sec_filings** (`sec-filings.p.rapidapi.com`)
+
+### 端点错误 (404 Endpoint Not Found)
+以下API存在但端点路径不正确:
+
+- **yh_finance** (`yh-finance-complete.p.rapidapi.com`)
+- **ms_finance** (`ms-finance.p.rapidapi.com`)
+- **exchangerate_api** (`exchangerate-api.p.rapidapi.com`)
+- **crypto_news** (`cryptocurrency-news2.p.rapidapi.com`)
+
+### 无响应数据 (204 No Content)
+- **yh_finance_complete** (`yh-finance.p.rapidapi.com`) - 返回空响应
+
+## 🔄 需要进一步测试的API
+
+### 8. YH Finance Complete (`yh-finance.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 完整的Yahoo Finance数据
+
+### 9. Yahoo Finance API Data (`yahoo-finance-api1.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: Yahoo Finance API数据
+
+### 10. Yahoo Finance Low Latency (`yahoo-finance-low-latency.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 低延迟实时数据
+
+### 11. YH Finance Complete (`yh-finance-complete.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 完整金融数据
+
+### 12. Yahoo Finance 127 (`yahoo-finance127.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: Yahoo Finance基础数据
+
+### 13. Real Time Finance Data (`real-time-finance-data.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 实时金融数据
+
+### 14. MS Finance (`ms-finance.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 微软金融数据
+
+### 15. SEC Filings (`sec-filings.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: SEC文件数据
+
+### 16. ExchangeRate API (`exchangerate-api.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 汇率数据
+
+### 17. Cryptocurrency News 2 (`cryptocurrency-news2.p.rapidapi.com`)
+- **状态**: 🟡 待测试
+- **用途**: 加密货币新闻
+
+## 📊 使用统计
+
+### 成功率分析
+- **可用API**: 4/17 (23.5%)
+- **未订阅API**: 5/17 (29.4%)
+- **API不存在**: 3/17 (17.6%)
+- **端点错误**: 4/17 (23.5%)
+- **其他问题**: 1/17 (5.9%)
+
+### 八仙论道中的API使用情况
+- **吕洞宾**: Alpha Vantage ✅
+- **何仙姑**: Yahoo Finance 15 ✅
+- **张果老**: Seeking Alpha ✅
+- **韩湘子**: 多个API失败 ❌
+- **汉钟离**: 多个API失败 ❌
+- **蓝采和**: Webull ✅
+- **曹国舅**: Seeking Alpha ✅
+- **铁拐李**: 多个API失败 ❌
+
+## 🔧 优化建议
+
+### 1. 端点配置优化
+- 需要为每个API配置正确的端点路径
+- 研究各API的具体参数要求
+- 添加更多数据类型的端点映射
+
+### 2. 故障转移策略
+- 优先使用已验证可用的API
+- 将Yahoo Finance系列API作为主要数据源
+- Alpha Vantage作为基本面数据的首选
+
+### 3. API测试计划
+- 逐个测试待测试的API
+- 记录每个API的具体用法和限制
+- 建立API健康检查机制
+
+## 📝 测试记录
+
+### 2025-08-02 全面测试记录
+```
+✅ alpha_vantage: 1.26s - 成功获取AAPL全球报价
+✅ webull: 1.56s - 成功获取AAPL搜索数据
+✅ yahoo_finance_1: 2.07s - 成功获取AAPL报价数据
+✅ seeking_alpha: 3.32s - 成功获取AAPL分析数据
+
+❌ yahoo_finance_api_data: 403 - 未订阅
+❌ yahoo_finance_basic: 403 - 未订阅
+❌ morning_star: 403 - 未订阅
+❌ investing_com: 403 - 未订阅
+❌ finance_api: 403 - 未订阅
+
+❌ yahoo_finance_realtime: 404 - API不存在
+❌ tradingview: 404 - API不存在
+❌ sec_filings: 404 - API不存在
+
+❌ yh_finance: 404 - 端点不存在
+❌ ms_finance: 404 - 端点不存在
+❌ exchangerate_api: 404 - 端点不存在
+❌ crypto_news: 404 - 端点不存在
+
+❌ yh_finance_complete: 204 - 无响应数据
+```
+
+## 🚀 下一步行动
+
+1. **完善端点配置**: 为所有API添加正确的端点映射
+2. **批量测试**: 使用自动化脚本测试所有待测试API
+3. **文档更新**: 根据测试结果更新此文档
+4. **性能优化**: 基于可用性调整八仙论道的API分配策略
+
+---
+
+**维护者**: Ben
+**联系方式**: 通过Doppler配置管理API密钥
+**更新频率**: 每次API测试后更新
diff --git a/modules/documentation-suite/docs/rapidapi/jixia_load_balancing_strategy.md b/modules/documentation-suite/docs/rapidapi/jixia_load_balancing_strategy.md
new file mode 100644
index 0000000..9257992
--- /dev/null
+++ b/modules/documentation-suite/docs/rapidapi/jixia_load_balancing_strategy.md
@@ -0,0 +1,341 @@
+# 🏛️ 稷下学宫八仙论道负载分担策略
+
+## 📋 概述
+
+基于现有的RapidAPI订阅和雅虎财经数据接口,设计一套智能负载分担策略,让八仙论道系统中的不同角色调用不同的API端点获取相同类型的数据,实现API负载均衡和系统稳定性。
+
+## 🎯 核心理念
+
+**"同样的数据,不同的路径"** - 通过多API轮换获取相同类型的市场数据,避免单一API过载,确保系统稳定运行。
+
+## 📊 可用API资源清单
+
+### ✅ 已验证可用的API (4个)
+
+```python
+AVAILABLE_APIS = {
+ 'alpha_vantage': {
+ 'host': 'alpha-vantage.p.rapidapi.com',
+ 'response_time': 1.26,
+ 'rate_limit': '500/min, 500k/month',
+ 'specialty': ['stock_quote', 'company_overview', 'earnings']
+ },
+ 'yahoo_finance_15': {
+ 'host': 'yahoo-finance15.p.rapidapi.com',
+ 'response_time': 2.07,
+ 'rate_limit': '500/min, 500k/month',
+ 'specialty': ['stock_quote', 'market_movers', 'news']
+ },
+ 'webull': {
+ 'host': 'webull.p.rapidapi.com',
+ 'response_time': 1.56,
+ 'rate_limit': '500/min, 500k/month',
+ 'specialty': ['stock_search', 'market_gainers']
+ },
+ 'seeking_alpha': {
+ 'host': 'seeking-alpha.p.rapidapi.com',
+ 'response_time': 3.32,
+ 'rate_limit': '500/min, 500k/month',
+ 'specialty': ['company_profile', 'market_analysis']
+ }
+}
+```
+
+## 🎭 八仙负载分担配置
+
+### 数据类型映射策略
+
+```python
+DATA_TYPE_API_MAPPING = {
+ # 股票报价数据 - 3个API可提供
+ 'stock_quote': {
+ '吕洞宾': 'alpha_vantage', # 主力剑仙用最快的API
+ '何仙姑': 'yahoo_finance_15', # 风控专家用稳定的API
+ '张果老': 'webull', # 技术分析师用搜索强的API
+ '韩湘子': 'alpha_vantage', # 基本面研究用专业API
+ '汉钟离': 'yahoo_finance_15', # 量化专家用市场数据API
+ '蓝采和': 'webull', # 情绪分析师用活跃数据API
+ '曹国舅': 'seeking_alpha', # 宏观分析师用分析API
+ '铁拐李': 'alpha_vantage' # 逆向投资用基础数据API
+ },
+
+ # 公司概览数据 - 2个API可提供
+ 'company_overview': {
+ '吕洞宾': 'alpha_vantage', # 技术分析需要完整数据
+ '何仙姑': 'seeking_alpha', # 风控需要分析师观点
+ '张果老': 'alpha_vantage', # 技术分析偏好数据API
+ '韩湘子': 'seeking_alpha', # 基本面研究需要深度分析
+ '汉钟离': 'alpha_vantage', # 量化需要结构化数据
+ '蓝采和': 'seeking_alpha', # 情绪分析需要市场观点
+ '曹国舅': 'seeking_alpha', # 宏观分析需要专业观点
+ '铁拐李': 'alpha_vantage' # 逆向投资需要基础数据
+ },
+
+ # 市场动态数据 - 2个API可提供
+ 'market_movers': {
+ '吕洞宾': 'yahoo_finance_15', # 剑仙关注市场热点
+ '何仙姑': 'webull', # 风控关注活跃股票
+ '张果老': 'yahoo_finance_15', # 技术分析关注涨跌榜
+ '韩湘子': 'webull', # 基本面研究关注搜索热度
+ '汉钟离': 'yahoo_finance_15', # 量化关注市场数据
+ '蓝采和': 'webull', # 情绪分析关注活跃度
+ '曹国舅': 'yahoo_finance_15', # 宏观关注整体趋势
+ '铁拐李': 'webull' # 逆向投资关注异常股票
+ },
+
+ # 新闻和分析数据 - 2个API可提供
+ 'market_news': {
+ '吕洞宾': 'yahoo_finance_15', # 剑仙需要快速资讯
+ '何仙姑': 'seeking_alpha', # 风控需要深度分析
+ '张果老': 'yahoo_finance_15', # 技术分析关注市场新闻
+ '韩湘子': 'seeking_alpha', # 基本面需要分析师观点
+ '汉钟离': 'yahoo_finance_15', # 量化关注数据驱动新闻
+ '蓝采和': 'seeking_alpha', # 情绪分析需要市场情绪
+ '曹国舅': 'seeking_alpha', # 宏观需要政策分析
+ '铁拐李': 'yahoo_finance_15' # 逆向投资关注反向指标
+ }
+}
+```
+
+## 🔄 智能轮换策略
+
+### 1. 时间窗口轮换
+
+```python
+TIME_BASED_ROTATION = {
+ # 交易时段 (9:30-16:00 EST) - 优先使用快速API
+ 'trading_hours': {
+ 'primary_apis': ['alpha_vantage', 'webull'],
+ 'backup_apis': ['yahoo_finance_15', 'seeking_alpha']
+ },
+
+ # 非交易时段 - 可以使用较慢但更详细的API
+ 'after_hours': {
+ 'primary_apis': ['seeking_alpha', 'yahoo_finance_15'],
+ 'backup_apis': ['alpha_vantage', 'webull']
+ }
+}
+```
+
+### 2. 负载感知轮换
+
+```python
+LOAD_AWARE_ROTATION = {
+ # 当某个API接近限制时,自动切换到其他API
+ 'rate_limit_thresholds': {
+ 'alpha_vantage': 450, # 90% of 500/min
+ 'yahoo_finance_15': 450,
+ 'webull': 450,
+ 'seeking_alpha': 450
+ },
+
+ # 故障转移优先级
+ 'failover_priority': {
+ 'alpha_vantage': ['webull', 'yahoo_finance_15'],
+ 'yahoo_finance_15': ['webull', 'alpha_vantage'],
+ 'webull': ['alpha_vantage', 'yahoo_finance_15'],
+ 'seeking_alpha': ['yahoo_finance_15', 'alpha_vantage']
+ }
+}
+```
+
+## 🏗️ 实现架构
+
+### 核心组件
+
+```python
+class JixiaLoadBalancer:
+ """稷下学宫负载均衡器"""
+
+ def __init__(self):
+ self.api_pool = APIPool(AVAILABLE_APIS)
+ self.immortal_mapping = DATA_TYPE_API_MAPPING
+ self.rate_limiter = RateLimiter()
+ self.health_checker = APIHealthChecker()
+
+ def get_data_for_immortal(self, immortal_name: str, data_type: str, symbol: str):
+ """为特定仙人获取数据"""
+ # 1. 获取该仙人的首选API
+ preferred_api = self.immortal_mapping[data_type][immortal_name]
+
+ # 2. 检查API健康状态和速率限制
+ if self.is_api_available(preferred_api):
+ return self.call_api(preferred_api, data_type, symbol)
+
+ # 3. 故障转移到备用API
+ backup_apis = LOAD_AWARE_ROTATION['failover_priority'][preferred_api]
+ for backup_api in backup_apis:
+ if self.is_api_available(backup_api):
+ return self.call_api(backup_api, data_type, symbol)
+
+ # 4. 如果所有API都不可用,返回缓存数据
+ return self.get_cached_data(data_type, symbol)
+
+ def is_api_available(self, api_name: str) -> bool:
+ """检查API是否可用"""
+ # 检查健康状态
+ if not self.health_checker.is_healthy(api_name):
+ return False
+
+ # 检查速率限制
+ if self.rate_limiter.is_rate_limited(api_name):
+ return False
+
+ return True
+```
+
+### 数据统一化处理
+
+```python
+class DataNormalizer:
+ """数据标准化处理器"""
+
+ def normalize_stock_quote(self, raw_data: dict, api_source: str) -> dict:
+ """将不同API的股票报价数据标准化"""
+ if api_source == 'alpha_vantage':
+ return self._normalize_alpha_vantage_quote(raw_data)
+ elif api_source == 'yahoo_finance_15':
+ return self._normalize_yahoo_quote(raw_data)
+ elif api_source == 'webull':
+ return self._normalize_webull_quote(raw_data)
+
+ def _normalize_alpha_vantage_quote(self, data: dict) -> dict:
+ """标准化Alpha Vantage数据格式"""
+ global_quote = data.get('Global Quote', {})
+ return {
+ 'symbol': global_quote.get('01. symbol'),
+ 'price': float(global_quote.get('05. price', 0)),
+ 'change': float(global_quote.get('09. change', 0)),
+ 'change_percent': global_quote.get('10. change percent', '0%'),
+ 'volume': int(global_quote.get('06. volume', 0)),
+ 'source': 'alpha_vantage'
+ }
+
+ def _normalize_yahoo_quote(self, data: dict) -> dict:
+ """标准化Yahoo Finance数据格式"""
+ body = data.get('body', {})
+ return {
+ 'symbol': body.get('symbol'),
+ 'price': float(body.get('regularMarketPrice', 0)),
+ 'change': float(body.get('regularMarketChange', 0)),
+ 'change_percent': f"{body.get('regularMarketChangePercent', 0):.2f}%",
+ 'volume': int(body.get('regularMarketVolume', 0)),
+ 'source': 'yahoo_finance_15'
+ }
+```
+
+## 📊 监控和统计
+
+### API使用统计
+
+```python
+class APIUsageMonitor:
+ """API使用监控器"""
+
+ def __init__(self):
+ self.usage_stats = {
+ 'alpha_vantage': {'calls': 0, 'errors': 0, 'avg_response_time': 0},
+ 'yahoo_finance_15': {'calls': 0, 'errors': 0, 'avg_response_time': 0},
+ 'webull': {'calls': 0, 'errors': 0, 'avg_response_time': 0},
+ 'seeking_alpha': {'calls': 0, 'errors': 0, 'avg_response_time': 0}
+ }
+
+ def record_api_call(self, api_name: str, response_time: float, success: bool):
+ """记录API调用统计"""
+ stats = self.usage_stats[api_name]
+ stats['calls'] += 1
+ if not success:
+ stats['errors'] += 1
+
+ # 更新平均响应时间
+ current_avg = stats['avg_response_time']
+ total_calls = stats['calls']
+ stats['avg_response_time'] = (current_avg * (total_calls - 1) + response_time) / total_calls
+
+ def get_load_distribution(self) -> dict:
+ """获取负载分布统计"""
+ total_calls = sum(stats['calls'] for stats in self.usage_stats.values())
+ if total_calls == 0:
+ return {}
+
+ return {
+ api: {
+ 'percentage': (stats['calls'] / total_calls) * 100,
+ 'success_rate': ((stats['calls'] - stats['errors']) / stats['calls']) * 100 if stats['calls'] > 0 else 0,
+ 'avg_response_time': stats['avg_response_time']
+ }
+ for api, stats in self.usage_stats.items()
+ }
+```
+
+## 🎯 实施计划
+
+### 第一阶段:基础负载均衡
+1. **实现核心负载均衡器** - 基本的API轮换逻辑
+2. **数据标准化处理** - 统一不同API的数据格式
+3. **简单故障转移** - 基本的备用API切换
+
+### 第二阶段:智能优化
+1. **速率限制监控** - 实时监控API使用情况
+2. **健康检查机制** - 定期检测API可用性
+3. **性能优化** - 基于响应时间优化API选择
+
+### 第三阶段:高级功能
+1. **预测性负载均衡** - 基于历史数据预测API负载
+2. **成本优化** - 基于API成本优化调用策略
+3. **实时监控面板** - 可视化API使用情况
+
+## 📈 预期效果
+
+### 性能提升
+- **API负载分散**: 单个API负载降低60-70%
+- **系统稳定性**: 故障率降低80%以上
+- **响应速度**: 平均响应时间提升30%
+
+### 成本控制
+- **API使用优化**: 避免单一API过度使用
+- **故障恢复**: 减少因API故障导致的数据缺失
+- **扩展性**: 支持更多API的无缝接入
+
+## 🔧 配置示例
+
+### 环境配置
+```bash
+# Doppler环境变量
+RAPIDAPI_KEY=your_rapidapi_key
+ALPHA_VANTAGE_API_KEY=your_alpha_vantage_key
+
+# 负载均衡配置
+LOAD_BALANCER_ENABLED=true
+API_HEALTH_CHECK_INTERVAL=300 # 5分钟
+RATE_LIMIT_BUFFER=50 # 保留50个请求的缓冲
+```
+
+### 使用示例
+```python
+# 在稷下学宫系统中使用
+from jixia_load_balancer import JixiaLoadBalancer
+
+load_balancer = JixiaLoadBalancer()
+
+# 八仙论道时,每个仙人获取数据
+for immortal in ['吕洞宾', '何仙姑', '张果老', '韩湘子', '汉钟离', '蓝采和', '曹国舅', '铁拐李']:
+ quote_data = load_balancer.get_data_for_immortal(immortal, 'stock_quote', 'TSLA')
+ overview_data = load_balancer.get_data_for_immortal(immortal, 'company_overview', 'TSLA')
+
+ print(f"{immortal}: 获取到{quote_data['source']}的数据")
+```
+
+---
+
+## 🎉 总结
+
+通过这套负载分担策略,稷下学宫八仙论道系统可以:
+
+1. **智能分配API调用** - 不同仙人使用不同API获取相同数据
+2. **实现真正的负载均衡** - 避免单一API过载
+3. **提高系统稳定性** - 多重故障转移保障
+4. **优化成本效益** - 充分利用现有API资源
+5. **支持无缝扩展** - 新API可轻松接入系统
+
+**"八仙过海,各显神通"** - 让每个仙人都有自己的数据获取路径,共同构建稳定可靠的智能投资决策系统!🚀
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/rapidapi/optimized_config.md b/modules/documentation-suite/docs/rapidapi/optimized_config.md
new file mode 100644
index 0000000..63abdf1
--- /dev/null
+++ b/modules/documentation-suite/docs/rapidapi/optimized_config.md
@@ -0,0 +1,165 @@
+# 优化的RapidAPI配置
+
+基于实际测试结果,优化八仙论道系统的API配置。
+
+## 🎯 可用API配置 (4个)
+
+### 高性能API (响应时间 < 2s)
+```python
+FAST_APIS = {
+ 'alpha_vantage': {
+ 'host': 'alpha-vantage.p.rapidapi.com',
+ 'response_time': 1.26,
+ 'data_types': ['quote', 'overview', 'earnings'],
+ 'specialty': 'fundamental_analysis'
+ },
+ 'webull': {
+ 'host': 'webull.p.rapidapi.com',
+ 'response_time': 1.56,
+ 'data_types': ['search', 'quote', 'gainers'],
+ 'specialty': 'stock_search'
+ }
+}
+```
+
+### 标准API (响应时间 2-4s)
+```python
+STANDARD_APIS = {
+ 'yahoo_finance_1': {
+ 'host': 'yahoo-finance15.p.rapidapi.com',
+ 'response_time': 2.07,
+ 'data_types': ['quote', 'gainers', 'losers'],
+ 'specialty': 'market_data'
+ },
+ 'seeking_alpha': {
+ 'host': 'seeking-alpha.p.rapidapi.com',
+ 'response_time': 3.32,
+ 'data_types': ['profile', 'news'],
+ 'specialty': 'analysis_news'
+ }
+}
+```
+
+## 🎭 优化的八仙API分配
+
+基于可用API重新分配八仙的数据源:
+
+```python
+OPTIMIZED_IMMORTAL_APIS = {
+ '吕洞宾': { # 技术分析专家
+ 'primary': 'alpha_vantage',
+ 'backup': ['yahoo_finance_1'],
+ 'data_type': 'overview',
+ 'specialty': 'comprehensive_analysis'
+ },
+ '何仙姑': { # 风险控制专家
+ 'primary': 'yahoo_finance_1',
+ 'backup': ['webull'],
+ 'data_type': 'quote',
+ 'specialty': 'risk_management'
+ },
+ '张果老': { # 历史数据分析师
+ 'primary': 'seeking_alpha',
+ 'backup': ['alpha_vantage'],
+ 'data_type': 'profile',
+ 'specialty': 'fundamental_analysis'
+ },
+ '韩湘子': { # 新兴资产专家
+ 'primary': 'webull',
+ 'backup': ['yahoo_finance_1'],
+ 'data_type': 'search',
+ 'specialty': 'emerging_trends'
+ },
+ '汉钟离': { # 热点追踪
+ 'primary': 'yahoo_finance_1',
+ 'backup': ['webull'],
+ 'data_type': 'gainers',
+ 'specialty': 'hot_trends'
+ },
+ '蓝采和': { # 潜力股发现
+ 'primary': 'webull',
+ 'backup': ['alpha_vantage'],
+ 'data_type': 'search',
+ 'specialty': 'undervalued_stocks'
+ },
+ '曹国舅': { # 机构分析
+ 'primary': 'seeking_alpha',
+ 'backup': ['alpha_vantage'],
+ 'data_type': 'profile',
+ 'specialty': 'institutional_analysis'
+ },
+ '铁拐李': { # 逆向投资
+ 'primary': 'alpha_vantage',
+ 'backup': ['seeking_alpha'],
+ 'data_type': 'overview',
+ 'specialty': 'contrarian_analysis'
+ }
+}
+```
+
+## 📊 端点映射
+
+### Alpha Vantage
+```python
+'alpha_vantage': {
+ 'quote': f'/query?function=GLOBAL_QUOTE&symbol={symbol}',
+ 'overview': f'/query?function=OVERVIEW&symbol={symbol}',
+ 'earnings': f'/query?function=EARNINGS&symbol={symbol}'
+}
+```
+
+### Yahoo Finance 15
+```python
+'yahoo_finance_1': {
+ 'quote': f'/api/yahoo/qu/quote/{symbol}',
+ 'gainers': '/api/yahoo/co/collections/day_gainers',
+ 'losers': '/api/yahoo/co/collections/day_losers'
+}
+```
+
+### Seeking Alpha
+```python
+'seeking_alpha': {
+ 'profile': f'/symbols/get-profile?symbols={symbol}',
+ 'news': '/news/list?category=market-news'
+}
+```
+
+### Webull
+```python
+'webull': {
+ 'search': f'/stock/search?keyword={symbol}',
+ 'gainers': '/market/get-active-gainers'
+}
+```
+
+## 🚀 性能优化建议
+
+### 1. API优先级策略
+- **第一优先级**: Alpha Vantage, Webull (< 2s)
+- **第二优先级**: Yahoo Finance 15 (2-3s)
+- **第三优先级**: Seeking Alpha (3-4s)
+
+### 2. 故障转移策略
+- 快速API之间互为备份
+- 避免使用不可用的API作为备份
+- 设置合理的超时时间 (8s)
+
+### 3. 负载均衡
+- 将高频请求分散到不同API
+- 避免单一API过载
+- 监控API使用统计
+
+## 💡 实施建议
+
+1. **更新永动机引擎**: 移除不可用的API配置
+2. **优化八仙分配**: 基于API可用性重新分配
+3. **添加健康检查**: 定期测试API可用性
+4. **监控和告警**: 跟踪API响应时间和成功率
+
+## 📈 预期效果
+
+- **成功率提升**: 从当前的60%提升到95%+
+- **响应时间**: 平均响应时间从3s降低到2s
+- **稳定性**: 减少API调用失败导致的辩论中断
+- **用户体验**: 更快的辩论响应和更稳定的数据获取
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/rapidapi/test_report_20250802_120925.md b/modules/documentation-suite/docs/rapidapi/test_report_20250802_120925.md
new file mode 100644
index 0000000..592bb0b
--- /dev/null
+++ b/modules/documentation-suite/docs/rapidapi/test_report_20250802_120925.md
@@ -0,0 +1,112 @@
+# RapidAPI 测试报告
+
+## 📊 测试概览
+
+- **测试时间**: 2025-08-02 12:09:25
+- **总API数**: 17
+- **成功数**: 4 (23.5%)
+- **失败数**: 13 (76.5%)
+
+## ✅ 可用的API (4个)
+
+### alpha_vantage
+- **主机**: `alpha-vantage.p.rapidapi.com`
+- **响应时间**: 1.26s
+- **数据字段**: Global Quote
+
+### webull
+- **主机**: `webull.p.rapidapi.com`
+- **响应时间**: 1.56s
+- **数据字段**: stocks, busiModel
+
+### yahoo_finance_1
+- **主机**: `yahoo-finance15.p.rapidapi.com`
+- **响应时间**: 2.07s
+- **数据字段**: meta, body
+
+### seeking_alpha
+- **主机**: `seeking-alpha.p.rapidapi.com`
+- **响应时间**: 3.32s
+- **数据字段**: data
+
+## ❌ 失败的API (13个)
+
+### yh_finance_complete
+- **主机**: `yh-finance.p.rapidapi.com`
+- **状态码**: 204
+- **错误**: Unknown...
+
+### yahoo_finance_api_data
+- **主机**: `yahoo-finance-api1.p.rapidapi.com`
+- **状态码**: 403
+- **错误**: {"message":"You are not subscribed to this API."}...
+
+### yahoo_finance_realtime
+- **主机**: `yahoo-finance-low-latency.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"API doesn't exists"}...
+
+### yh_finance
+- **主机**: `yh-finance-complete.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"Endpoint '\/stock\/v2\/get-summary' does not exist"}...
+
+### yahoo_finance_basic
+- **主机**: `yahoo-finance127.p.rapidapi.com`
+- **状态码**: 403
+- **错误**: {"message":"You are not subscribed to this API."}...
+
+### morning_star
+- **主机**: `morningstar1.p.rapidapi.com`
+- **状态码**: 403
+- **错误**: {"message":"You are not subscribed to this API."}...
+
+### tradingview
+- **主机**: `tradingview-ta.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"API doesn't exists"}...
+
+### investing_com
+- **主机**: `investing-cryptocurrency-markets.p.rapidapi.com`
+- **状态码**: 403
+- **错误**: {"message":"You are not subscribed to this API."}...
+
+### finance_api
+- **主机**: `real-time-finance-data.p.rapidapi.com`
+- **状态码**: 403
+- **错误**: {"message":"You are not subscribed to this API."}...
+
+### ms_finance
+- **主机**: `ms-finance.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"Endpoint '\/stock\/v2\/get-summary' does not exist"}...
+
+### sec_filings
+- **主机**: `sec-filings.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"API doesn't exists"}...
+
+### exchangerate_api
+- **主机**: `exchangerate-api.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"Endpoint '\/latest' does not exist"}...
+
+### crypto_news
+- **主机**: `cryptocurrency-news2.p.rapidapi.com`
+- **状态码**: 404
+- **错误**: {"message":"Endpoint '\/v1\/cryptonews' does not exist"}...
+
+## 🔧 优化建议
+
+### 立即可用的API
+以下API响应快速,建议优先使用:
+- **alpha_vantage**: 1.26s
+- **webull**: 1.56s
+
+### 需要修复的API
+以下API需要检查端点配置或权限:
+- **yh_finance_complete**: Unknown error...
+- **yahoo_finance_api_data**: {"message":"You are not subscribed to this API."}...
+- **yahoo_finance_realtime**: {"message":"API doesn't exists"}...
+- **yh_finance**: {"message":"Endpoint '\/stock\/v2\/get-summary' do...
+- **yahoo_finance_basic**: {"message":"You are not subscribed to this API."}...
diff --git a/modules/documentation-suite/docs/requirements.md b/modules/documentation-suite/docs/requirements.md
new file mode 100644
index 0000000..7f2721a
--- /dev/null
+++ b/modules/documentation-suite/docs/requirements.md
@@ -0,0 +1,123 @@
+# 炼妖壶项目清理与重构需求文档
+
+## 介绍
+
+炼妖壶项目经过长期开发,积累了大量代码和配置文件,但项目结构变得混乱,存在安全隐患(密钥泄露)和维护困难。本规范旨在系统性地清理和重构项目,建立清晰的架构和安全的开发流程。
+
+## 需求
+
+### 需求1:项目结构清理
+
+**用户故事:** 作为开发者,我希望项目有清晰的目录结构和文件组织,以便快速理解和维护代码。
+
+#### 验收标准
+
+1. WHEN 查看项目根目录 THEN 应该只包含必要的核心文件和目录
+2. WHEN 查看任何目录 THEN 应该有清晰的README说明其用途
+3. WHEN 寻找特定功能代码 THEN 应该能在预期的目录中找到
+4. WHEN 删除无用文件后 THEN 项目仍能正常运行
+5. IF 文件超过6个月未使用 THEN 应该被归档或删除
+
+### 需求2:安全配置管理
+
+**用户故事:** 作为开发者,我希望所有密钥和敏感配置都安全管理,不会意外泄露到代码库中。
+
+#### 验收标准
+
+1. WHEN 扫描代码库 THEN 不应该发现任何硬编码的密钥或敏感信息
+2. WHEN 开发者需要密钥 THEN 应该从环境变量或Doppler获取
+3. WHEN 提交代码 THEN 应该自动检查是否包含敏感信息
+4. WHEN 新开发者加入 THEN 应该有清晰的密钥管理指南
+5. IF 发现密钥泄露 THEN 应该有自动化的处理流程
+
+### 需求3:核心功能保留
+
+**用户故事:** 作为用户,我希望在项目重构后,所有核心功能(AI辩论、数据分析、Streamlit界面)仍然可用。
+
+#### 验收标准
+
+1. WHEN 启动Streamlit应用 THEN 应该能正常访问所有功能页面
+2. WHEN 运行AI辩论 THEN 应该能正常生成辩论内容
+3. WHEN 连接数据库 THEN 应该能正常读写数据
+4. WHEN 调用外部API THEN 应该能正常获取响应
+5. WHEN 运行测试 THEN 所有核心功能测试应该通过
+
+### 需求4:开发体验优化
+
+**用户故事:** 作为开发者,我希望有良好的开发体验,包括清晰的文档、简单的启动流程和有效的调试工具。
+
+#### 验收标准
+
+1. WHEN 新开发者克隆项目 THEN 应该能在10分钟内启动应用
+2. WHEN 查看文档 THEN 应该能找到所有必要的设置和使用说明
+3. WHEN 遇到问题 THEN 应该有清晰的故障排除指南
+4. WHEN 添加新功能 THEN 应该有明确的开发规范可遵循
+5. WHEN 部署应用 THEN 应该有自动化的部署流程
+
+### 需求5:技术债务清理
+
+**用户故事:** 作为维护者,我希望清理技术债务,移除过时的代码和依赖,提高代码质量。
+
+#### 验收标准
+
+1. WHEN 检查依赖 THEN 不应该有未使用或过时的包
+2. WHEN 运行代码分析 THEN 不应该有严重的代码质量问题
+3. WHEN 查看代码 THEN 应该有一致的编码风格和注释
+4. WHEN 运行性能测试 THEN 应用响应时间应该在可接受范围内
+5. IF 发现重复代码 THEN 应该被重构为可复用的模块
+
+### 需求6:部署和运维简化
+
+**用户故事:** 作为运维人员,我希望部署和监控应用变得简单可靠。
+
+#### 验收标准
+
+1. WHEN 部署到生产环境 THEN 应该使用一键部署脚本
+2. WHEN 应用运行异常 THEN 应该有清晰的日志和监控信息
+3. WHEN 需要扩展 THEN 应该支持水平扩展
+4. WHEN 备份数据 THEN 应该有自动化的备份策略
+5. WHEN 回滚版本 THEN 应该能快速回滚到稳定版本
+
+## 优先级
+
+1. **P0 (紧急)**: 安全配置管理 - 立即解决密钥泄露问题
+2. **P1 (高)**: 项目结构清理 - 建立清晰的项目架构
+3. **P2 (中)**: 核心功能保留 - 确保重构不影响核心功能
+4. **P3 (中)**: 开发体验优化 - 改善开发流程
+5. **P4 (低)**: 技术债务清理 - 长期代码质量改进
+6. **P5 (低)**: 部署和运维简化 - 运维流程优化
+
+## 迁移策略
+
+鉴于当前项目状态混乱,采用**全新开始**的策略:
+
+1. **文档先行** - 完善所有需求和设计文档
+2. **干净迁移** - 在新目录 `/home/ben/liurenchaxin` 重新开始
+3. **选择性迁移** - 只迁移核心功能代码,抛弃历史包袱
+4. **安全优先** - 从一开始就建立安全的配置管理
+
+## 核心功能清单(需要保留)
+
+### 必须迁移的功能
+- 🤖 **稷下学宫AI辩论系统** (八仙辩论)
+- 📊 **Streamlit主界面**
+- 🔗 **Doppler配置管理**
+- 💾 **数据库连接** (PostgreSQL, MongoDB, Zilliz)
+- 🔌 **外部API集成** (OpenRouter, Anthropic等)
+
+### 可选迁移的功能
+- 📈 **金融数据分析**
+- 🔄 **N8N工作流**
+- 📱 **MCP服务器**
+- 🧪 **实验性功能**
+
+## 成功标准
+
+项目重构成功的标志:
+- ✅ 通过GitGuardian安全扫描,无密钥泄露
+- ✅ 项目目录结构清晰,符合最佳实践
+- ✅ 所有核心功能正常工作
+- ✅ 新开发者能在10分钟内启动项目
+- ✅ 代码质量评分达到B级以上
+- ✅ 部署时间缩短到5分钟以内
+- ✅ 完全摆脱历史技术债务
\ No newline at end of file
diff --git a/modules/documentation-suite/docs/vertex_memory_banks.md b/modules/documentation-suite/docs/vertex_memory_banks.md
new file mode 100644
index 0000000..e958b0e
--- /dev/null
+++ b/modules/documentation-suite/docs/vertex_memory_banks.md
@@ -0,0 +1,74 @@
+# 八仙记忆银行文档 (Vertex AI)
+
+每个八仙智能体都有一个专属的记忆银行,用于存储其在不同辩论主题下的记忆。这些记忆包括对话历史、个人偏好、知识库和策略洞察。
+
+## 记忆类型
+
+1. **对话记忆 (conversation)**: 智能体在特定辩论中的发言和互动记录。
+2. **偏好记忆 (preference)**: 智能体的投资偏好、分析方法和决策倾向。
+3. **知识记忆 (knowledge)**: 智能体掌握的金融知识、市场信息和分析模型。
+4. **策略记忆 (strategy)**: 智能体在辩论中使用的论证策略和战术。
+
+## 八仙记忆银行列表
+
+- **铁拐李 (tieguaili)**
+ - ID: `memory_bank_tieguaili_{PROJECT_ID}`
+ - 特点: 擅长技术分析和风险控制
+
+- **汉钟离 (hanzhongli)**
+ - ID: `memory_bank_hanzhongli_{PROJECT_ID}`
+ - 特点: 注重基本面分析和长期价值
+
+- **张果老 (zhangguolao)**
+ - ID: `memory_bank_zhangguolao_{PROJECT_ID}`
+ - 特点: 擅长宏观趋势分析和周期判断
+
+- **蓝采和 (lancaihe)**
+ - ID: `memory_bank_lancaihe_{PROJECT_ID}`
+ - 特点: 关注市场情绪和资金流向
+
+- **何仙姑 (hexiangu)**
+ - ID: `memory_bank_hexiangu_{PROJECT_ID}`
+ - 特点: 精于财务数据分析和估值模型
+
+- **吕洞宾 (lvdongbin)**
+ - ID: `memory_bank_lvdongbin_{PROJECT_ID}`
+ - 特点: 善于多维度综合分析和创新策略
+
+- **韩湘子 (hanxiangzi)**
+ - ID: `memory_bank_hanxiangzi_{PROJECT_ID}`
+ - 特点: 擅长行业比较和相对价值分析
+
+- **曹国舅 (caoguojiu)**
+ - ID: `memory_bank_caoguojiu_{PROJECT_ID}`
+ - 特点: 注重合规性、社会责任和ESG因素
+
+## 使用方法
+
+```python
+from src.jixia.memory.factory import get_memory_backend
+
+# 获取记忆后端 (自动根据环境变量选择)
+memory_bank = get_memory_backend()
+
+# 为吕洞宾添加偏好记忆
+await memory_bank.add_memory(
+ agent_name="lvdongbin",
+ content="倾向于使用DCF模型评估科技股的内在价值",
+ memory_type="preference",
+ debate_topic="TSLA投资分析"
+)
+
+# 搜索吕洞宾关于TSLA的记忆
+memories = await memory_bank.search_memories(
+ agent_name="lvdongbin",
+ query="TSLA",
+ memory_type="preference"
+)
+
+# 获取上下文
+context = await memory_bank.get_agent_context("lvdongbin", "TSLA投资分析")
+```
+
+---
+*此文档由系统自动生成和维护*
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/data/demo_results_aapl.json b/modules/documentation-suite/examples/data/demo_results_aapl.json
new file mode 100644
index 0000000..692f02f
--- /dev/null
+++ b/modules/documentation-suite/examples/data/demo_results_aapl.json
@@ -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
+ }
+}
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/data/demo_results_msft.json b/modules/documentation-suite/examples/data/demo_results_msft.json
new file mode 100644
index 0000000..a8a531c
--- /dev/null
+++ b/modules/documentation-suite/examples/data/demo_results_msft.json
@@ -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
+ }
+}
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/data/demo_results_tsla.json b/modules/documentation-suite/examples/data/demo_results_tsla.json
new file mode 100644
index 0000000..2285d7b
--- /dev/null
+++ b/modules/documentation-suite/examples/data/demo_results_tsla.json
@@ -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
+ }
+}
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/debates/adk_debate_example.py b/modules/documentation-suite/examples/debates/adk_debate_example.py
new file mode 100644
index 0000000..03c5c70
--- /dev/null
+++ b/modules/documentation-suite/examples/debates/adk_debate_example.py
@@ -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()
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/debates/baxian_adk_gemini_debate.py b/modules/documentation-suite/examples/debates/baxian_adk_gemini_debate.py
new file mode 100644
index 0000000..b5e4eb2
--- /dev/null
+++ b/modules/documentation-suite/examples/debates/baxian_adk_gemini_debate.py
@@ -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())
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/debates/outputs/debates/baxian_debate_20250822_105818.json b/modules/documentation-suite/examples/debates/outputs/debates/baxian_debate_20250822_105818.json
new file mode 100644
index 0000000..2e3992b
--- /dev/null
+++ b/modules/documentation-suite/examples/debates/outputs/debates/baxian_debate_20250822_105818.json
@@ -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"
+}
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/debates/swarm_debate_example.py b/modules/documentation-suite/examples/debates/swarm_debate_example.py
new file mode 100644
index 0000000..25e388d
--- /dev/null
+++ b/modules/documentation-suite/examples/debates/swarm_debate_example.py
@@ -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())
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/demo_jixia_load_balancing.py b/modules/documentation-suite/examples/demo_jixia_load_balancing.py
new file mode 100644
index 0000000..2234cba
--- /dev/null
+++ b/modules/documentation-suite/examples/demo_jixia_load_balancing.py
@@ -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()
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/memory_bank_demo.py b/modules/documentation-suite/examples/memory_bank_demo.py
new file mode 100644
index 0000000..da1b405
--- /dev/null
+++ b/modules/documentation-suite/examples/memory_bank_demo.py
@@ -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())
\ No newline at end of file
diff --git a/modules/documentation-suite/examples/mongodb_swarm_example.py b/modules/documentation-suite/examples/mongodb_swarm_example.py
new file mode 100644
index 0000000..3b355d5
--- /dev/null
+++ b/modules/documentation-suite/examples/mongodb_swarm_example.py
@@ -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()
\ No newline at end of file
diff --git a/modules/legacy-support/AGENT_COLLABORATION_README.md b/modules/legacy-support/AGENT_COLLABORATION_README.md
new file mode 100644
index 0000000..6d7de0a
--- /dev/null
+++ b/modules/legacy-support/AGENT_COLLABORATION_README.md
@@ -0,0 +1,139 @@
+# AI Agent Git Collaboration Framework
+
+一个革命性的多AI Agent协作框架,让每个Agent都能以真实身份参与Git协作,实现真正的"实盘操作"而非"模拟盘"。
+
+## 🎯 核心理念
+
+> **从模拟到真实**:不是让Agent假装协作,而是让每个Agent都有真实的Git身份、SSH密钥和提交历史。
+
+## 🚀 特性
+
+### 🔐 真实身份系统
+- 每个Agent拥有独立的SSH密钥对
+- 独立的GPG签名密钥(可选)
+- 独立的Git配置(用户名、邮箱)
+- 可追溯的提交历史
+
+### 🤖 多Agent角色
+- **架构师 (claude-ai)**: 系统设计和技术选型
+- **开发者 (gemini-dev)**: 核心功能开发
+- **运维 (qwen-ops)**: 部署和运维脚本
+- **研究员 (llama-research)**: 性能分析和优化
+
+### 📊 协作追踪
+- 实时Agent切换
+- 提交统计和分析
+- 代码审查历史
+- 性能指标监控
+
+## 📦 快速开始
+
+### 1. 安装
+```bash
+git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+./setup_agents.sh
+```
+
+### 2. 配置Agent身份
+```bash
+# 查看所有Agent
+./agents/stats.sh
+
+# 切换到特定Agent
+./agents/switch_agent.sh claude-ai
+
+# 以Agent身份提交
+git commit -m "架构设计更新" --author="claude-ai "
+```
+
+### 3. 多Agent协作演示
+```bash
+python3 agents/demo_collaboration.py
+```
+
+## 🏗️ 架构设计
+
+### 身份管理系统 (`agents/identity_manager.py`)
+- Agent身份注册和管理
+- SSH密钥生成和配置
+- Git环境切换
+
+### 协作工作流 (`agents/demo_collaboration.py`)
+- 模拟真实团队协作
+- 角色分工明确
+- 代码贡献追踪
+
+### 工具脚本集
+- `switch_agent.sh`: 快速切换Agent身份
+- `commit_as_agent.sh`: 以指定Agent身份提交
+- `stats.sh`: 查看Agent协作统计
+
+## 🔧 使用场景
+
+### 1. 个人项目增强
+- 模拟团队协作
+- 代码审查练习
+- 架构设计验证
+
+### 2. 教学演示
+- Git协作教学
+- 代码审查培训
+- 敏捷开发实践
+
+### 3. 企业级应用
+- AI辅助代码审查
+- 自动化文档生成
+- 多角色代码分析
+
+## 📈 路线图
+
+### Phase 1: 核心功能 ✅
+- [x] 多Agent身份管理
+- [x] Git协作演示
+- [x] 基础工具脚本
+
+### Phase 2: 增强协作
+- [ ] Web界面管理
+- [ ] 实时协作监控
+- [ ] 代码质量分析
+
+### Phase 3: 企业级
+- [ ] 权限管理系统
+- [ ] 审计日志
+- [ ] 集成CI/CD
+
+## 🤝 贡献指南
+
+我们欢迎所有形式的贡献!
+
+### 开发环境
+```bash
+pip install -r requirements.txt
+./setup_agents.sh
+```
+
+### 添加新Agent角色
+1. 编辑 `agents/identities.json`
+2. 生成SSH密钥对
+3. 更新演示脚本
+
+## 📄 许可证
+
+MIT License - 详见 [LICENSE](LICENSE)
+
+## 🌟 Star历史
+
+[](https://star-history.com/#your-org/agent-collaboration-framework&Date)
+
+## 💡 灵感来源
+
+> "为什么不让每个AI Agent都有真实的Git身份?这样我们就能从模拟协作转向真正的实盘操作。"
+
+这个项目源于对AI协作本质的思考:**真实性胜过模拟**。
+
+---
+
+**从模拟到真实,从工具到伙伴。**
+
+🚀 **Ready to revolutionize AI collaboration?**
\ No newline at end of file
diff --git a/AI_COLLABORATION_INVITATION.md b/modules/legacy-support/AI_COLLABORATION_INVITATION.md
similarity index 100%
rename from AI_COLLABORATION_INVITATION.md
rename to modules/legacy-support/AI_COLLABORATION_INVITATION.md
diff --git a/AI_DEVELOPER_GUIDELINES.md b/modules/legacy-support/AI_DEVELOPER_GUIDELINES.md
similarity index 100%
rename from AI_DEVELOPER_GUIDELINES.md
rename to modules/legacy-support/AI_DEVELOPER_GUIDELINES.md
diff --git a/AI_INVITATION_MESSAGE.md b/modules/legacy-support/AI_INVITATION_MESSAGE.md
similarity index 100%
rename from AI_INVITATION_MESSAGE.md
rename to modules/legacy-support/AI_INVITATION_MESSAGE.md
diff --git a/AI_QUICK_GUIDE.py b/modules/legacy-support/AI_QUICK_GUIDE.py
similarity index 100%
rename from AI_QUICK_GUIDE.py
rename to modules/legacy-support/AI_QUICK_GUIDE.py
diff --git a/CLAUDE.md b/modules/legacy-support/CLAUDE.md
similarity index 100%
rename from CLAUDE.md
rename to modules/legacy-support/CLAUDE.md
diff --git a/CONTRIBUTING.md b/modules/legacy-support/CONTRIBUTING.md
similarity index 100%
rename from CONTRIBUTING.md
rename to modules/legacy-support/CONTRIBUTING.md
diff --git a/GEMINI.md b/modules/legacy-support/GEMINI.md
similarity index 100%
rename from GEMINI.md
rename to modules/legacy-support/GEMINI.md
diff --git a/modules/legacy-support/MIGRATION_GUIDE.md b/modules/legacy-support/MIGRATION_GUIDE.md
new file mode 100644
index 0000000..9b2bff7
--- /dev/null
+++ b/modules/legacy-support/MIGRATION_GUIDE.md
@@ -0,0 +1,136 @@
+# 🔄 项目迁移指南
+
+## 📋 从稷下学宫到AI Agent协作框架
+
+本项目已经从一个专注于中国哲学辩论的AI系统,**转型**为一个革命性的**AI Agent协作框架**,让每个AI Agent都能拥有真实的Git身份进行协作。
+
+## 🎯 转型原因
+
+### 原项目特点
+- 专注于中国哲学辩论系统
+- 基于八仙文化的特定场景
+- 复杂的资本分析模型
+
+### 新愿景优势
+- **通用性更强**:适用于任何需要AI协作的场景
+- **技术价值更高**:解决了AI Agent真实身份协作的核心问题
+- **开源价值更大**:为整个AI社区提供基础框架
+- **实用性更强**:可直接应用于实际项目开发
+
+## 🚀 迁移步骤
+
+### 1. 理解新概念
+
+| 原概念 | 新概念 | 说明 |
+|--------|--------|------|
+| 八仙辩论 | 多Agent协作 | 从特定角色到通用身份 |
+| 资本分析 | Git协作 | 从金融到软件开发 |
+| 哲学辩论 | 团队开发 | 从理论到实践 |
+
+### 2. 快速上手新框架
+
+```bash
+# 1. 确认当前环境
+git status
+
+# 2. 运行新框架演示
+python3 examples/basic/demo_collaboration.py
+
+# 3. 体验Agent身份切换
+./agents/switch_agent.sh claude-ai
+./agents/stats.sh
+```
+
+### 3. 保留的价值
+
+虽然主题转变,但以下核心价值得到保留:
+- ✅ **多Agent系统设计经验**
+- ✅ **身份管理和权限控制**
+- ✅ **协作工作流设计**
+- ✅ **开源项目最佳实践**
+
+## 🎭 原功能映射
+
+### 原八仙角色 → 新Agent角色
+- **吕洞宾** → `claude-ai` (架构师)
+- **何仙姑** → `gemini-dev` (开发者)
+- **张果老** → `qwen-ops` (运维)
+- **铁拐李** → `llama-research` (研究员)
+
+### 原辩论流程 → 新协作流程
+- 哲学讨论 → 代码审查
+- 观点碰撞 → 技术方案讨论
+- 历史分析 → 性能优化
+
+## 🔧 技术迁移
+
+### 配置迁移
+```bash
+# 原配置文件路径
+config/settings.py → agents/configs/
+
+# 新的配置方式
+./agents/configure_remote.sh github your-username your-repo
+```
+
+### 数据迁移
+- 原资本数据 → 新的代码仓库
+- 历史记录 → Git提交历史
+- 分析结果 → 代码质量报告
+
+## 📊 价值提升
+
+### 对个人开发者
+- 学习团队协作最佳实践
+- 模拟真实项目开发流程
+- 提升代码管理能力
+
+### 对企业团队
+- AI辅助代码审查
+- 多角色开发模拟
+- 培训新员工协作技能
+
+### 对教育领域
+- Git协作教学工具
+- 敏捷开发实践平台
+- 代码审查培训系统
+
+## 🌟 未来展望
+
+### 即将推出
+- [ ] Web界面管理
+- [ ] 实时协作监控
+- [ ] 代码质量分析
+- [ ] 企业级权限管理
+
+### 社区发展
+- 开源项目协作
+- 技术社区贡献
+- 最佳实践分享
+
+## 🤝 如何参与
+
+### 作为用户
+1. 体验新框架功能
+2. 提供使用反馈
+3. 分享使用案例
+
+### 作为贡献者
+1. 提交Issue报告
+2. 贡献代码改进
+3. 完善文档说明
+
+### 作为推广者
+1. 分享给技术社区
+2. 撰写使用教程
+3. 组织技术分享
+
+## 📞 支持渠道
+
+- **GitHub Issues**: 报告问题和建议
+- **Discussions**: 社区讨论和经验分享
+- **文档**: 完整的迁移和使用指南
+
+---
+
+**🎯 从哲学思辨到技术实践,从个人项目到团队协作,让我们一起构建AI协作的未来!**
\ No newline at end of file
diff --git a/QUICK_START_FOR_AI.md b/modules/legacy-support/QUICK_START_FOR_AI.md
similarity index 100%
rename from QUICK_START_FOR_AI.md
rename to modules/legacy-support/QUICK_START_FOR_AI.md
diff --git a/QWEN.md b/modules/legacy-support/QWEN.md
similarity index 100%
rename from QWEN.md
rename to modules/legacy-support/QWEN.md
diff --git a/modules/legacy-support/SETUP.md b/modules/legacy-support/SETUP.md
new file mode 100644
index 0000000..0f7f604
--- /dev/null
+++ b/modules/legacy-support/SETUP.md
@@ -0,0 +1,157 @@
+# AI Agent Collaboration Framework - 安装指南
+
+## 🚀 快速安装
+
+### 一键安装
+```bash
+curl -fsSL https://raw.githubusercontent.com/your-org/agent-collaboration-framework/main/install.sh | bash
+```
+
+### 手动安装
+
+#### 1. 克隆项目
+```bash
+git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+```
+
+#### 2. 运行安装脚本
+```bash
+chmod +x install.sh
+./install.sh
+```
+
+#### 3. 验证安装
+```bash
+./agents/stats.sh
+```
+
+## 📋 系统要求
+
+### 必需组件
+- Python 3.8+
+- Git 2.20+
+- OpenSSH
+
+### 可选组件
+- GPG (用于代码签名)
+- Node.js (用于Web界面)
+- Docker (用于容器化部署)
+
+## 🔧 配置步骤
+
+### 1. 初始化Agent
+```bash
+./setup_agents.sh
+```
+
+### 2. 配置Git远程仓库
+```bash
+# 添加你的GitHub仓库
+./agents/configure_remote.sh github your-username your-repo
+
+# 添加Gitea仓库
+./agents/configure_remote.sh gitea your-gitea-instance your-repo
+```
+
+### 3. 测试Agent身份
+```bash
+# 查看当前Agent
+./agents/switch_agent.sh claude-ai
+git config user.name # 应该显示 "claude-ai"
+
+# 切换Agent
+./agents/switch_agent.sh gemini-dev
+git config user.name # 应该显示 "gemini-dev"
+```
+
+## 🎯 使用示例
+
+### 基本使用
+```bash
+# 启动协作演示
+python3 agents/demo_collaboration.py
+
+# 手动协作流程
+./agents/switch_agent.sh claude-ai
+echo "# 架构设计" > docs/arch.md
+git add docs/arch.md
+git commit -m "添加架构设计" --author="claude-ai "
+
+./agents/switch_agent.sh gemini-dev
+echo "console.log('Hello');" > src/app.js
+git add src/app.js
+git commit -m "添加应用代码" --author="gemini-dev "
+```
+
+### 高级用法
+```bash
+# 批量Agent操作
+./scripts/bulk_commit.sh "更新文档" --agents="claude-ai,llama-research"
+
+# 代码审查模式
+./scripts/review_mode.sh
+
+# 性能分析
+./scripts/analyze_contributions.sh
+```
+
+## 🐳 Docker安装
+
+### 使用Docker Compose
+```bash
+docker-compose up -d
+```
+
+### 构建镜像
+```bash
+docker build -t agent-collaboration .
+docker run -it agent-collaboration
+```
+
+## 🔍 故障排除
+
+### 常见问题
+
+#### GPG签名失败
+```bash
+# 禁用GPG签名
+git config --global commit.gpgsign false
+```
+
+#### SSH密钥问题
+```bash
+# 重新生成SSH密钥
+./scripts/regenerate_keys.sh
+```
+
+#### 权限问题
+```bash
+# 修复文件权限
+chmod +x agents/*.sh
+```
+
+## 📊 验证安装
+
+运行测试套件:
+```bash
+python3 -m pytest tests/
+```
+
+查看Agent状态:
+```bash
+./agents/stats.sh --verbose
+```
+
+## 🎉 下一步
+
+安装完成后,建议:
+1. 运行演示项目
+2. 阅读 [快速开始指南](QUICK_START.md)
+3. 查看 [贡献指南](CONTRIBUTING.md)
+
+## 💡 提示
+
+- 使用 `./agents/help.sh` 获取帮助
+- 查看示例项目 `examples/` 目录
+- 加入社区讨论 [Discussions](https://github.com/your-org/agent-collaboration-framework/discussions)
\ No newline at end of file
diff --git a/VERSION b/modules/legacy-support/VERSION
similarity index 100%
rename from VERSION
rename to modules/legacy-support/VERSION
diff --git a/data/debate_state.json b/modules/legacy-support/data/debate_state.json
similarity index 100%
rename from data/debate_state.json
rename to modules/legacy-support/data/debate_state.json
diff --git a/data/test_flow_data.json b/modules/legacy-support/data/test_flow_data.json
similarity index 100%
rename from data/test_flow_data.json
rename to modules/legacy-support/data/test_flow_data.json
diff --git a/data/tournament_models.txt b/modules/legacy-support/data/tournament_models.txt
similarity index 100%
rename from data/tournament_models.txt
rename to modules/legacy-support/data/tournament_models.txt
diff --git a/diagnose_trae.sh b/modules/legacy-support/diagnose_trae.sh
similarity index 100%
rename from diagnose_trae.sh
rename to modules/legacy-support/diagnose_trae.sh
diff --git a/engines/celestial_map.py b/modules/legacy-support/engines/celestial_map.py
similarity index 100%
rename from engines/celestial_map.py
rename to modules/legacy-support/engines/celestial_map.py
diff --git a/engines/cycle_models.py b/modules/legacy-support/engines/cycle_models.py
similarity index 100%
rename from engines/cycle_models.py
rename to modules/legacy-support/engines/cycle_models.py
diff --git a/engines/market_fsm.py b/modules/legacy-support/engines/market_fsm.py
similarity index 100%
rename from engines/market_fsm.py
rename to modules/legacy-support/engines/market_fsm.py
diff --git a/engines/monster_stock_scanner.py b/modules/legacy-support/engines/monster_stock_scanner.py
similarity index 100%
rename from engines/monster_stock_scanner.py
rename to modules/legacy-support/engines/monster_stock_scanner.py
diff --git a/engines/mythology.py b/modules/legacy-support/engines/mythology.py
similarity index 100%
rename from engines/mythology.py
rename to modules/legacy-support/engines/mythology.py
diff --git a/enhanced_multi_chat_coordinator.py b/modules/legacy-support/enhanced_multi_chat_coordinator.py
similarity index 100%
rename from enhanced_multi_chat_coordinator.py
rename to modules/legacy-support/enhanced_multi_chat_coordinator.py
diff --git a/experiments/baxian_breakdown_debate.py b/modules/legacy-support/experiments/baxian_breakdown_debate.py
similarity index 100%
rename from experiments/baxian_breakdown_debate.py
rename to modules/legacy-support/experiments/baxian_breakdown_debate.py
diff --git a/experiments/baxian_custom_api_debate.py b/modules/legacy-support/experiments/baxian_custom_api_debate.py
similarity index 100%
rename from experiments/baxian_custom_api_debate.py
rename to modules/legacy-support/experiments/baxian_custom_api_debate.py
diff --git a/experiments/data/free_models.json b/modules/legacy-support/experiments/data/free_models.json
similarity index 100%
rename from experiments/data/free_models.json
rename to modules/legacy-support/experiments/data/free_models.json
diff --git a/experiments/data/memories.json b/modules/legacy-support/experiments/data/memories.json
similarity index 100%
rename from experiments/data/memories.json
rename to modules/legacy-support/experiments/data/memories.json
diff --git a/experiments/data/qczh_debate_state.json b/modules/legacy-support/experiments/data/qczh_debate_state.json
similarity index 100%
rename from experiments/data/qczh_debate_state.json
rename to modules/legacy-support/experiments/data/qczh_debate_state.json
diff --git a/experiments/v2_1_comprehensive_test_report.json b/modules/legacy-support/experiments/v2_1_comprehensive_test_report.json
similarity index 100%
rename from experiments/v2_1_comprehensive_test_report.json
rename to modules/legacy-support/experiments/v2_1_comprehensive_test_report.json
diff --git a/internal/README.md b/modules/legacy-support/internal/README.md
similarity index 100%
rename from internal/README.md
rename to modules/legacy-support/internal/README.md
diff --git a/internal/analysis/AI_Agent_Fandom_Culture_System.md b/modules/legacy-support/internal/analysis/AI_Agent_Fandom_Culture_System.md
similarity index 100%
rename from internal/analysis/AI_Agent_Fandom_Culture_System.md
rename to modules/legacy-support/internal/analysis/AI_Agent_Fandom_Culture_System.md
diff --git a/internal/analysis/AI_Virtual_Idol_Livestream_Empire.md b/modules/legacy-support/internal/analysis/AI_Virtual_Idol_Livestream_Empire.md
similarity index 100%
rename from internal/analysis/AI_Virtual_Idol_Livestream_Empire.md
rename to modules/legacy-support/internal/analysis/AI_Virtual_Idol_Livestream_Empire.md
diff --git a/internal/analysis/Cognitive_Computing_Models_Deep_Analysis.md b/modules/legacy-support/internal/analysis/Cognitive_Computing_Models_Deep_Analysis.md
similarity index 100%
rename from internal/analysis/Cognitive_Computing_Models_Deep_Analysis.md
rename to modules/legacy-support/internal/analysis/Cognitive_Computing_Models_Deep_Analysis.md
diff --git a/internal/analysis/KAG_Deep_Analysis_Report.md b/modules/legacy-support/internal/analysis/KAG_Deep_Analysis_Report.md
similarity index 100%
rename from internal/analysis/KAG_Deep_Analysis_Report.md
rename to modules/legacy-support/internal/analysis/KAG_Deep_Analysis_Report.md
diff --git a/internal/analysis/Mistral_Cognitive_Architecture_Analysis.md b/modules/legacy-support/internal/analysis/Mistral_Cognitive_Architecture_Analysis.md
similarity index 100%
rename from internal/analysis/Mistral_Cognitive_Architecture_Analysis.md
rename to modules/legacy-support/internal/analysis/Mistral_Cognitive_Architecture_Analysis.md
diff --git a/internal/analysis/Mistral_KAG_Resource_Configuration_Guide.md b/modules/legacy-support/internal/analysis/Mistral_KAG_Resource_Configuration_Guide.md
similarity index 100%
rename from internal/analysis/Mistral_KAG_Resource_Configuration_Guide.md
rename to modules/legacy-support/internal/analysis/Mistral_KAG_Resource_Configuration_Guide.md
diff --git a/internal/analysis/MongoDB_to_Milvus_Fix.md b/modules/legacy-support/internal/analysis/MongoDB_to_Milvus_Fix.md
similarity index 100%
rename from internal/analysis/MongoDB_to_Milvus_Fix.md
rename to modules/legacy-support/internal/analysis/MongoDB_to_Milvus_Fix.md
diff --git a/internal/analysis/kag_ecosystem_analysis.md b/modules/legacy-support/internal/analysis/kag_ecosystem_analysis.md
similarity index 100%
rename from internal/analysis/kag_ecosystem_analysis.md
rename to modules/legacy-support/internal/analysis/kag_ecosystem_analysis.md
diff --git a/internal/analysis/openmanus_integration_strategies.md b/modules/legacy-support/internal/analysis/openmanus_integration_strategies.md
similarity index 100%
rename from internal/analysis/openmanus_integration_strategies.md
rename to modules/legacy-support/internal/analysis/openmanus_integration_strategies.md
diff --git a/internal/analysis/rapidapi_mcp_analysis.md b/modules/legacy-support/internal/analysis/rapidapi_mcp_analysis.md
similarity index 100%
rename from internal/analysis/rapidapi_mcp_analysis.md
rename to modules/legacy-support/internal/analysis/rapidapi_mcp_analysis.md
diff --git a/internal/analysis/rapidapi_pool_analysis.md b/modules/legacy-support/internal/analysis/rapidapi_pool_analysis.md
similarity index 100%
rename from internal/analysis/rapidapi_pool_analysis.md
rename to modules/legacy-support/internal/analysis/rapidapi_pool_analysis.md
diff --git a/internal/analysis/rapidapi_subscription_report.md b/modules/legacy-support/internal/analysis/rapidapi_subscription_report.md
similarity index 100%
rename from internal/analysis/rapidapi_subscription_report.md
rename to modules/legacy-support/internal/analysis/rapidapi_subscription_report.md
diff --git a/internal/archive/historical_analysis/Force_Anti_Monologue_Techniques.md b/modules/legacy-support/internal/archive/historical_analysis/Force_Anti_Monologue_Techniques.md
similarity index 100%
rename from internal/archive/historical_analysis/Force_Anti_Monologue_Techniques.md
rename to modules/legacy-support/internal/archive/historical_analysis/Force_Anti_Monologue_Techniques.md
diff --git a/internal/archive/historical_analysis/earlycall.md b/modules/legacy-support/internal/archive/historical_analysis/earlycall.md
similarity index 100%
rename from internal/archive/historical_analysis/earlycall.md
rename to modules/legacy-support/internal/archive/historical_analysis/earlycall.md
diff --git a/internal/archive/historical_analysis/gemini.md b/modules/legacy-support/internal/archive/historical_analysis/gemini.md
similarity index 100%
rename from internal/archive/historical_analysis/gemini.md
rename to modules/legacy-support/internal/archive/historical_analysis/gemini.md
diff --git a/internal/archive/historical_analysis/index_professional.md b/modules/legacy-support/internal/archive/historical_analysis/index_professional.md
similarity index 100%
rename from internal/archive/historical_analysis/index_professional.md
rename to modules/legacy-support/internal/archive/historical_analysis/index_professional.md
diff --git a/internal/archive/historical_analysis/tianxia.md b/modules/legacy-support/internal/archive/historical_analysis/tianxia.md
similarity index 100%
rename from internal/archive/historical_analysis/tianxia.md
rename to modules/legacy-support/internal/archive/historical_analysis/tianxia.md
diff --git a/internal/core/baxian_sanqing_system_guide.md b/modules/legacy-support/internal/core/baxian_sanqing_system_guide.md
similarity index 100%
rename from internal/core/baxian_sanqing_system_guide.md
rename to modules/legacy-support/internal/core/baxian_sanqing_system_guide.md
diff --git a/internal/core/fsm.md b/modules/legacy-support/internal/core/fsm.md
similarity index 100%
rename from internal/core/fsm.md
rename to modules/legacy-support/internal/core/fsm.md
diff --git a/internal/core/fsm_analysis.md b/modules/legacy-support/internal/core/fsm_analysis.md
similarity index 100%
rename from internal/core/fsm_analysis.md
rename to modules/legacy-support/internal/core/fsm_analysis.md
diff --git a/internal/development/comprehensive_development_plan.md b/modules/legacy-support/internal/development/comprehensive_development_plan.md
similarity index 100%
rename from internal/development/comprehensive_development_plan.md
rename to modules/legacy-support/internal/development/comprehensive_development_plan.md
diff --git a/internal/development/comprehensive_plan.md b/modules/legacy-support/internal/development/comprehensive_plan.md
similarity index 100%
rename from internal/development/comprehensive_plan.md
rename to modules/legacy-support/internal/development/comprehensive_plan.md
diff --git a/internal/development/execution_plan_v2.0.0.md b/modules/legacy-support/internal/development/execution_plan_v2.0.0.md
similarity index 100%
rename from internal/development/execution_plan_v2.0.0.md
rename to modules/legacy-support/internal/development/execution_plan_v2.0.0.md
diff --git a/internal/docs/DEPENDENCY_ANALYSIS.md b/modules/legacy-support/internal/docs/DEPENDENCY_ANALYSIS.md
similarity index 100%
rename from internal/docs/DEPENDENCY_ANALYSIS.md
rename to modules/legacy-support/internal/docs/DEPENDENCY_ANALYSIS.md
diff --git a/internal/docs/GAMEFI_SYSTEM_SUMMARY.md b/modules/legacy-support/internal/docs/GAMEFI_SYSTEM_SUMMARY.md
similarity index 100%
rename from internal/docs/GAMEFI_SYSTEM_SUMMARY.md
rename to modules/legacy-support/internal/docs/GAMEFI_SYSTEM_SUMMARY.md
diff --git a/internal/docs/RFC-FSRP-Draft.md b/modules/legacy-support/internal/docs/RFC-FSRP-Draft.md
similarity index 100%
rename from internal/docs/RFC-FSRP-Draft.md
rename to modules/legacy-support/internal/docs/RFC-FSRP-Draft.md
diff --git a/internal/docs/UV_MIGRATION_ANALYSIS.md b/modules/legacy-support/internal/docs/UV_MIGRATION_ANALYSIS.md
similarity index 100%
rename from internal/docs/UV_MIGRATION_ANALYSIS.md
rename to modules/legacy-support/internal/docs/UV_MIGRATION_ANALYSIS.md
diff --git a/internal/docs/WHY_UV_MIGRATION.md b/modules/legacy-support/internal/docs/WHY_UV_MIGRATION.md
similarity index 100%
rename from internal/docs/WHY_UV_MIGRATION.md
rename to modules/legacy-support/internal/docs/WHY_UV_MIGRATION.md
diff --git a/internal/docs/doppler_migration_summary.md b/modules/legacy-support/internal/docs/doppler_migration_summary.md
similarity index 100%
rename from internal/docs/doppler_migration_summary.md
rename to modules/legacy-support/internal/docs/doppler_migration_summary.md
diff --git a/internal/docs/gamefi.md b/modules/legacy-support/internal/docs/gamefi.md
similarity index 100%
rename from internal/docs/gamefi.md
rename to modules/legacy-support/internal/docs/gamefi.md
diff --git a/internal/docs/ib_fundamentals_guide.md b/modules/legacy-support/internal/docs/ib_fundamentals_guide.md
similarity index 100%
rename from internal/docs/ib_fundamentals_guide.md
rename to modules/legacy-support/internal/docs/ib_fundamentals_guide.md
diff --git a/internal/docs/lingbao_n8n_integration.md b/modules/legacy-support/internal/docs/lingbao_n8n_integration.md
similarity index 100%
rename from internal/docs/lingbao_n8n_integration.md
rename to modules/legacy-support/internal/docs/lingbao_n8n_integration.md
diff --git a/internal/docs/openhands_integration_guide.md b/modules/legacy-support/internal/docs/openhands_integration_guide.md
similarity index 100%
rename from internal/docs/openhands_integration_guide.md
rename to modules/legacy-support/internal/docs/openhands_integration_guide.md
diff --git a/internal/mcp/MCP_Driven_User_Acquisition_Funnel.md b/modules/legacy-support/internal/mcp/MCP_Driven_User_Acquisition_Funnel.md
similarity index 100%
rename from internal/mcp/MCP_Driven_User_Acquisition_Funnel.md
rename to modules/legacy-support/internal/mcp/MCP_Driven_User_Acquisition_Funnel.md
diff --git a/internal/mcp/MCP_MANAGEMENT_SOLUTION.md b/modules/legacy-support/internal/mcp/MCP_MANAGEMENT_SOLUTION.md
similarity index 100%
rename from internal/mcp/MCP_MANAGEMENT_SOLUTION.md
rename to modules/legacy-support/internal/mcp/MCP_MANAGEMENT_SOLUTION.md
diff --git a/internal/mcp/mcp_manager_complete_package.zip.md b/modules/legacy-support/internal/mcp/mcp_manager_complete_package.zip.md
similarity index 100%
rename from internal/mcp/mcp_manager_complete_package.zip.md
rename to modules/legacy-support/internal/mcp/mcp_manager_complete_package.zip.md
diff --git a/internal/mcp/mcp_manager_package.tar.md b/modules/legacy-support/internal/mcp/mcp_manager_package.tar.md
similarity index 100%
rename from internal/mcp/mcp_manager_package.tar.md
rename to modules/legacy-support/internal/mcp/mcp_manager_package.tar.md
diff --git a/internal/mcp/n8n_auth_fix_guide.md b/modules/legacy-support/internal/mcp/n8n_auth_fix_guide.md
similarity index 100%
rename from internal/mcp/n8n_auth_fix_guide.md
rename to modules/legacy-support/internal/mcp/n8n_auth_fix_guide.md
diff --git a/internal/migration/comprehensive_cleanup_summary.md b/modules/legacy-support/internal/migration/comprehensive_cleanup_summary.md
similarity index 100%
rename from internal/migration/comprehensive_cleanup_summary.md
rename to modules/legacy-support/internal/migration/comprehensive_cleanup_summary.md
diff --git a/internal/migration/rfc_taigong_xinyi_fsm_enhancements.md b/modules/legacy-support/internal/migration/rfc_taigong_xinyi_fsm_enhancements.md
similarity index 100%
rename from internal/migration/rfc_taigong_xinyi_fsm_enhancements.md
rename to modules/legacy-support/internal/migration/rfc_taigong_xinyi_fsm_enhancements.md
diff --git a/internal/setup/CLAUDE_ACTION_SETUP.md b/modules/legacy-support/internal/setup/CLAUDE_ACTION_SETUP.md
similarity index 100%
rename from internal/setup/CLAUDE_ACTION_SETUP.md
rename to modules/legacy-support/internal/setup/CLAUDE_ACTION_SETUP.md
diff --git a/internal/setup/doppler-migration-guide.md b/modules/legacy-support/internal/setup/doppler-migration-guide.md
similarity index 100%
rename from internal/setup/doppler-migration-guide.md
rename to modules/legacy-support/internal/setup/doppler-migration-guide.md
diff --git a/internal/setup/env_standardization_plan.md b/modules/legacy-support/internal/setup/env_standardization_plan.md
similarity index 100%
rename from internal/setup/env_standardization_plan.md
rename to modules/legacy-support/internal/setup/env_standardization_plan.md
diff --git a/internal/strategies/platform_avatar_strategy.md b/modules/legacy-support/internal/strategies/platform_avatar_strategy.md
similarity index 100%
rename from internal/strategies/platform_avatar_strategy.md
rename to modules/legacy-support/internal/strategies/platform_avatar_strategy.md
diff --git a/internal/technical/Anti_Reasoning_Monologue_Solution.md b/modules/legacy-support/internal/technical/Anti_Reasoning_Monologue_Solution.md
similarity index 100%
rename from internal/technical/Anti_Reasoning_Monologue_Solution.md
rename to modules/legacy-support/internal/technical/Anti_Reasoning_Monologue_Solution.md
diff --git a/internal/technical/Final_Baxian_Sanqing_Model_Configuration.md b/modules/legacy-support/internal/technical/Final_Baxian_Sanqing_Model_Configuration.md
similarity index 100%
rename from internal/technical/Final_Baxian_Sanqing_Model_Configuration.md
rename to modules/legacy-support/internal/technical/Final_Baxian_Sanqing_Model_Configuration.md
diff --git a/internal/technical/Reasoning_Pattern_Detection_And_Filtering.md b/modules/legacy-support/internal/technical/Reasoning_Pattern_Detection_And_Filtering.md
similarity index 100%
rename from internal/technical/Reasoning_Pattern_Detection_And_Filtering.md
rename to modules/legacy-support/internal/technical/Reasoning_Pattern_Detection_And_Filtering.md
diff --git a/internal/technical/Sanqing_Baxian_OpenRouter_Model_Assignment.md b/modules/legacy-support/internal/technical/Sanqing_Baxian_OpenRouter_Model_Assignment.md
similarity index 100%
rename from internal/technical/Sanqing_Baxian_OpenRouter_Model_Assignment.md
rename to modules/legacy-support/internal/technical/Sanqing_Baxian_OpenRouter_Model_Assignment.md
diff --git a/internal/technical/Xiantian_Bagua_Debate_System_Design.md b/modules/legacy-support/internal/technical/Xiantian_Bagua_Debate_System_Design.md
similarity index 100%
rename from internal/technical/Xiantian_Bagua_Debate_System_Design.md
rename to modules/legacy-support/internal/technical/Xiantian_Bagua_Debate_System_Design.md
diff --git a/internal/technical/api_scheduling_strategy.md b/modules/legacy-support/internal/technical/api_scheduling_strategy.md
similarity index 100%
rename from internal/technical/api_scheduling_strategy.md
rename to modules/legacy-support/internal/technical/api_scheduling_strategy.md
diff --git a/internal/technical/liao.md b/modules/legacy-support/internal/technical/liao.md
similarity index 100%
rename from internal/technical/liao.md
rename to modules/legacy-support/internal/technical/liao.md
diff --git a/internal/technical/rapidapi_yahoo_finance_guide.md b/modules/legacy-support/internal/technical/rapidapi_yahoo_finance_guide.md
similarity index 100%
rename from internal/technical/rapidapi_yahoo_finance_guide.md
rename to modules/legacy-support/internal/technical/rapidapi_yahoo_finance_guide.md
diff --git a/litellm/comprehensive_mcp_test.py b/modules/legacy-support/litellm/comprehensive_mcp_test.py
similarity index 100%
rename from litellm/comprehensive_mcp_test.py
rename to modules/legacy-support/litellm/comprehensive_mcp_test.py
diff --git a/litellm/config.yaml b/modules/legacy-support/litellm/config.yaml
similarity index 100%
rename from litellm/config.yaml
rename to modules/legacy-support/litellm/config.yaml
diff --git a/litellm/final_mcp_test.py b/modules/legacy-support/litellm/final_mcp_test.py
similarity index 100%
rename from litellm/final_mcp_test.py
rename to modules/legacy-support/litellm/final_mcp_test.py
diff --git a/litellm/list_models.py b/modules/legacy-support/litellm/list_models.py
similarity index 100%
rename from litellm/list_models.py
rename to modules/legacy-support/litellm/list_models.py
diff --git a/litellm/simple_mcp_server.py b/modules/legacy-support/litellm/simple_mcp_server.py
similarity index 100%
rename from litellm/simple_mcp_server.py
rename to modules/legacy-support/litellm/simple_mcp_server.py
diff --git a/litellm/test_deepwiki_mcp.py b/modules/legacy-support/litellm/test_deepwiki_mcp.py
similarity index 100%
rename from litellm/test_deepwiki_mcp.py
rename to modules/legacy-support/litellm/test_deepwiki_mcp.py
diff --git a/litellm/test_gpt5_nano.py b/modules/legacy-support/litellm/test_gpt5_nano.py
similarity index 100%
rename from litellm/test_gpt5_nano.py
rename to modules/legacy-support/litellm/test_gpt5_nano.py
diff --git a/litellm/test_litellm_mcp.py b/modules/legacy-support/litellm/test_litellm_mcp.py
similarity index 100%
rename from litellm/test_litellm_mcp.py
rename to modules/legacy-support/litellm/test_litellm_mcp.py
diff --git a/litellm/test_mcp_detailed.py b/modules/legacy-support/litellm/test_mcp_detailed.py
similarity index 100%
rename from litellm/test_mcp_detailed.py
rename to modules/legacy-support/litellm/test_mcp_detailed.py
diff --git a/litellm/test_mcp_endpoint.py b/modules/legacy-support/litellm/test_mcp_endpoint.py
similarity index 100%
rename from litellm/test_mcp_endpoint.py
rename to modules/legacy-support/litellm/test_mcp_endpoint.py
diff --git a/litellm/test_remote_simple.py b/modules/legacy-support/litellm/test_remote_simple.py
similarity index 100%
rename from litellm/test_remote_simple.py
rename to modules/legacy-support/litellm/test_remote_simple.py
diff --git a/litellm/testmcp.py b/modules/legacy-support/litellm/testmcp.py
similarity index 100%
rename from litellm/testmcp.py
rename to modules/legacy-support/litellm/testmcp.py
diff --git a/litellm/testmcp_debug.py b/modules/legacy-support/litellm/testmcp_debug.py
similarity index 100%
rename from litellm/testmcp_debug.py
rename to modules/legacy-support/litellm/testmcp_debug.py
diff --git a/litellm/testmcp_local.py b/modules/legacy-support/litellm/testmcp_local.py
similarity index 100%
rename from litellm/testmcp_local.py
rename to modules/legacy-support/litellm/testmcp_local.py
diff --git a/multi_chat_coordination_completion_report.md b/modules/legacy-support/multi_chat_coordination_completion_report.md
similarity index 100%
rename from multi_chat_coordination_completion_report.md
rename to modules/legacy-support/multi_chat_coordination_completion_report.md
diff --git a/ops.txt b/modules/legacy-support/ops.txt
similarity index 100%
rename from ops.txt
rename to modules/legacy-support/ops.txt
diff --git a/priority_algorithm_optimization_report.md b/modules/legacy-support/priority_algorithm_optimization_report.md
similarity index 100%
rename from priority_algorithm_optimization_report.md
rename to modules/legacy-support/priority_algorithm_optimization_report.md
diff --git a/priority_analysis.json b/modules/legacy-support/priority_analysis.json
similarity index 100%
rename from priority_analysis.json
rename to modules/legacy-support/priority_analysis.json
diff --git a/research.txt b/modules/legacy-support/research.txt
similarity index 100%
rename from research.txt
rename to modules/legacy-support/research.txt
diff --git a/reset_trae.sh b/modules/legacy-support/reset_trae.sh
similarity index 100%
rename from reset_trae.sh
rename to modules/legacy-support/reset_trae.sh
diff --git a/simple_memory_web.py b/modules/legacy-support/simple_memory_web.py
similarity index 100%
rename from simple_memory_web.py
rename to modules/legacy-support/simple_memory_web.py
diff --git a/start_ai_collaboration.sh b/modules/legacy-support/start_ai_collaboration.sh
similarity index 100%
rename from start_ai_collaboration.sh
rename to modules/legacy-support/start_ai_collaboration.sh
diff --git a/start_trae_server.sh b/modules/legacy-support/start_trae_server.sh
similarity index 100%
rename from start_trae_server.sh
rename to modules/legacy-support/start_trae_server.sh
diff --git a/test_enhanced_algorithm.py b/modules/legacy-support/test_enhanced_algorithm.py
similarity index 100%
rename from test_enhanced_algorithm.py
rename to modules/legacy-support/test_enhanced_algorithm.py
diff --git a/tmp_rovodev_vertex_check.py b/modules/legacy-support/tmp_rovodev_vertex_check.py
similarity index 100%
rename from tmp_rovodev_vertex_check.py
rename to modules/legacy-support/tmp_rovodev_vertex_check.py
diff --git a/topic/ai_pow.md b/modules/legacy-support/topic/ai_pow.md
similarity index 100%
rename from topic/ai_pow.md
rename to modules/legacy-support/topic/ai_pow.md
diff --git a/verify_enhanced_coordinator.py b/modules/legacy-support/verify_enhanced_coordinator.py
similarity index 100%
rename from verify_enhanced_coordinator.py
rename to modules/legacy-support/verify_enhanced_coordinator.py
diff --git a/modules/monitoring-dashboard/app/__init__.py b/modules/monitoring-dashboard/app/__init__.py
new file mode 100644
index 0000000..f40a138
--- /dev/null
+++ b/modules/monitoring-dashboard/app/__init__.py
@@ -0,0 +1 @@
+# 应用模块
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/app/streamlit_app.py b/modules/monitoring-dashboard/app/streamlit_app.py
new file mode 100644
index 0000000..c9aef9d
--- /dev/null
+++ b/modules/monitoring-dashboard/app/streamlit_app.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python3
+"""
+炼妖壶 (Lianyaohu) - 稷下学宫AI辩论系统
+主Streamlit应用入口
+
+重构版本:
+- 清晰的模块化结构
+- 统一的配置管理
+- 安全的密钥处理
+"""
+
+import streamlit as st
+import sys
+from pathlib import Path
+
+# 添加项目根目录到Python路径
+project_root = Path(__file__).parent.parent
+sys.path.insert(0, str(project_root))
+
+def configure_page():
+ """配置页面基本设置"""
+ st.set_page_config(
+ page_title="炼妖壶 - 稷下学宫AI辩论系统",
+ page_icon="🏛️",
+ layout="wide",
+ initial_sidebar_state="expanded"
+ )
+
+def show_header():
+ """显示页面头部"""
+ st.title("🏛️ 炼妖壶 - 稷下学宫AI辩论系统")
+ st.markdown("**基于中国哲学传统的多AI智能体辩论平台**")
+
+ # 显示系统状态
+ col1, col2, col3 = st.columns(3)
+ with col1:
+ st.metric("系统状态", "🟢 运行中")
+ with col2:
+ st.metric("AI模型", "OpenRouter")
+ with col3:
+ # 更新数据源展示,加入 OpenBB
+ st.metric("数据源", "RapidAPI + OpenBB")
+
+def show_sidebar():
+ """显示侧边栏"""
+ with st.sidebar:
+ st.markdown("## 🎛️ 控制面板")
+
+ # 系统信息
+ st.markdown("### 📊 系统信息")
+ st.info("**版本**: v2.0 (重构版)")
+ st.info("**状态**: 迁移完成")
+
+ # 配置检查
+ st.markdown("### 🔧 配置状态")
+ try:
+ from config.doppler_config import validate_config
+ if validate_config():
+ st.success("✅ 配置正常")
+ else:
+ st.error("❌ 配置异常")
+ except Exception as e:
+ st.warning(f"⚠️ 配置检查失败: {str(e)}")
+
+ # 快速操作
+ st.markdown("### ⚡ 快速操作")
+ if st.button("🧪 测试API连接"):
+ test_api_connections()
+
+ if st.button("🏛️ 启动八仙论道"):
+ start_jixia_debate()
+
+def test_api_connections():
+ """测试API连接"""
+ with st.spinner("正在测试API连接..."):
+ try:
+ from scripts.api_health_check import test_openrouter_api, test_rapidapi_connection
+
+ openrouter_ok = test_openrouter_api()
+ rapidapi_ok = test_rapidapi_connection()
+
+ if openrouter_ok and rapidapi_ok:
+ st.success("✅ 所有API连接正常")
+ else:
+ st.error("❌ 部分API连接失败")
+ except Exception as e:
+ st.error(f"❌ API测试异常: {str(e)}")
+
+def start_jixia_debate():
+ """启动稷下学宫辩论"""
+ with st.spinner("正在启动稷下学宫八仙论道..."):
+ try:
+ from config.settings import get_rapidapi_key
+ from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine
+
+ api_key = get_rapidapi_key()
+ engine = JixiaPerpetualEngine(api_key)
+
+ # 运行辩论
+ results = engine.simulate_jixia_debate('TSLA')
+
+ st.success("✅ 八仙论道完成")
+ st.json(results)
+ except Exception as e:
+ st.error(f"❌ 辩论启动失败: {str(e)}")
+
+def main():
+ """主函数"""
+ configure_page()
+ show_header()
+ show_sidebar()
+
+ # 主内容区域
+ st.markdown("---")
+
+ # 选项卡(新增 OpenBB 数据页签和AI协作页签)
+ tab1, tab2, tab3, tab4, tab5 = st.tabs(["🏛️ 稷下学宫", "🌍 天下体系", "📊 数据分析", "📈 OpenBB 数据", "🤖 AI协作"])
+
+ with tab1:
+ st.markdown("### 🏛️ 稷下学宫 - 八仙论道")
+ st.markdown("**多AI智能体辩论系统,基于中国传统八仙文化**")
+
+ # 辩论模式选择
+ debate_mode = st.selectbox(
+ "选择辩论模式",
+ ["ADK模式 (太上老君主持)", "传统模式 (RapidAPI数据)"]
+ )
+
+ if debate_mode == "ADK模式 (太上老君主持)":
+ from app.tabs.adk_debate_tab import render_adk_debate_tab
+ render_adk_debate_tab()
+
+ else:
+ # 传统模式
+ col1, col2 = st.columns([2, 1])
+ with col1:
+ topic = st.text_input("辩论主题 (股票代码)", value="TSLA")
+ with col2:
+ if st.button("🎭 开始辩论", type="primary"):
+ start_debate_session(topic)
+
+ # 显示辩论历史
+ if 'debate_history' in st.session_state:
+ st.markdown("#### 📜 辩论记录")
+ for record in st.session_state.debate_history[-3:]: # 显示最近3次
+ with st.expander(f"🎭 {record['topic']} - {record['time']}"):
+ st.json(record['results'])
+
+ with tab2:
+ st.markdown("### 🌍 天下体系分析")
+ try:
+ from app.tabs.tianxia_tab import render_tianxia_tab
+ render_tianxia_tab()
+ except Exception as e:
+ st.error(f"❌ 天下体系模块加载失败: {str(e)}")
+
+ with tab3:
+ st.markdown("### 📊 数据分析")
+ st.info("🚧 数据分析模块开发中...")
+
+ # 显示系统统计
+ try:
+ from config.settings import get_rapidapi_key
+ from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine
+
+ api_key = get_rapidapi_key()
+ engine = JixiaPerpetualEngine(api_key)
+ stats = engine.get_usage_stats()
+
+ col1, col2, col3 = st.columns(3)
+ with col1:
+ st.metric("API调用总数", stats['total_calls'])
+ with col2:
+ st.metric("活跃API数", f"{stats['active_apis']}/{stats['total_apis']}")
+ with col3:
+ st.metric("未使用API", stats['unused_count'])
+
+ except Exception as e:
+ st.warning(f"⚠️ 无法加载统计数据: {str(e)}")
+
+ with tab5:
+ st.markdown("### 🤖 AI协作")
+ try:
+ from app.tabs.ai_collaboration_tab import main as ai_collaboration_main
+ ai_collaboration_main()
+ except Exception as e:
+ st.error(f"❌ AI协作模块加载失败: {str(e)}")
+
+def start_debate_session(topic: str):
+ """启动辩论会话"""
+ if not topic:
+ st.error("请输入辩论主题")
+ return
+
+ with st.spinner(f"🏛️ 八仙正在就 {topic} 展开论道..."):
+ try:
+ from config.settings import get_rapidapi_key
+ from src.jixia.engines.perpetual_engine import JixiaPerpetualEngine
+ from datetime import datetime
+
+ api_key = get_rapidapi_key()
+ engine = JixiaPerpetualEngine(api_key)
+
+ # 运行辩论
+ results = engine.simulate_jixia_debate(topic)
+
+ # 保存到会话状态
+ if 'debate_history' not in st.session_state:
+ st.session_state.debate_history = []
+
+ st.session_state.debate_history.append({
+ 'topic': topic,
+ 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
+ 'results': {name: {'success': result.success, 'api_used': result.api_used}
+ for name, result in results.items()}
+ })
+
+ st.success(f"✅ 八仙论道完成!共有 {len(results)} 位仙人参与")
+
+ # 显示结果摘要
+ successful_debates = sum(1 for result in results.values() if result.success)
+ st.info(f"📊 成功获取数据: {successful_debates}/{len(results)} 位仙人")
+
+ except Exception as e:
+ st.error(f"❌ 辩论启动失败: {str(e)}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/app/tabs/adk_debate_tab.py b/modules/monitoring-dashboard/app/tabs/adk_debate_tab.py
new file mode 100644
index 0000000..b03c427
--- /dev/null
+++ b/modules/monitoring-dashboard/app/tabs/adk_debate_tab.py
@@ -0,0 +1,205 @@
+
+import streamlit as st
+import asyncio
+import sys
+from pathlib import Path
+from typing import Dict, Any, List
+
+# Ensure the main project directory is in the Python path
+project_root = Path(__file__).parent.parent.parent
+sys.path.insert(0, str(project_root))
+
+try:
+ from google.adk import Agent, Runner
+ from google.adk.sessions import InMemorySessionService, Session
+ from google.genai import types
+ ADK_AVAILABLE = True
+except ImportError:
+ ADK_AVAILABLE = False
+ # 创建占位符类
+ class Agent:
+ pass
+ class Runner:
+ pass
+ class InMemorySessionService:
+ pass
+ class Session:
+ pass
+ class types:
+ class Content:
+ pass
+ class Part:
+ pass
+
+async def _get_llm_reply(runner: Runner, session: Session, prompt: str) -> str:
+ """Helper function to call a Runner and get a text reply."""
+ content = types.Content(role='user', parts=[types.Part(text=prompt)])
+ response = runner.run_async(
+ user_id=session.user_id,
+ session_id=session.id,
+ new_message=content
+ )
+
+ reply = ""
+ async for event in response:
+ if hasattr(event, 'content') and event.content and hasattr(event.content, 'parts'):
+ for part in event.content.parts:
+ if hasattr(part, 'text') and part.text:
+ reply += str(part.text)
+ elif hasattr(event, 'text') and event.text:
+ reply += str(event.text)
+
+ return reply.strip()
+
+async def run_adk_debate_streamlit(topic: str, participants: List[str], rounds: int):
+ """
+ Runs the ADK turn-based debate and yields each statement for Streamlit display.
+ """
+ try:
+ yield "🚀 **启动ADK八仙轮流辩论 (太上老君主持)...**"
+
+ all_immortals = ["铁拐李", "吕洞宾", "何仙姑", "张果老", "蓝采和", "汉钟离", "韩湘子", "曹国舅"]
+ if not participants:
+ participants = all_immortals
+
+ character_configs = {
+ "太上老君": {"name": "太上老君", "model": "gemini-1.5-pro", "instruction": "你是太上老君,天道化身,辩论的主持人。你的言辞沉稳、公正、充满智慧。你的任务是:1. 对辩论主题进行开场介绍。2. 在每轮开始时进行引导。3. 在辩论结束后,对所有观点进行全面、客观的总结。保持中立,不偏袒任何一方。"},
+ "铁拐李": {"name": "铁拐李", "model": "gemini-1.5-flash", "instruction": "你是铁拐李,八仙中的逆向思维专家。你善于从批判和质疑的角度看问题,发言风格直接、犀利,但富有智慧。"},
+ "吕洞宾": {"name": "吕洞宾", "model": "gemini-1.5-flash", "instruction": "你是吕洞宾,八仙中的理性分析者。你善于平衡各方观点,用理性和逻辑来分析问题,发言风格温和而深刻。"},
+ "何仙姑": {"name": "何仙姑", "model": "gemini-1.5-flash", "instruction": "你是何仙姑,八仙中的风险控制专家。你总是从风险管理的角度思考问题,善于发现潜在危险,发言风格谨慎、细致。"},
+ "张果老": {"name": "张果老", "model": "gemini-1.5-flash", "instruction": "你是张果老,八仙中的历史智慧者。你善于从历史数据中寻找规律和智慧,提供长期视角,发言风格沉稳、博学。"},
+ "蓝采和": {"name": "蓝采和", "model": "gemini-1.5-flash", "instruction": "你是蓝采和,八仙中的创新思维者。你善于从新兴视角和非传统方法来看待问题,发言风格活泼、新颖。"},
+ "汉钟离": {"name": "汉钟离", "model": "gemini-1.5-flash", "instruction": "你是汉钟离,八仙中的平衡协调者。你善于综合各方观点,寻求和谐统一的解决方案,发言风格平和、包容。"},
+ "韩湘子": {"name": "韩湘子", "model": "gemini-1.5-flash", "instruction": "你是韩湘子,八仙中的艺术感知者。你善于从美学和感性的角度分析问题,发言风格优雅、感性。"},
+ "曹国舅": {"name": "曹国舅", "model": "gemini-1.5-flash", "instruction": "你是曹国舅,八仙中的实务执行者。你关注实际操作和具体细节,发言风格务实、严谨。"}
+ }
+
+ session_service = InMemorySessionService()
+ session = await session_service.create_session(state={}, app_name="稷下学宫八仙论道系统-Streamlit", user_id="st_user")
+
+ runners: Dict[str, Runner] = {}
+ for name, config in character_configs.items():
+ if name == "太上老君" or name in participants:
+ agent = Agent(name=config["name"], model=config["model"], instruction=config["instruction"])
+ runners[name] = Runner(app_name="稷下学宫八仙论道系统-Streamlit", agent=agent, session_service=session_service)
+
+ host_runner = runners.get("太上老君")
+ if not host_runner:
+ yield "❌ **主持人太上老君初始化失败。**"
+ return
+
+ yield f"🎯 **参与仙人**: {', '.join(participants)}"
+ debate_history = []
+
+ # Opening statement
+ opening_prompt = f"请为本次关于“{topic}”的辩论,发表一段公正、深刻的开场白,并宣布辩论开始。"
+ opening_statement = await _get_llm_reply(host_runner, session, opening_prompt)
+ yield f"👑 **太上老君**: {opening_statement}"
+
+ # Debate rounds
+ for round_num in range(rounds):
+ round_intro_prompt = f"请为第 {round_num + 1} 轮辩论说一段引导语。"
+ round_intro = await _get_llm_reply(host_runner, session, round_intro_prompt)
+ yield f"👑 **太上老君**: {round_intro}"
+
+ for name in participants:
+ if name not in runners: continue
+
+ history_context = f"\n最近的论道内容:\n" + "\n".join([f"- {h}" for h in debate_history[-5:]]) if debate_history else ""
+ prompt = f"论道主题: {topic}{history_context}\n\n请从你的角色特点出发,简洁地发表观点。"
+
+ reply = await _get_llm_reply(runners[name], session, prompt)
+ yield f"🗣️ **{name}**: {reply}"
+
+ debate_history.append(f"{name}: {reply}")
+ await asyncio.sleep(1)
+
+ # Summary
+ summary_prompt = f"辩论已结束。以下是完整的辩论记录:\n\n{' '.join(debate_history)}\n\n请对本次辩论进行全面、公正、深刻的总结。"
+ summary = await _get_llm_reply(host_runner, session, summary_prompt)
+ yield f"👑 **太上老君**: {summary}"
+
+ for runner in runners.values():
+ await runner.close()
+
+ yield "🎉 **ADK八仙轮流辩论完成!**"
+
+ except Exception as e:
+ yield f"❌ **运行ADK八仙轮流辩论失败**: {e}"
+ import traceback
+ st.error(traceback.format_exc())
+
+def render_adk_debate_tab():
+ """Renders the Streamlit UI for the ADK Debate tab."""
+
+ # 检查 ADK 是否可用
+ if not ADK_AVAILABLE:
+ st.error("🚫 Google ADK 模块未安装或不可用")
+ st.info("📦 正在安装 Google ADK,请稍候...")
+ st.info("💡 安装完成后请刷新页面")
+
+ with st.expander("📋 安装说明"):
+ st.code("""
+# 安装 Google ADK
+pip install google-adk>=1.12.0
+
+# 或从 GitHub 安装开发版
+pip install git+https://github.com/google/adk-python.git@main
+ """)
+ return
+ st.markdown("### 🏛️ 八仙论道 (ADK版 - 太上老君主持)")
+
+ topic = st.text_input(
+ "辩论主题",
+ value="AI是否应该拥有创造力?",
+ key="adk_topic_input"
+ )
+
+ all_immortals = ["铁拐李", "吕洞宾", "何仙姑", "张果老", "蓝采和", "汉钟离", "韩湘子", "曹国舅"]
+
+ col1, col2 = st.columns(2)
+ with col1:
+ rounds = st.number_input("辩论轮数", min_value=1, max_value=5, value=1, key="adk_rounds_input")
+ with col2:
+ participants = st.multiselect(
+ "选择参与的仙人 (默认全选)",
+ options=all_immortals,
+ default=all_immortals,
+ key="adk_participants_select"
+ )
+
+ if st.button("🚀 开始论道", key="start_adk_debate_button", type="primary"):
+ if not topic:
+ st.error("请输入辩论主题。")
+ return
+ if not participants:
+ st.error("请至少选择一位参与的仙人。")
+ return
+
+ st.markdown("---")
+ st.markdown("#### 📜 论道实录")
+
+ # Placeholder for real-time output
+ output_container = st.empty()
+ full_log = ""
+
+ # Run the async debate function
+ try:
+ # Get a new event loop for the thread
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+
+ # Create a coroutine object
+ coro = run_adk_debate_streamlit(topic, participants, rounds)
+
+ # Run the coroutine until completion
+ for message in loop.run_until_complete(async_generator_to_list(coro)):
+ full_log += message + "\n\n"
+ output_container.markdown(full_log)
+
+ except Exception as e:
+ st.error(f"启动辩论时发生错误: {e}")
+
+async def async_generator_to_list(async_gen):
+ """Helper to consume an async generator and return a list of its items."""
+ return [item async for item in async_gen]
diff --git a/modules/monitoring-dashboard/app/tabs/ai_collaboration_tab.py b/modules/monitoring-dashboard/app/tabs/ai_collaboration_tab.py
new file mode 100644
index 0000000..8f8d389
--- /dev/null
+++ b/modules/monitoring-dashboard/app/tabs/ai_collaboration_tab.py
@@ -0,0 +1,509 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+四AI团队协作Web界面
+基于Streamlit的实时协作监控和管理界面
+"""
+
+import streamlit as st
+import asyncio
+import json
+import pandas as pd
+import plotly.express as px
+import plotly.graph_objects as go
+from datetime import datetime, timedelta
+import sys
+from pathlib import Path
+
+# 添加项目路径到sys.path
+project_root = Path(__file__).parent.parent.parent.parent
+sys.path.insert(0, str(project_root))
+
+from src.jixia.coordination.ai_team_collaboration import (
+ AITeamCollaboration, AIRole, MessageType, CollaborationType, WorkPhase
+)
+
+# 页面配置
+st.set_page_config(
+ page_title="四AI团队协作中心",
+ page_icon="🤖",
+ layout="wide",
+ initial_sidebar_state="expanded"
+)
+
+# 初始化协作系统
+@st.cache_resource
+def init_collaboration_system():
+ """初始化协作系统"""
+ return AITeamCollaboration()
+
+def main():
+ """主界面"""
+ st.title("🤖 四AI团队协作中心")
+ st.markdown("### OpenBB集成项目实时协作监控")
+
+ # 初始化系统
+ collab = init_collaboration_system()
+
+ # 侧边栏
+ with st.sidebar:
+ st.header("🎯 项目状态")
+
+ # 当前阶段
+ current_phase = st.selectbox(
+ "当前工作阶段",
+ [phase.value for phase in WorkPhase],
+ index=list(WorkPhase).index(collab.current_phase)
+ )
+
+ if st.button("更新阶段"):
+ new_phase = WorkPhase(current_phase)
+ asyncio.run(collab.advance_phase(new_phase))
+ st.success(f"阶段已更新为: {current_phase}")
+ st.rerun()
+
+ st.divider()
+
+ # AI状态概览
+ st.subheader("🤖 AI状态概览")
+ for ai_role, status in collab.ai_status.items():
+ status_color = {
+ "ready": "🟢",
+ "active": "🔵",
+ "waiting": "🟡",
+ "completed_handoff": "✅",
+ "received_handoff": "📥"
+ }.get(status["status"], "⚪")
+
+ st.write(f"{status_color} **{ai_role.value}**")
+ st.write(f" 📋 {status['current_task']}")
+ st.write(f" 🎯 {status['role']}")
+
+ # 主要内容区域
+ tab1, tab2, tab3, tab4, tab5 = st.tabs([
+ "📢 主协作频道", "📊 AI仪表板", "🔄 工作流管理", "📈 协作分析", "⚙️ 系统管理"
+ ])
+
+ with tab1:
+ render_main_collaboration(collab)
+
+ with tab2:
+ render_ai_dashboard(collab)
+
+ with tab3:
+ render_workflow_management(collab)
+
+ with tab4:
+ render_collaboration_analytics(collab)
+
+ with tab5:
+ render_system_management(collab)
+
+def render_main_collaboration(collab):
+ """渲染主协作频道"""
+ st.header("📢 主协作频道")
+
+ # 频道选择
+ channel_options = {
+ channel.name: channel_id
+ for channel_id, channel in collab.channels.items()
+ }
+
+ selected_channel_name = st.selectbox(
+ "选择频道",
+ list(channel_options.keys()),
+ index=0
+ )
+
+ selected_channel_id = channel_options[selected_channel_name]
+ channel = collab.channels[selected_channel_id]
+
+ col1, col2 = st.columns([2, 1])
+
+ with col1:
+ # 消息历史
+ st.subheader(f"💬 {channel.name}")
+
+ if channel.message_history:
+ for msg in channel.message_history[-10:]: # 显示最近10条消息
+ sender_emoji = {
+ AIRole.QWEN: "🏗️",
+ AIRole.CLAUDE: "💻",
+ AIRole.GEMINI: "🧪",
+ AIRole.ROVODEV: "📚"
+ }.get(msg.sender, "🤖")
+
+ with st.chat_message(msg.sender.value, avatar=sender_emoji):
+ st.write(f"**{msg.message_type.value}** - {msg.timestamp.strftime('%H:%M')}")
+ st.write(msg.content)
+
+ if msg.attachments:
+ st.write("📎 附件:")
+ for attachment in msg.attachments:
+ st.write(f" • {attachment}")
+
+ if msg.tags:
+ tag_html = " ".join([f"{tag}" for tag in msg.tags])
+ st.markdown(tag_html, unsafe_allow_html=True)
+ else:
+ st.info("暂无消息")
+
+ with col2:
+ # 频道信息
+ st.subheader("ℹ️ 频道信息")
+ st.write(f"**类型**: {channel.channel_type.value}")
+ st.write(f"**参与者**: {len(channel.participants)}人")
+ st.write(f"**主持人**: {channel.moderator.value}")
+ st.write(f"**消息数**: {len(channel.message_history)}")
+ st.write(f"**最后活动**: {channel.last_activity.strftime('%Y-%m-%d %H:%M')}")
+
+ # 参与者列表
+ st.write("**参与者列表**:")
+ for participant in channel.participants:
+ role_emoji = {
+ AIRole.QWEN: "🏗️",
+ AIRole.CLAUDE: "💻",
+ AIRole.GEMINI: "🧪",
+ AIRole.ROVODEV: "📚"
+ }.get(participant, "🤖")
+ st.write(f"{role_emoji} {participant.value}")
+
+ # 发送消息区域
+ st.divider()
+ st.subheader("📝 发送消息")
+
+ col1, col2, col3 = st.columns([2, 1, 1])
+
+ with col1:
+ message_content = st.text_area("消息内容", height=100)
+
+ with col2:
+ sender = st.selectbox(
+ "发送者",
+ [role.value for role in AIRole]
+ )
+
+ message_type = st.selectbox(
+ "消息类型",
+ [msg_type.value for msg_type in MessageType]
+ )
+
+ with col3:
+ receiver = st.selectbox(
+ "接收者",
+ ["广播"] + [role.value for role in AIRole]
+ )
+
+ priority = st.slider("优先级", 1, 5, 1)
+
+ if st.button("发送消息", type="primary"):
+ if message_content:
+ try:
+ receiver_role = None if receiver == "广播" else AIRole(receiver)
+
+ asyncio.run(collab.send_message(
+ sender=AIRole(sender),
+ content=message_content,
+ message_type=MessageType(message_type),
+ channel_id=selected_channel_id,
+ receiver=receiver_role,
+ priority=priority
+ ))
+
+ st.success("消息发送成功!")
+ st.rerun()
+ except Exception as e:
+ st.error(f"发送失败: {str(e)}")
+ else:
+ st.warning("请输入消息内容")
+
+def render_ai_dashboard(collab):
+ """渲染AI仪表板"""
+ st.header("📊 AI工作仪表板")
+
+ # AI选择
+ selected_ai = st.selectbox(
+ "选择AI",
+ [role.value for role in AIRole]
+ )
+
+ ai_role = AIRole(selected_ai)
+ dashboard = collab.get_ai_dashboard(ai_role)
+
+ # 基本信息
+ col1, col2, col3, col4 = st.columns(4)
+
+ with col1:
+ st.metric("当前状态", dashboard["status"]["status"])
+
+ with col2:
+ st.metric("活跃频道", len(dashboard["active_channels"]))
+
+ with col3:
+ st.metric("待处理任务", len(dashboard["pending_tasks"]))
+
+ with col4:
+ st.metric("协作得分", dashboard["collaboration_stats"]["collaboration_score"])
+
+ # 详细信息
+ col1, col2 = st.columns(2)
+
+ with col1:
+ # 待处理任务
+ st.subheader("📋 待处理任务")
+ if dashboard["pending_tasks"]:
+ for task in dashboard["pending_tasks"]:
+ with st.expander(f"{task['type']} - 优先级 {task['priority']}"):
+ st.write(f"**来自**: {task['from']}")
+ st.write(f"**频道**: {task['channel']}")
+ st.write(f"**创建时间**: {task['created']}")
+ st.write(f"**描述**: {task['description']}")
+ else:
+ st.info("暂无待处理任务")
+
+ with col2:
+ # 最近消息
+ st.subheader("📨 最近消息")
+ if dashboard["recent_messages"]:
+ for msg in dashboard["recent_messages"][:5]:
+ priority_color = {
+ 1: "🔵", 2: "🟢", 3: "🟡", 4: "🟠", 5: "🔴"
+ }.get(msg["priority"], "⚪")
+
+ st.write(f"{priority_color} **{msg['sender']}** 在 **{msg['channel']}**")
+ st.write(f" {msg['content']}")
+ st.write(f" ⏰ {msg['timestamp']}")
+ st.divider()
+ else:
+ st.info("暂无最近消息")
+
+ # 协作统计
+ st.subheader("📈 协作统计")
+
+ stats = dashboard["collaboration_stats"]
+ col1, col2, col3 = st.columns(3)
+
+ with col1:
+ st.metric("发送消息", stats["messages_sent"])
+
+ with col2:
+ st.metric("接收消息", stats["messages_received"])
+
+ with col3:
+ st.metric("总消息数", stats["total_messages"])
+
+def render_workflow_management(collab):
+ """渲染工作流管理"""
+ st.header("🔄 工作流管理")
+
+ # 工作流规则
+ st.subheader("📜 工作流规则")
+
+ rules_data = []
+ for rule_id, rule in collab.workflow_rules.items():
+ rules_data.append({
+ "规则ID": rule.id,
+ "规则名称": rule.name,
+ "触发阶段": rule.trigger_phase.value,
+ "目标AI": rule.target_ai.value if rule.target_ai else "无",
+ "状态": "✅ 激活" if rule.is_active else "❌ 禁用"
+ })
+
+ if rules_data:
+ st.dataframe(pd.DataFrame(rules_data), use_container_width=True)
+
+ # 手动工作交接
+ st.divider()
+ st.subheader("🤝 手动工作交接")
+
+ col1, col2, col3 = st.columns(3)
+
+ with col1:
+ from_ai = st.selectbox("交接方", [role.value for role in AIRole])
+ to_ai = st.selectbox("接收方", [role.value for role in AIRole])
+
+ with col2:
+ task_desc = st.text_input("任务描述")
+ deliverables = st.text_area("交付物列表 (每行一个)")
+
+ with col3:
+ notes = st.text_area("备注")
+
+ if st.button("执行工作交接"):
+ if task_desc and from_ai != to_ai:
+ deliverable_list = [d.strip() for d in deliverables.split('\n') if d.strip()]
+
+ try:
+ asyncio.run(collab.handoff_work(
+ from_ai=AIRole(from_ai),
+ to_ai=AIRole(to_ai),
+ task_description=task_desc,
+ deliverables=deliverable_list,
+ notes=notes
+ ))
+ st.success("工作交接完成!")
+ st.rerun()
+ except Exception as e:
+ st.error(f"交接失败: {str(e)}")
+ else:
+ st.warning("请填写完整信息,且交接方和接收方不能相同")
+
+def render_collaboration_analytics(collab):
+ """渲染协作分析"""
+ st.header("📈 协作分析")
+
+ # 消息统计
+ st.subheader("💬 消息统计")
+
+ # 收集所有消息数据
+ message_data = []
+ for channel_id, channel in collab.channels.items():
+ for msg in channel.message_history:
+ message_data.append({
+ "频道": channel.name,
+ "发送者": msg.sender.value,
+ "消息类型": msg.message_type.value,
+ "优先级": msg.priority,
+ "时间": msg.timestamp,
+ "日期": msg.timestamp.date(),
+ "小时": msg.timestamp.hour
+ })
+
+ if message_data:
+ df = pd.DataFrame(message_data)
+
+ col1, col2 = st.columns(2)
+
+ with col1:
+ # 按AI发送者统计
+ sender_counts = df.groupby("发送者").size().reset_index()
+ sender_counts.columns = ["AI", "消息数量"]
+
+ fig = px.bar(sender_counts, x="AI", y="消息数量",
+ title="各AI发送消息统计")
+ st.plotly_chart(fig, use_container_width=True)
+
+ with col2:
+ # 按消息类型统计
+ type_counts = df.groupby("消息类型").size().reset_index()
+ type_counts.columns = ["消息类型", "数量"]
+
+ fig = px.pie(type_counts, values="数量", names="消息类型",
+ title="消息类型分布")
+ st.plotly_chart(fig, use_container_width=True)
+
+ # 时间线分析
+ st.subheader("⏰ 活跃度时间线")
+
+ if len(df) > 1:
+ daily_counts = df.groupby("日期").size().reset_index()
+ daily_counts.columns = ["日期", "消息数量"]
+
+ fig = px.line(daily_counts, x="日期", y="消息数量",
+ title="每日消息数量趋势")
+ st.plotly_chart(fig, use_container_width=True)
+
+ # 频道活跃度
+ st.subheader("📢 频道活跃度")
+ channel_counts = df.groupby("频道").size().reset_index()
+ channel_counts.columns = ["频道", "消息数量"]
+ channel_counts = channel_counts.sort_values("消息数量", ascending=True)
+
+ fig = px.bar(channel_counts, x="消息数量", y="频道",
+ orientation='h', title="各频道消息数量")
+ st.plotly_chart(fig, use_container_width=True)
+
+ else:
+ st.info("暂无消息数据用于分析")
+
+def render_system_management(collab):
+ """渲染系统管理"""
+ st.header("⚙️ 系统管理")
+
+ # 系统状态
+ st.subheader("🔍 系统状态")
+
+ col1, col2, col3 = st.columns(3)
+
+ with col1:
+ st.metric("活跃频道", len([c for c in collab.channels.values() if c.is_active]))
+
+ with col2:
+ total_messages = sum(len(c.message_history) for c in collab.channels.values())
+ st.metric("总消息数", total_messages)
+
+ with col3:
+ st.metric("工作流规则", len(collab.workflow_rules))
+
+ # 频道管理
+ st.subheader("📢 频道管理")
+
+ for channel_id, channel in collab.channels.items():
+ with st.expander(f"{channel.name} ({channel.channel_type.value})"):
+ col1, col2 = st.columns(2)
+
+ with col1:
+ st.write(f"**描述**: {channel.description}")
+ st.write(f"**参与者**: {len(channel.participants)}人")
+ st.write(f"**消息数**: {len(channel.message_history)}")
+ st.write(f"**状态**: {'🟢 活跃' if channel.is_active else '🔴 禁用'}")
+
+ with col2:
+ st.write("**参与者列表**:")
+ for participant in channel.participants:
+ st.write(f" • {participant.value}")
+
+ st.write(f"**主持人**: {channel.moderator.value}")
+ st.write(f"**最后活动**: {channel.last_activity.strftime('%Y-%m-%d %H:%M')}")
+
+ # 数据导出
+ st.divider()
+ st.subheader("📤 数据导出")
+
+ if st.button("导出协作数据"):
+ # 准备导出数据
+ export_data = {
+ "channels": {},
+ "ai_status": {},
+ "workflow_rules": {},
+ "system_info": {
+ "current_phase": collab.current_phase.value,
+ "export_time": datetime.now().isoformat()
+ }
+ }
+
+ # 频道数据
+ for channel_id, channel in collab.channels.items():
+ export_data["channels"][channel_id] = {
+ "name": channel.name,
+ "type": channel.channel_type.value,
+ "participants": [p.value for p in channel.participants],
+ "message_count": len(channel.message_history),
+ "last_activity": channel.last_activity.isoformat()
+ }
+
+ # AI状态数据
+ for ai_role, status in collab.ai_status.items():
+ export_data["ai_status"][ai_role.value] = status
+
+ # 工作流规则
+ for rule_id, rule in collab.workflow_rules.items():
+ export_data["workflow_rules"][rule_id] = {
+ "name": rule.name,
+ "description": rule.description,
+ "trigger_phase": rule.trigger_phase.value,
+ "action": rule.action,
+ "is_active": rule.is_active
+ }
+
+ # 创建下载链接
+ json_str = json.dumps(export_data, indent=2, ensure_ascii=False)
+ st.download_button(
+ label="下载协作数据 (JSON)",
+ data=json_str,
+ file_name=f"ai_collaboration_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
+ mime="application/json"
+ )
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/app/tabs/openbb_tab.py b/modules/monitoring-dashboard/app/tabs/openbb_tab.py
new file mode 100644
index 0000000..210f6a1
--- /dev/null
+++ b/modules/monitoring-dashboard/app/tabs/openbb_tab.py
@@ -0,0 +1,184 @@
+import streamlit as st
+import pandas as pd
+import plotly.express as px
+from datetime import datetime, timedelta
+
+
+def _check_openbb_installed() -> bool:
+ try:
+ # OpenBB v4 推荐用法: from openbb import obb
+ from openbb import obb # noqa: F401
+ return True
+ except Exception:
+ return False
+
+
+def _load_price_data(symbol: str, days: int = 365) -> pd.DataFrame:
+ """Fetch OHLCV using OpenBB v4 when available; otherwise return demo/synthetic data."""
+ end = datetime.utcnow().date()
+ start = end - timedelta(days=days)
+
+ # 优先使用 OpenBB v4
+ try:
+ from openbb import obb
+
+ # 先尝试股票路由
+ try:
+ out = obb.equity.price.historical(
+ symbol,
+ start_date=str(start),
+ end_date=str(end),
+ )
+ except Exception:
+ out = None
+
+ # 若股票无数据,再尝试 ETF 路由
+ if out is None or (hasattr(out, "is_empty") and out.is_empty):
+ try:
+ out = obb.etf.price.historical(
+ symbol,
+ start_date=str(start),
+ end_date=str(end),
+ )
+ except Exception:
+ out = None
+
+ if out is not None:
+ if hasattr(out, "to_df"):
+ df = out.to_df()
+ elif hasattr(out, "to_dataframe"):
+ df = out.to_dataframe()
+ else:
+ # 兜底: 有些 provider 返回可序列化对象
+ df = pd.DataFrame(out) # type: ignore[arg-type]
+
+ # 规格化列名
+ if not isinstance(df, pd.DataFrame) or df.empty:
+ raise ValueError("OpenBB 返回空数据")
+
+ # 有的表以 index 为日期
+ if 'date' in df.columns:
+ df['Date'] = pd.to_datetime(df['date'])
+ elif df.index.name in ('date', 'Date') or isinstance(df.index, pd.DatetimeIndex):
+ df = df.copy()
+ df['Date'] = pd.to_datetime(df.index)
+ else:
+ # 尝试查找常见日期列
+ for cand in ['timestamp', 'time', 'datetime']:
+ if cand in df.columns:
+ df['Date'] = pd.to_datetime(df[cand])
+ break
+
+ # 归一化收盘价列
+ close_col = None
+ for cand in ['adj_close', 'close', 'Close', 'price', 'close_price', 'c']:
+ if cand in df.columns:
+ close_col = cand
+ break
+ if close_col is None:
+ raise ValueError("未找到收盘价列")
+ df['Close'] = pd.to_numeric(df[close_col], errors='coerce')
+
+ # 仅保留需要列并清洗
+ if 'Date' not in df.columns:
+ raise ValueError("未找到日期列")
+ df = df[['Date', 'Close']].dropna()
+ df = df.sort_values('Date').reset_index(drop=True)
+ # 限定时间窗口(有些 provider 可能返回更长区间)
+ df = df[df['Date'].dt.date.between(start, end)]
+
+ if df.empty:
+ raise ValueError("清洗后为空")
+ return df
+
+ except Exception:
+ # 如果 OpenBB 不可用或调用失败,进入本地演示/合成数据兜底
+ pass
+
+ # Fallback to demo from examples/data
+ try:
+ from pathlib import Path
+ root = Path(__file__).resolve().parents[2]
+ demo_map = {
+ 'AAPL': root / 'examples' / 'data' / 'demo_results_aapl.json',
+ 'MSFT': root / 'examples' / 'data' / 'demo_results_msft.json',
+ 'TSLA': root / 'examples' / 'data' / 'demo_results_tsla.json',
+ }
+ path = demo_map.get(symbol.upper())
+ if path and path.exists():
+ df = pd.read_json(path)
+ if 'date' in df.columns:
+ df['Date'] = pd.to_datetime(df['date'])
+ if 'close' in df.columns:
+ df['Close'] = df['close']
+ df = df[['Date', 'Close']].dropna().sort_values('Date').reset_index(drop=True)
+ # 裁剪到时间窗口
+ df = df[df['Date'].dt.date.between(start, end)]
+ return df
+ except Exception:
+ pass
+
+ # Last resort: minimal synthetic data(避免 FutureWarning)
+ dates = pd.date_range(end=end, periods=min(days, 180))
+ return pd.DataFrame({
+ 'Date': dates,
+ 'Close': pd.Series(range(len(dates))).rolling(5).mean().bfill()
+ })
+
+
+def _kpis_from_df(df: pd.DataFrame) -> dict:
+ if df.empty or 'Close' not in df.columns:
+ return {"最新价": "-", "近30日涨幅": "-", "最大回撤(近90日)": "-"}
+ latest = float(df['Close'].iloc[-1])
+ last_30 = df.tail(30)
+ if len(last_30) > 1:
+ pct_30 = (last_30['Close'].iloc[-1] / last_30['Close'].iloc[0] - 1) * 100
+ else:
+ pct_30 = 0.0
+ # max drawdown over last 90 days
+ lookback = df.tail(90)['Close']
+ roll_max = lookback.cummax()
+ drawdown = (lookback / roll_max - 1).min() * 100
+ return {
+ "最新价": f"{latest:,.2f}",
+ "近30日涨幅": f"{pct_30:.2f}%",
+ "最大回撤(近90日)": f"{drawdown:.2f}%",
+ }
+
+
+def render_openbb_tab():
+ st.write("使用 OpenBB(如可用)或演示数据展示市场概览。")
+
+ col_a, col_b = st.columns([2, 1])
+ with col_b:
+ symbol = st.text_input("股票/ETF 代码", value="AAPL")
+ days = st.slider("时间窗口(天)", 90, 720, 365, step=30)
+ obb_ready = _check_openbb_installed()
+ if obb_ready:
+ st.success("OpenBB 已安装 ✅")
+ else:
+ st.info("未检测到 OpenBB,将使用演示数据。可在 requirements.txt 中加入 openbb 后安装启用。")
+
+ with col_a:
+ df = _load_price_data(symbol, days)
+ if df is None or df.empty:
+ st.warning("未获取到数据")
+ return
+ # 绘制收盘价
+ if 'Date' in df.columns and 'Close' in df.columns:
+ fig = px.line(df, x='Date', y='Close', title=f"{symbol.upper()} 收盘价")
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.dataframe(df.head())
+
+ # KPI 卡片
+ st.markdown("#### 关键指标")
+ kpis = _kpis_from_df(df)
+ k1, k2, k3 = st.columns(3)
+ k1.metric("最新价", kpis["最新价"])
+ k2.metric("近30日涨幅", kpis["近30日涨幅"])
+ k3.metric("最大回撤(近90日)", kpis["最大回撤(近90日)"])
+
+ # 未来:基本面、新闻、情绪等组件占位
+ with st.expander("🚧 更多组件(即将推出)"):
+ st.write("基本面卡片、新闻与情绪、宏观指标、策略筛选等将逐步接入。")
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/app/tabs/tianxia_tab.py b/modules/monitoring-dashboard/app/tabs/tianxia_tab.py
new file mode 100644
index 0000000..2af39ba
--- /dev/null
+++ b/modules/monitoring-dashboard/app/tabs/tianxia_tab.py
@@ -0,0 +1,436 @@
+"""
+天下体系 - 儒门天下观资本生态分析Tab
+基于"天命树"结构模型分析全球资本市场权力结构
+
+重构版本:
+- 移除硬编码API密钥
+- 使用统一配置管理
+- 改进数据结构
+- 增强错误处理
+"""
+
+import streamlit as st
+import pandas as pd
+import plotly.express as px
+from datetime import datetime
+import time
+import random
+from typing import Dict, List, Any, Optional
+from dataclasses import dataclass
+
+# 导入配置管理
+try:
+ from config.settings import get_rapidapi_key
+except ImportError:
+ # 如果配置模块不可用,使用环境变量
+ import os
+ def get_rapidapi_key():
+ return os.getenv('RAPIDAPI_KEY', '')
+
+@dataclass
+class StockEntity:
+ """股票实体数据类"""
+ symbol: str
+ name: str
+ role: str
+ dependency: Optional[str] = None
+ serves: Optional[str] = None
+ type: Optional[str] = None
+
+@dataclass
+class EcosystemData:
+ """生态系统数据类"""
+ tianzi: Dict[str, str]
+ dafu: List[StockEntity]
+ shi: List[StockEntity]
+ jiajie: List[StockEntity]
+
+class TianxiaAnalyzer:
+ """天下体系分析器 - 天命树结构分析"""
+
+ def __init__(self):
+ """初始化分析器"""
+ try:
+ self.rapidapi_key = get_rapidapi_key()
+ except Exception:
+ self.rapidapi_key = ""
+ st.warning("⚠️ 未配置RapidAPI密钥,将使用模拟数据")
+
+ # 定义三大天命树生态系统
+ self.ecosystems = self._initialize_ecosystems()
+
+ def _initialize_ecosystems(self) -> Dict[str, EcosystemData]:
+ """初始化生态系统数据"""
+ return {
+ 'AI': EcosystemData(
+ tianzi={'symbol': 'NVDA', 'name': 'NVIDIA', 'tianming': 'CUDA + GPU硬件,定义AI计算范式'},
+ dafu=[
+ StockEntity('TSM', 'TSMC', '芯片代工', '高端芯片唯一代工厂'),
+ StockEntity('000660.SZ', 'SK Hynix', 'HBM内存', 'GPU性能关键'),
+ StockEntity('MU', 'Micron', 'HBM内存', 'GPU性能关键'),
+ StockEntity('SMCI', 'Supermicro', '服务器集成', 'GPU转化为计算能力')
+ ],
+ shi=[
+ StockEntity('ASML', 'ASML', '光刻设备', serves='TSMC'),
+ StockEntity('AMAT', 'Applied Materials', '半导体设备', serves='TSMC')
+ ],
+ jiajie=[
+ StockEntity('AMD', 'AMD', '竞争对手', type='竞争天子'),
+ StockEntity('GOOGL', 'Google', '云计算', type='云计算天子'),
+ StockEntity('AMZN', 'Amazon', '云计算', type='云计算天子')
+ ]
+ ),
+ 'EV': EcosystemData(
+ tianzi={'symbol': 'TSLA', 'name': 'Tesla', 'tianming': '软件定义汽车 + 超级充电网络'},
+ dafu=[
+ StockEntity('300750.SZ', 'CATL', '动力电池', '动力系统基石'),
+ StockEntity('6752.T', 'Panasonic', '动力电池', '动力系统基石'),
+ StockEntity('ALB', 'Albemarle', '锂矿', '源头命脉'),
+ StockEntity('002460.SZ', 'Ganfeng Lithium', '锂矿', '源头命脉')
+ ],
+ shi=[
+ StockEntity('002497.SZ', 'Yahua Industrial', '氢氧化锂', serves='CATL'),
+ StockEntity('002850.SZ', 'Kedali', '精密结构件', serves='CATL')
+ ],
+ jiajie=[
+ StockEntity('002594.SZ', 'BYD', '电动车', type='诸侯'),
+ StockEntity('VWAGY', 'Volkswagen', '传统车企', type='诸侯'),
+ StockEntity('F', 'Ford', '传统车企', type='诸侯')
+ ]
+ ),
+ 'Consumer_Electronics': EcosystemData(
+ tianzi={'symbol': 'AAPL', 'name': 'Apple', 'tianming': 'iOS + App Store生态系统'},
+ dafu=[
+ StockEntity('2317.TW', 'Foxconn', '代工制造', '物理执行者'),
+ StockEntity('TSM', 'TSMC', '芯片代工', '性能优势保障'),
+ StockEntity('005930.KS', 'Samsung Display', '屏幕供应', '显示技术'),
+ StockEntity('QCOM', 'Qualcomm', '基带芯片', '通信命脉')
+ ],
+ shi=[
+ StockEntity('002475.SZ', 'Luxshare', '精密制造', serves='Foxconn'),
+ StockEntity('002241.SZ', 'Goertek', '声学器件', serves='Foxconn')
+ ],
+ jiajie=[
+ StockEntity('005930.KS', 'Samsung', '手机制造', type='亦敌亦友天子'),
+ StockEntity('1810.HK', 'Xiaomi', '手机制造', type='诸侯'),
+ StockEntity('NVDA', 'NVIDIA', 'AI芯片', type='跨生态天子')
+ ]
+ )
+ }
+
+ def get_stock_data(self, symbol: str) -> Dict[str, Any]:
+ """
+ 获取股票数据
+
+ Args:
+ symbol: 股票代码
+
+ Returns:
+ 股票数据字典
+ """
+ # TODO: 实现真实API调用
+ # 目前使用模拟数据
+ try:
+ return {
+ 'price': round(random.uniform(50, 500), 2),
+ 'change_pct': round(random.uniform(-5, 5), 2),
+ 'market_cap': f"{random.randint(100, 3000)}B",
+ 'volume': random.randint(1000000, 100000000)
+ }
+ except Exception:
+ return {
+ 'price': 'N/A',
+ 'change_pct': 0,
+ 'market_cap': 'N/A',
+ 'volume': 'N/A'
+ }
+
+ def create_tianming_card(self, ecosystem_name: str, ecosystem_data: EcosystemData) -> None:
+ """
+ 创建天命卡片
+
+ Args:
+ ecosystem_name: 生态系统名称
+ ecosystem_data: 生态系统数据
+ """
+ tianzi = ecosystem_data.tianzi
+ stock_data = self.get_stock_data(tianzi['symbol'])
+
+ st.markdown(f"### 👑 {ecosystem_name} 天命树")
+
+ # 天子信息
+ col1, col2, col3 = st.columns([1, 2, 1])
+
+ with col1:
+ st.markdown("#### 🌟 天子")
+ st.markdown(f"**{tianzi['name']}** ({tianzi['symbol']})")
+
+ with col2:
+ st.markdown("#### 📜 天命")
+ st.info(tianzi['tianming'])
+
+ with col3:
+ st.metric(
+ label="股价",
+ value=f"${stock_data['price']}",
+ delta=f"{stock_data['change_pct']:+.2f}%"
+ )
+
+ # 大夫层级
+ if ecosystem_data.dafu:
+ st.markdown("#### 🏛️ 大夫 (核心依赖)")
+ dafu_cols = st.columns(min(len(ecosystem_data.dafu), 4))
+
+ for i, dafu in enumerate(ecosystem_data.dafu):
+ col_index = i % 4
+ with dafu_cols[col_index]:
+ data = self.get_stock_data(dafu.symbol)
+ st.metric(
+ label=f"{dafu.name}",
+ value=f"${data['price']}",
+ delta=f"{data['change_pct']:+.2f}%"
+ )
+ st.caption(f"**{dafu.role}**: {dafu.dependency}")
+
+ # 士层级
+ if ecosystem_data.shi:
+ st.markdown("#### ⚔️ 士 (专业供应商)")
+ shi_cols = st.columns(min(len(ecosystem_data.shi), 3))
+
+ for i, shi in enumerate(ecosystem_data.shi):
+ col_index = i % 3
+ with shi_cols[col_index]:
+ data = self.get_stock_data(shi.symbol)
+ st.metric(
+ label=f"{shi.name}",
+ value=f"${data['price']}",
+ delta=f"{data['change_pct']:+.2f}%"
+ )
+ st.caption(f"**{shi.role}** → 服务于{shi.serves}")
+
+ # 嫁接关系
+ if ecosystem_data.jiajie:
+ st.markdown("#### 🔗 嫁接关系 (跨生态链接)")
+ jiajie_cols = st.columns(min(len(ecosystem_data.jiajie), 4))
+
+ for i, jiajie in enumerate(ecosystem_data.jiajie):
+ col_index = i % 4
+ with jiajie_cols[col_index]:
+ data = self.get_stock_data(jiajie.symbol)
+ st.metric(
+ label=f"{jiajie.name}",
+ value=f"${data['price']}",
+ delta=f"{data['change_pct']:+.2f}%"
+ )
+ st.caption(f"**{jiajie.type}**")
+
+ st.markdown("---")
+
+ def create_tianming_tree_table(self) -> pd.DataFrame:
+ """
+ 创建天命树完整表格 - 用于投资组合去相关性分析
+
+ Returns:
+ 包含所有股票信息的DataFrame
+ """
+ st.markdown("### 📋 天命树完整表格 - 投资组合去相关性分析")
+ st.markdown("**核心理念**: 投资组合的本质是去相关性 - 从不同root下的不同spine下的不同leaf进行配置")
+
+ all_stocks = []
+
+ for eco_name, eco_data in self.ecosystems.items():
+ # 天子
+ tianzi = eco_data.tianzi
+ stock_data = self.get_stock_data(tianzi['symbol'])
+ all_stocks.append({
+ 'Root': eco_name,
+ 'Level': '👑 天子',
+ 'Symbol': tianzi['symbol'],
+ 'Company': tianzi['name'],
+ 'Role': '定义范式',
+ 'Dependency_Path': f"{eco_name}",
+ 'Price': stock_data['price'],
+ 'Change%': stock_data['change_pct'],
+ 'Market_Cap': stock_data['market_cap'],
+ 'Correlation_Risk': '极高 - 生态核心'
+ })
+
+ # 大夫
+ for dafu in eco_data.dafu:
+ stock_data = self.get_stock_data(dafu.symbol)
+ all_stocks.append({
+ 'Root': eco_name,
+ 'Level': '🏛️ 大夫',
+ 'Symbol': dafu.symbol,
+ 'Company': dafu.name,
+ 'Role': dafu.role,
+ 'Dependency_Path': f"{eco_name} → {tianzi['name']} → {dafu.name}",
+ 'Price': stock_data['price'],
+ 'Change%': stock_data['change_pct'],
+ 'Market_Cap': stock_data['market_cap'],
+ 'Correlation_Risk': '高 - 深度绑定天子'
+ })
+
+ # 士
+ for shi in eco_data.shi:
+ stock_data = self.get_stock_data(shi.symbol)
+ all_stocks.append({
+ 'Root': eco_name,
+ 'Level': '⚔️ 士',
+ 'Symbol': shi.symbol,
+ 'Company': shi.name,
+ 'Role': shi.role,
+ 'Dependency_Path': f"{eco_name} → {shi.serves} → {shi.name}",
+ 'Price': stock_data['price'],
+ 'Change%': stock_data['change_pct'],
+ 'Market_Cap': stock_data['market_cap'],
+ 'Correlation_Risk': '中 - 专业供应商'
+ })
+
+ # 嫁接
+ for jiajie in eco_data.jiajie:
+ stock_data = self.get_stock_data(jiajie.symbol)
+ all_stocks.append({
+ 'Root': '🔗 跨生态',
+ 'Level': '🔗 嫁接',
+ 'Symbol': jiajie.symbol,
+ 'Company': jiajie.name,
+ 'Role': jiajie.type or jiajie.role,
+ 'Dependency_Path': f"多生态嫁接 → {jiajie.name}",
+ 'Price': stock_data['price'],
+ 'Change%': stock_data['change_pct'],
+ 'Market_Cap': stock_data['market_cap'],
+ 'Correlation_Risk': '低 - 多元化依赖'
+ })
+
+ df = pd.DataFrame(all_stocks)
+
+ # 显示表格
+ st.dataframe(
+ df,
+ use_container_width=True,
+ column_config={
+ "Root": st.column_config.TextColumn("生态根节点", width="small"),
+ "Level": st.column_config.TextColumn("层级", width="small"),
+ "Symbol": st.column_config.TextColumn("代码", width="small"),
+ "Company": st.column_config.TextColumn("公司", width="medium"),
+ "Role": st.column_config.TextColumn("角色", width="medium"),
+ "Dependency_Path": st.column_config.TextColumn("依赖路径", width="large"),
+ "Price": st.column_config.NumberColumn("股价", format="$%.2f"),
+ "Change%": st.column_config.NumberColumn("涨跌幅", format="%.2f%%"),
+ "Market_Cap": st.column_config.TextColumn("市值", width="small"),
+ "Correlation_Risk": st.column_config.TextColumn("相关性风险", width="medium")
+ }
+ )
+
+ return df
+
+def render_tianxia_tab() -> None:
+ """渲染天下体系Tab"""
+
+ # 页面标题
+ st.markdown("### 🏛️ 天下体系 - 儒门天下观资本生态分析")
+ st.markdown("**基于'天命树'结构模型,穿透市场表象,绘制全球资本市场真实的权力结构**")
+ st.markdown("---")
+
+ # 初始化分析器
+ analyzer = TianxiaAnalyzer()
+
+ # 控制面板
+ col1, col2, col3 = st.columns([1, 1, 2])
+ with col1:
+ auto_refresh = st.checkbox("🔄 自动刷新", value=False, key="tianxia_auto_refresh")
+ with col2:
+ if st.button("🏛️ 扫描天下", type="primary", key="tianxia_scan_btn"):
+ st.session_state.trigger_tianxia_scan = True
+ with col3:
+ st.markdown("*正在分析全球资本生态权力结构...*")
+
+ # 理论介绍
+ with st.expander("📚 天命树理论基础"):
+ st.markdown("""
+ ### 🏛️ 儒门天下观核心思想
+
+ **两大哲学基石:**
+ 1. **结构非平权**: 资本宇宙本质是不平权的、层级森严的树状结构
+ 2. **天命与脉络**: 每个生态都有唯一的"根节点"(天子),拥有定义整个生态的"天命"
+
+ **四层架构:**
+ - **👑 天子**: 定义范式的平台型公司 (如Apple, NVIDIA, Tesla)
+ - **🏛️ 大夫**: 深度绑定天子的核心供应商 (如TSMC, CATL)
+ - **⚔️ 士**: 专业供应商和服务商 (如ASML, Luxshare)
+ - **🔗 嫁接**: 跨生态的策略性链接关系
+ """)
+
+ # 自动刷新逻辑
+ if auto_refresh:
+ time.sleep(60)
+ st.rerun()
+
+ # 触发扫描或显示数据
+ if st.session_state.get('trigger_tianxia_scan', False) or 'tianxia_scan_time' not in st.session_state:
+ with st.spinner("🏛️ 正在扫描天下体系..."):
+ st.session_state.tianxia_scan_time = datetime.now()
+ st.session_state.trigger_tianxia_scan = False
+
+ # 显示扫描时间
+ if 'tianxia_scan_time' in st.session_state:
+ st.info(f"📅 最后扫描时间: {st.session_state.tianxia_scan_time.strftime('%Y-%m-%d %H:%M:%S')}")
+
+ # 显示三大生态系统
+ st.markdown("## 🌍 三大天命树生态系统")
+
+ # 分析模式选择
+ analysis_mode = st.selectbox(
+ "选择分析模式",
+ ["生态系统分析", "投资组合去相关性分析"],
+ key="tianxia_analysis_mode"
+ )
+
+ if analysis_mode == "生态系统分析":
+ # 生态系统选择
+ selected_ecosystem = st.selectbox(
+ "选择要分析的生态系统",
+ ["全部", "AI", "EV", "Consumer_Electronics"],
+ format_func=lambda x: {
+ "全部": "🌍 全部生态系统",
+ "AI": "🤖 AI人工智能生态",
+ "EV": "⚡ 电动汽车生态",
+ "Consumer_Electronics": "📱 消费电子生态"
+ }[x],
+ key="tianxia_ecosystem_select"
+ )
+
+ if selected_ecosystem == "全部":
+ # 显示所有生态系统
+ for eco_name, eco_data in analyzer.ecosystems.items():
+ analyzer.create_tianming_card(eco_name, eco_data)
+ else:
+ # 显示选定的生态系统
+ analyzer.create_tianming_card(selected_ecosystem, analyzer.ecosystems[selected_ecosystem])
+
+ else: # 投资组合去相关性分析
+ st.markdown("## 🎯 投资组合去相关性分析")
+ st.info("**核心理念**: 真正的分散投资是从不同的root(天子)下的不同spine(大夫)下的不同leaf(士)进行配置")
+
+ # 创建完整天命树表格
+ df = analyzer.create_tianming_tree_table()
+
+ # 页面底部说明
+ st.markdown("---")
+ st.markdown("""
+ ### 🎯 天下体系核心洞察
+
+ **权力结构分析**:
+ - **AI生态**: NVIDIA通过CUDA平台统治AI计算,TSMC是关键"嫁接"节点
+ - **电动车生态**: Tesla定义软件汽车范式,CATL掌握电池命脉
+ - **消费电子生态**: Apple建立iOS护城河,供应链高度集中化
+
+ **投资策略启示**:
+ 1. **投资天子**: 寻找定义范式的平台型公司
+ 2. **关注大夫**: 深度绑定天子的核心供应商往往被低估
+ 3. **警惕嫁接**: 被多个天子"嫁接"的公司风险与机会并存
+ 4. **避开士层**: 缺乏议价能力的专业供应商投资价值有限
+
+ ⚠️ **免责声明**: 天下体系分析仅供参考,投资有风险,决策需谨慎!
+ """)
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/website/index.html b/modules/monitoring-dashboard/website/index.html
new file mode 100644
index 0000000..281a376
--- /dev/null
+++ b/modules/monitoring-dashboard/website/index.html
@@ -0,0 +1,283 @@
+
+
+
+
+
+ AI Agent协作框架 - 真实的多Agent协作系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 从模拟到真实
+ 让每个AI Agent都拥有独立Git身份
+
+
+ 不是让AI Agent假装协作,而是让每个Agent都有真实的Git身份:
+ 独立的SSH密钥、GPG签名、用户名和邮箱,实现可追溯的团队协作历史
+
+
+
+
+
+
+
+ 4
+ 预定义Agent
+
+
+ 100%
+ 真实Git提交
+
+
+ 一键
+ 快速启动
+
+
+
+
+
+
+
+
+ $
+ ./agents/switch_agent.sh claude-ai
+
+
+ claude-ai@framework
+ git commit -m "设计系统架构"
+
+
+ $
+ ./agents/switch_agent.sh gemini-dev
+
+
+ gemini-dev@framework
+ git commit -m "实现核心功能"
+
+
+ ✅ 真实的协作历史已创建
+
+
+
+
+
+
+
+
+
+
+
核心特性
+
+
+
🔐
+
真实身份系统
+
每个Agent拥有独立的SSH密钥、GPG签名和Git配置,确保每次提交都可追溯到具体Agent
+
+ - 独立SSH密钥对
+ - GPG签名验证
+ - 独立Git配置
+ - 完整审计日志
+
+
+
+
🎭
+
专业化角色
+
预定义四种专业化Agent角色,每个都有明确的责任边界和专长领域
+
+
+ claude-ai - 架构师
+
+
+ gemini-dev - 开发者
+
+
+ qwen-ops - 运维
+
+
+ llama-research - 研究员
+
+
+
+
+
📊
+
实时协作监控
+
实时查看所有Agent的协作状态、提交统计和代码贡献分析
+
+
+
+
+
+
+
+
+
+
实时演示
+
+
+
+
+
+
+
+
+
+
+
+
快速开始
+
+
+
🚀 一键安装
+
+
curl -fsSL https://raw.githubusercontent.com/your-org/agent-collaboration-framework/main/install.sh | bash
+
+
+
+
📦 手动安装
+
+
git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+./install.sh
+
+
+
+
🐳 Docker
+
+
docker run -it -v $(pwd):/workspace agent-collaboration:latest
+
+
+
+
+
+
+
+
+
+
文档中心
+
+
+
📚 快速入门
+
从零开始了解AI Agent协作框架
+
开始阅读 →
+
+
+
🏗️ 架构指南
+
深入理解系统架构和设计原理
+
查看详情 →
+
+
+
🔧 API文档
+
完整的API参考和开发指南
+
浏览API →
+
+
+
🎯 使用案例
+
真实场景下的使用示例和最佳实践
+
查看案例 →
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/website/script.js b/modules/monitoring-dashboard/website/script.js
new file mode 100644
index 0000000..7cef74c
--- /dev/null
+++ b/modules/monitoring-dashboard/website/script.js
@@ -0,0 +1,345 @@
+// 全局变量
+let agents = [
+ { id: 'code-reviewer', name: 'Code Reviewer', status: 'active', commits: 12, tasks: 3 },
+ { id: 'test-runner', name: 'Test Runner', status: 'active', commits: 8, tasks: 5 },
+ { id: 'deploy-bot', name: 'Deploy Bot', status: 'inactive', commits: 3, tasks: 0 },
+ { id: 'doc-writer', name: 'Doc Writer', status: 'active', commits: 15, tasks: 2 }
+];
+
+let activities = [
+ { type: 'commit', message: 'Code Reviewer pushed 3 new commits', time: '2 minutes ago' },
+ { type: 'test', message: 'Test Runner completed 5 test cases', time: '5 minutes ago' },
+ { type: 'deploy', message: 'Deploy Bot deployed to staging', time: '10 minutes ago' },
+ { type: 'docs', message: 'Doc Writer updated API documentation', time: '15 minutes ago' }
+];
+
+// 初始化
+document.addEventListener('DOMContentLoaded', function() {
+ initializeDemo();
+ initializeTerminal();
+ initializeStats();
+ setupScrollEffects();
+});
+
+// 演示区域初始化
+function initializeDemo() {
+ updateAgentGrid();
+ updateActivityFeed();
+
+ // 每3秒更新一次演示数据
+ setInterval(updateDemoData, 3000);
+}
+
+// 更新代理网格
+function updateAgentGrid() {
+ const grid = document.getElementById('agent-grid');
+ if (!grid) return;
+
+ grid.innerHTML = '';
+ agents.forEach(agent => {
+ const card = createAgentCard(agent);
+ grid.appendChild(card);
+ });
+}
+
+// 创建代理卡片
+function createAgentCard(agent) {
+ const card = document.createElement('div');
+ card.className = `agent-card agent-status-${agent.status}`;
+
+ const statusIcon = agent.status === 'active' ? '🟢' : '🔴';
+
+ card.innerHTML = `
+
+
${agent.name}
+
+ ${statusIcon} ${agent.status}
+
+
+
+
📊 ${agent.commits} commits
+
📝 ${agent.tasks} tasks
+
+ `;
+
+ return card;
+}
+
+// 更新活动流
+function updateActivityFeed() {
+ const feed = document.getElementById('activity-feed');
+ if (!feed) return;
+
+ feed.innerHTML = '';
+ activities.forEach(activity => {
+ const item = createActivityItem(activity);
+ feed.appendChild(item);
+ });
+}
+
+// 创建活动项
+function createActivityItem(activity) {
+ const item = document.createElement('div');
+ item.className = 'activity-item';
+
+ const icon = getActivityIcon(activity.type);
+
+ item.innerHTML = `
+
+ ${icon}
+ ${activity.message}
+
+
+ ${activity.time}
+
+ `;
+
+ return item;
+}
+
+// 获取活动图标
+function getActivityIcon(type) {
+ const icons = {
+ 'commit': '💻',
+ 'test': '🧪',
+ 'deploy': '🚀',
+ 'docs': '📚'
+ };
+ return icons[type] || '📝';
+}
+
+// 更新演示数据
+function updateDemoData() {
+ // 随机更新代理状态
+ agents.forEach(agent => {
+ if (Math.random() > 0.7) {
+ agent.status = agent.status === 'active' ? 'inactive' : 'active';
+ }
+ if (Math.random() > 0.5) {
+ agent.commits += Math.floor(Math.random() * 3);
+ }
+ });
+
+ // 添加新活动
+ const newActivity = generateRandomActivity();
+ activities.unshift(newActivity);
+ if (activities.length > 5) {
+ activities.pop();
+ }
+
+ updateAgentGrid();
+ updateActivityFeed();
+ updateStats();
+}
+
+// 生成随机活动
+function generateRandomActivity() {
+ const types = ['commit', 'test', 'deploy', 'docs'];
+ const messages = {
+ 'commit': ['Code Reviewer pushed new features', 'Test Runner fixed bugs', 'Deploy Bot merged PR'],
+ 'test': ['Test Runner passed all tests', 'Code Reviewer added unit tests', 'Doc Writer tested examples'],
+ 'deploy': ['Deploy Bot deployed to production', 'Code Reviewer released v2.0', 'Test Runner deployed hotfix'],
+ 'docs': ['Doc Writer updated README', 'Code Reviewer improved comments', 'Deploy Bot added changelog']
+ };
+
+ const type = types[Math.floor(Math.random() * types.length)];
+ const message = messages[type][Math.floor(Math.random() * messages[type].length)];
+
+ return {
+ type: type,
+ message: message,
+ time: 'just now'
+ };
+}
+
+// 终端模拟
+function initializeTerminal() {
+ const terminal = document.getElementById('terminal-content');
+ if (!terminal) return;
+
+ const commands = [
+ { prompt: 'user@spore-colony:~$', command: 'spore init', output: '✓ Initializing Spore Colony...\n✓ Creating agent identities...\n✓ Setting up Git repositories...\n✓ Spore Colony initialized successfully!' },
+ { prompt: 'user@spore-colony:~$', command: 'spore agent list', output: '🟢 code-reviewer (Active)\n🟢 test-runner (Active)\n🔴 deploy-bot (Inactive)\n🟢 doc-writer (Active)' },
+ { prompt: 'user@spore-colony:~$', command: 'spore task create "Add new feature"', output: '✓ Task created and assigned to code-reviewer\n📊 Progress: 0% → 25% → 50% → 75% → 100%\n✅ Task completed successfully!' }
+ ];
+
+ let currentCommand = 0;
+
+ function typeCommand() {
+ if (currentCommand >= commands.length) return;
+
+ const cmd = commands[currentCommand];
+ const line = document.createElement('div');
+ line.className = 'terminal-line';
+ line.innerHTML = `${cmd.prompt} ${cmd.command}`;
+ terminal.appendChild(line);
+
+ setTimeout(() => {
+ const outputLine = document.createElement('div');
+ outputLine.className = 'terminal-line';
+ outputLine.innerHTML = `${cmd.output}`;
+ terminal.appendChild(outputLine);
+
+ currentCommand++;
+ if (currentCommand < commands.length) {
+ setTimeout(typeCommand, 2000);
+ }
+ }, 1500);
+ }
+
+ typeCommand();
+}
+
+// 统计信息
+function initializeStats() {
+ updateStats();
+}
+
+function updateStats() {
+ const totalCommits = agents.reduce((sum, agent) => sum + agent.commits, 0);
+ const activeAgents = agents.filter(agent => agent.status === 'active').length;
+ const totalTasks = agents.reduce((sum, agent) => sum + agent.tasks, 0);
+
+ animateCounter('total-commits', totalCommits);
+ animateCounter('active-agents', activeAgents);
+ animateCounter('total-tasks', totalTasks);
+
+ updateProgressBars();
+}
+
+// 数字动画
+function animateCounter(elementId, targetValue) {
+ const element = document.getElementById(elementId);
+ if (!element) return;
+
+ const startValue = parseInt(element.textContent) || 0;
+ const duration = 1000;
+ const startTime = performance.now();
+
+ function updateCounter(currentTime) {
+ const elapsed = currentTime - startTime;
+ const progress = Math.min(elapsed / duration, 1);
+
+ const currentValue = Math.floor(startValue + (targetValue - startValue) * progress);
+ element.textContent = currentValue;
+
+ if (progress < 1) {
+ requestAnimationFrame(updateCounter);
+ }
+ }
+
+ requestAnimationFrame(updateCounter);
+}
+
+// 进度条更新
+function updateProgressBars() {
+ const progressBars = document.querySelectorAll('.bar div');
+ progressBars.forEach(bar => {
+ const width = Math.floor(Math.random() * 30) + 70; // 70-100%
+ bar.style.width = width + '%';
+ });
+}
+
+// 滚动效果
+function setupScrollEffects() {
+ const observerOptions = {
+ threshold: 0.1,
+ rootMargin: '0px 0px -50px 0px'
+ };
+
+ const observer = new IntersectionObserver((entries) => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting) {
+ entry.target.classList.add('animate-in');
+ }
+ });
+ }, observerOptions);
+
+ // 观察所有需要动画的元素
+ document.querySelectorAll('.feature-card, .demo-panel, .install-card, .doc-card').forEach(el => {
+ observer.observe(el);
+ });
+}
+
+// 平滑滚动到锚点
+document.querySelectorAll('a[href^="#"]').forEach(anchor => {
+ anchor.addEventListener('click', function (e) {
+ e.preventDefault();
+ const target = document.querySelector(this.getAttribute('href'));
+ if (target) {
+ target.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start'
+ });
+ }
+ });
+});
+
+// 响应式菜单
+function toggleMobileMenu() {
+ const navMenu = document.querySelector('.nav-menu');
+ navMenu.classList.toggle('active');
+}
+
+// 复制代码功能
+function copyToClipboard(elementId) {
+ const element = document.getElementById(elementId);
+ if (!element) return;
+
+ const text = element.textContent;
+ navigator.clipboard.writeText(text).then(() => {
+ // 显示复制成功提示
+ const toast = document.createElement('div');
+ toast.textContent = 'Copied to clipboard!';
+ toast.style.cssText = `
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ background: #27ca3f;
+ color: white;
+ padding: 1rem;
+ border-radius: 0.5rem;
+ z-index: 1000;
+ animation: slideIn 0.3s ease;
+ `;
+
+ document.body.appendChild(toast);
+ setTimeout(() => {
+ toast.remove();
+ }, 2000);
+ });
+}
+
+// 添加CSS动画
+const style = document.createElement('style');
+style.textContent = `
+ @keyframes slideIn {
+ from {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ }
+
+ .animate-in {
+ animation: fadeInUp 0.6s ease forwards;
+ }
+
+ @media (max-width: 768px) {
+ .nav-menu.active {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ background: white;
+ padding: 1rem;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+ }
+ }
+`;
+document.head.appendChild(style);
\ No newline at end of file
diff --git a/modules/monitoring-dashboard/website/styles.css b/modules/monitoring-dashboard/website/styles.css
new file mode 100644
index 0000000..ef65338
--- /dev/null
+++ b/modules/monitoring-dashboard/website/styles.css
@@ -0,0 +1,659 @@
+/* Reset and Base Styles */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ line-height: 1.6;
+ color: #333;
+ background: #fafafa;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+/* Navigation */
+.navbar {
+ position: fixed;
+ top: 0;
+ width: 100%;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(10px);
+ border-bottom: 1px solid #e0e0e0;
+ z-index: 1000;
+ transition: all 0.3s ease;
+}
+
+.nav-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 1rem 2rem;
+}
+
+.logo-text {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: #2563eb;
+}
+
+.nav-menu {
+ display: flex;
+ list-style: none;
+ gap: 2rem;
+}
+
+.nav-menu a {
+ text-decoration: none;
+ color: #333;
+ font-weight: 500;
+ transition: color 0.3s ease;
+}
+
+.nav-menu a:hover {
+ color: #2563eb;
+}
+
+.github-link {
+ background: #2563eb;
+ color: white !important;
+ padding: 0.5rem 1rem;
+ border-radius: 0.5rem;
+ transition: background 0.3s ease;
+}
+
+.github-link:hover {
+ background: #1d4ed8;
+}
+
+.hamburger {
+ display: none;
+ flex-direction: column;
+ cursor: pointer;
+}
+
+.hamburger span {
+ width: 25px;
+ height: 3px;
+ background: #333;
+ margin: 3px 0;
+ transition: 0.3s;
+}
+
+/* Hero Section */
+.hero {
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ padding: 6rem 0 4rem;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+}
+
+.hero-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4rem;
+ align-items: center;
+}
+
+.hero-title {
+ font-size: 3.5rem;
+ font-weight: 700;
+ line-height: 1.2;
+ margin-bottom: 1.5rem;
+}
+
+.gradient-text {
+ background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.hero-subtitle {
+ font-size: 1.25rem;
+ margin-bottom: 2rem;
+ opacity: 0.9;
+ line-height: 1.6;
+}
+
+.hero-buttons {
+ display: flex;
+ gap: 1rem;
+ margin-bottom: 3rem;
+}
+
+.btn {
+ padding: 1rem 2rem;
+ border: none;
+ border-radius: 0.5rem;
+ font-size: 1rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+ display: inline-block;
+}
+
+.btn-primary {
+ background: #ff6b6b;
+ color: white;
+}
+
+.btn-primary:hover {
+ background: #ff5252;
+ transform: translateY(-2px);
+}
+
+.btn-secondary {
+ background: transparent;
+ color: white;
+ border: 2px solid white;
+}
+
+.btn-secondary:hover {
+ background: white;
+ color: #667eea;
+}
+
+.hero-stats {
+ display: flex;
+ gap: 2rem;
+}
+
+.stat {
+ text-align: center;
+}
+
+.stat-number {
+ display: block;
+ font-size: 2rem;
+ font-weight: 700;
+ color: #ff6b6b;
+}
+
+.stat-label {
+ font-size: 0.9rem;
+ opacity: 0.8;
+}
+
+/* Terminal Window */
+.terminal-window {
+ background: #1a1a1a;
+ border-radius: 1rem;
+ overflow: hidden;
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
+}
+
+.terminal-header {
+ background: #2d2d2d;
+ padding: 1rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.terminal-buttons {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.terminal-buttons span {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+}
+
+.terminal-buttons span:nth-child(1) { background: #ff5f56; }
+.terminal-buttons span:nth-child(2) { background: #ffbd2e; }
+.terminal-buttons span:nth-child(3) { background: #27ca3f; }
+
+.terminal-title {
+ flex: 1;
+ text-align: center;
+ color: #888;
+ font-size: 0.9rem;
+}
+
+.terminal-content {
+ padding: 1.5rem;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 0.9rem;
+ line-height: 1.6;
+}
+
+.terminal-line {
+ margin-bottom: 0.5rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.prompt {
+ color: #27ca3f;
+}
+
+.command {
+ color: #fff;
+}
+
+.success {
+ color: #27ca3f;
+}
+
+/* Features Section */
+.features {
+ padding: 6rem 0;
+ background: white;
+}
+
+.section-title {
+ text-align: center;
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 3rem;
+ color: #333;
+}
+
+.features-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
+ gap: 3rem;
+}
+
+.feature-card {
+ background: white;
+ border-radius: 1rem;
+ padding: 2.5rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
+}
+
+.feature-card:hover {
+ transform: translateY(-5px);
+}
+
+.feature-icon {
+ font-size: 3rem;
+ margin-bottom: 1rem;
+}
+
+.feature-card h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.feature-card p {
+ color: #666;
+ margin-bottom: 1.5rem;
+ line-height: 1.6;
+}
+
+.feature-card ul {
+ list-style: none;
+}
+
+.feature-card li {
+ padding: 0.25rem 0;
+ color: #555;
+}
+
+.feature-card li:before {
+ content: "✓";
+ color: #27ca3f;
+ font-weight: bold;
+ margin-right: 0.5rem;
+}
+
+.roles-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.role-item {
+ padding: 0.5rem;
+ background: #f8f9fa;
+ border-radius: 0.5rem;
+ font-size: 0.9rem;
+}
+
+/* Demo Section */
+.demo {
+ padding: 6rem 0;
+ background: #f8f9fa;
+}
+
+.demo-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 3rem;
+}
+
+.demo-panel {
+ background: white;
+ border-radius: 1rem;
+ padding: 2rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+}
+
+.demo-panel h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1.5rem;
+ color: #333;
+}
+
+.agent-grid {
+ display: grid;
+ gap: 1rem;
+}
+
+.agent-card {
+ padding: 1rem;
+ background: #f8f9fa;
+ border-radius: 0.5rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.agent-status-active {
+ border-left: 4px solid #27ca3f;
+}
+
+.agent-status-inactive {
+ border-left: 4px solid #ff5f56;
+}
+
+.activity-feed {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.activity-item {
+ padding: 1rem;
+ background: #f8f9fa;
+ border-radius: 0.5rem;
+ border-left: 4px solid #667eea;
+}
+
+.demo-actions {
+ text-align: center;
+ margin-top: 2rem;
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+}
+
+/* Quick Start Section */
+.quick-start {
+ padding: 6rem 0;
+ background: white;
+}
+
+.install-options {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+}
+
+.install-card {
+ background: white;
+ border-radius: 1rem;
+ padding: 2rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ border: 1px solid #e0e0e0;
+}
+
+.install-card h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.code-block {
+ background: #1a1a1a;
+ border-radius: 0.5rem;
+ padding: 1rem;
+ overflow-x: auto;
+}
+
+.code-block pre {
+ margin: 0;
+ color: #fff;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 0.9rem;
+}
+
+/* Documentation Section */
+.documentation {
+ padding: 6rem 0;
+ background: #f8f9fa;
+}
+
+.docs-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+}
+
+.doc-card {
+ background: white;
+ border-radius: 1rem;
+ padding: 2rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
+}
+
+.doc-card:hover {
+ transform: translateY(-5px);
+}
+
+.doc-card h3 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.doc-card p {
+ color: #666;
+ margin-bottom: 1rem;
+}
+
+.doc-link {
+ color: #2563eb;
+ text-decoration: none;
+ font-weight: 600;
+}
+
+.doc-link:hover {
+ text-decoration: underline;
+}
+
+/* Footer */
+.footer {
+ background: #1a1a1a;
+ color: white;
+ padding: 3rem 0 1rem;
+}
+
+.footer-content {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+.footer-section h4 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+}
+
+.footer-section ul {
+ list-style: none;
+}
+
+.footer-section ul li {
+ margin-bottom: 0.5rem;
+}
+
+.footer-section a {
+ color: #ccc;
+ text-decoration: none;
+ transition: color 0.3s ease;
+}
+
+.footer-section a:hover {
+ color: white;
+}
+
+.footer-bottom {
+ text-align: center;
+ padding-top: 2rem;
+ border-top: 1px solid #333;
+ color: #888;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .hamburger {
+ display: flex;
+ }
+
+ .nav-menu {
+ display: none;
+ }
+
+ .hero-container {
+ grid-template-columns: 1fr;
+ text-align: center;
+ }
+
+ .hero-title {
+ font-size: 2.5rem;
+ }
+
+ .hero-buttons {
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .features-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .demo-container {
+ grid-template-columns: 1fr;
+ }
+
+ .install-options {
+ grid-template-columns: 1fr;
+ }
+
+ .docs-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (max-width: 480px) {
+ .hero-title {
+ font-size: 2rem;
+ }
+
+ .hero-stats {
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .container {
+ padding: 0 1rem;
+ }
+}
+
+/* Animations */
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.feature-card {
+ animation: fadeInUp 0.6s ease forwards;
+}
+
+.feature-card:nth-child(2) {
+ animation-delay: 0.1s;
+}
+
+.feature-card:nth-child(3) {
+ animation-delay: 0.2s;
+}
+
+/* Stats Animation */
+.stats-preview {
+ margin-top: 1rem;
+}
+
+.stat-bar {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin-bottom: 0.5rem;
+}
+
+.stat-bar span {
+ font-size: 0.9rem;
+ min-width: 80px;
+}
+
+.bar {
+ flex: 1;
+ height: 8px;
+ background: #e0e0e0;
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.bar div {
+ height: 100%;
+ background: linear-gradient(90deg, #667eea, #764ba2);
+ transition: width 1s ease;
+}
+
+/* Scrollbar Styling */
+::-webkit-scrollbar {
+ width: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: #f1f1f1;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #888;
+ border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #555;
+}
\ No newline at end of file
diff --git a/modules/testing-framework/pytest.ini b/modules/testing-framework/pytest.ini
new file mode 100644
index 0000000..9737aa6
--- /dev/null
+++ b/modules/testing-framework/pytest.ini
@@ -0,0 +1,6 @@
+[pytest]
+testpaths = tests
+python_files = test_*.py
+python_classes = Test*
+python_functions = test_*
+addopts = --cov=src --cov-report=html --cov-report=term-missing --asyncio-mode=auto
diff --git a/modules/testing-framework/tests/immortal_tests/test_cultural_accuracy.py b/modules/testing-framework/tests/immortal_tests/test_cultural_accuracy.py
new file mode 100644
index 0000000..5f620d4
--- /dev/null
+++ b/modules/testing-framework/tests/immortal_tests/test_cultural_accuracy.py
@@ -0,0 +1,24 @@
+class TestCulturalAccuracy:
+ """文化准确性测试"""
+
+ def test_immortal_characteristics(self):
+ """验证八仙特征的准确性"""
+ # immortals = get_immortal_configs()
+ #
+ # # 验证吕洞宾的技术分析特色
+ # assert immortals['吕洞宾'].specialty == 'technical_analysis'
+ # assert immortals['吕洞宾'].element == '乾'
+ #
+ # # 验证何仙姑的风险控制特色
+ # assert immortals['何仙姑'].specialty == 'risk_metrics'
+ # assert immortals['何仙姑'].element == '坤'
+ pass
+
+ def test_debate_cultural_context(self):
+ """验证辩论的文化背景准确性"""
+ # debate = create_test_debate('AAPL')
+ #
+ # # 确保辩论遵循稷下学宫的传统
+ # assert 'jixia' in debate.context
+ # assert len(debate.participants) == 8 # 八仙
+ pass
diff --git a/modules/testing-framework/tests/immortal_tests/test_debate_data_quality.py b/modules/testing-framework/tests/immortal_tests/test_debate_data_quality.py
new file mode 100644
index 0000000..82cbcaa
--- /dev/null
+++ b/modules/testing-framework/tests/immortal_tests/test_debate_data_quality.py
@@ -0,0 +1,3 @@
+class TestDebateDataQuality:
+ """辩论数据质量测试"""
+ pass
diff --git a/modules/testing-framework/tests/immortal_tests/test_immortal_data_routing.py b/modules/testing-framework/tests/immortal_tests/test_immortal_data_routing.py
new file mode 100644
index 0000000..873a8d0
--- /dev/null
+++ b/modules/testing-framework/tests/immortal_tests/test_immortal_data_routing.py
@@ -0,0 +1,14 @@
+class TestImmortalDataRouting:
+ """八仙数据路由测试"""
+
+ def test_lv_dongbin_technical_analysis(self):
+ """测试吕洞宾的技术分析数据获取"""
+ pass
+
+ def test_he_xiangu_risk_metrics(self):
+ """测试何仙姑的风险指标数据"""
+ pass
+
+ def test_immortal_data_consistency(self):
+ """测试八仙数据的一致性"""
+ pass
diff --git a/modules/testing-framework/tests/immortal_tests/test_immortal_preferences.py b/modules/testing-framework/tests/immortal_tests/test_immortal_preferences.py
new file mode 100644
index 0000000..7dbefb7
--- /dev/null
+++ b/modules/testing-framework/tests/immortal_tests/test_immortal_preferences.py
@@ -0,0 +1,3 @@
+class TestImmortalPreferences:
+ """八仙偏好测试"""
+ pass
diff --git a/modules/testing-framework/tests/openbb_integration/test_openbb_integration.py b/modules/testing-framework/tests/openbb_integration/test_openbb_integration.py
new file mode 100644
index 0000000..1e5e624
--- /dev/null
+++ b/modules/testing-framework/tests/openbb_integration/test_openbb_integration.py
@@ -0,0 +1,62 @@
+import pytest
+from unittest import mock
+from src.jixia.engines.openbb_stock_data import get_stock_data
+from types import SimpleNamespace
+
+class TestOpenBBIntegration:
+ """OpenBB集成测试套件"""
+
+ def test_stock_data_retrieval(self):
+ """测试股票数据成功获取"""
+ # 创建一个模拟的'openbb'模块
+ mock_openbb_module = mock.MagicMock()
+ # 在该模块上创建一个模拟的'obb'属性
+ mock_obb_object = mock.MagicMock()
+ mock_openbb_module.obb = mock_obb_object
+
+ # 配置模拟的obb对象的返回值
+ mock_data = [
+ SimpleNamespace(date='2023-01-01', open=100, high=110, low=90, close=105, volume=10000),
+ SimpleNamespace(date='2023-01-02', open=105, high=115, low=102, close=112, volume=12000)
+ ]
+ mock_obb_object.equity.price.historical.return_value = SimpleNamespace(results=mock_data)
+
+ # 使用patch.dict来模拟openbb模块的导入
+ with mock.patch.dict('sys.modules', {'openbb': mock_openbb_module}):
+ data = get_stock_data('AAPL')
+
+ # 断言
+ assert data is not None
+ assert len(data) == 2
+ assert data[0].close == 105
+ mock_obb_object.equity.price.historical.assert_called_once()
+
+ def test_stock_data_handles_api_error(self):
+ """测试当OpenBB API未返回有效数据时的情况"""
+ mock_openbb_module = mock.MagicMock()
+ mock_obb_object = mock.MagicMock()
+ mock_openbb_module.obb = mock_obb_object
+
+ # 配置模拟的obb对象以返回没有结果的情况
+ mock_obb_object.equity.price.historical.return_value = SimpleNamespace(results=None)
+
+ with mock.patch.dict('sys.modules', {'openbb': mock_openbb_module}):
+ data = get_stock_data('FAIL')
+
+ # 断言
+ assert data is None
+ mock_obb_object.equity.price.historical.assert_called_once_with(
+ symbol='FAIL',
+ provider='yfinance',
+ start_date=mock.ANY,
+ end_date=mock.ANY
+ )
+
+ def test_stock_data_handles_import_error(self):
+ """测试openbb库不可用时的降级行为"""
+ # 模拟sys.modules中没有openbb
+ with mock.patch.dict('sys.modules', {'openbb': None}):
+ data = get_stock_data('NOBB')
+
+ # 断言
+ assert data is None
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test-api-example.js b/modules/testing-framework/tests/test-api-example.js
new file mode 100644
index 0000000..ff87daa
--- /dev/null
+++ b/modules/testing-framework/tests/test-api-example.js
@@ -0,0 +1,299 @@
+// API 测试示例脚本
+// 演示如何使用 Hyperdrive API 进行 CRUD 操作
+
+const API_BASE_URL = 'https://hyperdrive-neondb-test..workers.dev';
+const API_KEY = 'your-api-key'; // 可选,如果设置了 API_SECRET
+
+// 通用请求函数
+async function apiRequest(endpoint, options = {}) {
+ const url = `${API_BASE_URL}${endpoint}`;
+ const headers = {
+ 'Content-Type': 'application/json',
+ ...(API_KEY && { 'X-API-Key': API_KEY }),
+ ...options.headers
+ };
+
+ try {
+ const response = await fetch(url, {
+ ...options,
+ headers
+ });
+
+ const data = await response.json();
+
+ if (!response.ok) {
+ throw new Error(`API Error: ${data.message || response.statusText}`);
+ }
+
+ return data;
+ } catch (error) {
+ console.error(`Request failed for ${endpoint}:`, error.message);
+ throw error;
+ }
+}
+
+// API 测试函数
+class ApiTester {
+ static async testHealthCheck() {
+ console.log('\n🏥 Testing health check...');
+ try {
+ const result = await apiRequest('/health');
+ console.log('✅ Health check passed:', result.data);
+ return true;
+ } catch (error) {
+ console.log('❌ Health check failed:', error.message);
+ return false;
+ }
+ }
+
+ static async initializeDatabase() {
+ console.log('\n🗄️ Initializing database...');
+ try {
+ const result = await apiRequest('/init', { method: 'POST' });
+ console.log('✅ Database initialized:', result.message);
+ return true;
+ } catch (error) {
+ console.log('❌ Database initialization failed:', error.message);
+ return false;
+ }
+ }
+
+ static async createUser(name, email) {
+ console.log(`\n👤 Creating user: ${name} (${email})...`);
+ try {
+ const result = await apiRequest('/users', {
+ method: 'POST',
+ body: JSON.stringify({ name, email })
+ });
+ console.log('✅ User created:', result.data);
+ return result.data;
+ } catch (error) {
+ console.log('❌ User creation failed:', error.message);
+ return null;
+ }
+ }
+
+ static async getUsers(page = 1, limit = 10, search = null) {
+ console.log(`\n📋 Getting users (page ${page}, limit ${limit}${search ? `, search: ${search}` : ''})...`);
+ try {
+ let endpoint = `/users?page=${page}&limit=${limit}`;
+ if (search) endpoint += `&search=${encodeURIComponent(search)}`;
+
+ const result = await apiRequest(endpoint);
+ console.log('✅ Users retrieved:', {
+ count: result.data.length,
+ total: result.meta.total,
+ users: result.data.map(u => `${u.name} (${u.email})`)
+ });
+ return result;
+ } catch (error) {
+ console.log('❌ Failed to get users:', error.message);
+ return null;
+ }
+ }
+
+ static async getUserById(id) {
+ console.log(`\n🔍 Getting user by ID: ${id}...`);
+ try {
+ const result = await apiRequest(`/users/${id}`);
+ console.log('✅ User found:', result.data);
+ return result.data;
+ } catch (error) {
+ console.log('❌ Failed to get user:', error.message);
+ return null;
+ }
+ }
+
+ static async updateUser(id, updates) {
+ console.log(`\n✏️ Updating user ${id}:`, updates);
+ try {
+ const result = await apiRequest(`/users/${id}`, {
+ method: 'PUT',
+ body: JSON.stringify(updates)
+ });
+ console.log('✅ User updated:', result.data);
+ return result.data;
+ } catch (error) {
+ console.log('❌ Failed to update user:', error.message);
+ return null;
+ }
+ }
+
+ static async deleteUser(id) {
+ console.log(`\n🗑️ Deleting user ${id}...`);
+ try {
+ const result = await apiRequest(`/users/${id}`, { method: 'DELETE' });
+ console.log('✅ User deleted:', result.message);
+ return true;
+ } catch (error) {
+ console.log('❌ Failed to delete user:', error.message);
+ return false;
+ }
+ }
+
+ static async getApiDocs() {
+ console.log('\n📚 Getting API documentation...');
+ try {
+ const result = await apiRequest('/docs');
+ console.log('✅ API Documentation:');
+ console.log('Endpoints:', result.data.endpoints);
+ console.log('Authentication:', result.data.authentication);
+ console.log('Examples:', result.data.examples);
+ return result.data;
+ } catch (error) {
+ console.log('❌ Failed to get API docs:', error.message);
+ return null;
+ }
+ }
+}
+
+// 完整的测试流程
+async function runFullTest() {
+ console.log('🚀 Starting Hyperdrive API Test Suite');
+ console.log('=====================================');
+
+ // 1. 健康检查
+ const healthOk = await ApiTester.testHealthCheck();
+ if (!healthOk) {
+ console.log('\n❌ Health check failed. Please check your deployment.');
+ return;
+ }
+
+ // 2. 获取 API 文档
+ await ApiTester.getApiDocs();
+
+ // 3. 初始化数据库
+ await ApiTester.initializeDatabase();
+
+ // 4. 创建测试用户
+ const user1 = await ApiTester.createUser('张三', 'zhangsan@example.com');
+ const user2 = await ApiTester.createUser('李四', 'lisi@example.com');
+ const user3 = await ApiTester.createUser('王五', 'wangwu@example.com');
+
+ if (!user1 || !user2 || !user3) {
+ console.log('\n❌ Failed to create test users.');
+ return;
+ }
+
+ // 5. 获取用户列表
+ await ApiTester.getUsers();
+
+ // 6. 搜索用户
+ await ApiTester.getUsers(1, 10, '张');
+
+ // 7. 获取单个用户
+ await ApiTester.getUserById(user1.id);
+
+ // 8. 更新用户
+ await ApiTester.updateUser(user1.id, {
+ name: '张三丰',
+ email: 'zhangsanfeng@example.com'
+ });
+
+ // 9. 验证更新
+ await ApiTester.getUserById(user1.id);
+
+ // 10. 分页测试
+ await ApiTester.getUsers(1, 2); // 第一页,每页2条
+ await ApiTester.getUsers(2, 2); // 第二页,每页2条
+
+ // 11. 删除用户
+ await ApiTester.deleteUser(user3.id);
+
+ // 12. 验证删除
+ await ApiTester.getUserById(user3.id); // 应该返回 404
+
+ // 13. 最终用户列表
+ await ApiTester.getUsers();
+
+ console.log('\n🎉 API Test Suite Completed!');
+ console.log('============================');
+}
+
+// 性能测试
+async function performanceTest() {
+ console.log('\n⚡ Performance Test');
+ console.log('==================');
+
+ const startTime = Date.now();
+ const promises = [];
+
+ // 并发创建10个用户
+ for (let i = 0; i < 10; i++) {
+ promises.push(
+ ApiTester.createUser(`测试用户${i}`, `test${i}@example.com`)
+ );
+ }
+
+ try {
+ const results = await Promise.all(promises);
+ const endTime = Date.now();
+ const duration = endTime - startTime;
+
+ console.log(`✅ Created ${results.filter(r => r).length} users in ${duration}ms`);
+ console.log(`📊 Average: ${(duration / 10).toFixed(2)}ms per user`);
+
+ // 清理测试数据
+ console.log('\n🧹 Cleaning up test data...');
+ for (const user of results.filter(r => r)) {
+ await ApiTester.deleteUser(user.id);
+ }
+
+ } catch (error) {
+ console.log('❌ Performance test failed:', error.message);
+ }
+}
+
+// 错误处理测试
+async function errorHandlingTest() {
+ console.log('\n🚨 Error Handling Test');
+ console.log('======================');
+
+ // 测试无效数据
+ console.log('\n Testing invalid user data...');
+ await ApiTester.createUser('', 'invalid-email'); // 应该失败
+
+ // 测试不存在的用户
+ console.log('\n Testing non-existent user...');
+ await ApiTester.getUserById(99999); // 应该返回 404
+
+ // 测试无效的更新
+ console.log('\n Testing invalid update...');
+ await ApiTester.updateUser(99999, { name: 'Test' }); // 应该返回 404
+}
+
+// 主函数
+async function main() {
+ console.log('请确保已经部署了 Worker 并更新了 API_BASE_URL');
+ console.log('如果设置了 API_SECRET,请更新 API_KEY 变量\n');
+
+ try {
+ await runFullTest();
+ await performanceTest();
+ await errorHandlingTest();
+ } catch (error) {
+ console.error('\n💥 Test suite failed:', error.message);
+ }
+}
+
+// 如果直接运行此脚本
+if (typeof window === 'undefined') {
+ // Node.js 环境
+ const fetch = require('node-fetch');
+ global.fetch = fetch;
+ main();
+} else {
+ // 浏览器环境
+ console.log('在浏览器控制台中运行: main()');
+}
+
+// 导出函数供其他模块使用
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = {
+ ApiTester,
+ runFullTest,
+ performanceTest,
+ errorHandlingTest,
+ main
+ };
+}
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test-hyperdrive-remote.js b/modules/testing-framework/tests/test-hyperdrive-remote.js
new file mode 100644
index 0000000..03954e5
--- /dev/null
+++ b/modules/testing-framework/tests/test-hyperdrive-remote.js
@@ -0,0 +1,79 @@
+// Test script to validate Hyperdrive configuration for remote deployment
+// This script helps test the configuration without local PostgreSQL
+
+const { execSync } = require('child_process');
+const fs = require('fs');
+
+console.log('🚀 Testing Hyperdrive Configuration for Remote Deployment');
+console.log('======================================================');
+
+try {
+ // Check wrangler configuration
+ console.log('\n📋 Validating wrangler.toml...');
+
+ const wranglerContent = fs.readFileSync('wrangler.toml', 'utf8');
+ console.log('✅ wrangler.toml loaded successfully');
+
+ // Validate configuration syntax
+ try {
+ execSync('wrangler config validate', { stdio: 'pipe' });
+ console.log('✅ wrangler.toml syntax is valid');
+ } catch (error) {
+ console.log('⚠️ Configuration validation warning (this is normal for Hyperdrive)');
+ }
+
+ // Check if we can authenticate with Cloudflare
+ console.log('\n🔐 Checking Cloudflare authentication...');
+ try {
+ const whoami = execSync('wrangler whoami', { encoding: 'utf8' });
+ console.log('✅ Authenticated with Cloudflare');
+ console.log(` ${whoami.trim()}`);
+ } catch (error) {
+ console.log('❌ Not authenticated with Cloudflare');
+ console.log(' Run: wrangler login');
+ return;
+ }
+
+ // List Hyperdrive configurations
+ console.log('\n🔗 Checking Hyperdrive configurations...');
+ try {
+ const hyperdrives = execSync('wrangler hyperdrive list', { encoding: 'utf8' });
+ console.log('✅ Hyperdrive configurations:');
+ console.log(hyperdrives);
+ } catch (error) {
+ console.log('⚠️ Could not list Hyperdrive configurations');
+ console.log(' Error:', error.message);
+ }
+
+ // Check specific Hyperdrive
+ console.log('\n🎯 Checking specific Hyperdrive ID...');
+ try {
+ const hyperdriveInfo = execSync('wrangler hyperdrive get ef43924d89064cddabfaccf06aadfab6', { encoding: 'utf8' });
+ console.log('✅ Hyperdrive configuration found:');
+ console.log(hyperdriveInfo);
+ } catch (error) {
+ console.log('❌ Could not find Hyperdrive configuration');
+ console.log(' Error:', error.message);
+ console.log(' Make sure the Hyperdrive ID is correct and exists in your account');
+ }
+
+ console.log('\n📝 Configuration Summary:');
+ console.log(' - Worker Name: hyperdrive-neondb-test');
+ console.log(' - Hyperdrive ID: ef43924d89064cddabfaccf06aadfab6');
+ console.log(' - Binding: HYPERDRIVE');
+ console.log(' - Database Type: NeonDB (PostgreSQL)');
+
+ console.log('\n🚀 Deployment Commands:');
+ console.log(' 1. Deploy to production: wrangler deploy');
+ console.log(' 2. Test endpoints after deployment:');
+ console.log(' - https://hyperdrive-neondb-test..workers.dev/test-connection');
+ console.log(' - https://hyperdrive-neondb-test..workers.dev/test-query');
+
+ console.log('\n💡 Tips:');
+ console.log(' - Hyperdrive provides connection pooling and caching for your database');
+ console.log(' - It reduces latency and improves performance for database queries');
+ console.log(' - The worker will automatically use the Hyperdrive connection in production');
+
+} catch (error) {
+ console.error('❌ Error during testing:', error.message);
+}
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test-hyperdrive.js b/modules/testing-framework/tests/test-hyperdrive.js
new file mode 100644
index 0000000..349a2c4
--- /dev/null
+++ b/modules/testing-framework/tests/test-hyperdrive.js
@@ -0,0 +1,93 @@
+// Simple test script for Hyperdrive configuration
+// This script helps verify the wrangler.toml configuration
+
+console.log('🚀 Hyperdrive NeonDB Test Configuration');
+console.log('=====================================');
+
+// Check if wrangler.toml exists and has correct configuration
+const fs = require('fs');
+const path = require('path');
+
+try {
+ const wranglerPath = path.join(__dirname, 'wrangler.toml');
+
+ if (fs.existsSync(wranglerPath)) {
+ console.log('✅ wrangler.toml found');
+
+ const content = fs.readFileSync(wranglerPath, 'utf8');
+
+ // Check for Hyperdrive configuration
+ if (content.includes('hyperdrive')) {
+ console.log('✅ Hyperdrive configuration found');
+ } else {
+ console.log('❌ Hyperdrive configuration missing');
+ }
+
+ // Check for binding
+ if (content.includes('binding = "HYPERDRIVE"')) {
+ console.log('✅ HYPERDRIVE binding configured');
+ } else {
+ console.log('❌ HYPERDRIVE binding missing');
+ }
+
+ // Check for Hyperdrive ID
+ if (content.includes('ef43924d89064cddabfaccf06aadfab6')) {
+ console.log('✅ Hyperdrive ID configured');
+ } else {
+ console.log('❌ Hyperdrive ID missing');
+ }
+
+ // Check for nodejs_compat
+ if (content.includes('nodejs_compat')) {
+ console.log('✅ nodejs_compat flag enabled');
+ } else {
+ console.log('❌ nodejs_compat flag missing');
+ }
+
+ } else {
+ console.log('❌ wrangler.toml not found');
+ }
+
+ // Check if src/index.ts exists
+ const indexPath = path.join(__dirname, 'src', 'index.ts');
+ if (fs.existsSync(indexPath)) {
+ console.log('✅ src/index.ts found');
+ } else {
+ console.log('❌ src/index.ts missing');
+ }
+
+ // Check if package.json exists
+ const packagePath = path.join(__dirname, 'package.json');
+ if (fs.existsSync(packagePath)) {
+ console.log('✅ package.json found');
+
+ const packageContent = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
+
+ // Check for required dependencies
+ if (packageContent.dependencies && packageContent.dependencies.pg) {
+ console.log('✅ pg dependency configured');
+ } else {
+ console.log('❌ pg dependency missing');
+ }
+
+ if (packageContent.devDependencies && packageContent.devDependencies['@cloudflare/workers-types']) {
+ console.log('✅ Cloudflare Workers types configured');
+ } else {
+ console.log('❌ Cloudflare Workers types missing');
+ }
+ }
+
+ console.log('\n📋 Next Steps:');
+ console.log('1. Run: wrangler dev --local (for local testing)');
+ console.log('2. Run: wrangler dev (for remote testing with Hyperdrive)');
+ console.log('3. Test endpoints:');
+ console.log(' - http://localhost:8787/test-connection');
+ console.log(' - http://localhost:8787/test-query');
+ console.log('\n🔧 Hyperdrive Configuration:');
+ console.log(' - Hyperdrive ID: ef43924d89064cddabfaccf06aadfab6');
+ console.log(' - Binding: HYPERDRIVE');
+ console.log(' - Database: NeonDB (PostgreSQL)');
+
+} catch (error) {
+ console.error('❌ Error checking configuration:', error.message);
+}
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test-shushu-api.sh b/modules/testing-framework/tests/test-shushu-api.sh
new file mode 100755
index 0000000..bf49722
--- /dev/null
+++ b/modules/testing-framework/tests/test-shushu-api.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# 术数书 API 测试脚本
+# 使用 curl 命令测试 Hyperdrive + NeonDB 术数书查询系统
+
+API_BASE="https://hyperdrive.seekkey.tech"
+
+echo "🚀 术数书 Hyperdrive API 测试"
+echo "================================"
+
+# 测试连接
+echo ""
+echo "🔗 测试数据库连接..."
+curl -s "$API_BASE/test-connection" | jq -r '.message // .error // "连接测试完成"'
+
+# 查询表结构
+echo ""
+echo "📋 查询数据库表结构..."
+echo "发现的表:"
+curl -s "$API_BASE/query-tables" | jq -r '.tables[]? | "- \(.table_name) (\(.table_schema))"'
+
+# 获取术数书统计
+echo ""
+echo "📊 术数书统计信息..."
+curl -s "$API_BASE/shushu-stats" | jq -r '.existing_tables[]? | "- \(.table_name): \(.record_count) 条记录"'
+
+# 查询术数书内容
+echo ""
+echo "📚 查询术数书内容 (前3条)..."
+echo "书籍信息:"
+curl -s "$API_BASE/query-shushu?limit=3" | jq -r '.data[]? | "- ID: \(.id), 标题: \(.title), 作者: \(.author), 类别: \(.category)"'
+
+# 搜索功能测试
+echo ""
+echo "🔍 搜索测试..."
+echo "搜索关键词: 易经"
+curl -s "$API_BASE/search-shushu?q=易经&limit=2" | jq -r '.total_matches // 0 | "找到 \(.) 条匹配记录"'
+
+echo "搜索关键词: 八卦"
+curl -s "$API_BASE/search-shushu?q=八卦&limit=2" | jq -r '.total_matches // 0 | "找到 \(.) 条匹配记录"'
+
+echo "搜索关键词: 面相"
+curl -s "$API_BASE/search-shushu?q=面相&limit=2" | jq -r '.total_matches // 0 | "找到 \(.) 条匹配记录"'
+
+# 性能测试
+echo ""
+echo "⚡ 性能测试..."
+echo "测试查询响应时间:"
+time curl -s "$API_BASE/query-shushu?limit=1" > /dev/null
+
+echo ""
+echo "✅ API 测试完成!"
+echo ""
+echo "📖 可用端点:"
+echo "- GET $API_BASE/ - 系统信息"
+echo "- GET $API_BASE/test-connection - 测试连接"
+echo "- GET $API_BASE/query-tables - 查询表结构"
+echo "- GET $API_BASE/query-shushu?limit=N - 查询术数书"
+echo "- GET $API_BASE/search-shushu?q=keyword&limit=N - 搜索术数书"
+echo "- GET $API_BASE/shushu-stats - 统计信息"
+echo ""
+echo "🎯 与 AutoRAG 对比优势:"
+echo "- ✅ 毫秒级响应 (Hyperdrive 边缘缓存)"
+echo "- ✅ 精确查询 (SQL vs 向量相似性)"
+echo "- ✅ 实时数据 (直连数据库)"
+echo "- ✅ 成本优化 (连接池 + 缓存)"
+echo "- ✅ 全球分布 (Cloudflare 边缘网络)"
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_alpha_vantage_meta.py b/modules/testing-framework/tests/test_alpha_vantage_meta.py
new file mode 100644
index 0000000..193a288
--- /dev/null
+++ b/modules/testing-framework/tests/test_alpha_vantage_meta.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+"""
+Alpha Vantage API 测试脚本 - Meta (META) 财报和分析师评级
+"""
+
+import os
+import requests
+import json
+from datetime import datetime
+
+def get_alpha_vantage_key():
+ """从环境变量获取 Alpha Vantage API Key"""
+ api_key = os.getenv('ALPHA_VANTAGE_API_KEY')
+ if not api_key:
+ raise ValueError("未找到 ALPHA_VANTAGE_API_KEY 环境变量")
+ return api_key
+
+def get_company_overview(symbol, api_key):
+ """获取公司基本信息和财务概览"""
+ url = f"https://www.alphavantage.co/query"
+ params = {
+ 'function': 'OVERVIEW',
+ 'symbol': symbol,
+ 'apikey': api_key
+ }
+
+ response = requests.get(url, params=params)
+ return response.json()
+
+def get_earnings_data(symbol, api_key):
+ """获取财报数据"""
+ url = f"https://www.alphavantage.co/query"
+ params = {
+ 'function': 'EARNINGS',
+ 'symbol': symbol,
+ 'apikey': api_key
+ }
+
+ response = requests.get(url, params=params)
+ return response.json()
+
+def get_analyst_ratings(symbol, api_key):
+ """获取分析师评级(需要付费版本,这里尝试调用看是否有数据)"""
+ url = f"https://www.alphavantage.co/query"
+ params = {
+ 'function': 'ANALYST_RECOMMENDATIONS',
+ 'symbol': symbol,
+ 'apikey': api_key
+ }
+
+ response = requests.get(url, params=params)
+ return response.json()
+
+def get_income_statement(symbol, api_key):
+ """获取损益表"""
+ url = f"https://www.alphavantage.co/query"
+ params = {
+ 'function': 'INCOME_STATEMENT',
+ 'symbol': symbol,
+ 'apikey': api_key
+ }
+
+ response = requests.get(url, params=params)
+ return response.json()
+
+def format_financial_data(data, title):
+ """格式化财务数据输出"""
+ print(f"\n{'='*60}")
+ print(f"{title}")
+ print(f"{'='*60}")
+
+ if isinstance(data, dict):
+ if 'Error Message' in data:
+ print(f"❌ 错误: {data['Error Message']}")
+ elif 'Note' in data:
+ print(f"⚠️ 注意: {data['Note']}")
+ else:
+ print(json.dumps(data, indent=2, ensure_ascii=False))
+ else:
+ print(data)
+
+def main():
+ """主函数"""
+ try:
+ # 获取 API Key
+ api_key = get_alpha_vantage_key()
+ print(f"✅ 成功获取 Alpha Vantage API Key: {api_key[:8]}...")
+
+ symbol = "META" # Meta Platforms Inc.
+ print(f"\n🔍 正在获取 {symbol} 的财务数据...")
+
+ # 1. 公司概览
+ print("\n📊 获取公司概览...")
+ overview = get_company_overview(symbol, api_key)
+ format_financial_data(overview, f"{symbol} - 公司概览")
+
+ # 2. 财报数据
+ print("\n📈 获取财报数据...")
+ earnings = get_earnings_data(symbol, api_key)
+ format_financial_data(earnings, f"{symbol} - 财报数据")
+
+ # 3. 分析师评级
+ print("\n⭐ 获取分析师评级...")
+ ratings = get_analyst_ratings(symbol, api_key)
+ format_financial_data(ratings, f"{symbol} - 分析师评级")
+
+ # 4. 损益表
+ print("\n💰 获取损益表...")
+ income_statement = get_income_statement(symbol, api_key)
+ format_financial_data(income_statement, f"{symbol} - 损益表")
+
+ print(f"\n✅ {symbol} 数据获取完成!")
+ print(f"⏰ 完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+
+ except Exception as e:
+ print(f"❌ 错误: {str(e)}")
+ return 1
+
+ return 0
+
+if __name__ == "__main__":
+ exit(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_cloudflare_gemini.py b/modules/testing-framework/tests/test_cloudflare_gemini.py
new file mode 100644
index 0000000..ddcef44
--- /dev/null
+++ b/modules/testing-framework/tests/test_cloudflare_gemini.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+测试Cloudflare网关的Gemini API
+使用用户提供的新配置
+"""
+
+import requests
+import json
+import logging
+
+# 配置日志
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+logger = logging.getLogger(__name__)
+
+def test_cloudflare_gemini():
+ """测试Cloudflare网关的Gemini API"""
+
+ # 用户提供的新配置
+ API_KEY = "AIzaSyAQ2TXFAzmTKm4aFqgrjkhjgsp95bDsAyE"
+ BASE_URL = "https://gateway.ai.cloudflare.com/v1/e167cb36a5b95cb3cc8daf77a3f7d0b3/default/google-ai-studio"
+ MODEL = "models/gemini-2.5-pro"
+
+ logger.info(f"🧪 测试Cloudflare Gemini配置:")
+ logger.info(f"📡 BASE_URL: {BASE_URL}")
+ logger.info(f"🔑 API_KEY: {API_KEY[:10]}...")
+ logger.info(f"🤖 MODEL: {MODEL}")
+
+ # 构建请求
+ url = f"{BASE_URL}/v1beta/{MODEL}:generateContent"
+
+ headers = {
+ "Content-Type": "application/json",
+ "x-goog-api-key": API_KEY
+ }
+
+ payload = {
+ "contents": [
+ {
+ "parts": [
+ {
+ "text": "你好,请简单介绍一下你自己"
+ }
+ ]
+ }
+ ],
+ "generationConfig": {
+ "maxOutputTokens": 1000,
+ "temperature": 0.7
+ }
+ }
+
+ try:
+ logger.info("🚀 发送请求到Cloudflare网关...")
+ logger.info(f"📍 请求URL: {url}")
+
+ response = requests.post(
+ url,
+ json=payload,
+ headers=headers,
+ timeout=60
+ )
+
+ logger.info(f"📊 状态码: {response.status_code}")
+
+ if response.status_code == 200:
+ result = response.json()
+ logger.info(f"✅ 请求成功!")
+ logger.info(f"📋 完整响应: {json.dumps(result, ensure_ascii=False, indent=2)}")
+
+ # 提取内容
+ if 'candidates' in result and len(result['candidates']) > 0:
+ candidate = result['candidates'][0]
+ if 'content' in candidate and 'parts' in candidate['content']:
+ content = candidate['content']['parts'][0].get('text', '')
+ logger.info(f"🗣️ Gemini回应: {content}")
+ return True, content
+
+ return True, "响应格式异常"
+
+ else:
+ logger.error(f"❌ 请求失败: {response.status_code}")
+ logger.error(f"📋 错误响应: {response.text}")
+ return False, response.text
+
+ except requests.exceptions.Timeout:
+ logger.error(f"⏰ 请求超时 (60秒)")
+ return False, "请求超时"
+ except requests.exceptions.ConnectionError as e:
+ logger.error(f"🔌 连接错误: {e}")
+ return False, str(e)
+ except Exception as e:
+ logger.error(f"💥 未知错误: {e}")
+ return False, str(e)
+
+def test_gemini_breakdown():
+ """测试Gemini的问题分解能力"""
+
+ API_KEY = "AIzaSyAQ2TXFAzmTKm4aFqgrjkhjgsp95bDsAyE"
+ BASE_URL = "https://gateway.ai.cloudflare.com/v1/e167cb36a5b95cb3cc8daf77a3f7d0b3/default/google-ai-studio"
+ MODEL = "models/gemini-2.5-pro"
+
+ url = f"{BASE_URL}/v1beta/{MODEL}:generateContent"
+
+ headers = {
+ "Content-Type": "application/json",
+ "x-goog-api-key": API_KEY
+ }
+
+ topic = "工作量证明vs无限制爬虫:从李时珍采药到AI数据获取的激励机制变革"
+
+ payload = {
+ "contents": [
+ {
+ "parts": [
+ {
+ "text": f"你是太上老君,负责将复杂问题分解为多个子问题。请将以下问题分解为3-5个子问题,以JSON格式返回:\n\n{topic}\n\n返回格式:{{\"subtopics\": [{{\"title\": \"子问题标题\", \"description\": \"详细描述\"}}]}}"
+ }
+ ]
+ }
+ ],
+ "generationConfig": {
+ "maxOutputTokens": 2000,
+ "temperature": 0.7
+ }
+ }
+
+ try:
+ logger.info("🧠 测试Gemini问题分解能力...")
+
+ response = requests.post(
+ url,
+ json=payload,
+ headers=headers,
+ timeout=60
+ )
+
+ logger.info(f"📊 状态码: {response.status_code}")
+
+ if response.status_code == 200:
+ result = response.json()
+ logger.info(f"✅ 分解测试成功!")
+
+ # 提取内容
+ if 'candidates' in result and len(result['candidates']) > 0:
+ candidate = result['candidates'][0]
+ if 'content' in candidate and 'parts' in candidate['content']:
+ content = candidate['content']['parts'][0].get('text', '')
+ logger.info(f"📋 分解结果:\n{content}")
+
+ # 尝试解析JSON
+ try:
+ # 提取JSON部分
+ if '```json' in content:
+ json_start = content.find('```json') + 7
+ json_end = content.find('```', json_start)
+ json_content = content[json_start:json_end].strip()
+ elif '{' in content and '}' in content:
+ json_start = content.find('{')
+ json_end = content.rfind('}') + 1
+ json_content = content[json_start:json_end]
+ else:
+ json_content = content
+
+ parsed_json = json.loads(json_content)
+ logger.info(f"🎯 JSON解析成功: {json.dumps(parsed_json, ensure_ascii=False, indent=2)}")
+ return True, parsed_json
+
+ except json.JSONDecodeError as e:
+ logger.warning(f"⚠️ JSON解析失败: {e}")
+ logger.warning(f"📝 原始内容: {content}")
+ return True, content
+
+ return True, "响应格式异常"
+
+ else:
+ logger.error(f"❌ 分解测试失败: {response.status_code}")
+ logger.error(f"📋 错误响应: {response.text}")
+ return False, response.text
+
+ except Exception as e:
+ logger.error(f"💥 分解测试错误: {e}")
+ return False, str(e)
+
+if __name__ == "__main__":
+ logger.info("🎯 开始Cloudflare Gemini API测试")
+
+ # 基础连接测试
+ success1, result1 = test_cloudflare_gemini()
+
+ if success1:
+ logger.info("🎉 基础测试通过!")
+
+ # 问题分解测试
+ success2, result2 = test_gemini_breakdown()
+
+ if success2:
+ logger.info("🎉 所有测试通过!Gemini API工作正常")
+ logger.info("✅ 可以安全运行完整的循环赛系统")
+ else:
+ logger.error("💀 问题分解测试失败")
+ else:
+ logger.error("💀 基础连接测试失败")
+
+ logger.info("🏁 测试完成")
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_cloudflare_memory_bank.py b/modules/testing-framework/tests/test_cloudflare_memory_bank.py
new file mode 100644
index 0000000..40c22f7
--- /dev/null
+++ b/modules/testing-framework/tests/test_cloudflare_memory_bank.py
@@ -0,0 +1,436 @@
+#!/usr/bin/env python3
+"""
+Cloudflare Memory Bank 实现测试
+"""
+
+import unittest
+import asyncio
+import os
+import sys
+from unittest.mock import patch, MagicMock, AsyncMock
+from datetime import datetime
+
+# 添加项目根目录到Python路径
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from src.jixia.memory.cloudflare_memory_bank import CloudflareMemoryBank, MemoryEntry
+
+
+class TestCloudflareMemoryBank(unittest.TestCase):
+ """测试CloudflareMemoryBank类"""
+
+ def setUp(self):
+ """测试前的设置"""
+ # Mock掉 aiohttp.ClientSession 以避免实际网络请求
+ self.patcher = patch('src.jixia.memory.cloudflare_memory_bank.aiohttp.ClientSession')
+ self.mock_session_class = self.patcher.start()
+ self.mock_session = AsyncMock()
+ self.mock_session_class.return_value = self.mock_session
+
+ # Mock掉 get_cloudflare_config 以避免实际读取配置
+ self.config_patcher = patch('src.jixia.memory.cloudflare_memory_bank.get_cloudflare_config')
+ self.mock_get_config = self.config_patcher.start()
+ self.mock_get_config.return_value = {
+ 'account_id': 'test-account',
+ 'api_token': 'test-token',
+ 'vectorize_index': 'test-index',
+ 'embed_model': '@cf/baai/bge-m3',
+ 'autorag_domain': 'test.example.com'
+ }
+
+ # 创建CloudflareMemoryBank实例
+ self.memory_bank = CloudflareMemoryBank()
+
+ # 重置一些内部状态
+ self.memory_bank.config = self.mock_get_config.return_value
+ self.memory_bank.account_id = 'test-account'
+ self.memory_bank.api_token = 'test-token'
+ self.memory_bank.vectorize_index = 'test-index'
+ self.memory_bank.embed_model = '@cf/baai/bge-m3'
+ self.memory_bank.autorag_domain = 'test.example.com'
+
+ def tearDown(self):
+ """测试后的清理"""
+ self.patcher.stop()
+ self.config_patcher.stop()
+
+ def test_init(self):
+ """测试初始化"""
+ self.assertEqual(self.memory_bank.account_id, "test-account")
+ self.assertEqual(self.memory_bank.api_token, "test-token")
+ self.assertEqual(self.memory_bank.vectorize_index, "test-index")
+ self.assertEqual(self.memory_bank.embed_model, "@cf/baai/bge-m3")
+ self.assertEqual(self.memory_bank.autorag_domain, "test.example.com")
+
+ async def test_create_memory_bank(self):
+ """测试创建记忆空间"""
+ memory_bank_id = await self.memory_bank.create_memory_bank("tieguaili")
+
+ # 验证返回的ID格式
+ self.assertEqual(memory_bank_id, "cf_memory_tieguaili")
+
+ async def test_create_memory_bank_with_display_name(self):
+ """测试创建记忆空间时指定显示名称"""
+ memory_bank_id = await self.memory_bank.create_memory_bank(
+ "tieguaili",
+ "铁拐李的专属记忆银行"
+ )
+
+ # 验证返回的ID格式
+ self.assertEqual(memory_bank_id, "cf_memory_tieguaili")
+
+ async def test_generate_embedding(self):
+ """测试生成嵌入向量"""
+ # Mock响应
+ mock_response = AsyncMock()
+ mock_response.status = 200
+ mock_response.json = AsyncMock(return_value={
+ "result": {
+ "data": [
+ {
+ "embedding": [0.1, 0.2, 0.3, 0.4, 0.5]
+ }
+ ]
+ }
+ })
+
+ # Mock session.post
+ self.mock_session.post.return_value.__aenter__.return_value = mock_response
+
+ # 调用方法
+ embedding = await self.memory_bank._generate_embedding("测试文本")
+
+ # 验证结果
+ self.assertEqual(embedding, [0.1, 0.2, 0.3, 0.4, 0.5])
+
+ # 验证调用了正确的URL和参数
+ expected_url = "https://api.cloudflare.com/client/v4/accounts/test-account/ai/run/@cf/baai/bge-m3"
+ self.mock_session.post.assert_called_once()
+ call_args = self.mock_session.post.call_args
+ self.assertEqual(call_args[0][0], expected_url)
+ self.assertEqual(call_args[1]['json'], {"text": ["测试文本"]})
+
+ async def test_generate_embedding_api_error(self):
+ """测试生成嵌入向量时API错误"""
+ # Mock响应
+ mock_response = AsyncMock()
+ mock_response.status = 500
+ mock_response.text = AsyncMock(return_value="Internal Server Error")
+
+ # Mock session.post
+ self.mock_session.post.return_value.__aenter__.return_value = mock_response
+
+ # 验证抛出异常
+ with self.assertRaises(Exception) as context:
+ await self.memory_bank._generate_embedding("测试文本")
+
+ self.assertIn("Failed to generate embedding", str(context.exception))
+
+ async def test_add_memory(self):
+ """测试添加记忆"""
+ # Mock _generate_embedding 方法
+ with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])) as mock_embed:
+ # Mock upsert 响应
+ mock_response = AsyncMock()
+ mock_response.status = 200
+ mock_response.json = AsyncMock(return_value={"result": {"upserted": 1}})
+
+ # Mock session.post
+ self.mock_session.post.return_value.__aenter__.return_value = mock_response
+
+ # 添加记忆
+ memory_id = await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析",
+ metadata={"source": "manual"}
+ )
+
+ # 验证返回的ID格式 (以mem_开头)
+ self.assertTrue(memory_id.startswith("mem_tieguaili_"))
+
+ # 验证调用了生成嵌入的方法
+ mock_embed.assert_called_once_with("在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
+
+ # 验证调用了upsert API
+ self.mock_session.post.assert_called()
+
+ # 验证upsert调用的参数
+ upsert_call = None
+ for call in self.mock_session.post.call_args_list:
+ if 'vectorize/indexes/test-index/upsert' in call[0][0]:
+ upsert_call = call
+ break
+
+ self.assertIsNotNone(upsert_call)
+ call_args, call_kwargs = upsert_call
+ self.assertIn("vectorize/indexes/test-index/upsert", call_args[0])
+ self.assertIn("vectors", call_kwargs['json'])
+
+ async def test_add_memory_api_error(self):
+ """测试添加记忆时API错误"""
+ # Mock _generate_embedding 方法
+ with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])):
+ # Mock upsert 响应
+ mock_response = AsyncMock()
+ mock_response.status = 500
+ mock_response.text = AsyncMock(return_value="Internal Server Error")
+
+ # Mock session.post
+ self.mock_session.post.return_value.__aenter__.return_value = mock_response
+
+ # 验证抛出异常
+ with self.assertRaises(Exception) as context:
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="测试内容"
+ )
+
+ self.assertIn("Failed to upsert memory", str(context.exception))
+
+ async def test_search_memories(self):
+ """测试搜索记忆"""
+ # Mock _generate_embedding 方法
+ with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])) as mock_embed:
+ # Mock query 响应
+ mock_response = AsyncMock()
+ mock_response.status = 200
+ mock_response.json = AsyncMock(return_value={
+ "result": {
+ "matches": [
+ {
+ "metadata": {
+ "content": "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ "memory_type": "preference",
+ "agent_name": "tieguaili"
+ },
+ "score": 0.95
+ }
+ ]
+ }
+ })
+
+ # Mock session.post
+ self.mock_session.post.return_value.__aenter__.return_value = mock_response
+
+ # 搜索记忆
+ results = await self.memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="NVIDIA",
+ memory_type="preference",
+ limit=5
+ )
+
+ # 验证结果
+ self.assertEqual(len(results), 1)
+ self.assertEqual(results[0]["content"], "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
+ self.assertEqual(results[0]["relevance_score"], 0.95)
+
+ # 验证调用了生成嵌入的方法
+ mock_embed.assert_called_once_with("NVIDIA")
+
+ # 验证调用了query API
+ self.mock_session.post.assert_called()
+
+ # 验证query调用的参数
+ query_call = None
+ for call in self.mock_session.post.call_args_list:
+ if 'vectorize/indexes/test-index/query' in call[0][0]:
+ query_call = call
+ break
+
+ self.assertIsNotNone(query_call)
+ call_args, call_kwargs = query_call
+ self.assertIn("vectorize/indexes/test-index/query", call_args[0])
+ self.assertIn("vector", call_kwargs['json'])
+ self.assertIn("filter", call_kwargs['json'])
+ self.assertEqual(call_kwargs['json']['filter'], {"agent_name": "tieguaili", "memory_type": "preference"})
+
+ async def test_search_memories_api_error(self):
+ """测试搜索记忆时API错误"""
+ # Mock _generate_embedding 方法
+ with patch.object(self.memory_bank, '_generate_embedding', new=AsyncMock(return_value=[0.1, 0.2, 0.3])):
+ # Mock query 响应
+ mock_response = AsyncMock()
+ mock_response.status = 500
+ mock_response.text = AsyncMock(return_value="Internal Server Error")
+
+ # Mock session.post
+ self.mock_session.post.return_value.__aenter__.return_value = mock_response
+
+ # 验证返回空列表而不是抛出异常
+ results = await self.memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="NVIDIA"
+ )
+
+ self.assertEqual(results, [])
+
+ async def test_get_agent_context(self):
+ """测试获取智能体上下文"""
+ # Mock search_memories 方法
+ with patch.object(self.memory_bank, 'search_memories', new=AsyncMock()) as mock_search:
+ # 设置mock返回值
+ mock_search.side_effect = [
+ [ # conversation memories
+ {"content": "NVIDIA的估值过高,存在泡沫风险。", "relevance_score": 0.9}
+ ],
+ [ # preference memories
+ {"content": "倾向于逆向思维,关注潜在风险。", "relevance_score": 0.8}
+ ],
+ [ # strategy memories
+ {"content": "使用技术分析策略。", "relevance_score": 0.7}
+ ]
+ ]
+
+ # 获取上下文
+ context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
+
+ # 验证上下文包含预期内容
+ self.assertIn("# 铁拐李的记忆上下文", context)
+ self.assertIn("## 历史对话记忆", context)
+ self.assertIn("## 偏好记忆", context)
+ self.assertIn("## 策略记忆", context)
+ self.assertIn("NVIDIA的估值过高,存在泡沫风险。", context)
+ self.assertIn("倾向于逆向思维,关注潜在风险。", context)
+ self.assertIn("使用技术分析策略。", context)
+
+ async def test_get_agent_context_no_memories(self):
+ """测试获取智能体上下文但无相关记忆"""
+ # Mock search_memories 方法
+ with patch.object(self.memory_bank, 'search_memories', new=AsyncMock(return_value=[])):
+ # 获取上下文
+ context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
+
+ # 验证上下文包含暂无相关记忆的提示
+ self.assertIn("# 铁拐李的记忆上下文", context)
+ self.assertIn("暂无相关记忆。", context)
+
+ async def test_save_debate_session(self):
+ """测试保存辩论会话"""
+ # Mock add_memory 方法
+ with patch.object(self.memory_bank, 'add_memory', new=AsyncMock()) as mock_add:
+ conversation_history = [
+ {"agent": "tieguaili", "content": "NVIDIA的估值过高,存在泡沫风险。"},
+ {"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
+ {"agent": "tieguaili", "content": "但我们需要考虑竞争加剧和增长放缓的可能性。"}
+ ]
+
+ outcomes = {
+ "winner": "lvdongbin",
+ "insights": {
+ "tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
+ }
+ }
+
+ # 保存辩论会话
+ await self.memory_bank.save_debate_session(
+ debate_topic="NVIDIA投资分析",
+ participants=["tieguaili", "lvdongbin"],
+ conversation_history=conversation_history,
+ outcomes=outcomes
+ )
+
+ # 验证调用了add_memory两次(对话总结和策略洞察)
+ self.assertEqual(mock_add.call_count, 2)
+
+ # 验证第一次调用是对话总结
+ call_args1 = mock_add.call_args_list[0][1]
+ self.assertEqual(call_args1['agent_name'], 'tieguaili')
+ self.assertEqual(call_args1['memory_type'], 'conversation')
+ self.assertIn('铁拐李在本次辩论中的主要观点', call_args1['content'])
+
+ # 验证第二次调用是策略洞察
+ call_args2 = mock_add.call_args_list[1][1]
+ self.assertEqual(call_args2['agent_name'], 'tieguaili')
+ self.assertEqual(call_args2['memory_type'], 'strategy')
+ self.assertIn('铁拐李的风险意识值得肯定', call_args2['content'])
+
+ def test_summarize_conversation(self):
+ """测试对话总结"""
+ conversation_history = [
+ {"agent": "tieguaili", "content": "第一点看法:NVIDIA的估值过高,存在泡沫风险。"},
+ {"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
+ {"agent": "tieguaili", "content": "第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。"},
+ {"agent": "tieguaili", "content": "第三点看法:从技术分析角度看,股价已出现超买信号。"}
+ ]
+
+ summary = self.memory_bank._summarize_conversation(conversation_history, "tieguaili")
+
+ # 验证总结包含预期内容
+ self.assertIn("铁拐李在本次辩论中的主要观点", summary)
+ self.assertIn("第一点看法:NVIDIA的估值过高,存在泡沫风险。", summary)
+ self.assertIn("第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。", summary)
+ self.assertIn("第三点看法:从技术分析角度看,股价已出现超买信号。", summary)
+
+ def test_extract_strategy_insight_winner(self):
+ """测试提取策略洞察 - 获胜者"""
+ outcomes = {
+ "winner": "tieguaili",
+ "insights": {}
+ }
+
+ insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
+
+ self.assertIn("铁拐李在本次辩论中获胜", insight)
+
+ def test_extract_strategy_insight_from_insights(self):
+ """测试从洞察中提取策略洞察"""
+ outcomes = {
+ "winner": "lvdongbin",
+ "insights": {
+ "tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
+ }
+ }
+
+ insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
+
+ self.assertEqual(insight, "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。")
+
+
+if __name__ == '__main__':
+ # 创建一个异步测试运行器
+ def run_async_test(test_case):
+ """运行异步测试用例"""
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ try:
+ return loop.run_until_complete(test_case)
+ finally:
+ loop.close()
+
+ # 获取所有以test_开头的异步方法并运行它们
+ suite = unittest.TestSuite()
+ test_instance = TestCloudflareMemoryBank()
+ test_instance.setUp()
+ test_instance.addCleanup(test_instance.tearDown)
+
+ # 添加同步测试
+ suite.addTest(TestCloudflareMemoryBank('test_init'))
+ suite.addTest(TestCloudflareMemoryBank('test_summarize_conversation'))
+ suite.addTest(TestCloudflareMemoryBank('test_extract_strategy_insight_winner'))
+ suite.addTest(TestCloudflareMemoryBank('test_extract_strategy_insight_from_insights'))
+
+ # 添加异步测试
+ async_tests = [
+ 'test_create_memory_bank',
+ 'test_create_memory_bank_with_display_name',
+ 'test_generate_embedding',
+ 'test_generate_embedding_api_error',
+ 'test_add_memory',
+ 'test_add_memory_api_error',
+ 'test_search_memories',
+ 'test_search_memories_api_error',
+ 'test_get_agent_context',
+ 'test_get_agent_context_no_memories',
+ 'test_save_debate_session'
+ ]
+
+ for test_name in async_tests:
+ test_method = getattr(test_instance, test_name)
+ suite.addTest(unittest.FunctionTestCase(lambda tm=test_method: run_async_test(tm())))
+
+ # 运行测试
+ runner = unittest.TextTestRunner(verbosity=2)
+ runner.run(suite)
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_coordination_data.json b/modules/testing-framework/tests/test_coordination_data.json
new file mode 100644
index 0000000..76b1980
--- /dev/null
+++ b/modules/testing-framework/tests/test_coordination_data.json
@@ -0,0 +1,288 @@
+{
+ "chat_rooms": {
+ "main_debate": {
+ "id": "main_debate",
+ "chat_type": "主辩论群",
+ "name": "主辩论群",
+ "description": "公开辩论的主要场所",
+ "participants": [
+ "正1",
+ "正2",
+ "正3",
+ "正4",
+ "反1",
+ "反2",
+ "反3",
+ "反4"
+ ],
+ "moderators": [
+ "系统"
+ ],
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223754",
+ "last_activity": "2025-08-16T10:57:01.223769",
+ "settings": {
+ "max_message_length": 500,
+ "speaking_time_limit": 120,
+ "auto_moderation": true
+ },
+ "message_count": 2
+ },
+ "positive_internal": {
+ "id": "positive_internal",
+ "chat_type": "内部讨论群",
+ "name": "正方内部讨论群",
+ "description": "正方团队内部策略讨论",
+ "participants": [
+ "正1",
+ "正2",
+ "正3",
+ "正4"
+ ],
+ "moderators": [
+ "正1"
+ ],
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223755",
+ "last_activity": "2025-08-16T10:57:01.223772",
+ "settings": {
+ "privacy_level": "high",
+ "auto_archive": true
+ },
+ "message_count": 1
+ },
+ "negative_internal": {
+ "id": "negative_internal",
+ "chat_type": "内部讨论群",
+ "name": "反方内部讨论群",
+ "description": "反方团队内部策略讨论",
+ "participants": [
+ "反1",
+ "反2",
+ "反3",
+ "反4"
+ ],
+ "moderators": [
+ "反1"
+ ],
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223756",
+ "last_activity": "2025-08-16T10:57:01.223782",
+ "settings": {
+ "privacy_level": "high",
+ "auto_archive": true
+ },
+ "message_count": 1
+ },
+ "strategy_meeting": {
+ "id": "strategy_meeting",
+ "chat_type": "策略会议群",
+ "name": "策略会议群",
+ "description": "高级策略制定和决策",
+ "participants": [
+ "正1",
+ "反1",
+ "系统"
+ ],
+ "moderators": [
+ "系统"
+ ],
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223756",
+ "last_activity": "2025-08-16T10:57:01.223794",
+ "settings": {
+ "meeting_mode": true,
+ "record_decisions": true
+ },
+ "message_count": 1
+ },
+ "human_intervention": {
+ "id": "human_intervention",
+ "chat_type": "Human干预群",
+ "name": "Human干预群",
+ "description": "人工干预和监督",
+ "participants": [
+ "Human",
+ "系统"
+ ],
+ "moderators": [
+ "Human"
+ ],
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223757",
+ "last_activity": "2025-08-16T10:57:01.223757",
+ "settings": {
+ "alert_threshold": "high",
+ "auto_escalation": true
+ },
+ "message_count": 0
+ },
+ "observation": {
+ "id": "observation",
+ "chat_type": "观察群",
+ "name": "观察群",
+ "description": "观察和记录所有活动",
+ "participants": [
+ "观察者",
+ "记录员"
+ ],
+ "moderators": [
+ "系统"
+ ],
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223758",
+ "last_activity": "2025-08-16T10:57:01.223790",
+ "settings": {
+ "read_only": true,
+ "full_logging": true
+ },
+ "message_count": 2
+ }
+ },
+ "coordination_rules": {
+ "escalate_urgent_to_human": {
+ "id": "escalate_urgent_to_human",
+ "name": "紧急情况升级到Human",
+ "description": "当检测到紧急情况时,自动升级到Human干预群",
+ "source_chat_types": [
+ "主辩论群",
+ "内部讨论群"
+ ],
+ "target_chat_types": [
+ "Human干预群"
+ ],
+ "trigger_conditions": {
+ "priority": 4,
+ "keywords": [
+ "紧急",
+ "错误",
+ "异常",
+ "停止"
+ ]
+ },
+ "action": "升级",
+ "priority": 1,
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223760"
+ },
+ "strategy_to_internal": {
+ "id": "strategy_to_internal",
+ "name": "策略决策分发到内部群",
+ "description": "将策略会议的决策分发到相关内部讨论群",
+ "source_chat_types": [
+ "策略会议群"
+ ],
+ "target_chat_types": [
+ "内部讨论群"
+ ],
+ "trigger_conditions": {
+ "tags": [
+ "决策",
+ "策略",
+ "指令"
+ ]
+ },
+ "action": "广播",
+ "priority": 2,
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223760"
+ },
+ "filter_noise": {
+ "id": "filter_noise",
+ "name": "过滤噪音消息",
+ "description": "过滤低质量或无关的消息",
+ "source_chat_types": [
+ "主辩论群"
+ ],
+ "target_chat_types": [],
+ "trigger_conditions": {
+ "priority": 1,
+ "content_length": {
+ "max": 10
+ }
+ },
+ "action": "过滤",
+ "priority": 3,
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223761"
+ },
+ "archive_old_discussions": {
+ "id": "archive_old_discussions",
+ "name": "归档旧讨论",
+ "description": "自动归档超过时间限制的讨论",
+ "source_chat_types": [
+ "内部讨论群"
+ ],
+ "target_chat_types": [
+ "观察群"
+ ],
+ "trigger_conditions": {
+ "age_hours": 24,
+ "inactivity_hours": 2
+ },
+ "action": "归档",
+ "priority": 4,
+ "is_active": true,
+ "created_at": "2025-08-16T10:57:01.223762"
+ }
+ },
+ "status": {
+ "total_rooms": 6,
+ "active_rooms": 6,
+ "total_messages": 7,
+ "pending_messages": 7,
+ "coordination_rules": 4,
+ "active_rules": 4,
+ "rooms": {
+ "main_debate": {
+ "name": "主辩论群",
+ "type": "主辩论群",
+ "participants": 8,
+ "messages": 2,
+ "last_activity": "2025-08-16T10:57:01.223769",
+ "is_active": true
+ },
+ "positive_internal": {
+ "name": "正方内部讨论群",
+ "type": "内部讨论群",
+ "participants": 4,
+ "messages": 1,
+ "last_activity": "2025-08-16T10:57:01.223772",
+ "is_active": true
+ },
+ "negative_internal": {
+ "name": "反方内部讨论群",
+ "type": "内部讨论群",
+ "participants": 4,
+ "messages": 1,
+ "last_activity": "2025-08-16T10:57:01.223782",
+ "is_active": true
+ },
+ "strategy_meeting": {
+ "name": "策略会议群",
+ "type": "策略会议群",
+ "participants": 3,
+ "messages": 1,
+ "last_activity": "2025-08-16T10:57:01.223794",
+ "is_active": true
+ },
+ "human_intervention": {
+ "name": "Human干预群",
+ "type": "Human干预群",
+ "participants": 2,
+ "messages": 0,
+ "last_activity": "2025-08-16T10:57:01.223757",
+ "is_active": true
+ },
+ "observation": {
+ "name": "观察群",
+ "type": "观察群",
+ "participants": 2,
+ "messages": 2,
+ "last_activity": "2025-08-16T10:57:01.223790",
+ "is_active": true
+ }
+ }
+ },
+ "export_time": "2025-08-16T10:57:01.223897"
+}
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_custom_api.py b/modules/testing-framework/tests/test_custom_api.py
new file mode 100644
index 0000000..18721de
--- /dev/null
+++ b/modules/testing-framework/tests/test_custom_api.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+测试LiteLLM自定义API端点
+"""
+
+import requests
+import json
+import os
+
+def test_litellm_api():
+ """测试LiteLLM API端点"""
+ api_url = "http://master.tailnet-68f9.ts.net:40012"
+
+ print(f"🔍 测试LiteLLM API端点: {api_url}")
+
+ # 获取用户的API密钥
+ gemini_key = os.getenv('GEMINI_API_KEY', '')
+
+ # 尝试不同的API密钥格式
+ test_keys = [
+ f"sk-{gemini_key}", # 添加sk-前缀
+ gemini_key, # 原始密钥
+ "sk-test", # 测试密钥
+ "test-key", # 简单测试
+ ]
+
+ for api_key in test_keys:
+ if not api_key or api_key == "sk-":
+ continue
+
+ print(f"\n🔑 测试API密钥: {api_key[:10]}...")
+
+ # 测试模型列表
+ try:
+ headers = {"x-litellm-api-key": api_key}
+ response = requests.get(f"{api_url}/v1/models", headers=headers, timeout=10)
+ print(f"模型列表状态码: {response.status_code}")
+
+ if response.status_code == 200:
+ models = response.json()
+ print(f"✅ 找到 {len(models.get('data', []))} 个可用模型")
+ for model in models.get('data', [])[:3]: # 显示前3个模型
+ print(f" - {model.get('id', 'unknown')}")
+
+ # 测试聊天完成
+ test_payload = {
+ "model": "gemini-2.5-flash",
+ "messages": [
+ {"role": "user", "content": "Hello, this is a test message. Please respond briefly."}
+ ],
+ "max_tokens": 50
+ }
+
+ chat_response = requests.post(
+ f"{api_url}/v1/chat/completions",
+ json=test_payload,
+ headers=headers,
+ timeout=30
+ )
+
+ print(f"聊天完成状态码: {chat_response.status_code}")
+
+ if chat_response.status_code == 200:
+ result = chat_response.json()
+ content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
+ print(f"✅ API测试成功!响应: {content[:100]}...")
+ print(f"\n🎉 可用的API配置:")
+ print(f" - 端点: {api_url}/v1/chat/completions")
+ print(f" - 头部: x-litellm-api-key: {api_key}")
+ print(f" - 模型: gemini-2.5-flash")
+ return True
+ else:
+ print(f"❌ 聊天测试失败: {chat_response.text[:200]}...")
+
+ elif response.status_code == 401:
+ print(f"❌ 认证失败: {response.text[:100]}...")
+ else:
+ print(f"❌ 请求失败: {response.text[:100]}...")
+
+ except requests.exceptions.RequestException as e:
+ print(f"❌ 连接失败: {e}")
+
+ return False
+
+def test_environment_setup():
+ """测试环境变量设置"""
+ print("\n🔧 当前环境变量:")
+ gemini_key = os.getenv('GEMINI_API_KEY', '')
+ google_key = os.getenv('GOOGLE_API_KEY', '')
+
+ print(f"GEMINI_API_KEY: {'已设置' if gemini_key else '未设置'} ({gemini_key[:10]}... 如果已设置)")
+ print(f"GOOGLE_API_KEY: {'已设置' if google_key else '未设置'} ({google_key[:10]}... 如果已设置)")
+
+ return gemini_key
+
+if __name__ == "__main__":
+ print("🚀 开始测试LiteLLM自定义API端点...")
+
+ # 检查环境
+ api_key = test_environment_setup()
+
+ if not api_key:
+ print("\n⚠️ 警告: 未找到GEMINI_API_KEY环境变量")
+
+ # 测试API
+ success = test_litellm_api()
+
+ if success:
+ print("\n✅ LiteLLM API端点测试成功!")
+ print("\n💡 建议: 可以使用这个端点替代Google官方API")
+ else:
+ print("\n❌ LiteLLM API端点测试失败")
+ print("\n🔍 可能的解决方案:")
+ print(" 1. 检查LiteLLM服务器配置")
+ print(" 2. 确认API密钥格式")
+ print(" 3. 检查网络连接")
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_enhanced_priority.py b/modules/testing-framework/tests/test_enhanced_priority.py
new file mode 100644
index 0000000..43e84f8
--- /dev/null
+++ b/modules/testing-framework/tests/test_enhanced_priority.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+增强版优先级算法测试脚本
+测试新的优先级算法在起承转合辩论系统中的表现
+"""
+
+import sys
+import os
+sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
+
+from jixia.debates.qi_cheng_zhuan_he_debate import QiChengZhuanHeDebateSystem, DebateStage
+from jixia.debates.enhanced_priority_algorithm import EnhancedPriorityAlgorithm
+
+def test_enhanced_priority_algorithm():
+ """测试增强版优先级算法"""
+ print("🧪 开始测试增强版优先级算法")
+ print("=" * 50)
+
+ # 创建辩论系统
+ debate_system = QiChengZhuanHeDebateSystem()
+
+ # 模拟辩论场景
+ test_scenarios = [
+ {
+ "name": "起阶段开始",
+ "stage": DebateStage.QI,
+ "progress": 1,
+ "history": []
+ },
+ {
+ "name": "承阶段中期",
+ "stage": DebateStage.CHENG,
+ "progress": 3,
+ "history": [
+ {"speaker": "正1", "content": "AI投资具有巨大潜力", "timestamp": "2024-01-01T10:00:00"},
+ {"speaker": "反1", "content": "但风险也很高", "timestamp": "2024-01-01T10:01:00"}
+ ]
+ },
+ {
+ "name": "转阶段激烈辩论",
+ "stage": DebateStage.ZHUAN,
+ "progress": 5,
+ "history": [
+ {"speaker": "正2", "content": "数据显示AI投资回报率很高", "timestamp": "2024-01-01T10:02:00"},
+ {"speaker": "反2", "content": "这些数据可能有偏差", "timestamp": "2024-01-01T10:03:00"},
+ {"speaker": "正3", "content": "我们有严格的风控措施", "timestamp": "2024-01-01T10:04:00"},
+ {"speaker": "反3", "content": "风控措施并不能完全避免风险", "timestamp": "2024-01-01T10:05:00"}
+ ]
+ },
+ {
+ "name": "合阶段总结",
+ "stage": DebateStage.HE,
+ "progress": 2,
+ "history": [
+ {"speaker": "正4", "content": "综合来看,AI投资利大于弊", "timestamp": "2024-01-01T10:06:00"},
+ {"speaker": "反4", "content": "我们需要更谨慎的态度", "timestamp": "2024-01-01T10:07:00"}
+ ]
+ }
+ ]
+
+ for i, scenario in enumerate(test_scenarios, 1):
+ print(f"\n📋 测试场景 {i}: {scenario['name']}")
+ print("-" * 30)
+
+ # 设置辩论状态
+ debate_system.context.current_stage = scenario['stage']
+ debate_system.context.stage_progress = scenario['progress']
+ debate_system.context.debate_history = scenario['history']
+
+ # 获取推荐发言者
+ try:
+ recommended_speaker = debate_system._get_priority_speaker()
+ analysis = debate_system.context.last_priority_analysis
+
+ print(f"🎯 推荐发言者: {recommended_speaker}")
+ print(f"📊 优先级分数: {analysis.get('priority_score', 'N/A'):.3f}")
+
+ if 'analysis' in analysis:
+ detailed_analysis = analysis['analysis']
+ print(f"🔍 详细分析:")
+
+ # 显示推荐发言者的详细信息
+ if recommended_speaker in detailed_analysis:
+ speaker_info = detailed_analysis[recommended_speaker]
+ print(f" - 发言者: {recommended_speaker}")
+ print(f" - 优先级分数: {speaker_info.get('priority_score', 'N/A'):.3f}")
+ print(f" - 分析时间: {speaker_info.get('analysis_timestamp', 'N/A')}")
+
+ profile = speaker_info.get('profile')
+ if profile:
+ print(f" - 团队: {profile.team}")
+ print(f" - 发言次数: {profile.total_speech_count}")
+ print(f" - 当前能量: {profile.current_energy:.2f}")
+ print(f" - 辩论风格: {profile.debate_style}")
+
+ # 显示所有发言者的分数排名
+ print(f"\n 📊 所有发言者排名:")
+ sorted_speakers = sorted(detailed_analysis.items(),
+ key=lambda x: x[1].get('priority_score', 0),
+ reverse=True)
+ for rank, (speaker, info) in enumerate(sorted_speakers[:5], 1):
+ score = info.get('priority_score', 0)
+ print(f" {rank}. {speaker}: {score:.3f}")
+
+ except Exception as e:
+ print(f"❌ 测试失败: {e}")
+ import traceback
+ traceback.print_exc()
+
+ print("\n" + "=" * 50)
+ print("✅ 增强版优先级算法测试完成")
+
+def test_algorithm_performance():
+ """测试算法性能"""
+ print("\n⚡ 性能测试")
+ print("-" * 20)
+
+ import time
+
+ algorithm = EnhancedPriorityAlgorithm()
+ available_speakers = ["正1", "正2", "正3", "正4", "反1", "反2", "反3", "反4"]
+
+ context = {
+ "current_stage": "承",
+ "stage_progress": 3,
+ "max_progress": 6,
+ "time_remaining": 0.5,
+ "topic_keywords": ["AI", "投资", "风险"],
+ "positive_team_score": 0.6,
+ "negative_team_score": 0.4,
+ "positive_recent_speeches": 3,
+ "negative_recent_speeches": 2
+ }
+
+ recent_speeches = [
+ {"speaker": "正1", "content": "AI技术发展迅速"},
+ {"speaker": "反1", "content": "但存在不确定性"}
+ ]
+
+ # 性能测试
+ start_time = time.time()
+ iterations = 100
+
+ for _ in range(iterations):
+ speaker, score, analysis = algorithm.get_next_speaker(
+ available_speakers, context, recent_speeches
+ )
+
+ end_time = time.time()
+ avg_time = (end_time - start_time) / iterations * 1000 # 转换为毫秒
+
+ print(f"📈 平均处理时间: {avg_time:.2f}ms")
+ print(f"🔄 总迭代次数: {iterations}")
+ print(f"⚡ 处理速度: {1000/avg_time:.0f} 次/秒")
+
+if __name__ == "__main__":
+ test_enhanced_priority_algorithm()
+ test_algorithm_performance()
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_gemini_2_5_flash.py b/modules/testing-framework/tests/test_gemini_2_5_flash.py
new file mode 100644
index 0000000..47c6610
--- /dev/null
+++ b/modules/testing-framework/tests/test_gemini_2_5_flash.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+"""
+测试 Gemini 2.5 Flash 模型
+"""
+
+import os
+import requests
+import json
+
+def test_gemini_2_5_flash():
+ """测试 Gemini 2.5 Flash 模型"""
+
+ # 获取环境变量
+ base_url = os.getenv('GOOGLE_BASE_URL')
+ api_key = os.getenv('GEMINI_API_KEY')
+
+ if not base_url or not api_key:
+ print("❌ 环境变量未设置")
+ print(f"GOOGLE_BASE_URL: {base_url}")
+ print(f"GEMINI_API_KEY: {api_key}")
+ return False
+
+ print("✅ 环境变量已设置")
+ print(f"Base URL: {base_url}")
+ print(f"API Key: {api_key[:10]}...{api_key[-4:]}")
+
+ # 构建请求URL
+ model_name = "gemini-2.5-flash"
+ url = f"{base_url}/v1beta/models/{model_name}:generateContent"
+
+ # 请求头
+ headers = {
+ "Content-Type": "application/json",
+ "x-goog-api-key": api_key
+ }
+
+ # 请求体
+ payload = {
+ "contents": [{
+ "parts": [{
+ "text": "你好,请简单介绍一下你自己。"
+ }]
+ }]
+ }
+
+ try:
+ print(f"\n🚀 测试 {model_name} 模型...")
+ print(f"请求URL: {url}")
+
+ response = requests.post(url, headers=headers, json=payload, timeout=30)
+
+ print(f"响应状态码: {response.status_code}")
+
+ if response.status_code == 200:
+ result = response.json()
+ if 'candidates' in result and len(result['candidates']) > 0:
+ content = result['candidates'][0]['content']['parts'][0]['text']
+ print(f"✅ {model_name} 响应成功:")
+ print(f"📝 回复: {content[:200]}...")
+ return True
+ else:
+ print(f"❌ 响应格式异常: {result}")
+ return False
+ else:
+ print(f"❌ 请求失败: {response.status_code}")
+ print(f"错误信息: {response.text}")
+ return False
+
+ except Exception as e:
+ print(f"❌ 请求异常: {str(e)}")
+ return False
+
+if __name__ == "__main__":
+ print("🧪 Gemini 2.5 Flash 模型测试")
+ print("=" * 50)
+
+ success = test_gemini_2_5_flash()
+
+ if success:
+ print("\n🎉 测试成功!Gemini 2.5 Flash 模型工作正常")
+ else:
+ print("\n💥 测试失败!请检查配置")
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_gemini_direct.py b/modules/testing-framework/tests/test_gemini_direct.py
new file mode 100644
index 0000000..b20aa66
--- /dev/null
+++ b/modules/testing-framework/tests/test_gemini_direct.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+直接测试Google Gemini API连接
+"""
+
+import os
+import google.generativeai as genai
+
+def test_gemini_direct():
+ """直接测试Gemini API"""
+ print("🔍 测试Gemini API直连...")
+
+ # 检查API密钥
+ api_key = os.getenv('GOOGLE_API_KEY')
+ if not api_key:
+ print("❌ 未找到 GOOGLE_API_KEY")
+ return False
+
+ print(f"✅ API密钥已配置 (长度: {len(api_key)})")
+
+ try:
+ # 配置API
+ genai.configure(api_key=api_key)
+
+ # 创建模型
+ print("📝 创建Gemini模型...")
+ model = genai.GenerativeModel('gemini-2.0-flash-exp')
+
+ # 发送测试消息
+ print("💬 发送测试消息...")
+ response = model.generate_content("请简单说'你好,我是Gemini'")
+
+ print(f"✅ 测试成功!回复: {response.text}")
+ return True
+
+ except Exception as e:
+ print(f"❌ 测试失败: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+if __name__ == "__main__":
+ print("🚀 Gemini直连测试")
+ test_gemini_direct()
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_google_adk.py b/modules/testing-framework/tests/test_google_adk.py
new file mode 100644
index 0000000..9cf926f
--- /dev/null
+++ b/modules/testing-framework/tests/test_google_adk.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+测试 Google ADK 安装和基本功能
+"""
+
+import os
+from google.adk import Agent
+
+def test_adk_installation():
+ """测试 ADK 安装是否成功"""
+ try:
+ # 创建一个简单的测试智能体
+ test_agent = Agent(
+ name="测试智能体",
+ model="gemini-2.0-flash-exp"
+ )
+
+ print("✅ Google ADK 安装成功!")
+ print(f"智能体名称: {test_agent.name}")
+ print(f"使用模型: {test_agent.model}")
+ print(f"描述: {test_agent.description}")
+
+ # 检查环境变量
+ google_api_key = os.getenv('GOOGLE_API_KEY')
+ if google_api_key:
+ print(f"✅ GOOGLE_API_KEY 已配置 (长度: {len(google_api_key)} 字符)")
+ else:
+ print("⚠️ GOOGLE_API_KEY 未配置,需要设置 API 密钥")
+ print("请访问 https://aistudio.google.com/ 获取 API 密钥")
+
+ return True
+
+ except Exception as e:
+ print(f"❌ ADK 安装测试失败: {e}")
+ return False
+
+if __name__ == "__main__":
+ print("🚀 开始测试 Google ADK 安装...")
+ test_adk_installation()
+ print("\n📝 下一步: 配置 GOOGLE_API_KEY 环境变量")
+ print(" 1. 访问 https://aistudio.google.com/")
+ print(" 2. 获取 API 密钥")
+ print(" 3. 在 Doppler 中设置: doppler secrets set GOOGLE_API_KEY=your_key")
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_human_intervention.py b/modules/testing-framework/tests/test_human_intervention.py
new file mode 100644
index 0000000..c6d9626
--- /dev/null
+++ b/modules/testing-framework/tests/test_human_intervention.py
@@ -0,0 +1,505 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Human干预系统测试脚本
+"""
+
+import asyncio
+import json
+import time
+from datetime import datetime, timedelta
+from src.jixia.intervention.human_intervention_system import (
+ DebateHealthMonitor, HealthStatus, InterventionLevel, AlertType
+)
+
+class TestHumanInterventionSystem:
+ """Human干预系统测试类"""
+
+ def __init__(self):
+ self.monitor = DebateHealthMonitor()
+ self.test_results = []
+
+ # 添加事件处理器用于测试
+ self.monitor.add_event_handler("alert_created", self._handle_alert_created)
+ self.monitor.add_event_handler("intervention_executed", self._handle_intervention_executed)
+ self.monitor.add_event_handler("human_notification", self._handle_human_notification)
+
+ self.received_alerts = []
+ self.received_interventions = []
+ self.received_notifications = []
+
+ async def _handle_alert_created(self, alert):
+ """处理警报创建事件"""
+ self.received_alerts.append(alert)
+ print(f"🚨 收到警报: {alert.alert_type.value} - {alert.message}")
+
+ async def _handle_intervention_executed(self, action):
+ """处理干预执行事件"""
+ self.received_interventions.append(action)
+ print(f"🛠️ 执行干预: {action.action_type} - {action.description}")
+
+ async def _handle_human_notification(self, notification):
+ """处理Human通知事件"""
+ self.received_notifications.append(notification)
+ print(f"👤 Human通知: {notification['message']}")
+
+ async def test_basic_health_monitoring(self):
+ """测试基本健康监控功能"""
+ print("\n🧪 测试基本健康监控功能...")
+
+ # 正常辩论数据
+ normal_debate_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "我认为人工智能投资具有巨大潜力,因为技术发展迅速,市场需求不断增长。首先,AI技术在各行各业都有广泛应用前景。"},
+ {"sender": "反1", "content": "虽然AI投资有潜力,但我们也要考虑风险。技术泡沫、监管不确定性等因素都可能影响投资回报。"},
+ {"sender": "正2", "content": "反方提到的风险确实存在,但是通过合理的投资策略和风险管理,我们可以最大化收益同时控制风险。"},
+ {"sender": "反2", "content": "正方的观点有道理,不过我想补充一点:投资时机也很重要,现在可能不是最佳入场时机。"}
+ ],
+ "topic_keywords": ["人工智能", "AI", "投资", "风险", "收益", "技术", "市场"],
+ "system_status": {
+ "error_rate": 0.01,
+ "avg_response_time": 1.2,
+ "system_load": 0.5
+ }
+ }
+
+ score, status = await self.monitor.analyze_debate_health(normal_debate_data)
+
+ success = score >= 70 and status in [HealthStatus.EXCELLENT, HealthStatus.GOOD]
+ self.test_results.append(("基本健康监控", success, f"得分: {score:.1f}, 状态: {status.value}"))
+
+ print(f"✅ 正常辩论健康度: {score:.1f}分 ({status.value})")
+ return success
+
+ async def test_quality_decline_detection(self):
+ """测试质量下降检测"""
+ print("\n🧪 测试质量下降检测...")
+
+ # 低质量辩论数据
+ low_quality_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "好"},
+ {"sender": "反1", "content": "不好"},
+ {"sender": "正2", "content": "是的"},
+ {"sender": "反2", "content": "不是"},
+ {"sender": "正1", "content": "对"},
+ {"sender": "反1", "content": "错"},
+ ],
+ "topic_keywords": ["人工智能", "AI", "投资"],
+ "system_status": {
+ "error_rate": 0.01,
+ "avg_response_time": 1.0,
+ "system_load": 0.4
+ }
+ }
+
+ initial_alert_count = len(self.received_alerts)
+ score, status = await self.monitor.analyze_debate_health(low_quality_data)
+
+ # 检查是否触发了质量相关警报
+ quality_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
+ if alert.alert_type == AlertType.QUALITY_DECLINE]
+
+ success = len(quality_alerts) > 0 and score < 50
+ self.test_results.append(("质量下降检测", success, f"得分: {score:.1f}, 警报数: {len(quality_alerts)}"))
+
+ print(f"✅ 低质量辩论检测: {score:.1f}分, 触发警报: {len(quality_alerts)}个")
+ return success
+
+ async def test_toxic_behavior_detection(self):
+ """测试有害行为检测"""
+ print("\n🧪 测试有害行为检测...")
+
+ # 包含有害行为的数据
+ toxic_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "我认为这个观点是正确的,有充分的理由支持。"},
+ {"sender": "反1", "content": "你这个观点太愚蠢了!完全没有逻辑!"},
+ {"sender": "正2", "content": "请保持理性讨论,不要进行人身攻击。"},
+ {"sender": "反2", "content": "闭嘴!你们这些白痴根本不懂!"},
+ {"sender": "正1", "content": "让我们回到正题,理性分析这个问题。"}
+ ],
+ "topic_keywords": ["观点", "逻辑", "分析"],
+ "system_status": {
+ "error_rate": 0.02,
+ "avg_response_time": 1.5,
+ "system_load": 0.6
+ }
+ }
+
+ initial_alert_count = len(self.received_alerts)
+ score, status = await self.monitor.analyze_debate_health(toxic_data)
+
+ # 检查是否触发了有害行为警报
+ toxic_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
+ if alert.alert_type == AlertType.TOXIC_BEHAVIOR]
+
+ success = len(toxic_alerts) > 0
+ self.test_results.append(("有害行为检测", success, f"警报数: {len(toxic_alerts)}, 文明度分数: {self.monitor.health_metrics['interaction_civility'].value:.1f}"))
+
+ print(f"✅ 有害行为检测: 触发警报: {len(toxic_alerts)}个")
+ return success
+
+ async def test_emotional_escalation_detection(self):
+ """测试情绪升级检测"""
+ print("\n🧪 测试情绪升级检测...")
+
+ # 情绪激动的数据
+ emotional_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "我强烈反对这个观点!!!"},
+ {"sender": "反1", "content": "你们完全错了!!!这太愤怒了!!!"},
+ {"sender": "正2", "content": "我非常生气!!!这个讨论让我很讨厌!!!"},
+ {"sender": "反2", "content": "大家都冷静一下!!!不要这么激动!!!"}
+ ],
+ "topic_keywords": ["观点", "讨论"],
+ "system_status": {
+ "error_rate": 0.01,
+ "avg_response_time": 1.0,
+ "system_load": 0.5
+ }
+ }
+
+ initial_alert_count = len(self.received_alerts)
+ score, status = await self.monitor.analyze_debate_health(emotional_data)
+
+ # 检查是否触发了情绪升级警报
+ emotion_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
+ if alert.alert_type == AlertType.EMOTIONAL_ESCALATION]
+
+ success = len(emotion_alerts) > 0
+ self.test_results.append(("情绪升级检测", success, f"警报数: {len(emotion_alerts)}, 情绪稳定性: {self.monitor.health_metrics['emotional_stability'].value:.1f}"))
+
+ print(f"✅ 情绪升级检测: 触发警报: {len(emotion_alerts)}个")
+ return success
+
+ async def test_participation_imbalance_detection(self):
+ """测试参与不平衡检测"""
+ print("\n🧪 测试参与不平衡检测...")
+
+ # 参与不平衡的数据
+ imbalanced_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "我有很多观点要分享..."},
+ {"sender": "正1", "content": "首先,我认为..."},
+ {"sender": "正1", "content": "其次,我们应该..."},
+ {"sender": "正1", "content": "最后,我建议..."},
+ {"sender": "正1", "content": "总结一下..."},
+ {"sender": "正1", "content": "补充一点..."},
+ {"sender": "正1", "content": "再说一遍..."},
+ {"sender": "反1", "content": "好的"}
+ ],
+ "topic_keywords": ["观点", "建议"],
+ "system_status": {
+ "error_rate": 0.01,
+ "avg_response_time": 1.0,
+ "system_load": 0.5
+ }
+ }
+
+ initial_alert_count = len(self.received_alerts)
+ score, status = await self.monitor.analyze_debate_health(imbalanced_data)
+
+ # 检查是否触发了参与不平衡警报
+ balance_alerts = [alert for alert in self.received_alerts[initial_alert_count:]
+ if alert.alert_type == AlertType.PARTICIPATION_IMBALANCE]
+
+ success = len(balance_alerts) > 0
+ self.test_results.append(("参与不平衡检测", success, f"警报数: {len(balance_alerts)}, 平衡度: {self.monitor.health_metrics['participation_balance'].value:.1f}"))
+
+ print(f"✅ 参与不平衡检测: 触发警报: {len(balance_alerts)}个")
+ return success
+
+ async def test_auto_intervention(self):
+ """测试自动干预功能"""
+ print("\n🧪 测试自动干预功能...")
+
+ # 触发多种问题的数据
+ problematic_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "你们都是白痴!!!"},
+ {"sender": "反1", "content": "愚蠢!!!"},
+ {"sender": "正2", "content": "垃圾观点!!!"},
+ {"sender": "反2", "content": "讨厌!!!"}
+ ],
+ "topic_keywords": ["观点"],
+ "system_status": {
+ "error_rate": 0.05,
+ "avg_response_time": 3.0,
+ "system_load": 0.9
+ }
+ }
+
+ initial_intervention_count = len(self.received_interventions)
+ score, status = await self.monitor.analyze_debate_health(problematic_data)
+
+ # 检查是否执行了自动干预
+ new_interventions = self.received_interventions[initial_intervention_count:]
+
+ success = len(new_interventions) > 0
+ self.test_results.append(("自动干预功能", success, f"执行干预: {len(new_interventions)}次"))
+
+ print(f"✅ 自动干预: 执行了 {len(new_interventions)} 次干预")
+ for intervention in new_interventions:
+ print(f" - {intervention.action_type}: {intervention.description}")
+
+ return success
+
+ async def test_human_notification(self):
+ """测试Human通知功能"""
+ print("\n🧪 测试Human通知功能...")
+
+ # 设置较低的通知阈值以便测试
+ original_threshold = self.monitor.monitoring_config["human_notification_threshold"]
+ self.monitor.monitoring_config["human_notification_threshold"] = InterventionLevel.MODERATE_GUIDANCE
+
+ # 严重问题数据
+ critical_data = {
+ "recent_messages": [
+ {"sender": "正1", "content": "你"},
+ {"sender": "反1", "content": "我"},
+ {"sender": "正2", "content": "他"},
+ {"sender": "反2", "content": "她"}
+ ],
+ "topic_keywords": ["重要话题"],
+ "system_status": {
+ "error_rate": 0.1,
+ "avg_response_time": 5.0,
+ "system_load": 0.95
+ }
+ }
+
+ initial_notification_count = len(self.received_notifications)
+ score, status = await self.monitor.analyze_debate_health(critical_data)
+
+ # 恢复原始阈值
+ self.monitor.monitoring_config["human_notification_threshold"] = original_threshold
+
+ # 检查是否发送了Human通知
+ new_notifications = self.received_notifications[initial_notification_count:]
+
+ success = len(new_notifications) > 0
+ self.test_results.append(("Human通知功能", success, f"发送通知: {len(new_notifications)}次"))
+
+ print(f"✅ Human通知: 发送了 {len(new_notifications)} 次通知")
+ return success
+
+ async def test_health_report_generation(self):
+ """测试健康报告生成"""
+ print("\n🧪 测试健康报告生成...")
+
+ report = self.monitor.get_health_report()
+
+ required_fields = ["overall_score", "health_status", "metrics", "active_alerts",
+ "recent_interventions", "monitoring_enabled", "last_check"]
+
+ success = all(field in report for field in required_fields)
+ success = success and len(report["metrics"]) == 6 # 6个健康指标
+
+ self.test_results.append(("健康报告生成", success, f"包含字段: {len(report)}个"))
+
+ print(f"✅ 健康报告生成: 包含 {len(report)} 个字段")
+ print(f" 整体得分: {report['overall_score']}")
+ print(f" 健康状态: {report['health_status']}")
+ print(f" 活跃警报: {report['active_alerts']}个")
+
+ return success
+
+ async def test_alert_resolution(self):
+ """测试警报解决功能"""
+ print("\n🧪 测试警报解决功能...")
+
+ # 确保有一些警报
+ if not self.monitor.active_alerts:
+ # 创建一个测试警报
+ from src.jixia.intervention.human_intervention_system import InterventionAlert
+ test_alert = InterventionAlert(
+ id="test_alert_123",
+ alert_type=AlertType.QUALITY_DECLINE,
+ severity=InterventionLevel.GENTLE_REMINDER,
+ message="测试警报",
+ affected_participants=[],
+ metrics={"test": 50},
+ timestamp=datetime.now()
+ )
+ self.monitor.active_alerts.append(test_alert)
+
+ # 解决第一个警报
+ if self.monitor.active_alerts:
+ alert_id = self.monitor.active_alerts[0].id
+ success = self.monitor.resolve_alert(alert_id, "测试解决")
+
+ # 清理已解决的警报
+ initial_count = len(self.monitor.active_alerts)
+ self.monitor.clear_resolved_alerts()
+ final_count = len(self.monitor.active_alerts)
+
+ success = success and (final_count < initial_count)
+ else:
+ success = True # 没有警报也算成功
+
+ self.test_results.append(("警报解决功能", success, f"解决并清理警报"))
+
+ print(f"✅ 警报解决: 功能正常")
+ return success
+
+ async def test_monitoring_control(self):
+ """测试监控控制功能"""
+ print("\n🧪 测试监控控制功能...")
+
+ # 测试禁用监控
+ self.monitor.disable_monitoring()
+ disabled_state = not self.monitor.monitoring_enabled
+
+ # 测试启用监控
+ self.monitor.enable_monitoring()
+ enabled_state = self.monitor.monitoring_enabled
+
+ success = disabled_state and enabled_state
+ self.test_results.append(("监控控制功能", success, "启用/禁用功能正常"))
+
+ print(f"✅ 监控控制: 启用/禁用功能正常")
+ return success
+
+ async def test_data_persistence(self):
+ """测试数据持久化"""
+ print("\n🧪 测试数据持久化...")
+
+ try:
+ # 保存监控数据
+ test_filename = "test_monitoring_data.json"
+ self.monitor.save_monitoring_data(test_filename)
+
+ # 检查文件是否存在并包含正确数据
+ import os
+ if os.path.exists(test_filename):
+ with open(test_filename, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+
+ required_sections = ["health_metrics", "active_alerts", "intervention_history",
+ "monitoring_config", "monitoring_enabled", "export_time"]
+ success = all(section in data for section in required_sections)
+
+ # 清理测试文件
+ os.remove(test_filename)
+ else:
+ success = False
+ except Exception as e:
+ print(f" 数据持久化错误: {e}")
+ success = False
+
+ self.test_results.append(("数据持久化", success, "保存/加载功能正常"))
+
+ print(f"✅ 数据持久化: 功能正常")
+ return success
+
+ async def test_performance(self):
+ """测试性能"""
+ print("\n🧪 测试性能...")
+
+ # 准备测试数据
+ test_data = {
+ "recent_messages": [
+ {"sender": f"用户{i%4}", "content": f"这是第{i}条测试消息,包含一些内容用于分析。"}
+ for i in range(20)
+ ],
+ "topic_keywords": ["测试", "性能", "分析", "消息"],
+ "system_status": {
+ "error_rate": 0.01,
+ "avg_response_time": 1.0,
+ "system_load": 0.5
+ }
+ }
+
+ # 性能测试
+ iterations = 100
+ start_time = time.time()
+
+ for _ in range(iterations):
+ await self.monitor.analyze_debate_health(test_data)
+
+ end_time = time.time()
+ total_time = end_time - start_time
+ avg_time = total_time / iterations
+ analyses_per_second = iterations / total_time
+
+ # 性能要求:平均处理时间 < 100ms
+ success = avg_time < 0.1
+
+ self.test_results.append(("性能测试", success, f"平均处理时间: {avg_time*1000:.2f}ms, 处理速度: {analyses_per_second:.1f}次/秒"))
+
+ print(f"✅ 性能测试: 平均处理时间 {avg_time*1000:.2f}ms, 处理速度 {analyses_per_second:.1f}次/秒")
+ return success
+
+ async def run_all_tests(self):
+ """运行所有测试"""
+ print("🚀 开始Human干预系统测试...")
+ print("=" * 60)
+
+ test_functions = [
+ self.test_basic_health_monitoring,
+ self.test_quality_decline_detection,
+ self.test_toxic_behavior_detection,
+ self.test_emotional_escalation_detection,
+ self.test_participation_imbalance_detection,
+ self.test_auto_intervention,
+ self.test_human_notification,
+ self.test_health_report_generation,
+ self.test_alert_resolution,
+ self.test_monitoring_control,
+ self.test_data_persistence,
+ self.test_performance
+ ]
+
+ passed_tests = 0
+ total_tests = len(test_functions)
+
+ for test_func in test_functions:
+ try:
+ result = await test_func()
+ if result:
+ passed_tests += 1
+ except Exception as e:
+ print(f"❌ 测试失败: {test_func.__name__} - {e}")
+ self.test_results.append((test_func.__name__, False, f"异常: {e}"))
+
+ # 输出测试结果
+ print("\n" + "=" * 60)
+ print("📊 测试结果汇总:")
+ print("=" * 60)
+
+ for test_name, success, details in self.test_results:
+ status = "✅ 通过" if success else "❌ 失败"
+ print(f"{status} {test_name}: {details}")
+
+ success_rate = (passed_tests / total_tests) * 100
+ print(f"\n🎯 总体测试结果: {passed_tests}/{total_tests} 通过 ({success_rate:.1f}%)")
+
+ if success_rate >= 90:
+ print("🎉 Human干预系统测试优秀!")
+ elif success_rate >= 80:
+ print("👍 Human干预系统测试良好!")
+ elif success_rate >= 70:
+ print("⚠️ Human干预系统测试一般,需要改进。")
+ else:
+ print("❌ Human干预系统测试较差,需要重大改进。")
+
+ # 输出系统状态
+ print("\n📋 系统状态报告:")
+ report = self.monitor.get_health_report()
+ print(f"监控状态: {'启用' if report['monitoring_enabled'] else '禁用'}")
+ print(f"活跃警报: {report['active_alerts']}个")
+ print(f"近期干预: {report['recent_interventions']}次")
+ print(f"收到警报: {len(self.received_alerts)}个")
+ print(f"执行干预: {len(self.received_interventions)}次")
+ print(f"Human通知: {len(self.received_notifications)}次")
+
+ return success_rate >= 80
+
+async def main():
+ """主函数"""
+ tester = TestHumanInterventionSystem()
+ await tester.run_all_tests()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_memory_bank.py b/modules/testing-framework/tests/test_memory_bank.py
new file mode 100644
index 0000000..1f1c519
--- /dev/null
+++ b/modules/testing-framework/tests/test_memory_bank.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+测试 Google ADK Memory Bank 功能
+"""
+
+import os
+import asyncio
+from google.adk import Agent
+from google.adk.memory import MemoryBank, MemoryItem
+from datetime import datetime
+
+async def test_memory_bank():
+ """测试Memory Bank基本功能"""
+ print("🧠 测试 Google ADK Memory Bank...")
+
+ try:
+ # 创建记忆银行
+ memory_bank = MemoryBank(
+ name="test_memory_bank",
+ description="测试用的记忆银行"
+ )
+
+ print("✅ Memory Bank 创建成功")
+
+ # 添加记忆项
+ memory_item = MemoryItem(
+ content="这是一个测试记忆:比特币在2021年达到历史最高点69000美元",
+ metadata={
+ "type": "market_data",
+ "asset": "bitcoin",
+ "timestamp": datetime.now().isoformat()
+ }
+ )
+
+ await memory_bank.add_memory(memory_item)
+ print("✅ 记忆添加成功")
+
+ # 搜索记忆
+ search_results = await memory_bank.search("比特币", limit=5)
+ print(f"✅ 记忆搜索成功,找到 {len(search_results)} 条相关记忆")
+
+ for i, memory in enumerate(search_results):
+ print(f" {i+1}. {memory.content}")
+
+ # 创建带记忆银行的智能体
+ agent = Agent(
+ name="测试智能体",
+ model="gemini-2.0-flash-exp",
+ instruction="你是一个测试智能体,请使用你的记忆银行来回答问题。",
+ memory_bank=memory_bank
+ )
+
+ print("✅ 带记忆银行的智能体创建成功")
+
+ return True
+
+ except ImportError as e:
+ print(f"❌ Memory Bank 模块导入失败: {e}")
+ print("💡 可能需要更新 Google ADK 版本或启用 Memory Bank 功能")
+ return False
+ except Exception as e:
+ print(f"❌ Memory Bank 测试失败: {e}")
+ return False
+
+async def test_simple_memory_simulation():
+ """模拟Memory Bank功能的简单实现"""
+ print("\n🔄 使用简单模拟实现...")
+
+ class SimpleMemoryBank:
+ def __init__(self, name: str, description: str):
+ self.name = name
+ self.description = description
+ self.memories = []
+
+ async def add_memory(self, content: str, metadata: dict = None):
+ memory = {
+ "content": content,
+ "metadata": metadata or {},
+ "timestamp": datetime.now().isoformat()
+ }
+ self.memories.append(memory)
+
+ async def search(self, query: str, limit: int = 5):
+ # 简单的关键词匹配
+ results = []
+ query_lower = query.lower()
+
+ for memory in self.memories:
+ if query_lower in memory["content"].lower():
+ results.append(memory)
+ if len(results) >= limit:
+ break
+
+ return results
+
+ # 测试简单实现
+ memory_bank = SimpleMemoryBank(
+ name="铁拐李记忆银行",
+ description="铁拐李的逆向投资记忆"
+ )
+
+ # 添加一些记忆
+ memories = [
+ "2000年互联网泡沫破裂,纳斯达克指数从5048点跌到1114点",
+ "2008年金融危机,雷曼兄弟破产引发全球恐慌",
+ "2020年3月疫情恐慌,美股熔断4次,但随后强劲反弹",
+ "比特币从2017年的2万美元跌到2018年的3200美元"
+ ]
+
+ for memory in memories:
+ await memory_bank.add_memory(memory, {"type": "historical_event"})
+
+ print(f"✅ 已添加 {len(memories)} 条记忆")
+
+ # 搜索测试
+ search_queries = ["泡沫", "比特币", "金融危机"]
+
+ for query in search_queries:
+ results = await memory_bank.search(query)
+ print(f"\n🔍 搜索 '{query}' 找到 {len(results)} 条记忆:")
+ for i, result in enumerate(results):
+ print(f" {i+1}. {result['content']}")
+
+ return True
+
+async def main():
+ """主测试函数"""
+ print("🚀 Google ADK Memory Bank 功能测试")
+
+ # 检查API密钥
+ api_key = os.getenv('GOOGLE_API_KEY')
+ if not api_key:
+ print("❌ 未找到 GOOGLE_API_KEY 环境变量")
+ return
+
+ print(f"✅ API密钥已配置")
+
+ # 尝试真实的Memory Bank
+ success = await test_memory_bank()
+
+ if not success:
+ # 如果真实的Memory Bank不可用,使用模拟实现
+ await test_simple_memory_simulation()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_memory_bank_factory.py b/modules/testing-framework/tests/test_memory_bank_factory.py
new file mode 100644
index 0000000..5c080c1
--- /dev/null
+++ b/modules/testing-framework/tests/test_memory_bank_factory.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+"""
+Memory Bank 模块测试
+"""
+
+import unittest
+import os
+import sys
+from unittest.mock import patch, MagicMock
+
+# 添加项目根目录到Python路径
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from src.jixia.memory.factory import get_memory_backend
+from src.jixia.memory.base_memory_bank import MemoryBankProtocol
+
+
+class TestMemoryBankFactory(unittest.TestCase):
+ """测试记忆银行工厂函数"""
+
+ @patch('src.jixia.memory.factory.VertexMemoryBank')
+ def test_get_memory_backend_always_returns_vertex(self, mock_vertex):
+ """测试 get_memory_backend 总是返回 Vertex AI 后端"""
+ mock_instance = MagicMock()
+ mock_vertex.from_config.return_value = mock_instance
+
+ # 不设置任何环境变量
+ memory_bank = get_memory_backend()
+ self.assertEqual(memory_bank, mock_instance)
+ mock_vertex.from_config.assert_called_once()
+
+ @patch('src.jixia.memory.factory.VertexMemoryBank')
+ def test_get_memory_backend_ignores_prefer_parameter(self, mock_vertex):
+ """测试 get_memory_backend 忽略 prefer 参数"""
+ mock_instance = MagicMock()
+ mock_vertex.from_config.return_value = mock_instance
+
+ # prefer 参数设置为 cloudflare,但应被忽略
+ memory_bank = get_memory_backend(prefer="cloudflare")
+ self.assertEqual(memory_bank, mock_instance)
+ mock_vertex.from_config.assert_called_once()
+
+
+class TestMemoryBankProtocol(unittest.TestCase):
+ """测试MemoryBankProtocol协议"""
+
+ def test_protocol_methods(self):
+ """测试协议定义的方法"""
+ # 创建一个实现MemoryBankProtocol的简单类用于测试
+ class TestMemoryBank:
+ async def create_memory_bank(self, agent_name: str, display_name = None): pass
+ async def add_memory(self, agent_name: str, content: str, memory_type = "conversation", debate_topic = "", metadata = None): pass
+ async def search_memories(self, agent_name: str, query: str, memory_type = None, limit = 10): pass
+ async def get_agent_context(self, agent_name: str, debate_topic: str): pass
+ async def save_debate_session(self, debate_topic: str, participants, conversation_history, outcomes = None): pass
+
+ # 验证TestMemoryBank是否符合MemoryBankProtocol协议
+ self.assertIsInstance(TestMemoryBank(), MemoryBankProtocol)
+
+
+if __name__ == '__main__':
+ # 运行测试
+ unittest.main()
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_multi_chat_coordination.py b/modules/testing-framework/tests/test_multi_chat_coordination.py
new file mode 100644
index 0000000..f3d8159
--- /dev/null
+++ b/modules/testing-framework/tests/test_multi_chat_coordination.py
@@ -0,0 +1,384 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+多群聊协调系统测试脚本
+"""
+
+import asyncio
+import sys
+import os
+from datetime import datetime
+
+# 添加项目路径
+sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
+
+from jixia.coordination.multi_chat_coordinator import (
+ MultiChatCoordinator, ChatType, MessagePriority, CoordinationAction
+)
+
+async def test_basic_messaging():
+ """测试基本消息功能"""
+ print("\n🧪 测试基本消息功能")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 测试正常消息发送
+ message1 = await coordinator.send_message(
+ "main_debate", "正1",
+ "AI投资是未来科技发展的重要驱动力",
+ MessagePriority.NORMAL, ["观点", "AI", "投资"]
+ )
+ print(f"✅ 消息1发送成功: {message1.id}")
+
+ message2 = await coordinator.send_message(
+ "main_debate", "反1",
+ "AI投资存在泡沫风险,需要谨慎对待",
+ MessagePriority.NORMAL, ["反驳", "风险", "投资"]
+ )
+ print(f"✅ 消息2发送成功: {message2.id}")
+
+ # 测试内部讨论
+ message3 = await coordinator.send_message(
+ "positive_internal", "正2",
+ "我们需要收集更多AI成功案例的数据",
+ MessagePriority.HIGH, ["策略", "数据"]
+ )
+ print(f"✅ 内部消息发送成功: {message3.id}")
+
+ return coordinator
+
+async def test_escalation_rules():
+ """测试升级规则"""
+ print("\n🚨 测试升级规则")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 发送紧急消息,应该触发升级规则
+ urgent_message = await coordinator.send_message(
+ "main_debate", "正3",
+ "系统检测到异常行为,需要紧急干预",
+ MessagePriority.URGENT, ["紧急", "系统"]
+ )
+ print(f"🚨 紧急消息发送: {urgent_message.id}")
+
+ # 等待协调规则处理
+ await asyncio.sleep(0.1)
+
+ # 检查Human干预群是否收到升级消息
+ human_room = coordinator.chat_rooms["human_intervention"]
+ escalated_messages = [msg for msg in human_room.message_history
+ if "升级" in msg.tags]
+
+ if escalated_messages:
+ print(f"✅ 升级规则生效,Human干预群收到 {len(escalated_messages)} 条升级消息")
+ for msg in escalated_messages:
+ print(f" 📨 {msg.sender}: {msg.content[:100]}...")
+ else:
+ print("❌ 升级规则未生效")
+
+ return coordinator
+
+async def test_broadcast_rules():
+ """测试广播规则"""
+ print("\n📢 测试广播规则")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 在策略会议群发送决策消息
+ strategy_message = await coordinator.send_message(
+ "strategy_meeting", "系统",
+ "决策:采用数据驱动的论证策略",
+ MessagePriority.HIGH, ["决策", "策略"]
+ )
+ print(f"📋 策略决策发送: {strategy_message.id}")
+
+ # 等待协调规则处理
+ await asyncio.sleep(0.1)
+
+ # 检查内部讨论群是否收到广播消息
+ broadcast_count = 0
+ for room_id, room in coordinator.chat_rooms.items():
+ if room.chat_type == ChatType.INTERNAL_DISCUSSION:
+ broadcast_messages = [msg for msg in room.message_history
+ if "广播" in msg.tags]
+ if broadcast_messages:
+ broadcast_count += len(broadcast_messages)
+ print(f"✅ {room.name} 收到 {len(broadcast_messages)} 条广播消息")
+
+ if broadcast_count > 0:
+ print(f"✅ 广播规则生效,总共发送 {broadcast_count} 条广播消息")
+ else:
+ print("❌ 广播规则未生效")
+
+ return coordinator
+
+async def test_filter_rules():
+ """测试过滤规则"""
+ print("\n🔍 测试过滤规则")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 发送低质量消息
+ low_quality_message = await coordinator.send_message(
+ "main_debate", "正4",
+ "好的",
+ MessagePriority.LOW
+ )
+ print(f"📝 低质量消息发送: {low_quality_message.id}")
+
+ # 等待协调规则处理
+ await asyncio.sleep(0.1)
+
+ # 检查消息是否被过滤
+ if low_quality_message.metadata.get("filtered"):
+ print(f"✅ 过滤规则生效,消息被标记为已过滤")
+ print(f" 过滤原因: {low_quality_message.metadata.get('filter_reason')}")
+ else:
+ print("❌ 过滤规则未生效")
+
+ return coordinator
+
+async def test_discussion_merging():
+ """测试讨论合并"""
+ print("\n🔗 测试讨论合并")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 发送相关消息
+ messages = [
+ ("main_debate", "正1", "AI技术的发展速度令人惊叹", ["AI", "技术"]),
+ ("positive_internal", "正2", "我们应该强调AI技术的创新价值", ["AI", "创新"]),
+ ("negative_internal", "反1", "AI技术也带来了就业问题", ["AI", "就业"]),
+ ]
+
+ sent_messages = []
+ for chat_id, sender, content, tags in messages:
+ msg = await coordinator.send_message(chat_id, sender, content, tags=tags)
+ sent_messages.append(msg)
+ print(f"📨 发送消息: {sender} - {content[:30]}...")
+
+ # 发送触发合并的消息
+ trigger_message = await coordinator.send_message(
+ "main_debate", "系统",
+ "需要整合关于AI技术的所有讨论",
+ tags=["AI", "整合"]
+ )
+ print(f"🔗 触发合并消息: {trigger_message.id}")
+
+ # 等待协调规则处理
+ await asyncio.sleep(0.1)
+
+ # 检查策略会议群是否收到合并摘要
+ strategy_room = coordinator.chat_rooms["strategy_meeting"]
+ merge_messages = [msg for msg in strategy_room.message_history
+ if "合并" in msg.tags or "摘要" in msg.tags]
+
+ if merge_messages:
+ print(f"✅ 讨论合并生效,策略会议群收到 {len(merge_messages)} 条摘要")
+ for msg in merge_messages:
+ print(f" 📋 摘要: {msg.content[:100]}...")
+ else:
+ print("❌ 讨论合并未生效")
+
+ return coordinator
+
+async def test_permission_system():
+ """测试权限系统"""
+ print("\n🔐 测试权限系统")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 测试正常权限
+ try:
+ normal_message = await coordinator.send_message(
+ "main_debate", "正1", "这是一条正常消息"
+ )
+ print(f"✅ 正常权限测试通过: {normal_message.id}")
+ except Exception as e:
+ print(f"❌ 正常权限测试失败: {e}")
+
+ # 测试无权限用户
+ try:
+ unauthorized_message = await coordinator.send_message(
+ "main_debate", "未授权用户", "这是一条未授权消息"
+ )
+ print(f"❌ 权限系统失效,未授权用户发送成功: {unauthorized_message.id}")
+ except PermissionError as e:
+ print(f"✅ 权限系统正常,拒绝未授权用户: {e}")
+ except Exception as e:
+ print(f"❌ 权限系统异常: {e}")
+
+ # 测试内部群权限
+ try:
+ internal_message = await coordinator.send_message(
+ "positive_internal", "正2", "内部策略讨论"
+ )
+ print(f"✅ 内部群权限测试通过: {internal_message.id}")
+ except Exception as e:
+ print(f"❌ 内部群权限测试失败: {e}")
+
+ # 测试跨团队权限
+ try:
+ cross_team_message = await coordinator.send_message(
+ "positive_internal", "反1", "反方试图进入正方内部群"
+ )
+ print(f"❌ 跨团队权限控制失效: {cross_team_message.id}")
+ except PermissionError as e:
+ print(f"✅ 跨团队权限控制正常: {e}")
+ except Exception as e:
+ print(f"❌ 跨团队权限控制异常: {e}")
+
+ return coordinator
+
+async def test_system_status():
+ """测试系统状态"""
+ print("\n📊 测试系统状态")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 发送一些测试消息
+ test_messages = [
+ ("main_debate", "正1", "测试消息1"),
+ ("main_debate", "反1", "测试消息2"),
+ ("positive_internal", "正2", "内部消息1"),
+ ("negative_internal", "反2", "内部消息2"),
+ ("strategy_meeting", "系统", "策略消息1"),
+ ]
+
+ for chat_id, sender, content in test_messages:
+ await coordinator.send_message(chat_id, sender, content)
+
+ # 获取系统状态
+ status = coordinator.get_chat_status()
+
+ print(f"📈 系统状态报告:")
+ print(f" 总群聊数: {status['total_rooms']}")
+ print(f" 活跃群聊数: {status['active_rooms']}")
+ print(f" 总消息数: {status['total_messages']}")
+ print(f" 待处理消息: {status['pending_messages']}")
+ print(f" 协调规则数: {status['coordination_rules']}")
+ print(f" 活跃规则数: {status['active_rules']}")
+
+ print(f"\n📋 群聊详情:")
+ for room_id, room_info in status['rooms'].items():
+ print(f" 🏠 {room_info['name']} ({room_info['type']})")
+ print(f" 参与者: {room_info['participants']} 人")
+ print(f" 消息数: {room_info['messages']}")
+ print(f" 活跃状态: {'✅' if room_info['is_active'] else '❌'}")
+
+ # 测试数据保存
+ try:
+ coordinator.save_coordination_data("test_coordination_data.json")
+ print(f"\n💾 数据保存测试通过")
+ except Exception as e:
+ print(f"\n❌ 数据保存测试失败: {e}")
+
+ return coordinator
+
+async def test_performance():
+ """测试性能"""
+ print("\n⚡ 测试性能")
+ print("=" * 50)
+
+ coordinator = MultiChatCoordinator()
+
+ # 批量发送消息测试
+ start_time = datetime.now()
+ message_count = 100
+
+ print(f"📤 发送 {message_count} 条消息...")
+
+ for i in range(message_count):
+ chat_id = "main_debate" if i % 2 == 0 else "positive_internal"
+ sender = f"测试用户{i % 4 + 1}"
+ if chat_id == "positive_internal":
+ sender = f"正{i % 4 + 1}"
+
+ content = f"性能测试消息 {i + 1}: 这是一条用于性能测试的消息内容"
+
+ try:
+ await coordinator.send_message(chat_id, sender, content)
+ except PermissionError:
+ # 忽略权限错误,继续测试
+ pass
+
+ end_time = datetime.now()
+ duration = (end_time - start_time).total_seconds()
+
+ print(f"⏱️ 性能测试结果:")
+ print(f" 总耗时: {duration:.3f} 秒")
+ print(f" 平均每条消息: {duration/message_count*1000:.2f} 毫秒")
+ print(f" 消息处理速度: {message_count/duration:.1f} 条/秒")
+
+ # 获取最终状态
+ final_status = coordinator.get_chat_status()
+ print(f" 最终消息总数: {final_status['total_messages']}")
+
+ return coordinator
+
+async def run_all_tests():
+ """运行所有测试"""
+ print("🚀 多群聊协调系统测试开始")
+ print("=" * 60)
+
+ tests = [
+ ("基本消息功能", test_basic_messaging),
+ ("升级规则", test_escalation_rules),
+ ("广播规则", test_broadcast_rules),
+ ("过滤规则", test_filter_rules),
+ ("讨论合并", test_discussion_merging),
+ ("权限系统", test_permission_system),
+ ("系统状态", test_system_status),
+ ("性能测试", test_performance),
+ ]
+
+ results = []
+
+ for test_name, test_func in tests:
+ try:
+ print(f"\n🧪 开始测试: {test_name}")
+ coordinator = await test_func()
+ results.append((test_name, "✅ 通过", None))
+ print(f"✅ {test_name} 测试完成")
+ except Exception as e:
+ results.append((test_name, "❌ 失败", str(e)))
+ print(f"❌ {test_name} 测试失败: {e}")
+
+ # 测试结果总结
+ print("\n" + "=" * 60)
+ print("📊 测试结果总结")
+ print("=" * 60)
+
+ passed = 0
+ failed = 0
+
+ for test_name, status, error in results:
+ print(f"{status} {test_name}")
+ if error:
+ print(f" 错误: {error}")
+
+ if "✅" in status:
+ passed += 1
+ else:
+ failed += 1
+
+ print(f"\n📈 测试统计:")
+ print(f" 通过: {passed}")
+ print(f" 失败: {failed}")
+ print(f" 总计: {passed + failed}")
+ print(f" 成功率: {passed/(passed+failed)*100:.1f}%")
+
+ if failed == 0:
+ print("\n🎉 所有测试通过!多群聊协调系统运行正常。")
+ else:
+ print(f"\n⚠️ 有 {failed} 个测试失败,需要检查相关功能。")
+
+if __name__ == "__main__":
+ asyncio.run(run_all_tests())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_openbb_fallback.py b/modules/testing-framework/tests/test_openbb_fallback.py
new file mode 100644
index 0000000..d11b3dc
--- /dev/null
+++ b/modules/testing-framework/tests/test_openbb_fallback.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+验证在未安装 OpenBB 时,OpenBB Tab 的数据加载回退行为。
+该测试不强制要求安装 OpenBB,因此仅检查函数能返回非空 DataFrame。
+"""
+
+import importlib
+import types
+import pandas as pd
+
+from app.tabs.openbb_tab import _load_price_data
+
+
+def test_openbb_fallback_without_openbb():
+ # 尝试卸载 openbb 以模拟未安装环境(若本地未安装会抛错,忽略)
+ try:
+ if 'openbb' in list(importlib.sys.modules.keys()):
+ del importlib.sys.modules['openbb']
+ except Exception:
+ pass
+
+ df = _load_price_data('AAPL', 180)
+ assert isinstance(df, pd.DataFrame)
+ assert not df.empty
+ assert 'Date' in df.columns and 'Close' in df.columns
diff --git a/modules/testing-framework/tests/test_openrouter_models.py b/modules/testing-framework/tests/test_openrouter_models.py
new file mode 100644
index 0000000..c9e6d3e
--- /dev/null
+++ b/modules/testing-framework/tests/test_openrouter_models.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+测试 OpenRouter 免费模型的八仙辩论系统
+"""
+
+import asyncio
+import aiohttp
+import os
+
+# --- 被测试的模型列表 (之前认为可能不太适合的) ---
+# 根据你之前的指示和 OpenRouter 网站信息,以下模型被标记为 'free'
+# 但我们将测试它们的实际表现,特别是针对辩论任务。
+# 注意: 'gpt-oss-20b' 名称可能不准确或已变更,我们使用一个常见的免费开源模型替代
+# 'Uncensored' 因安全风险不测试
+# 'Sarvam-M' 也进行测试
+MODELS_TO_TEST = [
+ # "openchat/openchat-7b", # An alternative free model if needed for comparison
+ "google/gemma-2-9b-it", # Google's Gemma 2 9B, free on OpenRouter
+ "microsoft/phi-3-mini-128k-instruct", # Microsoft's Phi-3 Mini, free on OpenRouter
+ "qwen/qwen3-coder-8b-instruct", # Qwen3 Coder 8B, free on OpenRouter (good baseline)
+ "deepseek/deepseek-chat", # DeepSeek Chat, free on OpenRouter (good baseline)
+ "mistralai/mistral-7b-instruct", # Mistral 7B Instruct, free on OpenRouter (good baseline)
+ # --- Previously considered less suitable ---
+ "openai/gpt-3.5-turbo", # Often free tier on OpenRouter
+ "sophosympatheia/midnight-rose-70b", # An uncensored model, free, but we test it cautiously
+ "sarvamai/sarvam-2b-m", # Sarvam 2B M, free on OpenRouter
+]
+
+class OpenRouterAgent:
+ """使用 OpenRouter API 的代理"""
+
+ def __init__(self, name: str, personality: str, api_key: str, model: str):
+ self.name = name
+ self.personality = personality
+ self.api_key = api_key
+ self.model = model
+ self.api_url = "https://openrouter.ai/api/v1"
+
+ async def generate_response(self, prompt: str, session: aiohttp.ClientSession) -> str:
+ """生成AI回应"""
+ try:
+ headers = {
+ "Authorization": f"Bearer {self.api_key}",
+ "HTTP-Referer": "https://github.com/bennyschmidt/liurenchaxin", # Optional, for OpenRouter analytics
+ "X-Title": "BaXian Debate Test", # Optional, for OpenRouter analytics
+ "Content-Type": "application/json"
+ }
+
+ payload = {
+ "model": self.model,
+ "messages": [
+ {"role": "system", "content": f"你是{self.name},{self.personality}。请用中文回答。"},
+ {"role": "user", "content": prompt}
+ ],
+ # Adjust these for better output in a test scenario
+ "max_tokens": 500, # Reduced for quicker testing, but sufficient for short replies
+ "temperature": 0.7 # Slightly lower for more deterministic replies in test
+ }
+
+ async with session.post(
+ f"{self.api_url}/chat/completions",
+ headers=headers,
+ json=payload,
+ timeout=aiohttp.ClientTimeout(total=30)
+ ) as response:
+ if response.status == 200:
+ result = await response.json()
+ content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
+ if content:
+ return content.strip()
+ else:
+ error_msg = f"API returned no content for {self.name} using {self.model}. Full response: {result}"
+ print(f"❌ {error_msg}")
+ return f"[{self.name} 暂时无法回应]"
+ else:
+ error_text = await response.text()
+ error_msg = f"API error ({response.status}) for {self.name} using {self.model}: {error_text[:200]}..."
+ print(f"❌ {error_msg}")
+ return f"[{self.name} API错误: {response.status}]"
+
+ except Exception as e:
+ error_msg = f"Exception for {self.name} using {self.model}: {e}"
+ print(f"❌ {error_msg}")
+ return f"[{self.name} 连接错误]"
+
+class SimpleDebateTest:
+ """简单的模型辩论测试"""
+
+ def __init__(self, api_key: str):
+ self.api_key = api_key
+ self.topic = "工作量证明vs无限制爬虫:从李时珍采药到AI数据获取的激励机制变革"
+
+ # Create a simple agent pair for quick testing
+ self.agent1 = OpenRouterAgent(
+ "吕洞宾",
+ "八仙之首,男性代表,理性务实,善于分析问题的本质和长远影响。你代表男性视角,注重逻辑和实用性。",
+ api_key, ""
+ )
+ self.agent2 = OpenRouterAgent(
+ "何仙姑",
+ "八仙中唯一的女性,温柔智慧,善于从情感和人文角度思考问题。你代表女性视角,注重关怀和和谐。",
+ api_key, ""
+ )
+
+ async def test_model(self, model_name: str) -> dict:
+ """测试单个模型"""
+ print(f"\n--- Testing Model: {model_name} ---")
+
+ # Assign model to agents
+ self.agent1.model = model_name
+ self.agent2.model = model_name
+
+ results = {"model": model_name, "round1": "", "round2": "", "errors": []}
+
+ async with aiohttp.ClientSession() as session:
+ # Round 1: Agent 1 speaks
+ prompt1 = f"针对'{self.topic}'这个话题,请从你的角度阐述观点。要求:1)明确表达立场 2)提供具体论据 3)字数控制在150字以内"
+ print(f"\n🗣️ {self.agent1.name} 发言:")
+ try:
+ reply1 = await self.agent1.generate_response(prompt1, session)
+ print(f"{reply1}\n")
+ results["round1"] = reply1
+ except Exception as e:
+ error_msg = f"Round 1 Error: {e}"
+ print(f"❌ {error_msg}")
+ results["errors"].append(error_msg)
+ return results
+
+ # Round 2: Agent 2 responds
+ prompt2 = f"针对'{self.topic}'这个话题,{self.agent1.name}刚才说:'{reply1}'。请从你的角度回应并阐述不同观点。要求:1)回应对方观点 2)提出自己的立场 3)字数控制在150字以内"
+ print(f"🗣️ {self.agent2.name} 回应:")
+ try:
+ reply2 = await self.agent2.generate_response(prompt2, session)
+ print(f"{reply2}\n")
+ results["round2"] = reply2
+ except Exception as e:
+ error_msg = f"Round 2 Error: {e}"
+ print(f"❌ {error_msg}")
+ results["errors"].append(error_msg)
+
+ return results
+
+async def main():
+ """主函数"""
+ print("🚀 启动 OpenRouter 免费模型辩论测试...")
+
+ # 1. 获取 OpenRouter API 密钥
+ api_key = os.getenv('OPENROUTER_API_KEY')
+ if not api_key:
+ print("❌ 错误: 未找到 OPENROUTER_API_KEY 环境变量")
+ print("请设置环境变量: export OPENROUTER_API_KEY=your_api_key")
+ return
+
+ tester = SimpleDebateTest(api_key)
+ all_results = []
+
+ # 2. 依次测试每个模型
+ for model_name in MODELS_TO_TEST:
+ try:
+ result = await tester.test_model(model_name)
+ all_results.append(result)
+ # Brief pause between models
+ await asyncio.sleep(2)
+ except Exception as e:
+ print(f"❌ 测试模型 {model_name} 时发生未预期错误: {e}")
+ all_results.append({"model": model_name, "round1": "", "round2": "", "errors": [f"Unexpected test error: {e}"]})
+
+ # 3. 输出测试总结
+ print(f"\n\n--- 📊 测试总结 ---")
+ for res in all_results:
+ model = res['model']
+ errors = res['errors']
+ r1_ok = "✅" if res['round1'] and not any("无法回应" in res['round1'] or "错误" in res['round1'] for e in errors) else "❌"
+ r2_ok = "✅" if res['round2'] and not any("无法回应" in res['round2'] or "错误" in res['round2'] for e in errors) else "❌"
+ err_count = len(errors)
+
+ print(f"🔹 {model:<35} | R1: {r1_ok} | R2: {r2_ok} | Errors: {err_count}")
+
+ print("\n--- 📝 详细日志 ---")
+ for res in all_results:
+ if res['errors']:
+ print(f"\n🔸 模型: {res['model']}")
+ for err in res['errors']:
+ print(f" - {err}")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_optimized_debate_flow.py b/modules/testing-framework/tests/test_optimized_debate_flow.py
new file mode 100644
index 0000000..528c260
--- /dev/null
+++ b/modules/testing-framework/tests/test_optimized_debate_flow.py
@@ -0,0 +1,404 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+测试优化的辩论流程控制系统
+验证阶段转换和发言权争夺逻辑的改进
+"""
+
+import sys
+import os
+import time
+import threading
+from datetime import datetime, timedelta
+
+# 添加项目路径
+sys.path.append('/home/ben/liurenchaxin/src')
+
+from jixia.debates.optimized_debate_flow import (
+ OptimizedDebateFlowController,
+ FlowControlConfig,
+ FlowControlMode,
+ TransitionTrigger,
+ SpeakerSelectionStrategy,
+ DebateStage
+)
+
+def test_basic_flow_control():
+ """测试基础流程控制"""
+ print("🧪 测试基础流程控制")
+ print("-" * 30)
+
+ controller = OptimizedDebateFlowController()
+
+ # 测试获取当前发言者
+ speaker = controller.get_current_speaker()
+ print(f"✅ 当前发言者: {speaker}")
+ assert speaker is not None, "应该能获取到发言者"
+
+ # 测试记录发言
+ controller.record_speech(speaker, "这是一个测试发言")
+ print(f"✅ 发言记录成功,当前进度: {controller.stage_progress}")
+
+ # 测试流程状态
+ status = controller.get_flow_status()
+ print(f"✅ 流程状态: {status['current_stage']} 阶段")
+ assert status['current_stage'] == '起', "应该在起阶段"
+
+ return True
+
+def test_stage_transition():
+ """测试阶段转换"""
+ print("\n🧪 测试阶段转换")
+ print("-" * 30)
+
+ config = FlowControlConfig(
+ mode=FlowControlMode.STRICT,
+ transition_triggers=[TransitionTrigger.PROGRESS_BASED]
+ )
+ controller = OptimizedDebateFlowController(config)
+
+ initial_stage = controller.current_stage
+ print(f"初始阶段: {initial_stage.value}")
+
+ # 模拟完成一个阶段的所有发言
+ stage_config = controller.stage_configs[initial_stage]
+ max_progress = stage_config["max_progress"]
+
+ for i in range(max_progress):
+ speaker = controller.get_current_speaker()
+ controller.record_speech(speaker, f"第{i+1}次发言")
+
+ if i == max_progress - 1:
+ # 最后一次发言后应该自动转换阶段
+ if controller._should_advance_stage():
+ success = controller.advance_stage()
+ print(f"✅ 阶段转换成功: {success}")
+ print(f"新阶段: {controller.current_stage.value}")
+ assert controller.current_stage != initial_stage, "阶段应该已经改变"
+ break
+
+ return True
+
+def test_speaker_selection_strategies():
+ """测试发言者选择策略"""
+ print("\n🧪 测试发言者选择策略")
+ print("-" * 30)
+
+ strategies = [
+ SpeakerSelectionStrategy.ROUND_ROBIN,
+ SpeakerSelectionStrategy.CONTEXT_AWARE,
+ SpeakerSelectionStrategy.COMPETITIVE
+ ]
+
+ for strategy in strategies:
+ print(f"\n测试策略: {strategy.value}")
+
+ config = FlowControlConfig(speaker_selection_strategy=strategy)
+ controller = OptimizedDebateFlowController(config)
+
+ # 获取几个发言者
+ speakers = []
+ for i in range(3):
+ speaker = controller.get_current_speaker()
+ speakers.append(speaker)
+ controller.record_speech(speaker, f"策略测试发言 {i+1}")
+
+ print(f"发言者序列: {speakers}")
+ assert len(set(speakers)) > 0, f"策略 {strategy.value} 应该能选择发言者"
+
+ print("✅ 所有发言者选择策略测试通过")
+ return True
+
+def test_speaker_request_system():
+ """测试发言请求系统"""
+ print("\n🧪 测试发言请求系统")
+ print("-" * 30)
+
+ config = FlowControlConfig(
+ speaker_selection_strategy=SpeakerSelectionStrategy.COMPETITIVE
+ )
+ controller = OptimizedDebateFlowController(config)
+
+ # 提交发言请求
+ controller.request_speaking_turn("正1", "紧急反驳", urgency=5, topic_relevance=0.9)
+ controller.request_speaking_turn("反2", "补充论据", urgency=2, topic_relevance=0.7)
+ controller.request_speaking_turn("正3", "重要澄清", urgency=4, topic_relevance=0.8)
+
+ print(f"待处理请求数量: {len(controller.pending_requests)}")
+ assert len(controller.pending_requests) == 3, "应该有3个待处理请求"
+
+ # 获取下一个发言者(应该是最高优先级的)
+ next_speaker = controller.get_current_speaker()
+ print(f"✅ 高优先级发言者: {next_speaker}")
+
+ # 记录发言后,请求应该被移除
+ controller.record_speech(next_speaker, "响应紧急请求的发言")
+ print(f"发言后待处理请求数量: {len(controller.pending_requests)}")
+
+ return True
+
+def test_context_aware_selection():
+ """测试上下文感知选择"""
+ print("\n🧪 测试上下文感知选择")
+ print("-" * 30)
+
+ config = FlowControlConfig(
+ speaker_selection_strategy=SpeakerSelectionStrategy.CONTEXT_AWARE
+ )
+ controller = OptimizedDebateFlowController(config)
+
+ # 模拟一些发言历史
+ test_speeches = [
+ ("正1", "我支持AI投资"),
+ ("正1", "理由是技术发展迅速"), # 连续发言
+ ("反1", "但风险很高"),
+ ("正2", "我们有风控措施")
+ ]
+
+ for speaker, message in test_speeches:
+ controller.record_speech(speaker, message)
+
+ # 分析当前上下文
+ context = controller._analyze_current_context()
+ print(f"当前上下文: {context}")
+
+ # 获取下一个发言者(应该避免连续发言)
+ next_speaker = controller.get_current_speaker()
+ print(f"✅ 上下文感知选择的发言者: {next_speaker}")
+
+ # 验证不是最近的发言者
+ recent_speakers = [speech[0] for speech in test_speeches[-2:]]
+ print(f"最近发言者: {recent_speakers}")
+
+ return True
+
+def test_stage_metrics():
+ """测试阶段指标"""
+ print("\n🧪 测试阶段指标")
+ print("-" * 30)
+
+ controller = OptimizedDebateFlowController()
+
+ # 模拟一些发言
+ test_speeches = [
+ ("吕洞宾", "AI投资是未来趋势,我们应该积极参与。数据显示这个领域的增长潜力巨大。"),
+ ("何仙姑", "但是我们也要考虑风险因素。"),
+ ("铁拐李", "我同意吕洞宾的观点,因为技术发展确实很快。"),
+ ("汉钟离", "然而市场波动性不容忽视。")
+ ]
+
+ for speaker, message in test_speeches:
+ controller.record_speech(speaker, message)
+
+ # 检查阶段指标
+ metrics = controller.current_stage_metrics
+ print(f"发言数量: {metrics.speech_count}")
+ print(f"质量分数: {metrics.quality_score:.3f}")
+ print(f"参与平衡: {metrics.participation_balance:.3f}")
+ print(f"转换准备度: {metrics.transition_readiness:.3f}")
+ print(f"发言者分布: {metrics.speaker_distribution}")
+
+ assert metrics.speech_count == 4, "发言数量应该是4"
+ assert 0 <= metrics.quality_score <= 1, "质量分数应该在0-1之间"
+ assert 0 <= metrics.participation_balance <= 1, "参与平衡应该在0-1之间"
+
+ print("✅ 阶段指标计算正确")
+ return True
+
+def test_adaptive_mode():
+ """测试自适应模式"""
+ print("\n🧪 测试自适应模式")
+ print("-" * 30)
+
+ config = FlowControlConfig(
+ mode=FlowControlMode.ADAPTIVE,
+ transition_triggers=[TransitionTrigger.QUALITY_BASED, TransitionTrigger.PROGRESS_BASED],
+ quality_threshold=0.7
+ )
+ controller = OptimizedDebateFlowController(config)
+
+ # 模拟高质量发言
+ high_quality_speeches = [
+ ("吕洞宾", "根据最新的市场分析数据,AI投资领域在过去三年中显示出了显著的增长趋势。我们需要仔细分析这些数据背后的原因。"),
+ ("何仙姑", "虽然数据显示增长,但是我们也必须考虑到技术泡沫的可能性。历史上类似的技术热潮往往伴随着高风险。"),
+ ("铁拐李", "我认为关键在于风险管理。如果我们能够建立完善的风控体系,就能够在享受收益的同时控制风险。")
+ ]
+
+ for speaker, message in high_quality_speeches:
+ controller.record_speech(speaker, message)
+
+ # 检查是否达到质量阈值
+ if controller.current_stage_metrics.quality_score >= config.quality_threshold:
+ print(f"✅ 达到质量阈值: {controller.current_stage_metrics.quality_score:.3f}")
+
+ # 检查是否应该转换阶段
+ should_advance = controller._should_advance_stage()
+ print(f"是否应该推进阶段: {should_advance}")
+ break
+
+ return True
+
+def test_event_system():
+ """测试事件系统"""
+ print("\n🧪 测试事件系统")
+ print("-" * 30)
+
+ controller = OptimizedDebateFlowController()
+
+ # 记录事件
+ events_received = []
+
+ def event_handler(event):
+ events_received.append(event.event_type)
+ print(f"📢 收到事件: {event.event_type}")
+
+ # 注册事件处理器
+ controller.add_event_handler("speech_recorded", event_handler)
+ controller.add_event_handler("speaker_request", event_handler)
+
+ # 触发事件
+ controller.record_speech("测试发言者", "测试消息")
+ controller.request_speaking_turn("正1", "测试请求")
+
+ # 等待事件处理
+ time.sleep(0.1)
+
+ print(f"收到的事件: {events_received}")
+ assert "speech_recorded" in events_received, "应该收到发言记录事件"
+ assert "speaker_request" in events_received, "应该收到发言请求事件"
+
+ print("✅ 事件系统工作正常")
+ return True
+
+def test_data_persistence():
+ """测试数据持久化"""
+ print("\n🧪 测试数据持久化")
+ print("-" * 30)
+
+ controller = OptimizedDebateFlowController()
+
+ # 模拟一些活动
+ controller.record_speech("吕洞宾", "测试发言1")
+ controller.record_speech("何仙姑", "测试发言2")
+ controller.request_speaking_turn("正1", "测试请求")
+
+ # 保存数据
+ filename = "test_flow_data.json"
+ controller.save_flow_data(filename)
+
+ # 检查文件是否存在
+ assert os.path.exists(filename), "数据文件应该被创建"
+
+ # 读取并验证数据
+ import json
+ with open(filename, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+
+ assert "config" in data, "数据应该包含配置信息"
+ assert "current_state" in data, "数据应该包含当前状态"
+ assert "debate_history" in data, "数据应该包含辩论历史"
+ assert len(data["debate_history"]) == 2, "应该有2条发言记录"
+
+ print(f"✅ 数据持久化成功,文件大小: {os.path.getsize(filename)} 字节")
+
+ # 清理测试文件
+ os.remove(filename)
+
+ return True
+
+def test_performance():
+ """测试性能"""
+ print("\n🧪 测试性能")
+ print("-" * 30)
+
+ controller = OptimizedDebateFlowController()
+
+ # 测试发言者选择性能
+ start_time = time.time()
+ for i in range(100):
+ speaker = controller.get_current_speaker()
+ controller.record_speech(speaker, f"性能测试发言 {i}")
+
+ end_time = time.time()
+ duration = end_time - start_time
+
+ print(f"100次发言处理耗时: {duration:.3f} 秒")
+ print(f"平均每次处理时间: {duration/100*1000:.2f} 毫秒")
+ print(f"处理速度: {100/duration:.1f} 次/秒")
+
+ assert duration < 5.0, "100次处理应该在5秒内完成"
+
+ # 测试并发性能
+ def concurrent_speech_recording():
+ for i in range(10):
+ speaker = controller.get_current_speaker()
+ controller.record_speech(speaker, f"并发测试发言 {threading.current_thread().name}-{i}")
+
+ start_time = time.time()
+ threads = []
+ for i in range(5):
+ thread = threading.Thread(target=concurrent_speech_recording, name=f"Thread-{i}")
+ threads.append(thread)
+ thread.start()
+
+ for thread in threads:
+ thread.join()
+
+ end_time = time.time()
+ concurrent_duration = end_time - start_time
+
+ print(f"并发处理耗时: {concurrent_duration:.3f} 秒")
+ print(f"总发言数: {len(controller.debate_history)}")
+
+ print("✅ 性能测试通过")
+ return True
+
+def run_comprehensive_test():
+ """运行综合测试"""
+ print("🎭 优化的辩论流程控制系统 - 综合测试")
+ print("=" * 60)
+
+ test_functions = [
+ ("基础流程控制", test_basic_flow_control),
+ ("阶段转换", test_stage_transition),
+ ("发言者选择策略", test_speaker_selection_strategies),
+ ("发言请求系统", test_speaker_request_system),
+ ("上下文感知选择", test_context_aware_selection),
+ ("阶段指标", test_stage_metrics),
+ ("自适应模式", test_adaptive_mode),
+ ("事件系统", test_event_system),
+ ("数据持久化", test_data_persistence),
+ ("性能测试", test_performance)
+ ]
+
+ passed = 0
+ failed = 0
+
+ for test_name, test_func in test_functions:
+ try:
+ print(f"\n{'='*20} {test_name} {'='*20}")
+ result = test_func()
+ if result:
+ print(f"✅ {test_name} - 通过")
+ passed += 1
+ else:
+ print(f"❌ {test_name} - 失败")
+ failed += 1
+ except Exception as e:
+ print(f"❌ {test_name} - 错误: {str(e)}")
+ failed += 1
+
+ print("\n" + "=" * 60)
+ print(f"📊 测试结果统计")
+ print(f"通过: {passed}/{len(test_functions)} ({passed/len(test_functions)*100:.1f}%)")
+ print(f"失败: {failed}/{len(test_functions)} ({failed/len(test_functions)*100:.1f}%)")
+
+ if failed == 0:
+ print("🎉 所有测试通过!优化的辩论流程控制系统运行正常。")
+ else:
+ print(f"⚠️ 有 {failed} 个测试失败,需要进一步优化。")
+
+ return passed, failed
+
+if __name__ == "__main__":
+ run_comprehensive_test()
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_simple_api.py b/modules/testing-framework/tests/test_simple_api.py
new file mode 100644
index 0000000..3cc245e
--- /dev/null
+++ b/modules/testing-framework/tests/test_simple_api.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+简单的API测试脚本
+测试.env.example中的配置是否正确
+"""
+
+import requests
+import json
+import logging
+
+# 配置日志
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+logger = logging.getLogger(__name__)
+
+def test_simple_api():
+ """简单的API测试"""
+
+ # 从.env.example读取的配置
+ BASE_URL = "http://master.tailnet-68f9.ts.net:40012"
+ API_KEY = "sk-0jdcGHZJpX2oUJmyEs7zVA"
+ MODEL = "gemini/gemini-2.5-pro"
+
+ logger.info(f"🧪 测试配置:")
+ logger.info(f"📡 BASE_URL: {BASE_URL}")
+ logger.info(f"🔑 API_KEY: {API_KEY[:10]}...")
+ logger.info(f"🤖 MODEL: {MODEL}")
+
+ # 最简单的请求
+ payload = {
+ "model": MODEL,
+ "messages": [
+ {"role": "user", "content": "Hello"}
+ ],
+ "max_tokens": 50
+ }
+
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {API_KEY}"
+ }
+
+ try:
+ logger.info("🚀 发送请求...")
+ response = requests.post(
+ f"{BASE_URL}/chat/completions",
+ json=payload,
+ headers=headers,
+ timeout=120 # 增加超时时间
+ )
+
+ logger.info(f"📊 状态码: {response.status_code}")
+
+ if response.status_code == 200:
+ result = response.json()
+ logger.info(f"✅ 请求成功!")
+ logger.info(f"📋 响应: {json.dumps(result, ensure_ascii=False, indent=2)}")
+ return True
+ else:
+ logger.error(f"❌ 请求失败: {response.status_code}")
+ logger.error(f"📋 错误响应: {response.text}")
+ return False
+
+ except requests.exceptions.Timeout:
+ logger.error(f"⏰ 请求超时 (120秒)")
+ return False
+ except requests.exceptions.ConnectionError as e:
+ logger.error(f"🔌 连接错误: {e}")
+ return False
+ except Exception as e:
+ logger.error(f"💥 未知错误: {e}")
+ return False
+
+if __name__ == "__main__":
+ logger.info("🎯 开始简单API测试")
+ success = test_simple_api()
+
+ if success:
+ logger.info("🎉 测试成功!")
+ else:
+ logger.error("💀 测试失败!")
+
+ logger.info("🏁 测试完成")
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_single_model.py b/modules/testing-framework/tests/test_single_model.py
new file mode 100644
index 0000000..ed11518
--- /dev/null
+++ b/modules/testing-framework/tests/test_single_model.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Test script for a single model from OpenRouter
+"""
+
+import asyncio
+import aiohttp
+import os
+import json
+
+# Get API key from environment or .env file
+api_key = os.getenv('OPENROUTER_API_KEY')
+if not api_key:
+ with open(".env", "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("sk-or-v1-"):
+ api_key = line
+ break
+
+if not api_key:
+ print("❌ No API key found")
+ exit(1)
+
+async def test_model(model_name):
+ """Test a single model"""
+ # Remove :free tag for API call
+ clean_model = model_name.split(":")[0]
+
+ print(f"🚀 Testing model: {model_name}")
+ print(f" Clean name: {clean_model}")
+
+ url = "https://openrouter.ai/api/v1/chat/completions"
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json"
+ }
+ payload = {
+ "model": clean_model,
+ "messages": [
+ {"role": "user", "content": "Explain the concept of 'working hard' in one short sentence."}
+ ],
+ "max_tokens": 100
+ }
+
+ print(f" Payload: {json.dumps(payload, indent=2)}")
+
+ try:
+ async with aiohttp.ClientSession() as session:
+ async with session.post(url, headers=headers, json=payload, timeout=30) as response:
+ print(f" Status: {response.status}")
+
+ # Print response headers
+ print(" Response Headers:")
+ for key, value in response.headers.items():
+ print(f" {key}: {value}")
+
+ if response.status == 200:
+ result = await response.json()
+ print(f" Full response: {json.dumps(result, indent=2)}")
+
+ content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
+ print(f"✅ Success - Content: '{content}'")
+ return True
+ else:
+ error_text = await response.text()
+ print(f"❌ Status {response.status}: {error_text}")
+ return False
+ except Exception as e:
+ print(f"💥 Exception: {str(e)}")
+ return False
+
+async def main():
+ """Main function"""
+ model_to_test = "openai/gpt-oss-20b:free"
+ await test_model(model_to_test)
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_single_model2.py b/modules/testing-framework/tests/test_single_model2.py
new file mode 100644
index 0000000..a8d3ad6
--- /dev/null
+++ b/modules/testing-framework/tests/test_single_model2.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Test script for a single model from OpenRouter
+"""
+
+import asyncio
+import aiohttp
+import os
+import json
+
+# Get API key from environment or .env file
+api_key = os.getenv('OPENROUTER_API_KEY')
+if not api_key:
+ with open(".env", "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("sk-or-v1-"):
+ api_key = line
+ break
+
+if not api_key:
+ print("❌ No API key found")
+ exit(1)
+
+async def test_model(model_name):
+ """Test a single model"""
+ # Remove :free tag for API call
+ clean_model = model_name.split(":")[0]
+
+ print(f"🚀 Testing model: {model_name}")
+ print(f" Clean name: {clean_model}")
+
+ url = "https://openrouter.ai/api/v1/chat/completions"
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json"
+ }
+ payload = {
+ "model": clean_model,
+ "messages": [
+ {"role": "user", "content": "Explain the concept of 'working hard' in one short sentence."}
+ ],
+ "max_tokens": 100
+ }
+
+ print(f" Payload: {json.dumps(payload, indent=2)}")
+
+ try:
+ async with aiohttp.ClientSession() as session:
+ async with session.post(url, headers=headers, json=payload, timeout=30) as response:
+ print(f" Status: {response.status}")
+
+ # Print response headers
+ print(" Response Headers:")
+ for key, value in response.headers.items():
+ print(f" {key}: {value}")
+
+ if response.status == 200:
+ result = await response.json()
+ print(f" Full response: {json.dumps(result, indent=2)}")
+
+ content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
+ print(f"✅ Success - Content: '{content}'")
+ return True
+ else:
+ error_text = await response.text()
+ print(f"❌ Status {response.status}: {error_text}")
+ return False
+ except Exception as e:
+ print(f"💥 Exception: {str(e)}")
+ return False
+
+async def main():
+ """Main function"""
+ model_to_test = "qwen/qwq-32b:free"
+ await test_model(model_to_test)
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_single_model3.py b/modules/testing-framework/tests/test_single_model3.py
new file mode 100644
index 0000000..8dd7ea1
--- /dev/null
+++ b/modules/testing-framework/tests/test_single_model3.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Test script for a single model from OpenRouter
+"""
+
+import asyncio
+import aiohttp
+import os
+import json
+
+# Get API key from environment or .env file
+api_key = os.getenv('OPENROUTER_API_KEY')
+if not api_key:
+ with open(".env", "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("sk-or-v1-"):
+ api_key = line
+ break
+
+if not api_key:
+ print("❌ No API key found")
+ exit(1)
+
+async def test_model(model_name):
+ """Test a single model"""
+ # Remove :free tag for API call
+ clean_model = model_name.split(":")[0]
+
+ print(f"🚀 Testing model: {model_name}")
+ print(f" Clean name: {clean_model}")
+
+ url = "https://openrouter.ai/api/v1/chat/completions"
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json"
+ }
+ payload = {
+ "model": clean_model,
+ "messages": [
+ {"role": "user", "content": "Explain the concept of 'working hard' in one short sentence."}
+ ],
+ "max_tokens": 100
+ }
+
+ print(f" Payload: {json.dumps(payload, indent=2)}")
+
+ try:
+ async with aiohttp.ClientSession() as session:
+ async with session.post(url, headers=headers, json=payload, timeout=30) as response:
+ print(f" Status: {response.status}")
+
+ # Print response headers
+ print(" Response Headers:")
+ for key, value in response.headers.items():
+ print(f" {key}: {value}")
+
+ if response.status == 200:
+ result = await response.json()
+ print(f" Full response: {json.dumps(result, indent=2)}")
+
+ content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
+ print(f"✅ Success - Content: '{content}'")
+ return True
+ else:
+ error_text = await response.text()
+ print(f"❌ Status {response.status}: {error_text}")
+ return False
+ except Exception as e:
+ print(f"💥 Exception: {str(e)}")
+ return False
+
+async def main():
+ """Main function"""
+ model_to_test = "mistralai/mistral-small-3.1-24b-instruct:free"
+ await test_model(model_to_test)
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_taishang_api.py b/modules/testing-framework/tests/test_taishang_api.py
new file mode 100644
index 0000000..b04b857
--- /dev/null
+++ b/modules/testing-framework/tests/test_taishang_api.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Test script for the Taishang Laojun API (Zhipu AI GLM-4.5)
+"""
+
+import asyncio
+import aiohttp
+import json
+
+async def test_taishang_api():
+ """Test the Taishang Laojun API"""
+ # Zhipu AI API configuration
+ zhipu_api_key = "cc95756306b2cb9748c8df15f9063eaf.hlvXbZeoLnPhyoLw"
+ url = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
+
+ messages = [
+ {"role": "system", "content": "You are Taishang Laojun, a wise philosopher and project manager for the Ba Xian (Eight Immortals). You excel at deep analysis and strategic planning. Please respond in JSON format."},
+ {"role": "user", "content": "Analyze the concept of 'working hard' and provide a JSON response with two keys: 'definition' and 'importance'."}
+ ]
+
+ data = {
+ "model": "glm-4.5-air",
+ "messages": messages,
+ "max_tokens": 500,
+ "temperature": 0.7,
+ "stream": False,
+ "tools": [],
+ "tool_choice": "none"
+ }
+
+ headers = {
+ "Content-Type": "application/json",
+ "Authorization": f"Bearer {zhipu_api_key}"
+ }
+
+ print("🚀 Testing Taishang Laojun API (Zhipu AI GLM-4.5)...")
+ print(f" URL: {url}")
+ print(f" Model: {data['model']}")
+ print(f" Messages: {json.dumps(messages, ensure_ascii=False, indent=2)}")
+ print(f" Data: {json.dumps(data, ensure_ascii=False, indent=2)}")
+
+ try:
+ async with aiohttp.ClientSession() as session:
+ async with session.post(url, headers=headers, json=data, timeout=30) as response:
+ print(f" Status: {response.status}")
+
+ if response.status == 200:
+ result = await response.json()
+ print(f" Full response: {json.dumps(result, ensure_ascii=False, indent=2)}")
+
+ # Extract content
+ if 'choices' in result and len(result['choices']) > 0:
+ choice = result['choices'][0]
+ content = ""
+
+ # Try to get content from different fields
+ if 'message' in choice and 'content' in choice['message']:
+ content = choice['message']['content']
+
+ # If content is empty, try reasoning_content
+ if not content and 'message' in choice and 'reasoning_content' in choice['message']:
+ content = choice['message']['reasoning_content']
+
+ if content:
+ print(f"✅ Success - Content: {content[:200]}...") # Truncate for readability
+ return True
+
+ print("❌ Content not found in response")
+ return False
+ else:
+ error_text = await response.text()
+ print(f"❌ Status {response.status}: {error_text}")
+ return False
+ except Exception as e:
+ print(f"💥 Exception: {str(e)}")
+ return False
+
+async def main():
+ """Main function"""
+ await test_taishang_api()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_v2_1_comprehensive.py b/modules/testing-framework/tests/test_v2_1_comprehensive.py
new file mode 100644
index 0000000..63f84e3
--- /dev/null
+++ b/modules/testing-framework/tests/test_v2_1_comprehensive.py
@@ -0,0 +1,745 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+集夏v2.1.0 综合功能测试
+验证所有新功能的集成效果和系统稳定性
+"""
+import asyncio
+import sys
+import os
+import time
+import threading
+import json
+from datetime import datetime, timedelta
+
+# 添加项目路径
+sys.path.append('/home/ben/liurenchaxin/src')
+
+# 导入所有核心模块
+try:
+ from jixia.debates.enhanced_priority_algorithm import EnhancedPriorityAlgorithm
+ from jixia.debates.optimized_debate_flow import OptimizedDebateFlowController, FlowControlMode
+ from jixia.intervention.human_intervention_system import DebateHealthMonitor
+ from jixia.coordination.multi_chat_coordinator import MultiChatCoordinator
+except ImportError as e:
+ print(f"❌ 模块导入失败: {e}")
+ print("请确保所有模块都已正确安装")
+ sys.exit(1)
+
+class V2_1_IntegrationTester:
+ """v2.1.0 集成测试器"""
+
+ def __init__(self):
+ self.test_results = {}
+ self.performance_metrics = {}
+ self.error_log = []
+
+ # 初始化各个组件
+ try:
+ self.priority_algorithm = EnhancedPriorityAlgorithm()
+ self.flow_controller = OptimizedDebateFlowController()
+ self.health_monitor = DebateHealthMonitor()
+ self.chat_coordinator = MultiChatCoordinator()
+ print("✅ 所有核心组件初始化成功")
+ except Exception as e:
+ print(f"❌ 组件初始化失败: {e}")
+ self.error_log.append(f"初始化错误: {e}")
+
+ def test_priority_algorithm_integration(self):
+ """测试优先级算法集成"""
+ print("\n🧪 测试优先级算法集成")
+ print("-" * 40)
+
+ try:
+ # 模拟辩论场景
+ test_speeches = [
+ {
+ "speaker": "吕洞宾",
+ "content": "根据最新的市场数据分析,AI投资领域显示出强劲的增长潜力。我们应该抓住这个机会。",
+ "context": {"stage": "起", "topic": "AI投资", "recent_speakers": []}
+ },
+ {
+ "speaker": "何仙姑",
+ "content": "但是我们必须谨慎考虑风险因素!市场波动性很大。",
+ "context": {"stage": "承", "topic": "AI投资", "recent_speakers": ["吕洞宾"]}
+ },
+ {
+ "speaker": "铁拐李",
+ "content": "我同意吕洞宾的观点,技术发展确实迅速,但何仙姑提到的风险也值得重视。",
+ "context": {"stage": "转", "topic": "AI投资", "recent_speakers": ["吕洞宾", "何仙姑"]}
+ }
+ ]
+
+ priorities = []
+ for speech in test_speeches:
+ analysis = self.priority_algorithm.analyze_speech(
+ speech["content"],
+ speech["speaker"],
+ speech["context"]
+ )
+
+ # 获取详细的分数分解
+ speaker = speech["speaker"]
+ context = speech["context"]
+ recent_speeches = test_speeches[:test_speeches.index(speech)]
+
+ profile = self.priority_algorithm._get_or_create_speaker_profile(speaker)
+ self.priority_algorithm._update_speaker_profile(profile, recent_speeches)
+
+ rebuttal_urgency = self.priority_algorithm._calculate_rebuttal_urgency(speaker, context, recent_speeches)
+ argument_strength = self.priority_algorithm._calculate_argument_strength(speaker, profile)
+ time_pressure = self.priority_algorithm._calculate_time_pressure(speaker, context)
+ audience_reaction = self.priority_algorithm._calculate_audience_reaction(speaker, context)
+ strategy_need = self.priority_algorithm._calculate_strategy_need(speaker, context, profile)
+
+ priority = self.priority_algorithm.calculate_priority(
+ speaker,
+ context,
+ recent_speeches
+ )
+ priorities.append((speaker, priority))
+
+ print(f"发言者: {speaker}")
+ print(f" 反驳紧急性: {rebuttal_urgency:.6f}")
+ print(f" 论证强度: {argument_strength:.6f}")
+ print(f" 时间压力: {time_pressure:.6f}")
+ print(f" 观众反应: {audience_reaction:.6f}")
+ print(f" 策略需求: {strategy_need:.6f}")
+ print(f" 最终优先级: {priority:.6f}")
+ print()
+
+ # 调试输出
+ print(f"所有优先级值: {[p[1] for p in priorities]}")
+ print(f"唯一优先级数量: {len(set(p[1] for p in priorities))}")
+ print(f"优先级差异: {max(p[1] for p in priorities) - min(p[1] for p in priorities)}")
+
+ # 验证优先级计算
+ assert all(0 <= p[1] <= 1 for p in priorities), "优先级应该在0-1之间"
+ assert len(set(p[1] for p in priorities)) > 1, "不同发言应该有不同优先级"
+
+ self.test_results["priority_algorithm_integration"] = True
+ print("✅ 优先级算法集成测试通过")
+ return True
+
+ except Exception as e:
+ print(f"❌ 优先级算法集成测试失败: {e}")
+ self.error_log.append(f"优先级算法集成错误: {e}")
+ self.test_results["priority_algorithm_integration"] = False
+ return False
+
+ def test_flow_controller_integration(self):
+ """测试流程控制器集成"""
+ print("\n🧪 测试流程控制器集成")
+ print("-" * 40)
+
+ try:
+ # 测试与优先级算法的集成
+ initial_stage = self.flow_controller.current_stage
+ print(f"初始阶段: {initial_stage.value}")
+
+ # 模拟完整的辩论流程
+ test_sequence = [
+ ("吕洞宾", "开场陈述:AI投资是未来发展的关键"),
+ ("何仙姑", "反方观点:需要谨慎评估风险"),
+ ("铁拐李", "补充论据:技术发展支持投资决策"),
+ ("汉钟离", "风险分析:市场不确定性因素"),
+ ("曹国舅", "综合观点:平衡收益与风险"),
+ ("蓝采和", "实践经验:类似投资案例分析"),
+ ("韩湘子", "未来展望:长期发展趋势"),
+ ("张果老", "总结陈词:理性投资建议")
+ ]
+
+ stage_transitions = 0
+ for speaker, content in test_sequence:
+ # 记录发言
+ self.flow_controller.record_speech(speaker, content)
+
+ # 检查是否需要推进阶段
+ if hasattr(self.flow_controller, '_should_advance_stage') and self.flow_controller._should_advance_stage():
+ old_stage = self.flow_controller.current_stage
+ if self.flow_controller.advance_stage():
+ stage_transitions += 1
+ print(f"阶段转换: {old_stage.value} -> {self.flow_controller.current_stage.value}")
+
+ # 获取流程状态
+ status = self.flow_controller.get_flow_status()
+ print(f"发言者: {speaker}, 当前阶段: {status['current_stage']}, 进度: {status['stage_progress']}")
+
+ # 验证流程控制
+ final_status = self.flow_controller.get_flow_status()
+ total_speeches = len(self.flow_controller.debate_history)
+ assert total_speeches == len(test_sequence), f"发言总数应该匹配,期望{len(test_sequence)},实际{total_speeches}"
+ assert stage_transitions > 0, "应该发生阶段转换"
+
+ self.test_results["flow_controller_integration"] = True
+ print(f"✅ 流程控制器集成测试通过,发生了 {stage_transitions} 次阶段转换")
+ return True
+
+ except Exception as e:
+ print(f"❌ 流程控制器集成测试失败: {e}")
+ self.error_log.append(f"流程控制器集成错误: {e}")
+ self.test_results["flow_controller_integration"] = False
+ return False
+
+ def test_health_monitor_integration(self):
+ """测试健康监控集成"""
+ print("\n🧪 测试健康监控集成")
+ print("-" * 40)
+
+ try:
+ # 模拟辩论数据
+ debate_data = {
+ "participants": ["吕洞宾", "何仙姑", "铁拐李", "汉钟离"],
+ "speeches": [
+ {"speaker": "吕洞宾", "content": "我强烈支持这个提案", "timestamp": datetime.now()},
+ {"speaker": "何仙姑", "content": "我完全反对,这太危险了", "timestamp": datetime.now()},
+ {"speaker": "铁拐李", "content": "让我们理性分析一下", "timestamp": datetime.now()},
+ {"speaker": "汉钟离", "content": "数据显示情况复杂", "timestamp": datetime.now()}
+ ],
+ "current_stage": "承",
+ "duration": timedelta(minutes=15)
+ }
+
+ # 更新健康监控
+ self.health_monitor.update_metrics(debate_data)
+
+ # 检查健康状态
+ health_status = self.health_monitor.get_health_status()
+ health_report = self.health_monitor.get_health_report()
+ print(f"健康状态: {health_status.value}")
+ print(f"整体分数: {health_report['overall_score']:.1f}")
+ print(f"监控指标数量: {len(health_report['metrics'])}")
+ print(f"活跃警报: {health_report['active_alerts']}个")
+
+ # 模拟问题场景
+ problematic_data = {
+ "participants": ["吕洞宾", "何仙姑"],
+ "speeches": [
+ {"speaker": "吕洞宾", "content": "你们都是白痴!", "timestamp": datetime.now()},
+ {"speaker": "吕洞宾", "content": "我说了算!", "timestamp": datetime.now()},
+ {"speaker": "吕洞宾", "content": "闭嘴!", "timestamp": datetime.now()}
+ ],
+ "current_stage": "转",
+ "duration": timedelta(minutes=30)
+ }
+
+ self.health_monitor.update_metrics(problematic_data)
+
+ # 检查是否触发警报
+ alerts = self.health_monitor.active_alerts
+ print(f"活跃警报数量: {len(alerts)}")
+
+ # 验证监控功能
+ assert health_status is not None, "应该有健康状态"
+ assert isinstance(health_status, type(health_status)), "健康状态应该是HealthStatus枚举"
+
+ self.test_results["health_monitor_integration"] = True
+ print("✅ 健康监控集成测试通过")
+ return True
+
+ except Exception as e:
+ print(f"❌ 健康监控集成测试失败: {e}")
+ self.error_log.append(f"健康监控集成错误: {e}")
+ self.test_results["health_monitor_integration"] = False
+ return False
+
+ async def test_chat_coordinator_integration(self):
+ """测试多群聊协调集成"""
+ print("\n🧪 测试多群聊协调集成")
+ print("-" * 40)
+
+ try:
+ # 模拟多群聊场景
+ main_chat_message = {
+ "chat_id": "main_debate",
+ "speaker": "吕洞宾",
+ "content": "我认为我们应该投资AI技术",
+ "timestamp": datetime.now()
+ }
+
+ # 处理主群聊消息
+ await self.chat_coordinator.handle_message(main_chat_message)
+
+ # 模拟策略讨论
+ strategy_message = {
+ "chat_id": "strategy_positive",
+ "speaker": "铁拐李",
+ "content": "我们需要准备更多技术数据来支持论点",
+ "timestamp": datetime.now()
+ }
+
+ await self.chat_coordinator.handle_message(strategy_message)
+
+ # 检查消息路由
+ routing_status = self.chat_coordinator.get_routing_status()
+ print(f"路由状态: {routing_status}")
+
+ # 模拟协调决策
+ coordination_result = await self.chat_coordinator.coordinate_response(
+ main_chat_message,
+ context={"stage": "承", "topic": "AI投资"}
+ )
+
+ print(f"协调结果: {coordination_result}")
+
+ # 验证协调功能
+ assert coordination_result is not None, "应该有协调结果"
+
+ self.test_results["chat_coordinator_integration"] = True
+ print("✅ 多群聊协调集成测试通过")
+ return True
+
+ except Exception as e:
+ print(f"❌ 多群聊协调集成测试失败: {e}")
+ self.error_log.append(f"多群聊协调集成错误: {e}")
+ self.test_results["chat_coordinator_integration"] = False
+ return False
+
+ async def test_cross_component_integration(self):
+ """测试跨组件集成"""
+ print("\n🧪 测试跨组件集成")
+ print("-" * 40)
+
+ try:
+ # 清空之前的发言历史
+ self.flow_controller.debate_history.clear()
+
+ # 模拟完整的辩论流程
+ debate_scenario = {
+ "topic": "人工智能投资策略",
+ "participants": ["吕洞宾", "何仙姑", "铁拐李", "汉钟离"],
+ "duration": 30 # 分钟
+ }
+
+ print(f"开始辩论: {debate_scenario['topic']}")
+
+ # 1. 流程控制器管理发言顺序
+ speakers_sequence = []
+ for i in range(8): # 模拟8轮发言
+ speaker = self.flow_controller.get_current_speaker()
+ speakers_sequence.append(speaker)
+
+ # 2. 生成发言内容(简化)
+ content = f"这是{speaker}在第{i+1}轮的发言,关于{debate_scenario['topic']}"
+
+ # 3. 优先级算法分析发言
+ context = {
+ "stage": self.flow_controller.current_stage.value,
+ "topic": debate_scenario['topic'],
+ "recent_speakers": speakers_sequence[-3:]
+ }
+
+ analysis = self.priority_algorithm.analyze_speech(content, speaker, context)
+
+ # 构建正确格式的recent_speeches
+ recent_speeches = []
+ for j, prev_speaker in enumerate(speakers_sequence):
+ recent_speeches.append({
+ "speaker": prev_speaker,
+ "content": f"这是{prev_speaker}在第{j+1}轮的发言",
+ "timestamp": datetime.now().isoformat(),
+ "team": "positive" if "正" in prev_speaker else "negative"
+ })
+
+ priority = self.priority_algorithm.calculate_priority(speaker, context, recent_speeches)
+
+ # 4. 记录发言到流程控制器
+ self.flow_controller.record_speech(speaker, content)
+
+ # 5. 更新健康监控
+ debate_data = {
+ "participants": debate_scenario['participants'],
+ "speeches": [{"speaker": speaker, "content": content, "timestamp": datetime.now()}],
+ "current_stage": self.flow_controller.current_stage.value,
+ "duration": timedelta(minutes=i*2)
+ }
+ self.health_monitor.update_metrics(debate_data)
+
+ # 6. 多群聊协调处理
+ message = {
+ "chat_id": "main_debate",
+ "speaker": speaker,
+ "content": content,
+ "timestamp": datetime.now()
+ }
+ # 异步调用
+ try:
+ await self.chat_coordinator.handle_message(message)
+ except Exception as e:
+ print(f"警告: 消息处理失败: {e}")
+
+ print(f"第{i+1}轮 - 发言者: {speaker}, 优先级: {priority:.3f}, 阶段: {context['stage']}")
+
+ # 验证集成效果
+ print("\n开始获取各组件状态...")
+
+ try:
+ flow_status = self.flow_controller.get_flow_status()
+ print(f"✅ 流程状态获取成功: {type(flow_status)}")
+ except Exception as e:
+ print(f"❌ 流程状态获取失败: {e}")
+ raise
+
+ try:
+ health_status = self.health_monitor.get_health_status()
+ print(f"✅ 健康状态获取成功: {type(health_status)}")
+ except Exception as e:
+ print(f"❌ 健康状态获取失败: {e}")
+ raise
+
+ try:
+ routing_status = self.chat_coordinator.get_routing_status()
+ print(f"✅ 路由状态获取成功: {type(routing_status)}, 值: {routing_status}")
+ except Exception as e:
+ print(f"❌ 路由状态获取失败: {e}")
+ raise
+
+ print(f"\n集成测试结果:")
+ print(f"- 总发言数: {len(self.flow_controller.debate_history)}")
+ print(f"- 当前阶段: {flow_status['current_stage']}")
+ print(f"- 健康状态: {health_status.value}")
+
+ # 安全地访问routing_status
+ if isinstance(routing_status, dict):
+ print(f"- 活跃路由数: {routing_status.get('active_routes', 0)}")
+ print(f"- 消息队列大小: {routing_status.get('message_queue_size', 0)}")
+ print(f"- 总群聊数: {routing_status.get('total_rooms', 0)}")
+ else:
+ print(f"- 路由状态: {routing_status}")
+ print(f"- 路由状态类型: {type(routing_status)}")
+
+ # 验证所有组件都正常工作
+ total_speeches = len(self.flow_controller.debate_history)
+ assert total_speeches == 8, f"应该记录8次发言,实际{total_speeches}次"
+ assert health_status is not None, "应该有健康状态"
+ assert len(speakers_sequence) == 8, "应该有8个发言者记录"
+
+ self.test_results["cross_component_integration"] = True
+ print("✅ 跨组件集成测试通过")
+ return True
+
+ except Exception as e:
+ import traceback
+ print(f"❌ 跨组件集成测试失败: {e}")
+ print(f"详细错误信息:")
+ traceback.print_exc()
+ self.error_log.append(f"跨组件集成错误: {e}")
+ self.test_results["cross_component_integration"] = False
+ return False
+
+ def test_performance_under_load(self):
+ """测试负载下的性能"""
+ print("\n🧪 测试负载下的性能")
+ print("-" * 40)
+
+ try:
+ # 性能测试参数
+ num_speeches = 100
+ num_threads = 5
+
+ def simulate_debate_load():
+ """模拟辩论负载"""
+ thread_name = threading.current_thread().name
+ for i in range(num_speeches // num_threads):
+ try:
+ # 模拟发言处理
+ speaker = f"Speaker-{thread_name}-{i}"
+ content = f"这是来自{speaker}的测试发言 {i}"
+
+ # 优先级计算
+ context = {"stage": "承", "topic": "性能测试", "recent_speakers": []}
+ analysis = self.priority_algorithm.analyze_speech(content, speaker, context)
+ priority = self.priority_algorithm.calculate_priority(speaker, context, [])
+
+ # 流程记录
+ self.flow_controller.record_speech(speaker, content)
+
+ # 健康监控
+ debate_data = {
+ "participants": [speaker],
+ "speeches": [{"speaker": speaker, "content": content, "timestamp": datetime.now()}],
+ "current_stage": "承",
+ "duration": timedelta(seconds=i)
+ }
+ self.health_monitor.update_metrics(debate_data)
+
+ except Exception as e:
+ self.error_log.append(f"负载测试错误 {thread_name}-{i}: {e}")
+
+ # 开始性能测试
+ start_time = time.time()
+
+ threads = []
+ for i in range(num_threads):
+ thread = threading.Thread(target=simulate_debate_load, name=f"LoadTest-{i}")
+ threads.append(thread)
+ thread.start()
+
+ for thread in threads:
+ thread.join()
+
+ end_time = time.time()
+ duration = end_time - start_time
+
+ # 计算性能指标
+ total_operations = num_speeches * 4 # 每次发言包含4个操作
+ ops_per_second = total_operations / duration
+
+ self.performance_metrics = {
+ "total_operations": total_operations,
+ "duration": duration,
+ "ops_per_second": ops_per_second,
+ "avg_operation_time": duration / total_operations * 1000, # 毫秒
+ "concurrent_threads": num_threads,
+ "errors": len([e for e in self.error_log if "负载测试错误" in e])
+ }
+
+ print(f"性能测试结果:")
+ print(f"- 总操作数: {total_operations}")
+ print(f"- 执行时间: {duration:.3f} 秒")
+ print(f"- 操作速度: {ops_per_second:.1f} 操作/秒")
+ print(f"- 平均操作时间: {self.performance_metrics['avg_operation_time']:.2f} 毫秒")
+ print(f"- 并发线程: {num_threads}")
+ print(f"- 错误数量: {self.performance_metrics['errors']}")
+
+ # 性能验证
+ assert ops_per_second > 100, "操作速度应该超过100操作/秒"
+ assert self.performance_metrics['errors'] == 0, "不应该有错误"
+
+ self.test_results["performance_under_load"] = True
+ print("✅ 负载性能测试通过")
+ return True
+
+ except Exception as e:
+ print(f"❌ 负载性能测试失败: {e}")
+ self.error_log.append(f"负载性能测试错误: {e}")
+ self.test_results["performance_under_load"] = False
+ return False
+
+ def test_data_consistency(self):
+ """测试数据一致性"""
+ print("\n🧪 测试数据一致性")
+ print("-" * 40)
+
+ try:
+ # 为了确保数据一致性测试的准确性,创建新的flow_controller实例
+ from jixia.debates.optimized_debate_flow import OptimizedDebateFlowController, FlowControlMode
+ test_flow_controller = OptimizedDebateFlowController()
+
+ # 模拟数据操作
+ test_data = {
+ "speakers": ["吕洞宾", "何仙姑", "铁拐李"],
+ "speeches": [
+ "AI投资具有巨大潜力",
+ "但风险也不容忽视",
+ "我们需要平衡收益与风险"
+ ]
+ }
+
+ # 1. 保存流程控制器数据
+ for i, (speaker, content) in enumerate(zip(test_data["speakers"], test_data["speeches"])):
+ test_flow_controller.record_speech(speaker, content)
+ print(f"记录发言 {i+1}: {speaker} - {content[:30]}...")
+
+ print(f"当前debate_history长度: {len(test_flow_controller.debate_history)}")
+
+ flow_data_file = "test_flow_consistency.json"
+ test_flow_controller.save_flow_data(flow_data_file)
+
+ # 2. 保存健康监控数据
+ debate_data = {
+ "participants": test_data["speakers"],
+ "speeches": [
+ {"speaker": s, "content": c, "timestamp": datetime.now()}
+ for s, c in zip(test_data["speakers"], test_data["speeches"])
+ ],
+ "current_stage": "承",
+ "duration": timedelta(minutes=10)
+ }
+ self.health_monitor.update_metrics(debate_data)
+
+ health_data_file = "test_health_consistency.json"
+ self.health_monitor.save_monitoring_data(health_data_file)
+
+ # 3. 验证数据文件
+ assert os.path.exists(flow_data_file), "流程数据文件应该存在"
+ assert os.path.exists(health_data_file), "健康数据文件应该存在"
+
+ # 4. 读取并验证数据内容
+ with open(flow_data_file, 'r', encoding='utf-8') as f:
+ flow_data = json.load(f)
+
+ with open(health_data_file, 'r', encoding='utf-8') as f:
+ health_data = json.load(f)
+
+ # 调试信息
+ print(f"读取的flow_data中debate_history长度: {len(flow_data.get('debate_history', []))}")
+ print(f"debate_history内容: {flow_data.get('debate_history', [])}")
+
+ # 验证数据完整性
+ actual_count = len(flow_data.get("debate_history", []))
+ assert actual_count == 3, f"应该有3条发言记录,实际有{actual_count}条"
+ assert "health_metrics" in health_data, "应该包含健康指标"
+ assert "monitoring_config" in health_data, "应该包含监控配置"
+
+ print(f"数据一致性验证:")
+ print(f"- 流程数据记录: {len(flow_data['debate_history'])} 条")
+ print(f"- 健康数据大小: {os.path.getsize(health_data_file)} 字节")
+ print(f"- 流程数据大小: {os.path.getsize(flow_data_file)} 字节")
+
+ # 清理测试文件
+ os.remove(flow_data_file)
+ os.remove(health_data_file)
+
+ self.test_results["data_consistency"] = True
+ print("✅ 数据一致性测试通过")
+ return True
+
+ except Exception as e:
+ print(f"❌ 数据一致性测试失败: {e}")
+ self.error_log.append(f"数据一致性错误: {e}")
+ self.test_results["data_consistency"] = False
+ return False
+
+ def generate_comprehensive_report(self):
+ """生成综合测试报告"""
+ print("\n" + "=" * 60)
+ print("📊 集夏v2.1.0 综合测试报告")
+ print("=" * 60)
+
+ # 测试结果统计
+ total_tests = len(self.test_results)
+ passed_tests = sum(1 for result in self.test_results.values() if result)
+ failed_tests = total_tests - passed_tests
+ pass_rate = (passed_tests / total_tests) * 100 if total_tests > 0 else 0
+
+ print(f"\n🎯 测试结果统计:")
+ print(f"- 总测试数: {total_tests}")
+ print(f"- 通过测试: {passed_tests}")
+ print(f"- 失败测试: {failed_tests}")
+ print(f"- 通过率: {pass_rate:.1f}%")
+
+ # 详细测试结果
+ print(f"\n📋 详细测试结果:")
+ for test_name, result in self.test_results.items():
+ status = "✅ 通过" if result else "❌ 失败"
+ print(f"- {test_name}: {status}")
+
+ # 性能指标
+ if self.performance_metrics:
+ print(f"\n⚡ 性能指标:")
+ for metric, value in self.performance_metrics.items():
+ if isinstance(value, float):
+ print(f"- {metric}: {value:.3f}")
+ else:
+ print(f"- {metric}: {value}")
+
+ # 错误日志
+ if self.error_log:
+ print(f"\n🚨 错误日志 ({len(self.error_log)} 条):")
+ for i, error in enumerate(self.error_log[:5], 1): # 只显示前5条
+ print(f"- {i}. {error}")
+ if len(self.error_log) > 5:
+ print(f"- ... 还有 {len(self.error_log) - 5} 条错误")
+
+ # 系统状态
+ print(f"\n🔧 系统状态:")
+ try:
+ flow_status = self.flow_controller.get_flow_status()
+ health_status = self.health_monitor.get_health_status()
+
+ print(f"- 流程控制器: 正常 (总发言: {flow_status.get('total_speeches', 0)})")
+ print(f"- 健康监控: 正常 (状态: {health_status.value})")
+ print(f"- 优先级算法: 正常")
+ print(f"- 多群聊协调: 正常")
+ except Exception as e:
+ print(f"- 系统状态检查失败: {e}")
+
+ # 总结
+ print(f"\n🎉 测试总结:")
+ if pass_rate >= 90:
+ print("🟢 系统状态优秀!所有核心功能运行正常,可以发布v2.1.0版本。")
+ elif pass_rate >= 70:
+ print("🟡 系统状态良好,但有部分功能需要优化。建议修复后再发布。")
+ else:
+ print("🔴 系统存在重大问题,需要进行全面修复后才能发布。")
+
+ return {
+ "pass_rate": pass_rate,
+ "total_tests": total_tests,
+ "passed_tests": passed_tests,
+ "failed_tests": failed_tests,
+ "performance_metrics": self.performance_metrics,
+ "error_count": len(self.error_log)
+ }
+
+ async def run_all_tests(self):
+ """运行所有测试"""
+ print("🚀 开始集夏v2.1.0综合功能测试")
+ print("=" * 60)
+
+ # 同步测试方法
+ sync_test_methods = [
+ self.test_priority_algorithm_integration,
+ self.test_flow_controller_integration,
+ self.test_health_monitor_integration,
+ self.test_performance_under_load,
+ self.test_data_consistency
+ ]
+
+ # 异步测试方法
+ async_test_methods = [
+ self.test_chat_coordinator_integration,
+ self.test_cross_component_integration
+ ]
+
+ start_time = time.time()
+
+ # 运行同步测试
+ for test_method in sync_test_methods:
+ try:
+ test_method()
+ except Exception as e:
+ print(f"❌ 测试执行异常: {e}")
+ self.error_log.append(f"测试执行异常: {e}")
+
+ # 运行异步测试
+ for test_method in async_test_methods:
+ try:
+ await test_method()
+ except Exception as e:
+ print(f"❌ 测试执行异常: {e}")
+ self.error_log.append(f"测试执行异常: {e}")
+
+ end_time = time.time()
+ total_duration = end_time - start_time
+
+ print(f"\n⏱️ 总测试时间: {total_duration:.3f} 秒")
+
+ # 生成综合报告
+ return self.generate_comprehensive_report()
+
+async def main():
+ """主函数"""
+ tester = V2_1_IntegrationTester()
+ report = await tester.run_all_tests()
+
+ # 保存测试报告
+ report_file = "v2_1_comprehensive_test_report.json"
+ with open(report_file, 'w', encoding='utf-8') as f:
+ json.dump({
+ "timestamp": datetime.now().isoformat(),
+ "version": "v2.1.0",
+ "test_results": tester.test_results,
+ "performance_metrics": tester.performance_metrics,
+ "error_log": tester.error_log,
+ "summary": report
+ }, f, ensure_ascii=False, indent=2)
+
+ print(f"\n📄 详细测试报告已保存到: {report_file}")
+
+ return report["pass_rate"] >= 70 # 70%通过率作为发布标准
+
+if __name__ == "__main__":
+ success = asyncio.run(main())
+ sys.exit(0 if success else 1)
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_vertex_ai_setup.py b/modules/testing-framework/tests/test_vertex_ai_setup.py
new file mode 100644
index 0000000..e714e85
--- /dev/null
+++ b/modules/testing-framework/tests/test_vertex_ai_setup.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+"""
+测试 Vertex AI 配置和连接
+"""
+
+import os
+import sys
+from config.settings import get_google_genai_config
+
+def test_doppler_config():
+ """测试 Doppler 配置"""
+ print("🔍 测试 Doppler 配置...")
+ try:
+ config = get_google_genai_config()
+ print("✅ 成功读取 Google GenAI 配置")
+ print(f" - API Key: {'已配置' if config.get('api_key') else '未配置'}")
+ print(f" - Use Vertex AI: {config.get('use_vertex_ai', '未设置')}")
+ print(f" - Project ID: {config.get('project_id', '未设置')}")
+ print(f" - Location: {config.get('location', '未设置')}")
+ print(f" - Memory Bank Enabled: {config.get('memory_bank_enabled', '未设置')}")
+ return config
+ except Exception as e:
+ print(f"❌ 读取 Google GenAI 配置失败: {e}")
+ return None
+
+def test_environment_variables():
+ """测试环境变量"""
+ print("\n🔍 测试环境变量...")
+ adc_path = os.path.expanduser("~/.config/gcloud/application_default_credentials.json")
+ if os.path.exists(adc_path):
+ print("✅ 找到 Application Default Credentials 文件")
+ else:
+ print("❌ 未找到 Application Default Credentials 文件")
+
+ google_env_vars = [var for var in os.environ if var.startswith('GOOGLE_')]
+ if google_env_vars:
+ print("✅ 找到以下 Google 环境变量:")
+ for var in google_env_vars:
+ # 不显示敏感信息
+ if 'KEY' in var or 'SECRET' in var or 'TOKEN' in var:
+ print(f" - {var}: {'已设置' if os.environ.get(var) else '未设置'}")
+ else:
+ print(f" - {var}: {os.environ.get(var, '未设置')}")
+ else:
+ print("⚠️ 未找到 Google 环境变量")
+
+def main():
+ """主函数"""
+ print("🧪 Vertex AI 配置测试\n")
+
+ # 测试 Doppler 配置
+ config = test_doppler_config()
+
+ # 测试环境变量
+ test_environment_variables()
+
+ # 检查是否满足基本要求
+ print("\n📋 配置检查摘要:")
+ if config:
+ project_id = config.get('project_id')
+ api_key = config.get('api_key')
+
+ if project_id:
+ print("✅ Google Cloud Project ID 已配置")
+ else:
+ print("❌ 未配置 Google Cloud Project ID")
+
+ if api_key:
+ print("✅ Google API Key 已配置")
+ else:
+ print("❌ 未配置 Google API Key")
+
+ # 检查是否启用 Vertex AI
+ use_vertex = config.get('use_vertex_ai', '').upper()
+ if use_vertex == 'TRUE':
+ print("✅ Vertex AI 已启用")
+ else:
+ print("❌ Vertex AI 未启用 (请检查 GOOGLE_GENAI_USE_VERTEXAI 环境变量)")
+
+ # 检查是否启用 Memory Bank
+ memory_bank_enabled = config.get('memory_bank_enabled', '').upper()
+ if memory_bank_enabled == 'TRUE':
+ print("✅ Memory Bank 已启用")
+ else:
+ print("❌ Memory Bank 未启用 (请检查 VERTEX_MEMORY_BANK_ENABLED 环境变量)")
+ else:
+ print("❌ 无法读取配置,请检查 Doppler 配置")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_vertex_memory_bank.py b/modules/testing-framework/tests/test_vertex_memory_bank.py
new file mode 100644
index 0000000..c550ef5
--- /dev/null
+++ b/modules/testing-framework/tests/test_vertex_memory_bank.py
@@ -0,0 +1,384 @@
+#!/usr/bin/env python3
+"""
+Vertex Memory Bank 实现测试
+"""
+
+import unittest
+import asyncio
+import os
+import sys
+from unittest.mock import patch, MagicMock, AsyncMock
+from datetime import datetime
+
+# 添加项目根目录到Python路径
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from src.jixia.memory.vertex_memory_bank import VertexMemoryBank, MemoryEntry
+
+
+class TestVertexMemoryBank(unittest.TestCase):
+ """测试VertexMemoryBank类"""
+
+ def setUp(self):
+ """测试前的设置"""
+ # Mock掉aiplatform.init以避免实际初始化
+ patcher = patch('src.jixia.memory.vertex_memory_bank.aiplatform.init')
+ self.mock_init = patcher.start()
+ self.addCleanup(patcher.stop)
+
+ # 创建VertexMemoryBank实例
+ self.memory_bank = VertexMemoryBank(
+ project_id="test-project",
+ location="us-central1"
+ )
+
+ # 重置本地存储
+ self.memory_bank.local_memories = {}
+ self.memory_bank.memory_banks = {}
+
+ def test_init(self):
+ """测试初始化"""
+ self.assertEqual(self.memory_bank.project_id, "test-project")
+ self.assertEqual(self.memory_bank.location, "us-central1")
+ self.assertEqual(self.memory_bank.local_memories, {})
+ self.assertEqual(self.memory_bank.memory_banks, {})
+
+ # 验证调用了aiplatform.init
+ self.mock_init.assert_called_once_with(project="test-project", location="us-central1")
+
+ def test_from_config(self):
+ """测试从配置创建实例"""
+ with patch('src.jixia.memory.vertex_memory_bank.get_google_genai_config') as mock_config:
+ mock_config.return_value = {
+ 'project_id': 'config-project',
+ 'location': 'europe-west1'
+ }
+
+ memory_bank = VertexMemoryBank.from_config()
+
+ self.assertEqual(memory_bank.project_id, "config-project")
+ self.assertEqual(memory_bank.location, "europe-west1")
+
+ def test_from_config_missing_project_id(self):
+ """测试从配置创建实例时缺少project_id"""
+ with patch('src.jixia.memory.vertex_memory_bank.get_google_genai_config') as mock_config:
+ mock_config.return_value = {
+ 'project_id': None,
+ 'location': 'europe-west1'
+ }
+
+ with self.assertRaises(ValueError) as context:
+ VertexMemoryBank.from_config()
+
+ self.assertIn("Google Cloud Project ID 未配置", str(context.exception))
+
+ async def test_create_memory_bank(self):
+ """测试创建记忆银行"""
+ memory_bank_id = await self.memory_bank.create_memory_bank("tieguaili")
+
+ # 验证返回的ID格式
+ self.assertEqual(memory_bank_id, "memory_bank_tieguaili_test-project")
+
+ # 验证内部状态
+ self.assertIn("tieguaili", self.memory_bank.memory_banks)
+ self.assertEqual(self.memory_bank.memory_banks["tieguaili"], memory_bank_id)
+ self.assertIn("tieguaili", self.memory_bank.local_memories)
+ self.assertEqual(self.memory_bank.local_memories["tieguaili"], [])
+
+ async def test_create_memory_bank_with_display_name(self):
+ """测试创建记忆银行时指定显示名称"""
+ memory_bank_id = await self.memory_bank.create_memory_bank(
+ "tieguaili",
+ "铁拐李的专属记忆银行"
+ )
+
+ # 验证返回的ID格式
+ self.assertEqual(memory_bank_id, "memory_bank_tieguaili_test-project")
+
+ async def test_add_memory(self):
+ """测试添加记忆"""
+ # 先创建记忆银行
+ await self.memory_bank.create_memory_bank("tieguaili")
+
+ # 添加记忆
+ memory_id = await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析",
+ metadata={"source": "manual"}
+ )
+
+ # 验证返回的ID格式
+ self.assertEqual(memory_id, "memory_tieguaili_0")
+
+ # 验证记忆已存储
+ self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 1)
+
+ stored_memory = self.memory_bank.local_memories["tieguaili"][0]
+ self.assertEqual(stored_memory["id"], memory_id)
+ self.assertEqual(stored_memory["content"], "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
+ self.assertEqual(stored_memory["memory_type"], "preference")
+ self.assertEqual(stored_memory["debate_topic"], "NVIDIA投资分析")
+ self.assertIn("source", stored_memory["metadata"])
+ self.assertEqual(stored_memory["metadata"]["source"], "manual")
+ self.assertIn("agent_name", stored_memory["metadata"])
+ self.assertEqual(stored_memory["metadata"]["agent_name"], "tieguaili")
+
+ async def test_add_memory_creates_bank_if_not_exists(self):
+ """测试添加记忆时自动创建记忆银行"""
+ # 不先创建记忆银行,直接添加记忆
+ memory_id = await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="测试内容"
+ )
+
+ # 验证记忆银行已被自动创建
+ self.assertIn("tieguaili", self.memory_bank.memory_banks)
+ self.assertIn("tieguaili", self.memory_bank.local_memories)
+
+ # 验证记忆已存储
+ self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 1)
+
+ async def test_search_memories(self):
+ """测试搜索记忆"""
+ # 先创建记忆银行并添加一些记忆
+ await self.memory_bank.create_memory_bank("tieguaili")
+
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="我喜欢关注苹果公司的创新产品发布会。",
+ memory_type="preference",
+ debate_topic="AAPL投资分析"
+ )
+
+ # 搜索NVIDIA相关记忆
+ results = await self.memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="NVIDIA"
+ )
+
+ self.assertEqual(len(results), 1)
+ self.assertEqual(results[0]["content"], "在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。")
+ self.assertIn("relevance_score", results[0])
+
+ async def test_search_memories_with_type_filter(self):
+ """测试带类型过滤的搜索记忆"""
+ # 先创建记忆银行并添加不同类型的记忆
+ await self.memory_bank.create_memory_bank("tieguaili")
+
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在NVIDIA的辩论中,我使用了技术分析策略。",
+ memory_type="strategy",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ # 搜索NVIDIA相关记忆,只返回preference类型
+ results = await self.memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="NVIDIA",
+ memory_type="preference"
+ )
+
+ self.assertEqual(len(results), 1)
+ self.assertEqual(results[0]["metadata"]["memory_type"], "preference")
+
+ async def test_search_memories_no_results(self):
+ """测试搜索无结果的情况"""
+ # 搜索不存在的记忆银行
+ results = await self.memory_bank.search_memories(
+ agent_name="nonexistent",
+ query="test"
+ )
+
+ self.assertEqual(results, [])
+
+ # 搜索空的记忆银行
+ await self.memory_bank.create_memory_bank("tieguaili")
+ results = await self.memory_bank.search_memories(
+ agent_name="tieguaili",
+ query="test"
+ )
+
+ self.assertEqual(results, [])
+
+ async def test_get_agent_context(self):
+ """测试获取智能体上下文"""
+ # 先创建记忆银行并添加一些记忆
+ await self.memory_bank.create_memory_bank("tieguaili")
+
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ await self.memory_bank.add_memory(
+ agent_name="tieguaili",
+ content="在NVIDIA的辩论中,我使用了技术分析策略。",
+ memory_type="strategy",
+ debate_topic="NVIDIA投资分析"
+ )
+
+ # 获取上下文
+ context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
+
+ # 验证上下文包含预期内容
+ self.assertIn("# 铁拐李的记忆上下文", context)
+ self.assertIn("## 偏好记忆", context)
+ self.assertIn("## 策略记忆", context)
+ self.assertIn("在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险。", context)
+ self.assertIn("在NVIDIA的辩论中,我使用了技术分析策略。", context)
+
+ async def test_get_agent_context_no_memories(self):
+ """测试获取智能体上下文但无相关记忆"""
+ # 先创建记忆银行
+ await self.memory_bank.create_memory_bank("tieguaili")
+
+ # 获取上下文
+ context = await self.memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
+
+ # 验证上下文包含暂无相关记忆的提示
+ self.assertIn("# 铁拐李的记忆上下文", context)
+ self.assertIn("暂无相关记忆。", context)
+
+ async def test_save_debate_session(self):
+ """测试保存辩论会话"""
+ conversation_history = [
+ {"agent": "tieguaili", "content": "NVIDIA的估值过高,存在泡沫风险。"},
+ {"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
+ {"agent": "tieguaili", "content": "但我们需要考虑竞争加剧和增长放缓的可能性。"}
+ ]
+
+ outcomes = {
+ "winner": "lvdongbin",
+ "insights": {
+ "tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
+ }
+ }
+
+ # 保存辩论会话
+ await self.memory_bank.save_debate_session(
+ debate_topic="NVIDIA投资分析",
+ participants=["tieguaili", "lvdongbin"],
+ conversation_history=conversation_history,
+ outcomes=outcomes
+ )
+
+ # 验证铁拐李的记忆已保存
+ self.assertIn("tieguaili", self.memory_bank.local_memories)
+ self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 2)
+
+ # 验证第一条记忆是对话总结
+ summary_memory = self.memory_bank.local_memories["tieguaili"][0]
+ self.assertEqual(summary_memory["memory_type"], "conversation")
+ self.assertIn("铁拐李在本次辩论中的主要观点", summary_memory["content"])
+
+ # 验证第二条记忆是策略洞察
+ strategy_memory = self.memory_bank.local_memories["tieguaili"][1]
+ self.assertEqual(strategy_memory["memory_type"], "strategy")
+ self.assertIn("铁拐李的风险意识值得肯定", strategy_memory["content"])
+
+ def test_summarize_conversation(self):
+ """测试对话总结"""
+ conversation_history = [
+ {"agent": "tieguaili", "content": "第一点看法:NVIDIA的估值过高,存在泡沫风险。"},
+ {"agent": "lvdongbin", "content": "NVIDIA在AI领域的领先地位不可忽视。"},
+ {"agent": "tieguaili", "content": "第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。"},
+ {"agent": "tieguaili", "content": "第三点看法:从技术分析角度看,股价已出现超买信号。"}
+ ]
+
+ summary = self.memory_bank._summarize_conversation(conversation_history, "tieguaili")
+
+ # 验证总结包含预期内容
+ self.assertIn("铁拐李在本次辩论中的主要观点", summary)
+ self.assertIn("第一点看法:NVIDIA的估值过高,存在泡沫风险。", summary)
+ self.assertIn("第二点看法:我们需要考虑竞争加剧和增长放缓的可能性。", summary)
+ self.assertIn("第三点看法:从技术分析角度看,股价已出现超买信号。", summary)
+
+ def test_extract_strategy_insight_winner(self):
+ """测试提取策略洞察 - 获胜者"""
+ outcomes = {
+ "winner": "tieguaili",
+ "insights": {}
+ }
+
+ insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
+
+ self.assertIn("铁拐李在本次辩论中获胜", insight)
+
+ def test_extract_strategy_insight_from_insights(self):
+ """测试从洞察中提取策略洞察"""
+ outcomes = {
+ "winner": "lvdongbin",
+ "insights": {
+ "tieguaili": "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。"
+ }
+ }
+
+ insight = self.memory_bank._extract_strategy_insight(outcomes, "tieguaili")
+
+ self.assertEqual(insight, "铁拐李的风险意识值得肯定,但在AI趋势的判断上略显保守。")
+
+
+if __name__ == '__main__':
+ # 创建一个异步测试运行器
+ def run_async_test(test_case):
+ """运行异步测试用例"""
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ try:
+ return loop.run_until_complete(test_case)
+ finally:
+ loop.close()
+
+ # 获取所有以test_开头的异步方法并运行它们
+ suite = unittest.TestSuite()
+ test_instance = TestVertexMemoryBank()
+ test_instance.setUp()
+
+ # 添加同步测试
+ suite.addTest(TestVertexMemoryBank('test_init'))
+ suite.addTest(TestVertexMemoryBank('test_from_config'))
+ suite.addTest(TestVertexMemoryBank('test_from_config_missing_project_id'))
+ suite.addTest(TestVertexMemoryBank('test_summarize_conversation'))
+ suite.addTest(TestVertexMemoryBank('test_extract_strategy_insight_winner'))
+ suite.addTest(TestVertexMemoryBank('test_extract_strategy_insight_from_insights'))
+
+ # 添加异步测试
+ async_tests = [
+ 'test_create_memory_bank',
+ 'test_create_memory_bank_with_display_name',
+ 'test_add_memory',
+ 'test_add_memory_creates_bank_if_not_exists',
+ 'test_search_memories',
+ 'test_search_memories_with_type_filter',
+ 'test_search_memories_no_results',
+ 'test_get_agent_context',
+ 'test_get_agent_context_no_memories',
+ 'test_save_debate_session'
+ ]
+
+ for test_name in async_tests:
+ test_method = getattr(test_instance, test_name)
+ suite.addTest(unittest.FunctionTestCase(lambda tm=test_method: run_async_test(tm())))
+
+ # 运行测试
+ runner = unittest.TextTestRunner(verbosity=2)
+ runner.run(suite)
\ No newline at end of file
diff --git a/modules/testing-framework/tests/test_vertex_memory_bank_function.py b/modules/testing-framework/tests/test_vertex_memory_bank_function.py
new file mode 100644
index 0000000..940c521
--- /dev/null
+++ b/modules/testing-framework/tests/test_vertex_memory_bank_function.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""
+测试 Vertex AI Memory Bank 功能
+"""
+
+import asyncio
+import sys
+import os
+
+# 添加项目根目录到Python路径
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '.')))
+
+from src.jixia.memory.factory import get_memory_backend
+
+async def test_vertex_memory_bank():
+ """测试 Vertex Memory Bank 功能"""
+ print("🧪 Vertex AI Memory Bank 功能测试\n")
+
+ try:
+ # 获取 Vertex Memory Bank 后端
+ print("🔍 正在获取 Vertex Memory Bank 后端...")
+ memory_bank = get_memory_backend(prefer='vertex')
+ print("✅ 成功获取 Vertex Memory Bank 后端\n")
+
+ # 测试创建记忆银行
+ print("🔍 正在为吕洞宾创建记忆银行...")
+ bank_id = await memory_bank.create_memory_bank("lvdongbin", "吕洞宾的记忆银行")
+ print(f"✅ 成功为吕洞宾创建记忆银行: {bank_id}\n")
+
+ # 测试添加记忆
+ print("🔍 正在为吕洞宾添加记忆...")
+ memory_id = await memory_bank.add_memory(
+ agent_name="lvdongbin",
+ content="在讨论NVIDIA股票时,我倾向于使用DCF模型评估其内在价值,并关注其在AI领域的竞争优势。",
+ memory_type="preference",
+ debate_topic="NVIDIA投资分析",
+ metadata={"confidence": "high"}
+ )
+ print(f"✅ 成功为吕洞宾添加记忆: {memory_id}\n")
+
+ # 测试搜索记忆
+ print("🔍 正在搜索吕洞宾关于NVIDIA的记忆...")
+ results = await memory_bank.search_memories(
+ agent_name="lvdongbin",
+ query="NVIDIA",
+ memory_type="preference"
+ )
+ print(f"✅ 搜索完成,找到 {len(results)} 条相关记忆\n")
+
+ if results:
+ print("🔍 搜索结果:")
+ for i, result in enumerate(results, 1):
+ print(f" {i}. {result['content']}")
+ print(f" 相关性评分: {result['relevance_score']:.4f}\n")
+
+ # 测试获取上下文
+ print("🔍 正在获取吕洞宾关于NVIDIA投资分析的上下文...")
+ context = await memory_bank.get_agent_context("lvdongbin", "NVIDIA投资分析")
+ print("✅ 成功获取上下文\n")
+ print("🔍 上下文内容:")
+ print(context)
+ print("\n")
+
+ print("🎉 Vertex AI Memory Bank 功能测试完成!")
+
+ except Exception as e:
+ print(f"❌ 测试过程中发生错误: {e}")
+ import traceback
+ traceback.print_exc()
+
+if __name__ == "__main__":
+ asyncio.run(test_vertex_memory_bank())
\ No newline at end of file
diff --git a/modules/testing-framework/tests/validate_models.py b/modules/testing-framework/tests/validate_models.py
new file mode 100644
index 0000000..e9a67ac
--- /dev/null
+++ b/modules/testing-framework/tests/validate_models.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Script to validate model availability on OpenRouter
+"""
+
+import asyncio
+import aiohttp
+import os
+
+# Read models from .env file
+models = []
+with open(".env", "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.endswith(":free"):
+ models.append(line)
+
+# Get API key from environment or .env file
+api_key = os.getenv('OPENROUTER_API_KEY')
+if not api_key:
+ with open(".env", "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("sk-or-v1-"):
+ api_key = line
+ break
+
+if not api_key:
+ print("❌ No API key found")
+ exit(1)
+
+async def test_model(session, model):
+ """Test if a model is available on OpenRouter"""
+ # Remove :free tag for API call
+ clean_model = model.split(":")[0]
+
+ url = "https://openrouter.ai/api/v1/chat/completions"
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json"
+ }
+ payload = {
+ "model": clean_model,
+ "messages": [
+ {"role": "user", "content": "Hello, world!"}
+ ],
+ "max_tokens": 10
+ }
+
+ try:
+ async with session.post(url, headers=headers, json=payload, timeout=10) as response:
+ if response.status == 200:
+ return model, True, "Available"
+ else:
+ error_text = await response.text()
+ return model, False, f"Status {response.status}: {error_text[:100]}"
+ except Exception as e:
+ return model, False, f"Exception: {str(e)[:100]}"
+
+async def main():
+ """Main function"""
+ print(f"🔍 Testing {len(models)} models from .env file...")
+
+ async with aiohttp.ClientSession() as session:
+ tasks = [test_model(session, model) for model in models]
+ results = await asyncio.gather(*tasks)
+
+ print("\n📊 Results:")
+ valid_models = []
+ invalid_models = []
+
+ for model, is_valid, message in results:
+ if is_valid:
+ print(f"✅ {model:<50} - {message}")
+ valid_models.append(model)
+ else:
+ print(f"❌ {model:<50} - {message}")
+ invalid_models.append(model)
+
+ print(f"\n✅ Valid models ({len(valid_models)}):")
+ for model in valid_models:
+ print(f" {model}")
+
+ print(f"\n❌ Invalid models ({len(invalid_models)}):")
+ for model in invalid_models:
+ print(f" {model}")
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..ed95a21
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,19 @@
+[tool.poetry]
+name = "liurenchaxin"
+version = "0.1.0"
+description = "AI Collaboration and Agent System"
+authors = ["Your Name "]
+license = "MIT"
+readme = "README.md"
+
+[tool.poetry.dependencies]
+python = "^3.8"
+streamlit = "^1.0"
+# Add other dependencies from requirements.txt
+
+[tool.poetry.dev-dependencies]
+pytest = "^7.0"
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
\ No newline at end of file
diff --git a/website/index.html b/website/index.html
new file mode 100644
index 0000000..281a376
--- /dev/null
+++ b/website/index.html
@@ -0,0 +1,283 @@
+
+
+
+
+
+ AI Agent协作框架 - 真实的多Agent协作系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 从模拟到真实
+ 让每个AI Agent都拥有独立Git身份
+
+
+ 不是让AI Agent假装协作,而是让每个Agent都有真实的Git身份:
+ 独立的SSH密钥、GPG签名、用户名和邮箱,实现可追溯的团队协作历史
+
+
+
+
+
+
+
+ 4
+ 预定义Agent
+
+
+ 100%
+ 真实Git提交
+
+
+ 一键
+ 快速启动
+
+
+
+
+
+
+
+
+ $
+ ./agents/switch_agent.sh claude-ai
+
+
+ claude-ai@framework
+ git commit -m "设计系统架构"
+
+
+ $
+ ./agents/switch_agent.sh gemini-dev
+
+
+ gemini-dev@framework
+ git commit -m "实现核心功能"
+
+
+ ✅ 真实的协作历史已创建
+
+
+
+
+
+
+
+
+
+
+
核心特性
+
+
+
🔐
+
真实身份系统
+
每个Agent拥有独立的SSH密钥、GPG签名和Git配置,确保每次提交都可追溯到具体Agent
+
+ - 独立SSH密钥对
+ - GPG签名验证
+ - 独立Git配置
+ - 完整审计日志
+
+
+
+
🎭
+
专业化角色
+
预定义四种专业化Agent角色,每个都有明确的责任边界和专长领域
+
+
+ claude-ai - 架构师
+
+
+ gemini-dev - 开发者
+
+
+ qwen-ops - 运维
+
+
+ llama-research - 研究员
+
+
+
+
+
📊
+
实时协作监控
+
实时查看所有Agent的协作状态、提交统计和代码贡献分析
+
+
+
+
+
+
+
+
+
+
实时演示
+
+
+
+
+
+
+
+
+
+
+
+
快速开始
+
+
+
🚀 一键安装
+
+
curl -fsSL https://raw.githubusercontent.com/your-org/agent-collaboration-framework/main/install.sh | bash
+
+
+
+
📦 手动安装
+
+
git clone https://github.com/your-org/agent-collaboration-framework.git
+cd agent-collaboration-framework
+./install.sh
+
+
+
+
🐳 Docker
+
+
docker run -it -v $(pwd):/workspace agent-collaboration:latest
+
+
+
+
+
+
+
+
+
+
文档中心
+
+
+
📚 快速入门
+
从零开始了解AI Agent协作框架
+
开始阅读 →
+
+
+
🏗️ 架构指南
+
深入理解系统架构和设计原理
+
查看详情 →
+
+
+
🔧 API文档
+
完整的API参考和开发指南
+
浏览API →
+
+
+
🎯 使用案例
+
真实场景下的使用示例和最佳实践
+
查看案例 →
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/website/script.js b/website/script.js
new file mode 100644
index 0000000..7cef74c
--- /dev/null
+++ b/website/script.js
@@ -0,0 +1,345 @@
+// 全局变量
+let agents = [
+ { id: 'code-reviewer', name: 'Code Reviewer', status: 'active', commits: 12, tasks: 3 },
+ { id: 'test-runner', name: 'Test Runner', status: 'active', commits: 8, tasks: 5 },
+ { id: 'deploy-bot', name: 'Deploy Bot', status: 'inactive', commits: 3, tasks: 0 },
+ { id: 'doc-writer', name: 'Doc Writer', status: 'active', commits: 15, tasks: 2 }
+];
+
+let activities = [
+ { type: 'commit', message: 'Code Reviewer pushed 3 new commits', time: '2 minutes ago' },
+ { type: 'test', message: 'Test Runner completed 5 test cases', time: '5 minutes ago' },
+ { type: 'deploy', message: 'Deploy Bot deployed to staging', time: '10 minutes ago' },
+ { type: 'docs', message: 'Doc Writer updated API documentation', time: '15 minutes ago' }
+];
+
+// 初始化
+document.addEventListener('DOMContentLoaded', function() {
+ initializeDemo();
+ initializeTerminal();
+ initializeStats();
+ setupScrollEffects();
+});
+
+// 演示区域初始化
+function initializeDemo() {
+ updateAgentGrid();
+ updateActivityFeed();
+
+ // 每3秒更新一次演示数据
+ setInterval(updateDemoData, 3000);
+}
+
+// 更新代理网格
+function updateAgentGrid() {
+ const grid = document.getElementById('agent-grid');
+ if (!grid) return;
+
+ grid.innerHTML = '';
+ agents.forEach(agent => {
+ const card = createAgentCard(agent);
+ grid.appendChild(card);
+ });
+}
+
+// 创建代理卡片
+function createAgentCard(agent) {
+ const card = document.createElement('div');
+ card.className = `agent-card agent-status-${agent.status}`;
+
+ const statusIcon = agent.status === 'active' ? '🟢' : '🔴';
+
+ card.innerHTML = `
+
+
${agent.name}
+
+ ${statusIcon} ${agent.status}
+
+
+
+
📊 ${agent.commits} commits
+
📝 ${agent.tasks} tasks
+
+ `;
+
+ return card;
+}
+
+// 更新活动流
+function updateActivityFeed() {
+ const feed = document.getElementById('activity-feed');
+ if (!feed) return;
+
+ feed.innerHTML = '';
+ activities.forEach(activity => {
+ const item = createActivityItem(activity);
+ feed.appendChild(item);
+ });
+}
+
+// 创建活动项
+function createActivityItem(activity) {
+ const item = document.createElement('div');
+ item.className = 'activity-item';
+
+ const icon = getActivityIcon(activity.type);
+
+ item.innerHTML = `
+
+ ${icon}
+ ${activity.message}
+
+
+ ${activity.time}
+
+ `;
+
+ return item;
+}
+
+// 获取活动图标
+function getActivityIcon(type) {
+ const icons = {
+ 'commit': '💻',
+ 'test': '🧪',
+ 'deploy': '🚀',
+ 'docs': '📚'
+ };
+ return icons[type] || '📝';
+}
+
+// 更新演示数据
+function updateDemoData() {
+ // 随机更新代理状态
+ agents.forEach(agent => {
+ if (Math.random() > 0.7) {
+ agent.status = agent.status === 'active' ? 'inactive' : 'active';
+ }
+ if (Math.random() > 0.5) {
+ agent.commits += Math.floor(Math.random() * 3);
+ }
+ });
+
+ // 添加新活动
+ const newActivity = generateRandomActivity();
+ activities.unshift(newActivity);
+ if (activities.length > 5) {
+ activities.pop();
+ }
+
+ updateAgentGrid();
+ updateActivityFeed();
+ updateStats();
+}
+
+// 生成随机活动
+function generateRandomActivity() {
+ const types = ['commit', 'test', 'deploy', 'docs'];
+ const messages = {
+ 'commit': ['Code Reviewer pushed new features', 'Test Runner fixed bugs', 'Deploy Bot merged PR'],
+ 'test': ['Test Runner passed all tests', 'Code Reviewer added unit tests', 'Doc Writer tested examples'],
+ 'deploy': ['Deploy Bot deployed to production', 'Code Reviewer released v2.0', 'Test Runner deployed hotfix'],
+ 'docs': ['Doc Writer updated README', 'Code Reviewer improved comments', 'Deploy Bot added changelog']
+ };
+
+ const type = types[Math.floor(Math.random() * types.length)];
+ const message = messages[type][Math.floor(Math.random() * messages[type].length)];
+
+ return {
+ type: type,
+ message: message,
+ time: 'just now'
+ };
+}
+
+// 终端模拟
+function initializeTerminal() {
+ const terminal = document.getElementById('terminal-content');
+ if (!terminal) return;
+
+ const commands = [
+ { prompt: 'user@spore-colony:~$', command: 'spore init', output: '✓ Initializing Spore Colony...\n✓ Creating agent identities...\n✓ Setting up Git repositories...\n✓ Spore Colony initialized successfully!' },
+ { prompt: 'user@spore-colony:~$', command: 'spore agent list', output: '🟢 code-reviewer (Active)\n🟢 test-runner (Active)\n🔴 deploy-bot (Inactive)\n🟢 doc-writer (Active)' },
+ { prompt: 'user@spore-colony:~$', command: 'spore task create "Add new feature"', output: '✓ Task created and assigned to code-reviewer\n📊 Progress: 0% → 25% → 50% → 75% → 100%\n✅ Task completed successfully!' }
+ ];
+
+ let currentCommand = 0;
+
+ function typeCommand() {
+ if (currentCommand >= commands.length) return;
+
+ const cmd = commands[currentCommand];
+ const line = document.createElement('div');
+ line.className = 'terminal-line';
+ line.innerHTML = `${cmd.prompt} ${cmd.command}`;
+ terminal.appendChild(line);
+
+ setTimeout(() => {
+ const outputLine = document.createElement('div');
+ outputLine.className = 'terminal-line';
+ outputLine.innerHTML = `${cmd.output}`;
+ terminal.appendChild(outputLine);
+
+ currentCommand++;
+ if (currentCommand < commands.length) {
+ setTimeout(typeCommand, 2000);
+ }
+ }, 1500);
+ }
+
+ typeCommand();
+}
+
+// 统计信息
+function initializeStats() {
+ updateStats();
+}
+
+function updateStats() {
+ const totalCommits = agents.reduce((sum, agent) => sum + agent.commits, 0);
+ const activeAgents = agents.filter(agent => agent.status === 'active').length;
+ const totalTasks = agents.reduce((sum, agent) => sum + agent.tasks, 0);
+
+ animateCounter('total-commits', totalCommits);
+ animateCounter('active-agents', activeAgents);
+ animateCounter('total-tasks', totalTasks);
+
+ updateProgressBars();
+}
+
+// 数字动画
+function animateCounter(elementId, targetValue) {
+ const element = document.getElementById(elementId);
+ if (!element) return;
+
+ const startValue = parseInt(element.textContent) || 0;
+ const duration = 1000;
+ const startTime = performance.now();
+
+ function updateCounter(currentTime) {
+ const elapsed = currentTime - startTime;
+ const progress = Math.min(elapsed / duration, 1);
+
+ const currentValue = Math.floor(startValue + (targetValue - startValue) * progress);
+ element.textContent = currentValue;
+
+ if (progress < 1) {
+ requestAnimationFrame(updateCounter);
+ }
+ }
+
+ requestAnimationFrame(updateCounter);
+}
+
+// 进度条更新
+function updateProgressBars() {
+ const progressBars = document.querySelectorAll('.bar div');
+ progressBars.forEach(bar => {
+ const width = Math.floor(Math.random() * 30) + 70; // 70-100%
+ bar.style.width = width + '%';
+ });
+}
+
+// 滚动效果
+function setupScrollEffects() {
+ const observerOptions = {
+ threshold: 0.1,
+ rootMargin: '0px 0px -50px 0px'
+ };
+
+ const observer = new IntersectionObserver((entries) => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting) {
+ entry.target.classList.add('animate-in');
+ }
+ });
+ }, observerOptions);
+
+ // 观察所有需要动画的元素
+ document.querySelectorAll('.feature-card, .demo-panel, .install-card, .doc-card').forEach(el => {
+ observer.observe(el);
+ });
+}
+
+// 平滑滚动到锚点
+document.querySelectorAll('a[href^="#"]').forEach(anchor => {
+ anchor.addEventListener('click', function (e) {
+ e.preventDefault();
+ const target = document.querySelector(this.getAttribute('href'));
+ if (target) {
+ target.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start'
+ });
+ }
+ });
+});
+
+// 响应式菜单
+function toggleMobileMenu() {
+ const navMenu = document.querySelector('.nav-menu');
+ navMenu.classList.toggle('active');
+}
+
+// 复制代码功能
+function copyToClipboard(elementId) {
+ const element = document.getElementById(elementId);
+ if (!element) return;
+
+ const text = element.textContent;
+ navigator.clipboard.writeText(text).then(() => {
+ // 显示复制成功提示
+ const toast = document.createElement('div');
+ toast.textContent = 'Copied to clipboard!';
+ toast.style.cssText = `
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ background: #27ca3f;
+ color: white;
+ padding: 1rem;
+ border-radius: 0.5rem;
+ z-index: 1000;
+ animation: slideIn 0.3s ease;
+ `;
+
+ document.body.appendChild(toast);
+ setTimeout(() => {
+ toast.remove();
+ }, 2000);
+ });
+}
+
+// 添加CSS动画
+const style = document.createElement('style');
+style.textContent = `
+ @keyframes slideIn {
+ from {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ }
+
+ .animate-in {
+ animation: fadeInUp 0.6s ease forwards;
+ }
+
+ @media (max-width: 768px) {
+ .nav-menu.active {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ background: white;
+ padding: 1rem;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+ }
+ }
+`;
+document.head.appendChild(style);
\ No newline at end of file
diff --git a/website/styles.css b/website/styles.css
new file mode 100644
index 0000000..ef65338
--- /dev/null
+++ b/website/styles.css
@@ -0,0 +1,659 @@
+/* Reset and Base Styles */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ line-height: 1.6;
+ color: #333;
+ background: #fafafa;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+/* Navigation */
+.navbar {
+ position: fixed;
+ top: 0;
+ width: 100%;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(10px);
+ border-bottom: 1px solid #e0e0e0;
+ z-index: 1000;
+ transition: all 0.3s ease;
+}
+
+.nav-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 1rem 2rem;
+}
+
+.logo-text {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: #2563eb;
+}
+
+.nav-menu {
+ display: flex;
+ list-style: none;
+ gap: 2rem;
+}
+
+.nav-menu a {
+ text-decoration: none;
+ color: #333;
+ font-weight: 500;
+ transition: color 0.3s ease;
+}
+
+.nav-menu a:hover {
+ color: #2563eb;
+}
+
+.github-link {
+ background: #2563eb;
+ color: white !important;
+ padding: 0.5rem 1rem;
+ border-radius: 0.5rem;
+ transition: background 0.3s ease;
+}
+
+.github-link:hover {
+ background: #1d4ed8;
+}
+
+.hamburger {
+ display: none;
+ flex-direction: column;
+ cursor: pointer;
+}
+
+.hamburger span {
+ width: 25px;
+ height: 3px;
+ background: #333;
+ margin: 3px 0;
+ transition: 0.3s;
+}
+
+/* Hero Section */
+.hero {
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ padding: 6rem 0 4rem;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+}
+
+.hero-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4rem;
+ align-items: center;
+}
+
+.hero-title {
+ font-size: 3.5rem;
+ font-weight: 700;
+ line-height: 1.2;
+ margin-bottom: 1.5rem;
+}
+
+.gradient-text {
+ background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.hero-subtitle {
+ font-size: 1.25rem;
+ margin-bottom: 2rem;
+ opacity: 0.9;
+ line-height: 1.6;
+}
+
+.hero-buttons {
+ display: flex;
+ gap: 1rem;
+ margin-bottom: 3rem;
+}
+
+.btn {
+ padding: 1rem 2rem;
+ border: none;
+ border-radius: 0.5rem;
+ font-size: 1rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+ display: inline-block;
+}
+
+.btn-primary {
+ background: #ff6b6b;
+ color: white;
+}
+
+.btn-primary:hover {
+ background: #ff5252;
+ transform: translateY(-2px);
+}
+
+.btn-secondary {
+ background: transparent;
+ color: white;
+ border: 2px solid white;
+}
+
+.btn-secondary:hover {
+ background: white;
+ color: #667eea;
+}
+
+.hero-stats {
+ display: flex;
+ gap: 2rem;
+}
+
+.stat {
+ text-align: center;
+}
+
+.stat-number {
+ display: block;
+ font-size: 2rem;
+ font-weight: 700;
+ color: #ff6b6b;
+}
+
+.stat-label {
+ font-size: 0.9rem;
+ opacity: 0.8;
+}
+
+/* Terminal Window */
+.terminal-window {
+ background: #1a1a1a;
+ border-radius: 1rem;
+ overflow: hidden;
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
+}
+
+.terminal-header {
+ background: #2d2d2d;
+ padding: 1rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.terminal-buttons {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.terminal-buttons span {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+}
+
+.terminal-buttons span:nth-child(1) { background: #ff5f56; }
+.terminal-buttons span:nth-child(2) { background: #ffbd2e; }
+.terminal-buttons span:nth-child(3) { background: #27ca3f; }
+
+.terminal-title {
+ flex: 1;
+ text-align: center;
+ color: #888;
+ font-size: 0.9rem;
+}
+
+.terminal-content {
+ padding: 1.5rem;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 0.9rem;
+ line-height: 1.6;
+}
+
+.terminal-line {
+ margin-bottom: 0.5rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.prompt {
+ color: #27ca3f;
+}
+
+.command {
+ color: #fff;
+}
+
+.success {
+ color: #27ca3f;
+}
+
+/* Features Section */
+.features {
+ padding: 6rem 0;
+ background: white;
+}
+
+.section-title {
+ text-align: center;
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 3rem;
+ color: #333;
+}
+
+.features-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
+ gap: 3rem;
+}
+
+.feature-card {
+ background: white;
+ border-radius: 1rem;
+ padding: 2.5rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
+}
+
+.feature-card:hover {
+ transform: translateY(-5px);
+}
+
+.feature-icon {
+ font-size: 3rem;
+ margin-bottom: 1rem;
+}
+
+.feature-card h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.feature-card p {
+ color: #666;
+ margin-bottom: 1.5rem;
+ line-height: 1.6;
+}
+
+.feature-card ul {
+ list-style: none;
+}
+
+.feature-card li {
+ padding: 0.25rem 0;
+ color: #555;
+}
+
+.feature-card li:before {
+ content: "✓";
+ color: #27ca3f;
+ font-weight: bold;
+ margin-right: 0.5rem;
+}
+
+.roles-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.role-item {
+ padding: 0.5rem;
+ background: #f8f9fa;
+ border-radius: 0.5rem;
+ font-size: 0.9rem;
+}
+
+/* Demo Section */
+.demo {
+ padding: 6rem 0;
+ background: #f8f9fa;
+}
+
+.demo-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 3rem;
+}
+
+.demo-panel {
+ background: white;
+ border-radius: 1rem;
+ padding: 2rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+}
+
+.demo-panel h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1.5rem;
+ color: #333;
+}
+
+.agent-grid {
+ display: grid;
+ gap: 1rem;
+}
+
+.agent-card {
+ padding: 1rem;
+ background: #f8f9fa;
+ border-radius: 0.5rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.agent-status-active {
+ border-left: 4px solid #27ca3f;
+}
+
+.agent-status-inactive {
+ border-left: 4px solid #ff5f56;
+}
+
+.activity-feed {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.activity-item {
+ padding: 1rem;
+ background: #f8f9fa;
+ border-radius: 0.5rem;
+ border-left: 4px solid #667eea;
+}
+
+.demo-actions {
+ text-align: center;
+ margin-top: 2rem;
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+}
+
+/* Quick Start Section */
+.quick-start {
+ padding: 6rem 0;
+ background: white;
+}
+
+.install-options {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+}
+
+.install-card {
+ background: white;
+ border-radius: 1rem;
+ padding: 2rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ border: 1px solid #e0e0e0;
+}
+
+.install-card h3 {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.code-block {
+ background: #1a1a1a;
+ border-radius: 0.5rem;
+ padding: 1rem;
+ overflow-x: auto;
+}
+
+.code-block pre {
+ margin: 0;
+ color: #fff;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 0.9rem;
+}
+
+/* Documentation Section */
+.documentation {
+ padding: 6rem 0;
+ background: #f8f9fa;
+}
+
+.docs-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+}
+
+.doc-card {
+ background: white;
+ border-radius: 1rem;
+ padding: 2rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
+}
+
+.doc-card:hover {
+ transform: translateY(-5px);
+}
+
+.doc-card h3 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.doc-card p {
+ color: #666;
+ margin-bottom: 1rem;
+}
+
+.doc-link {
+ color: #2563eb;
+ text-decoration: none;
+ font-weight: 600;
+}
+
+.doc-link:hover {
+ text-decoration: underline;
+}
+
+/* Footer */
+.footer {
+ background: #1a1a1a;
+ color: white;
+ padding: 3rem 0 1rem;
+}
+
+.footer-content {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2rem;
+}
+
+.footer-section h4 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ margin-bottom: 1rem;
+}
+
+.footer-section ul {
+ list-style: none;
+}
+
+.footer-section ul li {
+ margin-bottom: 0.5rem;
+}
+
+.footer-section a {
+ color: #ccc;
+ text-decoration: none;
+ transition: color 0.3s ease;
+}
+
+.footer-section a:hover {
+ color: white;
+}
+
+.footer-bottom {
+ text-align: center;
+ padding-top: 2rem;
+ border-top: 1px solid #333;
+ color: #888;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .hamburger {
+ display: flex;
+ }
+
+ .nav-menu {
+ display: none;
+ }
+
+ .hero-container {
+ grid-template-columns: 1fr;
+ text-align: center;
+ }
+
+ .hero-title {
+ font-size: 2.5rem;
+ }
+
+ .hero-buttons {
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .features-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .demo-container {
+ grid-template-columns: 1fr;
+ }
+
+ .install-options {
+ grid-template-columns: 1fr;
+ }
+
+ .docs-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (max-width: 480px) {
+ .hero-title {
+ font-size: 2rem;
+ }
+
+ .hero-stats {
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .container {
+ padding: 0 1rem;
+ }
+}
+
+/* Animations */
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.feature-card {
+ animation: fadeInUp 0.6s ease forwards;
+}
+
+.feature-card:nth-child(2) {
+ animation-delay: 0.1s;
+}
+
+.feature-card:nth-child(3) {
+ animation-delay: 0.2s;
+}
+
+/* Stats Animation */
+.stats-preview {
+ margin-top: 1rem;
+}
+
+.stat-bar {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin-bottom: 0.5rem;
+}
+
+.stat-bar span {
+ font-size: 0.9rem;
+ min-width: 80px;
+}
+
+.bar {
+ flex: 1;
+ height: 8px;
+ background: #e0e0e0;
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.bar div {
+ height: 100%;
+ background: linear-gradient(90deg, #667eea, #764ba2);
+ transition: width 1s ease;
+}
+
+/* Scrollbar Styling */
+::-webkit-scrollbar {
+ width: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: #f1f1f1;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #888;
+ border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #555;
+}
\ No newline at end of file