TradingAgents 深度实战:多智能体 LLM 金融交易框架——从架构设计到生产部署的全链路解析
当 AI Agent 从单一对话走向复杂协作,金融交易领域正在经历一场静默的革命。TradingAgents 用 5.6 万 Star 证明了:专业交易公司的组织结构,可以被代码完美复刻。
引言:为什么金融交易需要多智能体?
在量化交易领域,单一策略模型面对复杂多变的市场环境时,往往显得力不从心。突发新闻、宏观数据发布、盘中情绪剧烈波动——这些因素交织在一起,构成了一个多维度的决策空间。传统交易系统的核心局限在于:
- 缺乏组织结构模拟:真实交易公司有分析师、交易员、风控团队等角色分工,单一模型难以捕捉这种复杂互动
- 通信效率低下:依赖自然语言作为主要通信媒介,随着对话延长出现"电话效应"——细节丢失、状态受损
- 决策维度单一:无法同时从基本面、技术面、情绪面等多个维度进行综合研判
TradingAgents 的出现,正是为了解决这些痛点。它模拟专业交易公司的运作模式,通过多个具有专门角色的 LLM 驱动智能体协作完成金融交易决策。本文将深入剖析这个 5.6 万 Star 项目的设计哲学、架构实现与实战应用。
一、核心设计哲学:从交易公司到代码架构
1.1 角色专业化:每个智能体各司其职
TradingAgents 的核心洞察是:专业交易公司的成功,源于角色分工与协作机制。框架将这一理念转化为代码:
┌─────────────────────────────────────────────────────────────┐
│ TradingAgents 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 分析师团队 │───▶│ 研究团队 │───▶│ 交易员 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 基本面分析 │ │ 多头研究员 │ │ 风险管理 │ │
│ │ 情绪分析 │ │ 空头研究员 │ │ 团队 │ │
│ │ 新闻分析 │ │ (辩论) │ │ │ │
│ │ 技术分析 │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Manager │ │
│ │ (协调器) │ │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Execution │ │
│ │ (执行层) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.2 智能体角色详解
分析师团队:市场信息的收集者与解读员
分析师团队是框架的信息来源核心,负责从多个维度收集和分析市场数据:
| 角色 | 职责 | 输出 |
|---|---|---|
| 基本面分析师 | 评估公司财务报表、盈利能力、行业地位 | 基本面报告(估值、财务健康度) |
| 情绪分析师 | 分析社交媒体、公众舆论、投资者心理 | 情绪指数(恐惧/贪婪分数) |
| 新闻分析师 | 关注新闻事件、宏观经济指标 | 事件影响评估报告 |
| 技术分析师 | 运用技术指标分析价格走势 | 技术信号列表(支撑位、阻力位、趋势) |
研究团队:多空辩论的智慧碰撞
研究团队的设计是 TradingAgents 最具创新性的部分。它引入了辩论机制:
- 多头研究员:强调市场的积极因素和增长潜力,寻找买入机会
- 空头研究员:关注市场的风险和负面信号,识别潜在风险
这种辩论机制避免了单一视角的局限性,通过对抗性分析形成更加平衡、客观的市场观点。
交易员与风险管理:决策执行与风险控制
交易员综合研究团队的分析结果,结合历史数据做出交易决策。风险管理团队则从三个维度进行风险控制:
- 激进型:追求高收益,容忍较大回撤
- 中性型:平衡收益与风险
- 保守型:优先资本保全,追求稳定收益
二、架构深度解析:从设计到实现
2.1 技术栈选型
TradingAgents-CN 中文增强版的技术栈:
前端层:Vue 3 + Element Plus
后端层:FastAPI + Uvicorn
数据存储:MongoDB
缓存层:Redis
AI 编排:LangGraph + LangChain
模型支持:DeepSeek、Claude、GPT、MiniMax、通义千问
2.2 多智能体协作架构
系统采用微服务架构设计,将复杂的金融分析任务分解为多个独立的智能体模块:
# 核心架构层次
ARCHITECTURE_LAYERS = {
"数据输入层": {
"市场数据": ["AKShare", "Tushare", "BaoStock"],
"新闻数据": ["新闻API", "RSS订阅"],
"情绪数据": ["社交媒体爬虫"]
},
"智能体层": {
"分析师模块": ["基本面", "情绪", "新闻", "技术"],
"研究模块": ["多头", "空头"],
"决策模块": ["交易员", "风控"]
},
"编排层": {
"LangGraph": "状态机编排",
"Manager": "智能体协调器"
},
"输出层": {
"交易信号": "买入/卖出/持有",
"风险报告": "VaR、最大回撤",
"分析报告": "Markdown/PDF"
}
}
2.3 结构化通信协议
TradingAgents 的另一个创新是结构化通信协议。传统多智能体系统依赖自然语言对话,存在信息损失问题。TradingAgents 采用结构化输出与自然语言结合的方式:
from pydantic import BaseModel
from typing import List, Optional
class AnalysisReport(BaseModel):
"""分析师报告的结构化输出"""
symbol: str # 股票代码
timestamp: str # 分析时间
analyst_type: str # 分析师类型
# 核心指标
confidence_score: float # 置信度 0-1
key_findings: List[str] # 关键发现
risk_factors: List[str] # 风险因素
# 技术指标(仅技术分析师)
support_levels: Optional[List[float]] = None
resistance_levels: Optional[List[float]] = None
trend_direction: Optional[str] = None
# 基本面指标(仅基本面分析师)
valuation_score: Optional[float] = None
financial_health: Optional[str] = None
growth_potential: Optional[str] = None
这种结构化设计确保:
- 智能体之间的信息传递准确、高效
- 减少信息损失,维持上下文连贯性
- 便于后续分析和回溯
三、核心功能模块深度解析
3.1 分析师智能体系统
技术分析师实现
# app/agents/technical_analyst.py
from typing import Dict, List
import pandas as pd
import talib
class TechnicalAnalyst:
"""技术分析师智能体"""
def __init__(self, llm_client):
self.llm = llm_client
self.indicators = {
"MACD": self._calculate_macd,
"RSI": self._calculate_rsi,
"Bollinger": self._calculate_bollinger,
"SMA": self._calculate_sma,
"EMA": self._calculate_ema
}
def analyze(self, price_data: pd.DataFrame) -> AnalysisReport:
"""执行技术分析"""
# 1. 计算技术指标
indicators_result = {}
for name, calc_func in self.indicators.items():
indicators_result[name] = calc_func(price_data)
# 2. 识别关键价格位
support, resistance = self._find_key_levels(price_data)
# 3. 判断趋势方向
trend = self._determine_trend(price_data, indicators_result)
# 4. 生成交易信号
signals = self._generate_signals(indicators_result, trend)
# 5. LLM 综合研判
analysis_prompt = self._build_analysis_prompt(
indicators_result, support, resistance, trend, signals
)
llm_insight = self.llm.generate(analysis_prompt)
return AnalysisReport(
symbol=price_data.symbol,
timestamp=datetime.now().isoformat(),
analyst_type="technical",
confidence_score=self._calculate_confidence(signals),
key_findings=llm_insight.key_findings,
risk_factors=llm_insight.risk_factors,
support_levels=support,
resistance_levels=resistance,
trend_direction=trend
)
def _calculate_macd(self, data: pd.DataFrame) -> Dict:
"""MACD 指标计算"""
close = data['close'].values
macd, signal, hist = talib.MACD(
close,
fastperiod=12,
slowperiod=26,
signalperiod=9
)
return {
"macd": macd[-1],
"signal": signal[-1],
"histogram": hist[-1],
"signal_type": "bullish" if hist[-1] > 0 else "bearish"
}
def _calculate_rsi(self, data: pd.DataFrame) -> Dict:
"""RSI 指标计算"""
close = data['close'].values
rsi = talib.RSI(close, timeperiod=14)
current_rsi = rsi[-1]
return {
"value": current_rsi,
"zone": "oversold" if current_rsi < 30 else
"overbought" if current_rsi > 70 else "neutral"
}
def _find_key_levels(self, data: pd.DataFrame, window: int = 20) -> tuple:
"""识别支撑位和阻力位"""
# 使用局部极值点识别
highs = data['high'].rolling(window=window, center=True).max()
lows = data['low'].rolling(window=window, center=True).min()
resistance_levels = highs[highs == data['high']].dropna().tail(3).tolist()
support_levels = lows[lows == data['low']].dropna().tail(3).tolist()
return support_levels, resistance_levels
基本面分析师实现
# app/agents/fundamental_analyst.py
class FundamentalAnalyst:
"""基本面分析师智能体"""
TOOLS = {
"get_fundamentals": "获取公司综合基本面数据",
"get_balance_sheet": "获取资产负债表",
"get_cashflow": "获取现金流量表",
"get_income_statement": "获取利润表"
}
SYSTEM_PROMPT = """你是一名研究员,负责梳理某公司过去一周的基本面信息。
请撰写一份详尽的基本面报告,内容包括:
• 公司财务文件(资产负债表、现金流量表、利润表)
• 公司概况、基本财务指标、历史财务表现
不要只用'趋势喜忧参半'这类空话,务必给出具体、细致、可辅助交易决策的洞察。"""
async def analyze(self, symbol: str) -> AnalysisReport:
"""执行基本面分析"""
# 1. 获取财务数据
fundamentals = await self._fetch_financial_data(symbol)
# 2. 计算关键财务比率
ratios = self._calculate_financial_ratios(fundamentals)
# 3. 估值分析
valuation = self._analyze_valuation(fundamentals, ratios)
# 4. LLM 深度分析
analysis = await self.llm.generate(
system_prompt=self.SYSTEM_PROMPT,
user_prompt=self._build_prompt(fundamentals, ratios, valuation)
)
return AnalysisReport(
symbol=symbol,
timestamp=datetime.now().isoformat(),
analyst_type="fundamental",
confidence_score=valuation.confidence,
key_findings=analysis.key_findings,
risk_factors=analysis.risk_factors,
valuation_score=valuation.score,
financial_health=ratios.health_status,
growth_potential=valuation.growth_assessment
)
def _calculate_financial_ratios(self, data: Dict) -> FinancialRatios:
"""计算财务比率"""
return FinancialRatios(
# 盈利能力
roe=data.net_income / data.shareholders_equity,
roa=data.net_income / data.total_assets,
gross_margin=data.gross_profit / data.revenue,
net_margin=data.net_income / data.revenue,
# 偿债能力
current_ratio=data.current_assets / data.current_liabilities,
quick_ratio=(data.current_assets - data.inventory) / data.current_liabilities,
debt_to_equity=data.total_debt / data.shareholders_equity,
# 运营效率
asset_turnover=data.revenue / data.total_assets,
inventory_turnover=data.cogs / data.inventory,
# 评估健康度
health_status=self._assess_health(data)
)
3.2 研究团队:多空辩论机制
# app/agents/research_team.py
from enum import Enum
from typing import List, Tuple
class Stance(Enum):
BULLISH = "bullish" # 看多
BEARISH = "bearish" # 看空
NEUTRAL = "neutral" # 中性
class ResearchDebate:
"""研究团队辩论机制"""
def __init__(self, llm_client):
self.bull_researcher = Researcher(llm_client, Stance.BULLISH)
self.bear_researcher = Researcher(llm_client, Stance.BEARISH)
self.debate_rounds = 3
async def conduct_debate(
self,
analysis_reports: List[AnalysisReport]
) -> DebateResult:
"""执行多空辩论"""
# 初始论点
bull_args = await self.bull_researcher.initial_argument(analysis_reports)
bear_args = await self.bear_researcher.initial_argument(analysis_reports)
# 多轮辩论
debate_history = []
for round_num in range(self.debate_rounds):
# 空方反驳多方
bear_rebuttal = await self.bear_researcher.rebuttal(
bull_args, analysis_reports, debate_history
)
# 多方反驳空方
bull_rebuttal = await self.bull_researcher.rebuttal(
bear_args, analysis_reports, debate_history
)
debate_history.append({
"round": round_num + 1,
"bull_argument": bull_rebuttal,
"bear_argument": bear_rebuttal
})
bull_args = bull_rebuttal
bear_args = bear_rebuttal
# 综合评判
final_verdict = self._synthesize_verdict(debate_history)
return DebateResult(
bull_position=bull_args,
bear_position=bear_args,
debate_history=debate_history,
final_stance=final_verdict.stance,
confidence=final_verdict.confidence,
key_points=final_verdict.key_points
)
def _synthesize_verdict(self, history: List) -> Verdict:
"""综合辩论结果"""
# 统计论点强度
bull_strength = sum(h["bull_argument"].strength for h in history)
bear_strength = sum(h["bear_argument"].strength for h in history)
total = bull_strength + bear_strength
bull_ratio = bull_strength / total
if bull_ratio > 0.6:
stance = Stance.BULLISH
elif bull_ratio < 0.4:
stance = Stance.BEARISH
else:
stance = Stance.NEUTRAL
return Verdict(
stance=stance,
confidence=abs(bull_ratio - 0.5) * 2,
key_points=self._extract_key_points(history)
)
3.3 交易员与风险管理
# app/agents/trader.py
class Trader:
"""交易员智能体"""
def __init__(self, llm_client, risk_manager):
self.llm = llm_client
self.risk_manager = risk_manager
async def make_decision(
self,
debate_result: DebateResult,
market_state: MarketState,
portfolio: Portfolio
) -> TradeDecision:
"""做出交易决策"""
# 1. 综合研究团队观点
market_view = self._synthesize_view(debate_result)
# 2. 评估当前持仓
position_analysis = self._analyze_positions(portfolio, market_state)
# 3. LLM 决策推理
decision_prompt = self._build_decision_prompt(
market_view, position_analysis, market_state
)
raw_decision = await self.llm.generate(decision_prompt)
# 4. 风险管理审核
approved_decision = await self.risk_manager.review(
raw_decision, portfolio, market_state
)
return approved_decision
# app/agents/risk_manager.py
class RiskManager:
"""风险管理智能体"""
def __init__(self, risk_profile: str = "neutral"):
self.profile = risk_profile
self.limits = self._load_limits(risk_profile)
async def review(
self,
decision: TradeDecision,
portfolio: Portfolio,
market_state: MarketState
) -> TradeDecision:
"""风险审核"""
# 1. 检查仓位限制
if not self._check_position_limit(decision, portfolio):
decision = self._adjust_position(decision, portfolio)
# 2. 检查止损设置
decision = self._apply_stop_loss(decision, market_state)
# 3. 计算风险敞口
exposure = self._calculate_exposure(decision, portfolio)
# 4. VaR 检查
var = self._calculate_var(portfolio, market_state)
if var > self.limits.max_var:
decision = self._reduce_exposure(decision, var)
# 5. 流动性检查
if not self._check_liquidity(decision, market_state):
decision = self._adjust_for_liquidity(decision, market_state)
return decision
def _calculate_var(
self,
portfolio: Portfolio,
market_state: MarketState,
confidence: float = 0.95
) -> float:
"""计算 VaR(风险价值)"""
# 历史模拟法
returns = portfolio.get_historical_returns()
var = np.percentile(returns, (1 - confidence) * 100)
return abs(var * portfolio.total_value)
四、数据流与编排:LangGraph 状态机
4.1 状态机设计
TradingAgents 使用 LangGraph 进行智能体编排,实现复杂的工作流:
# app/workflow/trading_workflow.py
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
class TradingState(TypedDict):
"""交易工作流状态"""
symbol: str
analysis_reports: Annotated[list, "分析师报告列表"]
debate_result: Annotated[dict, "辩论结果"]
trade_decision: Annotated[dict, "交易决策"]
execution_result: Annotated[dict, "执行结果"]
errors: Annotated[list, "错误列表"]
def build_trading_workflow():
"""构建交易工作流"""
workflow = StateGraph(TradingState)
# 添加节点
workflow.add_node("fundamental_analysis", fundamental_analyst_node)
workflow.add_node("sentiment_analysis", sentiment_analyst_node)
workflow.add_node("technical_analysis", technical_analyst_node)
workflow.add_node("news_analysis", news_analyst_node)
workflow.add_node("research_debate", research_debate_node)
workflow.add_node("trading_decision", trader_node)
workflow.add_node("risk_review", risk_manager_node)
workflow.add_node("execution", execution_node)
# 并行分析
workflow.add_edge("fundamental_analysis", "research_debate")
workflow.add_edge("sentiment_analysis", "research_debate")
workflow.add_edge("technical_analysis", "research_debate")
workflow.add_edge("news_analysis", "research_debate")
# 串行决策
workflow.add_edge("research_debate", "trading_decision")
workflow.add_edge("trading_decision", "risk_review")
workflow.add_edge("risk_review", "execution")
workflow.add_edge("execution", END)
# 设置入口
workflow.set_entry_point("fundamental_analysis")
return workflow.compile()
4.2 并行执行与结果聚合
# app/workflow/parallel_analysis.py
import asyncio
from typing import List
async def parallel_analysis(
symbol: str,
analysts: List[BaseAnalyst]
) -> List[AnalysisReport]:
"""并行执行多个分析师"""
tasks = [analyst.analyze(symbol) for analyst in analysts]
results = await asyncio.gather(*tasks, return_exceptions=True)
# 处理异常
successful_results = []
for i, result in enumerate(results):
if isinstance(result, Exception):
logger.error(f"Analyst {analysts[i].__class__.__name__} failed: {result}")
else:
successful_results.append(result)
return successful_results
五、性能优化策略
5.1 LLM 模型选择与配置
根据任务复杂度选择合适的模型:
# app/config/model_config.py
MODEL_CONFIG = {
# 快速响应任务
"data_retrieval": {
"model": "gpt-4o-mini",
"temperature": 0.1,
"max_tokens": 1000
},
# 中等复杂度分析
"analysis": {
"model": "claude-3-5-sonnet",
"temperature": 0.3,
"max_tokens": 2000
},
# 深度推理任务
"decision_making": {
"model": "claude-3-opus",
"temperature": 0.5,
"max_tokens": 4000
},
# 辩论任务(需要创造性)
"debate": {
"model": "gpt-4o",
"temperature": 0.7,
"max_tokens": 3000
}
}
5.2 缓存策略
# app/services/cache_service.py
from functools import lru_cache
import redis
import json
class AnalysisCache:
"""分析结果缓存"""
def __init__(self, redis_client: redis.Redis):
self.redis = redis_client
self.ttl = 3600 # 1小时
def get_or_compute(self, key: str, compute_func, *args):
"""获取缓存或计算"""
cached = self.redis.get(key)
if cached:
return json.loads(cached)
result = compute_func(*args)
self.redis.setex(key, self.ttl, json.dumps(result))
return result
def invalidate_pattern(self, pattern: str):
"""批量失效缓存"""
keys = self.redis.keys(pattern)
if keys:
self.redis.delete(*keys)
5.3 异步与批处理
# app/services/batch_processor.py
class BatchAnalysisProcessor:
"""批量分析处理器"""
def __init__(self, batch_size: int = 10):
self.batch_size = batch_size
self.queue = asyncio.Queue()
async def enqueue(self, symbols: List[str]):
"""入队"""
for symbol in symbols:
await self.queue.put(symbol)
async def process_batch(self):
"""批量处理"""
batch = []
while len(batch) < self.batch_size:
try:
symbol = await asyncio.wait_for(
self.queue.get(),
timeout=1.0
)
batch.append(symbol)
except asyncio.TimeoutError:
break
if batch:
# 批量获取数据
market_data = await self._fetch_batch_data(batch)
# 并行分析
tasks = [self._analyze(symbol, market_data[symbol])
for symbol in batch]
results = await asyncio.gather(*tasks)
return dict(zip(batch, results))
六、实战案例:性能验证
6.1 实验设置
实验使用 2024 年 1 月至 3 月的多资产、多模态金融数据集,在 2024 年 6 月至 11 月的交易环境中进行模拟。
6.2 策略对比
| 策略 | 累积回报 | 年化回报 | 夏普比率 | 最大回撤 |
|---|---|---|---|---|
| TradingAgents | 26.62% | 53.24% | 8.21 | -5.3% |
| 买入持有 | 12.45% | 24.90% | 1.85 | -15.2% |
| MACD 策略 | 8.32% | 16.64% | 0.92 | -12.8% |
| KDJ&RSI 策略 | 5.67% | 11.34% | 0.65 | -18.5% |
| SMA 策略 | 3.21% | 6.42% | 0.38 | -22.1% |
6.3 关键发现
- 多维度分析的价值:TradingAgents 在累积回报上显著优于单一策略,证明了多维度综合分析的有效性
- 辩论机制的作用:多空辩论避免了单一视角的盲区,在市场转折点表现出更好的适应性
- 风险控制的效果:最大回撤控制在 5.3%,显著低于其他策略
七、部署指南
7.1 Docker 部署
# docker-compose.yml
version: '3.8'
services:
tradingagents:
build: .
ports:
- "8000:8000"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
- MONGODB_URI=mongodb://mongodb:27017/tradingagents
- REDIS_URL=redis://redis:6379
depends_on:
- mongodb
- redis
volumes:
- ./config:/app/config
- ./logs:/app/logs
mongodb:
image: mongo:7.0
volumes:
- mongodb_data:/data/db
ports:
- "27017:27017"
redis:
image: redis:7.2-alpine
volumes:
- redis_data:/data
ports:
- "6379:6379"
volumes:
mongodb_data:
redis_data:
7.2 配置文件
# config/settings.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# API 配置
openai_api_key: str
anthropic_api_key: str
deepseek_api_key: str = ""
# 数据库配置
mongodb_uri: str
redis_url: str
# 智能体配置
default_risk_profile: str = "neutral"
debate_rounds: int = 3
analysis_cache_ttl: int = 3600
# 交易配置
max_position_size: float = 0.1 # 单只股票最大仓位
max_portfolio_var: float = 0.02 # 最大 VaR
class Config:
env_file = ".env"
settings = Settings()
7.3 启动服务
# 克隆项目
git clone https://github.com/TradingAgents-AI/TradingAgents.git
cd TradingAgents
# 配置环境变量
cp .env.example .env
# 编辑 .env 填入 API Keys
# Docker 启动
docker-compose up -d
# 查看日志
docker-compose logs -f tradingagents
八、最佳实践与注意事项
8.1 数据源选择
| 数据源 | 特点 | 适用场景 |
|---|---|---|
| AKShare | 免费、无需 API Key | 个人研究、快速验证 |
| Tushare | 专业数据、需 Token | 生产环境、高质量需求 |
| BaoStock | 轻量级 | 快速查询、历史回测 |
8.2 模型选择建议
- 数据检索任务:使用快速模型(gpt-4o-mini),降低延迟和成本
- 深度分析任务:使用推理能力强的模型(claude-3-opus)
- 辩论任务:使用创造性较好的模型,温度设置 0.7+
8.3 风险控制要点
- 始终设置止损:每笔交易都应有明确的止损点位
- 控制仓位:单只股票仓位不超过总资金的 10%
- 监控 VaR:组合 VaR 控制在预设阈值内
- 流动性检查:大额交易前检查市场深度
九、总结与展望
TradingAgents 代表了金融 AI 的一个重要方向:从单一模型走向多智能体协作。通过模拟专业交易公司的组织结构,它实现了:
- 角色专业化:每个智能体专注于特定分析维度
- 辩论机制:多空对抗形成平衡的市场观点
- 结构化通信:减少信息损失,提高协作效率
- 风险控制:多层次风险管理保障交易安全
随着框架的不断完善,TradingAgents 有望在以下方向继续演进:
- 实时交易支持:从回测走向实盘
- 更多市场覆盖:支持期货、期权、加密货币
- 强化学习集成:让智能体从历史交易中学习
- 可解释性增强:提供更透明的决策路径
对于开发者而言,TradingAgents 不仅是一个交易框架,更是一个学习多智能体系统设计的绝佳案例。它的架构思想——角色分工、辩论机制、结构化通信——可以迁移到其他需要复杂决策的场景中。
参考资料
本文首发于程序员茄子(chenxutan.com),转载请注明出处。