用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/18816132863/xiaoyi-claw-omega-final --skill diet-logging-claw命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | diet-logging-claw |
| description | 饮食记录、饮食打卡、记录饮食、记一下吃了什么、吃了XX。当用户用文字描述饮食内容时使用,解析食物/数量/单位,查询数据库匹配热量后自动打卡。 |
| metadata | {"pha":{"emoji":"🍱","category":"health-coaching-cli","tags":["cli","diet","food","logging","calories"],"requires":{"tools":"[Truncated]","skills":"[Truncated]"}}} |
处理用户的自然语言饮食录入,提取食物信息,通过 CLI 查询数据库匹配卡路里,自动打卡写入,并给出简短点评。
调用工具,不问用户。 缺失信息通过工具和推断解决,不通过提问解决:
| 缺失信息 | 解决方式 | 禁止做法 |
|---|---|---|
| 餐别 | 用户有说 → 直接取值;用户没说 → 按当前时间推断 | ❌ 问用户"这是哪顿饭" |
| 数量/单位 | 第二步规则推断 | ❌ 问用户"吃了多少" |
必须问用户的场景:
query_and_format_food 返回多个结果且用户输入的食物名不能精确锁定唯一选项(第五步A)对原始文本按优先级逐一判断,命中即停止,直接输出对应话术:
| 类型 | 判定逻辑 | 话术 |
|---|---|---|
| INFORMATION | 文本中找不到任何有效食物名词("一个"、"这个"、"记录一下"等占位符不算食物) | 话术·信息缺失 |
| TIME | 明确出现非当日日期词(昨天/前天/明天/具体旧日期);注意:早上/中午/晚上/刚刚默认当天,不触发 | 话术·时间异常 |
| UNIT | 单位违反物理常识(如"一公里米饭"、"50瓦特牛奶");热量单位(大卡/千焦)视为正常 | 话术·单位异常 |
| FIX | 以"不对"/"不是"/"改成"/"换成"/"其实是"/"记错了"等修正词开头,但当前消息中没有可被修改的食物记录(孤立修改指令) | 话术·孤立修改 |
| NA | 以上均未命中,进入第一步 | — |
注意:含有 INFORMATION 时,无论是否有时间词,强制输出话术·信息缺失,不继续判断 TIME。
话术·信息缺失(INFORMATION):
"你想记录什么食物呢?告诉我名称就好,比如'早上吃了一个包子'。"
话术·时间异常(TIME):
"我目前只支持记录今天的饮食哦。如果你想记今天吃的,告诉我就好~"
话术·单位异常(UNIT):
"这个单位好像有点奇怪,你是说[食物]吃了多少[合理单位]吗?比如一碗、一个、200克这样?"
话术·孤立修改(FIX):
"你想修改哪条记录呢?告诉我原来记了什么、要改成什么就行,比如'刚才记的包子,其实是三明治'。"
话术A(非食物生理状态):
"听起来你描述的是身体状态,不是饮食记录——我没法把这个记到你的饮食日志里。如果身体不舒服欢迎告诉我详情;如果想记今天吃了什么,告诉我食物名称就行。"
话术B(荒诞不可食用):
"哈哈,[用户说的内容] 确实不在我的食物数据库里……你今天实际上吃了什么?告诉我,我帮你记上。"
话术C(饮食咨询转接):
"这个问题更像是营养咨询——我来帮你查一下 [食物] 的热量信息:[直接给出简要信息]。如果你今天吃了它,告诉我数量,我可以帮你录入。"
| 意图类型 | 判断标准 | 处理方式 |
|---|---|---|
| ✅ 饮食录入 | 包含真实可食用食物 + 进食动词(吃/喝/尝/吞/含) | 进入槽位提取(第1.2节) |
| 🚫 非食物生理状态 | 描述身体状态/症状,非饮食行为("来了姨妈"、"拉肚子"、"发烧") | 话术A |
| 🚫 荒诞不可食用 | 明显不是食物("吃了拖拉机"、"喝了汽油") | 话术B |
| 🔀 饮食咨询 | 问某食物热量或营养,但没有明确录入意图 | 话术C |
| ✅ 已含热量 | 文字中含有明确卡路里数字("吃了一个200卡的包子") | 录入流程,打卡时 kilocalorie 优先使用用户给出的值 |
从原始文本中提取以下6个槽位,若无法从原文确定,严格填 NA,禁止推测:
| 槽位 | 说明 | NA 条件 |
|---|---|---|
meal | 餐别(6种之一) | 原文无时间/餐别信息 |
food | 食物名称,不含数量和单位 | — |
quantity | 数字或小数(中文数字转阿拉伯数字) | 原文无数量 |
unit | 单位(个/碗/克/ml…) | 可根据食物类型推测合理值 |
energy | 热量数值 | 原文无具体热量数字 |
energy_unit | 热量单位(如"大卡"/"千焦") | 无热量时同为 NA |
只从用户原文提取,未提及餐别/时间词 → meal = NA,禁止凭食物种类或系统时间猜测:
| 关键词 | 餐别 |
|---|---|
| 早上/早餐/早饭 | 早餐 |
| 上午茶/上午(非早餐语境) | 上午加餐 |
| 中午/午餐/午饭 | 午餐 |
| 下午/下午茶 | 下午加餐 |
| 晚上/晚餐/晚饭 | 晚餐 |
| 宵夜/夜宵/睡前/半夜 | 晚上加餐 |
meal=NA 时:按当前时间推断:
禁止以任何理由(食物内容、用餐习惯等)修改按时间算出的餐别
多餐别处理:用户输入涉及 N 个餐别 → 提取 N 组槽位,每组对应该餐别的所有食物。
food 中不能出现数量和单位("一个包子" → food=包子, quantity=1, unit=个)判定有修改意图的标志词:不对/不是/其实是/记错了/改成/换成/改一下/修改
food_extract)food_fix)规则A:food_fix 数量 >= 2 → 完全覆盖,以修改后食物为准,删除所有 food_extract
规则B:单个 food_fix 且明确
规则C:无 food_fix,只有 quantity/unit 修改 → 就近替换
规则D:其他模糊情况 → 根据上下文判断
槽位提取完成后,对数量/单位/热量缺失的食物补全合理值:
units 字段已预计算),无法从库获取时走第五步A流程意图确认为饮食录入后,并行对所有食物调用(多个食物同时搜索,不要一个一个来):
query_and_format_food --food-name "<food槽位值>"
返回结构:
not_found: true → 该食物不在数据库,无法打卡(进入第五步A,提示用户换个名称重新搜索)not_found: false → 有结果,每项结构:{
idx: number, // 1-based 序号
foodId: string,
name: string,
kcal_per_100g: number,
protein_per_100g: number,
fat_per_100g: number,
carbs_per_100g: number,
units: [{ unit, weight_g, kcal, protein, fat, carbs }] // 每单位预计算值
}
有了此结构,可直接用选中项的 units[i] 乘以 quantity 构建 Output3 的全部字段。
收到 query_and_format_food 结果后,用语义理解判断匹配质量。
用户说的食物和返回结果本质上是同一个东西,大多数人不会区分。靠常识判断,不是规则。
举例:
用户说的食物和返回结果存在实质差异,不同选项之间营养/口味/食材不同。
举例:
not_found: true → 提示用户换个名称重新搜索多食物场景:所有食物并行搜索完毕后,强匹配的先放一边,把所有弱匹配/无匹配的一次性展示给用户。
展示格式:
当 not_found: true:
没找到「[food]」,无法打卡。换个名称试试,或者告诉我更具体的叫法?
当有选项但弱匹配:
没找到完全匹配「[food]」的记录,以下是最接近的选项,请选择序号或重新描述:
1. 猪肉包子 — 1个 ≈80g / 200kcal
2. 素菜包 — 1个 ≈70g / 140kcal
3. 豆沙包 — 1个 ≈65g / 190kcal
也可以直接告诉我你吃的食物名称,我重新查询。
| 用户输入 | 处理方式 | 计入重试 |
|---|---|---|
| 有效序号(1-N) | 确认,进入第五步B | 否 |
| 描述了另一种食物 | 重新调用 query_and_format_food | +1 |
| 无效输入/序号越界 | 提示重新输入 | 否 |
| 已用完 3 次 | 话术D | — |
话术D:
"找了好几次都没能精确匹配,你方便告诉我这个食物大概多少卡吗?或者说一下大概重量,我来帮你估算。"
selectedUnit = query_and_format_food 结果中与 unit槽位 匹配的单位项(默认取 units[0])
intakeWeight = selectedUnit.weight_g x quantity
kilocalorie = selectedUnit.kcal x quantity
protein = selectedUnit.protein x quantity
fat = selectedUnit.fat x quantity
carbohydrate = selectedUnit.carbs x quantity (注意字段名转换: carbs → carbohydrate)
若用户已声明热量,以用户值覆盖 kilocalorie,其余营养素仍按比例计算。
log_food_entry \
--food-id "<output3.foodId>" \
--food-name "<output3.foodName>" \
--meal-type "<meal槽位值>" \
--count <output3.quantity> \
--unit "<output3.unit>" \
--intake-weight <output3.intakeWeight> \
--kilocalorie <output3.kilocalorie> \
--protein <output3.protein> \
--fat <output3.fat> \
--carbohydrate <output3.carbohydrate>
打卡成功(httpStatus=200)→ 进入第五步C。
打卡失败 → 告知用户:"记录写入失败,请稍后重试,或手动记录一下。"
get_nutrition --date today
此时服务端已持久化本次打卡,返回的 totalCalories 等字段已含本次摄入。将结果传入第六步生成点评。
整个流程中,除了以下两种情况,禁止输出任何文字:
搜索中、打卡中、查询营养中——一个字都不许说。
| 信息类型 | 来源 | 字段 |
|---|---|---|
| 本次食物名/数量/单位 | Output3 | foodName, quantity, unit |
| 本次热量/蛋白质/脂肪/碳水 | Output3 | kilocalorie, protein, fat, carbohydrate |
| 今日累计总热量 | get_nutrition | totalCalories |
| 今日累计蛋白质 | get_nutrition | protein(可选,有则用) |
| 今日累计脂肪 | get_nutrition | fat(可选,有则用) |
| 今日累计碳水 | get_nutrition | carbs(可选,有则用) |
禁止从
get_nutrition.meals中读取食物名——该字段结构为{time, calories},不含食物名称。
第1部分(本次记录,必选):
[meal] [foodName] [quantity][unit] ≈ [kilocalorie]kcal,含蛋白质 [protein]g、脂肪 [fat]g、碳水 [carbohydrate]g
第2部分(今日累计,必选):
今日累计 [totalCalories]kcal,蛋白质 [protein]g / 脂肪 [fat]g / 碳水 [carbs]g
- get_nutrition 返回 null 时省略此部分
- protein/fat/carbs 字段缺失时只显示热量
第3部分(点评,必选):结合餐别参考范围和今日累计给出一句具体点评
早餐 猪肉包子 2个 ≈ 352kcal,含蛋白质 13.6g、脂肪 9.6g、碳水 51.2g。今日累计 352kcal,蛋白质 13.6g / 脂肪 9.6g / 碳水 51.2g。早餐热量合理,可以再加杯牛奶补钙。
基于 SOC 职业分类