refactor(project): 重构项目文档并优化代码结构

- 移除旧的文档结构和内容,清理 root 目录下的 markdown 文件
- 删除 GitHub Pages 部署配置和相关文件
- 移除 .env.example 文件,使用 Doppler 进行环境变量管理
- 更新 README.md,增加对 OpenBB 数据的支持
- 重构 streamlit_app.py,移除 Swarm 模式相关代码
- 更新 Doppler 配置管理模块,增加对 .env 文件的支持
- 删除 Memory Bank 实验和测试脚本
- 清理内部文档和开发计划
This commit is contained in:
ben
2025-08-18 16:56:04 +00:00
parent c4e8cfefc7
commit 51576ebb6f
87 changed files with 13056 additions and 1959 deletions

299
tests/test-api-example.js Normal file
View File

@@ -0,0 +1,299 @@
// API 测试示例脚本
// 演示如何使用 Hyperdrive API 进行 CRUD 操作
const API_BASE_URL = 'https://hyperdrive-neondb-test.<your-subdomain>.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
};
}

View File

@@ -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.<your-subdomain>.workers.dev/test-connection');
console.log(' - https://hyperdrive-neondb-test.<your-subdomain>.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);
}

93
tests/test-hyperdrive.js Normal file
View File

@@ -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);
}

67
tests/test-shushu-api.sh Executable file
View File

@@ -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 边缘网络)"

View File

@@ -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("🏁 测试完成")

View File

@@ -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)

View File

@@ -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"
}

117
tests/test_custom_api.py Normal file
View File

@@ -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. 检查网络连接")

View File

@@ -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()

View File

@@ -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💥 测试失败!请检查配置")

View File

@@ -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()

View File

@@ -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())

View File

@@ -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()

View File

@@ -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())

View File

@@ -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())

View File

@@ -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()

83
tests/test_simple_api.py Normal file
View File

@@ -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("🏁 测试完成")

View File

@@ -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())

View File

@@ -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())

View File

@@ -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())

View File

@@ -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())

View File

@@ -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)

View File

