人手改的那一手真正落得下去;界面不撒谎那几处补齐
手改是**兜 AI 的错**的那一手 —— 这一轮把它从「摆在那儿但落不了地」做成真的: 件上就地改 · 保存**按地址收**,不看当下那张卡:载荷从前借道工单的 `blocks[i]` 取列名, 于是熔断卡(没有 blocks)在屏上时,人补的那一格一个字都送不出去 —— 而他要补的恰恰是把这一单卡住的那个必填格。授权面改由活动清单的台账声明把关。 · **能增删行**:错不止「这一格填错了」,还有「这一行不该在」与「漏了一行」。 删挂记号不当场抹掉(看得见、可后悔),且**删要说出来**(`drops`)—— 「没回传就是删了」会把一次不完整的回传变成一次删表。 · **必填没填按不下提交**:与放行门 L1 同一个数同一套算法;闸上摆出差在哪一行哪一格。 · 只写真改了的那几行 —— 改一格却留「修订 4 行」的痕,那句话是假的。 判据与门 · 裁量判据带谓词时**谓词说了算**:「选填缺口已补齐」基座数得出来, 人填好的目标价它照样判「客户未提供」的毛病由此消掉。 · 验收卡判据**读时现算** —— 人在成果件上补一格,判据跟着变。 · 放行门认「**办完了没有**」不认「有人写过」:从前写个 `false` 就把门推开, 于是一单没打标就进了放行门。三个数全由基座现数。 · 拒回把「活没干完」说成「数或行对不上」的毛病:判据点名的表一行都没写时直说那一步没办。 **指向两扇打不开的门,比不指还糟。** 界面不撒谎 · 日志只有三色:负责人绿 · 智能体蓝 · 系统灰(归侧五种是度量的分法,不是给人看的)。 · 验收收口答两件事:落了什么(按**交付物**点名,一份成果的几张表并成一行)、 往哪儿去(转出哪一口、带过去哪些字段);一个口都没发就直说到此为止。 · 签完到收尾之间那一段有自己的话「字已签下,正在落地」—— 中间态本来就该说出来,只是要说对。 · 消息不再被内部事件刷屏:只有从通道进来的件才谈得上「无人认领」。 · 建客户公司与联系人**一次确认落两行**;联系人编码自增不问人;卡面摆表的人读名。 A1 三案例端到端全 released:全 A 类直通 12 拍 / 客户点名跳一条 10 拍 / 新客户缺必填 14 拍。 五道门禁全绿(971 passed)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
* 活动与工具的解耦就在②③之间:槽位只声明工具**名**,注册、连接值、白名单全在这里。
|
||||
*/
|
||||
import type { Container } from './container.ts';
|
||||
import { installRealActivities } from './seed-activities.ts';
|
||||
import { installSlots } from './seed-mvp-slots.ts';
|
||||
import { seedMvpFlow } from './seed-mvp-flow.ts';
|
||||
|
||||
@@ -16,16 +17,27 @@ import { seedMvpFlow } from './seed-mvp-flow.ts';
|
||||
const HISTORY_TOOL = {
|
||||
name: 'crm.history-price-read',
|
||||
displayName: '历史价查询',
|
||||
version: '1.0.0',
|
||||
description: '读取历史价格情报:某 PN 最近一次报价距今天数、行情是否平稳、生命周期状态',
|
||||
input: { type: 'object', required: ['pn'], properties: { pn: { type: 'string' } } },
|
||||
version: '1.1.0',
|
||||
description:
|
||||
'读取历史价格情报:某 PN 最近一次报价距今天数、行情是否平稳、生命周期状态、上次成交单价。' +
|
||||
'一次可查一批 —— 传 pns 数组,出参走 rows(一单几十条料不必一条一调)。',
|
||||
input: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
pn: { type: 'string', description: '单条查询' },
|
||||
pns: { type: 'array', items: { type: 'string' }, description: '批量查询(优先于 pn)' },
|
||||
},
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
pn: { type: 'string' },
|
||||
historyDays: { type: 'integer' },
|
||||
marketStable: { type: 'boolean' },
|
||||
lifecycle: { type: 'string' },
|
||||
hit: { type: 'boolean' },
|
||||
lastPrice: { type: 'number' },
|
||||
rows: { type: 'array', description: '批量查询的逐条结果' },
|
||||
},
|
||||
},
|
||||
effect: 'read' as const,
|
||||
@@ -53,6 +65,57 @@ const MAIL_TOOL = {
|
||||
connectionKeys: ['endpoint'],
|
||||
};
|
||||
|
||||
/**
|
||||
* 逐条打标 —— **纯工具**(活动私有作用域,`ownerActivityId` 定死是谁的)。
|
||||
*
|
||||
* 它是三分类规则 P-03 的**求值器**:同输入必同结论、零方差零 token、命中规则行随出参留痕。
|
||||
* 「能算的不问 LLM」的具体形态就是这样一枚工具 —— 不是让模型照着规则表判,
|
||||
* 而是把规则表做成工具,模型只负责把判据取齐。
|
||||
*
|
||||
* 出参键名与台账列同名(`type_tag` / `basis`):拿回来直接 write,不必让模型改名 ——
|
||||
* 那一步交给模型做,它会漏。
|
||||
*/
|
||||
const CLASSIFY_TOOL = {
|
||||
name: 'quote-intake.classify',
|
||||
displayName: '料号三分类打标',
|
||||
version: '1.0.0',
|
||||
description:
|
||||
'按三分类规则 P-03 逐条打标(A 历史价≤90天且行情稳 / B 无历史·过期·波动 / C EOL·缺货·要替代)。' +
|
||||
'一次可打一批 —— 传 rows(每行含 pn 与三项判据),出参走 results。',
|
||||
input: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rows: {
|
||||
type: 'array',
|
||||
description: '批量:每行 { pn, history_days, market_stable, lifecycle }',
|
||||
items: { type: 'object' },
|
||||
},
|
||||
history_days: { type: 'integer', description: '单条:距上次报价天数' },
|
||||
market_stable: { type: 'boolean', description: '单条:行情是否稳定' },
|
||||
lifecycle: { type: 'string', description: '单条:生命周期状态' },
|
||||
},
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
results: { type: 'array', description: '批量结果:每行 { pn, type_tag, play, basis, rule }' },
|
||||
type_tag: { type: 'string' },
|
||||
play: { type: 'string' },
|
||||
basis: { type: 'string' },
|
||||
rule: { type: 'string', description: '命中的规则行 —— 留痕靠它' },
|
||||
},
|
||||
},
|
||||
effect: 'read' as const,
|
||||
errors: [{ code: 'no-match', retryable: false, message: '三分类规则无命中行' }],
|
||||
idempotent: true,
|
||||
timeoutMs: 5_000,
|
||||
retries: 0,
|
||||
connectionKeys: [] as string[],
|
||||
// 纯工具:活动私有作用域 —— 别的活动调不到,白名单也给不了
|
||||
pure: true,
|
||||
ownerActivityId: 'quote-intake',
|
||||
};
|
||||
|
||||
/**
|
||||
* 活动槽位的占位产出 —— **编排层跑通期专用的纯工具**。
|
||||
*
|
||||
@@ -108,7 +171,8 @@ const PLACEHOLDER_TOOL = {
|
||||
|
||||
/** 白名单:逐槽位授权 —— 谁能调什么,治理台说了算,活动代码里看不到这张表 */
|
||||
const ALLOWLIST: Readonly<Record<string, readonly string[]>> = {
|
||||
'rfq-intake': [HISTORY_TOOL.name, PLACEHOLDER_TOOL.name],
|
||||
// A1 已是真活动:白名单里摘掉占位工具 —— 它一在,模型就会拿它糊弄过去
|
||||
'quote-intake': [HISTORY_TOOL.name],
|
||||
'alt-selection': [HISTORY_TOOL.name, PLACEHOLDER_TOOL.name],
|
||||
'sourcing-inquiry': [HISTORY_TOOL.name, MAIL_TOOL.name, PLACEHOLDER_TOOL.name],
|
||||
'cost-pricing': [HISTORY_TOOL.name, PLACEHOLDER_TOOL.name],
|
||||
@@ -147,13 +211,20 @@ export async function seedMvp(container: Container): Promise<void> {
|
||||
log(`① LLM 实例已绑定:deepseek-v4-flash · deepseek-v4-pro${apiKey === undefined ? '(环境无密钥 —— 两条都是未绑定,去治理台补)' : ''}`);
|
||||
|
||||
/* ② 功能工具注册两审 + 逐槽位白名单 */
|
||||
for (const contract of [HISTORY_TOOL, MAIL_TOOL, PLACEHOLDER_TOOL]) {
|
||||
for (const contract of [HISTORY_TOOL, MAIL_TOOL, CLASSIFY_TOOL, PLACEHOLDER_TOOL]) {
|
||||
const verdict = await container.toolbox.register({
|
||||
contract,
|
||||
samples: [
|
||||
{
|
||||
// 样例集一份喂三件工具:并集覆盖各家必填
|
||||
input: { pn: 'LM358DR', to: 'x@y.com', subject: '询价' },
|
||||
// 样例集一份喂四件工具:并集覆盖各家必填
|
||||
input: {
|
||||
pn: 'LM358DR',
|
||||
to: 'x@y.com',
|
||||
subject: '询价',
|
||||
history_days: 30,
|
||||
market_stable: true,
|
||||
lifecycle: '在产',
|
||||
},
|
||||
expectShape: { type: 'object' },
|
||||
},
|
||||
],
|
||||
@@ -167,11 +238,17 @@ export async function seedMvp(container: Container): Promise<void> {
|
||||
for (const [activityId, tools] of Object.entries(ALLOWLIST)) {
|
||||
await container.toolbox.setAllowlist(activityId, tools);
|
||||
}
|
||||
log('② 功能工具已注册并入白名单(读类 1 · 写类 1 · 占位纯工具 1,逐槽位授权)');
|
||||
log('② 功能工具已注册并入白名单(读类 1 · 写类 1 · 纯工具 2,逐活动授权)');
|
||||
|
||||
/* ③ 六个活动槽位经安装通道装入 —— 声明物化把四域十八对象建出来 */
|
||||
/*
|
||||
* ③ 活动装入 —— 两批:
|
||||
* · 真活动包经**安装通道读文件**装(系统外开发、安装即用);
|
||||
* · 尚未开发的槽位照旧从常量表装(契约就绪、实现留白),让编排层能整条走通。
|
||||
* 两批都走同一道安装两审,声明物化顺带把台账表建出来。
|
||||
*/
|
||||
await installRealActivities(container);
|
||||
await installSlots(container);
|
||||
log('③ 六个活动槽位已装入(契约就绪,实现留白)');
|
||||
log('③ 活动已装入(真活动包 1 · 槽位 6:契约就绪、实现留白)');
|
||||
|
||||
/* ④ 流程包 1:1 + 触发器 + 通道 */
|
||||
await seedMvpFlow(container);
|
||||
|
||||
Reference in New Issue
Block a user