news 2026/2/9 0:34:39

Qwen3-ASR在医疗领域的应用:语音电子病历系统开发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qwen3-ASR在医疗领域的应用:语音电子病历系统开发

Qwen3-ASR在医疗领域的应用:语音电子病历系统开发

医生查房时,一边观察病人情况,一边口述记录,旁边还得有个人手忙脚乱地打字——这个场景在很多医院里每天都在上演。查完房回到办公室,医生还得花大量时间整理、核对、补充病历,一天下来,真正留给思考和诊疗的时间反而被压缩了。

有没有一种方法,能让医生“说说话”就把病历写好了?今天我们就来聊聊,如何用最新的语音识别技术Qwen3-ASR,搭建一套能听懂医生说话的智能电子病历系统。

1. 医疗场景下的语音识别:为什么需要Qwen3-ASR?

在医疗这个特殊领域,对语音识别的要求比普通场景高得多。你想想看,医生说话有什么特点?

首先,专业术语多。“急性阑尾炎”、“冠状动脉粥样硬化性心脏病”、“糖化血红蛋白”……这些词对普通人来说可能很陌生,但对语音识别模型来说,必须能准确识别出来,一个字母都不能错。

其次,说话方式特殊。医生在描述病情时,往往语速快、逻辑跳跃,还可能夹杂着英文缩写和数字。比如“患者T 38.5℃,P 100次/分,R 20次/分,BP 120/80mmHg”,这种表达方式对识别模型是很大的考验。

再者,环境复杂。病房里可能有各种仪器声音、其他病人的声音、走廊里的脚步声,这些都会干扰识别效果。

最后,方言和口音。中国这么大,各地医生说话口音不同,患者也可能说方言。一套好的医疗语音识别系统,必须能听懂各种口音。

Qwen3-ASR恰好在这些方面表现突出。它支持52种语言和方言,对专业术语识别准确,在嘈杂环境下也能稳定工作。更重要的是,它开源了,这意味着医院可以自己部署,不用担心数据隐私问题。

2. 系统架构设计:从语音到结构化病历

一套完整的语音电子病历系统,不只是把语音转成文字那么简单。我们需要的是一个完整的流程:录音→识别→结构化→存储→展示。

2.1 整体架构

我设计了一个相对简单的三层架构:

医生口述 → 前端录音 → 语音识别服务 → 自然语言处理 → 结构化存储 → 电子病历系统

前端负责采集医生的语音,可以是手机App、电脑客户端,甚至是专门的录音设备。

语音识别服务是核心,这里我们用Qwen3-ASR。它负责把语音转换成文字。

自然语言处理层负责把识别出来的文字,按照病历的格式进行结构化。比如,识别出“患者主诉头痛三天”,系统要知道“头痛”是症状,“三天”是持续时间。

存储层把结构化的数据存到数据库里,方便后续查询和分析。

展示层就是医生看到的电子病历界面,可以查看、修改、补充。

2.2 为什么选择Qwen3-ASR?

你可能想问,市面上语音识别方案不少,为什么偏偏选Qwen3-ASR?

第一是准确率高。根据官方数据,Qwen3-ASR在医疗相关文本的识别准确率很高,特别是对专业术语的识别。这对医疗场景至关重要——把“糖尿病”识别成“唐尿病”,后果可能很严重。

第二是支持上下文。Qwen3-ASR有个很实用的功能:可以给它提供上下文信息。比如,你可以告诉它“现在在写病历的现病史部分”,或者“接下来要记录的是体格检查结果”。有了这些上下文,识别的准确率会更高。

第三是支持时间戳。通过配套的Qwen3-ForcedAligner模型,我们可以知道每个词在音频中的具体位置。这在医生需要回听核对时特别有用——点击文字,就能定位到对应的语音片段。

第四是开源可定制。医院的数据非常敏感,很多医院不愿意把数据传到云端。Qwen3-ASR开源了,医院可以在自己的服务器上部署,数据不出院,安全有保障。

3. 核心实现:用代码搭建语音识别服务

理论说再多,不如看看代码怎么写。下面我带你一步步搭建一个简单的语音识别服务。

