Archived
差异比对三刀:客户约束不再一票否决 · 入参由基座从台账取 · 「下限~上限」一律读成范围
①**两颗一模一样的输入电压范围判成 MISMATCH**(用户送来 0bddd862):客户写「45V 以内」→ requirement `>= 45`,
而原 PN 与候选上限都是 40V;`judgePair` 只看候选过不过客户线、不看原 PN 自己过不过 ——
需求边界与在用料的差距记在了候选头上,硬约束 MISMATCH → 整颗不推荐。差异评估比的是「换上去会不会比现在差」:
候选与原 PN 相等 / 盖住、且客户线原 PN 也过不去 → 仍按比对结果判(MATCH,风险中),备注点名
「需求边界,请回头核对需求」;候选更窄且过不了线仍 MISMATCH(3 形有测)。
②**入参由基座从台账取,模型只报料号与客户约束**(用户:「这个做差异评估比对的 harness 肯定有问题」):
同一单痕里模型念出「输入上限 32V 低于客户 40V」—— 那是 S3 剧本示例的原话、不是这单的数;
工具入参只存哈希,喂了哪几对值事后查不到;写回时还把工具的 `equal` 改成 `less`。两头都靠模型抄、两头都没有基座核。
改三层:工具运行时把 `taskId / activityId` 交给处理器(`ToolHandler` 入参加两个可选键);
`compare-parameters` 给 `originalInternalPn + candidates[].candidateInternalPn(+ requirements)`,
参数行从 `parts.parameter`、封装 / 生命周期从 `parts.profile`、证据引用从 `parts.document` 由工具现读任务视图
(本单草稿也算),出参每项带原值与证据,写盘照抄;老形状(自带 pairs)照接,试运行走它;
container 用 `compareParametersWith(ledger)` 顶掉静态名单那份;≤800 字的工具入参整份进 `result` 痕(审得了才谈得上认真)。
**基座能读到的事实,不让模型转述给工具。**
③**「下限~上限」一律是范围**(用户:「4.5~40 / -40~+85 这种我怕模型搞不清楚」):实测解析器真有洞 ——
单位写进值里(`4.5V~40V` / `-40℃~+85℃`)被读成单个数,Unicode 减号、`…`、`≥45 / 40 以内` 读成文本。
分隔符认 ~ ~ - – — … 至 到 to、单位可夹在值里、单边界读成半开范围;出参每项 `readAs:{original,candidate}`
写明「范围 4.5~40 / 定值 5 / 下界 ≥ 45 / 文本」—— 比对依据可见,模型照它写影响、不自己重新解释值;
契约描述与 S3 / P-08 剧本明写读法(示例用中性数 1~10,不用真数据里的 4.5~40 —— 模型会把示例当这单的值)。
工具 1.0.0 → 1.3.0(注册一名一行、upsert 换版本,handler 在进程内按名绑,装完稳定版重建即生效);
W05 包 1.6.2 → 1.6.4:S3 第一拍只报料号与约束、示例只留占位形,第三拍 compare_result 照抄,S4 重比只改 requirements。
13 工具测 + 包内 89。在途单要人在审核卡上「重做」并写明意见才会重比。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167qWjeyBwvfdGovd7FWbCu
This commit is contained in:
@@ -866,7 +866,16 @@ export function createTurnRunner(deps: TurnRunnerDeps): LoopEngineService {
|
||||
? ''
|
||||
: ` —— 这是同一份入参的第 ${sameCalls + 1} 次调用,出参与上次一字不差:别再调了,按这个数往下办`),
|
||||
// inputHash 是「同一份入参重调」检查的账 —— 存短哈希,不存整份入参(轨迹要进提示词)
|
||||
detail: { output: result.output, error: result.error?.message, inputHash: toolInputHash(action.input) },
|
||||
/*
|
||||
* **小入参原样留痕**(2026-08-27 晚):比对工具的入参从前只存哈希,模型到底喂了哪几对值事后没法审
|
||||
* (实测它把剧本示例的值当这单的值念出来)。入参不长(≤ 800 字)就整份存 —— 审得了才谈得上「认真比对每一条」。
|
||||
*/
|
||||
detail: {
|
||||
output: result.output,
|
||||
error: result.error?.message,
|
||||
inputHash: toolInputHash(action.input),
|
||||
...(JSON.stringify(action.input).length <= 800 ? { input: action.input } : {}),
|
||||
},
|
||||
});
|
||||
return {
|
||||
// 失败才动状态(Failed 是拓扑里的一档;没挂上项就没有项可标);成了就留在 Active 等 Agent 宣告完成
|
||||
|
||||
@@ -77,3 +77,7 @@
|
||||
影响半径: index/port 加法式扩容(新端口类型 + 三件纯函数 + 一张表);
|
||||
`invoke` 对未注册工具的**行为**变了(抛 → 回 `tool-unregistered`)——
|
||||
下游只有 app 的 `toolGateway` 一处消费,已同步改为转人。
|
||||
|
||||
- **处理器拿得到 `taskId` / `activityId`**(2026-08-27):`ToolHandler` 入参多两个可选键,运行时从 `ToolCall` 透传。
|
||||
读台账的第一方工具(差异评估的 `compare-parameters`)靠它读**本单的任务视图**;试运行 / 老调用方没有,工具退回纯入参那条路。
|
||||
这是「基座能读到的事实,不让模型转述给工具」的接口面 —— 工具仍只读,不经它写台账。
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { Ajv } from 'ajv';
|
||||
import addFormats from 'ajv-formats';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import type { TaskId } from '@contracts';
|
||||
import type { Db } from '@shared/db.ts';
|
||||
import type { SchemaValidator, ToolHandoff, ToolHandoffStore, ToolRegistry, ToolReplayStore, ToolRuntime } from '../../port.ts';
|
||||
import type { ToolCall, ToolResult } from '../../contract.ts';
|
||||
@@ -175,6 +176,13 @@ export type ToolHandler = (input: {
|
||||
readonly connection: Readonly<Record<string, string>>;
|
||||
readonly operation: string | undefined;
|
||||
readonly idempotencyKey: string | undefined;
|
||||
/**
|
||||
* 调用发生在哪一单 / 哪个活动(2026-08-27 晚):**读台账的工具**靠 taskId 认「本单的草稿层」——
|
||||
* 比对入参由基座从台账取,不再由模型抄给工具(抄错、抄示例都拦不住,且抄了什么不留痕)。
|
||||
* 试运行 / 老调用方没有这两样,工具自己退回纯入参那条路。
|
||||
*/
|
||||
readonly taskId?: TaskId | undefined;
|
||||
readonly activityId?: string | undefined;
|
||||
}) => Promise<{ ok: boolean; output?: Record<string, unknown>; error?: { code: string; retryable: boolean; message: string } }>;
|
||||
|
||||
/**
|
||||
@@ -209,6 +217,8 @@ export function createToolRuntime(
|
||||
connection: scoped,
|
||||
operation: call.operation,
|
||||
idempotencyKey,
|
||||
taskId: call.taskId,
|
||||
activityId: call.activityId,
|
||||
}),
|
||||
timeout,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user