案例分析入门2026-10-23

麦当劳 MCP 实战:WorkBuddy 开发多人点餐 Agent 全流程

项目已开源,搜索 "FoodPilot 麦当劳 MCP" 可找到 本项目为参赛作品,非麦当劳官方产品

作者 @瓜哥

预算 160,AI 算成了 163.5

compare-dark.png

先说个挺离谱的事。

我想做个东西:帮一群人点麦当劳。

五个人,预算 160,一个不吃牛肉,一个不能吃辣,一个在控热量。

做完之后我发现,真正难的根本不是"吃什么",是协调。😮‍💨

你肯定经历过这个场面:

群里喊一句"点麦当劳了,报一下忌口",然后等。

有人说"我都行",有人三小时后才回,有人回"随便"——但你记得他上次不吃香菜。

你打开小程序翻菜单,算价格,发现超了,删掉一份薯条,再算一遍。

然后有人说:"等等,我其实不吃牛肉。"

十分钟过去了,群里还在问"到底谁不吃啥"。

这不就是该让 AI 干的活吗?

我把它交出去了。然后它翻车了。


一、AI 第一次算账,就错了

我把需求原封不动丢给模型,让它出方案。

方案出来了,看着还挺像样:谁吃哪个堡、配什么小食、总价多少。

我核对了一遍账:

  • 它报的总价是 163.5 元
  • 我的预算是 160
  • 五个人里有个"不吃牛肉"的,它给人家排了一份巨无霸

我以为是个偶然,又问了一遍同样的问题。

这次价格变成了 155.8。

第三次,又是另一个数。

同一句话,问三遍,三个价格。而且我完全看不出 163.5 是怎么加出来的——它只给了结果,没给过程。

到这一步,很多人会得出一个结论:模型不够强,换个更好的。

但我后来想明白了,这个结论是错的。


二、不是它不会算,是这个任务不该它算

大模型擅长的是语言。而这件事的核心,是搜索 + 约束满足。

两个完全不同的活。

AI 硬干这件事,会翻在三个地方:

🔹 不可复现:同一输入,三次三个价格。因为它是在"生成"一个答案,不是在"计算"一个答案。

🔹 不可验证:163.5 错在哪?你没法指着一行代码说"这儿错了"。你只能整体重算,然后继续猜。

🔹 不可解释:它会告诉你"这款最受欢迎"。

但这不是解释。这叫形容词。🙃

真正的解释必须能回答两个问题:为什么是它?它牺牲了什么?

第三条最致命。因为用户不同意方案的时候,需要一个能下手的地方。如果理由是一句形容词,那他只能全盘推翻重来。


三、于是我做了个分工

我把活儿切开了,切得挺狠:

大模型:只听懂人话。谁不吃什么、预算多少、要不要辣。缺什么就问。最后把方案讲成人话。

代码:只算账。能不能满足、怎么组合最优、总价多少、有没有违规。

MCP 接口:只提供事实。门店有什么、多少钱、有没有货。

听起来很啰嗦,但它解决了一个特别实际的问题——出问题我能定位。

是接口给的价不对?还是我枚举漏了?还是展示时算错了?

三条路,分得清清楚楚。这套分法后来成了我所有 Agent 项目的默认指南,也是这次工程里最关键的一个经验分享:让该算的算,让该说的说。

后来我给自己定了一条死规矩:

页面上、对话里出现的每一个数字,都必须能追溯到代码的那一次输出。没有一处是模型算的。


四、第二版,我又翻车了

给用户 2-3 套方案,是这类产品的标配。

我第一版很聪明:加权打分。

价格占 40%,多样性占 40%,热量占 20%。跑三组权重,起了三个名字:省钱版、均衡版、健康版。

然后我自己点了一下切换。

三套方案几乎一模一样。

我把权重从 0.4 调到 0.5,结果没变。调到 0.7,才换了一个菜。

用户只要点两下就会发现:这是个障眼法。💀

这一瞬间,"可解释"这三个字就已经死了。

改法:不调权重了,换目标函数。

让每套方案有自己真正的优化目标,各自求最优:

🔸 最省钱:把总价压到最低(附带"至少 3 种主餐",防止五个人全吃一样)

🔸 最不重样:主餐种类尽量多

🔸 最低热量:整桌热量最小(低卡名额优先给有热量要求的人)

5 个人 160 块,实测出来是这样:

  • 最省钱:117.5 元,3 种主餐,2480 大卡
  • 最不重样:145.5 元,5 种主餐,2880 大卡
  • 最低热量:127.5 元,3 种主餐,2190 大卡

差别一下子就"结构性"了:

便宜的方案有三个人吃同款;不重样的方案最贵;低卡方案比不重样少了 690 大卡。

用户选哪套,是在做真实的权衡,不是在看我摇骰子。