3.1 环境准备

首先,你需要准备一个Python环境。我建议用Python 3.8或以上版本。

# 安装必要的库 pip install dashscope pip install flask pip install pydub # 用于音频处理

你还需要一个阿里云的API Key。如果你在医院内网部署,可能需要申请企业版的Key,或者使用开源版本自己部署。

3.2 基础语音识别

我们先从最简单的开始:上传一个音频文件,把它转成文字。

import os import dashscope from flask import Flask, request, jsonify app = Flask(__name__) # 设置API Key,实际使用时建议放到环境变量里 dashscope.api_key = os.getenv('DASHSCOPE_API_KEY', '你的API Key') @app.route('/transcribe', methods=['POST']) def transcribe_audio(): """ 接收音频文件,转写成文字 """ if 'audio' not in request.files: return jsonify({'error': '没有上传音频文件'}), 400 audio_file = request.files['audio'] # 临时保存文件 temp_path = f'temp_{audio_file.filename}' audio_file.save(temp_path) try: # 调用Qwen3-ASR进行识别 response = dashscope.MultiModalConversation.call( model='qwen3-asr-flash', messages=[ { 'role': 'system', 'content': [{'text': '这是一份医疗病历录音,请准确识别医学术语。'}] }, { 'role': 'user', 'content': [{'audio': f'file://{os.path.abspath(temp_path)}'}] } ], result_format='message', asr_options={ 'language': 'zh', # 指定中文 'enable_itn': True # 开启逆文本标准化,把“一百二十”转成“120” } ) # 提取识别结果 if response.status_code == 200: text = response.output.choices[0].message.content[0]['text'] return jsonify({'text': text}) else: return jsonify({'error': '识别失败', 'details': response}), 500 except Exception as e: return jsonify({'error': str(e)}), 500 finally: # 清理临时文件 if os.path.exists(temp_path): os.remove(temp_path) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)

这段代码创建了一个简单的Web服务,接收音频文件,调用Qwen3-ASR进行识别,返回文字结果。

3.3 添加上下文信息

在医疗场景下,上下文特别重要。医生可能在记录不同的病历部分:主诉、现病史、体格检查、诊断意见等。我们可以通过系统消息给模型提供上下文。

def transcribe_with_context(audio_path, context): """ 根据不同的病历部分提供不同的上下文 """ context_prompts = { 'chief_complaint': '这是患者的主诉部分,请准确记录患者的症状和持续时间。', 'present_illness': '这是现病史部分,请按时间顺序记录疾病的发展过程。', 'physical_exam': '这是体格检查部分,请准确记录各项检查结果和数值。', 'diagnosis': '这是诊断部分,请准确记录疾病名称和ICD编码。', 'treatment': '这是治疗方案部分,请准确记录药物名称、剂量和用法。' } system_prompt = context_prompts.get(context, '这是一份医疗病历录音,请准确识别医学术语。') response = dashscope.MultiModalConversation.call( model='qwen3-asr-flash', messages=[ {'role': 'system', 'content': [{'text': system_prompt}]}, {'role': 'user', 'content': [{'audio': f'file://{audio_path}'}]} ], result_format='message', asr_options={'language': 'zh', 'enable_itn': True} ) return response.output.choices[0].message.content[0]['text']

3.4 实时语音识别

查房时,医生可能需要边说话边看到识别结果。这时候就需要实时语音识别。

