基于浏览器扩展的医疗智能助手参考实践
发表于: 2026/06/30
非商用声明
该文档提供的内容为参考实践,仅供用户参考使用,用户可参考文档构建自己的软件,产品化方案需进行安全、可靠性加固,不能直接将相关Demo或镜像文件集成到商用产品中。
1 方案背景
医疗ISV伙伴在HIS智能助手方案拓展和交付中,与医院现网HIS系统对接困难,影响拓展效率和交付成本。其中伙伴的关键堵点是与医院HIS系统对接“慢、贵、难”,直接影响项目拓展和交付成本。
当前面临的挑战如下:
1、对接周期长:从需求沟通、技术评估、开发联调到上线部署,周期通常较长,受制于HIS厂商配合度,易延误。
2、对接成本高:HIS厂商通常按接口数量和数据量收取对接费,较多的接口和字段导致对接成本高昂。
3、可扩展性差:API与HIS接口“紧耦合”难扩展,且HIS系统导致API接口和数据字段变化,需重新调试和定制。
本方案基于浏览器扩展实现HIS系统对接能力。零侵入、可适配,兼容Chrome、Edge等浏览器。通过适配器架构,新增HIS平台时仅需编写一个适配器文件,注册配置即可快速集成,大幅降低对接成本与交付周期。
本方案组件关系图如下:
图1 组件关系图

本方案流程图如下:
图2 方案流程图

2 使用指导
用户从gitcode/his-plugin-demo处下载HIS智能助手的安装文件后,可按照以下流程完成智能助手的安装、使用。
2.1 安装插件
步骤一:加载扩展插件
1、打开 Chrome或者Edge,地址栏输入 chrome://extensions/或者 edge://extensions/
Chrome:

Edge:

2、右上角开启 "开发者模式"
Chrome:

Edge:

3、加载插件
Chrome:点击左上角 "加载未打包的扩展程序"

Edge:点击左上角 "加载解压缩的扩展"

4、选择本目录(即 extension 文件夹)

步骤二:允许访问文件网址
如果你需要用 file:// 协议打开本地页面进行测试(例如 file:///D:/xxx/demo.html):
1、在 chrome://extensions/ 中找到本扩展卡片,点击 "详细信息"
2、向下滚动,开启 "允许访问文件网址"


步骤三:验证安装
安装后打开一个 HIS 页面(例如:his-plugin-demo\示例医院HIS系统目录下的 index.html 文件)

加入页面后,右侧会出现一个浮窗:

