一、整体架构概览
系统分为五个层级:
-
数据层 :定义
FinancialData和AgentState两个 TypedDict,作为 Agent 之间传递的共享状态。 -
分析层:三位独立分析师(基本面、情绪、技术)并行或顺序产出基础报告。
-
决策层:多空研究员分别基于基础报告构建论据,然后通过"辩论裁判"得到初步结论。
-
执行层:交易员生成具体提案(方向、仓位、止损),风控审核提案合规性。
-
最终决策层:投资组合经理综合所有中间结果,输出最终评级(买入/持有/卖出)。
整个流程是一个 顺序 + 扇出(技术分析结果同时发给多空双方) 的有向无环图,最终汇聚到决策节点。
二、核心模块详解(可作博客章节)
1. 大模型配置(兼容阿里云百炼)
python
llm = ChatOpenAI(
model=MODEL_NAME,
api_key=API_KEY,
base_url=BASE_URL,
temperature=0.7,
)
-
利用阿里云百炼的 兼容模式 (
/compatible-mode/v1),可以直接使用 OpenAI SDK 调用通义千问模型。 -
环境变量
DASHSCOPE_API_KEY存储密钥,避免硬编码。
2. 状态管理(LangGraph 核心)
python
class AgentState(TypedDict):
ticker: str
data: FinancialData
fundamental_report: str
sentiment_report: str
technical_report: str
bull_argument: str
bear_argument: str
debate_result: str
trader_proposal: str
risk_assessment: str
final_decision: str
-
每个节点函数接收
state字典,返回需要更新的字段(增量更新)。 -
LangGraph 自动合并返回结果到全局状态。
3. 分析师节点(纯逻辑 + 小部分 LLM)
-
fundamental_analyst:使用 LLM 生成基本面分析(估值、盈利、风险)。
-
sentiment_analyst:基于情绪得分进行规则判断(>50 看多,< -50 看空)。
-
technical_analyst:基于 RSI 指标规则判断(>70 超买,<30 超卖)。
亮点:混合使用 LLM 和传统规则,降低不必要的 API 调用。
4. 多空辩论机制
-
bull_researcher / bear_researcher:分别基于相同的三份报告,要求 LLM 扮演"看多/看空研究员"构建论据。
-
debate:作为裁判,综合两方观点给出最终倾向(买入/卖出/持有)。
这种"双角色辩论 + 第三方裁判"的模式,可以有效抑制大模型的 立场偏见,提升中立性。
5. 交易员与风控
-
trader_agent:根据辩论结论生成具体交易提案(方向、仓位、止损位)。
-
risk_manager:审核提案,结合股价和 PE 给出"允许/限制/否决"。
风控节点是合规性检查的关键,可在此扩展更多指标(如最大回撤、行业敞口等)。
6. 最终决策(投资组合经理)
- 综合情绪报告、风控意见和交易提案,输出最终评级并做简短总结。
三、LangGraph 工作流构建(重点技术点)
python
workflow = StateGraph(AgentState)
workflow.add_node("fundamental", fundamental_analyst)
# ... 添加所有节点
workflow.set_entry_point("fundamental")
workflow.add_edge("fundamental", "sentiment")
workflow.add_edge("sentiment", "technical")
workflow.add_edge("technical", "bull")
workflow.add_edge("technical", "bear") # fan-out
workflow.add_edge("bull", "debate")
workflow.add_edge("bear", "debate")
# ... 后续顺序边
workflow.add_edge("pm", END)
-
扇出 (fan-out) :
technical节点的输出同时流向bull和bear,LangGraph 会自动并行执行这两个节点(若硬件支持)。 -
汇聚 :
debate节点需要等待bull和bear都完成才会执行。 -
顺序边:后续节点逐一串联,形成决策链。
这种 声明式图结构 比传统的函数调用链更易于修改、扩展和调试。
四、技术亮点与可改进点(供博客深入讨论)
✅ 亮点
-
角色分工清晰:每个 Agent 只负责单一任务,符合单一职责原则。
-
状态驱动:所有 Agent 通过共享状态通信,解耦了直接函数调用。
-
混合推理:部分节点使用规则(情绪、RSI),部分使用 LLM,平衡了成本与灵活性。
-
可观测性:LangGraph 内置支持流式输出、节点重试、断点调试(需额外配置)。
整体最小代码的实现》
python
import os
from typing import TypedDict
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, END
# ==================== 配置阿里云百炼大模型 ====================
# 方式1:从环境变量获取 API Key(推荐)
# 在终端执行: export DASHSCOPE_API_KEY="你的阿里云API Key"
# 方式2:直接填写(不推荐提交到代码仓库)
API_KEY = os.getenv("DASHSCOPE_API_KEY", "your-api-key-here")
BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
MODEL_NAME = "qwen-plus" # 可选: qwen-turbo, qwen-max, qwen-plus
llm = ChatOpenAI(
model=MODEL_NAME,
api_key=API_KEY,
base_url=BASE_URL,
temperature=0.7,
)
# ==================== 定义数据结构 ====================
class FinancialData(TypedDict):
price: float
pe: float
roe: float
sentiment_score: int # -100 到 100
rsi: float
class AgentState(TypedDict):
ticker: str
data: FinancialData
fundamental_report: str
sentiment_report: str
technical_report: str
bull_argument: str
bear_argument: str
debate_result: str
trader_proposal: str
risk_assessment: str
final_decision: str
# ==================== 1. 三位分析师 ====================
def fundamental_analyst(state: AgentState):
data, ticker = state["data"], state["ticker"]
prompt = f"""请对股票{ticker}进行基本面分析:
- PE(市盈率): {data['pe']} 倍
- ROE(净资产收益率): {data['roe']}%
请从估值水平、盈利质量、潜在风险三个方面分析,最后给出看多或看空的倾向。"""
return {"fundamental_report": llm.invoke(prompt).content}
def sentiment_analyst(state: AgentState):
data, ticker = state["data"], state["ticker"]
score = data["sentiment_score"]
if score > 50:
result = "强烈看多"
elif score < -50:
result = "强烈看空"
else:
result = "中性"
return {"sentiment_report": f"{ticker}市场情绪得分 {score},结论:{result}"}
def technical_analyst(state: AgentState):
data, ticker = state["data"], state["ticker"]
rsi = data["rsi"]
if rsi > 70:
result = "超买(可能回调)"
elif rsi < 30:
result = "超卖(可能反弹)"
else:
result = "中性"
return {"technical_report": f"{ticker} RSI = {rsi:.1f},处于{result}区域"}
# ==================== 2. 多空研究员辩论 ====================
def bull_researcher(state: AgentState):
prompt = f"""你是一名看多研究员。基于以下信息,构建强有力的看多论据:
- 基本面分析: {state['fundamental_report']}
- 情绪分析: {state['sentiment_report']}
- 技术面分析: {state['technical_report']}
请用事实和逻辑支持买入该股票的理由。"""
return {"bull_argument": llm.invoke(prompt).content}
def bear_researcher(state: AgentState):
prompt = f"""你是一名看空研究员。基于以下信息,构建强有力的看空论据:
- 基本面分析: {state['fundamental_report']}
- 情绪分析: {state['sentiment_report']}
- 技术面分析: {state['technical_report']}
请用事实和逻辑支持卖出或回避该股票的理由。"""
return {"bear_argument": llm.invoke(prompt).content}
def debate(state: AgentState):
prompt = f"""请综合以下多空双方观点,做出最终裁决:
【多方观点】{state['bull_argument']}
【空方观点】{state['bear_argument']}
请给出明确的结论:买入、卖出 或 持有,并简要说明理由。"""
return {"debate_result": llm.invoke(prompt).content}
# ==================== 3. 交易员提案 ====================
def trader_agent(state: AgentState):
prompt = f"""根据辩论结论:{state['debate_result']}
生成具体的交易提案,包含:
- 买卖方向(买入/卖出/观望)
- 建议仓位(占总资金百分比)
- 止损位(价格或百分比)
请以清晰列表形式输出。"""
return {"trader_proposal": llm.invoke(prompt).content}
# ==================== 4. 风控审核 ====================
def risk_manager(state: AgentState):
prompt = f"""审核以下交易提案,并结合当前股价 ${state['data']['price']} 和 PE {state['data']['pe']} 倍:
{state['trader_proposal']}
请输出:允许执行 / 限制执行(说明限制条件) / 否决(说明风险原因)。"""
return {"risk_assessment": llm.invoke(prompt).content}
# ==================== 5. 投资组合经理最终决策 ====================
def portfolio_manager(state: AgentState):
prompt = f"""这是最终决策阶段,请综合所有信息:
- 情绪分析:{state['sentiment_report']}
- 风控审核意见:{state['risk_assessment']}
- 交易员提案:{state['trader_proposal']}
给出最终评级(买入/卖出/持有),并做简短总结。"""
return {"final_decision": llm.invoke(prompt).content}
# ==================== 构建工作流(LangGraph) ====================
workflow = StateGraph(AgentState)
workflow.add_node("fundamental", fundamental_analyst)
workflow.add_node("sentiment", sentiment_analyst)
workflow.add_node("technical", technical_analyst)
workflow.add_node("bull", bull_researcher)
workflow.add_node("bear", bear_researcher)
workflow.add_node("debate", debate)
workflow.add_node("trader", trader_agent)
workflow.add_node("risk", risk_manager)
workflow.add_node("pm", portfolio_manager)
workflow.set_entry_point("fundamental")
workflow.add_edge("fundamental", "sentiment")
workflow.add_edge("sentiment", "technical")
workflow.add_edge("technical", "bull")
workflow.add_edge("technical", "bear")
workflow.add_edge("bull", "debate")
workflow.add_edge("bear", "debate")
workflow.add_edge("debate", "trader")
workflow.add_edge("trader", "risk")
workflow.add_edge("risk", "pm")
workflow.add_edge("pm", END)
app = workflow.compile()
# ==================== 交互式输入测试 ====================
def interactive_input():
print("\n===== 多 Agent 股票分析系统(阿里通义千问)=====")
ticker = input("请输入股票代码(例如 NVDA,AAPL):").strip().upper()
try:
price = float(input("当前股价:"))
pe = float(input("市盈率 PE:"))
roe = float(input("净资产收益率 ROE(%):"))
sentiment = int(input("市场情绪得分(-100 到 100,正数积极,负数消极):"))
rsi = float(input("RSI 指标(0-100):"))
except ValueError:
print("输入格式错误,请使用数字。")
return None
return {
"ticker": ticker,
"data": {
"price": price,
"pe": pe,
"roe": roe,
"sentiment_score": sentiment,
"rsi": rsi,
}
}
if __name__ == "__main__":
print("注意:请先设置环境变量 DASHSCOPE_API_KEY")
print("若未设置,可在脚本中直接修改 API_KEY 变量")
user_input = interactive_input()
if user_input:
print("\n正在调用 Agent 团队进行分析,请稍候...\n")
result = app.invoke(user_input)
print("\n" + "="*50)
print(f"最终决策:{result['final_decision']}")
print("="*50)
# 可选:打印中间结果
print("\n--- 详细过程 ---")
print(f"基本面分析:{result['fundamental_report'][:200]}...")
print(f"情绪分析:{result['sentiment_report']}")
print(f"技术分析:{result['technical_report']}")
print(f"辩论结论:{result['debate_result'][:200]}...")
print(f"交易提案:{result['trader_proposal'][:200]}...")
print(f"风控审核:{result['risk_assessment'][:200]}...")
五、运行与交互
-
用户通过命令行交互输入股票代码、价格、PE、ROE、情绪得分、RSI。
-
系统依次调用各个 Agent,最终输出最终决策和部分中间报告。
-
当前为一次性推理,若要实现实时监控或回测,需要封装为类并集成数据源 API。