import threading import websocket import json import base64 import time class RealtimeASR: def __init__(self, api_key, on_text_callback): self.api_key = api_key self.on_text_callback = on_text_callback # 收到识别结果时的回调函数 self.ws = None self.is_running = False def connect(self): """连接WebSocket服务""" url = 'wss://dashscope.aliyuncs.com/api-ws/v1/realtime' url += f'?model=qwen3-asr-flash-realtime' self.ws = websocket.WebSocketApp( url, header=['Authorization: Bearer ' + self.api_key, 'OpenAI-Beta: realtime=v1'], on_open=self.on_open, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close ) # 在新线程中运行WebSocket self.is_running = True ws_thread = threading.Thread(target=self.ws.run_forever) ws_thread.daemon = True ws_thread.start() def on_open(self, ws): """连接建立后的初始化""" print("连接建立") # 发送会话配置 session_config = { 'event_id': 'session_init', 'type': 'session.update', 'session': { 'modalities': ['text'], 'input_audio_format': 'pcm', 'sample_rate': 16000, 'input_audio_transcription': { 'language': 'zh' }, 'turn_detection': { 'type': 'server_vad', # 使用服务端的语音活动检测 'threshold': 0.0, 'silence_duration_ms': 800 # 800毫秒静默认为一句话结束 } } } ws.send(json.dumps(session_config)) def on_message(self, ws, message): """收到服务器消息""" data = json.loads(message) if data.get('type') == 'transcript.delta': # 收到部分识别结果 text = data.get('text', '') if text and self.on_text_callback: self.on_text_callback(text, is_final=False) elif data.get('type') == 'transcript.completed': # 一句话识别完成 text = data.get('text', '') if text and self.on_text_callback: self.on_text_callback(text, is_final=True) def send_audio_chunk(self, audio_data): """发送音频数据块""" if self.ws and self.is_running: event = { 'event_id': f'audio_{int(time.time() * 1000)}', 'type': 'input_audio_buffer.append', 'audio': base64.b64encode(audio_data).decode('utf-8') } self.ws.send(json.dumps(event)) def stop(self): """停止识别""" self.is_running = False if self.ws: self.ws.close() def on_error(self, ws, error): print(f"WebSocket错误: {error}") def on_close(self, ws, close_status_code, close_msg): print(f"连接关闭: {close_status_code} - {close_msg}") self.is_running = False # 使用示例 def handle_recognition(text, is_final): if is_final: print(f"[最终结果] {text}") # 这里可以把识别结果插入到病历编辑器中 else: print(f"[实时结果] {text}", end='\r') # 创建实时识别实例 asr = RealtimeASR(api_key='你的API Key', on_text_callback=handle_recognition) asr.connect() # 模拟发送音频数据(实际使用时从麦克风获取) # while True: # audio_chunk = get_audio_from_microphone() # 需要实现这个函数 # asr.send_audio_chunk(audio_chunk) # time.sleep(0.1)

这段代码实现了实时语音识别。医生说话时,系统会实时显示识别结果,当医生停顿超过800毫秒,系统会认为一句话结束,给出最终识别结果。

4. 从文字到结构化病历:自然语言处理的应用

语音识别只是第一步。识别出来的文字还需要转换成结构化的病历数据。这部分需要一些自然语言处理技术。

4.1 基本信息提取

病历有一些固定的结构。我们可以用规则+机器学习的方法来提取信息。

