""" 智能Agent - 真正使用LLM进行全面分析 """ import re import json from typing import Dict, Any, Optional, List from app.config import get_settings from app.agent.context import ContextManager from app.agent.skill_manager import skill_manager from app.skills.market_data import MarketDataSkill from app.skills.technical_analysis import TechnicalAnalysisSkill from app.skills.fundamental import FundamentalSkill from app.skills.visualization import VisualizationSkill from app.skills.brave_search import BraveSearchSkill from app.services.llm_service import llm_service from app.services.tushare_service import tushare_service from app.utils.logger import logger class SmartStockAgent: """智能股票分析Agent - 深度集成LLM""" def __init__(self): """初始化Agent""" self.context_manager = ContextManager() self.settings = get_settings() # 注册技能 self._register_skills() # 检查LLM是否可用 self.use_llm = bool(self.settings.zhipuai_api_key) and llm_service.client is not None if self.use_llm: logger.info("Smart Agent初始化完成(LLM深度集成模式 + Brave搜索)") else: logger.warning("Smart Agent初始化完成(规则模式,建议配置LLM)") def _register_skills(self): """注册所有技能""" skill_manager.register(MarketDataSkill()) skill_manager.register(TechnicalAnalysisSkill()) skill_manager.register(FundamentalSkill()) skill_manager.register(VisualizationSkill()) skill_manager.register(BraveSearchSkill()) logger.info("技能注册完成(包含Brave搜索)") async def process_message( self, message: str, session_id: str, user_id: Optional[str] = None ) -> Dict[str, Any]: """ 处理用户消息(智能版) Args: message: 用户消息 session_id: 会话ID user_id: 用户ID Returns: 响应结果 """ logger.info(f"处理消息: {message[:50]}...") # 保存用户消息 self.context_manager.add_message(session_id, "user", message) # 第一步:使用LLM理解问题意图 intent_analysis = await self._analyze_question_intent(message) if not intent_analysis: response = { "message": "抱歉,我无法理解您的问题。请重新描述您的需求。", "metadata": {"type": "error"} } self.context_manager.add_message(session_id, "assistant", response["message"]) return response # 第二步:根据意图类型处理 question_type = intent_analysis['type'] if question_type == 'stock_specific': # 针对特定股票的问题 response = await self._handle_stock_question(intent_analysis, message) elif question_type == 'macro_finance': # 宏观金融问题 response = await self._handle_macro_question(intent_analysis, message) elif question_type == 'knowledge': # 金融知识问答 response = await self._handle_knowledge_question(intent_analysis, message) else: response = { "message": "抱歉,我暂时无法处理这类问题。", "metadata": {"type": "error"} } # 保存助手响应 self.context_manager.add_message( session_id, "assistant", response["message"], metadata=response.get("metadata") ) return response def _is_comprehensive_analysis(self, message: str) -> bool: """ 判断是否需要全面分析 默认情况下,如果用户只是简单提到股票名称或代码,就进行全面分析 只有明确要求特定信息时(如"技术指标"、"K线图"等),才做单一查询 """ # 明确要求单一查询的关键词 single_query_keywords = [ "k线", "图表", "走势图", "kline", "技术指标", "macd", "rsi", "均线", "kdj", "基本面", "公司信息", "行业", "实时行情", "价格", "涨跌" ] # 如果明确要求单一查询,返回False if any(keyword in message.lower() for keyword in single_query_keywords): return False # 默认进行全面分析 return True async def _comprehensive_analysis( self, stock_code: str, stock_name: Optional[str], message: str ) -> Dict[str, Any]: """ 全面分析:整合多个数据源 + LLM深度分析 Args: stock_code: 股票代码 stock_name: 股票名称 message: 用户消息 Returns: 综合分析结果 """ logger.info(f"执行全面分析: {stock_code}") display_name = stock_name or stock_code # 1. 并行获取所有数据 try: # 获取实时行情 quote_result = await skill_manager.execute_skill( "market_data", stock_code=stock_code, data_type="quote" ) # 获取技术指标 technical_result = await skill_manager.execute_skill( "technical_analysis", stock_code=stock_code, indicators=["ma", "macd", "rsi", "kdj"] ) # 获取基本面 fundamental_result = await skill_manager.execute_skill( "fundamental", stock_code=stock_code ) # 获取最新新闻(Brave搜索) search_query = f"{display_name} {stock_code} 股票 最新消息" news_result = await skill_manager.execute_skill( "brave_search", query=search_query, search_type="news", count=5, freshness="pw" # 过去一周 ) # 整合数据 all_data = { "stock_code": stock_code, "stock_name": display_name, "quote": quote_result.get("data") if quote_result.get("success") else None, "technical": technical_result.get("data") if technical_result.get("success") else None, "fundamental": fundamental_result.get("data") if fundamental_result.get("success") else None, "news": news_result.get("results") if news_result and not news_result.get("error") else None } # 2. 使用LLM进行深度分析 if self.use_llm: analysis = await self._llm_comprehensive_analysis(all_data, message) else: analysis = self._rule_based_analysis(all_data) return { "message": analysis, "metadata": { "type": "comprehensive", "data": all_data } } except Exception as e: logger.error(f"全面分析失败: {e}") return { "message": f"分析{display_name}时出错:{str(e)}", "metadata": {"type": "error"} } async def _llm_comprehensive_analysis( self, data: Dict[str, Any], user_message: str ) -> str: """使用LLM进行深度综合分析""" # 获取当前时间 from datetime import datetime current_time = datetime.now().strftime("%Y-%m-%d %H:%M") # 获取行情数据的交易日期 quote_date = "未知" if data.get('quote') and data['quote'].get('trade_date'): quote_date = data['quote']['trade_date'] # 构建新闻摘要 news_summary = "" news_source_info = "" if data.get('news'): news_summary = "\n【消息面分析】\n" news_summary += f"数据来源:Brave Search API\n" news_summary += f"搜索时间:{current_time}\n" news_summary += f"新闻范围:过去一周内相关新闻\n\n" for idx, news_item in enumerate(data['news'][:5], 1): news_summary += f"{idx}. {news_item.get('title', '无标题')}\n" news_summary += f" 来源: {news_item.get('source', '未知')}\n" news_summary += f" 摘要: {news_item.get('description', '无描述')}\n" news_summary += f" 发布时间: {news_item.get('published', '未知')}\n\n" news_source_info = "(消息来源:Brave搜索引擎,数据可能存在延迟)" else: news_summary = "\n【消息面分析】\n暂无最新新闻数据\n" # 构建详细的分析提示 prompt = f"""你是一位专业的股票分析师。请对{data['stock_name']}({data['stock_code']})进行全面分析,用简洁专业但易懂的语言回答。 用户问题:{user_message} 【实时行情数据】 数据来源:Tushare Pro API 交易日期:{quote_date} {json.dumps(data.get('quote'), ensure_ascii=False, indent=2) if data.get('quote') else '数据获取失败'} 【技术指标数据】 数据来源:Tushare Pro API(基于历史K线数据计算) 计算截止日期:{quote_date} {json.dumps(data.get('technical'), ensure_ascii=False, indent=2) if data.get('technical') else '数据获取失败'} 【基本面数据】 数据来源:Tushare Pro API {json.dumps(data.get('fundamental'), ensure_ascii=False, indent=2) if data.get('fundamental') else '数据获取失败'} {news_summary} 请按以下结构进行分析,并在每个部分明确标注数据来源和时效性: ## 一、基本面分析 分段说明公司情况,每个要点独立成段: - 第一段:公司主营业务和行业地位 - 第二段:所属行业发展前景 - 第三段:如果有新闻,简要分析对公司的影响{news_source_info} ## 二、技术面分析(数据截止:{quote_date}) 使用清晰的分段结构,每个技术指标独立成段: **价格走势** 当前价格走势特征(上涨/下跌/震荡),结合成交量分析。 **均线系统** 短期均线(MA5、MA10)与长期均线(MA20、MA60)的位置关系,判断当前趋势(多头/空头/震荡)。 **MACD指标** DIF和DEA的位置关系,MACD柱状图变化,判断动能强弱和买卖信号。 **RSI指标** 当前RSI值的位置,是否超买(>70)或超卖(<30),短期走势预判。 **支撑与压力** 关键支撑位和压力位的具体价格区间。 ## 三、市场情绪分析 分段分析市场情绪: - 第一段:当前市场情绪(乐观/谨慎/悲观)及原因 - 第二段:如果有新闻,分析是利好还是利空 - 第三段:短期可能的催化因素 ## 四、投资建议 基于技术面分析,给出具体的操作建议和点位: **短期(1-2周)操作建议** - 明确的操作建议:买入/持有/观望/减仓 - **具体点位建议**: - 如果建议买入:给出建议买入价格区间(基于支撑位) - 如果建议卖出:给出建议卖出价格区间(基于压力位) - 止损位:明确的止损价格点位 - 止盈位:明确的止盈价格点位 - 操作理由:基于技术指标的具体分析 **中期(1-3个月)策略** - 趋势判断(上涨/下跌/震荡) - 关键价格区间: - 上方目标位:具体价格 - 下方支撑位:具体价格 - 策略建议 **长期(半年以上)** 投资价值评估和长期持有建议。 **风险提示** - 主要风险点和注意事项 - 需要关注的关键价格位 ## 五、总结 用一句话概括核心观点。 --- **数据说明** - 行情数据来源:Tushare Pro(截止{quote_date}) - 技术指标:基于历史K线数据计算(截止{quote_date}) - 新闻数据:Brave搜索(搜索时间{current_time},范围:过去一周) 写作要求: 1. 语言简洁专业,避免过度修饰和比喻 2. 专业术语后用括号简单解释,例如"RSI超买(指标>70,股价可能回调)" 3. **重要:每个分析点必须独立成段,段落之间用空行分隔** 4. **技术面分析部分,每个指标必须使用加粗标题(**标题**)并独立成段** 5. 分析要客观理性,基于数据而非情绪 3. 分析要客观理性,基于数据而非情绪 4. 结论要明确,不要模棱两可 5. 控制在500-600字 6. 最后必须声明:"以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。" """ try: analysis = llm_service.chat( messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=2000 ) if analysis: return f"【{data['stock_name']}({data['stock_code']}) - AI深度分析】\n\n{analysis}" else: return self._rule_based_analysis(data) except Exception as e: logger.error(f"LLM分析失败: {e}") return self._rule_based_analysis(data) async def _llm_single_analysis( self, intent: Dict[str, Any], result: Dict[str, Any], stock_code: str, stock_name: Optional[str], user_message: str ) -> Dict[str, Any]: """使用LLM对单一查询进行分析""" data = result.get("data", result) display_name = stock_name or stock_code # 根据查询类型构建不同的prompt if intent["type"] == "technical": prompt = f"""你是一位专业的股票分析师。用户询问了{display_name}({stock_code})的技术指标。 用户问题:{user_message} 【技术指标数据】 {json.dumps(data, ensure_ascii=False, indent=2)} 请进行专业的技术分析: ## 技术指标解读 1. 均线系统分析: - 短期均线(MA5、MA10)与长期均线(MA20、MA60)的位置关系 - 判断当前趋势(多头/空头/震荡) 2. MACD指标分析: - DIF和DEA的位置关系 - MACD柱状图的变化趋势 - 判断动能强弱 3. RSI指标分析: - 当前RSI值的位置(超买/超卖/中性) - 短期可能的走势 4. KDJ指标分析(如有): - K、D、J值的位置关系 - 金叉/死叉信号 ## 综合判断 - 短期走势预判(1-2周) - 关键支撑位和压力位 - 操作建议(买入/持有/观望/减仓) ## 风险提示 - 主要技术风险点 写作要求: 1. 语言简洁专业,直接给出分析结论 2. 基于数据进行分析,不要编造 3. 控制在300-400字 4. 最后声明:"以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。" """ elif intent["type"] == "quote": prompt = f"""你是一位专业的股票分析师。用户询问了{display_name}({stock_code})的实时行情。 用户问题:{user_message} 【实时行情数据】 {json.dumps(data, ensure_ascii=False, indent=2)} 请进行专业的行情分析: ## 行情解读 1. 当日表现: - 涨跌幅分析 - 成交量分析 - 振幅分析 2. 价格位置: - 当前价格相对开盘价、最高价、最低价的位置 - 判断多空力量对比 3. 短期判断: - 当日走势特征 - 短期可能的走势 - 操作建议 写作要求: 1. 语言简洁专业,直接给出分析结论 2. 基于数据进行分析,不要编造 3. 控制在200-300字 4. 最后声明:"以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。" """ elif intent["type"] == "fundamental": prompt = f"""你是一位专业的股票分析师。用户询问了{display_name}({stock_code})的基本面信息。 用户问题:{user_message} 【基本面数据】 {json.dumps(data, ensure_ascii=False, indent=2)} 请进行专业的基本面分析: ## 公司概况 - 公司主营业务 - 所属行业和地域 - 上市时间和市场 ## 行业分析 - 所属行业的发展前景 - 行业地位和竞争优势 ## 投资价值 - 基本面评估 - 长期投资价值 - 关注要点 写作要求: 1. 语言简洁专业,直接给出分析结论 2. 基于数据进行分析,不要编造 3. 控制在200-300字 4. 最后声明:"以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。" """ else: # 其他类型,使用通用分析 prompt = f"""你是一位专业的股票分析师。用户询问了{display_name}({stock_code})的相关信息。 用户问题:{user_message} 【数据】 {json.dumps(data, ensure_ascii=False, indent=2)} 请基于提供的数据进行专业分析,给出有价值的见解和建议。 写作要求: 1. 语言简洁专业,直接给出分析结论 2. 基于数据进行分析,不要编造 3. 控制在200-300字 4. 最后声明:"以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。" """ try: analysis = llm_service.chat( messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=1500 ) if analysis: return { "message": f"【{display_name}({stock_code}) - AI分析】\n\n{analysis}", "metadata": {"type": intent["type"], "data": data} } else: # LLM失败,使用原始格式化 return self._format_response(intent, result, stock_code, stock_name) except Exception as e: logger.error(f"LLM单一分析失败: {e}") return self._format_response(intent, result, stock_code, stock_name) def _rule_based_analysis(self, data: Dict[str, Any]) -> str: """基于规则的分析(LLM不可用时的备选方案)""" parts = [f"【{data['stock_name']}({data['stock_code']}) - 综合分析】\n"] # 行情信息 if data.get('quote'): quote = data['quote'] parts.append("## 一、实时行情") parts.append(f"最新价:{quote.get('close', 0):.2f}元") parts.append(f"涨跌幅:{quote.get('pct_chg', 0):.2f}%") parts.append(f"成交量:{quote.get('vol', 0):.0f}手") parts.append("") # 技术分析 if data.get('technical'): tech = data['technical'].get('indicators', {}) parts.append("## 二、技术指标") if 'ma' in tech: ma = tech['ma'] parts.append(f"均线系统:MA5={ma.get('ma5')}, MA10={ma.get('ma10')}, MA20={ma.get('ma20')}") if 'macd' in tech: macd = tech['macd'] parts.append(f"MACD:DIF={macd.get('dif')}, DEA={macd.get('dea')}") if 'rsi' in tech: rsi = tech['rsi'] rsi6 = rsi.get('rsi6', 50) if rsi6 > 70: parts.append(f"RSI:{rsi6:.1f}(超买区域,注意回调风险)") elif rsi6 < 30: parts.append(f"RSI:{rsi6:.1f}(超卖区域,可能存在反弹机会)") else: parts.append(f"RSI:{rsi6:.1f}(中性区域)") parts.append("") # 基本面 if data.get('fundamental'): fund = data['fundamental'] parts.append("## 三、基本信息") parts.append(f"所属行业:{fund.get('industry', '未知')}") parts.append(f"上市日期:{fund.get('list_date', '未知')}") parts.append("") # 简单建议 parts.append("## 四、参考建议") parts.append("建议结合更多信息进行综合判断。") parts.append("") parts.append("⚠️ 以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。") return "\n".join(parts) async def _single_query( self, stock_code: str, stock_name: Optional[str], message: str ) -> Dict[str, Any]: """单一查询处理 - 使用LLM进行分析""" # 识别意图 intent = self._recognize_intent(message, stock_code) # 执行技能 result = await skill_manager.execute_skill( intent["skill"], **intent["params"] ) # 格式化响应 if not result.get("success", True): return { "message": f"查询失败:{result.get('error', '未知错误')}", "metadata": {"type": "error"} } # 所有查询都使用LLM进行分析(除了可视化) if intent["type"] != "visualization" and self.use_llm: return await self._llm_single_analysis(intent, result, stock_code, stock_name, message) else: return self._format_response(intent, result, stock_code, stock_name) def _recognize_intent(self, message: str, stock_code: str) -> Dict[str, Any]: """识别查询意图""" message_lower = message.lower() # K线图 if any(kw in message_lower for kw in ["k线", "图表", "走势图", "kline"]): return { "type": "visualization", "skill": "visualization", "params": {"stock_code": stock_code} } # 技术分析 if any(kw in message_lower for kw in ["技术", "指标", "macd", "rsi", "均线"]): return { "type": "technical", "skill": "technical_analysis", "params": {"stock_code": stock_code, "indicators": ["ma", "macd", "rsi"]} } # 基本面 if any(kw in message_lower for kw in ["基本面", "公司", "行业", "信息"]): return { "type": "fundamental", "skill": "fundamental", "params": {"stock_code": stock_code} } # 默认:实时行情 return { "type": "quote", "skill": "market_data", "params": {"stock_code": stock_code, "data_type": "quote"} } def _format_response( self, intent: Dict[str, Any], result: Dict[str, Any], stock_code: str, stock_name: Optional[str] ) -> Dict[str, Any]: """格式化响应""" data = result.get("data", result) display_name = stock_name or stock_code if intent["type"] == "quote": message = f"""【{display_name}】实时行情 交易日期:{data.get('trade_date', '')} 最新价:{data.get('close', 0):.2f}元 涨跌幅:{data.get('pct_chg', 0):+.2f}% 涨跌额:{data.get('change', 0):+.2f}元 开盘价:{data.get('open', 0):.2f}元 最高价:{data.get('high', 0):.2f}元 最低价:{data.get('low', 0):.2f}元 成交量:{data.get('vol', 0):.0f}手 成交额:{data.get('amount', 0):.0f}千元""" return { "message": message, "metadata": {"type": "quote", "data": data} } elif intent["type"] == "technical": indicators = data.get("indicators", {}) parts = [f"【{display_name}】技术指标\n"] if "ma" in indicators: ma = indicators["ma"] parts.append(f"均线:MA5={ma.get('ma5')}, MA10={ma.get('ma10')}, MA20={ma.get('ma20')}") if "macd" in indicators: macd = indicators["macd"] parts.append(f"MACD:DIF={macd.get('dif')}, DEA={macd.get('dea')}, MACD={macd.get('macd')}") if "rsi" in indicators: rsi = indicators["rsi"] parts.append(f"RSI:RSI6={rsi.get('rsi6')}, RSI12={rsi.get('rsi12')}") return { "message": "\n".join(parts), "metadata": {"type": "technical", "data": data} } elif intent["type"] == "visualization": return { "message": f"已生成【{display_name}】的K线图", "metadata": {"type": "chart", "data": data} } elif intent["type"] == "fundamental": message = f"""【{display_name}】基本信息 股票代码:{data.get('ts_code', '')} 所属地域:{data.get('area', '')} 所属行业:{data.get('industry', '')} 上市市场:{data.get('market', '')} 上市日期:{data.get('list_date', '')}""" return { "message": message, "metadata": {"type": "fundamental", "data": data} } return { "message": "查询完成", "metadata": {"type": "data", "data": data} } async def _analyze_question_intent(self, message: str) -> Optional[Dict[str, Any]]: """ 使用LLM分析问题意图 Args: message: 用户消息 Returns: 意图分析结果: { 'type': 'stock_specific' | 'macro_finance' | 'knowledge', 'description': '问题描述', 'keywords': ['关键词列表'], 'stock_names': ['股票名称'] (如果是stock_specific类型) } """ if not self.use_llm: logger.warning("LLM未配置,无法分析意图") return None prompt = f"""分析用户的金融问题,判断问题类型和关键信息。 用户问题:{message} 请分析这个问题属于以下哪一类: 1. **stock_specific** - 针对特定股票的问题 例如:"贵州茅台怎么样"、"分析一下比亚迪"、"600519的技术指标" 2. **macro_finance** - 宏观金融问题(不针对特定股票) 例如:"现在A股市场怎么样"、"最近有什么投资机会"、"如何看待当前经济形势" 3. **knowledge** - 金融知识问答 例如:"什么是MACD"、"如何看K线图"、"价值投资是什么" 请以JSON格式返回分析结果: {{ "type": "问题类型", "description": "问题的简要描述", "keywords": ["关键词1", "关键词2"], "stock_names": ["股票名称"] (仅当type为stock_specific时) }} 只返回JSON,不要有任何其他内容。""" try: result = llm_service.chat( messages=[{"role": "user", "content": prompt}], temperature=0.3, max_tokens=300 ) if not result: logger.warning("LLM返回空结果") return None # 清理结果,移除可能的markdown代码块标记 result = result.strip() if result.startswith("```json"): result = result[7:] if result.startswith("```"): result = result[3:] if result.endswith("```"): result = result[:-3] result = result.strip() # 检查是否为空 if not result: logger.warning("LLM返回内容为空") return None # 解析JSON intent = json.loads(result) logger.info(f"意图分析结果: {intent}") return intent except json.JSONDecodeError as e: logger.error(f"意图分析JSON解析失败: {e}, 原始响应: {result[:200] if result else 'None'}") return None except Exception as e: logger.error(f"意图分析失败: {e}") return None async def _handle_stock_question( self, intent_analysis: Dict[str, Any], message: str ) -> Dict[str, Any]: """处理针对特定股票的问题""" stock_names = intent_analysis.get('stock_names', []) if not stock_names: return { "message": "抱歉,我没有识别到您提到的股票。请提供更明确的股票代码或名称。", "metadata": {"type": "error"} } # 提取第一个股票(暂时只处理单只股票) stock_keyword = stock_names[0] # 使用Tushare搜索股票 search_results = tushare_service.search_stock(stock_keyword) if not search_results: return { "message": f"抱歉,未找到股票\"{stock_keyword}\"。请确认股票名称或代码是否正确。", "metadata": {"type": "error"} } stock = search_results[0] stock_code = stock['symbol'] stock_name = stock['name'] logger.info(f"处理股票问题: {stock_name}({stock_code})") # 判断是否需要全面分析 is_comprehensive = self._is_comprehensive_analysis(message) if is_comprehensive: return await self._comprehensive_analysis(stock_code, stock_name, message) else: return await self._single_query(stock_code, stock_name, message) async def _handle_macro_question( self, intent_analysis: Dict[str, Any], message: str ) -> Dict[str, Any]: """处理宏观金融问题""" keywords = intent_analysis.get('keywords', []) description = intent_analysis.get('description', '') logger.info(f"处理宏观问题: {description}") # 使用Brave搜索获取最新信息 search_query = f"A股市场 {' '.join(keywords)} 最新分析" try: news_result = await skill_manager.execute_skill( "brave_search", query=search_query, search_type="news", count=5, freshness="pw" ) # 构建新闻摘要 news_summary = "" if news_result and not news_result.get("error"): results = news_result.get("results", []) if results: news_summary = "\n【最新市场动态】\n" for idx, news_item in enumerate(results[:5], 1): news_summary += f"{idx}. {news_item.get('title', '无标题')}\n" news_summary += f" 来源: {news_item.get('source', '未知')}\n" news_summary += f" 时间: {news_item.get('published', '未知')}\n\n" # 使用LLM进行分析 prompt = f"""你是一位专业的金融分析师。用户询问了宏观金融问题。 用户问题:{message} 问题分析:{description} 关键词:{', '.join(keywords)} {news_summary} 请基于当前市场情况和最新动态,给出专业的分析和建议: ## 市场现状分析 - 当前市场整体情况 - 主要影响因素 ## 趋势判断 - 短期趋势 - 中长期展望 ## 投资建议 - 投资策略建议 - 风险提示 写作要求: 1. 语言简洁专业,避免过度修饰 2. 分析要客观理性,基于事实 3. 控制在400-500字 4. 最后声明:"以上分析仅供参考,不构成投资建议。股市有风险,投资需谨慎。" """ analysis = llm_service.chat( messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=1500 ) if analysis: return { "message": f"【宏观市场分析】\n\n{analysis}", "metadata": {"type": "macro_analysis"} } except Exception as e: logger.error(f"宏观问题处理失败: {e}") return { "message": "抱歉,暂时无法获取相关信息。请稍后再试。", "metadata": {"type": "error"} } async def _handle_knowledge_question( self, intent_analysis: Dict[str, Any], message: str ) -> Dict[str, Any]: """处理金融知识问答""" description = intent_analysis.get('description', '') keywords = intent_analysis.get('keywords', []) logger.info(f"处理知识问答: {description}") # 直接使用LLM回答 prompt = f"""你是一位专业的金融教育专家。用户询问了金融知识问题。 用户问题:{message} 请用通俗易懂的语言解释这个概念或回答这个问题: ## 核心概念 - 清晰定义和解释 ## 实际应用 - 如何在投资中应用 - 注意事项 ## 举例说明 - 用简单的例子帮助理解 写作要求: 1. 语言通俗易懂,避免过多专业术语 2. 如果使用专业术语,要简单解释 3. 控制在300-400字 4. 重点是帮助用户理解,而不是炫耀知识 """ try: answer = llm_service.chat( messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=1200 ) if answer: return { "message": f"【金融知识解答】\n\n{answer}", "metadata": {"type": "knowledge"} } except Exception as e: logger.error(f"知识问答处理失败: {e}") return { "message": "抱歉,暂时无法回答您的问题。请稍后再试。", "metadata": {"type": "error"} } # 创建全局实例 smart_agent = SmartStockAgent()