跳到主内容

从模糊需求到确定性输出:决策表式提示词实战 ​

问题背景:规则越复杂,自然语言提示词越容易失控 ​

在风控审批、订单履约、客服分流、营销资格判断等场景中,业务规则通常不是一句“如果……就……”能讲清楚的。它们往往包含多个条件组合、例外条款、优先级冲突和灰度策略。直接把这些规则写成大段自然语言提示词,LLM 虽然能理解大意,却容易在边界条件上自由发挥:有时漏看限制条件,有时自行补充常识,有时同一输入多次运行结论不一致。

典型现象是:业务方说“高价值客户可以放宽审核,但新注册账号除外,除非有白名单背书;如果命中风险标签还要转人工”。这类需求对人类专家不难,但对模型来说,条件之间存在嵌套、覆盖和冲突。若提示词只描述原则,没有规定判断顺序、命中规则和输出格式,结果就会变成“看起来合理,但无法验收”。

决策表式提示词的核心价值,是把隐性的专家判断改造成显式的条件矩阵:先规则化输入事实,再列出条件组合,随后绑定动作、理由和证据,最后要求模型按固定结构输出。它并不要求模型变聪明,而是减少模型需要临场决策的空间。

方案对比:自然语言、思维链与决策表提示词 ​

常见做法可以分为三类。

第一类是自然语言描述型提示词。优点是编写快,适合简单问答;缺点是规则一多就会出现顺序依赖和语义歧义。

第二类是思维链提示词,要求模型逐步分析。它能提升单步推理质量,但如果没有约束“依据哪些条件、按什么优先级判断”,模型可能推得很完整,却沿着错误前提前进。

第三类是决策表式提示词。它把业务规则整理成“条件列、规则行、动作列、优先级、兜底策略”,并要求模型只引用表中规则。思维链可以作为内部检查步骤,但最终输出必须映射到明确的规则编号。

模糊业务需求条款、例外、冲突抽取事实字段枚举值与缺失值构造决策表条件组合与动作结构化输出编号、理由、动作确定性结果与可评测样本回归测试可重复执行

决策表设计:把需求拆成条件、规则和动作 ​

设计决策表时,不要先写提示词,而要先完成需求规则化。建议按四步推进。

第一步,识别输入事实。每个事实都应是可观察、可赋值的字段,例如客户等级、账号注册天数、是否白名单、风险标签、订单金额。避免把“客户看起来可靠”这种主观描述交给模型判断。

第二步,规定字段取值。布尔字段使用 true/false,等级字段使用固定枚举,数值字段给出单位和比较阈值。缺失值必须显式表示为 unknown,不能让模型猜测。

第三步,整理规则行。每一行只表达一个条件组合,并给出唯一编号、动作和说明。存在冲突时设置优先级,例如风险规则优先于优惠规则,人工审核优先于自动通过。

第四步,定义兜底策略。没有任何规则命中时,是拒绝、转人工还是使用默认策略,必须写清楚。兜底不是模型自由裁量,而是表中的最后一行。

可复用提示词模板:规则编号必须可追溯 ​

下面模板可直接用于审批、资格判断、分流路由等任务。关键要求是:模型只能依据决策表判断;输出必须包含命中规则编号;若信息不足,只能返回 NEED_INFO,不能补全事实。

text
你是一个业务规则判断引擎。请严格根据【输入事实】和【决策表】输出结果。

【任务目标】
判断当前请求应执行的动作,并给出命中的规则编号与判断依据。

【强制要求】
1. 只能使用输入事实,不得根据常识猜测缺失字段。
2. 必须按 priority 从高到低评估规则。
3. 若多条规则同时命中,只返回 priority 数值最小的规则。
4. 若关键字段缺失,返回 decision="NEED_INFO",并列出缺失字段。
5. 若没有规则命中,执行 R999 兜底规则。
6. reason 只能引用输入字段和规则编号,不得输出表外政策。

【决策表】
R001 | priority=10 | risk_tag=true → MANUAL_REVIEW
R002 | priority=20 | customer_level="VIP" AND register_days>=30 AND risk_tag=false → APPROVE
R003 | priority=30 | whitelist=true AND risk_tag=false → APPROVE
R004 | priority=40 | register_days<7 AND whitelist=false → MANUAL_REVIEW
R005 | priority=50 | amount>=10000 AND risk_tag=false → MANUAL_REVIEW
R999 | priority=999 | 其他情况 → REJECT

【输出 JSON】
{
  "decision": "APPROVE | MANUAL_REVIEW | REJECT | NEED_INFO",
  "matched_rules": ["规则编号"],
  "missing_fields": ["字段名"],
  "reason": "基于哪些事实命中哪条规则",
  "confidence": 0.0
}

Python 示例:调用模型后再做一次确定性校验 ​

即使提示词要求 JSON 输出,也不要假设模型永远遵守。生产环境应增加 schema 校验和规则复核。下面示例展示了一个可运行的最小闭环:先用模拟 LLM 返回结构化结果,再用本地决策表验证其结论。真实项目中可把 fake_llm_call 替换为任意模型调用。

python
# 文件名:decision_table_demo.py
# 运行方式:python decision_table_demo.py
from typing import Dict, List, Any

