# 药物数据，供应用和 AI 代理使用

> 患者用药列表 vs 药物知识：FHIR 资源、RxNorm、ATC、openFDA 和 EMA 数据源，以及 FHIR 记录与 RxNorm 和 FDA 标签的已测试联合。

Source: https://developers.anpheros.com/zh/guides/medication-data-ai-agents

**医疗软件需要两种不同类型的药物数据：患者的用药列表——这个人服用什么药物，从何时开始，剂量如何，由谁记录——以及药物知识——产品包含什么，其官方标签，警告和相互作用。** 前者属于患者记录；后者来自权威药物数据库。混淆它们会导致 AI 代理从模型记忆中陈述药物事实。本页将解释这两者，涉及的 FHIR R4 资源和代码系统，美国和欧盟存在的公共数据源，以及一个将 FHIR 记录中的患者列表与 RxNorm 和 FDA 标签联合的有效示例。

## 两种药物数据

| | 患者用药列表 | 药物知识 |
|---|---|---|
| 回答 | Ana 正在服用什么药物，从什么时候开始，多久一次？ | 什么是二甲双胍 500 毫克，其标签有什么警告？ |
| 变更 | 当患者或临床医生更新时 | 当监管机构或发布者更新时 |
| 存储位置 | 患者记录（EHR、PHR、FHIR 服务器） | 药物数据库和术语集 |
| FHIR | `MedicationStatement`、`MedicationRequest`、`MedicationAdministration`、`Medication` | 大部分在记录之外；产品信息本身可以是 FHIR |
| 谁可以读取 | 仅在获得患者同意后 | 公开或已授权 |

一个回答“我是否可以与我的降压药一起服用布洛芬？”的应用程序或代理需要两者：患者的列表以了解服用的是哪种药物，以及药物知识来源以了解有关该组合的已知信息——再加上临床医生或药剂师来给出答案。

## 药物列表的 FHIR 资源

- **MedicationStatement**：患者正在服用、已服用或已停用的药物（患者报告或由临床医生记录）。通常用于 PHR 或核对列表的资源。
- **MedicationRequest**：处方或医嘱。
- **MedicationAdministration**：已服用或已给予（或跳过）的一剂药物，用于依从性分析。
- **Medication**：药物产品本身，当需要比代码更多的详细信息时（成分、剂型、批次）。

药物通过代码进行编码：在美国使用 **RxNorm**（来自美国国家医学图书馆）和 NDC 产品代码；国际上使用 WHO **ATC** 分类；在欧洲也使用国家产品代码，并且越来越多地使用 EMA 的基于 FHIR 的电子产品信息。一个声明可以携带同一种药物的多个编码。

## 药物知识来源

**美国**

