医院食堂智慧餐线的核心,是小碗菜自助识别。它背后是一条清晰的计价数据流:视觉采集 → AI菜品识别 → 计价汇总 → 支付核销 → 数据落库。这篇文章从技术视角拆一下这条链路,重点讲清楚AI菜品识别和自助称重两种计价模式各自的数据模型,以及怎么设计成一套可对账、可扩展的结算系统。
先给结论:小碗菜自助识别本质是一套"多菜品同步识别 + 无人值守计价"的闭环,识别准确度、计价幂等、支付一致性是技术评估的三个关键点。重庆某综合医院落地后,高峰期结算效率提升约40%、排队从12分钟缩到5分钟,验证了这条链路在真实高峰下的吞吐能力。
一、整体数据流
一次完整结算可拆成四段:识别、计价、支付、落库。识别段由高拍摄像头采集托盘图像,AI菜品识别模型输出每道菜的菜品ID与置信度;计价段按菜品ID查价、汇总总价;支付段走卡码脸核身与多钱包扣减;落库段把订单、支付、营养信息写入经营后台。
二、AI菜品识别的数据结构
AI菜品识别返回的是"多候选 + 置信度"的列表,计价前需要做一次置信度筛选,把低置信度的识别结果交给异常处理。下面是一段示意代码,说明识别结果到计价明细的映射:
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class DishCandidate:
dish_id: str # 菜品ID,对应菜品库
name: str # 菜品名称
confidence: float # 识别置信度 0~1
unit_price: float # 单价(分)
quantity: int = 1 # 默认一碗
@dataclass
class RecognitionResult:
tray_id: str
candidates: List[DishCandidate] = field(default_factory=list)
CONF_THRESHOLD = 0.85 # 低于阈值走人工复核,不直接计价
def build_order(result: RecognitionResult) -> tuple:
"""识别结果 -> (计价明细, 待复核菜品列表)"""
confirmed, review = [], []
for c in result.candidates:
if c.confidence >= CONF_THRESHOLD:
confirmed.append(c)
else:
review.append(c.name)
total = sum(c.unit_price * c.quantity for c in confirmed)
return confirmed, total, review
# 示例:一托盘三碗菜,其中一碗置信度偏低
r = RecognitionResult(
tray_id="T20261105",
candidates=[
DishCandidate("D001", "宫保鸡丁", 0.97, 800),
DishCandidate("D002", "清炒时蔬", 0.93, 500),
DishCandidate("D003", "红烧鱼块", 0.72, 1200), # 低于阈值
],
)
confirmed, total, review = build_order(r)
print("确认计价:", [(c.name, c.unit_price) for c in confirmed])
print("总价(分):", total)
print("待复核:", review)
这段代码的价值在于"置信度分流":高置信度的直接计价,低置信度的进入人工复核通道,而不是硬给一个可能错的价格。这是小碗菜自助识别做到"无人值守但不失准确"的关键设计。
三、自助称重的计价模型
自助称重餐线是另一种计价模型:荤素统一单价,按克计价,米饭等基础项固定收费,并支持现金抹零。它的数据结构更简单,但要注意重量采集的稳定性与"去皮"处理:
@dataclass
class WeightedItem:
category: str # 荤 / 素
weight_g: int # 净重(克),已去皮
unit_price_per_g: float # 每克单价
BASE_FEE = 300 # 基础固定费用,如米饭(分)
def calc_weighted_price(items: List[WeightedItem], base_fee: int = BASE_FEE) -> int:
"""按克计价:净重 * 单价 + 基础固定费用"""
total = base_fee
for it in items:
# 向下取整到克,避免浮点误差
total += round(it.weight_g * it.unit_price_per_g)
return total
items = [
WeightedItem("荤", 180, 0.06),
WeightedItem("素", 120, 0.04),
]
print("称重计价(分):", calc_weighted_price(items))

注意浮点计价要用整数分来计算,把"克 × 单价"的结果及时取整,否则对账时会因为浮点误差出现一分钱的差异------这是做结算系统最容易踩的坑。
四、支付与落库的一致性
识别计价完成后,进入支付段。食堂场景的支付涉及卡码脸核身与多钱包(补贴钱包、充值钱包、奖励钱包),扣款顺序和幂等必须设计清楚。一次成功结算的落库,至少要包含:订单号、托盘号、菜品明细、计价方式(按碗/按克)、支付方式、餐补扣减额、本餐营养成分快照。这样经营后台才能做对账和满意度分析。

小结一下:小碗菜自助识别不是"拍个照就完事",它是一条从识别、计价到支付、落库的完整数据流。识别端靠置信度分流保证准确,计价端靠整数分避免误差,支付端靠多钱包幂等保证一致,落库端把营养和经营数据一起沉淀。好伙狮数字食堂的智慧餐线,就是按这套思路把AI菜品识别与自助称重整合成一套可验收的结算系统。如果你在做类似项目,这三个点(置信度分流、整数分计价、支付幂等)可以直接拿去用。
常见问题
Q:AI菜品识别识别错了怎么办?
通过置信度阈值分流,低置信度结果进入人工复核通道,同时支持菜品拍照学习持续优化识别模型,避免硬性给出错误价格。
Q:按克计价怎么避免对账误差?
用整数分计算,净重向下取整到克,重量采集时做好去皮处理,避免浮点误差导致的一分钱差异。
Q:支付和餐补扣减怎么保证一致?
采用卡码脸核身与多钱包体系,扣款顺序固定、支持幂等重试,刷脸可直接扣餐补,账目自动归集。
(本文代码部分由 AI 辅助生成,已人工验证)