Archived
feat(w05): S2 配方 —— AI 唯一一次出场,行由字典决定不由它决定
明细按类型字典 each 出来,AI 的出参只是拿参数名去 lookup 的一张查表: 它漏一条,那一行的四态就是空,required 立刻变成 _missing > 0,闸与放行门当场拦住。 从前是 from each(AI 出参) —— 少给两条就少两行,而每一行看着都合规。 值一律 lookup 台账,一个字不让它重述;推荐等级、风险、摘要、理由全由规则与模板拼。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -305,7 +305,208 @@ export const ASSESSMENT_STEPS = [
|
||||
doneWhen:
|
||||
'substitution_difference_item_rows > 0 and substitution_difference_item_missing = 0 and ' +
|
||||
'substitution_relation_rows = 1 and validation_record_rows = 1',
|
||||
auto: { do: [{ kind: 'say' as const, text: '正在逐条比对两颗料的核心参数。' }] },
|
||||
auto: {
|
||||
/** **为什么不用 `{in:'chip_type_id'}`**:这个名字在三张表上都有,顶层同名以后写的赢 —— 拿它取值等于赌哪张表最后写。改成对准一张表 `lookup`,不歧义。 */
|
||||
let: {
|
||||
evalRef: { lookup: 'mine:sub_eval.case', by: {}, take: 'eval_ref', else: '' },
|
||||
typeId: { lookup: 'mine:sub_eval.case', by: {}, take: 'chip_type_id', else: '' },
|
||||
originalPn: { lookup: 'mine:sub_eval.part', by: { role: 'original' }, take: 'internal_pn', else: '' },
|
||||
candidatePn: { lookup: 'mine:sub_eval.part', by: { role: 'candidate' }, take: 'internal_pn', else: '' },
|
||||
relationId: { cat: ['SUB-', { lookup: 'mine:sub_eval.case', by: {}, take: 'eval_ref', else: '' }] },
|
||||
},
|
||||
do: [
|
||||
/*
|
||||
* ① **整个活动唯一一次模型调用**。系统把两颗料在该类型下的每一条核心参数
|
||||
* 组装好交给它,它只答「这一条算什么、为什么」——**不给工具、不给记忆、不多轮**。
|
||||
*/
|
||||
{
|
||||
kind: 'analyze' as const,
|
||||
model: 'deepseek-v4-flash',
|
||||
into: 'items',
|
||||
instruction: [
|
||||
'你在做芯片替代的**逐参数差异判定**。输入是一组核心参数,每一条给了:参数名、这个参数为什么要紧(说明)、',
|
||||
'硬约束还是软约束、单位,以及原料与候选料各自的值和值的备注。',
|
||||
'',
|
||||
'对**每一条**给出四态之一:',
|
||||
'· match —— 候选满足原料在这个参数上的要求(相等,或候选的范围盖住原料的范围);',
|
||||
'· mismatch —— 候选达不到(范围更窄、方向相反、量级不足);',
|
||||
'· unknown —— 任一侧的值缺失或语义不明,判不了;',
|
||||
'· conditional —— 改外围、限定工况、或加一道验证之后可以成立。',
|
||||
'',
|
||||
'三条硬规矩:',
|
||||
'1. **值是多少不要复述** —— 系统手里已经有值了。影响说明要答的是「换上去会不会比现在差、差在哪儿」。',
|
||||
'2. **判不了就判 unknown,不要猜**;判了 unknown 就必须在 unknown_disposition 里写清楚:实测哪一项、或去哪儿补这个值。',
|
||||
'3. **硬约束不因为措辞变成 match** —— 硬约束不满足就是 mismatch,证据不足就是 unknown。',
|
||||
'',
|
||||
'范围值的读法:「下限~上限」是一个区间(分隔符可能是 ~ 或 - 或 至);只给一边的是半开区间;',
|
||||
'单位可能写在值里。判「盖不盖得住」按区间比,不要拿端点当定值。',
|
||||
'',
|
||||
'只输出 JSON,不要解释、不要 markdown 代码围栏。',
|
||||
].join('\n'),
|
||||
input: {
|
||||
from: { each: 'parts.type_param', where: { type_id: { in: 'typeId' } } },
|
||||
fields: {
|
||||
param_name: { col: 'param_name' },
|
||||
/* **AI 分析时读的就是它** —— 参数名本身说不清「它为什么要紧」 */
|
||||
param_desc: { col: 'param_desc' },
|
||||
constraint_type: { col: 'constraint_type' },
|
||||
unit: { col: 'param_unit' },
|
||||
original_value: { lookup: 'parts.parameter', by: { internal_pn: { in: 'originalPn' }, param_name: { col: 'param_name' } }, take: 'param_value', else: '' },
|
||||
original_note: { lookup: 'parts.parameter', by: { internal_pn: { in: 'originalPn' }, param_name: { col: 'param_name' } }, take: 'param_note', else: '' },
|
||||
candidate_value: { lookup: 'parts.parameter', by: { internal_pn: { in: 'candidatePn' }, param_name: { col: 'param_name' } }, take: 'param_value', else: '' },
|
||||
candidate_note: { lookup: 'parts.parameter', by: { internal_pn: { in: 'candidatePn' }, param_name: { col: 'param_name' } }, take: 'param_note', else: '' },
|
||||
},
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
required: ['items'],
|
||||
properties: {
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['param_name', 'difference_status', 'impact_statement', 'evidence_note'],
|
||||
properties: {
|
||||
param_name: { type: 'string' },
|
||||
difference_status: { type: 'string', enum: ['match', 'mismatch', 'unknown', 'conditional'] },
|
||||
impact_statement: { type: 'string' },
|
||||
evidence_note: { type: 'string' },
|
||||
unknown_disposition: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
/*
|
||||
* ② 逐条明细 —— **行由字典 `each` 出来**,AI 的出参只是拿 `param_name` 去 `lookup` 的一张查表。
|
||||
* 它漏一条,那一行的四态就是空 → `required` 立刻变成 `_missing > 0`,提交闸与放行门当场拦住。
|
||||
* 从前是 `from each(AI 出参)`:它少给两条就少两行,**而每一行看着都合规**。
|
||||
*/
|
||||
{
|
||||
kind: 'project' as const,
|
||||
into: 'substitution.difference_item',
|
||||
prune: true,
|
||||
from: { each: 'parts.type_param', where: { type_id: { in: 'typeId' } } },
|
||||
fields: {
|
||||
substitution_relation_id: { in: 'relationId' },
|
||||
difference_item_id: { cat: [{ in: 'relationId' }, '-', { col: 'param_name' }] },
|
||||
parameter_name: { col: 'param_name' },
|
||||
parameter_desc: { col: 'param_desc' },
|
||||
parameter_unit: { col: 'param_unit' },
|
||||
/* 约束来自字典这一行本身;值一律 lookup 台账 —— 基座读得到的事实不让模型转述 */
|
||||
constraint_type: { col: 'constraint_type' },
|
||||
original_value: { lookup: 'parts.parameter', by: { internal_pn: { in: 'originalPn' }, param_name: { col: 'param_name' } }, take: 'param_value', else: '' },
|
||||
candidate_value: { lookup: 'parts.parameter', by: { internal_pn: { in: 'candidatePn' }, param_name: { col: 'param_name' } }, take: 'param_value', else: '' },
|
||||
difference_status: { lookup: 'result:items', by: { param_name: { col: 'param_name' } }, take: 'difference_status', else: '' },
|
||||
impact_statement: { lookup: 'result:items', by: { param_name: { col: 'param_name' } }, take: 'impact_statement', else: '' },
|
||||
evidence_note: { lookup: 'result:items', by: { param_name: { col: 'param_name' } }, take: 'evidence_note', else: '' },
|
||||
unknown_disposition: { lookup: 'result:items', by: { param_name: { col: 'param_name' } }, take: 'unknown_disposition', else: '' },
|
||||
/* 合成列:先认四态,最后才按约束类型把 mismatch 分成硬 / 软 */
|
||||
judgement_class: {
|
||||
when: 'difference_status = "match"', then: 'match',
|
||||
else: {
|
||||
when: 'difference_status = "unknown"', then: 'unknown',
|
||||
else: {
|
||||
when: 'difference_status = "conditional"', then: 'conditional',
|
||||
else: { when: 'constraint_type = "hard"', then: 'hard_mismatch', else: 'soft_mismatch' },
|
||||
},
|
||||
},
|
||||
},
|
||||
risk_level: {
|
||||
when: 'judgement_class = "hard_mismatch"', then: 'high',
|
||||
else: { when: 'judgement_class = "match"', then: 'low', else: 'medium' },
|
||||
},
|
||||
rule_version: RULE_VERSION,
|
||||
},
|
||||
},
|
||||
/*
|
||||
* ③ 关系一行 —— **等级、风险、摘要、理由全由规则与模板拼,不让 AI 编**。
|
||||
* 于是永远不会出现「有硬约束不符却写着推荐」;人在审核件上改了某一条四态,这一笔重跑,等级跟着变。
|
||||
*/
|
||||
{
|
||||
kind: 'project' as const,
|
||||
into: 'substitution.relation',
|
||||
from: { once: true as const },
|
||||
fields: {
|
||||
substitution_relation_id: { in: 'relationId' },
|
||||
eval_ref: { in: 'evalRef' },
|
||||
original_internal_pn: { in: 'originalPn' },
|
||||
candidate_internal_pn: { in: 'candidatePn' },
|
||||
chip_type_id: { in: 'typeId' },
|
||||
recommendation_level: {
|
||||
when: 'substitution_difference_item_judgement_class_hard_mismatch > 0', then: 'not_recommended',
|
||||
else: {
|
||||
when: 'substitution_difference_item_judgement_class_unknown > 0', then: 'conditional',
|
||||
else: {
|
||||
when: 'substitution_difference_item_judgement_class_conditional > 0', then: 'conditional',
|
||||
else: { when: 'substitution_difference_item_judgement_class_soft_mismatch > 0', then: 'conditional', else: 'recommended' },
|
||||
},
|
||||
},
|
||||
},
|
||||
risk_level: {
|
||||
when: 'recommendation_level = "not_recommended"', then: 'high',
|
||||
else: { when: 'recommendation_level = "recommended"', then: 'low', else: 'medium' },
|
||||
},
|
||||
difference_summary: {
|
||||
cat: [
|
||||
'共 ', { in: 'substitution_difference_item_rows' }, ' 项核心参数:',
|
||||
{ in: 'substitution_difference_item_judgement_class_match' }, ' 项一致 / ',
|
||||
{ in: 'substitution_difference_item_judgement_class_hard_mismatch' }, ' 项硬约束不符 / ',
|
||||
{ in: 'substitution_difference_item_judgement_class_soft_mismatch' }, ' 项软约束不符 / ',
|
||||
{ in: 'substitution_difference_item_judgement_class_unknown' }, ' 项待确认 / ',
|
||||
{ in: 'substitution_difference_item_judgement_class_conditional' }, ' 项有条件。',
|
||||
],
|
||||
},
|
||||
recommendation_reason: {
|
||||
when: 'recommendation_level = "not_recommended"',
|
||||
then: '有硬约束不满足 —— 逐条见差异明细里判为 MISMATCH 且约束类型为硬的那几行;硬性边界不满足,不因措辞改判。',
|
||||
else: {
|
||||
when: 'recommendation_level = "recommended"',
|
||||
then: '每一项核心参数都判为一致,没有待确认项,可直接替代。',
|
||||
else: '没有硬约束不满足,但仍有待确认或需附条件的项 —— 逐条见差异明细;闭环之后方可采用。',
|
||||
},
|
||||
},
|
||||
verification_requirement: {
|
||||
when: 'recommendation_level = "conditional"',
|
||||
/* `{joinRows}` 未实现 —— 不逐个列参数名,指向明细表(那里逐条摆着,且人能就地改) */
|
||||
then: '实测差异明细里判为 UNKNOWN 与 CONDITIONAL 的每一项,并把实测值回填 P-08 标准化参数集;回填后重跑本评估。',
|
||||
else: '',
|
||||
},
|
||||
validation_id: { cat: ['VAL-', { in: 'evalRef' }] },
|
||||
analysis_status: 'fae_confirmed',
|
||||
rule_version: RULE_VERSION,
|
||||
},
|
||||
},
|
||||
/*
|
||||
* ④ 验证记录一行 —— **一单固定一条**(用户定)。本活动只写「还得去验什么」,
|
||||
* 状态一律 `not_started`:它不是实测结果,**不许虚构实测**。
|
||||
*/
|
||||
{
|
||||
kind: 'project' as const,
|
||||
into: 'validation.record',
|
||||
from: { once: true as const },
|
||||
fields: {
|
||||
validation_id: { cat: ['VAL-', { in: 'evalRef' }] },
|
||||
eval_ref: { in: 'evalRef' },
|
||||
validation_internal_pn: { in: 'candidatePn' },
|
||||
validation_type: 'parametric',
|
||||
validation_status: 'not_started',
|
||||
test_condition: {
|
||||
when: 'substitution_difference_item_judgement_class_unknown + substitution_difference_item_judgement_class_conditional > 0',
|
||||
then: '差异明细里判为 UNKNOWN 与 CONDITIONAL 的每一项,按原厂规格书条件实测。',
|
||||
else: '无',
|
||||
},
|
||||
next_validation_action: {
|
||||
when: 'substitution_difference_item_judgement_class_unknown + substitution_difference_item_judgement_class_conditional > 0',
|
||||
then: '实测上述各项并把实测值回填 P-08 标准化参数集,回填后重跑本评估。',
|
||||
else: '本轮无待验项。',
|
||||
},
|
||||
},
|
||||
},
|
||||
{ kind: 'say' as const, text: '逐条差异结论已备好,推荐等级由规则按四态算出。' },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
item: 'S3_review',
|
||||
|
||||
Reference in New Issue
Block a user