第 11 课 · 研报解读 Agent

卖方研报天然偏多——这节课教你用"抽取式 Prompt + 一致性核对"批判性地读它,而不是被它带着走

预计用时:40 分钟 上一课:第 10 课 · 政策与公告数据

这节课你将得到什么

一个能跑的研报解读 Agent 雏形(scripts/report_reader.py):输入一篇券商研报(本课内置一篇"茅台提价点评"样本),输出一份结构化 JSON——评级、目标价、核心逻辑 3 条、风险点 2 条,每条结论都附原文逐字引用;再加一项本课独有的检查:一致性核对——把研报里涉及公告的说法,逐条与第 10 课核对的公告原文比对。最后由程序生成一段"人话摘要"。

第 10 课你拿到了"事实"(公告原文),这节课处理的是"观点"(券商对事实的解读)。事实可以信,观点必须审——这正是研报在 TradingAgents 团队里对应"基本面分析师"角色时,你必须给它套上的缰绳。

一、研报的立场偏差:先建立正确的怀疑

A 股市场上你免费能看到的研报,几乎全部是卖方研报——券商研究所写给客户(主要是基金等机构)看的。记住它的商业模式:研究所本身不卖研报赚钱,它靠基金分仓佣金与上市公司的投行业务关系吃饭。这决定了两个系统性偏差:

对策:用第 5 课的"证据引用"要求它

第 5 课的纪律是"每条结论必须挂证据来源"。对付研报,这条纪律要升级成更狠的版本:每条抽取的结论必须附研报原文的逐字引用(quote),不许改写。模型想替券商粉饰结论时,引用会出卖它——"近期批价回落属于淡旺季切换的正常波动"这句话一旦原文照抄摆在你面前,"证据呢?"三个字你自然问得出口。脚本里的 validate() 甚至会逐字校验 quote 是否真的出现在研报原文里,模型编造引用会直接报错。

二、抽取式 Prompt vs 生成式 Prompt(本课的知识核心)

同样读一篇研报,两种问法得到两种东西:

生成式 Prompt抽取式 Prompt(本课)
问法"帮我总结一下这篇研报""按这个 JSON schema 抽取字段,每条附原文引用"
产出一段流畅的散文摘要结构化 JSON,可进流水线
幻觉风险——模型会"顺嘴"补充研报里没有的常识——quote 字段把每句话锚定在原文上
立场容易被研报的语气带跑("强烈看好"式复述)抽取动作本身是中性的,偏差留在原文里供你审

经验法则:要"读懂",用生成式;要"采数据",用抽取式。你的量化流水线要消费的是数据——评级、目标价、盈利预测这些字段将来要入库、要跨研报聚合,所以必须是抽取式。摘要可以要,但那是最后一步、且由程序按模板生成(见脚本 human_summary()),不让 LLM 二次创作。

三、一致性核对:让研报跟公告原文对质

第 10 课你从公告原文核对出的事实是基准:零售价 1539 → 1639 元/瓶、合同价上调至 1369 元/瓶、2026-07-18 零时起执行。本课的设计是把这份"标准答案"直接塞进 Prompt,要求模型逐条核对研报的说法:

{"claim": <研报中涉及公告事实的说法>,
 "announcement": <对应的公告事实>,
 "verdict": <"一致"|"不一致"|"无法核对">}

这不是花架子——本课的内置样本研报里埋了一个真实的坑:研报把零售价写成了 1649 元(公告实为 1639 元)。真实世界里,二手转述、深夜赶工的点评报告写错数字并不罕见;而你的流水线如果直接采信 1649,后面所有测算都建在错的基数上。凡是涉及具体数字的观点,都要能回溯到一手事实。

四、动手:跑起来(无需 API Key,不访问网络)

演示模式使用预计算的抽取结果,先聚焦流程和输出结构:

cd "$HOME/AI Project/Quant Learning"
source .venv/bin/activate
python scripts/report_reader.py

你会看到(我已在你的环境实测通过,JSON 较长,中间字段省略):

抽取方式:演示模式(预计算结果)
输入:内置研报样本(XX证券·茅台提价点评)+ 第10课公告事实基准

