做这个系统的时候,说实话最大的阻力不是模型精度不够,而是“中医能不能用AI诊断”这个灵魂拷问。我先亮个结论:能,但只能做辅助,不能替代真人。我自己用YOLO加deepseek搭了一套舌象诊疗专家系统,输入一张舌头照片,先由YOLO完成舌体和舌苔区域的检测分割,再把量化特征送到deepseek,结合中医八纲辨证和脏腑辨证逻辑,生成诊断建议、体质分析和调理方向。整套流程跑通之后,实测下来对有明确舌象特征的案例确实能给出有参考价值的结论,但对光照、美颜、角度这些干扰因素也容易翻车。这篇就把这套系统的完整技术方案、训练数据和踩坑记录都梳理一遍,给想做医疗AI或中医数字化的人一个可复现的参考。
1. 为什么是舌象:中医诊断里最容易落地的切入点
1.1 舌诊的临床价值与复杂度
中医讲究望闻问切,四诊合参,但真正能“眼见为实”的,望舌是最直观的一项。舌头是人体唯一直接暴露在外的内脏组织,舌体、舌苔的颜色、质地、润燥,跟气血盛衰、脏腑寒热有非常强的相关性。脾虚湿盛的人舌体胖大、边有齿痕、苔白厚腻;阴虚火旺的人舌红少苔、甚至光红无苔;血瘀证常见舌质紫暗、有瘀点。这些特征并不是玄学,现代医学研究也证实舌尖、舌中、舌根的微生物环境和微循环状态确实存在差异。正因如此,舌诊成了中医数字化里相对好切入的点。脉诊需要传感器贴手腕,问诊需要自然语言交互,而舌诊只需要一张照片。
难点在于“客观化”。同一个病人的舌头,上午和下午看可能不一样,刚喝完咖啡和空腹看不一样,手机拍出来的偏色和医生肉眼看到的也可能不一样。传统中医靠经验积累,一个老中医看一万个舌头能形成肌肉记忆,但AI没有这种积累,它需要的是标注清晰、场景标准化的数据。所以这个项目的第一个核心问题不是算法,而是数据规范。
1.2 传统舌诊的客观化痛点
这几年市面上已经有不少舌象仪,但大多是固定设备、固定光源、把下巴搁上去那种台架式拍摄。效果稳定,但使用场景受限,只能放在诊室里,没法让用户在家自己拍。我的目标是做一套“手机随手拍就能分析”的系统,这就放大了客观化的难度。手机型号不同、摄像头白平衡不同、室内外光源不同,甚至用户在镜头前张嘴的角度不同,都会直接影响诊断结果。还有一个很多人忽略的问题:手机相机的AI美颜。现在主流手机默认开启的美颜功能会平滑皮肤纹理、提亮肤色,舌头边缘的纹理会被抹掉,舌苔的颗粒感也会被“优化”掉。这个问题我一开始完全没意识到,直到收集数据时发现同一部手机开美颜和关美颜拍出来的舌头,AI的置信度能差出20个百分点。
所以我把数据采集规范里最狠的一条定成了:所有用于训练和诊断的照片必须关闭美颜、开启原相机、使用后置主摄、在自然散射光下拍摄。这一条执行到位,后面能省掉至少一半的麻烦。
2. 技术选型:YOLO负责“看”,deepseek负责“想”
2.1 为什么用YOLO做舌象检测与分割
舌象诊断的第一步,是把舌头从照片里“抠”出来。虽然现在有很多语义分割模型,比如U-Net、DeepLabV3,但我在实际项目里最终选了YOLO家族。原因有三点:第一,YOLO的检测框加实例分割能力可以同时完成“找舌头”和“大致轮廓勾勒”两个任务,训练和部署都更省事。第二,YOLOv8/v11的生态非常成熟,从API调用到TensorRT加速都有现成方案,我不用从零写推理逻辑。第三,检测这件事本身比像素级分割更适合实际场景——我不需要精确到每根舌乳头,我只需要知道舌体的大致区域、舌苔覆盖的边界,以及舌中、舌根的位置即可。后面做特征提取时,再基于检测框做局部ROI采样,比全图分析抗干扰能力强很多。
这里补充一个项目初期的教训。我最早用的是YOLOv8n-seg,原因是模型小、推理快。跑起来确实快,但分割的边界很粗糙,尤其是舌苔厚腻的时候,分割mask会把舌苔区域的纹路吞掉,导致后续特征提取失真。后来换了YOLOv8m-seg,体积大了两倍,但边界精细度提升非常明显。如果你的部署设备性能不是特别受限,我建议直接用m或者l级别,别心疼那点推理时间。
2.2 为什么用deepseek做诊断建议
检测模型负责输出客观特征,但这些特征怎么转成中医诊断结论,传统做法是写一堆if-else规则。比如“舌质红 + 苔黄 + 干燥 -> 属实热证”,这种规则表维护起来太痛苦,而且中医本身讲究兼证、夹杂、体质差异,规则写死了就失去了辨证的灵活性。大模型的出现把这条路走通了。deepseek的强项在于对中医经典理论的理解和对复杂语义的归纳,我只要把提取到的舌象特征按结构化文本喂给它,它就能结合八纲辨证、脏腑辨证给出相对专业的分析。
为什么选deepseek而不是其他大模型?我实际对比过几个,deepseek在中文语境下的中医知识密度是最高的,而且在给出诊断建议时,它不会像某些模型一样张嘴就是“建议去医院看一下”这种万能回复,而是真的会从舌色、苔色、苔质、湿润度几个维度拆解,再对应到气虚、血瘀、湿热这些证型。这是做诊断建议最需要的能力:说理,不是给结论。
2.3 整体技术栈与备选方案
整套系统的处理链路如下:手机端上传图片 -> Python后端接收 -> YOLO做舌体检测与分割 -> OpenCV做HSV颜色空间分析 -> 提取舌色、苔色、苔质、润燥等量化特征 -> 构造结构化诊断提示词 -> 调用deepseek生成诊断建议 -> 返回给前端展示。
| 模块 | 技术选型 | 备选方案 | 我的选择理由 |
|---|---|---|---|
| 目标检测 | YOLOv8m-seg | YOLOv11、Faster R-CNN | 分割和检测一并解决,部署生态好 |
| 特征提取 | OpenCV + NumPy | 自定义CNN分类器 | 可解释性强,调试方便 |
| 诊断推演 | deepseek API | 本地微调医疗大模型 | 成本低,中医辨证知识现成 |
| 前端展示 | Vue3 + ECharts | React | 团队更熟,雷达图表现力好 |
| 后端服务 | FastAPI + Redis | Flask | 异步支持好,限流方便 |
这套组合的优点是每个模块都能独立替换,后期如果想换更强的医疗专用模型,不需要动整条链路。
3. 数据准备:舌象数据集的建设是全项目最重的活
3.1 数据采集:拍摄规范与设备选择
数据是这种AI项目的亲爹。一开始我尝试过从网上抓舌图,但网图的水印、分辨率、修图痕迹太乱,标注一致性没法保证。后来我改变策略,组建了一个小型采集小组,统一用三台主流安卓手机和一台iPhone,固定拍摄参数:后置主摄、关闭美颜、关闭HDR、色温设置到5500K对应当天自然光。拍摄时让志愿者自然伸出舌头,舌头放松不要用力,嘴巴张开到能看到舌根与咽峡边缘。每人在上午、下午各拍三张,覆盖空腹、饭后半小时、喝水后十分钟三种状态。
这样做不是为了采集多少数量,而是为了建立“状态变化”的意识。同一个人的舌头在不同时段、不同水分状态下的差异非常大,如果模型只在单一状态下训练,部署后就很难适应真实用户随手的照片。我最终采集了大约3000张有效图片,覆盖120个志愿者,年龄从20岁到60岁,尽量平衡男女和不同体质。
3.2 数据标注:舌体、舌色、苔色、苔质四个维度
标注是整个项目最需要耐心的环节。我用LabelMe做多边形标注,每一张图需要标注三类目标:舌体(tongue)、舌苔区域(coating)、唇部区域(lip)。舌苔区域不是简单画个框,而是沿着舌苔覆盖的边界描点,因为有部分舌苔可能只覆盖舌中半个区域,边界很模糊。这个工作做下来,一个熟练标注员一小时只能处理20张图。
舌体框确定之后,再给每一个标注区域打特征标签,包括:
- 舌色:淡白、淡红、红、绛红、青紫
- 苔色:白、黄白、黄、灰黑
- 苔质:薄、厚、腻、燥、润、剥脱
- 舌形:胖大、齿痕、瘦薄、裂纹、点刺
这里我遇到一个巨大的坑:对于“淡红舌,薄白苔”这种正常舌象,标注者之间的一致性非常高;但遇到“黄腻苔”和“黄燥苔”这种边界重叠的情况,标注者之间经常吵起来。最后我引入了一个“双人标注+仲裁”机制:每张图至少两个标注员独立标注,如果标签不一致,由具备中医背景的资深人员仲裁。这个成本很高,但最终产出的数据集质量对我的模型效果有决定性的帮助。
3.3 数据增强与样本均衡的坑
医疗AI数据天然类别不平衡。我的3000张图里,正常淡红舌占了将近40%,而灰黑苔只有不到30张,光看这个比例就知道模型一定会把灰黑苔学成“稀有物种”。我做了几个处理:
第一,对稀有类别做过采样复制,同时加上随机旋转、平移、亮度扰动等在线增强,让模型每次迭代看到的样本不会完全一样。第二,对多数的正常舌象做降采样,因为正常舌象本身形态接近,留着太多反而让模型偷懒。第三,专门增加了一个“色彩扰动增强”操作,随机把图片的色相偏移10度、饱和度拉伸10%——这一步非常重要,因为手机拍摄的颜色偏差往往是整体偏黄或偏蓝,这个增强模拟了不同白平衡下的效果,让模型对颜色变化更鲁棒。
这期间踩过一个具体的坑:在增强时我一开始把亮度扰动范围设成±30%,结果模型在训练集上很牛,一到真实图片就废,暗光环境下直接检测不到舌头。后来我把亮度扰动缩到±15%,并且对暗部做Gamma校正后再喂给模型,情况才好转。记住一个原则:数据增强是让模型适应真实环境,不是让它看“抽象派艺术”。
4. 模型训练:从YOLOv8到可用的检测模型
4.1 检测模型的标签体系设计
YOLO的训练本质是回归检测框和分割mask,但我的标签体系不只是“舌头”一个类别。我为YOLO设置了四个类:tongue(舌体)、coating(苔区)、lip(嘴唇)、face_part(下巴/牙齿边缘)。后面两个类表面上看没什么用,但实际上是为了“负样本抑制”。真实照片里总有嘴唇、牙齿露出来,如果模型分不清舌头和嘴唇,很容易把嘴唇边缘当成舌体边界,导致后续颜色分析被嘴唇干扰。把唇部标注出来,模型学到的是“舌头和嘴唇是不同物体”,推理时我可以忽略lip类,只保留tongue和coating的mask。
训练时我没有直接用Darknet原版YOLO的pyx文件,而是用了Ultralytics YOLO的Python接口,数据集格式从LabelMe JSON转成了YOLOv8的seg格式。这里要注意,coating类与tongue类存在包含关系,在YOLO的loss计算中同一像素不能同时属于两个mask,所以我在生成mask时做了层次处理:先画tongue的mask,再把coating的mask限制在tongue内部,超出部分的coating像素置为ignore。否则模型训练会崩溃。
4.2 训练参数与迭代记录
我的训练环境是一张消费级显卡,显存12GB。YOLOv8m-seg的输入尺寸设成640x640,batch size设成8,初始学习率0.01,训练100个epoch,使用SGD优化器和余弦退火调度。前20个epoch只冻结backbone训练head,后面80个epoch全部放开。整个过程大约跑了6个小时。训练到第60个epoch时mAP50到了0.92,mAP50-95到了0.76,看起来不错,但放到真实场景里还是偶尔会出问题。
具体问题集中在两种场景:一是舌头伸出不足、舌尖微翘时,模型会把舌尖和嘴唇当成一个整体;二是舌头表面出现很厚的裂纹时,YOLO的mask会出现“蜂窝状空洞”。第一个问题通过增加“舌尖上翘”样本解决;第二个问题我在后处理阶段对mask做了形态学闭运算,把细小的洞填掉,再取最大连通域作为舌体区域。
训练完还需要做量化校准,我对模型做了INT8量化,推理时间从80ms降到35ms,在普通手机CPU上也能跑到可用的帧率。但量化后精度掉了约1.5个百分点,尤其对暗苔的识别影响更大。后来我采用了一个折中方案:服务器端跑全精度FP16模型,手机端只跑轻量检测,把特征提取和推演都放到服务端完成。
4.3 模型评估:mAP之外还要看的指标
评估舌象检测模型,光看mAP远远不够。我额外统计了三个业务相关指标:
- 舌体交并比(IoU):预测mask与真实mask的重叠程度,低于0.75视为失败。
- 颜色偏移度:将检测到的舌体中心区域与真实标注区域的平均HSV差值,用于评估颜色分析是否被mask边界影响。
- 案例级准确率:在一整张舌象的辨证结果维度上,与中医专家结论的一致率,这个才是用户真正关心的。
我的模型在固定光源下的舌体IoU达到0.88,颜色偏移度很小;但在复杂背景下IoU掉到0.8左右。这说明检测模型已经基本可用,真正的瓶颈是颜色特征提取时的环境光干扰。
5. 系统架构:从单机Demo到可部署的专家系统
5.1 推理流程:图像输入到诊断建议
整个推理服务我用FastAPI写的,上传图片后,处理流程是:
- 请求进来先检查图片尺寸,超过1920px的长边直接等比压缩到1080px,减少推理压力。
- 图片进入YOLO检测,先跑全图得到舌头检测框,如果置信度低于0.5,直接返回“未检测到清晰的舌象,请重新拍摄”。
- 对检测框区域做分割mask,然后把mask之外的背景全部置黑色,避免环境干扰颜色统计。
- 将mask区域缩放到统一尺寸(256x256),此时再计算整张舌象的HSV通道均值和标准差。
- 对舌中、舌根两个ROI区域分别计算颜色特征,同时用图像梯度统计舌苔的厚薄、燥润特征。
- 把所有量化特征整理成JSON,送给deepseek生成诊断建议,并同时做一份本地规则引擎的“兜底结论”,用于校验AI输出。
第6步的“兜底规则”我非常推荐大家保留。大模型偶尔会出现幻觉,比如把“淡白舌”硬说成“阴虚火旺”。虽然比例不高,但在医疗场景里一次错误就可能让用户对系统失去信任。所以我在本地维护了一套从中医教材里提炼的数十条规则,当大模型输出与规则引擎出现明显冲突时,返回时会附上“规则引擎提醒”,让用户知道系统内部存在分歧。实测这个设计很管用。
5.2 deepseek提示词工程:把中医辨证逻辑写给大模型
大模型生成诊断建议的核心在于提示词结构。下面是我最终稳定使用的提示词模板(简化版):
你是一位有30年经验的中医诊断专家,善于通过舌象特征进行体质分析和辨证。请根据以下客观检测结果进行分析: 舌象检测特征: - 舌体颜色(HSV均值):{tongue_hsv_mean} - 舌苔颜色(HSV均值):{coating_hsv_mean} - 舌形描述:{tongue_shape} - 苔质描述:{coating_texture} - 润燥程度:{moisture} - 齿痕/瘀点/裂纹:{detail_flags} 用户基础信息:{age}岁,{gender},{optional_lifestyle} 请按以下结构回复: 1. 舌象核心特征总结(不超过50字) 2. 可能的中医证型(至少给出2个,说明兼夹可能) 3. 对应的体质倾向(2-3个) 4. 饮食与生活建议(3条,具体可操作) 5. 重要提醒(若舌象可能涉及严重问题,提示就医) 注意: - 只基于提供的舌象特征分析,不要臆造标准之外的表现 - 区分“可能”“倾向”“疑似”的程度词 - 不使用恐吓性语言这里有几个细节。第一,我喂的是HSV均值而不是颜色名称,这样避免模型在颜色理解上产生歧义。第二,必须提供年龄、性别,因为20岁的白厚腻和60岁的白厚腻,辨证方向完全不同。第三,提示词里明确“区分程度词”非常重要,大模型在描述不确定信息时会习惯性夸大,加了这条之后输出严谨很多。
5.3 前后端设计与现场部署
前端我做了H5页面和简版小程序两个端。H5主要用于调试和演示,用户上传图片后,页面会展示三个模块:左侧是原图和分割可视化图;中间是量化特征雷达图(舌色、苔色、苔质、润燥、舌形五个维度);右侧是deepseek生成的诊断建议卡片,里面包含证型、体质、建议和免责声明。雷达图用ECharts实现,视觉效果比纯文本好很多,用户也更容易理解“为什么AI会得出这个结论”。
部署方面,我用Docker打包了模型推理服务和大模型调用服务,放在一台有CPU和16G内存的服务器上。YOLO推理用CPU也能跑,但一次大概200ms;在GPU上只要30ms。deepseek调用走的是官方API,带超时重试,网络抖动时自动退避。生产环境里我在服务端加了限流,每个用户每分钟最多调用3次诊断接口,防止恶意刷请求打爆API账单。
6. 实测与翻车记录:舌象诊断系统的真实边界
6.1 正常光源下的效果实测
系统搭建完成后,我组织了一次小规模内部测试,把20个不同舌象的志愿者照片输入系统,然后又找了两位专业中医师对同一批照片做独立诊断,最后对比结论一致性。在光线均匀、图片清晰、常规舌象的情况下,系统给出的证型排序与中医师诊断的一致率为70%左右。这个数字听起来不算高,但考虑到中医辨证本身存在主观性和流派差异,其实已经具备参考意义。
具体案例:某女性,年龄32岁,舌体胖大有齿痕,苔白腻,舌色淡红。系统通过HSV特征判断为“脾虚湿盛,兼有气虚”,给出的建议是“少食生冷、规律作息、适当用山药薏米粥调理”。中医师给出的诊断是“脾虚湿困,中气不足”,建议方向几乎一致。这类“教科书级”舌象是系统最强的场景。
6.2 照度、色温、手机AI美颜导致的误判
翻车的地方集中在环境干扰。测试时我发现,在暖黄色室内灯光下拍出的舌头,模型会把淡红舌误判为红舌,进而给出“体内有热”的结论。这是因为后置摄像头的自动白平衡被暖光干扰,导致RGB整体偏红。我后来在特征提取环节前加了一个“灰色世界白平衡校正”算法,把图片的RGB通道拉回中性,情况有一定缓解。但遇到混合光源或剧烈逆光时,校正效果还是不稳定。
AI美颜的问题更隐蔽。有一台主流手机即使在“原相机”模式下,系统也会默认做轻度磨皮,舌苔的颗粒感和舌体边缘的微小裂纹会被模糊掉。我是在统计灰度梯度时发现数值明显偏小才意识到这个问题。解决方案有两个:要么在拍摄时用专业相机App锁定对焦和曝光并关闭所有处理;要么在后台对图片做锐化增强。锐化虽然能找回部分纹理,但也会放大噪声,属于治标不治本。
6.3 中医辨证的“符合率”不等于“准确率”
最后必须正视一个问题:AI判断的“符合率”不代表“准确率”。中医的诊断本质是辨证,不同流派对同一舌象的解读可能不同。比如“舌淡红苔薄白”既可以算正常,也可以算“平人”,但在特定体质下可能是“气血失和”的前兆。专家之间本来就有分歧,所以不能用“AI要与某个专家完全一致”来要求系统。
我给自己定的目标是:系统必须在客观特征提取上稳定,在辨证推演上参考权威教材逻辑,同时在输出时保留不确定性表述。这也是为什么我在前端卡片上始终显示“本结果仅供参考,不能替代线下医师面诊”。这不是免责声明式的废话,而是中医诊断本身就需要四诊合参,仅凭一个舌象照片本来就不足以做出最终诊断。
7. 下一步改进方向与个人体会
7.1 从“舌象统计”到“动态舌象”的升级
现在的系统是单帧静态分析,但中医舌诊里有一个维度是“动态观察”,比如舌下络脉的充盈程度、舌伸出来是否颤抖、舌体运动是否灵活,这些信息在静态照片里是拿不到的。我下一步准备引入视频流分析,拍摄一段两三秒的伸舌视频,用YOLO逐帧检测舌体位置和形变,通过帧间差分提取震颤和运动特征。这个方向一旦做通,对肝风内动、气血亏虚等证型的判断准确率会有明显提升。
7.2 把“单一舌象”升级成“多模态辅助诊断”
舌象只是望诊的一部分。如果能把面象、问诊信息、甚至用户的日常作息和饮食偏好加进来,让大模型做多模态推理,诊断的覆盖面会更完整。我的构想是做一个结构化的问诊表,让用户补充主诉、睡眠、二便、寒热偏好等信息,和舌象特征一起交给deepseek分析。这样“舌象专家系统”就慢慢变成一个“中医辅助辨证助手”。
7.3 个人踩坑之后的几条实用经验
最后分享几个真实经验,也是我做完这个项目之后最想说出来的:
第一,别过度迷信模型效果,先解决输入标准化。同样的模型,数据拍得规范和不规范,效果差出一倍,这不是玄学。把拍摄规范和提示词一样写清楚,是项目启动第一要务。
第二,在医疗相关场景里,永远保留“规则兜底”。大模型有创造力,但诊断建议需要可解释性。一条经不起推敲的建议,就算说得再漂亮也会毁掉用户信任。
第三,模型能给出结论,但给不出经验。我在这套系统上见过无数次有趣的现象:当一个人脾虚湿盛很明显时,AI的判断和专家几乎一样;但当存在复合证型、复杂体质、寒热错杂时,专家能透过舌象猜到病人的生活状态,AI只能给出干巴巴的证型概率。这也是为什么我一直强调“辅助”两个字——AI能把老一辈医生“只可意会”的舌诊经验,变成可量化、可复现、可教学的数据,但真正做决策的那一步,还是需要有温度的真人。