Files
airz-uniapp/docs/产品匹配规则开发契约.md
hujun e5406c23a6 fix: 修复匹配详情提示及公积金可选路径问题
修复匹配详情中“用户自填未经核验”等来源说明,清理未参与项的橙色注意提示,修正贷款统计口径文案;补充公积金完整可选路径提取逻辑,确保明确无额外时长要求的公积金分支可正确识别并通过。
2026-10-19 16:11:59 +08:00

424 lines
53 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 产品匹配规则开发契约
## 2026-10-15 最新增量:自填资质参考建议(本地未发布)
用户已授权必要的后端配套调整,覆盖下方“仅提示词”的旧边界:默认已填内容真实;未采集、模型不可见或精度不足的细项不补填、不阻断参考建议。职业类型和单位名称可外发,姓名、完整身份证、手机号仍排除。现有小程序填写、保存与回填不删减,线上和付费/真机复测继续暂缓。
新资质capture冻结profileAdvicePolicy=self-reported-profile-advice-v1,纳入目录/执行摘要及成功检查点绑定;无标记的历史目录、旧任务与报告保留原三态及missingFields非空语义。需求模式不启用。离线freeze新增末位显式opt-in参数,默认保持历史重建行为。
新策略条件仍为pass/fail/unknown,但所有missingFields必须为空。已完成unknown证据标为AI_CONDITION_NOT_ASSESSED,保留unknown,不阻断参考候选、不加分、不显示旧补填模板;待处理/超范围仍阻断。完整与或路径、引用、版本/摘要、数值及充分分支检查保持,明确不符仍fail。当前表单真实缺填/无效项仍由既有完整度体现;主报告improvements引用仅可对应真实缺填、无效或一致性问题。
标准比较在验证原规则后以self_reported副本执行,不伪造verified,原银行配置保留。未采集的标准细项缺失时标PROFILE_DETAIL_NOT_ASSESSED;当前字段缺填或异常不静默跳过。编译器固定“适用地区尚未核实。”且regionMode=unverified、regions=null时同样不阻断参考筛选,地区仍未核实,不标全国;其他配置提示和损坏配置仍拒绝或阻断。
新个人事实增加occupation(profession,100字符)与employer(50字符)文本白名单,主报告和条件共用引用,空白/超长/控制字符/HTML不外发。仅作不可信用户数据,禁止执行命令或据单位名猜未明示的身份资格;企业模式保持原外发边界。未采集性别不从证件推导,省份不猜城市,时长、金额、机构数等沿原粒度解释。
新策略unknown理由模板必须applicable=false、values=[];追加解释对未参与细项使用服务端固定说明,避免再次索要。报告、内部匹配项保存策略标记,原三态、存储与只读投影兼容,不重算旧报告。详细实现与验证见[资质参考建议调整](资质参考建议调整-20261015.md)。本轮6个后端运行文件、1份新增内存测试,未改产品原文/配置或小程序运行文件,未访问数据库/生产或调用真实模型。
## 2026-10-15 增量:仅加强资质评估提示词(本地未发布)
用户选择“只调整AI提示词”,小程序现有填写项、用户已填内容与回填保持。运行改动仅限ProductAiConditions的提示文字及AssessmentNeedsReport的system提示;不修改产品原文、事实白名单、输出结构、服务端校验、评分、分批或用量策略。
profileOnly=true的请求提示模型继续使用已有资质,不将本次申请金额、本次融资期限/贷款年限、本次资金用途、本笔新增贷款月供列为当前表单补填项或完整度不足依据。原产品约束仍须保留,不把未采集信息当零;复合条件按原与/或关系判断,明确不符仍fail,完整约束未确认仍unknown。unknown的missingFields沿用原非空结构,提示可写相关资料名称或核实事项,如“申请阶段负债核实依据”,不罗列未采集的具体申请字段;其他适用且确实缺失的资质仍保留。当前贷款月还款、当前信用卡使用额、有房不能分别代替完整银行月负债、近六个月均值、房产价值。
主报告待完善项只依原完整度缺失、无效项及一致性问题生成;固定理由正文若要求补填上述具体申请字段或断言未确认约束已满足,提示applicable=false并清空values,原绑定三态/引用规则保持。适用范围由已有冻结profileOnly标记控制,无该标记的需求模式不追加本段提示。已保存报告不重算;部署后重新构造的资质请求/重试使用新提示,成功批次检查点仍按既有规则复用。
这仅是模型提示约束,未增加服务端过滤或新的语义强制校验;现有unknown显示框架与“需补充”前缀保持。15项改动前后兼容核对及相关内存回归通过,但没有新的真实模型调用,不能认定模型已稳定遵守。证据D:/AAdesk/202609/airz-backups/profile-prompt-20261015。本轮未部署或重发小程序。
## 2026-10-15 增量:仅省份选择与地区事实冻结
当前填写页仅选择34省级地区,form.city存省份名称,显式provinceCode为六位省级代码,cityCode=null。新省份名称/代码须严格配对,不能同时提交具体城市;province_code仅冻结在评估版本,排除user_info写入列,不作表结构迁移。未带provinceCode的旧请求保持原五城推码及规范化摘要。历史版本不改写;编辑时已知城市转换为省份,未知旧地区须重选。
新目录regionFactsPolicy=region-label-v1冻结cityNames及provinceNames并计入catalogSnapshotId。cityCode可带冻结displayValue;provinceCode只表达所在省份,代码和输入名称不一致不外发。省份不能猜测城市/户籍/工作城市/申请地区/银行网点,缺具体城市仍unknown;不新增标准城市匹配的省级自动通过规则。旧目录不动态获得新省份事实或新标签,非法策略/名称映射拒绝。本轮零真实模型调用,不以本地输入回归冒充模型语义验收。
数据及生成入口见docs/data/city-options.json、scripts/generate-city-options.py;省级列表与历史城市回填数据分开使用。690项PHP、108项UTS、18项受控H5检查及微信29页编译通过,未部署、未验收持久化并发/真机/生产worker。证据D:/AAdesk/202609/airz-backups/city-options-20261015。
## 2026-10-15 明确充分分支与理由事实规范化(本地待发布)
新冻结目录带aiGroundingPolicy=product-ai-grounding-v1并纳入目录摘要。无标记的历史目录保留原条件解释与填值;未知标记拒绝,不能读历史报告时套用新行为。
仅从明示任选的硬条件eq原文中,保守提取独立、无附加要求的公积金分支为sufficientAlternatives。备注与尾句只允许空或当前已核对的纯路径固定说明;分号划分顶层时不拆内部顿号,圈号需每支完整同级,其他编号和嵌套括号歧义退回模型。带且关系、时长限制、否定或共同要求时不能把其中一个子条件升级为充分条件。当前实现是窄范围路径保护,不是通用自然语言规则编译器。
正向housingFund事实命中充分分支时,该模型条件必须pass且引用fact:housingFund;unknown、fail或缺少相关引用拒绝。服务端不自动改写供应商三态,不推导其他条件或整款产品通过;未命中不等于fail。批次中间证据副本可暂时移除新策略以建立未调用条件的unknown占位,但模型响应、成功检查点、最终报告均用原冻结目录重新验证,模型不能靠占位文字豁免检查。
理由保留模板固定正文,只规范有事实依据的填值:紧邻“月收入(信息)(为/是/冒号)”且无固定金额单位的槽中,裸数字必须等于引用的实际monthlyIncome,才补元;不能借用其他金额或猜万元换算。“你的/您的{X}符合……年龄要求/范围/条件”中的裸年龄或N岁规范为“年龄(N岁)”,数值必须直接等于所引实际age,已规范格式同样校验,不能借条件上下限作为用户年龄。固定单位槽与旧目录不改写,其他数值、单位、引用和三态检查保持。
622项相关内存检查及7批离线回放通过。旧目录判断/填值保持;新目录拦截原ID69矛盾。修正夹具通过合并与恢复并不等于新的真实模型评估,仍须验证新提示的真实返回后安排配套发布;本轮无新增模型调用、数据库访问或部署。
## 2026-10-15 待补资料不设固定条数上限(本地待发布)
按用户最新要求,customConditionJudgments的missingFields不再限制为最多4项。unknown至少提供1个相关资料名称,服务端保留完整列表;pass/fail仍必须为空。每项继续要求非空字符串、最多60字,不含控制字符或HTML;名称不得重复,列表须为连续下标数组。条件/产品绑定、版本/摘要、证据引用及三态校验保持,其他列表的既有限制不变。
模型提示同步取消固定条数。5项、6项及64项回归覆盖条件校验、报告解析和匹配理由展示,全部保留。第3次真实调用未改写的原始首批15条件+16模板已离线解析通过,5/6项待补资料及unknown判断均原样保留;没有新增模型调用或完成后6批评估。
本节覆盖下方“最多4项”“5项以上拒绝”的旧条数约定;尚未部署,不重写已发布报告或历史失败任务。已有模型响应整体大小/token预算仍沿用原有机制。
## 2026-10-15 不展示的绑定理由允许省略重复引用(本地待发布)
当理由已绑定有效条件(ruleId非空且存在最终条件证据)、conditionOutcome与该条件一致、applicable=false且values=[]时,允许evidenceRefs=[],复用关联条件已校验的证据。不补造引用、不替换判断,关闭的理由仍不展示,不影响准入、分数或排名。
实际展示的pass/fail理由,以及未绑定条件的pass/fail理由,仍至少引用一个白名单事实。即使理由不展示,已提供的非法/重复引用仍拒绝,版本/模板摘要、绑定结论和空填值等检查继续执行。unknown资料不足提示的既有口径保持,数值/单位和实际展示理由的填值检查不放宽。模型提示与此例外同步。
第2次真实评估未改写的首批响应15条件+16模板已通过本地离线解析,关联公积金证据与关闭理由保持;此项不代表后6批已完成、整轮真实语义验收通过或线上已生效。
## 2026-10-15 待补资料最多4项、年龄不叠加贷款期限(本地待发布)
自定义条件的 `missingFields` 在unknown时允许1—4个不重复的简短资料名称,pass/fail时仍必须为空;5项及以上继续拒绝。模型提示与服务端校验同步,保留所有合法返回项,不截断列表。
个人新资质评估(profileOnly=true)冻结目录时,对明确以年龄区间开头、含贷款年限/期限组合的手输年龄条件,只冻结该年龄区间为between条件,含上下界;不判断年龄加贷款年限。当前25款涉及优客分期18—65岁、润薪贷23—60岁、民易贷22—60岁。关联AI理由中的“年龄与贷款期限组合/年龄与贷款年限组合”同步改为“年龄要求”,避免宣称已经核对贷款期限。原产品行及完整原文保留;历史已冻结编译条件不在读取或重试时重新规范化,旧需求模式不应用该变换。分性别年龄条件保持原范围,不能合并为统一上下限。
模型提示明确区分或/与:任一完整可选分支满足即pass,其他可选分支未提供不影响已满足分支;分支内所有必需条件仍须满足。全部分支明确不满足才fail,资料不足且仍有可能满足才unknown。仅强化提示不等于真实模型语义验收通过,须另行复测。
## 2026-10-14 补充:三态显示真实匹配度(本地待发布)
符合条件、待核实和条件不符三态,报告/列表/详情/对比均展示冻结结果已有且通过校验的score,包括0%;旧score=null不补算或造分。“待确认”文案统一为“待核实”,硬条件缺失资料仍为“资料不足”。状态与匹配度独立展示,unknown/ineligible不进入候选rank、不因此获得申请准备入口,评分及排序规则保持。该约定覆盖下方旧阶段仅eligible显示百分比的口径。
报告匹配标签“查看更多产品”下方仅保留修改资料入口与“匹配度仅供参考,不代表获批概率”;重复统计、排序说明与次要报告信息移除,完整列表筛选及其他报告栏目保持。分析完成后默认进入本次已发布revision的matches栏目,处理中或失败不能因存在旧报告而跳转。本轮只改前端并完成本地验证,未部署;默认三款all分组及身份证年龄仍需下节后端配套。
## 2026-10-14 默认三款展示与身份证年龄(本地待发布)
两个匹配入口默认读取 `eligibility=all`,每页3款;先符合条件、再待核实、最后条件不符,同组按真实score降序、同分按产品ID升序。状态、分数和候选rank不改写;实际不足3款按已有数量展示,不生成虚构产品。旧eligible/ineligible/unknown分组及接口默认eligible保持兼容,all游标单独绑定分组与冻结结果。
新冻结目录带 `identityFactsPolicy=identity-age-v1`。个人评估从本人冻结输入中的有效身份证提取生日,按目录的上海业务日期计算周岁,校验18位校验码/生日并兼容15位号码;无效或未来生日不生成年龄。模型和公开报告只接收age整数事实,来源仍为self_reported,单位age;身份证号码不外发。自定义年龄条件及理由模板可引用 `fact:age`,报告展示“年龄:N 岁”。标准age_min/age_max列仍未启用,不新增表单字段或数据库列。
旧冻结目录没有该策略时保持原事实,重试/读取不补算年龄;用户需重新评估获取新年龄。此约定覆盖下方旧阶段“不能从身份证推导年龄/默认仅显示候选”的限制。本轮仅本地实现与验证,部署须配套4个后端库和小程序源码;不重算旧报告。
2026-09-30最新展示约定:按用户要求,当前六条产品使用正常业务名称及资料,前台/PDF不展示“演示、非真实”等环境标签;内部source reference、isDemo及containsDemoProducts继续保存,用于追溯既有产品。正式ID22—27已同步文案并增加版本,金融参数/条件不变,历史快照不改写。下文强制显示环境标签的表述仅作阶段记录,本次展示规则优先;部署状态和验证见[开发进度0.36](开发进度.md)。
## 2026-09-29 最新覆盖约定(inputVersion=3)
个人/企业信用融资恢复至2026-09-23 19:04需求扩展之前的采集范围:删除融资金额、融资期限、资金用途、其他用途说明;保留经营月数和原有身份/经营收入/资产负债/资料授权。提交使用inputVersion=3,结果仍为resultVersion=2,保留报告三栏、产品匹配、助手、PDF与行动入口。v3不生成需求事实或匹配规则,不把取消采集的字段列为“未提供/待核实”、补填项或完整度扣分项;产品自身额度、期限、利率和用途资料保留。其他真实缺失或来源未核验仍按既有规则处理。
资质匹配快照标记profileOnly=true并纳入摘要;编译产品规则时移除requestedAmountYuan、requestedTermMonths、purposeCode相关条件。新准备策略self-reported-profile-20260929-v2,个人11项/企业6项,不含需求条件项。旧输入1/2不再接受新建;保留旧报告解析分支仅供归档兼容。
已按用户授权在111.230.144.231/airz执行:删除报告161/229、关联会话151/219及2条日志;普通助手449及其2条日志保留,会员1个、产品6个保留。fa_user_info删除requested_amount、requested_term_months、purpose_code、purpose_detail四列;input_version、analysis_context属于必要版本和快照元数据,继续保留。两个触发器同步移除需求列校验,输入版本允许1/2/3,接口新建最低3。22张不相关表摘要一致,log_bin_trust_function_creators临时开启后恢复0。备份:D:/AAdesk/202609/airz-backups/restore-profile-20260929-180938/。
下文v2字段、用途字典、需求覆盖与旧保留历史约定为历史设计,不可据此恢复采集或重跑旧迁移;其他冻结、鉴权、幂等、三态、金额精度要求继续适用。
---
版本:1.4。日期:2026-09-30。关联PRODUCT-001、PRODUCT-002、PRODUCT-003。页面消费方式见[04—10方案](原型04-10页面改造与跳转方案.md),完整产品判定/快照/接口语义仍以[数据契约](需求与评估结果数据契约.md)第5节为准。
## 1. 本轮实现边界
后端新增 `application/common/library/ProductMatchRules.php`,引擎版本 `product-hard-rules-v1`,实现规范化硬规则列表校验、精确比较、来源门槛、三态合并和逐规则证据。`tests/product_match_rules.php` 64项内存测试通过;不初始化应用、不访问数据库/Redis/网络,正式worker可保持运行。
新增 `ProductPublication.php`,完成产品独立字段及JSON预检、按个人/企业编译规则,并接入后台Product模型的新增、修改及批量保存路径。73项编译测试、16项事务回滚模型测试和41项基础回归通过,原64项规则回归通过。
新增ProductMatching,已接入评估worker:冻结目录、确定性排序及理由生成,匹配结果与报告同事务落库;详见第7节。**匹配列表/详情读接口和04—10页面尚未完成**,单产品AI解释仍为not_requested。用户已明确允许本地产品库直接上架演示数据,本轮录入6条;名称和来源明确标识演示,不将其视为真实产品验收。
## 2. 上层实施门槛
1. 产品发布时校验独立金额/期限/利率范围、适用对象、地区代码/全国声明、用途依据、来源引用和有效期。regions=[]表示明确全国,null表示未配置;金额或期限为空不是无限制。
2. 由服务端编译器把独立字段及补充eligibility_rules映射为完整硬规则集合,必须包含本次需求金额、期限、用途、对象及地区适用性。没有合法发布预检的产品不得调用本模块后直接视为候选。
3. 省/市/区覆盖需使用可信地区树,不能用自由文本或盲目前缀猜测。本轮编译器复用AssessmentRecords::CITIES的5个城市代码,只支持明确全国或精确城市集合;省区代码、未支持城市拒绝发布。未实现全国行政区层级覆盖。
4. 只对已适用硬规则求值;不适用条件由上层确定性编译器处理,并保留not_applicable依据。当前不支持客户端when表达式、软评分、任意脚本或字符串SQL。
5. 事实映射器从本人冻结评估及经校验的外部结果构建facts。requiredSource=verified只能由真实有效外部证据满足,不能接收客户端/AI自报verified。尚无录入/API支撑的年龄、职业自由文本、流水等规则不在本版字段白名单中,发布前拒绝。
6. 首次执行在正式快照中冻结目录、规则全文、引擎版本、排序版本及证据来源;重试不读新产品或当前新规则。新增匹配阶段必须保留已有needs-report-v2快照读取分支,旧成功报告及已冻结无匹配报告不重算。
7. 产品集合不可用继续返回unavailable;合法执行且零候选才返回completed/0。非法产品配置使匹配failed,不能静默跳过后宣称完整结果。
8. 全部产品判定后,仅eligible按productId升序生成rank;score/scorePolicyVersion=null。每条理由由规则结果模板生成,AI只能解释已有依据。
## 3. 内部规则结构
以下是编译后的内部规则对象结构;独立字段对应的规则由服务端生成,不能原样填进补充条件覆盖产品额度或期限。`eligibility_rules.conditions`中的每条记录须加适用对象包装,完整录入格式见第6节。草稿仍兼容旧JSON;本轮不迁移/改写已有JSON,正式上架采用新增整体预检。
```json
[
{"id":"amount_range","field":"requestedAmountYuan","operator":"between","value":["10000.00","500000.00"],"requiredSource":"self_reported"},
{"id":"term_range","field":"requestedTermMonths","operator":"between","value":[6,36],"requiredSource":"self_reported"},
{"id":"purpose_allowed","field":"purposeCode","operator":"in","value":["education","daily_consumption"],"requiredSource":"self_reported"}
]
```
示例仅用于开发测试,不代表任何真实银行条件,也不是可直接发布的完整产品。validate/evaluate要求非空列表、最多50条;id在产品内唯一、以小写字母开头、最多48字符,仅字母数字下划线短横线。严格接受id/field/operator/value/requiredSource五个键,多键/少键均拒绝;规则版本由上层冻结并传入。
| 字段 | 内部类型/单位 | 支持操作符 |
| --- | --- | --- |
| requestedAmountYuan、monthlyIncome、annualRevenue、totalDebtBalance、monthlyLoanPayment、creditCardTotalLimit、creditCardUsedLimit | money/yuan;0.00—999999999.99两位小数字符串 | eq、in、gte、lte、between |
| requestedTermMonths、operatingMonths | integer/month;非负PHP整数 | 同上 |
| creditLoanCount、creditCardCount | integer/count;非负PHP整数 | 同上 |
| cityCode | region;六位代码字符串,实际行政区有效性由上层字典校验 | eq、in |
| applicantType | enum:personal/enterprise | eq、in |
| purposeCode | enum:首版用途字典中的稳定code | eq、in;actual=other始终unknown |
| socialSecurity、housingFund | enum:none/under_six_months/six_months_plus | eq、in |
| house、car | enum:yes/no | eq、in |
金额不接受float、科学计数法、三位小数、非规范前导零。整数不接受字符串、float、bool;运行模块支持0—4294967295,上层仍须执行具体字段业务上限。in要求1—50个不重复同类型值;between必须两个有序值,含上下边界。枚举不得使用范围运算。新增字段/枚举/操作符必须有版本化兼容和测试,不能运行时接受任意配置。
## 4. 事实、输出与错误
调用为 `ProductMatchRules::evaluate($rules, $facts, $productId, $ruleVersion)`。productId为正整数字符串;ruleVersion为1—64位字母数字点横线下划线字符串。facts结构:
```json
{
"requestedAmountYuan":{"value":"123456.78","source":"self_reported","observedAt":"2026-09-24T00:00:00Z"},
"requestedTermMonths":{"value":12,"source":"self_reported","observedAt":"2026-09-24T00:00:00Z"},
"purposeCode":{"value":"education","source":"self_reported","observedAt":"2026-09-24T00:00:00Z"}
}
```
结果为 `{eligibility,evidence}`,仅表示传入已适用条件集合的结果,未生成rank/score/推荐文案。先校验全部规则再求值,不在首个fail提前返回:有fail则ineligible,无fail有unknown则unknown,否则eligible。
每条证据包含evidenceId=`product:<productId>:rule:<ruleId>`、ruleId、ruleVersion、kind=hard、fieldRefs、operator、expected、actual、outcome、reasonCode、source、requiredSource、observedAt、valueType及unit。金额保持元字符串。source/observedAt在未知时为null,不冒充已核验来源或捏造观测时间;未被引用的额外身份字段不进入输出。该结构当前是内部camelCase对象,后续入库仍按已有契约显式映射snake_case,不直接绕过持久化校验。
| 情况 | outcome / reasonCode | 行为 |
| --- | --- | --- |
| 值缺失/null | unknown / FACT_MISSING | actual=null;不当0 |
| 值类型/枚举/精度非法 | unknown / FACT_INVALID | actual=null;原值不复制到证据或错误日志 |
| 来源未知或不满足verified要求 | unknown / SOURCE_INSUFFICIENT | 保留有效规范值及真实来源,不当已核验 |
| purposeCode=other | unknown / PURPOSE_REQUIRES_REVIEW | 不读取用途自由说明,不自动猜测 |
| 满足/不满足边界 | pass/fail / CONDITION_MET/CONDITION_NOT_MET | 保留预期值、实际值、类型、单位及规则引用 |
| 规则列表/字段/操作符/阈值/标识不合法 | 抛InvalidArgumentException,固定MATCH_RULES_INVALID | 上层转换为配置错误,不作为某用户条件不符 |
## 5. 当前验收与下一交付
64项覆盖金额上下界/一分钱误差/最大值/float拒绝、期限边界/类型、零值与缺失、fail优先但保留unknown、来源门槛、other用途、地区不从文本推断、证据产品隔离、确定性、无评分、身份字段排除、非法规则与列表大小等。
发布预检、字段编译、目录冻结/排序/理由及正式任务持久化已交付。匹配分页/详情与公共详情、03/04/05/06基础现已接通(第8节);下一步为07对比及09报告三栏;PRODUCT-003结构化编辑体验和真实产品录入仍待完成。演示产品联调不解除真实产品资料、外部核验和业务金标准验收的依赖。
## 6. 产品发布JSON与字段编译(本轮已实现)
### 6.1 完整格式
复用`fa_product.eligibility_rules`,不新增表或列。顶层严格要求version/source/purposes/conditions四个键,不接受旧rules或未知键。version为运营维护的正整数规则修订号;编译格式由`product-publication-v1`标识,产品行version独立由服务端递增。
下例只展示结构,来源是合成引用,**不能作为真实产品发布资料**。生产录入时必须替换为可核对的机构材料;程序只校验格式与完整性,不证明材料真实性。
```json
{
"version": 1,
"source": {
"publisher": "合成机构(仅限示例)",
"title": "额度、期限、利率、地区、用途及全部准入条件说明",
"reference": "fixture:test-only",
"checkedOn": "2026-09-24"
},
"purposes": {
"personal": ["education", "daily_consumption"],
"enterprise": ["working_capital"]
},
"conditions": [
{
"applicantTypes": ["personal"],
"rule": {
"id": "income_min",
"field": "monthlyIncome",
"operator": "gte",
"value": "8000.00",
"requiredSource": "self_reported"
}
}
]
}
```
此例对应object="1,2";个人产品只保留personal,企业产品只保留enterprise。purposes的键须恰好覆盖适用对象,每类至少一个来自当前需求字典的用途代码;other仍需人工核对,不会因此自动通过。conditions可以为[],不能为{};即使为空仍生成至少4条必要规则。最多44个补充条件,加上独立字段规则后每分支最多50条。
source为整份产品条件的共同来源:publisher为发布机构(最长100字)、title为资料标题(200字)、reference为可定位的公开文档链接或内部材料索引(500字)、checkedOn为实际核对日期且不得晚于发布日。引用必须覆盖独立字段、用途及全部补充条件,多份资料可由受控材料清单统一索引。不能存用户资料或私密链接令牌;后台不访问该地址,不把此声明当成用户事实的verified来源。
### 6.2 独立字段与规则
| 产品字段 | 发布要求 | 编译结果 |
| --- | --- | --- |
| product_name/product_type/bank_name | 必填,长度100/20/50以内 | 保留规范化公共字段 |
| object | 1个人、2企业或两者;不重复 | 每类独立规则分支,base_object严格eq该分支类型,错误选择分支不能通过 |
| amount_min/amount_max | 元的十进制字符串,0—999999999.99;有序且max大于0 | base_amount对requestedAmountYuan执行between,含边界,不拆额 |
| term_min_months/term_max_months | 1—9999整数月,有序 | base_term对requestedTermMonths执行between,不改期 |
| annual_rate_min/annual_rate_max | DECIMAL(7,4)年化百分比,有序且非负 | 四位小数字符串保留;不把利率本身当申请人准入条件 |
| valid_from/valid_until | 合法日期YYYY-MM-DD且有序;上架时结束日不得早于当天 | 含首尾日期;未来生效可维护,目录服务必须在执行日筛选,不能提前匹配 |
| regions | JSON数组;[]明确全国,null不合法;非空只能填现有城市代码字符串 | nationwide不要求用户城市;exact_city编译base_region/in,城市未知为unknown |
| operating_months_min | 可空;非空为0—9999整数且产品必须含企业对象 | 仅企业分支生成base_operating/gte;混合产品个人分支记录不适用依据 |
| age_min/age_max | 当前必须为空 | 尚无年龄事实采集,不从身份证或AI推断,含年龄硬条件拒绝发布 |
| eligibility_rules.purposes | 按对象分组、依据明确且代码合法 | base_purpose/in,未知/other不当满足 |
现有可用城市为440300深圳、440100广州、110100北京、310100上海、330100杭州,直接复用评估白名单;不是全量行政区字典。未来扩展省市区必须补可信树、版本和测试。
补充rule沿用第3节五键结构,每条外层必须恰含applicantTypes/rule。monthlyIncome/socialSecurity/housingFund只能用于个人,annualRevenue只能用于企业,其余共有事实可明确用于两类。operatingMonths复用独立列,补充条件不能重复指定;金额、期限、对象、地区、用途也禁止覆盖。自定义id全产品唯一,不得使用base_前缀。grade/condition/recommendation/deprecated等文本不执行规则,运营必须将所有硬条件完整结构化,不能只留在说明里。
### 6.3 模型写入与兼容
Product模型保存事务覆盖行锁、预检和写入;编辑合并锁定的最新记录与实际变更字段后验证,避免部分更新漏掉上架状态或使用旧值校验。新增version固定1,更新以最新version加1,不能从表单指定版本。默认后台add/edit/multi均使用模型save;multi任一条失败整批回滚。SQL/Db直写不触发模型事件,未来导入服务必须走模型或同一预检,不得当作发布接口。
草稿允许未齐资料和旧`{"version":1,"rules":[]}`。旧不完整上架产品再次编辑/上架会被拒绝,可先下架再补齐;下架不要求满足新增完整性门槛。不批量清理或自动下架现有数据。后台结构化编辑最新实现见第6.5节,原JSON文本框为历史状态。
compile(product,dictionary)不读当前时间,返回来源、字典、规范化范围、有效期、地区模式、两类规则及notApplicableByApplicantType。assertPublishable额外按传入日期检查过期和未来核对日期。全国声明由regionMode/regions/source保留,不生成空in;不适用记录包含ruleId和APPLICANT_TYPE_NOT_APPLICABLE,但尚未转换为正式报告证据。
上层ProductMatching已冻结原产品id/version/参数、编译结果及字典,校验上架状态/执行日有效性,按服务端申请类型选分支、建立事实并排序。不得仅因compile成功直接对外推荐,也不得在历史重试时使用新字典或新产品行。
### 6.4 前序发布预检验证记录
2026-09-24,PHP 7.4.3:`tests/product_publication.php`73项、`tests/product_publication_model.php`16项、`tests/product_match_rules.php`64项、`tests/finance.php`41项,共194项通过。覆盖必填/来源/用途/地区、精度/边界/过期、未知字段、覆盖及重复编号、混合对象/分支错用/不适用依据、来源门槛、50条上限、局部更新/旧模型/批量回滚/版本/旧品下架。
新模型测试及基础回归在事务内生成合成数据后回滚,测试Redis会话清理;产品前后全量记录比较一致。没有真实产品发布、数据库迁移、外部模型或生图调用。未修改模板或前端页面,未将模型路径测试描述为后台浏览器端到端验收。正式worker保持运行;本次脚本没有全库任务恢复扫描或评估任务入队。
### 6.5 结构化编辑及真实发布流程(2026-09-30本地完成)
新增/编辑共用表单:基本参数与有效期、待核实/全国/指定城市、个人/企业各自用途、source四字段及最多44条动态准入条件。新增默认待核实,SQL NULL表示尚未确认;全国必须明确选择并保存[];指定城市必须至少选择一个现有城市代码。NULL地区不是旧规则,但不能上架。补充字段来自既有白名单,数字支持eq/gte/lte/between/in,枚举支持eq/in;金额单位元、不转浮点,in数字集合逗号分隔,枚举多选。经营月数使用独立列,无年龄控件。条件编号保持稳定、全产品唯一、禁止base_前缀;切换字段/运算符保留各自已输入阈值,对象不一致明确提示并拒绝保存。
不支持的旧JSON、未知字段/用途/地区代码、错误JSON结构或年龄条件标为旧规则,普通保存保留原JSON和年龄。地区JSON文本null不等于SQL NULL,仍视为错误结构。已有来源单独提取,真正旧规则未重建时来源控件可见但禁用。运营明确勾选重建后才替换地区/来源/用途/条件,并清除旧年龄;无自动推断或迁移。来源/用途/条件实质变化递增规则JSON版本,选择顺序变化或单纯地区编辑不增加此版本;产品行版本每次保存仍递增。草稿允许空来源或用途,上架必须完整;空阈值或非法条件不能被静默丢弃。
POST后台product/preview只读预检当前表单,不修改产品/版本或上架;复用product/add或product/edit权限并检查数据范围。资料检查失败使用FastAdmin code=0,data.issues为[{field,message}],一次收集独立字段缺失/格式/范围/日期/用途及逐条条件问题;可选经营月数空值不列为必填。格式错误的诊断候选只在内存中使用,不能作为保存或上架输入;无问题时仍调用原完整编译器。版本冲突先拒绝预检,不拿旧版本生成通过回执。后台add/edit固定走结构化映射,编辑提交_base_version;服务端事务内锁定最新行核对,冲突拒绝整次写入,不能删除隐藏标记绕过。上架/下架按钮复用product/multi权限和模型,确认后整批事务,任一不完整产品导致全批回滚。无需新增数据库字段或权限节点。
真实发布顺序:运营提供实际机构材料和责任人 → 核对参数、城市/全国、用途、全部硬条件、有效期与来源索引 → 保存草稿 → 只读发布检查 → 人工核对来源并在获得发布授权后上架 → 用人工金标准验证三态及来源门槛。检查通过只证明格式与完整性,不访问来源地址、不证明真实有效,也不代表银行审批。材料不能包含用户身份资料或私密链接令牌;禁止将演示参数改名当真实产品。
代码在ProductEditor、admin Product控制器/模型、product/form.html及backend/product.js。本轮326项PHP、89项本机HTTP/浏览器检查通过,桌面/手机尺寸均无新增console/pageerror;正式产品材料、生产部署、真机与业务金标准仍待完成。
后续待核实与诊断改进:450项PHP、89项HTTP/浏览器、7项清理/完整性检查通过,四条真实公开材料仅存隔离库草稿。具体证据见开发进度0.33节;尚未部署,仍需受理银行确认当前政策和完整硬条件。
## 7. 目录冻结、结果持久化与本地演示产品(最新)
### 7.1 执行版本与冻结边界
新执行引擎`needs-report-v2-match-v1`仍输出resultVersion=2;规则执行器`product-matching-v1`、排序`product-id-ascending-v1`。首次worker抢占后、模型调用前,在评估事务内从产品表单次读取switch=1记录,编译并按Asia/Shanghai业务日期(含有效期首尾)筛选有效产品和申请主体,数字产品ID升序冻结。草稿/下架不读;已上架配置损坏使任务失败,不跳过后宣称完整匹配。已上架产品先完整校验再筛有效期,过期旧品有配置错误时也应下架或修复。
执行快照的productCatalog包含目录版本、排序版本、申请主体、evaluatedAt/businessDate、rulesPublished、每项产品ID/版本/参数白名单/编译结果、完整冻结字典和catalogSnapshotId。ID为规范化内容SHA-256;执行快照沿用executionHash/contentHash校验。最多100条上架记录、目录正文最多2MiB,SQL取101条探测超限;超限MATCH_CATALOG_LIMIT,绝不截断。仅纳入某主体的产品形成该评估目录,非该主体不生成“不符合”记录。
旧引擎needs-report-v2已冻结的unavailable报告和失败任务保留旧语义;新任务的目录为空、开关关闭或已有目录均冻结,重试不因产品更新/下架/过期/开关变化改读新目录。产品修订只影响新评估。配置`matching.enabled`默认开启;关闭仅影响未冻结的新评估,reasonCode=MATCH_RULES_UNPUBLISHED。
### 7.2 事实、判定与存储
事实只从服务端只读评估行按白名单映射,金额保持元字符串、整数严格转换、observedAt来自submitted_at。姓名/手机号/身份证/企业名/职业自由文本及客户端source不进入匹配事实。外部核验尚未接入,所以本轮事实来源全部self_reported;产品要求verified时返回unknown,不捏造核验结论。城市有效性使用冻结字典。
全部适用条件执行后fail优先于unknown。按产品ID升序,仅eligible生成连续rank;其他rank=null,全部score/scorePolicyVersion=null。not_applicable记录规则ID、产品版本依据和product_snapshot来源;不因不适用条件要求补填。正向、阻断和待核实理由分别从每条证据模板生成,完整保留、不凑数量;产品级evidenceRefs禁止互相借用。单产品AI解释当前not_requested,DeepSeek只整理自填报告事实,不作匹配决策。
结果由ProductMatching::storage显式映射嵌套键名,match_result保持有序snake_case数组,冻结产品参数、来源、材料/说明、规则和采集/更新时间。Assessment::complete对v2复算冻结结果并核对完整数组及matching统计,支持合法null rank/score;报告、结果、任务成功及日志在同一事务完成,禁止部分成功。v1写入格式保留。
无适用目录:unavailable、计数null;规则完成但无人符合:completed、candidateCount=0,其他两类仍按实际计数。配置错误MATCH_CONFIGURATION_INVALID、快照损坏MATCH_SNAPSHOT_INVALID通过失败状态反馈,不归咎用户。正式报告提供matchingMessage及containsDemoProducts,前端报告适配器显示实际统计;旧报告没有新文案时继续原提示。
### 7.3 本地录入的6条产品
用户明确授权在当前无用户使用的项目内直接录入并上架,替代此前“仅测试目录”的约束。来源文件为后端`database/demo_products.json`;`database/seed_demo_products.php`默认预检,`--apply`写入本机MySQL。脚本限制localhost连接、事务写入并用来源引用识别已存在记录;再次执行只保留,不覆盖运营修改。
| 本地ID | 名称(均带【演示】) | 对象 | 额度(万元) | 期限(月) | 核心演示条件 |
| --- | --- | --- | --- | --- | --- |
| 22 | 个人灵活消费 | 个人 | 1—30 | 3—36 | 全国;月收入≥0.3万元 |
| 23 | 个人小额周转 | 个人 | 1—8 | 3—24 | 深圳/广州;月收入≥0.5万元 |
| 24 | 个人收入核验 | 个人 | 2—50 | 6—60 | 全国;月收入≥0.8万元且需核验依据 |
| 25 | 企业初创周转 | 企业 | 5—50 | 3—36 | 全国;年营收≥10万元;经营0个月可参与判断 |
| 26 | 企业成长经营 | 企业 | 20—300 | 12—60 | 深圳/广州/杭州;年营收≥100万元、经营≥24个月 |
| 27 | 个人企业基础融资 | 两者 | 1—100 | 3—60 | 全国;主体分支用途分别编译 |
以上全部为合成参数,年化范围3.6%—12%,有效期2026-09-24至2030-12-31;数据库存元,表格显示万元。来源reference以`demo:airz-local-products-v1:`开头,报告/快照标演示。不存在真实银行对应关系、渠道授信或实际申请承诺。演示产品可在后台下架;已有报告保留其历史快照。投用前须替换真实资料并下架演示产品,不能只改名称去掉标识。
### 7.4 验证入口
`tests/product_matching.php`纯内存验证目录筛选、冻结摘要、排序、理由引用、来源门槛和配置失败;`tests/product_matching_tasks.php --worker-stopped`使用本地演示目录及随机合成账户/假模型验证正式提交、落库、重试、旧引擎、损坏快照和归属。后者预期6条初始演示参数;运营修改后需要同步业务金标准,不能自动覆盖产品凑测试。测试结束只清理本次账户/评估/会话/队列,6条演示产品按用户要求保留。
本阶段之后的匹配只读API及页面进展见第8节;单产品AI解释、公共产品列表、07—10扩展和真实产品验收仍待完成。
## 8. 匹配读取与页面消费(2026-09-24已实现)
### 8.1 接口、鉴权与分页
统一前缀`/api/v1`,全部要求`Authorization: Bearer <token>`,响应沿用`{code,msg,time,data}`并禁止缓存。以下GET只读,不创建评估、调用DeepSeek或重新计算匹配;重复读取只可能更新当前可用性。
| 方法和路径 | 参数/类型 | 响应data | 关键错误 |
| --- | --- | --- | --- |
| GET /assessments/:id/matches | id正整数字符串;eligibility为eligible/ineligible/unknown,默认eligible;limit查询字符串1—50,默认3;cursor可省略/空字符串 | assessmentId:string、resultVersion:number、matching、items:MatchResult[]、hasMore:boolean、nextCursor:string/null | 401未登录;404非本人/软删除/ID无效;409报告未完成/格式不可用/匹配损坏;422参数/游标错误 |
| GET /assessments/:id/matches/:productId | 两ID均为正整数字符串,无请求体 | assessmentId、resultVersion、matching、item:MatchResult | 404 MATCH_NOT_FOUND表示不在本次快照;其他鉴权/状态错误同列表;不回退公共详情 |
| GET /products/:id | 当前产品ID;无个人评估参数 | 当前公共Product DTO及rulesByApplicantType | 401未登录;404 PRODUCT_NOT_FOUND表示未发布/不在有效期/不存在;409 PRODUCT_CONFIGURATION_INVALID表示发布资料损坏 |
列表拒绝未知查询字段、数组参数和非法limit。先验证所有者,再解析游标,不泄露他人评估是否有匹配结果。游标使用既有AES-GCM加密方案,绑定userId、assessmentId、resultVersion、冻结结果摘要、eligibility及offset;不是页码,不由前端拼接,换组必须丢弃。结果更改、跨评估、跨组或篡改返回422 `MATCH_CURSOR_INVALID`,客户端从首屏重读。当前产品状态不进入摘要,产品下架不会令分页失效。
已匹配但无符合项时`status=completed,candidateCount=0`;未执行时`status=unavailable`、三组统计为null、items空数组,均返回200。v1成功报告返回`LEGACY_INPUT`;既有v2未匹配报告不补算。损坏的匹配列表、重复产品、非法rank/score、统计不一致或错误证据引用返回409 `MATCH_RESULT_UNAVAILABLE`,不以空数组掩盖损坏。
未执行匹配的data示例(ID仅为示意):
```json
{
"assessmentId": "100",
"resultVersion": 1,
"matching": {
"status": "unavailable", "reasonCode": "LEGACY_INPUT",
"ruleVersion": null, "orderingPolicyVersion": null, "catalogSnapshotId": null,
"candidateCount": null, "ineligibleCount": null, "unknownCount": null
},
"items": [], "hasMore": false, "nextCursor": null
}
```
### 8.2 字段投影、金额与历史
MatchResult沿用数据契约第5节:productId、productVersion、eligibility、rank、score、scorePolicyVersion、reasons、positiveReasons、blockingReasons、cautions、evidence、aiExplanation、productSnapshot,新增实时读取的currentAvailability(available/unavailable/unknown)。score无已发布评分策略时为null;rank仅eligible有值,不能渲染成百分比或审批概率。所有理由/evidenceRefs只关联本项证据;接口显式投影字段,不返回analysis_context、姓名、证件号码或未声明内部字段。
productSnapshot包含产品ID/版本/名称/机构/类型,amountMinYuan、amountMaxYuan(元的两位小数字符串)、termMinMonths/termMaxMonths(整数月)、annualRateMinPercent/annualRateMaxPercent(百分数字符串)、isDemo、applicantTypes、regions(空数组表示全国)、validFrom/validUntil(日期)、capturedAt、source(publisher/title/reference/checkedOn)、rules、information/condition及创建/更新时间。客户端仅在显示时转万元,例如`"123456.78"`元显示`12.345678 万元`;个人事实金额也按此规则。
公共DTO使用当前发布条件rulesByApplicantType按主体分组,不返回eligibility、rank、score、个人理由/事实/证据。repaymentMethod、channel、approvalDuration在两种产品DTO均为null,当前页面显示“未提供”;不得从演示或自由文本猜值。公共详情保留;GET /products当前列表实现见8.4节。
当前可用性通过一次受限ID集合查询读取,避免逐项查询。下架、删除、未到生效日或过期为unavailable;目录查询异常为unknown;历史快照仍可读。不会把产品当前版本/额度拼回历史详情。AI解释目前not_requested,前端明确提示尚未生成,保留完整确定性规则理由;失败时的提示分支已预留,真实生成与计费/重试待后续任务。
### 8.3 页面与验收边界
报告入口携带assessmentId;列表三组统计与分页来自同次结果;卡片只预览最多三条主要理由,详情保留全部不符/待核实理由,已满足项可展开。无评估编号时选择历史或重新评估;非法编号明确错误,绝不读取最近结果。详情无assessmentId只展示公共资料,有assessmentId始终读取本人快照。页面离开清空结果,响应返回时校验当前Token和请求序号,防止旧账户迟到响应恢复界面。
本轮`tests/match_records.php --worker-stopped`62项验证接口身份/方法、三组、游标分页和篡改、快照归属、未知键投影、损坏数据、下架/过期/删除/改价后历史、旧版报告、重复读取无副作用。产品变化只在测试连接事务内发生并回滚,随机账户及队列清理;停止正式worker以避免恢复扫描拾取合成评估。浏览器结果及截图见开发进度6.13。
### 8.4 当前公共产品列表(2026-09-30本地完成)
GET /api/v1/products要求会员Bearer,返回code/msg/time/data,data为items、nextCursor(末页null)与asOfDate(Asia/Shanghai业务日期)。items复用第8.2节公共Product DTO及现有详情投影,无个人事实/三态/评分/排名。不新增小程序列表页面,本阶段用于目录服务和后续页面接入。
| 参数 | 规则 |
| --- | --- |
| type | 可空;personal或enterprise,按产品适用对象过滤 |
| cityCode | 可空;现有5城市代码,匹配全国或明确含该城市的产品 |
| q | 可空;产品名或机构名,最长100字,拒绝控制字符;%和_按字面查询 |
| limit | 默认20;1—50的字符串整数 |
| cursor | 服务端返回的不透明游标,长度不超过2048;不能自行拼接 |
ID升序keyset分页,一次查询整页及下一项,不逐项查询详情。只读当前有效上架产品;草稿、下架、未生效或过期不返回。列表不是冻结历史,分页期间目录可能变化,从首屏重读才能获取最新集合。游标使用既有AES-GCM,绑定会员、全部筛选(包括limit)及业务日期;跨账号、换条件、跨天或篡改返回400 PRODUCT_CURSOR_INVALID。参数不合法422 VALIDATION_ERROR、未登录401、命中的发布资料损坏409 PRODUCT_CONFIGURATION_INVALID;不将损坏目录伪装为零产品。所有响应no-store,既有GET /products/:id DTO保持一致。
## 9. 单产品解释任务与原型04/05(2026-09-28已实现,覆盖第7/8节的未接入状态)
### 9.1 接口与状态
`POST /api/v1/assessments/:id/matches/:productId/explanation`要求会员Bearer Token、本人成功且未删除评估及该产品冻结结果,Content-Type为application/json。请求只允许`{"requestId":"explanation_20260928_001"}`;requestId为8—64位ASCII字母/数字/下划线/短横线,无金额或模型参数。重复读取GET不生成解释。
HTTP200沿用`{code:1,msg,time,data}`,data与匹配详情相同,不表示模型已经完成;客户端检查item.aiExplanation.status。queued/running期间轮询原GET匹配详情。例:
```json
{
"status": "completed",
"text": "该项信息来自自填资料,仍需核对证明材料。",
"evidenceRefs": ["product:22:rule:base_amount"],
"reasonExplanations": [{
"reasonId": "product:22:rule:base_amount:reason",
"text": "该项信息来自自填资料,仍需核对证明材料。",
"evidenceRefs": ["product:22:rule:base_amount"]
}],
"generatedAt": "2026-09-28T07:07:00+00:00",
"errorCode": null,
"canRetry": false
}
```
上例只说明结构,不是完整产品样例。text/evidenceRefs兼容已有消费者;逐条渲染使用reasonExplanations,数值/来源仍取确定性证据,不能从模型文本反解析金额。首次not_requested;queued/running保留空文本/数组;失败为failed,errorCode仅固定错误码,canRetry表示未超过三次上限;成功为completed并带生成时间。有效的旧not_requested对象缺新增字段时,前端按空值兼容。
| HTTP/错误 | 含义与行为 |
| --- | --- |
| 401 AUTH_REQUIRED | 会话失效;客户端清理并回登录 |
| 404 ASSESSMENT_NOT_FOUND / MATCH_NOT_FOUND | 非本人、已删记录或产品不在本次快照;不回退公共产品 |
| 409 REPORT_NOT_READY / MATCH_RESULT_UNAVAILABLE | 报告未成功或存储结构损坏,不调用模型 |
| 422 VALIDATION_ERROR | 非法requestId或多余请求字段 |
| 503 ANALYSIS_NOT_CONFIGURED | 模型服务未配置,不预留新调用 |
| 429 AI_DAILY_LIMIT | 与报告共用当日用户预留额度,开发默认二十次 |
| 409 AI_ATTEMPT_LIMIT | 每评估每产品最多三次尝试,不再创建任务 |
模型/网络失败写入状态,不使用供应商异常正文:AI_TIMEOUT、AI_NETWORK、AI_AUTH、AI_CONFIGURATION、AI_BALANCE、AI_RATE_LIMIT、AI_PROVIDER_ERROR、AI_INVALID_RESPONSE、AI_INVALID_REPORT、AI_TASK_INTERRUPTED等。用户可读状态与规则理由仍保留;不自动重新调用收费模型。
### 9.2 持久化、幂等和恢复
- fa_ai_chat.match_result中的单项ai_explanation保存状态、reason_explanations及生成时间;内部还保存task_id/request_keys/attempts/lease_until。只更新这一个对象,不修改冻结参数、证据、判定、排序、报告或评估生命周期。不同产品更新同一JSON时使用会话行锁,防止相互覆盖。
- fa_ai_chat_log使用role=assistant、request_id前缀`pex:`、pending/streaming/completed/failed以及已存在的模型/Token/耗时/错误字段。用户行锁串行预算预留;会话锁串行序号和快照写入。数据库事务原子保存任务和快照状态,不新增业务表/索引/迁移。
- 相同requestId重放返回当前状态;queued/running期间不同键也合并为同一任务;成功后不同键返回历史解释。明确failed后用户使用新键重试,最多三次。次数包含失败和不确定超时,防止无限收费。
- analysis:work继续优先处理既有报告队列,空闲时领取一条持久解释日志;pending任务无需Redis投递,进程重启不会丢失。租约为max(180秒,供应商超时+60秒),streaming过期改失败;`--recover-only`也回收解释租约,不调用模型。服务停机期间queued保持等待,恢复进程后继续消费。
- 多worker用日志状态和会话锁只允许一次领取。迟到回复不得回写已失效任务,已发生用量仍补记原日志。删除评估/禁用账户后不保存成功解释。运营需关注pending积压、失败错误码和调用用量;当前未实现独立解释后台管理页。
- 分页摘要排除ai_explanation,解释生成不使产品分页失效;其他冻结字段仍参与摘要并校验。部署时已有旧摘要游标可收到一次MATCH_CURSOR_INVALID,重新从首屏读取即可,不改历史报告。
### 9.3 模型边界与页面
使用已配置deepseek-v4-flash-0731,只发该产品规则理由、字段白名单、actual/expected/source/outcome,不发送姓名、电话、证件、附件、机构说明自由文本或完整报告。模型输出仅reasons数组,每项reasonId/text;按ID集合检验恰好覆盖所有理由,无重复、遗漏和外来ID,恢复规则顺序后由服务端附原证据引用。每条最多九十字,数字/金额/期限/HTML/明显授信承诺等拦截。确定性校验不能替代真实产品人工语义金标准,正式机构资料仍待验收。
页面生成期间可离开,重新打开读取保存状态;每三秒查询、最多六十次,断网/轮询结束提供手动查询,不重提任务。页面离开清理个人数据和计时器;迟到回包校验Token/请求序号/可见性。初始依据、AI解释失败、已保存解释可区分;已有数值仍以万元精确展示。布局与有意差异见原型方案第8节。
验证入口:`php tests/product_explanations.php --worker-stopped`(51项,假模型);可选`--live`额外调用一次真实Flash。`php tests/match_records.php --worker-stopped`更新为70项,含解释POST方法、归属、参数、删除记录和幂等回执。必须先停止worker,测试仅清理其随机账号/日志/评估/队列。真实模型和浏览器验证记录见开发进度6.18。