基于CLIPS的可行烹饪食谱专家系统开发技术问询
CLIPS烹饪食谱专家系统开发问题解决指南
核心需求与现存问题
- 开发目标:基于CLIPS构建烹饪食谱专家系统,从库存食材及可制作食谱推理可行菜品,执行食谱时自动更新食材库存
- 现存技术问题:
- 无法根据是否执行制作动作(如
make_dough)为新生成食材设置available或feasible状态 - 无法对已存在的食材(如面团)进行数量累加,只能重复断言新实例
- 无法根据是否执行制作动作(如
- 附加需求:能否输出制作N公斤某食材的完整步骤、现有可用食材及需采购食材,怀疑此类反向推理需求更适合Prolog
代码问题修复方案
针对上述两个核心问题,修正后的代码如下,关键改动已标注:
(defrule at-start => (set-dynamic-constraint-checking TRUE) ) (deftemplate Ingredient (slot name) (slot quantityKg (type FLOAT) (default 0.0) (range 0.0 ?VARIABLE)) (slot status) ; 可选值:available/feasible ) (deftemplate DoAction (slot name) ; 记录需要执行的动作,如make_dough ) (defrule feasible_recipe_dough ?f0 <- (Ingredient (name flour) (quantityKg ?q0)) (test (>= ?q0 0.5)) ?f1 <- (Ingredient (name butter | oil) (quantityKg ?q1)) (test (>= ?q1 0.15)) => ; 消耗原材料 (modify ?f0 (quantityKg (- ?q0 0.5))) (modify ?f1 (quantityKg (- ?q1 0.15))) ; 修复问题1:根据是否存在DoAction事实设置status (bind ?s "feasible") (if (find-fact ((?a DoAction)) (eq ?a:name "make_dough")) then (bind ?s "available") ) ; 修复问题2:累加已有食材数量或断言新实例 (bind ?existing_dough (find-fact ((?d Ingredient)) (eq ?d:name "dough"))) (if ?existing_dough then (modify ?existing_dough (quantityKg (+ ?existing_dough:quantityKg 0.5)) (status ?s)) else (assert (Ingredient (name dough) (quantityKg 0.5) (status ?s))) ) ) (defrule feasible_recipe_tomato_sauce ?f0 <- (Ingredient (name tomato) (quantityKg ?q0)) (test (>= ?q0 0.5)) => (modify ?f0 (quantityKg (- ?q0 0.5))) ; 同样应用累加逻辑和status设置 (bind ?s "feasible") (if (find-fact ((?a DoAction)) (eq ?a:name "make_tomato_sauce")) then (bind ?s "available") ) (bind ?existing_sauce (find-fact ((?sauce Ingredient)) (eq ?sauce:name "tomatoSauce"))) (if ?existing_sauce then (modify ?existing_sauce (quantityKg (+ ?existing_sauce:quantityKg 0.5)) (status ?s)) else (assert (Ingredient (name tomatoSauce) (quantityKg 0.5) (status ?s))) ) ) (defrule feasible_recipe_pizza_margarita ?f0 <- (Ingredient (name dough) (quantityKg ?q0)) (test (>= ?q0 0.5)) ?f1 <- (Ingredient (name tomatoSauce) (quantityKg ?q1)) (test (>= ?q1 0.15)) ?f2 <- (Ingredient (name mozzarela) (quantityKg ?q2)) (test (>= ?q2 0.3)) => (modify ?f0 (quantityKg (- ?q0 0.5))) (modify ?f1 (quantityKg (- ?q1 0.15))) (modify ?f2 (quantityKg (- ?q2 0.3))) ; 披萨的累加逻辑 (bind ?s "feasible") (if (find-fact ((?a DoAction)) (eq ?a:name "make_pizza_margarita")) then (bind ?s "available") ) (bind ?existing_pizza (find-fact ((?p Ingredient)) (eq ?p:name "pizzaMargarita"))) (if ?existing_pizza then (modify ?existing_pizza (quantityKg (+ ?existing_pizza:quantityKg 0.75)) (status ?s)) else (assert (Ingredient (name pizzaMargarita) (quantityKg 0.75) (status ?s))) ) )
关键修复说明
- 状态设置逻辑:使用
find-fact函数查询工作内存中是否存在指定的DoAction事实,以此动态绑定status值。避免了原代码中直接在RHS使用模式匹配的语法错误。 - 食材数量累加:通过
find-fact检查目标食材是否已存在,存在则用modify更新数量,不存在则断言新实例,解决了重复生成实例的问题。
附加问题解答
制作N公斤食材的反向推理需求,Prolog确实因其逻辑编程范式更适合这类目标驱动的推理场景,但CLIPS也可以通过以下方式实现:
- 定义目标事实(如
(target (name pizzaMargarita) (quantityKg 2.0))) - 编写反向链规则:从目标食材倒推所需原料,计算现有库存与需求的缺口,递归处理需要制作的中间食材
- 记录推理路径,最终输出完整步骤、现有可用食材及需采购清单
不过相比之下,Prolog的回溯机制和逻辑查询语法会让这类实现更简洁直观。
内容的提问来源于stack exchange,提问作者B.Bocquet
相关产品推荐
相关产品推荐

