clinical-note-extract-skill

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Clinical Note Extraction

临床笔记提取

Structured extraction from clinical notes against a user-defined schema, with span citations for every value and explicit nulls for every absence. One note or many — the path is the same: an isolated no-tools worker extracts each note, then a deterministic validation pass verifies spans and codes.
This is the extraction primitive that care-gap reasoning, adverse-event detection, trial-eligibility screening, prior-auth evidence assembly, and registry abstraction sit on.
根据用户定义的schema从临床笔记中进行结构化提取,为每个值提供跨度引用,并为每个缺失值明确标记空值。无论是单份还是多份笔记,流程都是一致的:由独立的无工具worker提取每份笔记,然后通过确定性验证步骤验证跨度和编码。
这是用于护理差距推理、不良事件检测、试验资格筛选、预先授权证据汇编和注册库提取的核心提取模块。

Steps

步骤

1  Define schema   — references/01-define-schema.md
2  Extract         — workflows/extract-batch.js (one isolated worker per note)
3  Validate        — span check + run each field's `check`
4  Report          — references/03-review.md
1  定义schema   — references/01-define-schema.md
2  提取         — workflows/extract-batch.js(每份笔记对应一个独立worker)
3  验证        — 跨度检查 + 运行每个字段的`check`
4  报告          — references/03-review.md

Step 1 — Define schema

步骤1 — 定义schema

Read
references/01-define-schema.md
. Turn the user's request into a schema: each field is
{desc, finding?, check?}
.
desc
says what to look for in the note's own terms;
finding: true
means classify assertion;
check
is how step 3 validates (open-ended —
{kind: "terminology"|"range"|"date"|"pattern"|"enum"|..., ...params}
). Confirm with the user before extracting.
阅读
references/01-define-schema.md
。将用户的需求转化为schema:每个字段为
{desc, finding?, check?}
desc
说明要在笔记中查找的内容;
finding: true
表示需要分类断言;
check
是步骤3的验证方式(开放式定义 —
{kind: "terminology"|"range"|"date"|"pattern"|"enum"|..., ...params}
)。提取前需与用户确认schema。

Step 2 — Extract

步骤2 — 提取

However the user supplied notes — pasted text, file paths, a directory, PDFs, a FHIR connector, a database query — resolve each to plain text using whatever tools you have, then call the saved workflow with one
{id, text}
per note. The workflow's input contract is the only strict piece; how you get there is yours to figure out. It runs one
note-extract-worker
agent per note (no tools — note text is untrusted), each following
references/rules.md
, and returns one schema-enforced record per note:
Workflow({
  scriptPath: "<this skill dir>/workflows/extract-batch.js",
  args: {
    notes:  [{id, text}, ...],     // one or many
    schema: <the schema from step 1>,
    rules:  <Read references/rules.md verbatim>
  }
})
Workers have no tools — they return only what they read (
value
,
span
,
presence
/
temporality
/
experiencer
,
null_reason
,
unit
). All checks happen in step 3. Because note text rides inline in
args
, the workflow path tops out at a few dozen notes per call. For larger corpora, run
bun <this skill dir>/scripts/batch.ts <notes-dir> <schema.json> records.jsonl
instead — it reads files in trusted code and spawns one tool-disabled extraction per note with the same rules, then resume at step 3 over the resulting
records.jsonl
.
无论用户以何种方式提供笔记——粘贴文本、文件路径、目录、PDF、FHIR连接器、数据库查询——使用现有工具将其转换为纯文本,然后调用已保存的工作流,每份笔记对应一个
{id, text}
参数。工作流的输入约定是唯一严格要求的部分;具体的获取方式可自行决定。每份笔记会运行一个
note-extract-worker
Agent(无工具——笔记文本不可信),每个Agent遵循
references/rules.md
,最终返回每份笔记符合schema要求的记录:
Workflow({
  scriptPath: "<this skill dir>/workflows/extract-batch.js",
  args: {
    notes:  [{id, text}, ...],     // 单份或多份
    schema: <步骤1中定义的schema>,
    rules:  <Read references/rules.md verbatim>
  }
})
Worker无工具支持——仅返回读取到的内容(
value
,
span
,
presence
/
temporality
/
experiencer
,
null_reason
,
unit
)。所有检查都在步骤3中进行。由于笔记文本内嵌在
args
中,每次调用的工作流最多处理几十份笔记。对于更大规模的语料库,请运行
bun <this skill dir>/scripts/batch.ts <notes-dir> <schema.json> records.jsonl
——它会在可信代码中读取文件,并为每份笔记启动一个禁用工具的提取进程,遵循相同规则,然后基于生成的
records.jsonl
继续执行步骤3。

Step 3 — Validate

步骤3 — 验证

Runs here in the calling session. Deterministic — no model judgment. For every record:
  1. Span check. For every non-null field, confirm
    span
    appears verbatim in that note's source text. Attach
    span_verified
    .
  2. Run each field's
    check
    .
    Dispatch on
    check.kind
    :
    • terminology
      — dedupe
      (check.via, value)
      across all records, look each up via whatever connector answers to
      via
      , attach
      {code, code_status, display}
      . No connector for that
      via
      code_status: "unvalidated"
      , name it in the report.
    • range
      value
      vs
      [min, max]
      and
      unit
      vs
      check.unit
      ; attach
      range_flag
      .
    • date
      — confirm
      value
      parses as a date; attach
      date_ok
      .
    • pattern
      /
      enum
      — match; attach
      check_ok
      .
    • other / no
      check
      — nothing to attach.