@@ -1,257 +1,384 @@
#!/usr/bin/env python3
"""
Vertex AI Memory Bank 测试脚本
验证稷下学宫记忆银行功能
Vertex Memory Bank 实现测试
"""
import unittest
import asyncio
import sys
import os
import sys
from unittest.mock import patch, MagicMock, AsyncMock
from datetime import datetime
# 添加项目根目录到路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 添加项目根目录到Python路径
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from src.jixia.memory.vertex_memory_bank import VertexMemoryBank, initialize_baxian_memory_banks
from src.jixia.agents.memory_enhanced_agent import MemoryEnhancedAgent, create_memory_enhanced_council
from config.doppler_config import get_google_genai_config, validate_config
from src.jixia.memory.vertex_memory_bank import VertexMemoryBank, MemoryEntry
async def test_memory_bank_basic():
"""测试Memory Bank基础功能"""
print("🧪 测试 Memory Bank 基础功能...")
try:
# 验证配置
if not validate_config("google_adk"):
print("❌ Google ADK 配置验证失败")
return False
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)
config = get_google_genai_config()
if not config.get('project_id'):
print("❌ Google Cloud Project ID 未配置")
print("请设置环境变量: GOOGLE_CLOUD_PROJECT_ID")
return False
# 创建Memory Bank实例
memory_bank = VertexMemoryBank.from_config()
print(f"✅ Memory Bank 实例创建成功")
print(f" 项目ID: {config['project_id']}")
print(f" 区域: {config['location']}")
# 测试创建记忆银行
bank_id = await memory_bank.create_memory_bank(
agent_name="tieguaili",
display_name="铁拐李测试记忆银行"
# 创建VertexMemoryBank实例
self.memory_bank = VertexMemoryBank(
project_id="test-project",
location="us-central1"
)
print(f"✅ 创建记忆银行成功: {bank_id}")
# 测试添加记忆
memory_id = await memory_bank.add_memory(
# 重置本地存储
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时我倾向于关注潜在的市场风险和估值泡沫",
content="在讨论NVIDIA股票时,我倾向于逆向思维,关注潜在风险",
memory_type="preference",
debate_topic="NVIDIA投资分析",
metadata={"test": True, "priority": "high"}
metadata={"source": "manual"}
)
print(f"✅ 添加记忆成功: {memory_id}")
# 测试搜索记忆
results = await memory_bank.search_memories(
# 验证返回的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",
query="NVIDIA 风险",
limit=5
)
print(f"✅ 搜索记忆成功,找到 {len(results)} 条结果")
for i, result in enumerate(results, 1):
print(f" {i}. {result['content'][:50]}... (相关度: {result.get('relevance_score', 'N/A')})")
# 测试获取上下文
context = await memory_bank.get_agent_context("tieguaili", "NVIDIA投资分析")
print(f"✅ 获取上下文成功,长度: {len(context)} 字符")
return True
except Exception as e:
print(f"❌ Memory Bank 基础测试失败: {e}")
return False
async def test_memory_enhanced_agent():
"""测试记忆增强智能体"""
print("\n🧪 测试记忆增强智能体...")
try:
# 创建记忆银行
memory_bank = VertexMemoryBank.from_config()
# 创建记忆增强智能体
agent = MemoryEnhancedAgent("tieguaili", memory_bank)
print(f"✅ 创建记忆增强智能体: {agent.personality.chinese_name}")
# 测试基于记忆的响应
response = await agent.respond_with_memory(
message="你对NVIDIA的最新财报有什么看法",
topic="NVIDIA投资分析"
)
print(f"✅ 智能体响应成功")
print(f" 响应长度: {len(response)} 字符")
print(f" 响应预览: {response[:100]}...")
# 测试学习偏好
await agent.learn_preference(
preference="用户偏好保守的投资策略,关注风险控制",
topic="投资偏好"
)
print("✅ 学习用户偏好成功")
# 测试保存策略洞察
await agent.save_strategy_insight(
insight="在高估值环境下,应该更加关注基本面分析和风险管理",
topic="投资策略"
)
print("✅ 保存策略洞察成功")
return True
except Exception as e:
print(f"❌ 记忆增强智能体测试失败: {e}")
return False
async def test_baxian_memory_council():
"""测试八仙记忆议会"""
print("\n🧪 测试八仙记忆议会...")
try:
# 创建记忆增强议会
council = await create_memory_enhanced_council()
print(f"✅ 创建八仙记忆议会成功,智能体数量: {len(council.agents)}")
# 列出所有智能体
for agent_name, agent in council.agents.items():
print(f" - {agent.personality.chinese_name} ({agent_name})")
# 进行简短的记忆辩论测试
print("\n🏛️ 开始记忆增强辩论测试...")
result = await council.conduct_memory_debate(
topic="比特币投资价值分析",
participants=["tieguaili", "lvdongbin"], # 只选择两个智能体进行快速测试
rounds=1
content="测试内容"
)
print(f"✅ 辩论完成")
print(f" 主题: {result['topic']}")
print(f" 参与者: {len(result['participants'])}")
print(f" 发言次数: {result['total_exchanges']}")
# 验证记忆银行已被自动创建
self.assertIn("tieguaili", self.memory_bank.memory_banks)
self.assertIn("tieguaili", self.memory_bank.local_memories)
# 显示辩论内容
for exchange in result['conversation_history']:
print(f" {exchange['chinese_name']}: {exchange['content'][:80]}...")
# 验证记忆已存储
self.assertEqual(len(self.memory_bank.local_memories["tieguaili"]), 1)
async def test_search_memories(self):
"""测试搜索记忆"""
# 先创建记忆银行并添加一些记忆
await self.memory_bank.create_memory_bank("tieguaili")
# 获取集体记忆摘要
summary = await council.get_collective_memory_summary("比特币投资价值分析")
print(f"\n📚 集体记忆摘要长度: {len(summary)} 字符")
await self.memory_bank.add_memory(
agent_name="tieguaili",
content="在讨论NVIDIA股票时我倾向于逆向思维关注潜在风险。",
memory_type="preference",
debate_topic="NVIDIA投资分析"
)
return True
await self.memory_bank.add_memory(
agent_name="tieguaili",
content="我喜欢关注苹果公司的创新产品发布会。",
memory_type="preference",
debate_topic="AAPL投资分析"
)
except Exception as e:
print(f"❌ 八仙记忆议会测试失败: {e}")
return False
# 搜索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趋势的判断上略显保守。")
async def test_memory_bank_initialization():
"""测试Memory Bank初始化"""
print("\n🧪 测试 Memory Bank 初始化...")
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()
try:
config = get_google_genai_config()
project_id = config.get('project_id')
location = config.get('location', 'us-central1')
if not project_id:
print("❌ 项目ID未配置跳过初始化测试")
return False
# 初始化所有八仙记忆银行
memory_bank = await initialize_baxian_memory_banks(project_id, location)
print(f"✅ 八仙记忆银行初始化成功")
print(f" 记忆银行数量: {len(memory_bank.memory_banks)}")
for agent_name, bank_name in memory_bank.memory_banks.items():
chinese_name = memory_bank.baxian_agents.get(agent_name, agent_name)
print(f" - {chinese_name}: {bank_name}")
return True
except Exception as e:
print(f"❌ Memory Bank 初始化测试失败: {e}")
return False
async def main():
"""主测试函数"""
print("🏛️ 稷下学宫 Vertex AI Memory Bank 测试")
print("=" * 50)
# 获取所有以test_开头的异步方法并运行它们
suite = unittest.TestSuite()
test_instance = TestVertexMemoryBank()
test_instance.setUp()
# 检查配置
print("🔧 检查配置...")
config = get_google_genai_config()
# 添加同步测试
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'))
print(f"Google API Key: {'已配置' if config.get('api_key') else '未配置'}")
print(f"Project ID: {config.get('project_id', '未配置')}")
print(f"Location: {config.get('location', 'us-central1')}")
print(f"Memory Bank: {'启用' if config.get('memory_bank_enabled', 'TRUE') == 'TRUE' else '禁用'}")
if not config.get('project_id'):
print("\n❌ 测试需要 Google Cloud Project ID")
print("请设置环境变量: GOOGLE_CLOUD_PROJECT_ID=your-project-id")
return
# 运行测试
tests = [
("Memory Bank 基础功能", test_memory_bank_basic),
("记忆增强智能体", test_memory_enhanced_agent),
("八仙记忆议会", test_baxian_memory_council),
("Memory Bank 初始化", test_memory_bank_initialization)
# 添加异步测试
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'
]
results = []
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())))
for test_name, test_func in tests:
print(f"\n{'='*20}")
print(f"测试: {test_name}")
print(f"{'='*20}")
try:
result = await test_func()
results.append((test_name, result))
except Exception as e:
print(f"❌ 测试 {test_name} 出现异常: {e}")
results.append((test_name, False))
# 显示测试结果摘要
print(f"\n{'='*50}")
print("🏛️ 测试结果摘要")
print(f"{'='*50}")
passed = 0
total = len(results)
for test_name, result in results:
status = "✅ 通过" if result else "❌ 失败"
print(f"{status} {test_name}")
if result:
passed += 1
print(f"\n📊 总体结果: {passed}/{total} 测试通过")
if passed == total:
print("🎉 所有测试通过Vertex AI Memory Bank 集成成功!")
else:
print("⚠️ 部分测试失败,请检查配置和网络连接")
if __name__ == "__main__":
# 运行测试
asyncio.run(main())
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

90
tests/validate_models.py Normal file
View File

@@ -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())