M6-L3.1M6-L3.2M6-L3.3案例概览:医疗机构研究
一句话: Provider Research Factory 把”全美所有泌尿科医生”这样的群体查询变成一份经过核验的数据集:五个 Puffo agent 负责需要判断的工作,确定性的 Python 流水线完成每一次下载、筛选、关联和计数,两道人工 gate 分别卡在高成本和高风险的步骤之前,而系统中没有任何东西能联系执业者。
一家公司需要接触某一类临床医生,可能是为了招聘,也可能是为了销售。它通常买一份名单或手工整理,两种方式以同样的方式失败:没人说得清为什么这位医生在名单里、那位不在,名单是否完整,数据有多新,哪些联系渠道是合法的。
这个系统在交付数据的同时回答这些问题。它的第一次构建在 2026 年 8 月 5 日完成,扫描了 9,671,888 条注册记录,产出一份 22,195 条记录的全美泌尿科数据集。之后同一条流水线又构建了心内科(73,394 条)和牙医(409,848 条)数据集。换一个目标群体只需改一个输入:专科及其代码集;下载、筛选、补充、QA 和打包都不变。
编排用确定性代码,模型只用于判断。 下载、流式读取、关联、标准化和打包都由脚本完成,因为脚本比 agent 更快、更可靠,而且确定性的阶段可以用断言来约束。模型只用在需要判断的地方:找数据源、决定哪些代码定义这个专科、攻击建好的数据集、撰写文档,以及营销分析。把模型放进逐行读文件的循环里,被视为设计缺陷。
Agent 名单
Section titled “Agent 名单”五个角色对应流水线需要的五个判断。它们运行在各自独立的 Puffo space 中,与这台机器上的其他业务完全隔离,使用 Claude Code harness。
| 角色 | 负责的判断 | 工具 |
|---|---|---|
| Research Lead | 唯一和人对话的 agent。推进状态机、派生其他 agent、运行流水线脚本、在两道 gate 处停下 | 子 agent、shell,只能写本次运行的目录 |
| Source Scout | 哪些注册库是权威的、每个文件里真正有什么(有效的下载链接和真实的列名)、值不值得下载;3 至 4 个并行,各用一个不同的检索角度(监管、学术、商业、开放数据目录) | 网页搜索、网页抓取、读取表头 |
| Taxonomy Specialist | 受控词表中哪些代码定义这个专科,并注明词表版本;哪些相邻代码默认排除 | 网页工具;shell 只能下载词表 |
| Challenger | 建好的数据集哪里不对:七个视角、每条问题三个复核者,以及一个重新推导代码集的盲审 critic | 只读仓库、仅限核验的 shell、网页工具 |
| Documentation Writer | 怎样解释结果:用平实语言写出来源、筛选规则、局限和联系规则 | 只读仓库 |
拿掉其中任何一个,流水线就少了一个自己做不出的判断。其余一切(下载、解压、筛选、补充、标准化、打包、输出校验)都是 Python 模块,不是 agent;每个角色的工具都限定在自己的工作范围内:找来源的角色不能写数据,写文档的角色不能运行脚本。
有两样东西刻意没有做成角色。下载前读取文件表头是代码的工作(一次范围请求加一次解析),随后由 Source Scout 判断这些列的含义,并有一条断言在声明的列缺失时阻止审批。营销分析(分群、排序、内容简报)是一个下游产品,通过营销视图和合规 gate 消费交付的数据集;见迁移。
一次查询怎么跑
Section titled “一次查询怎么跑”proposed → research Source Scout ×3–4 和 Taxonomy Specialist(并行);表头核对由代码完成 → GATE R 人工批准数据源、文件大小、代码集和磁盘预算 → fetching 可续传的并行下载,各来源之间不互相等待 → filtering 流式读取全量文件 → 屏障 → 补充 ×N → 屏障 → 标准化 → qa 先跑确定性检查,再跑七个视角;循环直到连续两轮无问题 → packaging CSV 拆分、工作簿、README、输出校验 → GATE D 人工批准交付物 → delivered 下游模块经由合规 gate 消费营销视图状态只能向前推进。断言失败或 QA 问题成立时,运行会退回到负责这个缺陷的阶段。两道 gate 都放在代价最小的位置:错误的数据源在 GATE R 被发现只需一次审阅,下载之后才发现则要赔上整次运行。
没有 RAG,也没有向量数据库。agent 的知识就是仓库本身:每个角色一份 brief,以及一份逐步记录第一次构建的方法论文档。
| 来源 | 提供什么 |
|---|---|
| NPPES 月度全量文件(压缩约 1 GB,解压 11 GB)及每周增量 | 姓名、分类代码、执照、地址、电话、传真;每周文件把数据更新到最新,同一 NPI 以最新行为准 |
| NPPES 停用 NPI 报告 | 剔除名单 |
| NUCC 分类代码表 | 定义专科的受控词表 |
| CMS Doctors and Clinicians | 所属执业集团、集团规模、医学院、毕业年份、远程医疗 |
| CMS Facility Affiliation 与 Hospital General Information | 具名的医院隶属关系 |
| Medicare Physician and Other Practitioners | 患者量和城乡属性,用于排序 |
注册库的搜索 API 只用于抽查。构建本身流式读取全量文件,因为无论哪个专科,全国扫描的规模都一样。
这个设计要防止的三个缺陷
Section titled “这个设计要防止的三个缺陷”第一次构建之所以能正确交付,是因为 QA 抓住了三个真实缺陷。现在每一个都有常设的防护。
| 缺陷 | 发生了什么 | 防护 |
|---|---|---|
| 静默的空关联 | 机构文件里根本没有机构名称这一列;加载器什么也没找到,返回空结果却没有报错,于是每条医院隶属信息都会以空值交付 | 每个声明的列都必须存在;每次关联都有最低匹配率 |
| 对领域术语做子串匹配 | 按名称筛选 “urolog” 时也匹配到了 “neurology”;一次校验查询因为混进神经科记录,报出了 28,841 个泌尿科 NPI | 只用精确匹配的代码集;在受控词表上按名称子串筛选,本身就被定义为缺陷 |
| 只信单一来源的状态标记 | 月度文件自带的状态标记漏掉了一个已停用的 NPI,而独立的停用报告里有它 | 始终与独立的权威剔除名单交叉核对 |
- 记录不等于人。 一位医生可能出现在多个代码下,机构记录和个人记录混在一起,退休的执业者仍在名单上。泌尿科 NPI 中约 54% 不向 Medicare 计费。
- 词表决定答案。 选定代码集是整个构建中最主要的判断。例如妇产科的泌尿妇科与泌尿科相邻,默认被排除。
- 自填数据会过期。 注册信息只有在执业者自己更新时才会刷新;方法论预计有 10% 至 20% 已经过时。
- 关联天生是部分的。 对泌尿科而言,Doctors and Clinicians 匹配了 46.4% 的记录,Medicare 使用数据匹配了 41.2%。每个来源声明自己的最低匹配率,每次运行的 manifest 都会与上一次比较;任何匹配率相对下降 20% 就会报警,说明来源的结构变了。
合规写进结构
Section titled “合规写进结构”合规 gate 是代码而不是 prompt,因为模型可以被说服绕过一段 prompt,却绕不过一次被阻止的函数调用。compliance/channel_rules.py 对每个渠道给出结论:传真被阻止(每份未经请求的广告传真面临 500 至 1,500 美元的法定赔偿),短信和自动拨号被阻止,没有记录同意依据的邮箱被阻止,未知渠道一律阻止,DIRECT 安全邮箱也被阻止。营销视图在写出时就不含 DIRECT 字段,营销模块只读取这个视图。仓库中没有任何发送路径;路线图刻意先做分析和合规 gate,再考虑任何对外渠道。
这是基于公开职业注册信息的医疗机构研究和潜在客户挖掘,不使用患者数据,也不做任何临床判断。
- “五个 agent 就是五个人在建数据集。” 它们没有一个在建数据集。它们决定数据集应该是什么、检查它、解释它;构建由流水线完成。
- “QA 跑得越多越好。” 重复同样的检查,不如换不同的问题。QA 用七个不同视角,在连续两轮无问题后停止,而不是跑固定次数。
- “提出的问题就是问题。” 只有附带可复现的步骤,并且在三个被要求去推翻它的复核者中至少有两个确认,才算成立。不确定时默认不成立,因为虚假缺陷会浪费重建时间。
- “营销应该放在同一个系统里。” 它只读数据集、从不写回,所以是一个独立的产品,应有自己的 PRD。这个系统必须保留的是边界:受限字段在结构上不存在的营销视图,以及合规函数。
为什么下载和筛选没有对应的 agent?
因为这些步骤不需要判断。脚本流式读取一个 11 GB 的文件,比模型更快、更便宜、更可靠,每次结果都一样,还能用断言来约束。agent 只留给那四五个答案取决于推理的地方。
在第一次构建中,下载前读取表头能省掉什么?
那次静默的空关联。在下载前读一下机构文件的表头,只需一次范围请求,就能发现它没有机构名称这一列,而不必等到构建产出了一堆空的医院隶属信息才发现。
为什么要让 ontology critic 看不到 ontology agent 的答案?
先读过推导过程的审查者往往会同意它。这个 critic 由 QA 一方而不是推导者来委派,只拿到专科名称和词表链接。它独立得出的代码集,再和已发布的代码集做对比。
- 文档:NPPES NPI Registry API(CMS)
- 文章:Entity resolution: one real thing, many messy names(DEV)
- 文档:dbt source freshness(dbt Labs)
- 文章:Understanding data lineage(Datadog)
- 文档:LangGraph interrupts(LangChain),用于在高成本或高风险步骤前设置人工 gate
Syllabus 行:M6-L3.1、M6-L3.2、M6-L3.3