Files
CADx-4/research-wiki/任务书/04-核对包改成医生读得懂.md

17 KiB
Raw Permalink Blame History

任务书 04:核对包改成医生读得懂;资料库超声一路只留给 agent 的参数

目标

任务书 03 做出来的核对包(runs/review_pack/20261017-060427-c7373ef-dirty/)是照任务书做的,但任务书本身写错了读者:它把我们自己才用得上的东西(检查编号、字段名、原因码、tic.json 全部字段)都要求给了医生。本任务做三件事:

  1. 资料库超声一路的 tic.json 只留「给 agent 的参数」,8 张图并进一个文件夹;
  2. CEUS 对紫圈也算灌注指标,重跑;
  3. 核对包改成合作医生拿到就能看懂的样子,医生看到的参数就是资料库里 agent 看到的那份。

医生不是搞计算机的。包里的每个文件、每一列、每一句话,都要回答得了「医生看这个能判断什么」;回答不了的不放。

来源:负责人 2026-10-17「说明.pdf 写的很奇怪,既不符合对于合作方的语气,我们是合作者啊……类似公文……合作方是医生,感觉他们也不一定看得懂」「TIC结果.csv 为什么有那么多值是空的」「中间结果……不需要给医生,他们又不是搞计算机的」「医生明确说需要有『给 agent 的参数』」「从 Lognormal 拟合曲线算出来,算不出来就是空;应该是要算两组的,一个是实质的曲线算,一个是去暗区的那条……得类似正常区域与疾病区域对比看。但是病灶整体肯定是不要的……每一组都是那些参数」「就用那几个指标」(指旧项目已经写程序算过的那组灌注指标);资料库借这次一起清理、8 张图放一个文件夹(负责人 2026-10-17 认可讨论会话的提议:「还没开始,你改任务书吧」)。

定下来的「给 agent 的参数」

  • 两组:胰腺实质(医生画的紫圈,roi_pan)一组,病灶去暗区(roi_perf)一组。病灶整体(roi_all)不要。
  • 每组同样的参数:旧项目 perfusion_metrics.py 那 11 个灌注指标,本仓库已迁移为 src/cadx/ceus/_perfusion_metrics.py:PE、TTP、WiR、RT、WiAUC、WiPI、WoR、FT、WoAUC、WiWoAUC、mTTl。辅助时刻 TI、TO、mTT 不给(它们只是算上面几项的中间量)。
  • 怎么算:照现在的做法,从过了质量门的 Lognormal 拟合曲线算;这一组拟合没过,整组为空;观测不够算不出的单项为空,不外推。
  • 不给:拟合成功与否、R²、背景圆、病灶整体、紫圈是否可用、关键帧未取到的原因、信号域等内部标记。

一、CEUS:指标改为对病灶去暗区和紫圈两组算

现在第 9 步对 LESION_CURVES = ("roi_all", "roi_perf") 算指标(src/cadx/ceus/_pipeline.py:59、:313),紫圈没算。改为只对 roi_perf 和 roi_pan 算;roi_all 的指标没有使用者了,同一次删掉。

注意 LESION_CURVES 同时决定「两条病灶曲线都过才定位 D1–D4」(_pipeline.py:300),那条规则不动;给「算指标的曲线」单独一个名字,不要改 LESION_CURVES。

summary.json 的 perfusion_metrics 下的键相应变为 roi_perf、roi_pan。

重跑

紫圈指标要重跑 CEUS 才有,顺便把 -dirty 的问题一起解决:

  1. 开跑前工作区必须干净(git status 无改动,包括负责人自己的 AGENTS.md、README.md、research-wiki/paper/)。不干净就停下来告诉负责人,不要替他提交。
  2. 全量重跑 ceus_quant(40 例),再用新运行重新 build,再出核对包。三个运行目录都不带 -dirty。
  3. 上次全量跑过一次 OOM(runs/ceus/20261016-070216-e165b32-dirty.partial),这次用当时修好后的设置。超过一分钟的命令放 tmux,日志写文件。
  4. 报告里对比新旧两次 CEUS 运行:成功例数、各曲线拟合成功例数、各槽位定位例数应完全相同(只有指标换了曲线);不同就停下来查原因,不要往下走。

二、资料库:超声一路只留给 agent 的东西

