“你饿了,有预算,可能还想凑够蛋白质、卡住热量上限,或者只是想吃点别的,别再是那老三样。”

打开网易新闻 查看精彩图片

然后你打开外卖App开始刷。二十分钟后,你看了47道菜,点开六个餐厅页面,依然完全不知道点什么。

问题从来不是吃的选项太少,而是“把合适的选项找出来”这件事,全得你自己干。开发者 SarveshDujari 为此做了 CraveCode——一个AI辅助的食物发现系统:按你的偏好搜餐、过滤掉不合适的、再给剩下的排序。

目标很朴素:少刷一点,少猜一点,把时间留给吃。

它回答的是一个“看着简单其实很难”的问题

CraveCode 要回答的是:有什么吃的,能同时满足我的目标、偏好和预算?

它的起点不是餐厅目录,而是一份“用餐简报”。你可以指定饮食偏好、蛋白质目标、热量上限、预算、想吃的菜系、用餐时段,以及当下馋的那类食物。系统随后去发现候选、按你的要求过滤、排序,并让结果更多样。

和普通推荐不一样的地方有几处:

  • 自适应发现:先并行发起两个菜单查询,当结果在多样性或覆盖度上不够时,最多扩展到四个初始发现查询。
  • 约束感知过滤:把已知不合适的选项筛掉,包括饮食标签不兼容、明确排除项、以及超出预算的菜品。
  • 不止看相关性:排序会考虑查询相关性、菜品家族匹配、价格、库存状态和可获得的餐厅反馈。
  • 减少重复推荐:同一家餐厅的重复菜品会被去掉,重复选择会被降权,以鼓励多样性。
  • 继续探索:本地部署的 Gemma 模型会在你想看更多时,给出额外的菜品搜索词。
  • 证据优先于猜测:公开网页结果只当作发现线索,不当成已核实的实时菜单;不确定的价格和粗略的营养估算,不会被当成确认事实呈现。

系统最多返回15个排序后的选项,实际数量取决于有多少候选。

有意思的地方不在于“AI会推荐吃的”,而在于这个应用把搜索、显式约束、确定性排序和可选的AI探索拼在一起,而不是让一个大模型把整个答案凭空编出来。

模型提议,应用核查,证据决定能说什么

作者不想让 CraveCode 变成一个“给你一段看着很可信的美食小作文、剩下你自己去核实”的聊天机器人。他要的是一个真的去搜候选、套规则、并且说清楚自己知道什么的系统。

架构大致是:用餐简报进入 React + Vite 前端,交给 Node.js / TypeScript 接口,再走 Mastra 工作流,按“计划 → 发现 → 验证”推进。发现阶段有两条路:本地环境用 Swiggy MCP 搜真实菜单,公开预览用 SerpApi 做公开网页发现。候选归一化之后,依次过滤、打分、去重,最后输出排序推荐。另外还接了本地 Gemma 和 MongoDB Atlas。

几个关键取舍:

  • Mastra 负责编排发现流程,但不包揽所有业务规则。资格检查和排序决策留在应用代码里,这样系统比“一个提示词管全部”更容易检查、调试和改进。
  • Swiggy MCP 只在登录后的本地环境使用,能搜到与保存的配送地址关联的菜单,拿到价格和可获得的库存信号。作者特意把它和托管预览区分开:餐厅页面存在,不等于某个菜品现在确认可下单。
  • SerpApi 是公开发现的后备方案,用来找城市相关的 Swiggy 页面,应用会检查查询相关性、保留合适的配送页链接、去掉重复和泛化结果。搜索引擎保证不了一道菜当前的价格、库存、营养或配送资格。
  • Gemma 只干一件聚焦的事:提出额外的菜品搜索词。建议要过白名单和结构化输出校验,格式不对或不合适就走确定性兜底。
  • MongoDB Atlas 存已完成的搜索、候选和共享用量计数器。公开预览依赖外部搜索服务时,这些计数器尤其重要——托管预算存储不可用,付费的 SerpApi 请求就直接停掉,而不是绕过共享预算保护继续跑。

串起来的原则就一句:模型提议,应用核查,证据决定能说什么。模型想出的菜品仍要过发现流水线;公开搜索结果不会因为看着相关就变成已核实菜单;粗略营养估算也不会变成某家餐厅的营养事实。

为什么不让AI决定一切

大模型能建议一顿完美的饭,但它保证不了这道菜有货、买得起、营养数据准确。所以职责被拆开:Gemma 探索新菜品,搜索发现候选,确定性代码负责过滤和排序。不确定的价格和营养估算,就老老实实标成估算。

作者说,这让 CraveCode 更好调试,也让他对推荐结果更有掌控。

下一步最想补的是营养。目前系统对支持的菜品类型用的是手工编写的宽泛营养区间,是估算,不是某家餐厅具体配方或分量的核实值。他想接入更可靠的单品级营养数据、加强对实时发现的评估、更清楚地核实最终应付价格和可售状态,以及在拿到批准后把 Swiggy 集成搬到 Render 上。

至于“懒人回报”,逻辑很直接:不用再一个个翻餐厅页面、逐道菜对预算、在长长的相似列表里比较,而是从自己的约束出发,拿到一份过滤并排序过的短名单。要衡量它值不值,合理的做法是拿几份贴近现实的用餐简报,对比手动找一顿合适的饭和用 CraveCode 各要多久。