import re from typing import Dict, List, Optional class MedicalTextParser: """医疗文本解析器""" def parse_chief_complaint(self, text: str) -> Dict: """ 解析主诉 格式通常为:症状 + 持续时间 例如:"头痛三天" -> {"symptom": "头痛", "duration": "三天"} """ result = {'symptom': '', 'duration': ''} # 匹配持续时间模式 duration_patterns = [ r'(\d+)[天日月年]', # 三天、两个月、一年 r'([一二三四五六七八九十百千万]+)[天日月年]', # 三天、两个月 r'约?(\d+)[-~](\d+)[天日月年]', # 3-5天 ] for pattern in duration_patterns: match = re.search(pattern, text) if match: result['duration'] = match.group(0) # 从原文中移除持续时间,剩下的就是症状 result['symptom'] = text.replace(match.group(0), '').strip() break if not result['duration']: result['symptom'] = text return result def parse_physical_exam(self, text: str) -> Dict: """ 解析体格检查 提取生命体征:体温(T)、脉搏(P)、呼吸(R)、血压(BP) """ result = { 'T': None, # 体温 'P': None, # 脉搏 'R': None, # 呼吸 'BP': None, # 血压 'other': [] # 其他检查结果 } # 匹配体温 t_match = re.search(r'T\s*[::]?\s*(\d+\.?\d*)°?[Cc]?', text) if t_match: result['T'] = float(t_match.group(1)) # 匹配脉搏 p_match = re.search(r'P\s*[::]?\s*(\d+)\s*次/分', text) if p_match: result['P'] = int(p_match.group(1)) # 匹配呼吸 r_match = re.search(r'R\s*[::]?\s*(\d+)\s*次/分', text) if r_match: result['R'] = int(r_match.group(1)) # 匹配血压 bp_match = re.search(r'BP\s*[::]?\s*(\d+)\s*/\s*(\d+)\s*mmHg', text) if bp_match: result['BP'] = f"{bp_match.group(1)}/{bp_match.group(2)}" return result def extract_medications(self, text: str) -> List[Dict]: """ 提取药物信息 格式:药物名称 + 剂量 + 用法 例如:"阿司匹林100mg口服每日一次" """ medications = [] # 简单的药物模式匹配(实际应用需要更复杂的规则或模型) patterns = [ # 药物 + 剂量 + 用法 r'([\u4e00-\u9fa5]+)\s*(\d+\.?\d*)(mg|g|ml|片|粒|支)\s*([\u4e00-\u9fa5]+)', ] for pattern in patterns: matches = re.finditer(pattern, text) for match in matches: med = { 'name': match.group(1), 'dose': match.group(2), 'unit': match.group(3), 'usage': match.group(4) } medications.append(med) return medications # 使用示例 parser = MedicalTextParser() # 解析主诉 chief_complaint = "头痛伴恶心呕吐三天" parsed = parser.parse_chief_complaint(chief_complaint) print(f"症状: {parsed['symptom']}, 持续时间: {parsed['duration']}") # 解析体格检查 exam_text = "T 36.8℃,P 80次/分,R 18次/分,BP 120/80mmHg,神志清楚" exam_data = parser.parse_physical_exam(exam_text) print(f"生命体征: {exam_data}")

4.2 与电子病历系统集成

识别和解析完成后,需要把数据写入电子病历系统。这里给出一个简单的集成示例。

class EMRIntegrator: """电子病历系统集成器""" def __init__(self, emr_api_url): self.emr_api_url = emr_api_url def create_medical_record(self, patient_id, record_data): """ 创建病历记录 """ record = { 'patient_id': patient_id, 'visit_id': self._generate_visit_id(), 'chief_complaint': record_data.get('chief_complaint', ''), 'present_illness': record_data.get('present_illness', ''), 'physical_exam': record_data.get('physical_exam', {}), 'diagnosis': record_data.get('diagnosis', []), 'treatment': record_data.get('treatment', {}), 'created_by': '语音录入系统', 'created_at': datetime.now().isoformat() } # 调用电子病历系统的API # response = requests.post(f'{self.emr_api_url}/records', json=record) # return response.json() # 这里简化处理,直接返回 return {'success': True, 'record_id': 'REC001'} def update_record_section(self, record_id, section_name, content): """ 更新病历的某个部分 用于实时识别时的增量更新 """ update_data = { 'section': section_name, 'content': content, 'updated_at': datetime.now().isoformat() } # 调用电子病历系统的更新API # response = requests.patch(f'{self.emr_api_url}/records/{record_id}', json=update_data) # return response.json() return {'success': True} def _generate_visit_id(self): """生成就诊ID""" return f"VISIT{datetime.now().strftime('%Y%m%d%H%M%S')}"

5. 实际应用中的优化建议

在实际医院环境中部署这套系统,还需要考虑一些实际问题。

5.1 准确率提升技巧

定制化训练:虽然Qwen3-ASR已经对医疗术语有很好的支持,但每个医院、每个科室可能有一些特定的说法。如果条件允许,可以用医院的真实病历录音对模型进行微调。

构建科室词库:为不同科室构建专门的词库。比如心内科的词库包括各种心脏病名称、检查项目、药物名称;骨科的有各种骨折类型、手术名称等。

后处理纠错:识别结果出来后,可以用规则进行后处理。比如,“心机梗死”应该纠正为“心肌梗死”,“糖料病”纠正为“糖尿病”。

5.2 用户体验优化

