内容
# McLottery Alchemist · 麦门全能管家
> 一个跑在 WorkBuddy 上的麦当劳 Agent Skill:**把一顿饭点明白,把优惠用到位,把积分算清楚,把抽奖守规矩。**
麦当劳的坑很具体:积分什么时候过期?30 积分到底能换什么?点餐时哪张券真的能用、这一单怎么付最省?
积分不够换礼品,要吃到什么时候?接口说「积分不足」是真的不足吗?抽奖没反应,是没抽成还是扣了分?
McLottery Alchemist 用三层结构回答这些问题:
| 层 | 负责 | 不负责 |
|---|---|---|
| **Skill(提示词 + 能力模块)** | 理解意图、组织对话、决定调哪个工具、按需加载点餐/券/营养/计划模块 | 算数、记账 |
| **确定性计算层(`src/mclottery`)** | 到期分类、兑换筛选、成本试算、带券算价比较、热量组合、积分缺口计划、下单金额复核 | 访问网络 |
| **MCP 工具(麦当劳官方 33 个)** | 门店、菜单、算价、下单、取消、券、积分、抽奖、活动、营养 | 判断该不该买、该不该抽 |
## 目标用户
- **想点餐但懒得算的人**:想知道「这单用哪张券最省、实付多少」,而不是一堆券名。
- **积分快过期但懒得算的人**:想被告知「先换哪个、别拖到月末」。
- **想抽奖但怕被坑的人**:希望先看到「单次 24 分、你只有 20.5 分、差 3.5 分」再决定。
- **想换礼品但积分不够的人**:需要一张按截止时间、到店频率、预算排出来的计划表。
- **想控制热量的人**:按目标热量组合一餐,而不是凭印象点。
- **被接口字段坑过的开发者**:需要一份把真实返回、真实坑位写清楚的 MCP 集成参考。
## 它解决的真实问题
这些不是设想,是接真实 MCP 后实测到的:
1. **`point = "0"` 不等于免费。** 积分商城列表里混着生日派对、读书会等**付费活动**,`point` 是 0、`price` 是 45/58/138 元。直接按「所需积分排序」会推荐一堆要花钱的东西。
2. **`status = 2`(上架)不等于能换。** 实测列表里存在 `downTime` 已过期的商品,状态仍为上架。必须同时校验 `upTime / downTime`。
3. **积分是小数,且按月汇总。** `availablePoint = 20.5`;到期字段只有 `currentMouthExpirePoint`(注意是 `Mouth`)与 `nextMouthExpirePoint`,**没有具体到期日期**。所以「你的 120 积分将在 10 月 23 日过期」这种话,接口根本支撑不了。
4. **能不能抽只看 `drawDecision.resourceEligible`。** `availableTimes = 0` 不代表不能抽(混合规则下会改扣积分),`drawTypeText` 也只是文案。
5. **`draw-lottery` 无入参、一次一抽、无幂等键。** 抽 3 次 = 3 次串行调用;超时重试就是重复扣分的风险。
6. **奖池没有概率。** 接口只给奖品名与类型,任何「期望收益」都是编的。
## 核心能力
- **点餐全流程**:门店 → 菜单 → 详情 → 算价 → 用券 → 六项确认卡 → 下单 → 支付链接 → 查单 → 取消;结果未知时禁止重复下单,先查订单列表。
- **优惠最大化**:先领麦麦省券,再用门店券判断可用性,一单选最省;**不为凑门槛加购**。
- **营养与热量**:按目标热量组合 1–3 件餐品,只做算术,不做医疗或减重建议。
- **积分缺口计划**:按截止时间、到店频率、预算区间算「够不够、要几周、总共花多少」,同时给替代路径。
- **积分体检**:余额、本月/下月将过期、已过期,全部带数据来源与精度声明。
- **兑换筛选与预检**:只留「状态上架 + 积分 > 0 + 在兑换窗口内」的商品,被排除的每个都给出原因;下单前校验 skuId、实物地址、**积分 + 现金双金额**,并说明「待支付」而非「兑换成功」。
- **三类方案**:A 止损 / B 稳健兑换 / C 娱乐抽奖;**不可执行的方案直接写明为什么**,不凑数。
- **抽奖守卫**:意图 → 明确授权 → 单次执行 → 未知状态冻结 → 对账解除,台账落盘、可审计。
- **活动与福利**:当月活动日历、主题活动四级预约链、可领券,只推进行中与即将开始。
- **MCti 人格 / 娱乐运势**:八种吃堡人格与今日签文,纯娱乐,且明确「不影响中奖概率」。
- **中奖追踪**:只展示接口返回的状态与提醒文案,不补期限。
- **Agent 工作台**:口令启动「麦门欧气补给站」,十三个面板覆盖点餐、福利、营养、计划、账户、兑换、活动、奖品与娱乐;宿主支持 UI Bridge 时渲染,不支持就降级成文字摘要。
- **单文件 Demo**:不联网、不扣分、不需要 Token,打开就能点着体验上述全部面板。
## 安装方法
### 方式一:在 WorkBuddy 里用(推荐)
1. 打开 WorkBuddy → 左侧栏【专家·技能·连接器】→【连接器】→ 右上角【自定义连接器】→【配置MCP】。
2. 在手动配置页填入(把 `${MCD_MCP_TOKEN}` 换成你自己的 Token):
```json
{
"mcpServers": {
"mcd-mcp": {
"type": "streamablehttp",
"url": "https://mcp.mcd.cn",
"headers": { "Authorization": "Bearer ${MCD_MCP_TOKEN}" }
}
}
}
```
3. 保存后回到【自定义连接器】启用 `mcd-mcp`。
4. 把 `skills/mclottery-alchemist/` 整个目录放进你的技能目录(项目级 `.workbuddy/skills/`,或用户级 `~/.workbuddy/skills/`)。
5. 如需计算和真实抽奖,在 Python 3.10+ 环境执行 `python -m pip install -e <本仓库绝对路径>`,确认 `mclottery --help` 可运行。仅复制 Skill 支持只读查询与娱乐互动,不能运行守卫。默认台账为 `~/.mclottery/ledger.jsonl`;旧版相对路径台账需先核实未结算状态并迁移,不能以新建空台账绕过冻结。
6. 直接对话:「我要吃麦当劳」「这单用哪张券最省」「帮我配一餐 700 卡」「积分不够换礼盒,帮我排个计划」「我积分怎么样」「现在有什么抽奖」。
> Token 申请:麦当劳 MCP 站点右上角登录 → 控制台 → 激活,阅读并同意服务协议后复制。
> **本仓库不含任何真实 Token**,`mcp-config.example.json` 只有占位符。
### 方式二:只用计算层(不需要 MCP)
```bash
git clone https://github.com/Bryce-border/-.git mclottery-alchemist
cd mclottery-alchemist
python run.py --help # Python 3.10+,零第三方依赖
```
可选安装为命令:
```bash
pip install -e . # 之后可直接用 mclottery 命令
```
## 在线体验(Agent 工作台 Demo)
不想先配 Token、也不想读代码?直接打开随 Skill 附带的单文件工作台:
```text
skills/mclottery-alchemist/assets/demo.html
```
双击用浏览器打开即可(也可以交给 WorkBuddy 直接预览)。**单文件、零依赖、不联网、不调用 MCP、不需要 MCP Token。**
在 Agent 里说出下面任一句,也可以启动同一个工作台(是否渲染成面板取决于宿主是否支持 UI Bridge):
> 启动麦门炼金台 · 打开麦门欧气补给站 · 麦门积分管家,开工 · 我要吃麦当劳
十三个面板:
| 面板 | 能体验什么 | 背后用的工具 |
|---|---|---|
| 炼金总览 | 能力介绍、今日活动播报、账户摘要、到期风险、快捷入口 | 账户 + 活动 + 券(只读) |
| 点餐台 | 选门店/取餐方式、菜单加购、带券算价比较试算、六项确认卡 | 门店、菜单、算价、下单(意图) |
| 活动日历 | 进行中/即将开始的活动、主题活动四级预约链 | `campaign-calendar`、`query-party-*` |
| 福利中心 | 可领券、门槛与带券算价比较、领券授权说明 | `available-coupons`、`query-store-coupons` |
| 营养实验室 | 目标热量输入、1–3 件组合、蛋白质/脂肪/碳水/钠汇总 | `list-nutrition-foods` + 本地算术 |
| 积分计划 | 缺口、每次约得、预计周期、预计总支出、逐周进度 | `query-my-account` + 商城 + 本地计算 |
| 积分体检站 | 余额与月度到期、固定成本试算、规划入口 | `query-my-account` |
| 积分兑换研究所 | 搜索、筛选、候选与排除原因、商品详情 | `mall-points-products`、`mall-product-detail` |
| 麦麦抽奖活动站 | 状态、成本、`drawDecision` 资格、奖池、前置核验、模拟仪式 | `query-lottery-info` + 账户 |
| 中奖收藏柜 / 我的麦享卡包 | 奖品状态与接口提醒、卡券与可用性边界 | `query-my-prizes`、`query-my-coupons` |
| MCti 人格实验室 | 八型人格、逐题/快测、多选、跳题、自选、改答、分享、搭子建议 | 纯本地,不查账户 |
| 今日麦气 | 1–5 星麦签、宜/忌、签文、幸运单品灵感 | 纯本地,不做中奖预测 |
> **数据口径**:页面默认是**示例数据**,只有宿主真正推送 `mclottery:state` 后才可能变成「实时数据」。页里的余额、价格、消耗、奖品、概率都是演的,不会扣任何积分。
> **页面没有「直接下单 / 直接支付 / 直接抽奖 / 直接领券」按钮**:有副作用的动作只产生意图,必须回到对话完成成本说明、确认与授权。
> **宿主不支持内嵌**时,Skill 会降级成文字摘要,不会假装已经打开面板。UI 契约见 [`agent-ui-integration.md`](./skills/mclottery-alchemist/references/agent-ui-integration.md),页面/意图映射见 [`demo-feature-map.md`](./skills/mclottery-alchemist/references/demo-feature-map.md)。
真实能力请在对话里用:「我积分多少」「现在有什么抽奖」「积分快过期了怎么办」。
## 使用示例
### 对话示例 A:积分体检(数据均为真实返回结构)
> **你**:我积分怎么样,快过期了吗
>
> **炼金术士**:账本看完了——
> 可用 **20.5** 积分(累计 34,已过期 13.5)。
> 本月将过期 **0**,下月将过期 **0**,暂时没有到期风险。
> 一句实话:接口只给「按月汇总」的到期数,没有具体到某一天,所以我没法告诉你「10 月 23 日过期多少」。
> 想花的话,目前门槛最低的可兑换项要 50 积分,还差 29.5 分。
### 对话示例 B:真实抽奖被守卫拦下
> **你**:直接帮我抽一次
>
> **炼金术士**:先对账再动手——活动「麦麦积分抽奖」,单次 **24** 积分,你的可用 **20.5**,差 **3.5** 分,服务端也标了「积分不足」。
> 这次不抽,也不替你「试试看」。等积分够了再说,抽奖不会跑。
### CLI 示例 C:生成三类方案
```bash
python run.py plan \
--account tests/fixtures/account_expiring.json \
--products tests/fixtures/products_mixed.json \
--activity tests/fixtures/lottery_running_ok.json \
--now "2026-10-19 12:00:00"
```
```text
—— 积分盘点 ——
· 本月将过期:120(接口仅返回月度汇总)
· 下月将过期:80(接口仅返回月度汇总)
· 提醒窗口为产品侧阈值,不是麦当劳官方积分有效期政策;实际有效期以麦当劳官方渠道为准。
【方案 A】优先止损(防止积分作废)
· 优先处理即将过期的 200 积分(本月 120 + 下月 80)
· 可兑换:6.9元可乐麦炫酷(50 积分,类目:到店专用)
...
【方案 B】稳健兑换(确定性优先)
· 按「用途 + 兑换门槛」选择,不按门槛低就认定性价比高
【方案 C】娱乐抽奖(体验随机结果)
· 麦麦积分抽奖:单次 24 积分
· 只在你明确同意的次数内执行,抽完即止,不追加
注:抽奖是概率事件,接口未返回中奖概率,任何「期望收益」都不成立。
```
### CLI 示例 D:守卫如何避免重复扣分
```bash
python run.py guard propose --activity-code dtx2 --activity-name 麦麦积分抽奖 --draws 1 --cost 24 --preflight-ok
python run.py guard authorize --intent-id intent_xxx --explicit # 没有 --explicit 会被拒
python run.py guard begin --auth-id auth_xxx # 登记一次执行
python run.py guard settle --attempt-id draw_xxx --result draw_timeout.json
python run.py guard status # 未知状态 → 冻结,禁止重试
```
### 对话示例 E:只想要趣味互动
> **你**:今天欧气怎么样
>
> **炼金术士**:**今日干饭运势:★★★☆☆**
> 麦门签文:薯条趁热,积分趁早,欧气随缘,快乐为王。
> 今日宜:先看一眼积分有效期。
> 今日忌:为了证明自己是欧皇而连抽三次。
> (纯娱乐,跟真实中奖概率没关系,我也不会去动你的账户。)
### 对话示例 F:点餐 + 用券(六项确认后才下单)
> **你**:我要吃麦当劳,公司附近有什么店?帮我点个巨无霸套餐,用最省的券。
>
> **管家**:先确认一下:你要**到店自取**还是**外送**?我查到 2 家店:人民广场店(320m,营业中)、南京东路店(860m)。
>
> **你**:到店自取,人民广场店。
>
> **管家**:
> 【下单确认】
> 门店:人民广场店(S-DEMO-01)
> 取餐方式:到店自取
> 商品:巨无霸 ×1 ¥25.5|中薯条 ×1 ¥12
> 优惠:满 30 减 5(-¥5)
> 配送费:¥0
> 实付:¥32.5(calculate-price 返回)
> 确认后我创建订单,支付在官方页面完成,我不代付。
>
> **你**:确认。
>
> **管家**:订单已创建:`ORD20261021001`,待支付。支付链接:<接口返回的链接>。未支付订单可能自动取消,具体时限以订单页为准。
### 对话示例 G:营养与热量(只算数,不做医疗建议)
> **你**:帮我配一餐 700 大卡左右的。
>
> **管家**:按 `list-nutrition-foods` 的默认份数据,最接近的是:
> 巨无霸(550 kcal)+ 中杯可乐(150 kcal)= **700 kcal**
> 蛋白质 25g|脂肪 30g|碳水 78g|钠 910mg
> 偏差 0;另有 1 个餐品缺热量字段,没算进来(麦旋风)。
> 这是热量搭配,不是营养处方;特殊人群建议咨询专业人士。
### 对话示例 H:积分不够,排一张计划表
> **你**:我想换那个 3000 分的礼盒,现在只有 2350 分,帮我看看还来得及吗?
>
> **管家**:先确认三件事:你大概**每周去几次**、**单次预算**多少、想在**什么时候之前**换到?
>
> **你**:每周 2 次,一顿 25–40,年底前。
>
> **管家**:
> 缺口 650 分。按你给的规则(1 元 = 1 分,单次取中位 32.5 元):
> 每次约 32.5 分,需要约 20 次,约 10 周。
> 距 12 月 31 日约 10.1 周 → **刚好能达成**,预计总支出约 ¥650。
> 提醒:积分按规则到账、礼盒在截止前仍有库存,这两个前提不成立就要重算。
> 如果不想花这么多,也可以换 2000 分以内的目标,或用现有积分直接换小件。
## 架构
```text
用户
│
▼
WorkBuddy Agent ── 加载 ──▶ skills/mclottery-alchemist/SKILL.md
│ │ 意图路由 / 授权红线 / 话术边界
│ ▼
│ references/*.md(工具契约、人格、算法)
│
├── 只读查询 ──▶ mcd-mcp(门店、菜单、券、积分、活动、营养 …)
│
├── 需要算数 ──▶ python run.py <cmd> ──▶ src/mclottery(纯函数,无网络)
│ │
│ ├── nutrition / mealplan / coupon / order
│ └── guard:ledger.jsonl(授权 / 执行 / 对账)
│
└── 想先体验 ──▶ assets/demo.html(十三面板工作台,默认示例数据)
│
└── 宿主支持 UI 时 ──▶ mclottery:state / agent-intent 桥接
(不支持则降级为文字摘要,不假装打开)
```
## 目录结构
```text
.
├── README.md # 本文件
├── CONTEST_DECLARATION.md # 参赛声明(官方原文,未改动)
├── MCP_INTEGRATION.md # MCP Server / Tool / 调用流程 / 业务价值
├── mcp-config.example.json # 脱敏配置示例(仅环境变量占位符)
├── workbuddy.md # WorkBuddy 开发对话上下文(专项奖励核验用)
├── run.py # 零安装 CLI 入口
├── pyproject.toml
├── skills/mclottery-alchemist/
│ ├── SKILL.md
│ ├── assets/demo.html # 单文件离线演示页(可直接打开体验)
│ ├── references/
│ │ ├── tool-workflows.md # 33 个工具契约与调用链
│ │ ├── ordering-workflow.md # 点餐/外送/下单/取消全流程
│ │ ├── coupon-strategy.md # 领券与一单最省
│ │ ├── nutrition-health.md # 热量与营养边界
│ │ ├── points-meal-plan.md # 积分缺口 → 饮食计划
│ │ ├── campaigns.md # 活动日历与福利推荐
│ │ ├── points-calculation.md mcti-personalities.md output-templates.md
│ │ └── agent-ui-integration.md demo-feature-map.md
│ └── tests/{intent-routing,mcti-experience,safety-cases,regression-cases,demo-acceptance}.md
├── src/mclottery/
│ ├── models.py expiry.py value.py
│ ├── lottery.py guard.py plan.py cli.py
│ ├── nutrition.py mealplan.py coupon.py order.py redemption.py
└── tests/ # 170 个单元测试 + fixtures
```
## 测试
```bash
python -m unittest discover -s tests -v # 170 tests, OK
pytest -q # 可选,已配置 pythonpath=src
```
覆盖:积分充足/不足/临期、活动结束/未登录、商品售罄/下架/预热/窗口过期/付费活动、
中奖/未中奖/超时未知、授权缺失、额度耗尽、单日上限、台账持久化与脱敏、
热量组合与缺字段排除、积分缺口与零频率、券门槛/封顶/不叠加、订单金额复核与重复提交指纹、
兑换预检(实物缺地址/积分不足/现金+积分)与「待支付」返回解析。
## 已知限制(重要,不粉饰)
- `draw-lottery` **没有幂等键**。守卫的防重复只能做到「本地台账 + 未知即冻结」,无法阻止在另一台设备上同时操作。请勿多端并发抽奖。
- `create-order` 同样**没有幂等键**。本地只做购物车指纹提示,不能阻止其他设备重复下单;结果未知时必须先查 `order-list`。
- 接口**不返回中奖概率**,因此期望价值功能默认锁死,只输出定性结论。
- 接口**不返回分批到期明细**,到期风险只能到「月」粒度。
- **接口不返回积分获取速度**(消费 1 元得多少分),积分计划的到账速度必须由官方规则或用户输入提供。
- 不提供商品参考价值,因此不做「元/积分」性价比排名。
- 点餐/券/营养域已按官方文档(2026-10-21)对齐字段,但**未做真实网络联调**;`party-session.price` 与 `party-order-create.amount` 的单位仍待确认。
- **券接口不返回门槛与面额**:门店券只能判断适用性,券后金额必须由 `calculate-price` 计算;麦麦省与卡包是 Markdown 文本。
- **算价单位是分、下单单位是元**,代码已分别处理,调用时不要混用。
- 本 Skill 只影响对话与本地台账,**不能**替服务端做风控、库存或支付校验。
## 合规说明
- 本项目为麦当劳程序员节创意开发大赛参赛作品,由参赛者独立开发,**非麦当劳官方产品**。
- 项目输出仅供参考,不构成营养、医疗或投资建议;餐品信息、价格与供应状态以麦当劳官方渠道为准。
- 项目不含真实 Token、密钥、账号凭证或他人个人信息;配置文件仅使用环境变量占位符。
- 抽奖内容为娱乐性记录与流程协助,不承诺中奖,不鼓励追加投入,不构成任何赌博性引导。
## License
MIT
## MCti 互动体验
默认三轮情景题,也支持一次答完。每题覆盖不同偏好,八种人格都有明确计分依据;支持改答、跳题、打平认领和重测。结果卡引用真实答案,附专属宣言、娱乐搭配和积分建议。可继续生成分享文案或搭子互动,全程不自动查询账户或抽奖。
开发过程记录见 [`workbuddy.md`](./workbuddy.md)。
连接信息
猜你喜欢
暂无推荐服务器