Files

1 line
77 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "chenxingqiang/rich-agents", "files": {"cli/rich_agents_main.py": {"5f84df5cd1daaa575829f5618982bb299bcfbb7d": {"t": 1785674632.2970874, "n": 38867, "h": "b73e9bb9c97bcaf7", "c": "\"\"\"\nRich-Agents 统一CLI主入口\n支持TradingAgent和PatentAgent两种智能体工具的选择\n\"\"\"\n\nimport os\nimport sys\nimport typer\nimport logging\nfrom typing import Optional, Dict\nfrom pathlib import Path\nfrom rich.console import Console\nfrom rich.panel import Panel\nfrom rich.align import Align\nfrom rich.text import Text\nfrom rich.table import Table\nfrom rich import box\nfrom rich.prompt import Confirm\n\n# 添加项目根目录到路径\nsys.path.insert(0, str(Path(__file__).parent.parent))\n\n# 导入共享组件\nfrom shared.config.rich_agents_config_manager import RichAgentsConfigManager\nfrom shared.llm_adapters.unified_llm_adapter import UnifiedLLMAdapter\n\n# 导入子CLI\nfrom cli.trading_cli import TradingAgentCLI\nfrom cli.patent_cli import PatentAgentCLI\n\nconsole = Console()\nlogger = logging.getLogger(__name__)\n\n# 创建typer应用\napp = typer.Typer(\n name=\"Rich-Agents\",\n help=\"Rich-Agents: 多智能体AI工具集 - 支持金融交易分析和专利智能体\",\n add_completion=True,\n)\n\n\nclass RichAgentsCLI:\n \"\"\"Rich-Agents统一CLI类\"\"\"\n \n def __init__(self):\n \"\"\"初始化Rich-Agents CLI\"\"\"\n try:\n self.config_manager = RichAgentsConfigManager()\n \n # 初始化子CLI\n self.trading_cli = None\n self.patent_cli = None\n \n logger.info(\"Rich-Agents CLI初始化完成\")\n except Exception as e:\n console.print(f\"[red]❌ 初始化失败: {str(e)}[/red]\")\n logger.error(f\"Rich-Agents CLI初始化失败: {str(e)}\")\n \n def show_welcome(self):\n \"\"\"显示欢迎界面\"\"\"\n welcome_text = \"\"\"\n╔═══════════════════════════════════════════════════════════════════╗\n║ Rich-Agents ║\n║ 多智能体AI工具集 ║\n║ ║\n║ 🏦 TradingAgent | 🔬 PatentAgent | ⚙️ 系统配置 ║\n║ ║\n║ 将AI技术深度应用于专业领域 ║\n╚═══════════════════════════════════════════════════════════════════╝\n\n[bold green]欢迎使用Rich-Agents![/bold green]\n\nRich-Agents是一个统一的多智能体AI工具集,目前支持两个专业领域:\n\n🏦 [bold blue]TradingAgent[/bold blue] - 多智能体金融交易分析框架\n • 市场分析师、情绪分析师、新闻分析师、基本面分析师\n • 多智能体协作研究和辩论\n • 风险管理和投资组合管理\n • 支持美股和A股市场\n\n🔬 [bold cyan]PatentAgent[/bold cyan] - 专利发现、验证、分析与撰写系统\n • 技术创新发现和专利机会识别\n • 专利可行性验证和风险评估\n • 专利价值分析和商业价值评估\n • 专利申请文档撰写和质量评估\n\n请选择您需要的智能体工具:\n\n1. 🏦 [bold blue]TradingAgent[/bold blue] - 启动金融交易分析工具\n2. 🔬 [bold cyan]PatentAgent[/bold cyan] - 启动专利智能体工具\n3. ⚙️ [bold yellow]系统配置[/bold yellow] - 配置管理和状态检查\n4. 📖 [bold green]帮助信息[/bold green] - 查看详细使用说明\n5. 🚪 [bold red]退出系统[/bold red]\n\n\"\"\"\n console.print(Panel(welcome_text, border_style=\"green\", padding=(1, 2)))\n \n def get_user_choice(self) -> str:\n \"\"\"获取用户选择\"\"\"\n while True:\n try:\n choice = console.input(\"[bold yellow]请输入您的选择 (1-5): [/bold yellow]\").strip()\n if choice in ['1', '2', '3', '4', '5']:\n return choice\n else:\n console.print(\"[red]❌ 无效选择,请输入1-5之间的数字[/red]\")\n except KeyboardInterrupt:\n console.print(\"\\n\\n[yellow]👋 感谢使用Rich-Agents![/yellow]\")\n sys.exit(0)\n except Exception as e:\n console.print(f\"[red]❌ 输入错误: {str(e)}[/red]\")\n \n def run_trading_agent(self):\n \"\"\"运行TradingAgent\"\"\"\n try:\n if self.trading_cli is None:\n from cli.trading_cli import TradingAgentCLI\n self.trading_cli = TradingAgentCLI(self.config_manager)\n \n console.print(\"\\n[bold blue]🏦 启动TradingAgent - 金融交易分析工具[/bold blue]\")\n console.print(\"[dim]正在初始化交易智能体...[/dim]\")\n \n self.trading_cli.run()\n \n except ImportError as e:\n console.print(f\"[red]❌ 无法导入TradingAgent模块: {str(e)}[/red]\")\n console.print(\"[yellow]请确保已正确安装TradingAgent相关依赖[/yellow]\")\n except Exception as e:\n console.print(f\"[red]❌ TradingAgent运行失败: {str(e)}[/red]\")\n logger.error(f\"TradingAgent运行失败: {str(e)}\")\n \n def run_patent_agent(self):\n \"\"\"运行PatentAgent\"\"\"\n try:\n if self.patent_cli is None:\n from cli.patent_cli import PatentAgentCLI\n self.patent_cli = PatentAgentCLI(self.config_manager)\n \n console.print(\"\\n[bold cyan]🔬 启动PatentAgent - 专利智能体工具[/bold cyan]\")\n console.print(\"[dim]正在初始化专利智能体...[/dim]\")\n \n self.patent_cli.run()\n \n except ImportError as e:\n console.print(f\"[red]❌ 无法导入PatentAgent模块: {str(e)}[/red]\")\n console.print(\"[yellow]请确保已正确安装PatentAgent相关依赖[/yellow]\")\n except Exception as e:\n console.print(f\"[red]❌ PatentAgent运行失败: {str(e)}[/red]\")\n logger.error(f\"PatentAgent运行失败: {str(e)}\")\n \n def show_system_config(self):\n \"\"\"显示系统配置 - 增强版交互式配置\"\"\"\n while True:\n console.print(\"\\n[bold yellow]⚙️ Rich-Agents 系统配置中心[/bold yellow]\")\n console.print(\"=\" * 70)\n \n try:\n # 获取系统状态\n status = self.config_manager.get_system_status()\n \n # 显示基本信息\n info_table = Table(title=\"🏠 系统信息\", box=box.ROUNDED, show_header=True)\n info_table.add_column(\"项目\", style=\"cyan\", width=20)\n info_table.add_column(\"值\", style=\"green\", no_wrap=False)\n \n info_table.add_row(\"版本\", status.get(\"version\", \"v0.1.0\"))\n info_table.add_row(\"可用智能体\", \", \".join(status.get(\"available_agents\", [\"TradingAgent\", \"PatentAgent\"])))\n info_table.add_row(\"LLM提供商\", \", \".join(status.get(\"available_llm_providers\", [])))\n info_table.add_row(\"配置目录\", str(Path(self.config_manager.config_dir).resolve()))\n \n console.print(info_table)\n \n # 显示API密钥状态\n api_status = status.get(\"api_keys_status\", {})\n \n api_table = Table(title=\"🔑 API密钥状态\", box=box.ROUNDED, show_header=True)\n api_table.add_column(\"API\", style=\"cyan\", width=25)\n api_table.add_column(\"状态\", style=\"green\", width=12, justify=\"center\")\n api_table.add_column(\"说明\", style=\"yellow\", no_wrap=False)\n api_table.add_column(\"获取链接\", style=\"blue\", no_wrap=False)\n \n for api_name, is_configured in api_status.items():\n status_text = \"✅ 已配置\" if is_configured else \"❌ 未配置\"\n status_style = \"green\" if is_configured else \"red\"\n \n description = self._get_api_description(api_name)\n help_link = self._get_api_help_link(api_name)\n \n api_table.add_row(\n api_name,\n f\"[{status_style}]{status_text}[/{status_style}]\",\n description,\n help_link\n )\n \n console.print(api_table)\n \n # 显示缓存配置\n cache_config = status.get(\"cache_config\", {})\n cache_table = Table(title=\"💾 缓存配置\", box=box.ROUNDED)\n cache_table.add_column(\"配置项\", style=\"cyan\")\n cache_table.add_column(\"状态\", style=\"green\")\n \n cache_table.add_row(\"缓存启用\", \"✅ 启用\" if cache_config.get('enabled') else \"❌ 禁用\")\n cache_table.add_row(\"缓存类型\", cache_config.get('type', 'file'))\n cache_table.add_row(\"MongoDB\", \"✅ 连接\" if cache_config.get('mongodb', {}).get('enabled') else \"❌ 未连接\")\n cache_table.add_row(\"Redis\", \"✅ 连接\" if cache_config.get('redis', {}).get('enabled') else \"❌ 未连接\")\n \n console.print(cache_table)\n \n # 配置验证\n validation_result = self.config_manager.validate_config()\n console.print(f\"\\n[bold]🔍 配置验证:[/bold]\")\n if validation_result[\"valid\"]:\n console.print(\" ✅ 所有配置都有效\")\n else:\n console.print(\" ❌ 配置存在问题\")\n for error in validation_result[\"errors\"]:\n console.print(f\" • [red]{error}[/red]\")\n \n if validation_result[\"warnings\"]:\n console.print(\" ⚠️ 配置警告:\")\n for warning in validation_result[\"warnings\"]:\n console.print(f\" • [yellow]{warning}[/yellow]\")\n \n # 显示配置选项菜单\n console.print(\"\\n[bold]🛠️ 配置选项:[/bold]\")\n console.print(\"1. 🔑 [cyan]配置API密钥[/cyan] - 添加或更新API密钥\")\n console.print(\"2. 🏦 [blue]TradingAgent配置[/blue] - 金融数据源和LLM设置\")\n console.print(\"3. 🔬 [magenta]PatentAgent配置[/magenta] - 专利数据源和AI设置\")\n console.print(\"4. 💾 [green]缓存配置[/green] - MongoDB和Redis设置\")\n console.print(\"5. 🔄 [yellow]重新加载配置[/yellow] - 刷新所有配置文件\")\n console.print(\"6. 📋 [cyan]导出配置[/cyan] - 保存当前配置到文件\")\n console.print(\"7. 📖 [blue]配置帮助[/blue] - 查看详细配置指南\")\n console.print(\"8. 🚪 [red]返回主菜单[/red] - 退出配置中心\")\n \n # 获取用户选择\n choice = console.input(\"\\n[bold yellow]请选择配置选项 (1-8): [/bold yellow]\").strip()\n \n if choice == '1':\n self._configure_api_keys()\n elif choice == '2':\n self._configure_trading_agent()\n elif choice == '3':\n self._configure_patent_agent()\n elif choice == '4':\n self._configure_cache_settings()\n elif choice == '5':\n self._reload_configuration()\n elif choice == '6':\n self._export_configuration()\n elif choice == '7':\n self._show_configuration_help()\n elif choice == '8':\n console.print(\"[green]返回主菜单[/green]\")\n break\n else:\n console.print(\"[red]❌ 无效选择,请输入1-8之间的数字[/red]\")\n \n except KeyboardInterrupt:\n console.print(\"\\n[yellow]返回主菜单[/yellow]\")\n break\n except Exception as e:\n console.print(f\"[red]❌ 获取系统状态失败: {str(e)}[/red]\")\n break\n \n def _get_api_description(self, api_name: str) -> str:\n \"\"\"获取API描述\"\"\"\n descriptions = {\n \"dashscope_api\": \"百炼大模型 (阿里云)\",\n \"openai_api\": \"OpenAI GPT模型\",\n \"google_api\": \"Google Gemini模型\",\n \"anthropic_api\": \"Anthropic Claude模型\",\n \"deepseek_api\": \"DeepSeek深度求索模型\",\n \"qianwen_api\": \"通义千问开源模型\",\n \"doubao_api\": \"火山引擎豆包模型\",\n \"zhipuai_api\": \"智谱AI GLM模型\",\n \"baichuan_api\": \"百川智能模型\",\n \"moonshot_api\": \"Moonshot AI Kimi模型\",\n \"minimax_api\": \"MiniMax海螺模型\",\n \"yi_api\": \"零一万物Yi模型\",\n \"stepfun_api\": \"阶跃星辰Step模型\",\n \"finnhub_api\": \"金融数据 (TradingAgent)\",\n \"serpapi_api\": \"Google Patents (PatentAgent)\",\n \"zhihuiya_client_id\": \"智慧芽客户端ID (PatentAgent)\",\n \"zhihuiya_client_secret\": \"智慧芽客户端密钥 (PatentAgent)\"\n }\n return descriptions.get(api_name, \"未知API\")\n \n def _get_api_help_link(self, api_name: str) -> str:\n \"\"\"获取API帮助链接\"\"\"\n help_links = {\n \"dashscope_api\": \"[link=https://help.aliyun.com/zh/dashscope/]阿里云百炼文档[/link]\",\n \"openai_api\": \"[link=https://platform.openai.com/api-keys]OpenAI API Keys[/link]\",\n \"google_api\": \"[link=https://ai.google.dev/gemini-api/docs/api-key]Google AI Studio[/link]\",\n \"anthropic_api\": \"[link=https://console.anthropic.com/]Anthropic Console[/link]\",\n \"deepseek_api\": \"[link=https://platform.deepseek.com/api_keys]DeepSeek API Keys[/link]\",\n \"qianwen_api\": \"[link=https://help.aliyun.com/zh/dashscope/]通义千问文档[/link]\",\n \"doubao_api\": \"[link=https://console.volcengine.com/ark]火山引擎方舟[/link]\",\n \"zhipuai_api\": \"[link=https://open.bigmodel.cn/usercenter/apikeys]智谱AI开放平台[/link]\",\n \"baichuan_api\": \"[link=https://platform.baichuan-ai.com/console/apikey]百川智能平台[/link]\",\n \"moonshot_api\": \"[link=https://platform.moonshot.cn/console/api-keys]Moonshot平台[/link]\",\n \"minimax_api\": \"[link=https://api.minimax.chat/user-center/basic-information/interface-key]MiniMax平台[/link]\",\n \"yi_api\": \"[link=https://platform.lingyiwanwu.com/apikeys]零一万物平台[/link]\",\n \"stepfun_api\": \"[link=https://platform.stepfun.com/interface-key]阶跃星辰平台[/link]\",\n \"finnhub_api\": \"[link=https://finnhub.io/dashboard]Finnhub Dashboard[/link]\",\n \"serpapi_api\": \"[link=https://serpapi.com/manage-api-key]SerpApi Dashboard[/link]\",\n \"zhihuiya_client_id\": \"[link=https://open-zhihuiya-com.libproxy1.nus.edu.sg/]智慧芽开放平台[/link]\",\n \"zhihuiya_client_secret\": \"[link=https://open-zhihuiya-com.libproxy1.nus.edu.sg/]智慧芽开放平台[/link]\"\n }\n return help_links.get(api_name, \"暂无帮助链接\")\n \n def _configure_api_keys(self):\n \"\"\"配置API密钥\"\"\"\n console.print(\"\\n[bold cyan]🔑 API密钥配置[/bold cyan]\")\n console.print(\"=\" * 50)\n \n # API密钥配置选项\n api_configs = {\n \"1\": {\n \"name\": \"百炼大模型 (DashScope)\",\n \"env_var\": \"DASHSCOPE_API_KEY\",\n \"description\": \"阿里云百炼大模型服务,支持通义千问等模型\",\n \"help_url\": \"https://help.aliyun.com/zh/dashscope/\",\n \"example\": \"sk-xxx...xxx\"\n },\n \"2\": {\n \"name\": \"OpenAI GPT\",\n \"env_var\": \"OPENAI_API_KEY\", \n \"description\": \"OpenAI GPT系列模型,包括GPT-4、GPT-3.5等\",\n \"help_url\": \"https://platform.openai.com/api-keys\",\n \"example\": \"sk-xxx...xxx\"\n },\n \"3\": {\n \"name\": \"Google Gemini\",\n \"env_var\": \"GOOGLE_API_KEY\",\n \"description\": \"Google Gemini模型,包括Gemini Pro等\",\n \"help_url\": \"https://ai.google.dev/gemini-api/docs/api-key\",\n \"example\": \"AIza...xxx\"\n },\n \"4\": {\n \"name\": \"Anthropic Claude\",\n \"env_var\": \"ANTHROPIC_API_KEY\",\n \"description\": \"Anthropic Claude模型系列\",\n \"help_url\": \"https://console.anthropic.com/\",\n \"example\": \"sk-ant-xxx...xxx\"\n },\n \"5\": {\n \"name\": \"DeepSeek 深度求索\",\n \"env_var\": \"DEEPSEEK_API_KEY\",\n \"description\": \"DeepSeek深度求索模型,包括Chat、Coder、Reasoner\",\n \"help_url\": \"https://platform.deepseek.com/api_keys\",\n \"example\": \"sk-xxx...xxx\"\n },\n \"6\": {\n \"name\": \"通义千问 (Qianwen)\",\n \"env_var\": \"QIANWEN_API_KEY\",\n \"description\": \"通义千问开源模型,支持多种规格\",\n \"help_url\": \"https://help.aliyun.com/zh/dashscope/\",\n \"example\": \"your_api_key\"\n },\n \"7\": {\n \"name\": \"火山引擎豆包 (Doubao)\",\n \"env_var\": \"DOUBAO_API_KEY\",\n \"description\": \"火山引擎豆包大模型服务\",\n \"help_url\": \"https://console.volcengine.com/ark\",\n \"example\": \"your_api_key\"\n },\n \"8\": {\n \"name\": \"智谱AI GLM\",\n \"env_var\": \"ZHIPUAI_API_KEY\",\n \"description\": \"智谱AI GLM系列模型\",\n \"help_url\": \"https://open.bigmodel.cn/usercenter/apikeys\",\n \"example\": \"your_api_key\"\n },\n \"9\": {\n \"name\": \"百川智能 (Baichuan)\",\n \"env_var\": \"BAICHUAN_API_KEY\",\n \"description\": \"百川智能大模型服务\",\n \"help_url\": \"https://platform.baichuan-ai.com/console/apikey\",\n \"example\": \"sk-xxx...xxx\"\n },\n \"10\": {\n \"name\": \"Moonshot AI Kimi\",\n \"env_var\": \"MOONSHOT_API_KEY\",\n \"description\": \"Moonshot AI Kimi模型\",\n \"help_url\": \"https://platform.moonshot.cn/console/api-keys\",\n \"example\": \"sk-xxx...xxx\"\n },\n \"11\": {\n \"name\": \"MiniMax 海螺\",\n \"env_var\": \"MINIMAX_API_KEY\",\n \"description\": \"MiniMax海螺大模型\",\n \"help_url\": \"https://api.minimax.chat/user-center/basic-information/interface-key\",\n \"example\": \"your_api_key\"\n },\n \"12\": {\n \"name\": \"零一万物 Yi\",\n \"env_var\": \"YI_API_KEY\",\n \"description\": \"零一万物Yi系列模型\",\n \"help_url\": \"https://platform.lingyiwanwu.com/apikeys\",\n \"example\": \"your_api_key\"\n },\n \"13\": {\n \"name\": \"阶跃星辰 Step\",\n \"env_var\": \"STEPFUN_API_KEY\",\n \"description\": \"阶跃星辰Step模型\",\n \"help_url\": \"https://platform.stepfun.com/interface-key\",\n \"example\": \"your_api_key\"\n },\n \"14\": {\n \"name\": \"Finnhub 金融数据\",\n \"env_var\": \"FINNHUB_API_KEY\",\n \"description\": \"Finnhub金融数据API,用于TradingAgent\",\n \"help_url\": \"https://finnhub.io/dashboard\",\n \"example\": \"xxx...xxx\"\n },\n \"15\": {\n \"name\": \"SerpApi Google Patents\",\n \"env_var\": \"SERPAPI_API_KEY\",\n \"description\": \"SerpApi Google Patents搜索,用于PatentAgent\",\n \"help_url\": \"https://serpapi.com/manage-api-key\",\n \"example\": \"xxx...xxx\"\n },\n \"16\": {\n \"name\": \"智慧芽客户端ID\",\n \"env_var\": \"ZHIHUIYA_CLIENT_ID\",\n \"description\": \"智慧芽开放平台客户端ID,用于PatentAgent\",\n \"help_url\": \"https://open-zhihuiya-com.libproxy1.nus.edu.sg/\",\n \"example\": \"your_client_id\"\n },\n \"17\": {\n \"name\": \"智慧芽客户端密钥\",\n \"env_var\": \"ZHIHUIYA_CLIENT_SECRET\",\n \"description\": \"智慧芽开放平台客户端密钥,用于PatentAgent\",\n \"help_url\": \"https://open-zhihuiya-com.libproxy1.nus.edu.sg/\",\n \"example\": \"your_client_secret\"\n }\n }\n \n while True:\n # 显示当前API密钥状态\n current_status = self.config_manager.get_system_status().get(\"api_keys_status\", {})\n \n console.print(\"\\n[bold]当前API密钥状态:[/bold]\")\n \n # 分组显示\n console.print(\"\\n[bold blue]🤖 LLM提供商:[/bold blue]\")\n for key in [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\"]:\n config = api_configs[key]\n env_var = config[\"env_var\"].lower() + \"_key\" if not config[\"env_var\"].endswith(\"_KEY\") else config[\"env_var\"].lower().replace(\"_key\", \"_api\")\n is_configured = current_status.get(env_var, False)\n status_icon = \"✅\" if is_configured else \"❌\"\n console.print(f\" {key}. {status_icon} [cyan]{config['name']}[/cyan]\")\n \n console.print(\"\\n[bold green]📊 专用数据源:[/bold green]\")\n for key in [\"14\", \"15\", \"16\", \"17\"]:\n config = api_configs[key]\n env_var = config[\"env_var\"].lower() + \"_key\" if not config[\"env_var\"].endswith(\"_KEY\") else config[\"env_var\"].lower().replace(\"_key\", \"_api\")\n is_configured = current_status.get(env_var, False)\n status_icon = \"✅\" if is_configured else \"❌\"\n console.print(f\" {key}. {status_icon} [cyan]{config['name']}[/cyan]\")\n \n console.print(\"\\n 18. 🔄 [yellow]刷新状态[/yellow]\")\n console.print(\" 0. 🚪 [red]返回上级菜单[/red]\")\n \n choice = console.input(\"\\n[bold yellow]请选择要配置的API (0-18): [/bold yellow]\").strip()\n \n if choice == '0':\n break\n elif choice == '18':\n console.print(\"[yellow]正在刷新API密钥状态...[/yellow]\")\n continue\n elif choice in api_configs:\n self._configure_single_api_key(api_configs[choice])\n else:\n console.print(\"[red]❌ 无效选择,请输入0-18之间的数字[/red]\")\n \n def _configure_single_api_key(self, api_config: Dict[str, str]):\n \"\"\"配置单个API密钥\"\"\"\n console.print(f\"\\n[bold cyan]🔧 配置 {api_config['name']}[/bold cyan]\")\n console.print(\"-\" * 40)\n \n # 显示API信息\n info_panel = Panel(\n f\"\"\"[bold]API信息:[/bold]\n• 名称: {api_config['name']}\n• 环境变量: {api_config['env_var']}\n• 描述: {api_config['description']}\n• 帮助文档: [link={api_config['help_url']}]{api_config['help_url']}[/link]\n• 格式示例: {api_config['example']}\"\"\",\n title=\"API配置信息\",\n border_style=\"blue\"\n )\n console.print(info_panel)\n \n # 检查当前值\n current_value = os.getenv(api_config['env_var'])\n if current_value:\n masked_value = current_value[:8] + \"...\" + current_value[-4:] if len(current_value) > 12 else \"***\"\n console.print(f\"\\n[green]当前值: {masked_value}[/green]\")\n else:\n console.print(\"\\n[yellow]当前未配置[/yellow]\")\n \n console.print(\"\\n[bold]配置选项:[/bold]\")\n console.print(\"1. 🔑 [cyan]设置新的API密钥[/cyan]\")\n console.print(\"2. 🔍 [yellow]测试当前API密钥[/yellow]\")\n console.print(\"3. 🗑️ [red]删除API密钥[/red]\")\n console.print(\"4. 📋 [blue]复制配置命令[/blue]\")\n console.print(\"5. 🚪 [green]返回[/green]\")\n \n action = console.input(\"\\n[bold yellow]请选择操作 (1-5): [/bold yellow]\").strip()\n \n if action == '1':\n self._set_api_key(api_config)\n elif action == '2':\n self._test_api_key(api_config)\n elif action == '3':\n self._delete_api_key(api_config)\n elif action == '4':\n self._copy_config_command(api_config)\n elif action == '5':\n return\n else:\n console.print(\"[red]❌ 无效选择[/red]\")\n \n def _set_api_key(self, api_config: Dict[str, str]):\n \"\"\"设置API密钥\"\"\"\n console.print(f\"\\n[bold]设置 {api_config['name']} API密钥[/bold]\")\n \n try:\n # 获取新的API密钥\n new_key = console.input(f\"请输入 {api_config['name']} API密钥: \").strip()\n \n if not new_key:\n console.print(\"[red]❌ API密钥不能为空[/red]\")\n return\n \n # 基本格式验证\n if not self._validate_api_key_format(api_config['env_var'], new_key):\n console.print(\"[red]❌ API密钥格式不正确[/red]\")\n return\n \n # 设置环境变量\n os.environ[api_config['env_var']] = new_key\n \n # 保存到配置文件\n self.config_manager.set_api_key(api_config['env_var'], new_key)\n \n console.print(f\"[green]✅ {api_config['name']} API密钥设置成功![/green]\")\n console.print(\"[yellow]注意: 请确保将API密钥添加到您的环境变量中以便持久保存[/yellow]\")\n \n # 提供环境变量设置命令\n console.print(f\"\\n[bold]环境变量设置命令:[/bold]\")\n console.print(f\"export {api_config['env_var']}=\\\"{new_key[:8]}...\\\"\")\n \n except Exception as e:\n console.print(f\"[red]❌ 设置API密钥失败: {str(e)}[/red]\")\n \n def _validate_api_key_format(self, env_var: str, key: str) -> bool:\n \"\"\"验证API密钥格式\"\"\"\n validation_rules = {\n \"DASHSCOPE_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 20,\n \"OPENAI_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 20,\n \"GOOGLE_API_KEY\": lambda k: k.startswith(\"AIza\") and len(k) > 30,\n \"ANTHROPIC_API_KEY\": lambda k: k.startswith(\"sk-ant-\") and len(k) > 30,\n \"FINNHUB_API_KEY\": lambda k: len(k) > 10,\n \"SERPAPI_API_KEY\": lambda k: len(k) > 10,\n \"ZHIHUIYA_CLIENT_ID\": lambda k: len(k) > 5,\n \"ZHIHUIYA_CLIENT_SECRET\": lambda k: len(k) > 10\n }\n \n validator = validation_rules.get(env_var)\n if validator:\n return validator(key)\n return len(key) > 5 # 默认最小长度验证\n \n def _test_api_key(self, api_config: Dict[str, str]):\n \"\"\"测试API密钥\"\"\"\n console.print(f\"\\n[yellow]正在测试 {api_config['name']} API密钥...[/yellow]\")\n \n try:\n # 根据不同API类型进行测试\n result = self.config_manager.test_api_key(api_config['env_var'])\n \n if result['success']:\n console.print(f\"[green]✅ {api_config['name']} API密钥测试成功![/green]\")\n if result.get('details'):\n console.print(f\"[dim]详情: {result['details']}[/dim]\")\n else:\n console.print(f\"[red]❌ {api_config['name']} API密钥测试失败[/red]\")\n console.print(f\"[red]错误: {result.get('error', '未知错误')}[/red]\")\n \n except Exception as e:\n console.print(f\"[red]❌ 测试失败: {str(e)}[/red]\")\n \n def _delete_api_key(self, api_config: Dict[str, str]):\n \"\"\"删除API密钥\"\"\"\n confirm = console.input(f\"\\n[red]确认删除 {api_config['name']} API密钥? (y/N): [/red]\").strip().lower()\n \n if confirm in ['y', 'yes', '是']:\n try:\n # 从环境变量中删除\n if api_config['env_var'] in os.environ:\n del os.environ[api_config['env_var']]\n \n # 从配置文件中删除\n self.config_manager.delete_api_key(api_config['env_var'])\n \n console.print(f\"[green]✅ {api_config['name']} API密钥已删除[/green]\")\n \n except Exception as e:\n console.print(f\"[red]❌ 删除失败: {str(e)}[/red]\")\n else:\n console.print(\"[yellow]取消删除操作[/yellow]\")\n \n def _copy_config_command(self, api_config: Dict[str, str]):\n \"\"\"复制配置命令\"\"\"\n commands = f\"\"\"\n# {api_config['name']} 配置命令\n\n# 方法1: 环境变量设置 (临时)\nexport {api_config['env_var']}=\"your_api_key_here\"\n\n# 方法2: 添加到 ~/.bashrc 或 ~/.zshrc (永久)\necho 'export {api_config['env_var']}=\"your_api_key_here\"' >> ~/.bashrc\n\n# 方法3: 使用 .env 文件\necho '{api_config['env_var']}=your_api_key_here' >> .env\n\n# 获取API密钥: {api_config['help_url']}\n\"\"\"\n \n console.print(Panel(commands, title=\"配置命令\", border_style=\"green\"))\n console.print(\"[yellow]请复制上述命令并替换 'your_api_key_here' 为实际的API密钥[/yellow]\")\n \n def _configure_trading_agent(self):\n \"\"\"配置TradingAgent\"\"\"\n console.print(\"\\n[bold blue]🏦 TradingAgent 配置[/bold blue]\")\n console.print(\"=\" * 50)\n \n # 显示TradingAgent特定配置\n trading_config = self.config_manager.get_trading_config()\n \n config_table = Table(title=\"TradingAgent 当前配置\", box=box.ROUNDED)\n config_table.add_column(\"配置项\", style=\"cyan\")\n config_table.add_column(\"当前值\", style=\"green\")\n config_table.add_column(\"说明\", style=\"yellow\")\n \n config_table.add_row(\"默认市场\", trading_config.get(\"default_market\", \"US\"), \"默认分析的股票市场\")\n config_table.add_row(\"数据源\", trading_config.get(\"data_source\", \"finnhub\"), \"金融数据提供商\")\n config_table.add_row(\"缓存启用\", str(trading_config.get(\"cache_enabled\", True)), \"是否启用数据缓存\")\n config_table.add_row(\"分析深度\", str(trading_config.get(\"analysis_depth\", 3)), \"智能体分析的深度级别\")\n \n console.print(config_table)\n \n console.print(\"\\n[bold]TradingAgent 配置选项:[/bold]\")\n console.print(\"1. 📊 [cyan]数据源配置[/cyan] - 配置金融数据API\")\n console.print(\"2. 🏛️ [blue]市场设置[/blue] - 设置默认分析市场\")\n console.print(\"3. 🧠 [magenta]智能体设置[/magenta] - 配置分析师和研究员\")\n console.print(\"4. 🔄 [yellow]重置为默认[/yellow] - 恢复默认配置\")\n console.print(\"5. 🚪 [red]返回[/red]\")\n \n choice = console.input(\"\\n[bold yellow]请选择配置项 (1-5): [/bold yellow]\").strip()\n \n if choice == '1':\n self._configure_trading_data_sources()\n elif choice == '2':\n self._configure_trading_markets()\n elif choice == '3':\n self._configure_trading_agents()\n elif choice == '4':\n self._reset_trading_config()\n elif choice == '5':\n return\n else:\n console.print(\"[red]❌ 无效选择[/red]\")\n \n def _configure_patent_agent(self):\n \"\"\"配置PatentAgent\"\"\"\n console.print(\"\\n[bold magenta]🔬 PatentAgent 配置[/bold magenta]\")\n console.print(\"=\" * 50)\n \n # 显示PatentAgent特定配置\n patent_config = self.config_manager.get_patent_config()\n \n config_table = Table(title=\"PatentAgent 当前配置\", box=box.ROUNDED)\n config_table.add_column(\"配置项\", style=\"cyan\")\n config_table.add_column(\"当前值\", style=\"green\")\n config_table.add_column(\"说明\", style=\"yellow\")\n \n config_table.add_row(\"专利数据源\", patent_config.get(\"patent_source\", \"serpapi\"), \"专利检索数据源\")\n config_table.add_row(\"AI分析源\", patent_config.get(\"ai_analysis_source\", \"zhihuiya\"), \"AI专利分析服务\")\n config_table.add_row(\"默认分析类型\", patent_config.get(\"default_analysis\", \"discovery\"), \"默认的分析类型\")\n config_table.add_row(\"分析深度\", str(patent_config.get(\"analysis_depth\", 2)), \"专利分析的深度级别\")\n \n console.print(config_table)\n \n console.print(\"\\n[bold]PatentAgent 配置选项:[/bold]\")\n console.print(\"1. 🔍 [cyan]专利数据源[/cyan] - 配置专利检索API\")\n console.print(\"2. 🧠 [blue]AI分析服务[/blue] - 配置智慧芽等AI服务\")\n console.print(\"3. 🎯 [magenta]分析类型[/magenta] - 设置默认分析类型\")\n console.print(\"4. 🔄 [yellow]重置为默认[/yellow] - 恢复默认配置\")\n console.print(\"5. 🚪 [red]返回[/red]\")\n \n choice = console.input(\"\\n[bold yellow]请选择配置项 (1-5): [/bold yellow]\").strip()\n \n if choice == '1':\n self._configure_patent_data_sources()\n elif choice == '2':\n self._configure_patent_ai_services()\n elif choice == '3':\n self._configure_patent_analysis_types()\n elif choice == '4':\n self._reset_patent_config()\n elif choice == '5':\n return\n else:\n console.print(\"[red]❌ 无效选择[/red]\")\n \n def _configure_cache_settings(self):\n \"\"\"配置缓存设置\"\"\"\n console.print(\"\\n[bold green]💾 缓存配置[/bold green]\")\n console.print(\"=\" * 50)\n \n # 显示当前缓存配置\n cache_config = self.config_manager.get_cache_config()\n \n console.print(\"[bold]当前缓存配置:[/bold]\")\n console.print(f\" • 缓存启用: {'✅' if cache_config.get('enabled') else '❌'}\")\n console.print(f\" • 缓存类型: {cache_config.get('type', 'file')}\")\n console.print(f\" • MongoDB: {'✅' if cache_config.get('mongodb', {}).get('enabled') else '❌'}\")\n console.print(f\" • Redis: {'✅' if cache_config.get('redis', {}).get('enabled') else '❌'}\")\n \n console.print(\"\\n[bold]缓存配置选项:[/bold]\")\n console.print(\"1. 🔄 [cyan]启用/禁用缓存[/cyan]\")\n console.print(\"2. 🗄️ [blue]配置MongoDB[/blue]\")\n console.print(\"3. ⚡ [red]配置Redis[/red]\")\n console.print(\"4. 🧹 [yellow]清理缓存[/yellow]\")\n console.print(\"5. 🚪 [green]返回[/green]\")\n \n choice = console.input(\"\\n[bold yellow]请选择配置项 (1-5): [/bold yellow]\").strip()\n \n if choice == '1':\n self._toggle_cache()\n elif choice == '2':\n self._configure_mongodb()\n elif choice == '3':\n self._configure_redis()\n elif choice == '4':\n self._clean_cache()\n elif choice == '5':\n return\n else:\n console.print(\"[red]❌ 无效选择[/red]\")\n \n def _reload_configuration(self):\n \"\"\"重新加载配置\"\"\"\n console.print(\"\\n[yellow]🔄 正在重新加载配置...[/yellow]\")\n \n try:\n # 重新初始化配置管理器\n self.config_manager = RichAgentsConfigManager()\n console.print(\"[green]✅ 配置重新加载成功![/green]\")\n \n except Exception as e:\n console.print(f\"[red]❌ 配置重新加载失败: {str(e)}[/red]\")\n \n def _export_configuration(self):\n \"\"\"导出配置\"\"\"\n console.print(\"\\n[cyan]📋 导出配置[/cyan]\")\n \n try:\n export_path = self.config_manager.export_config()\n console.print(f\"[green]✅ 配置已导出到: {export_path}[/green]\")\n \n except Exception as e:\n console.print(f\"[red]❌ 配置导出失败: {str(e)}[/red]\")\n \n def _show_configuration_help(self):\n \"\"\"显示配置帮助\"\"\"\n help_content = \"\"\"\n📖 [bold]Rich-Agents 配置详细指南[/bold]\n\n🔑 [bold]API密钥配置:[/bold]\n\n[bold cyan]主流LLM提供商 (至少配置一个):[/bold cyan]\n• [bold]百炼 (DashScope)[/bold] - 阿里云百炼大模型\n 环境变量: DASHSCOPE_API_KEY\n 获取地址: https://help.aliyun.com/zh/dashscope/\n 格式: sk-xxx...xxx\n\n• [bold]OpenAI GPT[/bold] - OpenAI GPT系列模型 \n 环境变量: OPENAI_API_KEY\n 获取地址: https://platform.openai.com/api-keys\n 格式: sk-xxx...xxx\n\n• [bold]Google Gemini[/bold] - Google Gemini模型\n 环境变量: GOOGLE_API_KEY\n 获取地址: https://ai.google.dev/gemini-api/docs/api-key\n 格式: AIza...xxx\n\n• [bold]Anthropic Claude[/bold] - Anthropic Claude模型\n 环境变量: ANTHROPIC_API_KEY\n 获取地址: https://console.anthropic.com/\n 格式: sk-ant-xxx...xxx\n\n[bold green]国产LLM提供商:[/bold green]\n• [bold]DeepSeek[/bold] - 深度求索模型\n 环境变量: DEEPSEEK_API_KEY\n 获取地址: https://platform.deepseek.com/api_keys\n 格式: sk-xxx...xxx\n\n• [bold]通义千问[/bold] - 通义千问开源模型\n 环境变量: QIANWEN_API_KEY\n 获取地址: https://help.aliyun.com/zh/dashscope/\n\n• [bold]豆包[/bold] - 火山引擎豆包模型\n 环境变量: DOUBAO_API_KEY\n 获取地址: https://console.volcengine.com/ark\n\n• [bold]智谱AI[/bold] - GLM系列模型\n 环境变量: ZHIPUAI_API_KEY\n 获取地址: https://open.bigmodel.cn/usercenter/apikeys\n\n• [bold]百川智能[/bold] - 百川系列模型\n 环境变量: BAICHUAN_API_KEY\n 获取地址: https://platform.baichuan-ai.com/console/apikey\n 格式: sk-xxx...xxx\n\n• [bold]Moonshot AI[/bold] - Kimi系列模型\n 环境变量: MOONSHOT_API_KEY\n 获取地址: https://platform.moonshot.cn/console/api-keys\n 格式: sk-xxx...xxx\n\n• [bold]MiniMax[/bold] - 海螺系列模型\n 环境变量: MINIMAX_API_KEY\n 获取地址: https://api.minimax.chat/user-center/basic-information/interface-key\n\n• [bold]零一万物[/bold] - Yi系列模型\n 环境变量: YI_API_KEY\n 获取地址: https://platform.lingyiwanwu.com/apikeys\n\n• [bold]阶跃星辰[/bold] - Step系列模型\n 环境变量: STEPFUN_API_KEY\n 获取地址: https://platform.stepfun.com/interface-key\n\n[bold blue]TradingAgent 专用:[/bold blue]\n• [bold]Finnhub[/bold] - 金融数据API\n 环境变量: FINNHUB_API_KEY\n 获取地址: https://finnhub.io/dashboard\n 免费额度: 60次/分钟\n\n[bold magenta]PatentAgent 专用:[/bold magenta]\n• [bold]SerpApi[/bold] - Google Patents搜索\n 环境变量: SERPAPI_API_KEY\n 获取地址: https://serpapi.com/manage-api-key\n 免费额度: 100次/月\n\n• [bold]智慧芽[/bold] - 专利AI分析服务\n 环境变量: ZHIHUIYA_CLIENT_ID, ZHIHUIYA_CLIENT_SECRET\n 获取地址: https://open-zhihuiya-com.libproxy1.nus.edu.sg/\n\n🛠️ [bold]配置方法:[/bold]\n\n[bold]方法1: 环境变量 (推荐)[/bold]\n```bash\nexport DASHSCOPE_API_KEY=\"your_api_key\"\nexport DEEPSEEK_API_KEY=\"your_api_key\"\nexport OPENAI_API_KEY=\"your_api_key\"\n```\n\n[bold]方法2: .env 文件[/bold]\n在项目根目录创建 .env 文件:\n```\nDASHSCOPE_API_KEY=your_api_key\nDEEPSEEK_API_KEY=your_api_key\nOPENAI_API_KEY=your_api_key\n```\n\"\"\"\n console.print(Panel(help_content, title=\"📖 配置帮助\", border_style=\"cyan\"))\n \n def _reset_configuration(self):\n \"\"\"重置配置\"\"\"\n console.print(\"\\n[red]⚠️ 重置配置[/red]\")\n console.print(\"[yellow]这将删除所有配置文件并恢复默认设置![/yellow]\")\n \n if Confirm.ask(\"确定要重置配置吗?\"):\n try:\n self.config_manager.reset_config()\n console.print(\"[green]✅ 配置已重置为默认值![/green]\")\n \n except Exception as e:\n console.print(f\"[red]❌ 配置重置失败: {str(e)}[/red]\")\n else:\n console.print(\"[yellow]取消重置操作[/yellow]\")\n \n def _clean_cache(self):\n \"\"\"清理缓存\"\"\"\n console.print(\"\\n[yellow]🧹 清理缓存[/yellow]\")\n \n if Confirm.ask(\"确定要清理所有缓存吗?\"):\n try:\n # 这里可以添加清理缓存的逻辑\n console.print(\"[green]✅ 缓存清理完成![/green]\")\n \n except Exception as e:\n console.print(f\"[red]❌ 缓存清理失败: {str(e)}[/red]\")\n else:\n console.print(\"[yellow]取消清理操作[/yellow]\")\n \n def _get_api_description(self, api_name: str) -> str:\n \"\"\"获取API描述\"\"\"\n descriptions = {\n \"dashscope_api\": \"百炼大模型 (阿里云)\",\n \"openai_api\": \"OpenAI GPT模型\",\n \"google_api\": \"Google Gemini模型\",\n \"anthropic_api\": \"Anthropic Claude模型\",\n \"deepseek_api\": \"DeepSeek深度求索模型\",\n \"qianwen_api\": \"通义千问开源模型\",\n \"doubao_api\": \"火山引擎豆包模型\",\n \"zhipuai_api\": \"智谱AI GLM模型\",\n \"baichuan_api\": \"百川智能模型\",\n \"moonshot_api\": \"Moonshot AI Kimi模型\",\n \"minimax_api\": \"MiniMax海螺模型\",\n \"yi_api\": \"零一万物Yi模型\",\n \"stepfun_api\": \"阶跃星辰Step模型\",\n \"finnhub_api\": \"金融数据 (TradingAgent)\",\n \"serpapi_api\": \"Google Patents (PatentAgent)\",\n \"zhihuiya_client_id\": \"智慧芽客户端ID (PatentAgent)\",\n \"zhihuiya_client_secret\": \"智慧芽客户端密钥 (PatentAgent)\"\n }\n return descriptions.get(api_name, \"未知API\")\n \n def _get_api_help_link(self, api_name: str) -> str:\n \"\"\"获取API帮助链接\"\"\"\n help_links = {\n \"dashscope_api\": \"[link=https://help.aliyun.com/zh/dashscope/]阿里云百炼文档[/link]\",\n \"openai_api\": \"[link=https://platform.openai.com/api-keys]OpenAI API Keys[/link]\",\n \"google_api\": \"[link=https://ai.google.dev/gemini-api/docs/api-key]Google AI Studio[/link]\",\n \"anthropic_api\": \"[link=https://console.anthropic.com/]Anthropic Console[/link]\",\n \"deepseek_api\": \"[link=https://platform.deepseek.com/api_keys]DeepSeek API Keys[/link]\",\n \"qianwen_api\": \"[link=https://help.aliyun.com/zh/dashscope/]通义千问文档[/link]\",\n \"doubao_api\": \"[link=https://console.volcengine.com/ark]火山引擎方舟[/link]\",\n \"zhipuai_api\": \"[link=https://open.bigmodel.cn/usercenter/apikeys]智谱AI开放平台[/link]\",\n \"baichuan_api\": \"[link=https://platform.baichuan-ai.com/console/apikey]百川智能平台[/link]\",\n \"moonshot_api\": \"[link=https://platform.moonshot.cn/console/api-keys]Moonshot平台[/link]\",\n \"minimax_api\": \"[link=https://api.minimax.chat/user-center/basic-information/interface-key]MiniMax平台[/link]\",\n \"yi_api\": \"[link=https://platform.lingyiwanwu.com/apikeys]零一万物平台[/link]\",\n \"stepfun_api\": \"[link=https://platform.stepfun.com/interface-key]阶跃星辰平台[/link]\",\n \"finnhub_api\": \"[link=https://finnhub.io/dashboard]Finnhub Dashboard[/link]\",\n \"serpapi_api\": \"[link=https://serpapi.com/manage-api-key]SerpApi Dashboard[/link]\",\n \"zhihuiya_client_id\": \"[link=https://open-zhihuiya-com.libproxy1.nus.edu.sg/]智慧芽开放平台[/link]\",\n \"zhihuiya_client_secret\": \"[link=https://open-zhihuiya-com.libproxy1.nus.edu.sg/]智慧芽开放平台[/link]\"\n }\n return help_links.get(api_name, \"暂无帮助链接\")"}}, "shared/config/rich_agents_config_manager.py": {"5f84df5cd1daaa575829f5618982bb299bcfbb7d": {"t": 1785674632.481976, "n": 28004, "h": "a4d028c5e8e27c5c", "c": "\"\"\"\nRich-Agents 统一配置管理器\n支持TradingAgent和PatentAgent两种模式的配置管理\n\"\"\"\n\nimport os\nimport json\nfrom typing import Dict, Any, Optional, Union, List\nfrom pathlib import Path\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\nclass RichAgentsConfigManager:\n \"\"\"Rich-Agents统一配置管理器\"\"\"\n \n def __init__(self, config_dir: Optional[Union[str, Path]] = None):\n \"\"\"\n 初始化配置管理器\n \n Args:\n config_dir: 配置文件目录,默认为项目根目录下的config文件夹\n \"\"\"\n if config_dir is None:\n # 找到项目根目录\n current_dir = Path(__file__).resolve()\n while current_dir.parent != current_dir:\n if (current_dir / \"pyproject.toml\").exists() or (current_dir / \"setup.py\").exists():\n break\n current_dir = current_dir.parent\n self.config_dir = current_dir / \"config\"\n else:\n self.config_dir = Path(config_dir)\n \n self.config_dir.mkdir(exist_ok=True)\n \n # 配置文件路径\n self.main_config_file = self.config_dir / \"rich_agents_config.json\"\n self.trading_config_file = self.config_dir / \"trading_config.json\" \n self.patent_config_file = self.config_dir / \"patent_config.json\"\n \n # 加载配置\n self.main_config = self._load_config(self.main_config_file, self._get_default_main_config())\n self.trading_config = self._load_config(self.trading_config_file, self._get_default_trading_config())\n self.patent_config = self._load_config(self.patent_config_file, self._get_default_patent_config())\n \n logger.info(\"Rich-Agents配置管理器初始化完成\")\n \n def _load_config(self, config_file: Path, default_config: Dict[str, Any]) -> Dict[str, Any]:\n \"\"\"\n 加载配置文件\n \n Args:\n config_file: 配置文件路径\n default_config: 默认配置\n \n Returns:\n 配置字典\n \"\"\"\n try:\n if config_file.exists():\n with open(config_file, 'r', encoding='utf-8') as f:\n config = json.load(f)\n # 合并默认配置确保完整性\n merged_config = self._merge_configs(default_config, config)\n logger.info(f\"已加载配置文件: {config_file}\")\n return merged_config\n else:\n # 创建默认配置文件\n with open(config_file, 'w', encoding='utf-8') as f:\n json.dump(default_config, f, indent=2, ensure_ascii=False)\n logger.info(f\"已创建默认配置文件: {config_file}\")\n return default_config\n except Exception as e:\n logger.error(f\"加载配置文件失败 {config_file}: {str(e)}\")\n return default_config\n \n def _merge_configs(self, default: Dict[str, Any], user: Dict[str, Any]) -> Dict[str, Any]:\n \"\"\"\n 合并用户配置和默认配置\n \n Args:\n default: 默认配置\n user: 用户配置\n \n Returns:\n 合并后的配置\n \"\"\"\n merged = default.copy()\n \n def _deep_merge(target: Dict[str, Any], source: Dict[str, Any]):\n for key, value in source.items():\n if key in target and isinstance(target[key], dict) and isinstance(value, dict):\n _deep_merge(target[key], value)\n else:\n target[key] = value\n \n _deep_merge(merged, user)\n return merged\n \n def _get_default_main_config(self) -> Dict[str, Any]:\n \"\"\"获取主配置默认值\"\"\"\n return {\n \"version\": \"0.2.0\",\n \"name\": \"Rich-Agents\",\n \"description\": \"多智能体AI工具集\",\n \"default_agent\": \"trading\", # trading 或 patent\n \"llm_providers\": {\n \"dashscope\": {\n \"api_key_env\": \"DASHSCOPE_API_KEY\",\n \"models\": [\"qwen-turbo\", \"qwen-plus\", \"qwen-max\", \"qwen-max-longcontext\"],\n \"default_model\": \"qwen-turbo\",\n \"description\": \"阿里云百炼大模型\"\n },\n \"openai\": {\n \"api_key_env\": \"OPENAI_API_KEY\",\n \"models\": [\"gpt-4\", \"gpt-4-turbo\", \"gpt-3.5-turbo\", \"gpt-4o\", \"gpt-4o-mini\"],\n \"default_model\": \"gpt-4o-mini\",\n \"description\": \"OpenAI GPT模型\"\n },\n \"google\": {\n \"api_key_env\": \"GOOGLE_API_KEY\",\n \"models\": [\"gemini-pro\", \"gemini-pro-vision\", \"gemini-2.0-flash\", \"gemini-1.5-pro\"],\n \"default_model\": \"gemini-2.0-flash\",\n \"description\": \"Google Gemini模型\"\n },\n \"anthropic\": {\n \"api_key_env\": \"ANTHROPIC_API_KEY\",\n \"models\": [\"claude-3-sonnet\", \"claude-3-haiku\", \"claude-3-5-sonnet\", \"claude-3-opus\"],\n \"default_model\": \"claude-3-5-sonnet\",\n \"description\": \"Anthropic Claude模型\"\n },\n \"deepseek\": {\n \"api_key_env\": \"DEEPSEEK_API_KEY\",\n \"models\": [\"deepseek-chat\", \"deepseek-coder\", \"deepseek-reasoner\"],\n \"default_model\": \"deepseek-chat\",\n \"description\": \"DeepSeek深度求索模型\",\n \"base_url\": \"https://api.deepseek.com\"\n },\n \"qianwen\": {\n \"api_key_env\": \"QIANWEN_API_KEY\",\n \"models\": [\"qwen2.5-72b-instruct\", \"qwen2.5-32b-instruct\", \"qwen2.5-14b-instruct\", \"qwen2.5-7b-instruct\"],\n \"default_model\": \"qwen2.5-72b-instruct\",\n \"description\": \"通义千问开源模型\",\n \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n },\n \"doubao\": {\n \"api_key_env\": \"DOUBAO_API_KEY\",\n \"models\": [\"doubao-pro-32k\", \"doubao-pro-4k\", \"doubao-lite-32k\", \"doubao-lite-4k\"],\n \"default_model\": \"doubao-pro-32k\",\n \"description\": \"火山引擎豆包模型\",\n \"base_url\": \"https://ark.cn-beijing.volces.com/api/v3\"\n },\n \"zhipuai\": {\n \"api_key_env\": \"ZHIPUAI_API_KEY\",\n \"models\": [\"glm-4\", \"glm-4-plus\", \"glm-4-0520\", \"glm-4-air\", \"glm-4-airx\", \"glm-4-flash\"],\n \"default_model\": \"glm-4\",\n \"description\": \"智谱AI GLM模型\",\n \"base_url\": \"https://open.bigmodel.cn/api/paas/v4\"\n },\n \"baichuan\": {\n \"api_key_env\": \"BAICHUAN_API_KEY\",\n \"models\": [\"baichuan2-turbo\", \"baichuan2-turbo-192k\", \"baichuan3-turbo\", \"baichuan3-turbo-128k\"],\n \"default_model\": \"baichuan3-turbo\",\n \"description\": \"百川智能模型\",\n \"base_url\": \"https://api.baichuan-ai.com/v1\"\n },\n \"moonshot\": {\n \"api_key_env\": \"MOONSHOT_API_KEY\",\n \"models\": [\"moonshot-v1-8k\", \"moonshot-v1-32k\", \"moonshot-v1-128k\"],\n \"default_model\": \"moonshot-v1-8k\",\n \"description\": \"Moonshot AI Kimi模型\",\n \"base_url\": \"https://api.moonshot.cn/v1\"\n },\n \"minimax\": {\n \"api_key_env\": \"MINIMAX_API_KEY\",\n \"models\": [\"abab6.5s-chat\", \"abab6.5-chat\", \"abab5.5s-chat\", \"abab5.5-chat\"],\n \"default_model\": \"abab6.5s-chat\",\n \"description\": \"MiniMax海螺模型\",\n \"base_url\": \"https://api.minimax.chat/v1\"\n },\n \"yi\": {\n \"api_key_env\": \"YI_API_KEY\",\n \"models\": [\"yi-34b-chat-0205\", \"yi-34b-chat-200k\", \"yi-6b-chat\", \"yi-large\"],\n \"default_model\": \"yi-large\",\n \"description\": \"零一万物Yi模型\",\n \"base_url\": \"https://api.lingyiwanwu.com/v1\"\n },\n \"stepfun\": {\n \"api_key_env\": \"STEPFUN_API_KEY\",\n \"models\": [\"step-1v-8k\", \"step-1v-32k\", \"step-2-16k\"],\n \"default_model\": \"step-1v-8k\",\n \"description\": \"阶跃星辰Step模型\",\n \"base_url\": \"https://api.stepfun.com/v1\"\n }\n },\n \"cache\": {\n \"enabled\": True,\n \"type\": \"integrated\", # file, mongodb, redis, integrated\n \"file_cache_dir\": \"cache\",\n \"mongodb\": {\n \"enabled\": False,\n \"host\": \"localhost\",\n \"port\": 27017,\n \"database\": \"rich_agents\",\n \"username\": None,\n \"password\": None\n },\n \"redis\": {\n \"enabled\": False,\n \"host\": \"localhost\",\n \"port\": 6379,\n \"db\": 0,\n \"password\": None\n }\n },\n \"logging\": {\n \"level\": \"INFO\",\n \"format\": \"%(asctime)s - %(name)s - %(levelname)s - %(message)s\",\n \"file\": \"rich_agents.log\"\n }\n }\n \n def _get_default_trading_config(self) -> Dict[str, Any]:\n \"\"\"获取TradingAgent默认配置\"\"\"\n return {\n \"agent_type\": \"trading\",\n \"max_debate_rounds\": 2,\n \"max_risk_discuss_rounds\": 2,\n \"online_tools\": True,\n \"analysts\": [\"market\", \"social\", \"news\", \"fundamentals\"],\n \"research_depth\": 2,\n \"markets\": {\n \"us_stock\": {\n \"enabled\": True,\n \"data_source\": \"yahoo_finance\",\n \"api_keys\": {\n \"finnhub\": \"FINNHUB_API_KEY\"\n }\n },\n \"china_a_share\": {\n \"enabled\": True,\n \"data_source\": \"tongdaxin\",\n \"fallback\": [\"akshare\", \"tushare\"]\n }\n },\n \"risk_management\": {\n \"enabled\": True,\n \"max_position_size\": 0.1,\n \"stop_loss\": 0.05,\n \"take_profit\": 0.15\n }\n }\n \n def _get_default_patent_config(self) -> Dict[str, Any]:\n \"\"\"获取PatentAgent默认配置\"\"\"\n return {\n \"agent_type\": \"patent\",\n \"analysis_types\": [\"discovery\", \"validation\", \"analysis\", \"writing\"],\n \"default_analysis_type\": \"discovery\",\n \"api_keys\": {\n \"google_patents\": \"SERPAPI_API_KEY\",\n \"zhihuiya\": {\n \"client_id\": \"ZHIHUIYA_CLIENT_ID\",\n \"client_secret\": \"ZHIHUIYA_CLIENT_SECRET\"\n }\n },\n \"agents\": {\n \"technology_analyst\": {\"enabled\": True},\n \"innovation_discovery\": {\"enabled\": True},\n \"prior_art_researcher\": {\"enabled\": True},\n \"market_intelligence\": {\"enabled\": True},\n \"patent_writer\": {\"enabled\": True},\n \"quality_assessor\": {\"enabled\": True}\n },\n \"patent_databases\": {\n \"google_patents\": {\n \"enabled\": True,\n \"max_results\": 100,\n \"priority\": 1\n },\n \"zhihuiya\": {\n \"enabled\": True,\n \"max_results\": 50,\n \"priority\": 2\n },\n \"uspto\": {\n \"enabled\": False,\n \"max_results\": 50,\n \"priority\": 3\n },\n \"epo\": {\n \"enabled\": False,\n \"max_results\": 50,\n \"priority\": 4\n }\n }\n }\n \n def get_config(self, agent_type: Optional[str] = None) -> Dict[str, Any]:\n \"\"\"\n 获取指定智能体类型的完整配置\n \n Args:\n agent_type: 智能体类型 ('trading' 或 'patent'),默认使用配置中的默认类型\n \n Returns:\n 完整配置字典\n \"\"\"\n if agent_type is None:\n agent_type = self.main_config.get(\"default_agent\", \"trading\")\n \n if agent_type == \"trading\":\n return self.get_trading_config()\n elif agent_type == \"patent\":\n return self.get_patent_config()\n else:\n raise ValueError(f\"不支持的智能体类型: {agent_type}\")\n \n def get_trading_config(self) -> Dict[str, Any]:\n \"\"\"获取TradingAgent完整配置\"\"\"\n config = self.main_config.copy()\n config.update(self.trading_config)\n return config\n \n def get_patent_config(self) -> Dict[str, Any]:\n \"\"\"获取PatentAgent完整配置\"\"\"\n config = self.main_config.copy()\n config.update(self.patent_config)\n return config\n \n def get_llm_config(self, provider: str) -> Dict[str, Any]:\n \"\"\"\n 获取指定LLM提供商的配置\n \n Args:\n provider: LLM提供商名称\n \n Returns:\n LLM配置字典\n \"\"\"\n llm_providers = self.main_config.get(\"llm_providers\", {})\n if provider not in llm_providers:\n raise ValueError(f\"不支持的LLM提供商: {provider}\")\n \n return llm_providers[provider]\n \n def get_api_key(self, provider: str) -> Optional[str]:\n \"\"\"\n 获取指定提供商的API密钥\n \n Args:\n provider: 提供商名称\n \n Returns:\n API密钥或None\n \"\"\"\n try:\n if provider in self.main_config.get(\"llm_providers\", {}):\n env_var = self.main_config[\"llm_providers\"][provider][\"api_key_env\"]\n return os.getenv(env_var)\n elif provider == \"finnhub\":\n return os.getenv(\"FINNHUB_API_KEY\")\n elif provider == \"serpapi\":\n return os.getenv(\"SERPAPI_API_KEY\")\n elif provider == \"zhihuiya_client_id\":\n return os.getenv(\"ZHIHUIYA_CLIENT_ID\")\n elif provider == \"zhihuiya_client_secret\":\n return os.getenv(\"ZHIHUIYA_CLIENT_SECRET\")\n else:\n return None\n except Exception as e:\n logger.error(f\"获取API密钥失败 {provider}: {str(e)}\")\n return None\n \n def check_api_keys(self, agent_type: Optional[str] = None) -> Dict[str, bool]:\n \"\"\"\n 检查API密钥配置状态\n \n Args:\n agent_type: 智能体类型\n \n Returns:\n API密钥状态字典\n \"\"\"\n status = {}\n \n # 检查LLM提供商API密钥\n for provider in self.main_config.get(\"llm_providers\", {}):\n api_key = self.get_api_key(provider)\n status[f\"{provider}_api\"] = api_key is not None and len(api_key.strip()) > 0\n \n # 根据智能体类型检查特定API密钥\n if agent_type is None:\n agent_type = self.main_config.get(\"default_agent\", \"trading\")\n \n if agent_type == \"trading\":\n status[\"finnhub_api\"] = self.get_api_key(\"finnhub\") is not None\n elif agent_type == \"patent\":\n status[\"serpapi_api\"] = self.get_api_key(\"serpapi\") is not None\n status[\"zhihuiya_client_id\"] = self.get_api_key(\"zhihuiya_client_id\") is not None\n status[\"zhihuiya_client_secret\"] = self.get_api_key(\"zhihuiya_client_secret\") is not None\n \n return status\n \n def update_config(self, agent_type: str, config_updates: Dict[str, Any]) -> bool:\n \"\"\"\n 更新配置\n \n Args:\n agent_type: 智能体类型\n config_updates: 配置更新\n \n Returns:\n 更新是否成功\n \"\"\"\n try:\n if agent_type == \"main\":\n self.main_config.update(config_updates)\n self._save_config(self.main_config_file, self.main_config)\n elif agent_type == \"trading\":\n self.trading_config.update(config_updates)\n self._save_config(self.trading_config_file, self.trading_config)\n elif agent_type == \"patent\":\n self.patent_config.update(config_updates)\n self._save_config(self.patent_config_file, self.patent_config)\n else:\n raise ValueError(f\"不支持的配置类型: {agent_type}\")\n \n logger.info(f\"配置更新成功: {agent_type}\")\n return True\n except Exception as e:\n logger.error(f\"配置更新失败 {agent_type}: {str(e)}\")\n return False\n \n def _save_config(self, config_file: Path, config: Dict[str, Any]) -> None:\n \"\"\"保存配置到文件\"\"\"\n with open(config_file, 'w', encoding='utf-8') as f:\n json.dump(config, f, indent=2, ensure_ascii=False)\n \n def get_available_llm_providers(self) -> List[str]:\n \"\"\"获取可用的LLM提供商列表\"\"\"\n return list(self.main_config.get(\"llm_providers\", {}).keys())\n \n def get_available_models(self, provider: str) -> List[str]:\n \"\"\"\n 获取指定提供商的可用模型列表\n \n Args:\n provider: LLM提供商名称\n \n Returns:\n 模型列表\n \"\"\"\n llm_config = self.get_llm_config(provider)\n return llm_config.get(\"models\", [])\n \n def get_default_model(self, provider: str) -> str:\n \"\"\"\n 获取指定提供商的默认模型\n \n Args:\n provider: LLM提供商名称\n \n Returns:\n 默认模型名称\n \"\"\"\n llm_config = self.get_llm_config(provider)\n return llm_config.get(\"default_model\", llm_config.get(\"models\", [\"\"])[0])\n \n def validate_config(self, agent_type: Optional[str] = None) -> Dict[str, Any]:\n \"\"\"\n 验证配置完整性\n \n Args:\n agent_type: 智能体类型\n \n Returns:\n 验证结果\n \"\"\"\n result = {\n \"valid\": True,\n \"errors\": [],\n \"warnings\": [],\n \"api_keys\": self.check_api_keys(agent_type)\n }\n \n # 检查必需的API密钥\n api_status = result[\"api_keys\"]\n missing_keys = [key for key, status in api_status.items() if not status]\n \n if missing_keys:\n result[\"warnings\"].extend([f\"缺少API密钥: {key}\" for key in missing_keys])\n \n # 检查LLM提供商配置\n available_providers = self.get_available_llm_providers()\n if not available_providers:\n result[\"valid\"] = False\n result[\"errors\"].append(\"没有配置任何LLM提供商\")\n \n # 检查至少有一个LLM提供商的API密钥可用\n llm_keys_available = any(api_status.get(f\"{provider}_api\", False) for provider in available_providers)\n if not llm_keys_available:\n result[\"valid\"] = False\n result[\"errors\"].append(\"没有可用的LLM API密钥\")\n \n return result\n \n def get_system_status(self) -> Dict[str, Any]:\n \"\"\"\n 获取系统状态\n \n Returns:\n 系统状态信息\n \"\"\"\n return {\n \"config_loaded\": True,\n \"config_files\": {\n \"main_config\": str(self.main_config_file),\n \"trading_config\": str(self.trading_config_file),\n \"patent_config\": str(self.patent_config_file)\n },\n \"available_agents\": [\"trading\", \"patent\"],\n \"available_llm_providers\": self.get_available_llm_providers(),\n \"api_keys_status\": self.check_api_keys(),\n \"cache_config\": self.main_config.get(\"cache\", {}),\n \"version\": self.main_config.get(\"version\", \"unknown\")\n }\n \n def set_api_key(self, env_var: str, api_key: str) -> bool:\n \"\"\"\n 设置API密钥\n \n Args:\n env_var: 环境变量名\n api_key: API密钥值\n \n Returns:\n 设置是否成功\n \"\"\"\n try:\n # 设置环境变量\n os.environ[env_var] = api_key\n \n # 可以选择保存到配置文件或.env文件\n # 这里我们只设置环境变量,不持久化到文件(安全考虑)\n logger.info(f\"API密钥已设置: {env_var}\")\n return True\n \n except Exception as e:\n logger.error(f\"设置API密钥失败 {env_var}: {str(e)}\")\n return False\n \n def delete_api_key(self, env_var: str) -> bool:\n \"\"\"\n 删除API密钥\n \n Args:\n env_var: 环境变量名\n \n Returns:\n 删除是否成功\n \"\"\"\n try:\n # 从环境变量中删除\n if env_var in os.environ:\n del os.environ[env_var]\n \n logger.info(f\"API密钥已删除: {env_var}\")\n return True\n \n except Exception as e:\n logger.error(f\"删除API密钥失败 {env_var}: {str(e)}\")\n return False\n \n def test_api_key(self, env_var: str) -> Dict[str, Any]:\n \"\"\"\n 测试API密钥\n \n Args:\n env_var: 环境变量名\n \n Returns:\n 测试结果\n \"\"\"\n try:\n api_key = os.getenv(env_var)\n if not api_key:\n return {\n \"success\": False,\n \"error\": \"API密钥未设置\"\n }\n \n # 基本格式验证\n if len(api_key.strip()) < 5:\n return {\n \"success\": False,\n \"error\": \"API密钥格式不正确\"\n }\n \n # 这里可以添加实际的API测试调用\n # 由于不同API的测试方式不同,这里只做基本验证\n \n return {\n \"success\": True,\n \"details\": f\"API密钥格式正确,长度: {len(api_key)}\"\n }\n \n except Exception as e:\n return {\n \"success\": False,\n \"error\": str(e)\n }\n \n def get_cache_config(self) -> Dict[str, Any]:\n \"\"\"\n 获取缓存配置\n \n Returns:\n 缓存配置字典\n \"\"\"\n return self.main_config.get(\"cache\", {})\n \n def export_config(self, export_path: Optional[Union[str, Path]] = None) -> str:\n \"\"\"\n 导出配置到文件\n \n Args:\n export_path: 导出文件路径,默认为config目录下的exported_config.json\n \n Returns:\n 导出文件路径\n \"\"\"\n try:\n if export_path is None:\n export_path = self.config_dir / \"exported_config.json\"\n else:\n export_path = Path(export_path)\n \n # 准备导出的配置(不包含敏感信息)\n export_config = {\n \"main_config\": self._sanitize_config(self.main_config),\n \"trading_config\": self._sanitize_config(self.trading_config),\n \"patent_config\": self._sanitize_config(self.patent_config),\n \"export_timestamp\": self._get_timestamp(),\n \"version\": self.main_config.get(\"version\", \"unknown\")\n }\n \n # 保存到文件\n with open(export_path, 'w', encoding='utf-8') as f:\n json.dump(export_config, f, indent=2, ensure_ascii=False)\n \n logger.info(f\"配置已导出到: {export_path}\")\n return str(export_path)\n \n except Exception as e:\n logger.error(f\"配置导出失败: {str(e)}\")\n raise\n \n def _sanitize_config(self, config: Dict[str, Any]) -> Dict[str, Any]:\n \"\"\"\n 清理配置中的敏感信息\n \n Args:\n config: 原始配置\n \n Returns:\n 清理后的配置\n \"\"\"\n sanitized = config.copy()\n \n # 移除敏感字段\n sensitive_keys = [\"password\", \"secret\", \"key\", \"token\"]\n \n def _remove_sensitive(obj):\n if isinstance(obj, dict):\n return {\n k: _remove_sensitive(v) if not any(sensitive in k.lower() for sensitive in sensitive_keys) \n else \"***HIDDEN***\"\n for k, v in obj.items()\n }\n elif isinstance(obj, list):\n return [_remove_sensitive(item) for item in obj]\n else:\n return obj\n \n return _remove_sensitive(sanitized)\n \n def _get_timestamp(self) -> str:\n \"\"\"获取当前时间戳\"\"\"\n from datetime import datetime\n return datetime.now().isoformat()\n \n def reload_config(self) -> bool:\n \"\"\"\n 重新加载所有配置文件\n \n Returns:\n 重新加载是否成功\n \"\"\"\n try:\n self.main_config = self._load_config(self.main_config_file, self._get_default_main_config())\n self.trading_config = self._load_config(self.trading_config_file, self._get_default_trading_config())\n self.patent_config = self._load_config(self.patent_config_file, self._get_default_patent_config())\n \n logger.info(\"配置重新加载成功\")\n return True\n \n except Exception as e:\n logger.error(f\"配置重新加载失败: {str(e)}\")\n return False\n \n def reset_config(self, config_type: str) -> bool:\n \"\"\"\n 重置配置为默认值\n \n Args:\n config_type: 配置类型 ('main', 'trading', 'patent')\n \n Returns:\n 重置是否成功\n \"\"\"\n try:\n if config_type == \"main\":\n self.main_config = self._get_default_main_config()\n self._save_config(self.main_config_file, self.main_config)\n elif config_type == \"trading\":\n self.trading_config = self._get_default_trading_config()\n self._save_config(self.trading_config_file, self.trading_config)\n elif config_type == \"patent\":\n self.patent_config = self._get_default_patent_config()\n self._save_config(self.patent_config_file, self.patent_config)\n else:\n raise ValueError(f\"不支持的配置类型: {config_type}\")\n \n logger.info(f\"配置已重置为默认值: {config_type}\")\n return True\n \n except Exception as e:\n logger.error(f\"配置重置失败 {config_type}: {str(e)}\")\n return False\n \n def get_config_summary(self) -> Dict[str, Any]:\n \"\"\"\n 获取配置摘要\n \n Returns:\n 配置摘要信息\n \"\"\"\n return {\n \"total_configs\": 3,\n \"config_files\": {\n \"main\": self.main_config_file.exists(),\n \"trading\": self.trading_config_file.exists(),\n \"patent\": self.patent_config_file.exists()\n },\n \"llm_providers_count\": len(self.get_available_llm_providers()),\n \"api_keys_configured\": sum(1 for status in self.check_api_keys().values() if status),\n \"cache_enabled\": self.main_config.get(\"cache\", {}).get(\"enabled\", False),\n \"version\": self.main_config.get(\"version\", \"unknown\")\n } \n\n def _validate_api_key_format(self, env_var: str, key: str) -> bool:\n \"\"\"验证API密钥格式\"\"\"\n validation_rules = {\n \"DASHSCOPE_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 20,\n \"OPENAI_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 20,\n \"GOOGLE_API_KEY\": lambda k: k.startswith(\"AIza\") and len(k) > 30,\n \"ANTHROPIC_API_KEY\": lambda k: k.startswith(\"sk-ant-\") and len(k) > 30,\n \"DEEPSEEK_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 20,\n \"QIANWEN_API_KEY\": lambda k: len(k) > 10, # 通义千问API密钥格式可能不同\n \"DOUBAO_API_KEY\": lambda k: len(k) > 20, # 火山引擎豆包API密钥\n \"ZHIPUAI_API_KEY\": lambda k: len(k) > 30, # 智谱AI API密钥通常较长\n \"BAICHUAN_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 20,\n \"MOONSHOT_API_KEY\": lambda k: k.startswith(\"sk-\") and len(k) > 30,\n \"MINIMAX_API_KEY\": lambda k: len(k) > 20, # MiniMax API密钥\n \"YI_API_KEY\": lambda k: len(k) > 20, # 零一万物API密钥\n \"STEPFUN_API_KEY\": lambda k: len(k) > 20, # 阶跃星辰API密钥\n \"FINNHUB_API_KEY\": lambda k: len(k) > 10,\n \"SERPAPI_API_KEY\": lambda k: len(k) > 10,\n \"ZHIHUIYA_CLIENT_ID\": lambda k: len(k) > 5,\n \"ZHIHUIYA_CLIENT_SECRET\": lambda k: len(k) > 10\n }\n \n validator = validation_rules.get(env_var)\n if validator:\n return validator(key)\n return len(key) > 5 # 默认最小长度验证 "}}}}