ReportLens Agent 复盘
2026.05.24 — 2026.05.25 · Bug Retrospective

ReportLens 全项目 Bug 复盘

这次跑通财报 Agent 的关键收获是:真正危险的不是“AI 不会写”,而是外部数据源、文件格式、状态一致性、上传路径、Prompt 约束和人工运维这些工程细节没有被系统性兜住。后续开发要把每一个环节都做成可验证、可回滚、可复盘的流水线。

Total Bugs12覆盖数据源、解析、部署、状态、后台和内容质量。
P0 + P16会直接影响报告生成或用户信任。
Core Lesson验证任务成功、下载成功、AI 输出成功,都不等于内容可信。

一句话结论

ReportLens 的核心工程原则应该从“让 AI 自动生成报告”,升级为“让系统每一步都有证据链”。 对外部 ID 要核验,对下载文件要验真,对数字要复算,对 AI 判断要限定边界,对任务状态要对账,对前端操作要给反馈,对报告内容要做去重和质量门禁。

根因地图

12 个 Bug 背后,不是 12 个孤立错误,而是 6 类反复出现的系统性风险。

1

外部数据源假设错误

SEC 访问策略、CIK 公司 ID、EDGAR 文件格式都不能凭经验假设,必须接入官方接口和启动自检。

2

下载成功不等于内容正确

13 KB 索引页被当成年报、iXBRL 机器标签占满截断窗口,说明文件大小和内容特征必须校验。

3

任务状态缺少对账机制

服务重启、后台线程消亡、watchdog 字段错配,都说明持久化状态必须和真实进程对账。

4

生产环境路径与本地不同

本地测试通过,不代表服务器上传路径、SSH 认证和运行位置都正确,部署依赖必须在真实环境测试。

5

前端静默失败最伤信任

删除按钮无反馈、任务状态反复横跳,会让用户怀疑系统,而不是怀疑某个小功能。

6

Prompt 需要负向约束

AI 会为了凑页数重复洞察,也会在找不到数字时填符号。宁缺毋滥和禁止项同样重要。

12 个 Bug 复盘卡片

默认只展示摘要,点开后再看根因、解决方案和工程启发,避免信息一上来全部堆满。

01
SEC EDGAR 返回 403,无法拉取美股财报列表
美股公司提交分析后任务失败,Telegram 收到错误通知,美股全线不可用。
P0
根因判断

feedparser 默认 User-Agent 不符合 SEC 程序化访问要求,浏览器正常但程序请求被拒绝。

解决方案

在 fetch_sec_filings() 中显式传入合规 User-Agent 与 Accept-Encoding。

工程启发

第三方 API 的访问策略不能假设跟浏览器一致,必须用无浏览器环境测试。

02
5 家美股公司 CIK 填错,查到了别人家的文件
任务可能失败,更严重的是静默下载错误公司的年报并生成错误报告。
P0
根因判断

CIK 来自搜索结果且未通过 EDGAR 官方 submissions API 二次核验。

解决方案

通过 EDGAR submissions API 逐一验证公司名,替换 WATCHLIST 中错误 CIK。

工程启发

外部 ID 类字段必须有二次校验,启动时应自动打印官方公司名供核对。

03
下载了 13 KB 的目录索引页,而不是 5 MB 的年报
Telegram 显示报告已生成,但内容全是空洞兜底话术,严重伤害用户信任。
P1
根因判断

原下载逻辑只认 PDF,遇到 SEC iXBRL inline 链接时把索引页当年报存盘。

解决方案

download_pdf() 新增 ix?doc= 链接识别,正确下载 htm 年报正文。

工程启发

下载成功不等于下载正确,兜底逻辑必须有文件大小与内容特征校验。

04
年报文件下载对了,但提取出的全是 XBRL 机器标签
报告成功生成但无真实财务数字,AI 判断数据严重缺失。
P1
根因判断

