来源:负责人 2026-10-17 要求把 29 例处理结果整理成医生能看的格式并做成长期入口(表格 CSV、文字 PDF、视频不压缩、不向医生提问、问题清单只写现象);文献核查为负责人要求的质量门依据核对,结论待医生看过后再定。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12 KiB
任务书 03:医生核对包
目标
把一次构建(library/ + answers/)和它装入的那次 CEUS 运行,整理成医生不用写代码就能看懂的一个文件夹:表格一律 CSV,文字一律 PDF,图和视频原样。负责人把文件夹打成压缩包、用 U 盘拷给医生,请医生核对我们的处理结果。
这是一项长期功能:以后医生每交一版数据,跑完 ceus_quant 和 build,再跑一次本入口,就得到新的核对包。所以按正式模块写,带测试和 guide,不写成一次性脚本。
来源:负责人 2026-10-17「我们把处理完的结果……整理一份給医生看看」「不需要问医生问题」「文本文件尽可能 pdf,表格尽可能 csv」「需要作为一项长期的功能……有一个入口能执行这个」;视频不压缩(「本来视频就模糊,你压缩不是更模糊」);病例目录用医生的病例号、问题清单只写现象、没进库的病例只在表里出现(负责人 2026-10-17 认可)。
不做什么
- 不向医生提问,不做反馈表。
- 问题清单只写程序观察到的现象,不写原因推测、不写我们查过的文献、不写建议。
- 不改 CEUS 算法、不改质量门、不改资料库的内容。质量门的去留等医生看过之后再定(文献核查记录在
research-wiki/scratch/2026-10-17-TIC拟合约束文献核查/,本任务不用读)。 - 不压缩视频,不缩放、不重新编码任何图片和视频。
核对包的内容
runs/review_pack/<运行号>/
snapshot/ 快照(不给医生,打包时由负责人去掉;见下文)
医生核对包_<构建号>/ 负责人整个打包的就是这个目录
说明.pdf
问题清单.csv
病例总表.csv
标准答案/
化名对照.csv
诊断.csv
跳过病例.csv
报告复核句.csv
病例/
<病例号>/ 只有进了资料库的病例,目录名用医生的病例号(如 P001)
临床信息.csv
超声报告.pdf
MR报告.pdf
关键图.png
关键帧/<槽位>_第<秒>秒.png 例如 B0_第1.6秒.png;秒数保留一位小数;没定位的槽位没有文件
TIC曲线.png
TIC结果.csv
回放视频.mp4
逐项要求:
- CSV:UTF-8 带 BOM(Excel 双击打开中文不乱码),列名用中文。缺失值留空,不写 null、NaN。
病例总表.csv:这次构建涉及的全部病例一例一行(进库的加跳过的;40 例交付包就是 40 行),按病例号排序。列:病例号、视频号、化名(没进库的留空)、是否进入资料库、没进的原因(检查编号和说明)、CEUS 定量是否成功、CEUS 失败在第几步、7 个槽位各一列(取到写视频时间秒数,没取到写「未取到」,CEUS 失败或没装 CEUS 时留空)。问题清单.csv:列为病例号、视频号、环节、问题。按病例号排序,一个病例可以多行。来源和写法见下文「问题清单的来源」。标准答案/:答案库的 4 张表照原样转成上面的 CSV 规格,列名不改。诊断编码和其他编码列照原值写;说明文件里写明编码含义(诊断 1 IPMN、2 SPN、3 MCN、4 SCN,出自交付包表头;其他编码列写「未解码」,解码开关见build.yaml)。临床信息.csv:资料库临床一路的字段,一行;列名用交付包原列名。超声报告.pdf、MR报告.pdf:资料库里的报告原文(就是 AI 专家看到的那段,结论段已被程序去掉),PDF 第一行写「病例号 Pxxx 超声描述(结论段已去除)」之类的标题,正文照抄不改字。关键图.png、关键帧/:从资料库拷贝(已去附加数据的那份),逐字节不变,只改文件名。TIC曲线.png、回放视频.mp4:从 CEUS 运行目录逐字节拷贝。TIC结果.csv:把资料库的tic.json摊平成「项目、值」两列的长表:四条曲线各自的拟合是否成功和 R²、灌注指标逐项、紫圈曲线是否可用、7 个槽位的状态与时间或原因。项目名用中文加原字段名,例如「病灶整体曲线 拟合成功(roi_all.success)」。- 没装 CEUS 结果的构建(
ceus_run为 null)也能出包:没有关键帧、TIC 曲线、TIC 结果、回放视频,病例总表里 CEUS 各列留空,说明文件写明这次没有 CEUS 结果。
问题清单的来源
每条都能追到某个已有文件里的某个值,不另做判断:
| 环节 | 来源 | 写法 |
|---|---|---|
| 装配资料库 | 答案库的跳过清单 | 检查说明 + 涉及的文件、列和值,原样写 |
| CEUS 第 N 步 | CEUS 运行的 failed.csv |
「第 N 步失败:」+ 原因原文 |
| TIC 拟合 | tic.json 里病灶整体、病灶去暗区两条曲线 success 为 false |
「病灶整体曲线未完成拟合」(去暗区同理);原因码(如 parameter_on_boundary)照写在括号里,并在说明文件里逐个解释每个原因码的意思 |
| 关键帧 | tic.json 里没定位的槽位 |
「B0 未取到:」+ reason 原文 |
| 紫圈 | pan_curve_usable 为 false |
「紫圈曲线不可用」 |
报告复核句(标准答案/报告复核句.csv)不进问题清单,单独成表。
说明.pdf
源文件是仓库里的一份版本化 Markdown 模板(放在 src/cadx/review/ 下,随代码走),出包时填入这次的构建号、CEUS 运行号、病例计数,再转成 PDF。至少写清:
- 这个包是什么、从哪次交付数据处理来(构建号、CEUS 运行号、生成日期);包里含患者资料,只在临床方与我们之间传递。
- 目录结构,每个文件是什么。
- 每张 CSV 每一列的意思。
- 我们的处理流程,用医生能懂的话分步讲(读交付包和检查 → CEUS 的第 1–9 步各做什么 → 装进资料库),问题清单里「环节」一列的每种取值对应哪一步。
- 7 个关键帧各代表什么时刻、怎么取(B0、D1–D4 来自拟合曲线,F1、F2 按推注时间取),以及「未取到」的几种原因。
- TIC 曲线图怎么看:每条线是什么(图上标注是英文,在这里逐个对照成中文)、竖线是什么。
- 化名是什么、为什么有;报告里的结论段为什么被去掉(AI 专家不能看到医生的诊断倾向);资料库只放「所见」。
- 编码列的含义(诊断编码,以及「未解码」的列)。
- 跳过病例为什么整例跳过、每例只记第一项没过的检查。
转换工具:pandoc 把 Markdown 转成 docx,再用 soffice --headless --convert-to pdf 转 PDF(本机都有,中文字体用已装的 Noto CJK)。报告 PDF 用同一条路。两个工具的版本记进快照。工具缺失直接报错。
怎么实现
模块
新建组织层模块 review(src/cadx/review/),藏住「核对包长什么样」这个决定:目录布局、每个文件的格式、问题清单的来源与写法、说明模板。
- 依赖:library(按化名读出各路)、answers(读 4 张表)、runs(读快照、读 CEUS 运行,见下)。不依赖 build、delivery、ceus。
- 它读的是已经构建好的
library/和answers/,不碰交付包。病例总表里的 40 例 = 答案库的化名对照 + 跳过清单。 - 只有 library 能引用 PIL:review 拷图片只按字节拷,不打开图片。
CEUS 运行目录的读取挪进 runs。 现在 build 的 _ceus.py 自己读 runs/ceus/<运行号>/ 的布局(failed.csv、summary.json、关键帧),review 也要读。按 结构.md 第三部分「出现第二个使用者再收进模块」,把读 CEUS 运行目录(打开运行、读 failed.csv、按视频号找结果目录和其中的文件)收进 runs,build 和 review 都经 runs 读。tic.json 挑哪些字段仍只在 build 里列(可见性的唯一决定处不动)。挪完 build 的行为不变,原有测试照过。
入口
scripts/review_pack.py --config config/review_pack.yaml。配置(字段定义在 review,全部必填):
library_dir、answers_dir:某次构建的资料库和答案库目录,两者目录名(构建号)必须相同,不同就报错;output_root:runs/review_pack。
CEUS 运行从资料库 manifest.json 的 CEUS 来源字段读,不另配。
运行目录先写 .partial,跑完改名,已存在报错(规则同前两份任务书)。快照记 git 状态、配置原文、构建号、CEUS 运行号、pandoc 和 soffice 版本。快照放在 医生核对包_<构建号>/ 外面,负责人只打包里面那个目录。
终端只打印计数:病例数、问题清单行数(按环节分)、PDF 份数、拷贝的视频总大小、耗时。不打印病例号。
规模
| 部分 | 预期行数 |
|---|---|
| review(含说明模板以外的代码) | 300–500 |
scripts/review_pack.py |
≤ 80 |
| runs 增量(读 CEUS 运行) | ≤ 150,build 相应减少 |
测试
预期值照本任务书写,不从实现里推。用现有的假交付包和假 CEUS 运行(tests/fake_delivery.py、tests/fake_ceus_run.py)构建一次,再出包:
- 目录结构与上面一致;进库病例每例一个目录、名为病例号;跳过的病例没有目录、在病例总表和问题清单里有。
- 每张 CSV 以 BOM 开头、列名与本任务书一致、缺失值为空串。
- 问题清单:每种来源至少各造一例,断言行数和「环节」「问题」原文。
- 关键图、关键帧、TIC 曲线、回放视频与源文件逐字节相同;关键帧文件名的秒数等于
tic.json里的video_time_s保留一位小数。 TIC结果.csv的值与tic.json逐项相同。ceus_run为 null 的构建也能出包,CEUS 相关文件都不存在。- 资料库与答案库构建号不同时报错。
- 说明和报告 PDF 生成成功、非空(这条依赖 pandoc 和 soffice,照常进
make check;如果让make check多出 30 秒以上,在报告里写明耗时,不自行加标记跳过)。 - build 原有测试全部照过(CEUS 运行读取挪进 runs 之后)。
真跑
用当前真实构建 20261016-094248-1de88a5-dirty 出一次包。报告:运行号、病例数、问题清单按环节分的行数、包的总大小、耗时;挑 1 个病例目录和 说明.pdf 的路径供负责人目视检查。不在报告里写病例号以外的任何病例内容。
文档
- 新写
research-wiki/guides/医生核对包.md:什么时候跑、怎么跑、产物在哪、打包前去掉snapshot/。过一轮「硕士生阅读」。 结构.md:第三部分加 review(组织层,可依赖 library、answers、runs),依赖表和 import-linter 契约同步;第四部分加核对包一节(指向本任务书和 guide,不抄布局);第五部分配置表加review_pack.yaml;第六部分加规模;第八部分加对外接口。WORK_LOG.md。
审阅
「其余部分」那一档,写完派一个全新上下文的子 Agent 审一轮:只给本任务书、结构.md 第三到第五部分和 diff。重点:问题清单有没有漏掉某个来源、有没有写进推测性的话;拷贝是否逐字节;CEUS 运行读取挪进 runs 后 build 行为是否不变;review 有没有写进 library/ 或 answers/(不许)。Codex 连不上就跳过。
报告
- 提交号;各部分行数。
make check完整输出。- 真跑结果(见上)。
- 审阅意见和处理。
- 和本任务书、
结构.md、AGENTS.md不一致的地方,以及为什么。