资料库的定义是「专家能看到什么」,可见范围只在 build 一处决定。多余的值放进去、等 agent 那边再挑,就成了两处决定,改了一处忘了另一处就会悄悄漏给专家。这部分属于 AGENTS.md 的账本级(答案隔离)。

tic.json

src/cadx/build/_ceus.py 的 tic_view 白名单改为只出下面两项,此外什么都不写:

{
  "perfusion_metrics": {
    "roi_pan":  { 11 个指标 } 或 null,
    "roi_perf": { 11 个指标 } 或 null
  },
  "keyframe_times_s": { "B0": 视频时间或 null, …, "F2": … }
}
  • 11 个指标的键沿用 summary.json 里 values 下的键名(PE_au、TTP_s …),单项算不出为 null。signal_domain、time_origin、area_curve、supporting_times_s 都不要。
  • keyframe_times_s 是 7 个槽位定位到的视频时间(秒),没取到为 null;未取到的原因不写。
  • 去掉:fits(成败和 R²,四条曲线全部)、pan_curve_usable、keyframes.*.located 和 reason。原来对 reason 做的「不含视频号、路径」检查随字段一起删掉。
  • 没装 CEUS 时照旧没有 tic.json。

8 张图放一个文件夹

医生截的关键图从 ultrasound/key.png 挪进 ultrasound/keyframes/key.png,和 B0.png … F2.png 放在一起;ultrasound/ 下不再有单独的 key.png。

  • 关键图来自交付包而不是 CEUS,所以没装 CEUS 的构建里 keyframes/ 只有 key.png 一张,照样有这个文件夹。
  • C14(保真重编码)对关键图和关键帧的规则不变。
  • library 的读取接口相应改:UltrasoundRoute 不再有单独的关键图字段,keyframes 里多一个 key。其余使用者(review 等)跟着改。

测试(账本级)

预期值手写,不从实现里推:

  • 用假交付包和假 CEUS 运行构建一次,逐例断言 tic.json 的完整内容等于手写的字典(不是只查几个键):两组都有、只有一组、两组都 null、某个单项为 null、某个槽位没取到各至少一例。
  • 断言 tic.json 里不出现 fits、r2、success、roi_all、background_circle、reason、pan_curve_usable 这些键。
  • 断言每例 ultrasound/ 下的文件清单恰好是 report.txt、tic.json(装了 CEUS 时)、keyframes/ 下的 key.png 加定位到的槽位;key.png 与原关键图逐像素相同。
  • 没装 CEUS 的构建:keyframes/ 下只有 key.png,没有 tic.json。

三、核对包

医生核对包_<构建号>/
  说明.pdf
  问题清单.csv
  病例总表.csv
  标准答案/                     4 张表照旧
  病例/<病例号>/
    临床信息.csv
    超声报告.pdf
    MR报告.pdf
    关键帧/
      医生截图.png              资料库 keyframes/key.png
      <槽位>_第<秒>秒.png        秒数取 tic.json 的 keyframe_times_s
    TIC曲线.png
    TIC参数.csv                 新增,取代 TIC结果.csv
    回放视频.mp4

TIC结果.csv 和单独的 关键图.png 删掉。其余文件的拷贝规则、CSV 格式(BOM、中文列名、缺失为空)照任务书 03。

TIC参数.csv

数值从资料库的 tic.json 读,不从 CEUS 运行读:医生核对的就是 agent 看到的那份。一例一张,行是 11 个指标,列:

列 内容
指标 中文名加缩写,如「达峰时间 TTP」
单位 秒、灰度、灰度·秒、灰度/秒
胰腺实质(紫圈) 数值
病灶(去暗区) 数值
  • 时间类保留 1 位小数,其余保留 2 位。
  • 某一组整组没算出时,该列全空,并在表的最后加一行:「指标」列写「没算出的原因」,对应列写一句医生能懂的话(见下文「原因的写法」)。两组都算出时没有这一行。原因从 CEUS 运行的 summary.json 读(资料库里已经没有了),这一行只给医生看,agent 拿到的只是 null;说明.pdf 不必提这个差别。
  • 单项因观测不够算不出、而同组其他项有值时,该格留空,不另写原因(说明.pdf 里统一交代一次)。
  • CEUS 失败的病例本来就不进资料库,没有这个文件。

问题清单.csv