============================================================
结构化抽取结果(JSON,可直接进你的流水线/数据库)
============================================================
{
  "rating": "买入(维持)",
  "target_price": 1980.0,
  "key_logic": [
    {
      "point": "提价直接增厚业绩(券商预测:2026年净利润约+6%,是预测不是事实)",
      "quote": "我们测算本次提价可增厚2026年营收约4%"
    },
    ……共 3 条,每条带 quote……
  ],
  "risks": [ ……共 2 条…… ],
  "consistency_check": [
    {
      "claim": "零售价由1539元/瓶上调至1649元/瓶",
      "announcement": "零售价由1539元/瓶调整为1639元/瓶",
      "verdict": "不一致"
    },
    ……另外 2 条 verdict 为"一致"……
  ],
  "sell_side_bias_note": "全文无一处看空表述,把'批价回落'直接定性为'正常波动'却不给数据支撑——典型卖方口吻。"
}

============================================================
人话摘要(程序按模板生成,不经过 LLM)
============================================================
这篇研报的评级是「买入(维持)」,目标价 1980 元。
核心逻辑 3 条:提价直接增厚业绩(券商预测:2026年净利润约+6%,是预测不是事实);零售价与合同价双升,渠道利润未被压缩;批价回落被定性为正常波动,无需担忧。
风险提示 2 条:宏观消费复苏不及预期;渠道批价持续下行。
一致性核对:3 条说法中有 1 条与公告原文不符(研报称零售价由1539元/瓶上调至1649元/瓶,公告实为零售价由1539元/瓶调整为1639元/瓶)——数字都能写错,这篇研报的其余说法也要打折看。
立场提醒:全文无一处看空表述,把'批价回落'直接定性为'正常波动'却不给数据支撑——典型卖方口吻。

注意人话摘要是程序按模板拼的,不经过 LLM——"3 条中 1 条不一致"这种计数和判断,让代码做,可复现、可测试。LLM 只负责它不擅长被替代的那部分:读懂研报。

五、接入真实模型(可选,课后完成)

真实模式与第 3、5 课同一套约定:LLM_API_KEY 必填,LLM_BASE_URL(默认 https://api.deepseek.com)、LLM_MODEL(默认 deepseek-chat)可选:

export LLM_API_KEY="sk-你的key"
python scripts/report_reader.py --live

真实模式已写好但尚未实测(你机器上还没有 Key)——拿到 Key 后跑一次,有报错直接贴给我。拿到 Key 后建议做一个实验:把 SYSTEM_PROMPT 里的 quote 纪律删掉再跑,对比幻觉率,你会对第二节的表格有切身体会。

六、概念进阶:多份研报的共识与分歧聚合

一篇研报是一家之言。真正的价值在横向聚合——把同一时点多家券商的抽取结果放在一起比较。本课不展开代码(留给你做挑战),但心智模型要先建好:

落到你的实盘辅助决策:盘后 Agent 把当天新发的自选股研报抽成 JSON 入库,聚合出"共识/分歧/边际变化"三行摘要摆在你面前——T+1 制度下,你有整个晚上消化这些信息、为明天写计划,不需要盘中追着研报跑。

动手挑战(可选,20 分钟)

SAMPLE_REPORT 复制一份改成另一家券商的"谨慎派"点评(评级"增持"、目标价 1700 元、强调批价回落风险),修改 DEMO_RESULT 后重跑脚本。然后写 20 行代码:读两个 JSON,输出两家的目标价差和分歧点列表——这就是第六节的雏形。

自测

凭记忆作答——答错比答对更能加固记忆。

延伸阅读

下一课预告

第 12 课 · 宏观数据与择时:个股消息之外,把 CPI、社融、利率这些宏观变量接进你的数据底座,讨论一个诚实的问题——宏观数据到底能不能用来择时,以及 Agent 在这里能帮什么、不能帮什么。

有任何不清楚的地方(比如 quote 校验的实现、一致性核对的 Prompt、聚合口径的设计),直接问我——我是你的老师。