# 使用元组表达条件:字段名、比较符、目标值
RULES = [
    {
        "id": "R001",
        "priority": 10,
        "conditions": [("risk_tag", "eq", True)],
        "decision": "MANUAL_REVIEW",
    },
    {
        "id": "R002",
        "priority": 20,
        "conditions": [
            ("customer_level", "eq", "VIP"),
            ("register_days", "gte", 30),
            ("risk_tag", "eq", False),
        ],
        "decision": "APPROVE",
    },
    {
        "id": "R003",
        "priority": 30,
        "conditions": [("whitelist", "eq", True), ("risk_tag", "eq", False)],
        "decision": "APPROVE",
    },
    {
        "id": "R004",
        "priority": 40,
        "conditions": [("register_days", "lt", 7), ("whitelist", "eq", False)],
        "decision": "MANUAL_REVIEW",
    },
    {
        "id": "R005",
        "priority": 50,
        "conditions": [("amount", "gte", 10000), ("risk_tag", "eq", False)],
        "decision": "MANUAL_REVIEW",
    },
]

FALLBACK = {"id": "R999", "priority": 999, "decision": "REJECT"}
REQUIRED_FIELDS = {"customer_level", "register_days", "whitelist", "risk_tag", "amount"}


def compare(actual: Any, op: str, expected: Any) -> bool:
    if op == "eq":
        return actual == expected
    if op == "gte":
        return actual >= expected
    if op == "lt":
        return actual < expected
    raise ValueError(f"不支持的比较符: {op}")


def evaluate(facts: Dict[str, Any]) -> Dict[str, Any]:
    missing = sorted(REQUIRED_FIELDS - set(facts))
    if missing:
        return {
            "decision": "NEED_INFO",
            "matched_rules": [],
            "missing_fields": missing,
            "reason": f"缺少关键字段:{','.join(missing)}",
            "confidence": 1.0,
        }

    matched: List[Dict[str, Any]] = []
    for rule in RULES:
        ok = all(compare(facts[field], op, expected) for field, op, expected in rule["conditions"])
        if ok:
            matched.append(rule)

    final_rule = sorted(matched, key=lambda x: x["priority"])[0] if matched else FALLBACK
    return {
        "decision": final_rule["decision"],
        "matched_rules": [final_rule["id"]],
        "missing_fields": [],
        "reason": f"按最高优先级命中 {final_rule['id']}",
        "confidence": 1.0,
    }


def fake_llm_call(facts: Dict[str, Any]) -> Dict[str, Any]:
    # 模拟模型偶尔返回错误结论,用于演示本地复核的重要性
    result = evaluate(facts)
    if facts.get("customer_level") == "VIP" and facts.get("risk_tag") is True:
        result["decision"] = "APPROVE"  # 故意制造错误:忽略 R001
    return result


def verify(llm_result: Dict[str, Any], facts: Dict[str, Any]) -> bool:
    expected = evaluate(facts)
    return (
        llm_result.get("decision") == expected["decision"]
        and llm_result.get("matched_rules") == expected["matched_rules"]
    )


if __name__ == "__main__":
    test_cases = [
        {"customer_level": "VIP", "register_days": 60, "whitelist": False, "risk_tag": False, "amount": 2000},
        {"customer_level": "VIP", "register_days": 60, "whitelist": False, "risk_tag": True, "amount": 2000},
        {"customer_level": "NORMAL", "register_days": 3, "whitelist": False, "risk_tag": False, "amount": 500},
    ]

    for index, facts in enumerate(test_cases, start=1):
        llm_result = fake_llm_call(facts)
        passed = verify(llm_result, facts)
        print(f"用例{index}:模型结论={llm_result['decision']},本地校验={'通过' if passed else '失败,应以规则引擎结果为准'}")

这个模式体现了一个重要原则:LLM 负责理解非标准输入和生成解释,确定性代码负责最终裁决。对于高风险业务,尤其不应让模型直接决定审批结果。

避坑总结:三类高频错误及修正方法 ​

第一,规则写成口号,缺少可判定字段。 常见错误提示词是“如果客户风险较高,就谨慎处理”。模型对“较高”“谨慎”的理解会随上下文变化。修正方法是把它们改成 risk_tag=true、risk_score>=80、decision=MANUAL_REVIEW 这类可计算表达,并统一枚举值。

第二,规则之间没有优先级,导致命中结果随机。 例如“VIP 自动通过”和“命中风险标签转人工”同时成立时,模型可能根据措辞强弱选择结果。修正方法是为每条规则增加 priority,并在提示词中明确“多条命中时只取最高优先级”。最好再用本地代码复核一次。

第三,缺失字段被模型自动补全。 输入没有说明是否白名单时,模型可能写成“假设用户不是白名单”。这会把信息缺失变成业务事实。修正方法是定义 unknown 或直接返回 NEED_INFO,并要求输出 missing_fields,由上游系统补齐后再判断。

第四,决策表没有兜底行和测试样例。 新规则上线后,未覆盖组合可能落入模型自由发挥区。修正方法是固定 R999 兜底规则,并为每条规则构造正反样例,对边界值如注册天数第 6、7、30 天和金额 9999、10000 做回归测试。

决策表式提示词不是让 LLM 放弃推理,而是把推理限制在可审计的业务空间内。当条件、动作、优先级和兜底策略都被明确写出,模糊需求才能转化为稳定、可测试、可追溯的确定性输出。

免责声明

本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。