如果浮窗显示 "未连接",说明插件未成功注入页面。常见原因:
- 忘记开启"允许访问文件网址"(file:// 页面专用)
- 扩展未正确加载(去 chrome://extensions 检查)
2.2 使用插件
在插件使用过程中,用户可根据以下步骤对新增HIS界面的适配,以及对接真实环境下的AGENT服务。
2.2.1 适配界面
项目架构如下:
his-plugin-demo/
├── extension/ ← Chrome 扩展插件(核心)
│ ├── manifest.json ← 扩展清单(权限、注入脚本)
│ ├── README.md ← 安装与使用说明
│ └── src/
│ ├── background.js ← Service Worker(OpenClaw 网络代理)
│ ├── shared/
│ │ └── config.js ← 配置(provider、apiKey、fillBlocks)
│ ├── agents/
│ │ ├── fakeClinicalAgent.js ← 假 Agent(离线演示,无需 API)
│ │ └── realClinicalAgent.js ← 真实 Agent(DeepSeek / OpenClaw)
│ ├── adapters/
│ │ ├── baseAdapter.js ← 适配器基类(抽象 extract/fill)
│ │ ├── mdHisDemoAdapter.js ← 示例医院 HIS 适配器
│ │ ├── mdHisDemoFixture.js ← 示例医院模拟数据
│ │ └── huaxiHisAdapter.js ← 华西 HIS 适配器
│ ├── services/
│ │ └── adapterRegistry.js ← 适配器注册表(按 URL 匹配)
│ ├── content/
│ │ ├── content.js ← 主控制器(患者监测、浮窗、回填)
│ │ └── overlay.css ← 浮窗样式
│ └── popup/
│ ├── popup.html
│ ├── popup.css
│ └── popup.js
│
└── 示例医院HIS系统(用于验证插件可用性)/ ← 演示用的本地 HIS 页面
├── index.html
├── app.js
├── styles.css
└── README.md每个 HIS 平台对应一个 adapter文件,主要负责三件事:
方法 | 职责 | 示例 |
|---|---|---|
canHandle() | 判断当前页面是否是本平台 | 检查页面URL、标题、DOM特征 |
extractPatientContext() | 提取当前患者信息 | 读DOM、读全局变量、读接口 |
fillRecord() | 将Agent结果填入页面字段 | 设置textarea/div的值 |
根据README.md文档中提供的Prompt模板,用户只需要添加待适配的HIS系统URL地址,让openclaw/opencode等AI助手自动生成adapter代码文件:
我需要你在当前目录为下面提供的 HIS 系统编写一个浏览器扩展适配器。
## 扩展架构
这是一个 Chrome 浏览器扩展,用于提取 HIS 页面患者信息、调用AI生成病历、回填到页面。
每个 HIS 平台对应一个 adapter,位于 `src/adapters/` 目录下。
### 关键代码结构
- adapter 继承 `BasePlatformAdapter`,需实现 `canHandle()`、`extractPatientContext()`、`getFingerprint()`、`fillRecord()`
- 参考已有 adapter:`src/adapters`
- 注册入口:`src/services/adapterRegistry.js`
- 配置入口:`src/shared/config.js`
- 加载清单:`manifest.json`
### 分析要求
分析该 HIS 页面,确定以下信息(注意:不同 HIS 的信息位置差别很大,可能在 DOM 文本、canvas、全局 JS 变量、加密载荷、XHR 接口、iframe 等任意位置,请尽可能通过 WebFetch/Read 工具分析后给出方案):
1. **平台识别方式**:如何判断当前页面是该 HIS(URL 特征、页面标题、特定 DOM 元素等),用于 `canHandle()`
2. **患者信息提取方式**:患者 ID、姓名、性别、年龄、科室等信息从何处获取
3. **回填字段选择器**:主诉、现病史、诊断等输入框/div 的 CSS 选择器
### 待适配 HIS 页面(用户修改)
- 页面 URL:`file:///D:/xxx/demo.html`
### 根据分析结果,请生成
1. 完整的 adapter 文件内容
2. config.js 中需要添加的平台配置
3. adapterRegistry.js 需要添加的注册代码
4. manifest.json 需要添加的文件引用
## 重要经验(逐条检查可避免返工)
### 一、架构规范
1. **优先从页面实时数据提取**:通过 fetch 获取页面 JS 脚本,正则提取并解码患者数据。仅当页面数据不可获取(如加密、跨域限制、动态接口)时才考虑 fixture 兜底
2. **fixture 仅用于页面数据无法直接读取的场景**:如数据在 canvas 内无 DOM 文本、经 XOR/base64 加密且解码失败时需要兜底。此时配套 `xxxFixture.js`(IIFE 挂到 `window.HisCopilot.xxxFixture`),manifest 中 fixture 排在 adapter 前加载。若页面数据可直接解析(如 URL 参数、全局 JSON、DOM 文本),则无需 fixture 文件
3. **getPatients() 推荐双保险模式**:`try { fetch 页面JS并解码 } catch { 读取 fixture 兜底 }`,确保即使主流程失败也能降级运行。无 fixture 时 catch 中返回 `[]`
4. **五文件同步修改**:adapter + fixture(如有)+ config + registry + manifest 缺一不可
### 二、平台识别与患者匹配
4. **canHandle() 只用 DOM 特征**:content script 在 isolated world,无法访问页面的 `window.*` 变量。只能用 `document.title`、固定 class 名、`location.host` 等 DOM 可见信息
5. **hash 匹配优先,但 hash 函数必须与页面完全一致**:`data-canvas-id` 的 hash 值需用页面的 `patientHash()` 函数计算。必须从 `app.js` 逐字复制(包括 bug,如 `char.charCodeAt(0)` 始终取第一个字符),不要在 adapter 中"修正"。复制后需验证输出一致
6. **禁止文本内容匹配**:textContent 受空格、编码、渲染差异影响不稳定。只用 hash 匹配定位患者
7. **`getFingerprint()` 返回复合值**(如 `id:activeToken`),避免不同患者被误判为同一人
### 三、数据获取
8. **禁止 eval/JSON.parse 解析页面脚本**:页面 JS 含注释和非标准 JSON,应改用 fetch + 正则提取关键字符串,分步解码(base64 → XOR → URL解码)
9. **禁止同步 XHR**:MV3 content script 不支持,必须用 fetch 或异步 XHR
10. **fixture 数据要完整**:包含 vitals、timeline、orders、alerts、payment、status 等字段,否则 agent 生成的病历无法区分不同患者
11. **所有字段返回空字符串而非 null**:下游 Agent 期望字符串类型,null 会崩溃
### 四、调试
12. **匹配失败也要显示浮窗**:输出各 adapter 的 `canHandle()` 结果,便于排查
13. **验证清单**:平台识别 → 患者姓名正确 → 切换患者 fingerprint 变化 → 回填字段正确写入完整文件改动清单
文件 | 操作 | 说明 |
|---|---|---|
src/adapters/yourHisAdapter.js | 新建 | adapter 实现代码 |
src/adapters/yourHisFixture.js | 新建 | 独立的兜底数据文件(manifest 中排在 adapter 前加载) |
src/shared/config.js | 修改 | 添加 platforms.yourHis 配置 |
src/services/adapterRegistry.js | 修改 | this.adapters 数组加入新实例 |
manifest.json | 修改 | JS 加载列表加入 fixture 和 adapter 两行 |
2.2.2 对接Agent
医疗智能助手插件默认使用 src/agents/fakeClinicalAgent.js 模拟 AI AGENT生成病历。如需对接真实环境下的医疗Agent,可根据下面的对接流程作为参考。
2.2.2.1 前提
1、已启动对外提供Restful API 的 AGENT 服务
2、无需安装任何额外服务
2.2.2.2 对接流程
用户可按以下步骤完成插件对接AGENT的流程。
1、 修改文件
步骤一:打开 extension/src/shared/config.js,修改以下内容:
agent: {
mode: "api",
provider: "openclaw", // "deepseek" | "openclaw"
endpoint: "http://127.0.0.1:18789/v1/responses",
apiKey: "openclaw的token",
timeoutMs: 30000
}说明:
将mode改为“api”后,插件走真实AGENT。
将provider改为“openclaw”。
endpoint为你的openclaw服务实际的endpoint。
apiKey为你的openclaw gateway-token。
接下来,添加http相关参数(以openclaw.json为例):
vim C:\Users\${your_user_path}\.openclaw\openclaw.json
# 找到gateway部分,将下面的配置代码填入
"http": {
"endpoints": {
"responses": {
"enabled": true
}
}
}
步骤二:在 src/agents/realClinicalAgent.js中修改以下部分代码:
1)generateRecord():根据provider的值,选择进入openclaw的代码分支
if (this.provider === "openclaw") {
return await this.generateViaOpenclaw(context);
}2) generateViaOpenclaw():拼接system prompt,模拟AGENT的医生回答效果。实际场景可将该部分提示词注入AGENT.md中。
try {
const systemPrompt = [
"你是一位三甲医院主治医师,具有20年临床经验。",
"请根据以下患者信息,生成专业的病历文书。",
"必须严格按照JSON格式输出,包含以下6个字段:",
"- chiefComplaint:主诉",
"- presentIllness:现病史",
"- pastHistory:既往史",
"- exam:查体",
"- diagnosis:诊断",
"- plan:处理意见",
"不要输出JSON之外的任何文本。"
].join("\n");3) generateViaOpenclaw():拼接患者信息和系统提示词,并进行请求代理,将HTTP请求绕过CORS转发给后台openclaw服务。
const proxyRes = await new Promise((resolve, reject) => {
chrome.runtime.sendMessage({
type: "FETCH",
url: this.endpoint,
options: {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`
},
body: JSON.stringify({
model: "openclaw",
instructions: systemPrompt,
input: this.buildPrompt(context)
})
}
}, (response) => {
if (chrome.runtime.lastError) reject(new Error(chrome.runtime.lastError.message));
else if (!response || !response.ok) reject(new Error(`OpenClaw API: ${response ? response.error : "无响应"}`));
else resolve(response);
});
});4)解析返回结果blocks
const data = JSON.parse(proxyRes.body);
const rawText = data.output?.[0]?.content?.[0]?.text || "";5)把blocks组装成统一格式,再返回给前端渲染
return {
agent: "openclaw",
mode: "api",
requestId: `oc-${Date.now().toString(36)}`,
generatedAt: new Date().toISOString(),
source: { platform: context.platform || "", patientId: context.patient ? context.patient.id : "" },
blocks: {
chiefComplaint: blocks.chiefComplaint || "",
presentIllness: blocks.presentIllness || "",
pastHistory: blocks.pastHistory || "",
exam: blocks.exam || "",
diagnosis: blocks.diagnosis || "",
plan: blocks.plan || ""
},
structuredDiagnosis: [
{ name: blocks.diagnosis || "", confidence: 0.85, basis: ["患者基础信息", "生命体征", "检查医嘱"] }
],
rawContext: null
};2、刷新扩展插件
1. 打开 Chrome,地址栏输入 chrome://extensions/。

2. 点击插件右下角的刷新按钮。

2.2.2.3 效果验证
1、回到HIS界面。选择患者,点击“生成病历”后,前端会将当前界面的患者信息和医生输入的诊断意见一起发给AGENT进行总结。

2、将AGENT生成的病历总结回显到右侧浮窗上

3、医生确认生成内容后,点击“确认回填”按钮后,将按病历字段回填到界面的各输入框中。

2.2.3 对接大模型
医疗智能助手插件默认使用 src/agents/fakeClinicalAgent.js 模拟 AI AGENT生成病历。如需对接真实环境下的医疗Agent,可根据下面的对接流程作为参考。
2.2.3.1 前提
1、需准备好DeepSeek的API Key
2、无需安装任何额外服务
2.2.3.2 对接流程
用户可按以下步骤完成插件对接大模型的流程。
1、 修改文件
步骤一:打开 extension/src/shared/config.js,修改以下内容:
agent: {
mode: "api",
provider: "deepseek", // "deepseek" | "openclaw"
endpoint: "https://api.deepseek.com/v1/chat/completions",
apiKey: "你的API Key",
timeoutMs: 30000
}步骤二:在 src/agents/realClinicalAgent.js中修改以下部分代码:
1)buildPrompt():将患者姓名、性别、年龄、生命体征拼接成自然语言,用户可按需修改提示词。
buildPrompt(context) {
const p = context.patient || {};
let text = `患者:${p.name},${p.gender},${p.age}岁,${p.department || ""}。`;
if (p.room) text += `${p.room}。`;
if (p.allergy && p.allergy !== "无") text += `过敏史:${p.allergy}。`;
const visit = context.visit || {};
if (visit.alerts && visit.alerts.length) {
text += `风险提示:${visit.alerts.map(a => a.text).join(";")}。`;
}
if (context.vitals && context.vitals.length) {
text += `生命体征:${context.vitals.map(v => `${v.label}${v.value}`).join(",")}。`;
}
if (context.orders && context.orders.length) {
text += `已开检查:${context.orders.map(o => o.name).join("、")}。`;
}
if (context.userNotes) {
text += `医生备注:${context.userNotes}。`;
}
return text + "请生成病历JSON。";
}
}2) fetch():按POST格式将请求发送到DeepSeek。代码中通过添加system prompt的方法模拟AGENT的医生回答效果。
fetch(this.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`
},
body: JSON.stringify({
model: "deepseek-chat",
messages: [
{
role: "system",
content: [
"你是一位三甲医院主治医师,具有20年临床经验。",
"请根据以下患者信息,生成专业的病历文书。",
"必须严格按照JSON格式输出,包含以下6个字段:",
"- chiefComplaint:主诉",
"- presentIllness:现病史",
"- pastHistory:既往史",
"- exam:查体",
"- diagnosis:诊断",
"- plan:处理意见",
"不要输出JSON之外的任何文本。"
].join(" ")
},
{ role: "user", content: this.buildPrompt(context) }
],
response_format: { type: "json_object" },
temperature: 0.3
}),
signal: controller.signal
});3)解析返回结果blocks
const data = await response.json();
const blocks = JSON.parse(data.choices[0].message.content);4)把blocks组装成统一格式,再返回给前端渲染
return {
agent: "deepseek",
mode: "api",
requestId: `ds-${Date.now().toString(36)}`,
generatedAt: new Date().toISOString(),
source: {
platform: context.platform || "",
patientId: context.patient ? context.patient.id : ""
},
blocks: {
chiefComplaint: blocks.chiefComplaint || "",
presentIllness: blocks.presentIllness || "",
pastHistory: blocks.pastHistory || "",
exam: blocks.exam || "",
diagnosis: blocks.diagnosis || "",
plan: blocks.plan || ""
},
structuredDiagnosis: [
{ name: blocks.diagnosis || "", confidence: 0.85, basis: ["患者基础信息", "生命体征", "检查医嘱"] }
],
rawContext: null
};
} finally {
clearTimeout(timeout);
}
}2、刷新扩展插件
1. 打开 Chrome,地址栏输入 chrome://extensions/。

2. 点击插件右下角的刷新按钮。

2.2.3.3 效果验证
1、回到HIS界面。选择患者,点击“生成病历”后,前端会将当前界面的患者信息和医生输入的诊断意见一起发给AGENT进行总结。

2、将AGENT生成的病历总结回显到界面上

3、医生确认生成内容后,点击“确认回填”按钮后,将按病历字段回填到界面的各输入框中。