五、"可解释"到底长什么样

这是我觉得整个项目最值钱的部分。

「可解释」很容易被写成形容词堆砌。我给自己定的标准是:每条理由必须有数字,而且必须承认牺牲了什么。

反面例子(我第一版真这么写的):

这款性价比最高,符合您的需求。

正面例子(现在实际输出的):

避开牛肉,该店只筛出 8 项可选;比全场更低的脆鸡排蛋堡贵 6 块,用来凑够 3 种不同主餐,避免整桌一个味。

差别在哪?

📌 有数字:8 项、6 块、3 种。你可以自己核对。

📌 有对比:说的是"比 X 贵多少",不是孤立地夸自己。

📌 有取舍:直说"我多花了 6 块,是为了不让你五个人吃一样的东西"。

看到这句,你可以直接怼回来:"那别凑种类了,就吃便宜的。"

一个能被反驳的方案,才是可解释的方案。

"性价比最高"没法反驳,你只能接受或者关掉。

所以可解释性的价值,从来不是让 AI 显得有道理——是让你有地方下手。


热量堆叠条让 bug 暴露出来:中间那条多出的橙色段就是麦旋风

六、一个我改了四次的 bug

这段是我这次遇到的最大挑战,也最真实。

求解器做完、测试全过,我开始做可视化页面。

为了体现"低卡方案不配甜点"这个决策,我加了条热量堆叠条:主餐一段、小食一段、甜点单独一段。

然后截图一看,我愣住了:

「最低热量」方案,热量比「最省钱」方案还高。

2760 大卡 vs 2480 大卡。

名字叫"最低热量",结果它最高。

顺着查下去,原因特别朴素:

低卡方案的共享小食,排序键用的是价格(挑最便宜的)。于是补位时,补进了一份 280 大卡的麦旋风。

主餐确实选了热量更低的,但一份小食把优势全吃回去了。

修复只改了一行:低卡方案的共享小食,按热量排序。

这个 bug 教会我一件事:

目标函数不只是用来选主餐的。挑小食、挑饮料、要不要甜点——每一个子决策都得服从同一个目标。

只要有一个子决策按别的口径走,整个方案的"最优"就是假的。

更坑的是:这个 bug 永远不会被自动化测试抓到。

它不超预算、不违反忌口、不超热量上限,所有硬约束都通过。

它只违反了一件事:方案的名字,和方案的实际效果不一致。

最后是靠人眼看截图发现的。所以我现在的习惯是:每个版本都必须真的把页面打开看一眼。


七、关于接口,一句话

这个项目最初的想法,其实是"自己写一个麦当劳下单接口"。

查完资料我就放弃了:麦当劳 2025 年 12 月就上线了官方 MCP 服务,33 个工具,免费,限流 600 次/分钟。

自己再造一个,等于给官方服务套层壳。

所以我改去啃"用哪些、按什么顺序用"。

33 个工具里,我只用了 15 个。剩下的(积分商城、抽奖、活动预约)明确不用。

理由很简单:

工具面越宽,AI 乱调用的概率越高。

33 个全接一遍不是本事,知道哪些不该接才是。 😌


八、一个特别反直觉的发现

测试的时候我点了几十种开关组合,发现一个有意思的事。

预算 160 的时候,打开"陈昊也不吃牛肉"这个开关——结果完全不变。因为他本来就没吃到牛肉。

但预算调到 200,同一个开关会让方案整体重排。

这说明什么?

改一个人,不等于换一份菜。

需求一变,腾出来的预算会改变其他所有人的最优解。所以任何一条约束变化,都必须整体重算。

你要是手动改一份,大概率踩预算,或者让另一个人失去最优选择。

这是多人协调最反直觉的地方,也是我做这个项目最想证明的一件事。


最后

这类 AI 产品的价值,从来不在"能聊"。

在敢交付。

用户说"就这个,下单吧",意味着他信了这个方案的每一个数字。

这份信任不能建立在"AI 看起来很聪明"上,只能建立在"每一步都能被验证"上。

所以我做的事情很朴素:

把不确定的部分(听懂、表达)交给 AI,把确定的部分(计算、校验)全部交给代码。

AI 负责听懂"有个不吃牛的"。

代码负责保证,那个人面前不会出现巨无霸。


你们公司点外卖,谁负责统计忌口?

评论区说说,我猜大概率是同一个人,每次都是他。🙋


项目已开源,搜索 "FoodPilot 麦当劳 MCP" 可找到 本项目为参赛作品,非麦当劳官方产品

#AI #大模型 #MCP #麦当劳 #WorkBuddy #工程实践 #Agent开发 #约束求解 #技术复盘 #独立开发

LIVE

今日访问
—
VISITS
今日浏览
—
PV
累计访问
—
VISITS
累计浏览
—
PV