- [RxNorm API](https://lhncbc.nlm.nih.gov/RxNav/APIs/RxNormAPIs.html) (NLM): 临床药物的标准化名称和标识符 (RXCUI)；免费，除一项例外，无需许可。
- [openFDA drug label API](https://open.fda.gov/apis/drug/label/) (FDA): 结构化的产品标签 — 适应症、黑框警告、禁忌症、药物相互作用部分 — 可通过 RXCUI 进行搜索。
- DailyMed (NLM): 供人们阅读的相同标签。

**欧洲联盟**

- 欧洲药品管理局发布了集中授权药品的上市许可信息，其电子上市许可信息 (ePI) 基于 FHIR 构建。国家授权的产品存在于国家注册表中。
- ATC 代码和标准日剂量由世界卫生组织药物统计方法合作中心维护。

**相互作用**是最难的部分。NLM 于 2024 年 1 月左右停用了其药物相互作用 API，而如今全面的相互作用检查依赖于获得许可的临床知识库。标签的相互作用部分是为临床医生编写的文本，而不是用于检查的工具。

## 关联记录与药物知识

该示例从 Anpheros 读取患者的活动用药，将每个名称解析为 RxNorm 概念，并获取 FDA 标签。它在平台的本地实例以及实时的 RxNorm 和 openFDA API 上运行。

```ts
import { Anpheros, apiKey } from '@anpheros/sdk';

const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) });

// 1. What the person takes: from their record (ATC codes, names as they were entered)
const { data: meds } = await anpheros.medications.list(patientId, { status: 'active' });

// 2. What each medicine is: RxNorm (US National Library of Medicine), free, no key
async function rxcui(name: string): Promise<string | null> {
  const r = await fetch(`https://rxnav.nlm.nih.gov/REST/approximateTerm.json?term=${encodeURIComponent(name)}&maxEntries=1`);
  const j: any = await r.json();
  const id = j.approximateGroup?.candidate?.[0]?.rxcui;
  if (!id) return null;
  // An approximate match can be an outdated concept: keep it only if RxNorm still describes it as a drug
  const props: any = await (await fetch(`https://rxnav.nlm.nih.gov/REST/rxcui/${id}/properties.json`)).json();
  return ['SCD', 'SBD', 'GPCK', 'BPCK'].includes(props.properties?.tty) ? id : null;
}

// 3. What the official label says: openFDA drug label API (US FDA), free
async function label(id: string) {
  const r = await fetch(`https://api.fda.gov/drug/label.json?search=openfda.rxcui:%22${id}%22&limit=1`);
  if (!r.ok) return null;
  const doc: any = (await r.json()).results?.[0];
  return doc && { set_id: doc.set_id, boxed_warning: doc.boxed_warning?.[0]?.slice(0, 120), has_interactions_section: !!doc.drug_interactions };
}

for (const m of meds) {
  const id = await rxcui(m.display);
  console.log(JSON.stringify({ record: { display: m.display, atc: m.code, dosage: m.dosage }, rxnorm: id, fda_label: id ? await label(id) : null }));
}
```

一位报告了二甲双胍和依那普利患者的输出：

```
{"record":{"display":"Metformin 500 mg tablet","atc":"A10BA02","dosage":"500 mg twice a day"},"rxnorm":"861007",
 "fda_label":{"set_id":"011de1a5-…","boxed_warning":"BOXED WARNING WARNING: LACTIC ACIDOSIS …","has_interactions_section":true}}
{"record":{"display":"Enalapril maleate 10 mg oral tablet","atc":"C09AA02","dosage":"10 mg once a day"},"rxnorm":"858817",
 "fda_label":{"set_id":"074fe718-…","boxed_warning":"WARNING: FETAL TOXICITY …","has_interactions_section":true}}
```

**运行中我们学到的经验。** 当名称写为“Enalapril 10 mg tablet”时，RxNorm 的近似匹配返回了 RXCUI 328290，这是一个 RxNorm 不再描述的概念，没有与之关联的标签。使用完整的临床名称“enalapril maleate 10 mg oral tablet”时，它返回了 858817，这是一个当前有标签的临床药物。人们输入的名称是近似的；请检查匹配项解析到的内容，一旦确认就存储代码，并向用户展示匹配的内容。

## AI 代理的规则

1. **绝不允许模型从内存中提供药物事实。** 提供患者的记录列表和权威来源的相关文本，并要求其引用。
2. **保持两个来源可见。** “您服用二甲双胍（您的记录，您于 3 月 3 日录入）”和“FDA 标签警告乳酸性酸中毒（标签集 011de1a5…）”是具有不同所有者的不同声明。
3. **缩小范围。** 只需要药物列表的代理应获得 `MedicationStatement` 的读取访问权限，而不是整个记录。使用 Anpheros，这可以通过授权范围或 MCP 服务器的只读工具来实现。
4. **不要回答需要临床医生才能回答的问题。** 药物相互作用、剂量调整和停药应咨询药剂师或医生；代理可以准备问题。

## Anpheros 的定位

Anpheros 存储了用药列表：`MedicationStatement` 和 `MedicationAdministration`（包含 ATC 或其他代码）、记录每项的个人、历史记录以及其他应用的授权信息；[上下文 API](https://developers.anpheros.com/zh/guides/ai-healthcare) 在为模型准备的摘要中包含当前用药信息，而 [MCP 服务器](https://developers.anpheros.com/zh/guides/mcp) 以只读方式向代理公开这些信息。它包含一个小的 ATC 子集（约 50 种常用药物）以自动命名代码；任何其他代码均被接受，但没有自动命名。

它不是药物数据库：它不提供药品标签、药物相互作用、剂量或禁忌症信息，并且目前不支持 `MedicationRequest` 或 `Medication` 资源。

## 常见问题解答

### 哪个 FHIR 资源应该用于药物列表？
`MedicationStatement` 用于记录一个人正在服用或曾经服用过的药物，包括患者报告的药物。处方是 `MedicationRequest`；单个剂量是 `MedicationAdministration`。

### 有免费的药物数据库 API 吗？
在美国，RxNorm (NLM) 提供药物标识符和名称，openFDA 提供官方产品标签，这些都是免费的。在欧洲，EMA 和各国机构会发布产品信息。全面的药物相互作用检查通常需要一个授权的知识库。

### AI 代理应如何获取药物信息？
通过两个工具：一个工具在获得同意后读取患者记录中的药物列表，另一个工具查询权威的药物来源。代理应引用两者，并将临床决策留给专业人士。

### Anpheros 是否检查药物相互作用？
否。它存储一个人正在服用的药物，并附带来源和同意信息。药物相互作用检查属于药物知识来源和临床医生的职责。

## 相关

- [AI 代理与医疗数据](https://developers.anpheros.com/zh/guides/ai-agents-medical-data)
- [如何授予 AI 代理访问医疗记录的权限](https://developers.anpheros.com/zh/guides/ai-agent-access-medical-records)
- [面向 AI 代理的 FHIR MCP 服务器](https://developers.anpheros.com/zh/guides/mcp)
- [FHIR 代码系统](https://developers.anpheros.com/zh/guides/fhir-code-systems)
- [FHIR R4 MedicationStatement 示例](https://developers.anpheros.com/tools/fhir-examples/medication-statement)