实时反馈:医生说话时,系统应该实时显示识别结果。如果识别错了,医生可以立即纠正。

快捷命令:支持语音命令,比如“换行”、“插入表格”、“保存并提交”等。

多模态输入:除了语音,医生可能还需要输入一些结构化数据,比如选择框、下拉菜单。系统应该支持语音和手动输入的无缝切换。

离线支持:医院有些区域网络可能不好,系统应该支持离线录音,网络恢复后再同步识别。

5.3 隐私与安全

数据加密:所有音频数据在传输和存储时都要加密。

访问控制:只有授权的医生才能访问自己病人的病历录音。

审计日志:记录谁在什么时候访问了哪些病历,便于追溯。

本地化部署:对于大型医院,建议在院内服务器部署Qwen3-ASR,确保数据不出院。

6. 效果评估与持续改进

系统上线后,需要持续监控和优化。

准确率监控:定期抽样检查识别准确率,特别是对关键医疗术语的识别准确率。

医生反馈收集:设置简单的反馈机制,医生发现识别错误时,可以一键反馈。

使用数据分析:分析哪些科室使用最多,哪些时间段使用最频繁,根据数据优化系统性能。

模型更新:随着Qwen3-ASR新版本的发布,及时评估和升级。

7. 总结

用Qwen3-ASR搭建语音电子病历系统,技术上已经比较成熟。从我们的实践来看,这套方案能显著提高医生的工作效率。原来需要半小时手写的病历,现在可能十分钟口述就完成了,而且格式更规范。

不过也要看到,技术只是工具。真正让系统用起来、用得好,还需要医院的配合、医生的适应、流程的优化。建议先从一个小科室开始试点,收集反馈,不断改进,再逐步推广。

医疗信息化是个长期的过程,语音录入只是其中一环。但随着像Qwen3-ASR这样的技术越来越成熟,我相信未来会有更多AI技术应用到医疗场景中,真正让技术为医生减负,为患者造福。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/9 0:34:17

Llava-v1.6-7b在微信小程序开发中的应用:图文交互功能实现

Llava-v1.6-7b在微信小程序开发中的应用:图文交互功能实现 1. 引言:当小程序“看懂”图片 想象一下,你正在开发一个电商小程序,用户上传一张商品照片,系统不仅能自动识别出这是什么商品,还能根据照片里的…

作者头像 李华
网站建设 2026/2/9 0:34:17

颠覆式学术效率工具:Elsevier稿件追踪插件如何重塑科研工作流

颠覆式学术效率工具:Elsevier稿件追踪插件如何重塑科研工作流 【免费下载链接】Elsevier-Tracker 项目地址: https://gitcode.com/gh_mirrors/el/Elsevier-Tracker 在竞争激烈的学术出版领域,研究者平均需花费28%的工作时间监控投稿状态&#xf…

作者头像 李华
网站建设 2026/2/9 0:34:02

Chandra AI与Elasticsearch集成:智能搜索系统开发

Chandra AI与Elasticsearch集成:智能搜索系统开发 你有没有过这样的经历?在一个庞大的文档库里,想找一份关于“2025年第三季度市场分析”的报告,你输入关键词“市场分析”,结果系统给你返回了上百份文档,从…

作者头像 李华
网站建设 2026/2/9 0:33:57

漫画下载工具跨平台使用完全指南:从问题解决到高级应用

漫画下载工具跨平台使用完全指南:从问题解决到高级应用 【免费下载链接】comics-downloader tool to download comics and manga in pdf/epub/cbr/cbz from a website 项目地址: https://gitcode.com/gh_mirrors/co/comics-downloader 漫画下载工具Comics Do…

作者头像 李华
网站建设 2026/2/9 0:33:52

小白必看:阿里小云语音唤醒模型快速上手与常见问题解决

小白必看:阿里小云语音唤醒模型快速上手与常见问题解决 你是不是也遇到过这样的场景:想给智能设备加个“小云小云”唤醒功能,但一看到环境配置、模型加载、音频预处理就头大?下载依赖报错、采样率不匹配、推理结果全是rejected……

作者头像 李华