mirror of
https://github.com/simonlin1212/TradingAgents-astock.git
synced 2026-08-31 01:23:38 +00:00
#39 role_llms(默认关闭,行为不变) 同一模型分饰多空两角时倾向自我附和,辩论失去意义。现在可给单个角色指定另一家 模型。16 个可配角色,agent 文件一个都没动——工厂签名本来就统一吃 llm。 - 角色名写错当场报错,不静默忽略 - 相同 provider+model 复用同一实例,不会开 N 条连接 - 换 provider 不继承主 provider 的 backend_url - 与订阅覆盖并用时点名警告哪些角色会绕开订阅计费 #61 情绪分析师数据驱动 此前只有 get_news,只能从新闻语气推断情绪。补上 get_fund_flow / get_stock_data / get_hot_stocks,提示词改为「先看资金再看新闻」,强制报出「资金面与消息面是否 背离」。ToolNode 同步注册,并加测试锁死两处一致性。 承接 #90:修掉 v0.4.1 自己引入的退步 全表不可用时会跑 bestip 全表测速,首次调用实测 >170s。根因是协议层失败没被计数 ——这批服务器在 Quotes.factory 握手期就抛错,走不到取数验证那步。修正计数、协议 被拒时跳过 bestip(同协议同主机,不可能有别的结果)、连续 3 台失败即停手。 实测 >170s → 18.7s,二次调用 0ms。报错据实区分「连不上」与「协议被拒」。 测试:新增 21 例,全量回归 243 passed (11 failed 为缺可选依赖 claude_agent_sdk 的既有失败)
68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
"""数据驱动的情绪分析师(#61)。
|
|
|
|
情绪分析师原本只有 `get_news` 一个工具,只能从新闻语气推断情绪——而"新闻听起来
|
|
利好"和"资金正在流出"完全可能同时发生。现在补上资金流 / 量价 / 强势股榜三样硬
|
|
数据。
|
|
|
|
这里锁的是两件最容易漂的事:
|
|
1. 分析师绑定的工具 与 图里 ToolNode 注册的工具 必须一致——不一致时模型会调用一个
|
|
图里不存在的工具,直接报错,而且只在真跑分析时才暴露。
|
|
2. 提示词点名的工具必须真的绑上了——否则模型按提示词去调,调不到。
|
|
"""
|
|
|
|
import inspect
|
|
import re
|
|
|
|
from tradingagents.agents.analysts import social_media_analyst as sma
|
|
|
|
|
|
def _tool_names_in_source(func) -> set:
|
|
"""从 create_social_media_analyst 源码里取出 tools 列表的成员名。"""
|
|
src = inspect.getsource(func)
|
|
block = re.search(r"tools = \[(.*?)\]", src, re.S)
|
|
assert block, "找不到 tools 列表"
|
|
return {t.strip().rstrip(",") for t in block.group(1).split("\n") if t.strip().rstrip(",")
|
|
and not t.strip().startswith("#")}
|
|
|
|
|
|
EXPECTED_TOOLS = {"get_news", "get_fund_flow", "get_hot_stocks", "get_stock_data"}
|
|
|
|
|
|
def test_analyst_binds_quantitative_tools():
|
|
"""光有新闻不足以判断情绪,资金流/量价/热度榜必须都在。"""
|
|
assert _tool_names_in_source(sma.create_social_media_analyst) == EXPECTED_TOOLS
|
|
|
|
|
|
def test_graph_tool_node_matches_analyst_tools():
|
|
"""图里注册的 social 工具必须与分析师绑定的一致,否则运行时才炸。"""
|
|
import tradingagents.graph.trading_graph as tg
|
|
|
|
src = inspect.getsource(tg.TradingAgentsGraph._create_tool_nodes)
|
|
social_block = re.search(r'"social": ToolNode\(\s*\[(.*?)\]\s*\)', src, re.S)
|
|
assert social_block, "找不到 social 的 ToolNode 定义"
|
|
registered = {
|
|
t.strip().rstrip(",")
|
|
for t in social_block.group(1).split("\n")
|
|
if t.strip().rstrip(",") and not t.strip().startswith("#")
|
|
}
|
|
assert registered == EXPECTED_TOOLS
|
|
|
|
|
|
def test_prompt_names_every_bound_tool():
|
|
"""提示词点名的工具必须真的绑上了,否则模型照着调会调空。"""
|
|
src = inspect.getsource(sma.create_social_media_analyst)
|
|
for tool in EXPECTED_TOOLS:
|
|
assert f"`{tool}(" in src, f"提示词里没有引导模型使用 {tool}"
|
|
|
|
|
|
def test_prompt_requires_divergence_check():
|
|
"""资金面与消息面背离是这次改造最有价值的产出,必须强制写进报告。"""
|
|
src = inspect.getsource(sma.create_social_media_analyst)
|
|
assert "背离" in src
|
|
|
|
|
|
def test_prompt_forbids_fabricating_missing_data():
|
|
"""取不到数就标注缺失,不许用新闻语气编一个数字出来。"""
|
|
src = inspect.getsource(sma.create_social_media_analyst)
|
|
assert "数据缺失" in src
|