diff --git a/.env.example b/.env.example index 1e257c3c..51edfed8 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ -ALPHA_VANTAGE_API_KEY=alpha_vantage_api_key_placeholder -OPENAI_API_KEY=openai_api_key_placeholder \ No newline at end of file +ALPHA_VANTAGE_API_KEY=W47FRS433AD7DVGQ +OPENAI_API_KEY=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 \ No newline at end of file diff --git a/cli/utils.py b/cli/utils.py index 7b9682a6..7c19575d 100644 --- a/cli/utils.py +++ b/cli/utils.py @@ -204,8 +204,8 @@ def select_deep_thinking_agent(provider) -> str: "google": [ ("Gemini 2.0 Flash-Lite - Cost efficiency and low latency", "gemini-2.0-flash-lite"), ("Gemini 2.0 Flash - Next generation features, speed, and thinking", "gemini-2.0-flash"), - ("Gemini 2.5 Flash - Adaptive thinking, cost efficiency", "gemini-2.5-flash-preview-05-20"), - ("Gemini 2.5 Pro", "gemini-2.5-pro-preview-06-05"), + ("Gemini 2.5 Flash - Adaptive thinking, cost efficiency", "gemini-2.5-flash"), + ("Gemini 2.5 Pro", "gemini-2.5-pro"), ], "openrouter": [ ("DeepSeek V3 - a 685B-parameter, mixture-of-experts model", "deepseek/deepseek-chat-v3-0324:free"), diff --git a/tradingagents/agents/researchers/bear_researcher.py b/tradingagents/agents/researchers/bear_researcher.py index 6634490a..d1ff0d27 100644 --- a/tradingagents/agents/researchers/bear_researcher.py +++ b/tradingagents/agents/researchers/bear_researcher.py @@ -3,37 +3,58 @@ import time import json +# 定义一个创建“看空”研究员(Bear Researcher)节点的工厂函数 def create_bear_researcher(llm, memory): - def bear_node(state) -> dict: - investment_debate_state = state["investment_debate_state"] - history = investment_debate_state.get("history", "") - bear_history = investment_debate_state.get("bear_history", "") + """ + 创建看空分析师(Bear Analyst)的 LangGraph 节点函数。 + Args: + llm: 语言模型实例,用于生成分析和论点。 + memory: 外部记忆/检索系统,用于获取历史教训。 + + Returns: + Callable: 接受当前状态并返回更新后的状态的节点函数 (bear_node)。 + """ + + def bear_node(state) -> dict: + """ + 看空分析师节点的核心逻辑。 + 根据全局状态中的报告和辩论历史,生成看空论点并更新状态。 + """ + # --- 1. 获取当前状态数据 --- + investment_debate_state = state["investment_debate_state"] + + # 提取辩论历史和上一轮多头(Bull)的回复 + history = investment_debate_state.get("history", "") current_response = investment_debate_state.get("current_response", "") + + # 提取所有研究报告作为论证的证据 market_research_report = state["market_report"] sentiment_report = state["sentiment_report"] news_report = state["news_report"] fundamentals_report = state["fundamentals_report"] + # --- 2. 记忆检索与格式化 --- + # 合并所有报告,作为检索记忆的查询(寻找相似情况下的历史教训) curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}" + + # 从外部记忆中检索历史记录/教训 past_memories = memory.get_memories(curr_situation, n_matches=2) + # 格式化检索到的历史教训,作为 Prompt 的一部分 past_memory_str = "" - for i, rec in enumerate(past_memories, 1): - past_memory_str += rec["recommendation"] + "\n\n" + for rec in past_memories: + past_memory_str += rec.get("recommendation", "") + "\n\n" + # --- 3. 构建 Prompt 并调用 LLM --- prompt = f"""You are a Bear Analyst making the case against investing in the stock. Your goal is to present a well-reasoned argument emphasizing risks, challenges, and negative indicators. Leverage the provided research and data to highlight potential downsides and counter bullish arguments effectively. Key points to focus on: - -- Risks and Challenges: Highlight factors like market saturation, financial instability, or macroeconomic threats that could hinder the stock's performance. -- Competitive Weaknesses: Emphasize vulnerabilities such as weaker market positioning, declining innovation, or threats from competitors. -- Negative Indicators: Use evidence from financial data, market trends, or recent adverse news to support your position. -- Bull Counterpoints: Critically analyze the bull argument with specific data and sound reasoning, exposing weaknesses or over-optimistic assumptions. -- Engagement: Present your argument in a conversational style, directly engaging with the bull analyst's points and debating effectively rather than simply listing facts. +- Risks and Challenges: Highlight factors like market saturation, financial instability, or macroeconomic threats. +- Bull Counterpoints: Critically analyze the bull argument with specific data and sound reasoning. +- Engagement: Present your argument in a conversational style, directly engaging with the bull analyst's points. Resources available: - Market research report: {market_research_report} Social media sentiment report: {sentiment_report} Latest world affairs news: {news_report} @@ -41,21 +62,32 @@ Company fundamentals report: {fundamentals_report} Conversation history of the debate: {history} Last bull argument: {current_response} Reflections from similar situations and lessons learned: {past_memory_str} + Use this information to deliver a compelling bear argument, refute the bull's claims, and engage in a dynamic debate that demonstrates the risks and weaknesses of investing in the stock. You must also address reflections and learn from lessons and mistakes you made in the past. """ + # 调用 LLM 生成看空分析师的回复 response = llm.invoke(prompt) + # 格式化看空分析师的论点,加上身份前缀 argument = f"Bear Analyst: {response.content}" + # --- 4. 更新全局状态 --- new_investment_debate_state = { + # 更新完整的辩论历史 "history": history + "\n" + argument, - "bear_history": bear_history + "\n" + argument, - "bull_history": investment_debate_state.get("bull_history", ""), + # 更新看空方的历史记录 (便于后续总结和自我反思) + "bear_history": investment_debate_state.get("bear_history", "") + "\n" + argument, + # 将当前回复设置为看空方的论点,供下一轮(如看多方)使用 "current_response": argument, + # 增加辩论的轮数计数 "count": investment_debate_state["count"] + 1, + # 保持看多方的历史不变 (从旧状态中获取) + "bull_history": investment_debate_state.get("bull_history", ""), } + # 返回包含更新后的投资辩论状态的字典,用于 LangGraph 传递 return {"investment_debate_state": new_investment_debate_state} + # 返回定义的节点函数 return bear_node diff --git a/tradingagents/agents/researchers/bull_researcher.py b/tradingagents/agents/researchers/bull_researcher.py index b03ef755..3ad2b8ba 100644 --- a/tradingagents/agents/researchers/bull_researcher.py +++ b/tradingagents/agents/researchers/bull_researcher.py @@ -3,25 +3,54 @@ import time import json +# 定义一个创建“看多”研究员(Bull Researcher)节点的工厂函数 def create_bull_researcher(llm, memory): + """ + 创建看多分析师(Bull Analyst)的 LangGraph 节点函数。 + + Args: + llm: 语言模型实例,用于生成分析和论点。 + memory: 外部记忆/检索系统,用于获取历史经验和教训。 + + Returns: + Callable: 接受当前状态并返回更新后的状态的节点函数 (bull_node)。 + """ + + # 内部定义的节点函数,接收整个状态字典 def bull_node(state) -> dict: + """ + 看多分析师节点的核心逻辑。 + 根据全局状态中的报告和辩论历史,生成看多论点并更新状态。 + """ + # --- 1. 获取当前状态数据 --- investment_debate_state = state["investment_debate_state"] + + # 提取辩论的完整历史和上一轮空头(Bear)的回复 history = investment_debate_state.get("history", "") bull_history = investment_debate_state.get("bull_history", "") - current_response = investment_debate_state.get("current_response", "") + + # 提取所有研究报告作为论证的证据 market_research_report = state["market_report"] sentiment_report = state["sentiment_report"] news_report = state["news_report"] fundamentals_report = state["fundamentals_report"] + # --- 2. 记忆检索与格式化 --- + # 合并所有报告,作为检索记忆的查询 curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}" + + # 从外部记忆中检索历史记录/教训 past_memories = memory.get_memories(curr_situation, n_matches=2) + # 格式化检索到的历史教训,作为 Prompt 的一部分 past_memory_str = "" - for i, rec in enumerate(past_memories, 1): - past_memory_str += rec["recommendation"] + "\n\n" + for rec in past_memories: + # 假设每个记忆记录包含一个 "recommendation" 字段 + past_memory_str += rec.get("recommendation", "") + "\n\n" + # --- 3. 构建 Prompt 并调用 LLM --- + # 构建发送给 LLM 的提示(Prompt),指导其扮演看多分析师的角色 prompt = f"""You are a Bull Analyst advocating for investing in the stock. Your task is to build a strong, evidence-based case emphasizing growth potential, competitive advantages, and positive market indicators. Leverage the provided research and data to address concerns and counter bearish arguments effectively. Key points to focus on: @@ -42,18 +71,28 @@ Reflections from similar situations and lessons learned: {past_memory_str} Use this information to deliver a compelling bull argument, refute the bear's concerns, and engage in a dynamic debate that demonstrates the strengths of the bull position. You must also address reflections and learn from lessons and mistakes you made in the past. """ + # 调用 LLM 生成看多分析师的回复 response = llm.invoke(prompt) + # 格式化看多分析师的论点,加上身份前缀 argument = f"Bull Analyst: {response.content}" + # --- 4. 更新全局状态 --- new_investment_debate_state = { + # 更新完整的辩论历史 "history": history + "\n" + argument, + # 更新看多方的历史记录 (便于后续总结) "bull_history": bull_history + "\n" + argument, + # 保持看空方的历史不变 (从旧状态中获取) "bear_history": investment_debate_state.get("bear_history", ""), + # 将当前回复设置为看多方的论点,供下一轮(如看空方)使用 "current_response": argument, + # 增加辩论的轮数计数 "count": investment_debate_state["count"] + 1, } + # 返回包含更新后的投资辩论状态的字典,用于 LangGraph 传递 return {"investment_debate_state": new_investment_debate_state} - return bull_node + # 返回定义的节点函数 (工厂函数模式) + return bull_node \ No newline at end of file