Install any skill in seconds. Free to start, no credit card required.
Get Started Free →中国药品权威数据库查询 — NMPA(国家药监局) + CDE(药品审评中心) + DrugBank(英文名/ATC) + PubChem(化学结构) 多源融合,提供(通用名 ↔ 商品名 ↔ 英文名 ↔ 适应症 ↔ NMPA 批文号 ↔ 上市日期)精确映射。Make sure to use this skill whenever the user mentions 药品名 / 通用名 / 商品名 / NMPA / 国药准字 / 药监局 / CDE / drug brand name / generic name / drug registry / pharmaceutical lookup / drug verification / 药物核验 / 商品名对应 / drug cross-check / drug authority lookup. 在任何 medical / market-sizing / clinical / disease-research 报告生成阶段,**所有药品提及必须先调 lookup_drug() 验证**,严禁 LLM 凭训练记忆拼凑通用名↔商品名↔英文名
.claude/skills/ethanyoq-nmpa-drug-registry-lookup/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 97% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 170% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 161% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 117% | 0% |
中国市场所有报告里的药品提及,都从此 skill 拿权威记录(NMPA + CDE + DrugBank + PubChem 多源融合);LLM 不允许凭记忆改写药品名。
任何写入报告的药品名(通用名 / 商品名 / 英文名),必须通过 lookup_drug() 验证。
LLM 不允许凭训练记忆拼凑通用名↔商品名↔英文名对应关系 — 因为:
唯一允许的姿势:
pythonfrom nmpa_drug_registry_lookup.scripts.registry import lookup_drug, UnverifiedDrugError rec = lookup_drug("洛拉替尼") if rec is None: raise UnverifiedDrugError("洛拉替尼 not in NMPA registry — refuse to write to report") # 报告里写药名时,通用名和商品名都从 record 取,不要手输 generic_zh = rec.generic_name_zh # "洛拉替尼" generic_en = rec.generic_name_en # "Lorlatinib" brand_zh = rec.brand_names_zh[0] # "博瑞纳"
绝不允许:
python# 错误!LLM 凭记忆 report_html += "<p>洛拉替尼(商品名:赛可瑞)...</p>" # 赛可瑞实际是克唑替尼! report_html += "<p>布加替尼(商品名:博瑞纳)...</p>" # 博瑞纳实际是洛拉替尼!
medical-evidence-grading / disease-market-sizing-orchestration 调用方需要药名锚定cross_check_drug_mentions() 全文扫描,catch LLM 偷偷凭记忆改写的药名pubtator-entity-search 抓基因/通路)clinical-trials-v2) ┌─ pubmed-eutils(召回主力)
召回层 ───┬─────────────┤
│ └─ europepmc-search
│
│ ┌─ cn-clinical-guidelines-fetch(指南权威)
权威层 ───┼─────────────┤
│ └─ ★ nmpa-drug-registry-lookup(本 skill · 药品权威)
│
▼
报告生成层 ─── 所有药品名引用 → lookup_drug() / cross_check_drug_mentions()调用顺序:
pythonfrom dataclasses import dataclass from pathlib import Path @dataclass(frozen=True) class DrugRecord: """中国药品权威记录。frozen 防止 LLM 修改。""" generic_name_zh: str # 通用名(中文,首选 NMPA 命名) generic_name_en: str # 通用名(英文,DrugBank/INN) brand_names_zh: tuple[str, ...] # 商品名列表(中国市场,可能多个生产厂家) brand_names_en: tuple[str, ...] # 商品名列表(全球) nmpa_approval_no: str # NMPA 批准文号(如 国药准字 H20180123 / 进 J20180012) first_approval_date_cn: str # 中国首次上市日期 ISO yyyy-mm-dd indications_cn: tuple[str, ...] # 适应症(中文) atc_code: str # ATC 分类(如 L01ED05 = 抗肿瘤 ALK 抑制剂) target: str # 靶点(对靶向药,如 "ALK") drug_class: str # 类别(如 "三代 ALK-TKI") sources: tuple[str, ...] # 来源 URL,可追溯 class UnverifiedDrugError(Exception): """lookup 失败时调用方应 raise — 拒绝写入报告。""" def lookup_drug( name: str, # 任意名称(通用/商品/英文,模糊匹配) market: str = "CN", cache_dir: Path | None = None, ) -> DrugRecord | None: """单药查询。匹配优先级: 1. 已知 fallback dict 精确命中(NMPA 网站抓不到时的兜底) 2. NMPA 精确通用名 3. NMPA 商品名 4. DrugBank generic_name 5. PubChem 化学名 fallback None = 该药不在权威数据库 → 调用方必须 raise UnverifiedDrugError。 """ def lookup_drugs_batch( names: list[str], market: str = "CN", cache_dir: Path | None = None, ) -> dict[str, DrugRecord | None]: """批量查询。返回 {name: DrugRecord or None}。""" def cross_check_drug_mentions( text: str, # 报告 HTML / Markdown 草稿 market: str = "CN", cache_dir: Path | None = None, ) -> dict: """扫描文本里所有疑似药品名,逐个 lookup,返回错误清单。 Returns: { "ok": bool, "verified_drugs": [...], # 命中权威数据库的药名 "unverified_drugs": [...], # 在数据库找不到 → 必须修 "name_mismatches": [ # 通用名/商品名混用错位(critical) {"text_uses": "赛可瑞", "claimed_as": "洛拉替尼", "actual_generic": "克唑替尼", "evidence_source": "NMPA"}, ... ], "violation_severity": "none" | "warning" | "critical", } 严重性规则: - 任何 name_mismatches 非空 → critical(LLM 把 A 药写成 B 药商品名) - 仅 unverified_drugs 非空 → warning(可能是新药 / 仿制名) - 全部 verified → none """
| 来源 | 提供 | 抓取方式 | |-----|------|---------| | NMPA 国家药监局 (nmpa.gov.cn) | 通用名 / 批文号 / 适应症 / 上市时间 (权威 I 级) | REST + WebFetch + bs4 | | CDE 药品审评中心 (cde.org.cn) | 临床试验阶段 / 适应症详情 | WebFetch | | DrugBank(免费学术) | 英文名 / ATC code / mechanism | API / scrape | | PubChem(NIH) | 化学结构 / IUPAC / 同义词 | REST(pug.ncbi.nlm.nih.gov/rest/pug) | | NCBI Gene | 靶点基因(已通过 pubtator-entity-search 间接) | 复用 |
fallback 兜底:NMPA 网站反爬严重时,scripts/_known_drugs_fallback.py 含一份手工核验的常用药字典,每条都有 NMPA 公开页 URL 引用作来源。
| # | 症状 | 原因 | 修复 | |---|------|------|------| | 1 | lookup 返回 None | 药品不在 NMPA(可能仿制名 / 进口未上市 / 拼写错)| 让用户确认是否仍写入,标 unverified;不允许 LLM 凭记忆补 | | 2 | 同一通用名多个商品名 | 多厂家(如阿仑膦酸钠) | brand_names_zh 列出全部,不要任选一个 | | 3 | 通用名↔商品名错位(LLM 偷偷脑补) | LLM 训练截止后数据老化 | cross_check_drug_mentions 全文扫描,critical 级 raise | | 4 | NMPA 网站抓取失败(反爬) | nmpa.gov.cn 改版 / 验证码 | 降级:cache → fallback dict → 报错 | | 5 | 同一英文名对应多个中文音译 | 早期未规范化 | NMPA 通用名为唯一权威,其他作 alias | | 6 | DrugBank 拒绝学术抓取 | 反爬升级 | 该字段标 None,不阻塞主流程(NMPA 字段是必需) | | 7 | LLM 在 prompt 里"脑补"通用名 | 训练数据过时 | 任何 grade_evidence / LP 阶段都强制 lookup,不接受 LLM 直出 | | 8 | 进口药批文号格式 vs 国产不同 | NMPA 编号规则:H/J/Z/S 前缀 | 不要自行拆解,作为 opaque string 存储 |
X | None 类型注解)httpx, beautifulsoup4, 可选 pypdf(适应症附件解析)python -m pytest(Windows 用 C:\Python3\python.exe -m pytest,不要用 python3 stub)sys.stdout.reconfigure(encoding="utf-8")<cache_dir>/drug_registry.json,TTL 7 天;SQLite 是 future worktests/fixtures/nmpa_responses/*.html 预录制响应,绝不在 CI 里直连 NMPApythonfrom nmpa_drug_registry_lookup.scripts.registry import lookup_drug, UnverifiedDrugError rec = lookup_drug("洛拉替尼") if rec is None: raise UnverifiedDrugError("洛拉替尼 not in NMPA registry — refuse to write to report") print(rec.generic_name_en) # "Lorlatinib" print(rec.brand_names_zh) # ("博瑞纳",) print(rec.atc_code) # "L01ED05" print(rec.first_approval_date_cn) # "2022-04-29"
pythonfrom nmpa_drug_registry_lookup.scripts.registry import lookup_drugs_batch key_drugs = ["克唑替尼", "阿来替尼", "塞瑞替尼", "恩沙替尼", "布加替尼", "洛拉替尼", "伊鲁阿克", "依奉阿克"] results = lookup_drugs_batch(key_drugs) missing = [d for d, r in results.items() if r is None] if missing: raise UnverifiedDrugError(f"NMPA registry missing: {missing}") # 写入 .cache/<slug>/drug_registry.json,后续报告生成阶段 LLM 必须从此取
pythonfrom nmpa_drug_registry_lookup.scripts.registry import cross_check_drug_mentions result = cross_check_drug_mentions(report_html) if result["violation_severity"] == "critical": # LLM 把 A 药写成 B 药商品名 — 必须重生成 raise OrchestrationError(f"drug name mismatches: {result['name_mismatches']}") elif result["violation_severity"] == "warning": # 仅有 unverified(可能是新药)— §0 加红色警告 add_section_zero_warning(result["unverified_drugs"])
cn-clinical-guidelines-fetch(指南先告诉本 skill 该疾病有哪些药)disease-market-sizing-orchestration(在内容生成阶段强制锚定)、content-verification-layer(report-level cross-check 的事实审计层)pubtator-entity-search(基因靶点)、pubmed-eutils(文献召回)参考文档:
references/nmpa-fetch-api.md — NMPA 网站结构 + 抓取策略references/drugbank-integration.md — DrugBank 学术免费用法references/failure-modes.md — 8 失败模式详解| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-03 | fail→fail | 16,175 | 17,974 | +11% | 1 | 1 | 0% | 3,356 | 7,278 | +117% | 0 | 0 | — |
case-01 | fail→fail | 11,516 | 8,300 | -28% | 1 | 1 | 0% | 2,344 | 4,560 | +95% | 0 | 0 | — |
case-02 | fail→fail | 16,666 | 12,185 | -27% | 1 | 1 | 0% | 3,422 | 6,034 | +76% | 0 | 0 | — |
case-04 | fail→pass | 13,438 | 10,276 | -24% | 1 | 1 | 0% | 2,817 | 5,537 | +97% | 0 | 0 | — |
case-05 | fail→pass | 19,221 | 9,286 | -52% | 1 | 1 | 0% | 3,762 | 5,149 | +37% | 0 | 0 | — |
case-06 | fail→fail | 14,450 | 10,591 | -27% | 1 | 1 | 0% | 2,808 | 5,377 | +91% | 0 | 0 | — |
case-07 | fail→pass | 11,035 | 11,443 | +4% | 1 | 1 | 0% | 2,104 | 5,681 | +170% | 0 | 0 | — |
case-08 | fail→pass | 12,396 | 10,720 | -14% | 1 | 1 | 0% | 1,979 | 5,156 | +161% | 0 | 0 | — |
case-09 | fail→pass | 13,025 | 8,735 | -33% | 1 | 1 | 0% | 2,290 | 4,971 | +117% | 0 | 0 | — |
case-10 | fail→pass | 8,431 | 4,818 | -43% | 1 | 1 | 0% | 1,664 | 4,246 | +155% | 0 | 0 | — |
case-11 | fail→pass | 12,301 | 13,522 | +10% | 1 | 1 | 0% | 2,246 | 5,920 | +164% | 0 | 0 | — |
case-12 | fail→pass | 15,650 | 11,449 | -27% | 1 | 1 | 0% | 3,282 | 5,773 | +76% | 0 | 0 | — |
case-13 | fail→pass | 13,639 | 3,078 | -77% | 1 | 1 | 0% | 2,485 | 3,848 | +55% | 0 | 0 | — |
case-14 | fail→pass | 10,019 | 10,344 | +3% | 1 | 1 | 0% | 2,116 | 5,563 | +163% | 0 | 0 | — |
case-15 | fail→fail | 16,180 | 17,792 | +10% | 1 | 1 | 0% | 3,021 | 7,716 | +155% | 0 | 0 | — |
case-16 | pass→pass | 8,539 | 3,110 | -64% | 1 | 1 | 0% | 1,679 | 3,858 | +130% | 0 | 0 | — |
case-17 | fail→pass | 13,404 | 13,206 | -1% | 1 | 1 | 0% | 2,711 | 6,298 | +132% | 0 | 0 | — |
case-18 | fail→pass | 9,885 | 8,927 | -10% | 1 | 1 | 0% | 2,095 | 5,270 | +152% | 0 | 0 | — |
case-19 | fail→pass | 9,211 | 3,190 | -65% | 1 | 1 | 0% | 1,995 | 3,953 | +98% | 0 | 0 | — |
case-20 | pass→pass | 8,686 | 8,774 | +1% | 1 | 1 | 0% | 2,005 | 5,132 | +156% | 0 | 0 | — |
case-21 | pass→pass | 8,141 | 15,918 | +96% | 1 | 1 | 0% | 1,893 | 6,958 | +268% | 0 | 0 | — |
case-22 | pass→pass | 13,506 | 13,306 | -1% | 1 | 1 | 0% | 3,229 | 6,481 | +101% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +59 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.