9c636c0a4f
- 结构.md 第二部分加四段整体框架图;第五部分新增「配置」:每段一份 YAML、 pydantic 定义、只接收配置路径、编码解码开关与独立映射表 - 结构.md 第三、四部分:检查不过整例跳过,答案库存三表诊断、化名对照、跳过清单 - AGENTS.md「错误怎么处理」加交付资料单例问题的例外。来源:负责人 2026-10-16 「都是遇到整个病例跳过,让医生核对去吧」 - 待定问题/03 补被跳过病例;WORK_LOG 记决定与下一步 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
155 lines
17 KiB
Markdown
155 lines
17 KiB
Markdown
# AGENTS.md
|
||
|
||
本文件是给所有编码 Agent(Claude Code、Codex 等)的工作说明。`CLAUDE.md` 只引用本文件,内容以这里为准。
|
||
|
||
## 项目是什么
|
||
|
||
CADx-4 研究胰腺囊性肿瘤的鉴别诊断:给同一个病人的三路资料(临床信息、CEUS 超声造影视频与超声报告、MR 报告)各配一个只看自己那一路的 AI 专家,模拟多学科会诊,判断病灶属于四类胰腺囊性肿瘤中的哪一类:IPMN(导管内乳头状黏液性肿瘤)、SPN(实性假乳头状肿瘤)、MCN(黏液性囊性肿瘤)、SCN(浆液性囊性肿瘤)。前三类有恶变可能或本身是低度恶性,通常要手术或密切随访;SCN 几乎都是良性,多数不用手术。分错直接决定病人是手术、随访还是不用管。金标准是术后或穿刺取得的病理结论。最终产出是一篇医学 AI 交叉论文,重点在临床问题、与人类医生的对比和可解释性,不在方法复杂度。
|
||
|
||
几个词先解释:**MR** 是磁共振检查,本项目只有它的文字报告;**CEUS** 是往静脉打造影剂后连续录下的超声视频;**ROI**(感兴趣区)是视频里圈出的病灶区域;**TIC**(时间-强度曲线)是 ROI 平均亮度随时间的变化,造影剂进来变亮、洗出变暗,曲线形状就是灌注的量化。本仓库的术语表随模块迁移逐步建在 `research-wiki/reference/术语表.md`;建成前查旧项目的 `reference/CADx-4-CAD/research-wiki/reference/glossary.md`。
|
||
|
||
本仓库是对旧项目的**重构**。旧项目在远程服务器上按工程产品搭建(HTTP 服务、数据库、任务队列),后来发现目前不需要做成产品,于是在这里按研究原型重写,只保留有研究价值的算法和知识。旧项目的完整副本在 `reference/CADx-4-CAD/`(只读,见下文)。重构的来由和取舍见 `research-wiki/design/0001-从产品重构为研究原型.md`。
|
||
|
||
和临床合作方之间的议题、会议纪要、交付清单和临床口径在 Linear(团队用的议题跟踪系统,临床方也在上面)上,不在本仓库。
|
||
|
||
## 新会话先读什么
|
||
|
||
1. `WORK_LOG.md`:当前目标、做到哪一步、下一步、运行中的任务。
|
||
2. `research-wiki/README.md`:文档体系与各目录的用途。
|
||
3. `research-wiki/explanation/结构.md`,以及与当前任务相关的其他 `explanation/` 文档。
|
||
|
||
## 事实来源
|
||
|
||
文档之间有冲突时按下表定谁说了算,找负责人确认,不自行折中成第三种说法。
|
||
|
||
| 问题 | 看哪里 |
|
||
| --- | --- |
|
||
| 当前进度、下一步 | `WORK_LOG.md` |
|
||
| 代码分哪些模块、谁能依赖谁、各模块预期规模 | `research-wiki/explanation/结构.md` |
|
||
| 各环节在做什么、输入输出 | `research-wiki/explanation/` 的其他文档 |
|
||
| 还没定的问题 | `research-wiki/待定问题/`(定了就删,结论进 `design/`) |
|
||
| 某个决策为什么这样定 | `research-wiki/design/NNNN-*.md`(写完冻结) |
|
||
| 命令怎么敲、环境怎么配 | `research-wiki/guides/` |
|
||
| 医学词、参数的原始口径、临床方给的字段定义 | `research-wiki/reference/`(每条自带出处) |
|
||
| 交付资料的格式和口径(列名、编码、时间的含义) | 最新的交付包,目前是 `data/交付包_20260908_40例/`。旧样本(如 `data/1.2-TEST/`)和旧程序的口径只当线索。来源:负责人 2026-10-16「数据改过很多版,所以你们需要对齐“40例交付包”那个」 |
|
||
| 配置值、字段定义 | 代码里的定义与校验;文档只解释含义,不抄数值 |
|
||
| 临床口径、双方约定、待交付清单 | Linear(临床方维护的那几份 document 是权威,仓库里的抄本以它为准) |
|
||
| 旧项目做了什么、踩过什么坑 | `reference/CADx-4-CAD/`(只当线索,见下文) |
|
||
|
||
## reference/ 怎么用
|
||
|
||
`reference/CADx-4-CAD/` 是旧项目的副本,含完整 git 历史(366 个提交)和当时没进 git 的 `debugs/` 脚本。
|
||
|
||
- 只读。不在里面改文件、不在里面跑会写盘的命令。
|
||
- **算法代码可以迁移**:`app/domain/ceus_roi/`(除 `service.py`)、`app/providers/video_decoder.py` 和 `debugs/` 里的三个 `.py` 脚本是负责人自己的成果,迁移时去掉数据库、HTTP、任务队列等产品层依赖,按本文件的标准改写,并补上测试。读交付包的逻辑(`app/providers/` 里的列白名单、病例号规范化、剔除报告结论段)只借规则,按普通函数重写。产品层代码(`app/api/`、`persistence/`、`workers/`、`migrations/` 等)不搬。
|
||
- 旧文档和报告里的数字(40 例跑通 34 例、参数取值等)只是线索。要写进本仓库的文档或结论,先在原始产物或本仓库的真实运行里核到。
|
||
- 旧 `research-wiki/design/0001–0049` 讲的是当时为什么那样定。其中与研究有关的结论(优先读哪几份见本仓库 `research-wiki/design/0001` 第 8 条的表)在本仓库重新写成 explanation 或 design。可以注明「出自旧 design 00NN」交代来历,但现行规则以本仓库的文档为准。
|
||
|
||
`reference-pdf/` 放文献原文,命名 `年份-第一作者-短名.pdf`,索引在 `reference-pdf/INDEX.md`。两者都不进 git。
|
||
|
||
## 硬性约束
|
||
|
||
1. **答案不进 AI 专家能看到的任何东西。** 病理金标准、工作簿里的诊断列、按规则算出诊断倾向的公式列、医生的结构化判读列(**标注工作簿**是临床方另交的一份表,医生在里面逐例标了病灶位置、大小、囊壁、增强模式等三十来列,它只用于评价专家抽取得准不准)、报告的「印象 / 结论」段、真实病例号、Excel 行序,一律不能进入提示词、工具返回或专家可读的文件。**行序也算**:原始表格按诊断分组录入,行号本身就带着答案。这一条错了不会报错,只会让所有「系统诊断得准不准」的结论变成「系统能不能读到答案」。任何会削弱这条的改动,先停下来问。来源:旧项目 CLAUDE.md §1.2、旧 design 0026。
|
||
2. **每个 AI 专家只看自己那一路资料。** 性别和年龄只给临床那一路;超声和 MR 两路看不到,即使医院把这几列也复制进了报告工作簿。各路能看见什么见 `research-wiki/explanation/结构.md` 第四部分。来源:同上。
|
||
3. **患者资料不进 git、文档和提交说明。** 原始资料只在 `data/`,运行产物只在 `runs/`,两者都不进 git。文档里可以写结构和规模,不写报告原文、姓名、病例号和诊断。把病例资料发给外部模型服务之前,先确认负责人已同意该服务。超声帧上烧录的信息栏(拼音姓名、检查号、性别年龄、医院与设备参数)不做遮蔽:临床方判定拼音和不唯一的检查号不构成身份泄露(出自旧 design 0041)。
|
||
4. **密钥不进 git、文档、日志和运行快照。** 只放环境变量或本地 `.env`;仓库只提交不含真实值的 `.env.example`。
|
||
5. **写进论文和结论的数字能追到一次真跑的原始记录**(`runs/` 下的运行目录)。不把预期、估算、旧项目报告或别人论文里的数字当成本仓库的结果;没有就写「没有」。文献里的数字核到 `reference-pdf/` 的原文。
|
||
6. **错误不静默吞掉。** 不吞异常,不用默认值把问题盖过去,缺关键配置直接报错。细则见「写代码的标准」。
|
||
7. **花钱的批量运行先说预估成本。** 调模型 API 跑全部病例这类动作,开跑前在回复里给出预估;量级明显超过以往的,先问。
|
||
|
||
## 怎么协作
|
||
|
||
- **用简体中文回复,先给一句话结论。**
|
||
- **先讲后写。** 新环节或新设计先在终端讲:旧项目怎么做的、问题在哪、打算怎么做、为什么。负责人认可后再写文件或代码。需要负责人决定时,一次列出全部问题、选项和你的倾向。
|
||
- **能自己定的直接定**,按设计判断或文献先例给方案,不把问题抛回去。
|
||
- **范围要窄,改得要深。** 只动这次要改的那一块;范围内要改到读起来像一开始就这么设计的,被取代的旧内容同一次删掉。范围外看到问题,记下来告诉负责人。
|
||
- **讨论会话与执行会话分开。** 和负责人讨论方向的会话写任务书(`research-wiki/任务书/NN-*.md`),由负责人另开会话执行、讨论会话验收。小改动不必写任务书。
|
||
- **子 Agent 交证据不交判断**:带 `文件:行号`、命令原始输出或产物路径;prompt 里不带邮箱等个人信息和患者资料;要用浏览器只能用无头模式。收回的报告先抽查两三条原文,其中一条挑带评价性修饰的句子;子 Agent 说「通过」不算数,要自己核对实际改动和测试产物。
|
||
- **审查**:改动完成后派一个新鲜上下文的子 Agent,只给 diff、验收标准和相关文档,不给实现时的推理。下文「账本级」的代码另派一个全新上下文的子 Agent 再审一轮;Codex 可用时再加一轮对抗审查(`/codex:rescue --fresh --wait`)。审查意见只采纳影响正确性或明确需求的项,采纳前问:日常使用中会不会真撞上。
|
||
- **汇报**时分开写已验证的事实、推断和未验证的部分。
|
||
- **新加的规则注明来源**:负责人哪句话、哪份 design 文档,还是 Agent 自己提的。本文件的改动来源写在提交说明里。
|
||
- 推送、建 PR、往 Linear 写东西这类外部可见的动作先问;Linear 上有临床方在看。
|
||
|
||
## 写代码的标准
|
||
|
||
### 两档标准
|
||
|
||
- **账本级**(像记账一样只追加、可核对;出错会悄悄污染结论的部分):答案隔离(各路资料怎么读、怎么分给专家)、金标准的读取、评分与统计、写进论文的定量结果。要求:
|
||
- 运行产物只追加,已有的运行目录不删、不覆盖,要删先问;
|
||
- 每条规则有独立预期值的测试,预期值来自手算、独立脚本或人工核对过的样例,不从实现里抄公式。
|
||
- **其余部分**:视频解码、ROI 追踪、绘图、提示词拼装、脚本。写错了马上能看出来,按研究原型的标准写:用最直接的写法,遇到罕见情况就停下来把原因写清楚。
|
||
|
||
### 可复现
|
||
|
||
随机种子、模型的精确版本号(以服务商返回为准)、提示词版本、git 提交号和全部配置,写进每次运行的快照。复现不了的结果等于没有结果。每次运行一个新目录,同一个输出目录同时只允许一个进程写。
|
||
|
||
### 不设默认值
|
||
|
||
配置的每个字段都必填,函数参数不写默认值;可以没有的值显式写 null,不靠省略。缺了就报错。默认值会掩盖错误:字段名拼错、文档改了代码没跟上,流水线照样跑完,没人知道用的是哪个值。路径、模型名、服务地址同样不写死在代码里。
|
||
|
||
### 罕见情况怎么办
|
||
|
||
「可能会出现」不是写分支的理由。按顺序选:
|
||
|
||
1. 改数据的表示或格式要求,让它不可能出现。
|
||
2. 做不到,就在系统边界检查,不满足就报错停下。边界指交付的资料、模型的输出、负责人的配置。模块之间的调用不算边界,不互相防御。交付资料里只落在某一个病例上的问题是例外,见「错误怎么处理」。
|
||
|
||
一个抽象在出现第二个真实调用点之前不引入。不考虑向后兼容:不写兼容层,读到旧格式直接报错;发现更好的设计就按它重写,同步改文档和测试。
|
||
|
||
### 遇到问题先找原因
|
||
|
||
出了问题先查清为什么,再到原因所在的地方改。重试、跳过、补默认值、放宽解析、捕获异常后接着跑,只是让症状消失。动手前问:这个改动是让问题不再发生,还是让问题发生了也没人看见?
|
||
|
||
### 错误怎么处理
|
||
|
||
- **外部错误**(模型接口超时、网络断开):只在调用外部服务的那一处做有限次重试,仍失败就把这一步记为失败并写明状态。
|
||
- **内部错误**(资料不满足规则、不该有的状态组合):立刻停下,报错写清是哪条规则、哪个病例的哪个文件。模型交不出合格输出按内部错误处理。
|
||
- **交付资料里只落在某一个病例上的问题**(这一例的编号认不出、缺文件、取值不合规则、和别的表对不上等):跳过这一整例,接着处理下一例,并在标准答案库的跳过清单里写明这一例没过的是哪项检查、哪个文件哪一列。对一个病例,遇到第一项不过的检查就不再往下查,所以清单上每例只有一项,后面的检查没做过,不代表没问题。整张表读不了(工作表名或列名不对、文件缺失、配置不全)仍然立刻停下。跳过不是把问题藏起来:跳过清单交给医生核对,评价时要报告跳过了几例、各因为什么。来源:负责人 2026-10-16「都是遇到整个病例跳过,让医生核对去吧」。
|
||
|
||
中间层不写 try/except,除非它能把错误完整处理掉且上层不需要知道。不写 `except Exception: pass` 及其变体。
|
||
|
||
### 提示词
|
||
|
||
- 提示词引导模型怎么想,不设必填栏目:逼模型填栏目,它会为了填而编。只有程序确实要读的值才做成输出字段。
|
||
- 提示词是 `prompts/` 下的版本化文件,不散落在代码字符串里;给模型的提示词用英文。
|
||
|
||
### 测试
|
||
|
||
- 真实模型链路要用真跑证明,假模型测试证明不了;需要显卡或花钱的测试用 pytest 标记 `gpu`、`live` 区分,不进 `make check`。
|
||
- 修缺陷时附一条能复现原问题的测试。
|
||
- 不为方便测试给产品代码加参数、开关或分支;不靠删断言、改预期值或只保留成功的运行让测试通过。
|
||
|
||
### 规模与注释
|
||
|
||
- 每个模块的预期规模写在结构文档里;超过预期一倍时停下检查:是需求本身复杂,还是专门路径在变多。
|
||
- 注释只写这段代码现在做什么、为什么这样做;修改过程写进提交说明和 `WORK_LOG.md`。
|
||
|
||
## 文档
|
||
|
||
- **代码标识符用英文;注释、docstring、文档和回复用简体中文。**
|
||
- 读者是没参与过讨论的医学 AI 方向硕士生,也包括负责人:懂 Python 和深度学习,不认识 IPMN,也不知道我们讨论过什么。医学词、缩写、代号首次出现处就地解释;每个决策写清为什么。
|
||
- 同一个配置值只在一处定义,别处引用。
|
||
- `explanation/`、`guides/`、`reference/` 是常青文档:改了就重写那一段,不在后面追加「某日又改了」。
|
||
- 决策的来历写进 `research-wiki/design/NNNN-简短主题.md`,按顺序编号,写完冻结;决策变了新写一份,开头写明取代哪份,旧的开头加一行指向新的。
|
||
- `WORK_LOG.md` 只记当前状态:目标、已完成(附证据)、未完成、关键决定(附负责人原话)、下一步。一个阶段完成后压缩成几行。没有真实证据的「可能情况」只在汇报里提一句,不写进 `WORK_LOG.md`。
|
||
- **新写或大改一份文档**(新文档、重写整节、改动超过约 100 行),过一轮「硕士生阅读」:新鲜上下文的子 Agent 扮演这样的读者,只读这份文档,先列出最可能读不下去或要回头重读的段落、再复述要点,然后报哪句读不懂、哪个医学词没解释、哪个决策缺理由、哪个值两处不一致。不要让它描述自己的思考过程。格式和措辞建议不采纳。
|
||
|
||
## 提交规范
|
||
|
||
提交信息用英文前缀加中文正文,前缀按 Conventional Commits:`feat:`、`fix:`、`docs:`、`test:`、`refactor:`、`chore:` 等,可加作用域,例如 `feat(ceus): 暗区掩膜改用奇偶规则`。
|
||
|
||
## 本机环境的坑
|
||
|
||
- `grep`、`find`、`ps`、`diff` 可能被 shell 包装函数改写,静默少输出。搜索用 `/usr/bin/grep`、`/usr/bin/find`;查进程用 `pgrep -af`;比较文件用 `cmp` 或 `/usr/bin/diff`;看 git 差异用 `git --no-pager diff`。派出去的子 Agent 的 prompt 里也写上这一条。
|
||
- 超过约一分钟的命令放进 tmux 跑,日志写到文件。
|
||
- 日常开发和实验在本机(一张 RTX 4070 Ti SUPER 16GB)。需要用远程服务器(旧项目所在的 4090 服务器)时,ssh 和 rsync 一律走 `wangwenhan@202.38.247.58`,不走 Tailscale 地址 `100.83.164.94`(同一台机器,后者实测约 150KB/s,前者约 100MB/s)。它的显卡是共用的,命令必须显式设 `CUDA_VISIBLE_DEVICES`。
|
||
|
||
## 开发命令
|
||
|
||
- `make sync`:用 uv 同步项目环境和依赖。
|
||
- `make fmt`:用 ruff 自动修正并格式化。
|
||
- `make test`:运行不花钱、不需要显卡的测试。
|
||
- `make check`:依次检查 lint、格式、类型、导入边界并运行测试;失败即停止。
|
||
|
||
环境怎么搭见 `research-wiki/guides/开发环境.md`。
|