列不变(病例号、视频号、环节、问题),内容改成每条一句大白话:

  • 「问题」里不出现:检查编号(C10、C15 …)、英文原因码、JSON、文件路径、运行号、roi_* 之类的字段名、程序内部用词(band、谷值、互相关、模板匹配 …)。
  • 「环节」改成医生认得的说法,例如「资料核对」「造影视频处理」「TIC 曲线」「关键帧」「紫圈」。
  • 由同一个原因引起的多条合并成一条。例如病灶曲线拟合没成功导致 B0、D1–D4 都没取到,只写一条:「病灶曲线没能拟合,B0、D1–D4 这 5 个关键帧没有取」;不要再各写 5 行。
  • 跨表不一致写出对不上的具体值,例如「三张表的年龄对不上:临床表 28 岁,超声表和 MR 表 63 岁」(这是病例数据,只进包,不进仓库、日志和报告)。
  • 一个 CEUS 失败的病例只写一条(现在是「CEUS 第 N 步」和「装配资料库 C15」各一条,说的是同一件事)。

原因的写法

在 review 里维护一张「程序原因 → 医生能懂的一句话」的对照表,覆盖:跳过清单的每个检查编号、failed.csv 里各步的失败原因、拟合的每个原因码、关键帧每类未取到的原因、紫圈不可用。

  • 对照表按「原因的种类」写,具体数值从原记录里取出来填进句子;数值对医生没意义的(谷值、像素偏移)不填。
  • 遇到对照表里没有的原因直接报错停下,不能把程序原文漏给医生。
  • 程序原文照旧留在 snapshot/ 里(新增一份 问题清单_原文.csv,列同旧版),给我们自己追溯用,不进医生的目录。

写法参考(执行者可改得更顺,意思不变):

程序原因 给医生的话
第 1 步找不到分屏暗缝 视频里找不到左右两屏的分界线
第 1 步两半配准相差超过门槛 视频左右两屏的位置对不齐
第 2 步两半都没有绿框 视频里找不到画好的绿框
拟合 parameter_on_boundary 曲线形状超出了程序预设的范围,没能拟合
拟合其他原因码 各写一句,说的是曲线本身的样子(太平、没有明显的峰、开头就已经很亮 …),不说算法
紫圈不可用 视频里大部分时间认不出紫圈

说明.pdf

整份重写,模板仍在 src/cadx/review/ 下。

  • 口吻:合作者之间说话。用「我们」「你们」,不用「贵方」「请您核对」这类公文腔。开头一两句说清这是什么、想请他们帮忙看什么就行。
  • 读者:胰腺外科或超声科医生,懂 CEUS、懂 TIC 的临床意义,不懂编程、不懂我们的程序。
  • 篇幅:尽量 3 页内,最多 4 页。
  • 只讲这些:
    1. 包里有什么、每个文件夹打开能看到什么(分条,不用长表);
    2. 看病例的建议顺序:报告 → 关键帧文件夹里的医生截图 → 回放视频(黄色、绿色线是程序画的病灶轮廓,蓝色是程序认为一直不进造影剂的部分)→ TIC 曲线图 → 关键帧 → TIC 参数;
    3. 7 个关键帧各是什么时刻,用临床的话说;
    4. TIC 曲线图上每条线是什么(图上的英文标注逐个对照成中文);
    5. 11 个指标各是什么意思,一句一个;两组的意思是让病灶和正常胰腺对着看;数值是在视频显示的灰度上算的,不是机器内部的回声强度,所以单看一个数意义不大,看两组的对比;时间从视频第一帧算起;空着表示没算出,最后一行写了原因;
    6. 问题清单、病例总表、标准答案 4 张表各是什么,一句一个;
    7. 包里有患者资料,只在我们双方之间传。
  • 不写:检查编号、原因码列表、字段名、算法和模型名(MedSAM2、Lognormal 等,Lognormal 可以说成「用一条平滑曲线去贴合」)、质量门的具体条件、构建配置开关、化名的设计理由。构建号、CEUS 运行号、生成日期放在第一页末尾一行小字即可。
  • 排版:现在的 PDF 有 4 张表(第 3、5 页的问题清单列说明、「环节」、「槽位」、「原因码」)在转换后只剩第一列。改完必须确认没有这种问题;能用分条就不用表。

