TradingAgents/tradingagents/agents/researchers/bull_researcher.py

146 lines
5.6 KiB
Python
Raw 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.

# -*- coding: utf-8 -*-
from langchain_core.messages import AIMessage
import time
import json
def create_bull_researcher(llm, memory):
"""
建立一個看漲研究員節點。
這個節點在辯論中扮演看漲分析師的角色,主張投資某支股票。
它會利用市場研究、情緒分析、新聞和基本面報告,並結合過去的經驗(記憶),
來構建一個有說服力的論點,並反駁看跌方的觀點。
Args:
llm: 用於生成回應的語言模型。
memory: 儲存過去情況和反思的記憶體物件。
Returns:
function: 一個代表看漲研究員節點的函式,可在 langgraph 中使用。
"""
def bull_node(state) -> dict:
"""
看漲研究員節點的執行函式。
Args:
state (dict): 當前的圖狀態。
Returns:
dict: 更新後的狀態,包含新的投資辯論狀態。
"""
# 從狀態中獲取投資辯論的相關資訊
investment_debate_state = state["investment_debate_state"]
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"]
# 整合當前情況並智能截斷以避免超過 token 限制
# 估算1 個中文字符 ≈ 2.5 tokens1 個英文字符 ≈ 0.25 tokens
# 目標:將每個報告限制在合理的字符數內,總共不超過約 15000 字符(約 20000-30000 tokens
def truncate_text(text, max_chars):
"""智能截斷文本到指定字符數,在句子邊界處截斷"""
if len(text) <= max_chars:
return text
# 在max_chars附近尋找句子結束標記
truncated = text[:max_chars]
# 尋找最後一個句號、換行或逗號
for delimiter in ['', '\n', '', '', ' ']:
last_pos = truncated.rfind(delimiter)
if last_pos > max_chars * 0.8: # 至少保留80%的內容
return text[:last_pos + 1] + "\n\n...(為控制長度已精簡)"
# 如果找不到合適的分隔符,直接在字符處截斷
return truncated + "...(為控制長度已精簡)"
# 為每個報告設置合理的字符限制
# 模型 gpt-4.1-mini 的限制是 8192 tokens
# 混合中英文估算: 1 字符 ≈ 1.5-2 tokens (取保守值)
# 目標: 總字符數 < 3000 字符 (約 4500-6000 tokens留 2000+ tokens 給 completion)
market_research_report = truncate_text(market_research_report, 500)
sentiment_report = truncate_text(sentiment_report, 500)
news_report = truncate_text(news_report, 800) # 新聞通常較長但也需要控制
fundamentals_report = truncate_text(fundamentals_report, 600)
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)
# 將過去的經驗格式化為字串(限制長度)
past_memory_str = ""
for i, rec in enumerate(past_memories, 1):
recommendation = rec["recommendation"]
# 限制每條記憶的長度
if len(recommendation) > 200:
recommendation = recommendation[:200] + "...(已截斷)"
past_memory_str += recommendation + "\n\n"
# 建立提示 (prompt) - 限制歷史長度以控制總 token 數
history = truncate_text(history, 300)
current_response = truncate_text(current_response, 200)
prompt = f"""**重要您必須使用繁體中文Traditional Chinese回覆所有內容。**
【專業身份】
您是看漲研究員,負責提出買入該股票的論點。
【分析重點】
1. **成長潛力**:營收/盈利成長機會
2. **競爭優勢**:核心優勢與護城河
3. **催化劑**:推升股價的因素
4. **估值**:為何當前價格被低估
【可用資料】
- 市場分析:{market_research_report}
- 社群情緒:{sentiment_report}
- 新聞:{news_report}
- 基本面:{fundamentals_report}
- 辯論歷史:{history}
- 看跌論點:{current_response}
- 過往經驗:{past_memory_str}
【輸出要求】
**長度**300-500字
**結構**
1. 核心看漲論點80字
2. 成長動能分析150字
3. 反駁看跌觀點100字
4. 投資建議70字
**注意**
- 用數據支撐論點
- 直接回應對方觀點
- 承認風險但論證機會更大
請提供有說服力的看漲論證!
"""
# 呼叫 LLM 生成回應
response = llm.invoke(prompt)
# 格式化論點
argument = f"看漲分析師:{response.content}"
# 更新投資辯論狀態
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,
}
return {"investment_debate_state": new_investment_debate_state}
return bull_node