BeautifulSoup.get_text() 抽取了隐藏的 ix:header / context / unit 元数据,截断窗口被机器标签占满。

解决方案

剔除 ix:header、ix:hidden、ix:resources 与 display:none,并用 EDGAR XBRL API 前置核心指标。

工程启发

iXBRL 不是普通 HTML,结构化数据应作为主数据源,文本提取只能补充。

05
Step 5 生成 HTML 后上传失败,返回空 URL
最后一步失败,用户没有收到报告,前面 5-8 分钟分析时间白跑。
P0
根因判断

生产环境 pipeline 在目标服务器本机运行,却通过 SSH loopback 上传到自己,因 authorized_keys 未配置导致认证失败。

解决方案

upload_to_server() 增加本地路径检测,目标目录可访问时直接 shutil.copy2()。

工程启发

文件传输逻辑依赖部署位置,必须在真实服务器环境验证。

06
服务重启后任务永久卡在“分析中”
用户长时间看到分析中,不知道任务成功、失败还是系统挂了。
P1
根因判断

systemd 重启杀死后台线程,但 jobs.json 中 running 状态没有被清理。

解决方案

服务启动时把 running 改为 error,并增加 5 分钟 watchdog 清理超时任务。

工程启发

进程状态和持久化状态必须对账,启动时清理 stale running 是标准动作。

07
运维操作误伤正在运行的用户任务
用户短暂看到任务失败,几分钟后又变成功,状态翻转造成困惑。
P2
根因判断

手写脚本批量把 running 改为 error,误伤了真实正在运行的理想任务。

解决方案

禁止运行期间手动批量修改 jobs.json,清理逻辑统一收进启动流程。

工程启发

运维操作也有影响半径,修改生产数据必须先确认现场状态并最小化范围。

08
Admin 后台报告排序逻辑反了,置顶反而排最后
管理员置顶成功但刷新后排到最后,功能预期完全相反。
P2
根因判断

tuple 排序叠加 reverse=True,把 pinned 维度和发布时间维度一起反转。

解决方案

改为两步稳定排序:先按发布时间倒序,再按 pinned 优先。

工程启发

多维排序方向不同的时候,不要合并 tuple 再 reverse。

09
pipeline.py CLI 缺少 --sec-cik 参数,手动测试直接报错
无用户感知,仅影响开发者在服务器上手动触发 pipeline 测试。
P3
根因判断

函数签名新增 sec_cik / sec_accession,但 argparse CLI 没同步。

解决方案

在 pipeline.py main() 中补全 CLI 参数并传入 run_pipeline()。

工程启发

函数签名新增参数后,必须 grep 所有调用入口同步更新。

10
Watchdog 时间戳字段名用错,实际上从不生效
永久 running 的边缘任务无法被正确超时清理,生产流量下会再次卡住。
P2
根因判断

清理逻辑读取 started_at,但 jobs.json 实际字段是 created_at,字段名不一致。

解决方案

统一使用 created_at,并增加注释和 fallback 说明。

工程启发

共享数据结构要有 schema 或常量定义,字段名拼错会静默走错逻辑。

11
管理后台删除按钮点击无效果
管理员确认删除后弹窗关闭但列表不变,且没有任何错误提示。
P1
根因判断

closeModal() 在 fetch 前清空 _pendingDeleteIdx,导致请求发到 /api/admin/reports/null。

解决方案

在关闭弹窗前先把待删索引复制到局部变量 idx,并处理非 ok 响应。

工程启发

共享状态变量要先复制到局部变量,前端 API 问题第一步看 Network 请求 URL。

12
AI 生成重复幻灯片,同一组数字被讲了两遍
拼多多报告第 04 页和第 12 页重复,左侧 metric 出现“净>营业”,有凑页数观感。
P2
根因判断

Step 3 没有去重规则,Step 4 没有禁止比较符号作为 metric。

解决方案

