Files
X-Financial/server/src/app/services/risk_rule_generation_prompt.py

177 lines
9.6 KiB
Python
Raw Normal View History

from __future__ import annotations
import json
from typing import Any
def build_risk_rule_compiler_messages(
*,
domain: str,
domain_label: str,
business_stage: str,
business_stage_label: str,
expense_category: str | None,
expense_category_label: str,
natural_language: str,
available_fields: list[dict[str, Any]],
) -> list[dict[str, str]]:
"""构造自然语言规则编译提示词。
大模型只负责把业务语言拆成语义计划后端会校验字段操作符和模板
"""
schema = {
"name": "规则名称,短句",
"description": "面向业务和审核人员的说明,不要写实现细节",
"template_key": "field_required_v1 | field_compare_v1 | keyword_match_v1 | composite_rule_v1",
"semantic_type": (
"可选。可用稳定英文短语描述语义类型;"
"已知差旅票据城市/路线一致性可使用 travel_route_city_consistency其他规则按业务含义命名"
),
"field_keys": ["只能选择 available_fields.key"],
"condition_summary": "用公式化语言描述判断依据,不要写'是否出现风险关键词'",
"rule_ir": {
"facts": "事实变量数组,例如 A=票据事实、B=业务申报事实、E=例外说明",
"conditions": "条件数组,必须能被人解释",
"hit_logic": "命中逻辑,例如 D AND ((A NOT_IN B) OR DATE_OUTSIDE(T,R)) AND NOT EXCEPTION(E)",
},
"conditions": [
{
"id": "稳定英文标识",
"operator": (
"exists_any | exists_all | in_scope | not_in_scope | overlap | "
"not_overlap | date_outside_range | contains_any | not_contains_any"
),
"fields": ["exists/contains 类操作使用"],
"left_fields": ["集合比较左侧字段"],
"right_fields": ["集合比较右侧字段"],
"date_fields": ["日期字段"],
"range_start_fields": ["日期范围开始字段"],
"range_end_fields": ["日期范围结束字段"],
"keywords": ["例外或风险词"],
}
],
"hit_logic": {"all": ["condition_id", {"any": ["condition_id"]}]},
"formula": "可执行逻辑公式,字段使用事实变量表达",
"message_template": "命中后的业务提示",
"unsupported_fields": ["用户规则提到但 available_fields 中暂时没有的字段"],
"keywords": "仅 keyword_match_v1 使用,且必须是真正风险词,不得把例外说明词当风险词",
"exception_keywords": "例外说明词,例如绕行、跨城办事、临时改签",
"risk_scoring_evidence": {
"impact_level": "low | medium | high | critical",
"violation_certainty": "low | medium | high | critical",
"evidence_strength": "low | medium | high | critical",
"exception_dependence": "low | medium | high | critical",
"control_action": "remind | supplement | manual_review | return | block",
"business_sensitivity": "low | medium | high | critical",
"reason": "用一句话说明这些评分证据来自哪些业务语义",
},
"flow": {
"start": "流程起点",
"evidence": "读取哪些事实",
"decision": "判断公式或分支条件",
"pass": "未命中时说明",
"fail": "命中时说明",
},
}
guardrails = [
"只能输出 JSON 对象,不能输出 Markdown 或解释。",
"必须区分业务环节:费用申请是事前风控,费用报销是事后核验;不要把二者的字段和流程语义混用。",
"费用申请阶段更关注预算余额、申请金额、申请事由、预计行程、预计费用科目、是否超预算或缺少前置审批。",
"费用报销阶段更关注真实票据、报销明细、发生日期、附件识别结果和申请/行程/票据一致性。",
"字段必须来自 available_fields不能编造字段。",
"多步骤规则要使用 composite_rule_v1先抽取事实变量再写 conditions 和 hit_logic不要压扁成单个关键词判断。",
"城市/地点/路线一致性必须用 field_compare_v1 或 semantic_type=travel_route_city_consistency。",
"涉及多个字段、日期范围、金额范围、集合关系、例外说明的规则必须使用 composite_rule_v1。",
"日期字段必须区分事实日期、票据日期和业务期间;如果只能拿到替代字段,要在 rule_ir 中说明这是 fallback evidence。",
"composite_rule_v1 只能使用受控 operatorexists_any、exists_all、in_scope、not_in_scope、overlap、not_overlap、date_outside_range、contains_any、not_contains_any。",
"差旅路线规则中,交通票行程城市和住宿发票城市属于附件城市集合。",
"申报目的地和明细发生地点属于申报行程城市集合。",
"员工常驻地/出发地如可用,属于合理起终点集合,不等同于申报目的地。",
"绕行、跨城办事、临时改签是例外说明证据,不是风险命中关键词。",
"如果票据路线出现申报目的地和常驻地之外的额外城市,应描述为中途周转/绕行异常。",
"keyword_match_v1 只用于品名、摘要、票据全文中出现明确风险词的规则。",
"不要直接指定 risk_level 或 risk_score只输出 risk_scoring_evidence后端会按固定评分模型计算 0-100 分和风险等级。",
"评分证据必须围绕六个指标:业务影响、违规确定性、证据强度、例外/规避空间、处置强度、场景敏感度。",
"若规则语义是可修复的低风险提醒,例如资料要素缺失但归属清晰、仅提醒/提示/补齐且不退回不阻断,则 impact_level 和 control_action 应保持低强度。",
"只有涉及造假、重复报销、金额超标、城市/日期不一致、禁止提交、退回修改、阻断或审计复核时,才应给 high 或 critical 的评分证据。",
]
examples = [
{
"user_rule": (
"差旅报销时,交通票或住宿票据中的城市均无法与申报目的地、"
"明细地点形成一致关系,且事由未说明绕行或改签原因,则高风险。"
),
"expected": {
"template_key": "field_compare_v1",
"semantic_type": "travel_route_city_consistency",
"field_keys": [
"attachment.route_cities",
"attachment.hotel_city",
"claim.location",
"item.item_location",
"employee.location",
"claim.reason",
"item.item_reason",
],
"condition_summary": (
"A=交通票行程城市住宿发票城市B=申报目的地∪明细发生地点,"
"C=员工常驻地/合理起终点A与B无交集且无合理说明或A中出现BC之外城市时命中。"
),
"keywords": [],
"exception_keywords": ["绕行", "跨城办事", "临时改签"],
},
},
{
"user_rule": (
"差旅报销时,票据已上传但发票号码或商品服务名称缺失,且报销事由、人员和部门"
"能够说明费用归属,则标记为低风险,仅提醒补齐票据要素。"
),
"expected": {
"template_key": "field_required_v1",
"field_keys": ["attachment.invoice_no", "attachment.goods_name", "claim.reason"],
"condition_summary": "票据要素缺失但费用归属清晰时,仅提示补齐。",
"risk_scoring_evidence": {
"impact_level": "low",
"violation_certainty": "medium",
"evidence_strength": "medium",
"exception_dependence": "low",
"control_action": "remind",
"business_sensitivity": "medium",
"reason": "命中后只做补齐提醒,不阻断、不退回,也不涉及舞弊或金额越权。",
},
},
}
]
return [
{
"role": "system",
"content": "\n".join(
[
"你是 X-Financial 风险规则语义编译器。",
"你的任务是把自然语言规则转换成可校验 JSON 语义计划。",
"后端执行器只接受受控模板和受控字段,所以你必须严格遵守以下约束:",
*[f"- {item}" for item in guardrails],
]
),
},
{
"role": "user",
"content": json.dumps(
{
"business_domain": domain,
"business_domain_label": domain_label,
"business_stage": business_stage,
"business_stage_label": business_stage_label,
"expense_category": expense_category,
"expense_category_label": expense_category_label,
"natural_language": natural_language,
"available_fields": available_fields,
"required_json_shape": schema,
"examples": examples,
},
ensure_ascii=False,
),
},
]