开发者
下载
基于浏览器扩展的医疗智能助手参考实践

基于浏览器扩展的医疗智能助手参考实践

计算商业SMECE

发表于: 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、医生确认生成内容后,点击“确认回填”按钮后,将按病历字段回填到界面的各输入框中。

本页内容