改为弹性 8-12 页,加入严格去重;metric 禁止 >、<、vs、→,选择更有冲击力的真实数字。

工程启发

Prompt 必须有负向约束和宁缺毋滥原则,否则 AI 会走阻力最小的路。

下次开发必须遵守的规则

这部分从“问题复盘”提炼成“开发约束”,后续新任务可以直接作为验收清单。

1. 外部 ID 必须官方核验CIK、股票代码、公司名、交易所代码、公告 accession number,都必须通过官方 API 反查公司名。
2. 下载文件必须验真下载后检查文件大小、MIME、关键文本特征。低于阈值或只有目录导航时必须失败。
3. 数字优先使用结构化数据XBRL / API / 表格数据优先于纯文本抽取。文本提取只做补充。
4. 任务状态必须可对账服务启动时清理 running 僵尸任务;watchdog 使用统一 schema 字段。
5. 前端失败必须可见所有 API 非 2xx 响应都必须展示错误提示;删除、置顶、发布等管理动作必须有反馈。
6. Prompt 要有禁止项禁止重复数字、禁止凑页数、禁止用比较符号冒充核心指标,允许宁缺毋滥。

遗留优化 Backlog

这些不是立即阻断项,但会影响系统长期稳定性和内容可信度。

高优先级CIK 自检脚本启动时打印每个 CIK 对应的 EDGAR 公司名,防止再次填错。
高优先级下载文件大小校验下载后低于 200 KB 立即告警,避免静默存下目录索引页。
中优先级iXBRL 章节定向提取150K 截断仍可能丢内容,考虑按章节标题定向截取财务报表部分。
中优先级XBRL 货币单位标准化部分公司 USD / CNY 混用,需自动统一后再展示。
低优先级重复提交保护同一公司已有进行中任务时,前端拒绝再次提交。
低优先级历史报告对比分析当期时自动拉取上期数据作为环比参考。

给 Claude Code / Codex 的后续开发指令

这段是给后续开发任务直接复用的“系统提示词”。相比把所有复盘塞进正文,这里单独做成可复制的黑色代码块,便于喂给 AI。

你正在维护 ReportLens 财报分析 Agent。请严格遵守以下工程规则: 1. 不要假设外部数据源稳定。所有 SEC / HKEX / IR / RSS 请求必须显式设置合规请求头,并用 curl 或 requests 在无浏览器环境下测试。 2. 不要相信人工填写的外部 ID。CIK、股票代码、公司名映射必须通过官方接口反查并在启动时自检。 3. 下载成功不等于下载正确。下载后必须检查文件大小、MIME、关键内容特征;如果文件过小、只有目录页或没有财务关键词,必须标记失败并报警。 4. iXBRL 不是普通 HTML。提取文本时必须剔除 ix:header、ix:hidden、display:none 等机器元数据,并优先使用 XBRL 结构化 API 注入核心财务指标。 5. 每一步中间产物都要落盘:raw_facts、calculation_check、opinion_matrix、page_script、html_output。每一步都要支持单独重跑。 6. 任务状态必须和真实进程对账。服务启动时清理 stale running;watchdog 使用统一 schema 字段;不要在运行时手动批量改 jobs.json。 7. 管理后台所有 API 调用必须处理非 ok 响应,并在 UI 上展示错误;删除等操作要先把共享状态复制为局部变量,再关闭弹窗。 8. AI 生成分析点必须宁缺毋滥,允许 8-12 页;禁止为了凑页数重复同一组数字;禁止用 “>、<、vs、→” 作为左侧核心 metric。 9. 财报内信息、财报外检索信息、AI 推断必须在页面中清楚区分。外部新闻可以作为补充模块,不能混写成财报原文。 10. 每次改函数签名后,必须 grep 全部调用方,确保 CLI、API、trigger、测试脚本同步更新。 完成开发后,请输出:改动文件列表、测试命令、验收结果、已知风险和回滚方式。