diff --git a/.env.example b/.env.example index 5529c41..bfeeb47 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,8 @@ DEEPSEEK_API_KEY=your_actual_deepseek_api_key_here # DeepSeek API基础URL(可选,使用默认值即可) DEEPSEEK_BASE_URL=https://api.deepseek.com/v1 +# DeepSeek 模型名称,为空时取默认值 deepseek-chat +DEEPSEEK_MODEL_NAME=deepseek-chat # ========== Tushare数据接口(可选)========== # Tushare Token(可选,用于获取更多金融数据) diff --git a/.gitignore b/.gitignore index 1dfa6a0..98fb92c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,22 @@ .env /.cursor /openspec -TradEnv/ \ No newline at end of file +TradEnv/ +/.idea/inspectionProfiles/profiles_settings.xml +/.idea/inspectionProfiles/Project_Default.xml +/.idea/.gitignore +/.idea/aiagents-stock.iml +/.idea/misc.xml +/.idea/modules.xml +/.idea/vcs.xml +/data/longhubang.db +/data/low_price_bull_monitor.db +/data/main_force_batch.db +/data/portfolio_stocks.db +/data/profit_growth_monitor.db +/data/sector_strategy.db +/data/smart_monitor.db +/data/stock_analysis.db +/data/stock_monitor.db +/migrate_databases.sh +/migrate_databases_by_size.sh diff --git "a/AI\346\250\241\345\236\213\351\200\211\346\213\251\350\257\264\346\230\216.md" "b/AI\346\250\241\345\236\213\351\200\211\346\213\251\350\257\264\346\230\216.md" new file mode 100644 index 0000000..ccd0e32 --- /dev/null +++ "b/AI\346\250\241\345\236\213\351\200\211\346\213\251\350\257\264\346\230\216.md" @@ -0,0 +1,258 @@ +# AI模型选择机制说明 + +## 📋 问题回答 + +### 1. 左侧的AI模型选择会全局默认生效吗? + +**答案:部分生效,但不完全全局** + +**当前状态**: +- ✅ 模型选择器会保存到 `st.session_state.selected_model` +- ❌ 但很多功能模块**强制使用** `config.DEEPSEEK_MODEL_NAME`(从 `.env` 文件读取),**忽略**了 `session_state` 中的选择 +- ✅ 只有部分页面(如"主力选股")会使用页面内的模型选择 + +**具体表现**: +- **股票分析页面**:强制使用 `config.DEEPSEEK_MODEL_NAME`,忽略侧边栏选择 +- **批量分析功能**:强制使用 `config.DEEPSEEK_MODEL_NAME`,忽略侧边栏选择 +- **主力选股页面**:使用页面内的模型选择(不是侧边栏的) +- **智策板块页面**:强制使用 `config.DEEPSEEK_MODEL_NAME` + +### 2. 如果选择其他模型,模型信息在哪里配置? + +**答案:两个地方** + +#### 位置1:模型选项列表 - `model_config.py` + +**文件路径**:`model_config.py` + +**作用**:定义所有可用的AI模型选项 + +**内容示例**: +```python +model_options = { + "deepseek-chat": "DeepSeek Chat (默认)", + "deepseek-reasoner": "DeepSeek Reasoner (推理增强)", + "qwen-plus": "qwen-plus (阿里百炼)", + # ... 更多模型 +} +``` + +**如何添加新模型**: +1. 在 `model_config.py` 的 `model_options` 字典中添加新项 +2. 格式:`"模型ID": "显示名称"` + +#### 位置2:默认模型配置 - `.env` 文件 + +**文件路径**:`.env`(项目根目录) + +**作用**:设置系统默认使用的模型 + +**配置项**: +```bash +DEEPSEEK_MODEL_NAME=deepseek-chat +``` + +**如何修改默认模型**: +1. 编辑 `.env` 文件 +2. 修改 `DEEPSEEK_MODEL_NAME` 的值 +3. 值必须是 `model_config.py` 中 `model_options` 的键之一 + +--- + +## 🔍 代码实现分析 + +### 模型选择器(侧边栏) + +**位置**:`app.py` 的 `model_selector()` 函数 + +**代码**: +```python +def model_selector(): + """模型选择器""" + st.sidebar.subheader("🤖 AI模型选择") + + # 获取配置文件中的默认模型 + default_model = config.DEEPSEEK_MODEL_NAME + + # 从 session_state 获取当前选择 + current_model = st.session_state.get('selected_model', default_model) + + # 显示选择框 + selected_model = st.sidebar.selectbox( + "选择AI模型", + options=list(model_options.keys()), + ... + ) + + return selected_model +``` + +**问题**:虽然保存到 `session_state`,但很多地方不使用它 + +### 实际使用情况 + +#### ❌ 不生效的地方(强制使用配置文件) + +**1. 股票分析页面** (`app.py` 的 `run_stock_analysis`) +```python +# 强制使用配置文件中的默认模型(忽略 session_state 中的旧值) +config_model = config.DEEPSEEK_MODEL_NAME +if config_model in model_options: + selected_model = config_model +else: + selected_model = list(model_options.keys())[0] + +agents = StockAnalysisAgents(model=selected_model) # 使用配置文件的值 +``` + +**2. 批量分析功能** (`app.py` 的 `run_batch_analysis`) +```python +# 强制使用配置文件中的默认模型 +config_model = config.DEEPSEEK_MODEL_NAME +if config_model in model_options: + selected_model = config_model +else: + selected_model = list(model_options.keys())[0] +``` + +**3. 批量分析中的单个股票分析** (`app.py` 的 `analyze_single_stock_for_batch`) +```python +# 强制使用配置文件中的默认模型(忽略传入的旧值) +config_model = config.DEEPSEEK_MODEL_NAME +if selected_model is None or selected_model == "" or selected_model == "deepseek-chat": + selected_model = config_model +``` + +#### ✅ 生效的地方 + +**1. 主力选股页面** (`main_force_ui.py`) +```python +# 页面内有自己的模型选择 +model = st.selectbox( + "选择AI模型", + list(app_model_options.keys()), + ... +) + +analyzer = MainForceAnalyzer(model=model) # 使用页面选择的值 +``` + +--- + +## 🔧 如何让侧边栏选择全局生效? + +### 方案1:修改代码使用 session_state(推荐) + +修改所有强制使用 `config.DEEPSEEK_MODEL_NAME` 的地方,改为优先使用 `session_state.selected_model`: + +```python +# 修改前 +config_model = config.DEEPSEEK_MODEL_NAME +selected_model = config_model + +# 修改后 +selected_model = st.session_state.get('selected_model', config.DEEPSEEK_MODEL_NAME) +if selected_model not in model_options: + selected_model = config.DEEPSEEK_MODEL_NAME +``` + +**需要修改的文件**: +1. `app.py` - `run_stock_analysis()` 函数 +2. `app.py` - `run_batch_analysis()` 函数 +3. `app.py` - `analyze_single_stock_for_batch()` 函数 + +### 方案2:保持现状,使用配置文件 + +**优点**: +- 配置持久化(重启后仍然有效) +- 不依赖 Streamlit session + +**缺点**: +- 需要修改 `.env` 文件才能改变模型 +- 不能通过UI快速切换 + +--- + +## 📝 模型配置详细说明 + +### model_config.py 结构 + +```python +model_options = { + # 键:模型ID(用于API调用) + # 值:显示名称(在UI中显示) + "deepseek-chat": "DeepSeek Chat (默认)", + "deepseek-reasoner": "DeepSeek Reasoner (推理增强)", + # ... +} +``` + +### 添加新模型的步骤 + +1. **确定模型ID**:从API文档获取模型标识符 +2. **添加到 model_config.py**: + ```python + model_options = { + # ... 现有模型 + "new-model-id": "新模型显示名称", + } + ``` +3. **(可选)设置为默认**:在 `.env` 文件中设置 + ```bash + DEEPSEEK_MODEL_NAME=new-model-id + ``` + +### 当前可用的模型 + +根据 `model_config.py`,当前支持以下模型: + +| 模型ID | 显示名称 | 说明 | +|--------|----------|------| +| `deepseek-chat` | DeepSeek Chat (默认) | 默认模型 | +| `deepseek-reasoner` | DeepSeek Reasoner (推理增强) | 推理能力更强 | +| `qwen-plus` | qwen-plus (阿里百炼) | 阿里云模型 | +| `qwen-plus-latest` | qwen-plus-latest (阿里百炼) | 最新版本 | +| `qwen-flash` | qwen-flash (阿里百炼) | 快速版本 | +| `qwen-turbo` | qwen-turbo (阿里百炼) | 加速版本 | +| `qwen3-max` | qwen-max (阿里百炼) | 最大版本 | +| `qwen-long` | qwen-long (阿里百炼) | 长文本版本 | +| `deepseek-ai/DeepSeek-R1-0528-Qwen3-8B` | DeepSeek-R1 免费(硅基流动) | 免费模型 | +| `Qwen/Qwen2.5-7B-Instruct` | Qwen 免费(硅基流动) | 免费模型 | +| `Pro/deepseek-ai/DeepSeek-V3.1-Terminus` | DeepSeek-V3.1-Terminus (硅基流动) | 专业版 | +| `deepseek-ai/DeepSeek-R1` | DeepSeek-R1 (硅基流动) | R1版本 | +| `Qwen/Qwen3-235B-A22B-Thinking-2507` | Qwen3-235B (硅基流动) | 大模型 | +| `zai-org/GLM-4.6` | 智谱(硅基流动) | 智谱模型 | +| `moonshotai/Kimi-K2-Instruct-0905` | Kimi (硅基流动) | Kimi模型 | +| `Ring-1T` | 蚂蚁百灵 (硅基流动) | 蚂蚁模型 | +| `step3` | 阶跃星辰(硅基流动) | 阶跃模型 | + +--- + +## 🎯 建议 + +### 短期方案(保持现状) + +1. **修改默认模型**:编辑 `.env` 文件,修改 `DEEPSEEK_MODEL_NAME` +2. **主力选股页面**:使用页面内的模型选择(已生效) + +### 长期方案(推荐) + +修改代码,让侧边栏的模型选择真正全局生效: + +1. 修改 `app.py` 中所有使用模型的地方 +2. 优先使用 `st.session_state.selected_model` +3. 如果不存在或无效,回退到 `config.DEEPSEEK_MODEL_NAME` + +这样可以: +- ✅ 通过UI快速切换模型 +- ✅ 配置持久化(通过 `.env`) +- ✅ 用户体验更好 + +--- + +## 📚 相关文件 + +- **模型选项定义**:`model_config.py` +- **默认模型配置**:`.env` 文件中的 `DEEPSEEK_MODEL_NAME` +- **模型选择器**:`app.py` 的 `model_selector()` 函数 +- **配置文件加载**:`config.py` diff --git a/README.md b/README.md index 756dc13..f75cbc6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # 🤖 复合多AI智能体股票团队分析系统 -- 初心:在股市摸爬滚打多年,自学自编各种指标,花冤柉钱学习了各种战法各种策略,也曾入各种小班,总是赚少赔多,逐渐失去在股市玩的信心。自从去年deepseek上市,一直探索用ai辅助分析,且近日受tradingagents项目启发(感谢原作),多agent结合跟踪主力资金战法(某指每年收费6000rmb),用各种ai辅助编程,拼凑了这么个小程序,根据软件提供的辅助信息,实盘测试盈率还是挺高的,并且逐步形成了自己的交易系统,近一个月来,账户也慢慢在扰亏为盈。开源此软件的目的,就是为了使像我一样的小散,不再迷范。也许这个软件不能让你发大财,但是他能给你足够的信心。最后提醒:股市有风险,入市需谨慎! +- 初心:在股市摸爬滚打多年,自学自编各种指标,花冤柉钱学习了各种战法各种策略,也曾入各种小班,总是赚少赔多,逐渐失去在股市玩的信心。自从去年deepseek上市,一直探索用ai辅助分析,且近日受tradingagents项目启发(感谢原作),多agent结合跟踪主力资金战法(某指每年收费6000rmb),用各种ai辅助编程,拼凑了这么个小程序,根据软件提供的辅助信息,实盘测试盈率还是挺高的,并且逐步形成了自己的交易系统,近一个月来,账户也慢慢在扰亏为盈。开源此软件的目的,就是为了使像我一样的小散,不再迷范。也许这个软件不能让你发大财,但是他能给你足够的信心。最后提醒:股市有风险,入市需谨慎!欢迎加入qq群聊,群号:1059277514 +QQ_1766893237734 + +**点击zread图标,查看详细文档** +[![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/oficcejo/aiagents-stock) ## ⭐ 1214更新 - 净利增长策略 📈 diff --git a/ai_agents.py b/ai_agents.py index 75ea06e..c6efe57 100644 --- a/ai_agents.py +++ b/ai_agents.py @@ -1,13 +1,30 @@ from deepseek_client import DeepSeekClient from typing import Dict, Any import time +import config class StockAnalysisAgents: """股票分析AI智能体集合""" - def __init__(self, model="deepseek-chat"): - self.model = model - self.deepseek_client = DeepSeekClient(model=model) + def __init__(self, model=None): + # 调试:打印传入的参数和配置 + print(f"[StockAnalysisAgents.__init__] 传入参数: model={model}") + print(f"[StockAnalysisAgents.__init__] 配置文件中的 DEEPSEEK_MODEL_NAME: {config.DEEPSEEK_MODEL_NAME}") + + # 强制使用配置文件中的默认模型 + # 如果传入的是 None、空字符串或旧的默认值 "deepseek-chat",都使用配置文件的值 + if model is None or model == "" or model == "deepseek-chat": + self.model = config.DEEPSEEK_MODEL_NAME + if model == "deepseek-chat": + print(f"[StockAnalysisAgents.__init__] ⚠️ 检测到传入的模型是旧的默认值 'deepseek-chat',强制使用配置文件中的模型: {self.model}") + else: + print(f"[StockAnalysisAgents.__init__] 使用配置文件中的默认模型: {self.model}") + else: + self.model = model + print(f"[StockAnalysisAgents.__init__] 使用传入的模型参数: {self.model}") + + print(f"[StockAnalysisAgents.__init__] ✅ 最终使用的模型: {self.model}") + self.deepseek_client = DeepSeekClient(model=self.model) def technical_analyst_agent(self, stock_info: Dict, stock_data: Any, indicators: Dict) -> Dict[str, Any]: """技术面分析智能体""" diff --git a/app.py b/app.py index f030097..609fec7 100644 --- a/app.py +++ b/app.py @@ -18,6 +18,7 @@ from monitor_service import monitor_service from notification_service import notification_service from config_manager import config_manager +import config from main_force_ui import display_main_force_selector from sector_strategy_ui import display_sector_strategy from longhubang_ui import display_longhubang @@ -37,17 +38,52 @@ def model_selector(): st.sidebar.markdown("---") st.sidebar.subheader("🤖 AI模型选择") - + # 获取配置文件中的默认模型 + default_model = config.DEEPSEEK_MODEL_NAME + + # 如果配置的模型不在选项中,使用列表第一个 + if default_model not in model_options: + default_model = list(model_options.keys())[0] + + # 如果 session_state 中已有值,且该值在选项中,使用它;否则使用配置的默认值 + current_model = st.session_state.get('selected_model', default_model) + if current_model not in model_options: + current_model = default_model selected_model = st.sidebar.selectbox( "选择AI模型", options=list(model_options.keys()), + index=list(model_options.keys()).index(current_model) if current_model in model_options else 0, format_func=lambda x: model_options[x], help="DeepSeek Reasoner提供更强的推理能力,但响应时间可能更长" ) return selected_model + +def get_selected_model(): + """ + 获取当前选择的AI模型 + 优先使用session_state中的选择,如果不存在或无效,则使用配置文件中的默认值 + + Returns: + str: 模型ID + """ + # 优先使用session_state中的选择 + selected_model = st.session_state.get('selected_model') + + # 如果session_state中有值且在有效选项中,使用它 + if selected_model and selected_model in model_options: + return selected_model + + # 否则使用配置文件中的默认值 + default_model = config.DEEPSEEK_MODEL_NAME + if default_model in model_options: + return default_model + + # 如果配置文件的值也不在选项中,使用第一个选项 + return list(model_options.keys())[0] + # 自定义CSS样式 - 专业版 st.markdown("""