Skip to main content
Glama

stcc-mcp — 电话分诊分级:规则确定性算,0.6B 只核对判据

一段问诊记录进去,出 L1–L5 档位 + 处置措辞 + 逐条引文 + 还缺哪几条判据。 分级由确定性规则引擎算出(225 份 STCC 协议 / 849 分支 / 4,168 条判据,随包分发), Qwen3-0.6B 只回答一件事:给定记录和一条判据,yes / no / unknown。

模型不选分支、不定档位、不生成处置措辞、不做 tool call。

⚠️ 不是急诊分诊系统,不做诊断,不能替代医生。L1–L5 是处置阶梯 (叫救护车 / 立即急诊 / 今天就医 / 近两日门诊 / 居家观察)。紧急情况直接拨 120。

三步跑起来

pip install stcc-mcp                                       # 或 uvx stcc-mcp …
ollama pull hf.co/chenhaodev/stcc-checker-0.6b-GGUF:Q8_0   # 640MB 核对器
stcc-mcp doctor                                            # 自检:索引 / Ollama / 模型
stcc-mcp triage --protocol Chest_Pain.md "$(cat 记录.txt)"

零常驻进程、零 Docker、不联网。引擎是纯标准库,无第三方依赖。

第一次运行大概率会看到 tier: L1 + certain: false —— 这是对的

拿一段普通问诊记录进去,很可能得到最紧急档加一串 unresolved。不是判错: 引擎只有在某支全部条件都为 no 时才敢排除它,而一次真实问诊不会把一支的判据问完。 例如轻症发热的记录里护士问了意识/呼吸/颈硬/皮疹,却从没问过脱水体征 (排尿减少、眼窝凹陷、皮肤张力差、口渴),于是该支排除不掉,输出停在它的档位上界。

unresolved 就是"再问这几条就能收紧"的清单。 把答案补进记录重跑, unresolved 会单调变短;但档位只有在某支被完全排除时才会降—— 实测同一份发热记录补齐脱水体征后 unresolved 8→2,档位仍停在 L1, 因为剩下的主干(老年人或免疫低下者…脱水表现: 这种半截话)核对器给的是 unknown。 这时候该动的是下面那个阈值旋钮,不是继续问。详见边界 ①②。

接进 agent(Claude Code / 任何 MCP client):

pip install "stcc-mcp[mcp]" && stcc-mcp serve               # stdio MCP

Ollama 不支持 MCP,而这对本形态不是问题:小模型从不 tool call, 编排层分别去调 Ollama(HTTP)和规则引擎(进程内),两者互不相识。 0.6B 自主 tool-calling 是已知重灾区,这个架构从设计上绕开了它。

Related MCP server: Quellgeist

输出

字段

含义

tier

L1–L5,安全上界:永不比真实答案更轻

disposition

该分支的处置措辞(来自规则表,不是模型生成)

certain

true = 证据已足以定档;false = 这是 worst_case 上界

citations

判定依据的判据 + 行号,可审计

unresolved

还缺哪几条判据 —— 补问它们就能收紧档位

档位到行动的映射由你的编排层定;本包只给档位与处置措辞。

判 no 的门槛是一个旋钮

--no-threshold(默认 0.63):P(no) ≥ τ ⇒ no,否则在 yes/unknown 里取大者。 同一个模型在发布分布(n=3225)上的整条取舍曲线:

τ

acc

false_no🔴

no_recall

0.63(默认)

0.9426

0.0000

0.9027

0.50

0.9457

0.0000

0.9189

0.40

0.9495

0.0024

0.9378

0.30

0.9498

0.0084

0.9432

0.10

0.9516

0.0120

0.9635

同一段发热问诊记录,只改 τ:

$ stcc-mcp triage --protocol Fever_Adult.md --no-threshold 0.63 "$(cat 记录.txt)"
  tier L1 · 拨打救护车        · unresolved 2
$ stcc-mcp triage --protocol Fever_Adult.md --no-threshold 0.40 "$(cat 记录.txt)"
  tier L3 · 2小时内接受医疗护理 · unresolved 5

τ 调低 ⇒ 核对器更敢把"问过且被否认"的判据判成 no ⇒ 分支被排除 ⇒ 档位下降。 这不是让模型更准,是在同一条取舍曲线上换工作点——换来的是漏诊风险上升。

false_no(该成立却判成 no)是硬门——假 no 会把真值分支从安全收敛里排除掉。 少判 no 只造成过分诊,是成本旋钮。 ⚠️ 默认 τ=0.63 是经验工作点,不是统计上"控制住了"的阈值。 按 Neyman-Pearson 范式(Tong et al., Sci Adv 2018, arXiv:1608.03109), 要以 95% 置信把 false_no 控制在 0.0036 以下,dev 需 ≥831 条正例;我们只有 495—— 即便最保守的阈值,真实 false_no 超标概率仍有 16.8%,495 条只能可靠控制到 α≈0.006。 文献还点名了我们用的那种选法(直接限制经验 type I error ≤ α)不构成控制。 ⇒ 当工作点用,别当保证用;曲线一起给出,按自己的代价矩阵挑点。 python -m scripts.threshold_sweep --pick-tau 会自己报可行性。 复现:python -m scripts.threshold_sweep --model <m> --split <s> --collect --report。

