FinRobot 失败案例实验室 / AI4Finance-Foundation
FinRobot 失败案例实验室:报错原文、数字血缘与后验评估
只展示成功截图的项目介绍没有判断价值。本页收集的是「这套系统在什么条件下会自己停下来、会输出什么报错、根因在哪一层」:本站在本机真跑官方确定性算子,触发了四道估值闸门与两类输入校验,并把这些原文报错逐条记下来。全部案例都能用固定 commit 的源码核对,不用相信我转述。
这批失败案例分别在什么条件下会被触发?
下表是全页导航。最后一列写清了证据强度:标「本站实测」的是我在本机真跑出来的输出与报错原文;标「源码/注释」的来自仓库代码及其注释,能定位到具体文件。
| 案例 | 拦截层 | 触发条件 | 证据强度 | 为什么值得你知道 |
|---|---|---|---|---|
| 终端增长率 ≥ WACC | 估值算子 | 模型给的 tg 超过或接近折现率 | 本站实测(报错原文) | Gordon 永续式在数学上失效,继续算就是编数字 |
| WACC 与 tg 利差过薄 | 估值算子 | 利差低于 1.5%(低利率、高杠杆标的常见) | 本站实测(报错原文) | 乘数会爆炸成几百倍,站内实测出现过 294× |
| 稳态终端自由现金流 ≤ 0 | 估值算子 | 低毛利叠加高资本开支 | 本站实测(报错原文) | 负现金流会被资本化成负终值,算出负的「每股价值」 |
| 净负债超过企业价值 | 估值算子 | 高杠杆或现金流失衡 | 本站实测(报错原文) | 股本价值为负没有经济含义,代码注释称之为 BUG-074 的镜像 |
| 输入里出现 NaN | 输入校验 | 数据源缺值被原样传进算子 | 本站实测(报错原文) | NaN 通过所有比较运算,不拦住就会把 NaN 一路带到结论 |
| ΔNWC 比例越界 | 输入校验 | 营运资本假设超出 ±50% 建模带 | 本站实测(报错原文) | 坏假设在很早期就被拒绝,而不是算出一个离谱结果 |
| 给银行股套 FCF-DCF | 流程层(类目判断) | 标的被判为金融业 | 本站实测 + 源码注释 | 代码注释记录了曾出现「DCF 719 对现价 325」的荒谬 2.2 倍估值行 |
| 叙述里没有任何数字 | 审计算子 | LLM 写出「估值有吸引力」这类无据表述 | 本站实测 + 源码注释 | 项目自己的盲审发现过 GOOGL/MSFT/KO 报告出现这类段落 |
| 数据缺失后的降级 | 输出与制品层 | 同业数据、历史估值带、前瞻指标缺项 | 本站实测(警告原文) | 方法行会被隐藏并留下警告,而不是拿占位数据凑数 |
| 版本错配(PyPI 装到零依赖 V0) | 环境层 | 照老教程用 pip install finrobot | 本站实测(PyPI + sdist 核查) | 「装上了」与「能用」是两件事,详见安装页与版本页 |
估值算不出来时,系统会怎么拒绝?
下面六条全部是本机真跑官方算子得到的原始报错(合成输入,非真实行情)。它们对应的是同一套估值算子里不同的前置判断,所以报错文本各不相同——这正是你排查时该抓的东西。
| 触发输入 | 实际输出(原文) | 根因 | 系统给出的解法 | 残余风险 |
|---|---|---|---|---|
| 终端增长率 0.05、折现率被压到 0 | Terminal growth rate 0.05 must be less than WACC 0.0 (Gordon Growth Model perpetuity is undefined when tg >= wacc) | 永续增长模型在 tg ≥ WACC 时数学上无定义 | 拒绝计算,由流水线回落到相对估值 | 回落后你拿到的是倍数法区间,不是内在价值 |
| 低利率 + 高杠杆,使 WACC 与 tg 利差降到 0.34% | WACC−terminal growth spread 0.34% is below the 1.5% minimum — the Gordon multiplier (1/(wacc−tg) = 294×) … | 乘数被利差放大,0.34% 对应 294 倍 | 以 1.5% 为下限拒绝,提示改用相对估值 | 利差在 1.5%–3% 之间的标的仍会得到很宽的估值区间 |
| EBITDA 利润率降到 2%、资本开支 6% | Steady-state terminal FCF is non-positive (-5.94); …a negative implied price. DCF is not applicable… | 稳态现金流为负,Gordon 会资本化成永续负值 | 拒绝计算,跳过 DCF 章节 | 真处于衰退期的公司本就该用别的框架,这里只是避免输出负价格 |
| 净负债放大到 100000(企业价值仅 2510) | Equity value is non-positive (-9.75e+04): net debt (1e+05) exceeds the enterprise value (2.51e+03). A negative per-share fair value is not meaningful… | 股本价值为负没有经济含义(股本更像一个下限为零的期权) | 拒绝计算,提示改用相对估值或困境/信用分析 | 真实高杠杆标的仍需人工判断是否处于困境 |
| 营收基数传入 NaN | ValidationError: revenue_base / Value error, must be finite — NaN/Inf is not a number, it's missing data | NaN 与任何数比较都为假,会绕过算子里所有区间判断 | 在校验层直接拒绝(带界字段天然拒绝 NaN,无界字段单独加校验) | 上游数据源若返回空值而非 NaN,仍可能被解释成 0 |
| ΔNWC 占营收 0.9 | ValidationError: nwc_pct_revenue / Input should be less than or equal to 0.5 | 假设超出建模带,属于口径错误而非极端情形 | 字段级边界拒绝,给出允许区间 | 区间内的坏假设仍会通过,需要你自己把关 |
2717499 取出 finrobot_desktop/finrobot/engine/compute/operators/ 与 models/,用本机 Python 3.11.9 直接调用 calculate_dcf 即可得到同样文本——这些算子是纯 Python,不需要 LLM,也不需要联网。输入是本站构造的合成数据,仅用于观察行为,不代表任何真实标的。给银行股套 DCF 会发生什么?
这不是数值问题,而是用错方法的问题:银行的「自由现金流」和「净负债」本身定义就不成立——债务是它的原材料,不是融资手段。项目处理方式值得单独看:它按行业类别把方法整体撤下,而不是硬算。
| 观察点 | 实际行为 | 说明 |
|---|---|---|
| 代码里有没有这类判断 | 有:入参带 financial_sector 标记,估值聚合器按它抑制现金流类方法 | 判断依据来自行业识别原语(是否银行/保险) |
| 本机实测(金融业标记打开) | 现金流类方法全部被撤下,返回的方法数为 0,point_target 与 confidence 均为空 | 系统没有给出一个「看起来像结论」的数字 |
| 同时给出的警告(原文节选) | dcf: financial-sector issuer — FCF-DCF does not apply… method withheld、ev_ebitda: …enterprise value is a category error for banks (debt is raw material, not financing) — method withheld | 不是静默隐藏,而是留下「为什么撤下」的理由 |
| 为什么值得警惕 | 代码注释记录了历史现象:某银行标的曾出现 DCF 结果与现价差 2.2 倍(约 719 对 325) | 那类结果会污染货币权重与分歧判断 |
| 正确做法 | 银行/保险改用 P/B、P/E 与股利折现(DDM)为主 | 这是行业惯例,也是项目在代码里写下的取舍 |
| 残余风险 | 行业识别本身可能误判(例如金融控股、租赁类) | 判断错时方法会被错误撤下或错误启用;上线前需人工确认标的类别 |
「数字由代码算」之外,LLM 写的那部分怎么防?
数字可以交给算子,但叙述仍是模型写的。项目为此加了一个审计算子,专门检查叙述里有没有没有任何数字支撑的段落。它的由来写在源码注释里,是一次真实的盲审。
| 项目 | 内容 |
|---|---|
| 盲审发现的三个实例(源码注释原文转述) | GOOGL 用被夸大的头条市盈率为「估值有吸引力」背书,却略过了自己的核心市盈率;MSFT 的多头理由只有「护城河强」这类没有数字的表述;KO 的催化剂条目既没有日期也没有量级 |
| 怎么判定「有数字」 | 剔除纯年份(1900–2099)与序数词(1st/2nd…)后,若还剩任意数字才算有支撑——避免把「2025 年」误当成数字依据 |
| 本机实测:无据叙述 | 返回告警原文 [NARRATIVE-NUMERIC] 3 narrative field(s) carry no supporting number (narrative, catalysts[0], risks[0]) … |
| 本机实测:带数字叙述 | 同一算子返回 None(无告警) |
| 它不会做什么 | 只产出非阻塞警告,从不修改结论方向、目标价与置信度 |
| 设计取舍 | 它是「轻量信号」:不做货币/百分比语义解析,也不逐条比对提示词白名单,宁可漏报也不误报 |
| 残余风险 | 句子里碰巧带了个无关数字(例如文件条目号)也会被算作「有支撑」 |
数据缺失时会发生什么?三种降级行为
「取数失败」在多数系统里表现为静默的空表,之后被当成 0 或用别的数据凑上。这里记录三种可核对的降级行为,并标出你要补的输入。
| 缺失项 | 系统的实际行为 | 你该补什么 |
|---|---|---|
| 同业比较数据(comps 制品) | 警告原文:comps_pe: no peer_analysis artifact — this row appears after running the full AI report;对应方法行不出现 | 跑完整研报流程,让同业分析制品先产出 |
| 历史估值带或 TTM EBITDA | 警告原文写明「multiple row degraded and hidden」——方法行被降级隐藏,而不是用 0 或均值顶上 | 确认该标的的历史估值数据与 TTM 口径可获取 |
| 前瞻自由现金流 | 同样以降级隐藏处理(P/FCF 行缺失并留警告) | 补齐前瞻指标来源,或接受更少的方法数 |
| 蒙特卡洛里的无效路径 | 本机实测 2000 条里 1996 条有效,其余被丢弃;结果只统计有效路径 | 不用处理,但要知道分位数来自有效子集 |
| 只有单一估值方法时 | 该方法区间会被标注为占位带,原文:implied_price ± 20% (placeholder band, not a real distribution) | 补第二种方法,否则不要把这个区间当统计分布 |
| 数据提供方整体不可用 | 7 个提供方共用接口、带健康状态(可用/已保存/可选/冷却中),故障时按状态切换 | 至少确认两个提供方可用,避免单点 |
版本与文档错配会怎么失败?系统不会替你拦的那一类
前面几组是系统主动拒绝,这一组是系统不会拒绝、但结果一定不对的情形——它们更常见,也更容易让人误判「这个项目不行」。
| 现象 | 真实原因 | 核对方式 | 正确做法 |
|---|---|---|---|
pip install finrobot 装完却 ModuleNotFoundError: No module named 'finnhub' | PyPI 上是 2024-06-17 的 0.1.5,sdist 里没有依赖清单文件,打包时依赖列表被置空 | 看包元数据里有没有 Requires-Dist;看 sdist 里有没有 requirements.txt | V0 走仓库根 pip install -e .;要 V2 走 uv sync |
| 按文章里的目录找不到 notebook | 教程目录已迁到 finrobot_autogen/,且分为 beginner / advanced 两层 | 在固定 commit 的仓库树里核对路径 | 按当前仓库路径执行 |
| 想调用 README 里提到的调度器却发现没有 | README 的「Research foundation」段保留的是论文期设计说明,当前仓库没有对应实现 | 在仓库里搜索对应模块名 | 按 V2 的类型化流水线思路理解编排 |
| 用 3.12 装不上 V0 包 | PyPI 元数据限定 >=3.10, <3.12;V2 则要求 >=3.11 | 看两边包定义里的 Python 约束 | V0 用 3.10/3.11 环境,V2 用 3.11+ 环境,分开建 |
| 两个版本装在同一环境互相覆盖 | 发布名与导入名都落在 finrobot 上 | 检查同一环境里是否出现两份包记录 | 一个版本一个隔离环境 |
| 拿 V0 的输出当研究结论 | 官方明确 V0 没有确定性计算层与溯源跟踪,不保证数字是算出来的 | 看官方 README 对 V0 的定位表述 | 需要可追溯结果就用 V2 |
数字血缘:怎么判断一个数字是谁产生的?
适用任何金融 AI 输出,不限于本项目。核心是把输出里的每一项拆进三个桶,然后对每个桶采取不同的信任策略。
| 桶 | 怎么识别 | 信任策略 | 本项目里的对应物 |
|---|---|---|---|
| 代码算出来的 | 能对应到具体函数调用与入参;改一个假设,数字会按确定规则变化 | 可以复核:重算一遍应得同样结果 | 26 个估值算子(DCF/DDM/LBO/倍数/蒙特卡洛/SOTP/剩余收益等) |
| 模型写出来的 | 段落、观点、定性与因果解释;无法回溯到某个函数 | 当观点处理:不做结论,只做线索 | 研报叙述、催化剂与风险条目、章节小结 |
| 两者混合 | 数字来自算子、结论来自模型(例如「目标价 23.1,较现价有 15% 上行空间」) | 拆开看:数字复核,判断打折 | 投资论点、评级与目标价表述、置信度说明 |
| 审计产生的 | 警告、降级标记、撤回决策 | 优先读:它告诉你哪一部分不可信 | 6 个审计算子(币种口径、EV 桥、叙述分歧、数字绑定性、行业符号、TTM 期间) |
2717499)③ 模型与数据源(模型名、数据来自哪个 provider、有无免费额度限制)④ 命令与输入(完整命令 + 输入参数;合成数据要写明是合成的)⑤ 输出与耗时(原始输出片段 + 单次运行时长)。本站自己就是按这五要素记录的:环境 Windows 10 / Python 3.11.9;版本 commit 2717499;模型 无(纯算子);输入 本站构造的合成标的;输出 WACC 9.509%、隐含价 23.0774、蒙特卡洛中位 23.11。有了这五行,别人才能真正复核你,而不是只能相信你。
怎么给一次金融 AI 输出打分?
不要只看结果对不对(一次运行说明不了什么),要看它是否具备可复核的结构。下面这张表可以直接当验收清单用。
| 评测维度 | 通过标准 | 不通过时的表现 | 怎么查 |
|---|---|---|---|
| 事实准确性 | 公司名、行业、报告期、币种与官方一致 | 币种混用、报告期错位 | 抽一条关键事实回官方披露核对 |
| 数字准确性 | 关键数字能被独立重算 | 数字无法回溯到任何计算 | 用同一套假设手算 DCF 的头一段 |
| 口径一致性 | 单位、币种、期间在全篇统一 | 同一指标前后单位不同 | 搜币种符号与单位词,看是否漂移 |
| 引用完整性 | 数据来源可指名到 provider 与时间 | 只写「根据市场数据」 | 查制品里有没有取数时间戳 |
| 可复现性 | 同环境同输入可得到同样结果 | 换个时间跑结果就变,且原因不明 | 固定随机种子重跑(本项目的蒙特卡洛支持 seed) |
| 失败可见性 | 缺数据时给出警告或降级标记 | 缺数据静默填 0 或省略不提 | 看输出里有没有 warning 通道 |
| 成本与延迟 | 记录单次运行的模型调用量与耗时 | 只有结果没有账单 | 按任务规模分档记录(单标的/单板块/多标的) |
| 后验校验 | 把「方向性判断」和「实际结果」分开记录,不混着算胜率 | 用后见之明宣布模型很准 | 事前写下判断与依据,事后单独复盘 |
最后一句边界:任何历史回测与方向性预测都不构成收益承诺;本页所有数值来自本站构造的合成输入,仅用于观察系统行为,不构成投资建议。
FinRobot 失败与审计常见问题
为什么一个估值系统要设计这么多「拒绝计算」?
因为金融模型失效的方式往往不是算错,而是在不适用的情况下仍然给出数字。永续增长、负现金流、负股本价值这几类情形都会产生数学上成立、经济上无意义的解。与其输出一个会被误用的数,不如停下来并告诉调用方「改用相对估值」。官方 README 也是这么定位的:模型负责推理、软件负责计算、系统负责验证。
这些报错原文我能自己复现吗?
可以。相关算子在 finrobot_desktop/finrobot/engine/compute/operators/ 下,是纯 Python,不依赖 LLM 与网络,只需要装了 pydantic 的环境。按固定 commit 取出代码,构造同样的输入即可得到同样文本。本站的实测环境是 Windows + Python 3.11.9,输入是合成数据。
「数字由代码算」之后,我是不是就可以相信结论了?
不是。代码算解决的是数字不被编造,但没有解决假设是否合理、方法是否适用、以及方向性判断是否成立。假设是模型选的或你填的,方法适用性由类目判断决定,方向性结论仍然只是观点。事实底稿、源码路径与固定 commit 都写在页面里,建议你自己抽一两项核对。
审计算子报警了,报告就会被拦下吗?
不会。以叙述数字绑定性这个算子为例,它只产出非阻塞警告,放进输出的警告通道,不会改写结论方向、目标价与置信度。设计上它是「轻量信号」而不是守门人——这一点在源码注释里写得很明确。真正会拦截输出的是前面的估值闸门与输入校验。
缺数据时会不会悄悄用 0 或平均值顶上?
从实测看不会。缺少同业数据、历史估值带或前瞻指标时,对应方法行会被降级隐藏并留下写清原因的警告;方法只有一种时,区间会被标注成「占位带,不是真实分布」。这正是判断一套输出是否诚实的线索:看它缺数据时是沉默还是留痕。
什么样的失败才是真正要担心的?
系统主动拒绝的那些反而不是问题——它们可见、可查、可复现。真正要担心的是不会报错的那一类:版本装错(PyPI 上零依赖的旧包)、路径变了、把论文期设计当成现成实现、用错方法但算得出来。这些只能靠「先确认版本与环境、再确认方法与假设、最后才看结论」的流程来防。
这套审计思路只能用在 FinRobot 上吗?
不是。三个桶(代码算 / 模型写 / 混合)与可复现记录五要素对任何金融 AI 输出都适用。你甚至可以对别的工具用同一套问法:这个数字能回溯到哪一步计算?缺数据时它怎么表现?换一天跑结果会不会变?这三个问题答不上来的工具,输出就只适合当线索。