A field is trustworthy when
span_verified
and its check (if any) passed. Adding a check kind = add a branch here; nothing upstream changes.
在调用会话中运行此步骤。过程具有确定性——无需模型判断。对于每条记录:
  1. 跨度检查。对于每个非空字段,确认
    span
    与该笔记源文本中的内容完全一致。添加
    span_verified
    标记。
  2. 运行每个字段的
    check
    。根据
    check.kind
    分发处理:
    • terminology
      — 去重所有记录中的
      (check.via, value)
      ,通过对应
      via
      的连接器查询,添加
      {code, code_status, display}
      。若该
      via
      无对应连接器,则
      code_status: "unvalidated"
      ,并在报告中注明。
    • range
      — 对比
      value
      [min, max]
      ,以及
      unit
      check.unit
      ;添加
      range_flag
      标记。
    • date
      — 确认
      value
      可解析为日期;添加
      date_ok
      标记。
    • pattern
      /
      enum
      — 匹配验证;添加
      check_ok
      标记。
    • 其他/无
      check
      — 不添加任何标记。
span_verified
为真且字段的检查(若有)通过时,该字段的数据是可信的。添加新的检查类型只需在此处增加分支;上游无需修改。

Step 4 — Report

步骤4 — 报告

Read
references/03-review.md
. Produce one row per (note, field):
note_id | field | value | presence/temporality/experiencer | span | check
. Below it, the completion summary: fields requested / populated / null, and per
check.kind
what passed vs flagged (name any terminology
via
that lacked a connector). Never let a failed check or unverified span pass silently.
Offer to write records + report to
~/.claude/data/healthcare/clinical-note-extract/<run-id>/
. That directory is local working state, not an archive: do not copy it to shared drives or external systems without the user's explicit instruction, and tell the user it can be deleted once they have what they need — extracted records carry whatever PHI was in the source notes.
阅读
references/03-review.md
。生成每行对应(笔记, 字段)的表格:
note_id | field | value | presence/temporality/experiencer | span | check
。表格下方是完成摘要:请求的字段数/已填充的字段数/空值字段数,以及按
check.kind
统计的通过与标记情况(注明任何缺少连接器的术语
via
)。绝不能让检查失败或未验证的跨度被忽略。
可将记录和报告写入
~/.claude/data/healthcare/clinical-note-extract/<run-id>/
。该目录为本地工作状态,而非归档:未经用户明确指示,请勿复制到共享驱动器或外部系统,并告知用户在获取所需内容后可删除该目录——提取的记录包含源笔记中的所有受保护健康信息(PHI)。

Output contract

输出约定

Worker emits, per field:
{value, span, location, presence?, temporality?, experiencer?, null_reason?, unit?}
— only what it read. Step 3 attaches
span_verified
plus whatever the field's
check
produced (
code
/
code_status
/
display
for terminology,
range_flag
for range, etc.).
Worker为每个字段输出:
{value, span, location, presence?, temporality?, experiencer?, null_reason?, unit?}
——仅包含读取到的内容。步骤3会添加
span_verified
以及字段
check
生成的内容(术语检查的
code
/
code_status
/
display
,范围检查的
range_flag
等)。

Optional — export as FHIR

可选 — 导出为FHIR格式

If the user wants FHIR resources instead of flat records, the assertion axes map directly:
recordFHIR
experiencer != patient
FamilyMemberHistory.condition
(not
Condition
)
presence: absent
verificationStatus: refuted
;
possible
unconfirmed
;
present
confirmed
Condition.verificationStatus
temporality: historical
inactive
;
current
active
Condition.clinicalStatus
temporality: hypothetical
no native field — omit, or use a
RiskAssessment
resource
value
+ terminology check result
Condition.code
as a
CodeableConcept
(
{text: value, coding: [{system, code, display}]}
)
span
+
location
Condition.note
or a provenance extension
This is a deterministic transform over the validated records — no model call. Offer it when the user names FHIR as the target; otherwise the flat records are the default.
若用户需要FHIR资源而非扁平记录,断言维度可直接映射:
记录字段FHIR字段
experiencer != patient
FamilyMemberHistory.condition
(而非
Condition
presence: absent
verificationStatus: refuted
;
possible
unconfirmed
;
present
confirmed
Condition.verificationStatus
temporality: historical
inactive
;
current
active
Condition.clinicalStatus
temporality: hypothetical
无原生字段——可省略,或使用
RiskAssessment
资源
value
+ 术语检查结果
Condition.code
作为
CodeableConcept
{text: value, coding: [{system, code, display}]}
span
+
location
Condition.note
或溯源扩展
这是对已验证记录的确定性转换——无需调用模型。当用户指定FHIR为目标格式时可提供此选项;否则默认输出扁平记录。

Prerequisites

前置条件

Connectors for whatever
check.via
values the schema names. Missing ones don't block extraction — those fields stay unvalidated and the report names them.
为schema中指定的所有
check.via
值提供连接器。缺失的连接器不会阻止提取——这些字段将保持未验证状态,并在报告中注明。