🔴 已知边界(先读这段再决定用不用)

① 「该用哪份协议」这一步本包不提供。 --protocol 是必填参数,需要调用方给——完整链路里这一环是空的:

一段问诊记录 ──[?? 谁来选协议 ??]──► protocol_id ──► 本包(引擎 + 核对器)──► L1–L5
                     ↑ 缺这一环

推荐形态:编排层用一个大模型看中文标题菜单来选(stcc-mcp protocols 可打印,225 份)。 上一轮(run1,221 份协议的菜单,34 条真实自述)实测:大模型菜单选择 @1 = 0.85(原文直选)/ 0.94(先抽一句主诉再选)· @2 = 1.00; 而用判据文本做向量检索定协议只有 @1 = 0.18 —— 同一句判据(如"恶心或呕吐") 跨几十份协议出现,判据级索引天然定不了协议,这条路已证伪,别再走。 选错协议时引擎的 referral / indeterminate 状态是自纠网,但那是网,不是替代。

② 输入必须是「已按协议问过一轮」的记录,不是原始自述。 短主诉 unknown 率 94%;真实富对话(IMCS-21,748 字 / 40 轮)仍有 88%。 原因是 STCC 前置分支筛的是急症红旗(噎着、发紫、无反应), 而自然产生的语料按定义不含这些情形、医生也不会去问——这是选择效应,换更富的语料无效。

③ 一次真实问诊不会把一支的判据全问完,于是档位停在该支上界。 这是 worst_case 在正确工作,但上界松紧完全由问诊完备性决定。

④ worst_case 的安全性以「不产生假 no」为前提。 输出是在现有证据下排除不掉的最紧急一档(某支只有全部条件为 no 才算排除), 因此欠分诊恒为 0、证据每多一个 no 就单调收紧(两条不变量由 tests/ 守着)。 信息不足时它会退化成"人人叫救护车"——这是设计取向(欠分诊 10·d² vs 过分诊 d),不是 bug。

⑤ 分级本身是 silver:分支级参照由强模型定稿 + 人工复核,终局结论仍缺一个真人护士 gold。

unknown 为什么是第一等状态

STCC 分支语义是「本支任一条件为是 ⇒ 命中;全部为否 ⇒ 转下一支」。 "没提到" ≠ "说了没有":前者必须触发追问,后者才能转分支。 把 unknown 压成 no 等于凭空伪造阴性,会让引擎走到错误的分支。

判据文本

索引里的判据是逐条独立改写版(5,214/5,214)。纯阈值与单个医学术语 (「咳嗽」「体温>100.4°F」)按事实保留。改写过三道闸: 数值/否定/长度/雷同的形式校验、oracle 回放与原版逐位一致、下游 checker 指标不掉。

冒烟:用发布物验,不是用仓库源码验

pip install --no-cache-dir stcc-mcp
cd /tmp && python <本仓>/scripts/smoke_published.py            # 命令行契约
python <本仓>/scripts/smoke_published.py --skip-cli --links README.md   # 文档里每个 URL

断言的是文档承诺过的东西:协议菜单 225 条、协议名写错→退出码 2 + 可执行提示、 输入过短→rejected 且不给档位、依赖不可达→退出码 3 + 不吐 traceback、README 里每个链接可达。 CI 见 .github/workflows/smoke.yml(repo 测源码、published 从 PyPI 装再测、 e2e 装 Ollama 拉发布模型跑三分类与端到端)。

为什么单独搞这一层:本项目发布后靠人肉抓到 7 个"传上去了但用不了"的东西 (死链、没发布的命令、返回空串、废弃的 CLI、账号名写错、默认模型名只在开发机成立、 依赖没起时抛裸 traceback)。它们都不会让上传失败,也都不会被单测抓到—— 单测跑仓库源码,用户跑发布物。

开发

uv sync
uv run pytest -q                        # 27 条回归
uv run python -m scripts.mcp_selfcheck  # oracle 回放 4,168 条判据,<1 秒

scripts/mcp_selfcheck.py 是引擎的忠实度自检:逐条判据置 yes、其余置 no, 核对引擎走到的分支与处置。这不是模型评测——对不上就是编译或求值有洞。

模型

chenhaodev/stcc-checker-0.6b-GGUF (Q8_0 / Q4_K_M)。判据级 false_no 0.0024、延迟中位 ~250ms、端到端 1.25s/条。

Apache-2.0.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An agentic AI system that enables healthcare professionals to log patient symptoms, retrieve similar clinical cases, and search medical documents using RAG. It integrates a Chroma vector database with the Model Context Protocol to provide real-time clinical decision support.
    -
  • A
    license
    A
    quality
    C
    maintenance
    First-line incident triage you can trust: ranked root-cause hypotheses where every claim cites a real evidence handle — and the agent abstains rather than guess.
    1
    1
    MIT