四、验收要求(执行者自己做完再交)

  1. 把 PDF 渲染成图片逐页看一遍(pdftoppm),说明.pdf 全部页和一份超声报告 PDF。报告里写看过了、有没有发现问题。
  2. 医生视角阅读:派一个全新上下文的子 Agent,扮演「三甲医院胰腺外科医生,懂 CEUS,不会编程,第一次拿到这个包」,只给它:说明.pdf 转出的文字、问题清单.csv、一例病例目录里的 TIC参数.csv 和 临床信息.csv(用假交付包测试产出的那份,不给真实病例数据)。让它先复述「这个包让我看什么、怎么看」,再列出读不懂的句子、看不懂的词、觉得多余的内容、语气别扭的地方。这一轮替代 AGENTS.md 的「硕士生阅读」(读者不同)。格式建议不采纳,读不懂和多余的必须改。
  3. 问题清单全文 /usr/bin/grep 一遍,确认不含:C[0-9]、roi_、_、{、[、band、运行号格式。写成测试。

测试

预期值照本任务书写,不从实现里推:

  • 资料库:见第二部分「测试(账本级)」。
  • 紫圈指标:假 CEUS 运行里造一例紫圈拟合成功的,summary.json 的 perfusion_metrics 恰好有 roi_perf、roi_pan 两个键,roi_pan 且 11 项值等于直接调 compute_lognormal_perfusion_metrics 的结果;lesion_fit_ready 的判定不受影响(造一例紫圈过、病灶有一条没过,D1–D4 仍不定位)。
  • TIC参数.csv:列名、11 行的顺序和中文名;两组都有值、只有一组有值、两组都没有三种情况;「没算出的原因」行只在有组为空时出现;数值的小数位。
  • 问题清单:每种原因至少一例,断言「环节」「问题」原文;拟合失败连带的关键帧只出一行;CEUS 失败只出一行;对照表里没有的原因报错;上面第 3 条的禁用字符检查。
  • snapshot/问题清单_原文.csv 存在且内容与旧写法一致。
  • 包里不再有 TIC结果.csv 和单独的 关键图.png;关键帧/医生截图.png 与资料库 keyframes/key.png 逐字节相同;TIC参数.csv 的数值与资料库 tic.json 逐项相同。
  • build、ceus、review 原有测试照过(按本任务改了预期的除外,在报告里列出改了哪几条、为什么)。

文档

  • research-wiki/explanation/ 里讲 CEUS 第 9 步的地方:指标改为对病灶去暗区和紫圈两组算,写明来源是负责人 2026-10-17 的决定(医生要正常区与病灶对比看)。
  • research-wiki/guides/医生核对包.md:文件清单改成新的;重跑顺序写成「干净工作区 → ceus_quant → build → review_pack」。
  • 结构.md:第四部分资料库布局(key.png 挪进 keyframes/)和 tic.json 字段说明重写(现在第 163–171 行一带);第八部分 UltrasoundRoute 的说明;规模表若有变化同步。
  • WORK_LOG.md。

审阅

资料库那部分是账本级:先单独派一个全新上下文的子 Agent,只给本任务书第二部分、结构.md 第四部分(改后)和 build、library 的 diff,问一件事:专家现在能读到的超声一路,是否恰好是第二部分列的那些,多一个字段、多一个文件都算问题。处理完再做下面这轮。

核对包和 CEUS 属于「其余部分」那一档。写完派一个全新上下文的子 Agent,只给本任务书、diff 和渲染后的说明.pdf 页面图片。重点:问题清单里有没有漏出程序原文;对照表是否覆盖了真跑时出现的全部原因;紫圈指标改动有没有影响 D1–D4 的定位规则;review 有没有写 library/ 或 answers/。Codex 连不上就跳过。

报告

  1. 提交号;各部分行数变化。
  2. make check 完整输出。
  3. 新旧 CEUS 运行的对比(见「重跑」第 4 条);新的 CEUS、build、review_pack 三个运行号。
  4. 紫圈、病灶去暗区两组各有几例算出了指标,两组都有的几例(只报计数);资料库任挑一例 tic.json 的键结构(只报键,不报数值)。
  5. 问题清单按新「环节」分的行数,与旧版行数对比。
  6. 渲染检查和医生视角阅读的结果,以及据此改了什么;两轮审阅的意见和处理。
  7. 说明.pdf 和一例病例目录的路径,供负责人目视检查。
  8. 和本任务书、AGENTS.md 不一致的地方,以及为什么。