度量八指标全部接真:DMN 覆盖率与单位成本不再恒为 0

两处度量是空的,查下来都是「没人记」而不是「算错了」:

① **DMN 覆盖率恒 0**:判据只认标题里的「求值:」,把跑得最多的**纯工具步**整个漏掉。
   DMN 决策表与机检正是落在纯工具/工具步上。改为按步类型分:
   确定性求值(pure-tool / tool)÷ 判断总数(再加 LLM 步)——「临场搬进确定」的进度表。
   顺带把**步类型显式写进留痕**:判据该由引擎给出,不靠解析标题后缀。
   现读数 66%。

② **单位成本恒 0**:任务消耗只记步数,token / 活跃时长 / 调人次数**从来没人累加** ——
   于是八指标里的单位成本永远是 0,预算熔断与打扰上限也形同虚设。
   · tick 计这一拍真正花掉的时间(挂起等人的不算活跃,那是世界等待);
   · flow 的 LLM 步与 loop 的每一回合都把 token 计入;
   · 每发一张卡计一次调人。
   现读数:A2 单轮 12k token、A3 3.4k;单位成本 73 token 每放行单。

另修:执行卡的 ask 优先取 `card.ask`(此前只认 `reason`,新卡面格式下会退化成标题)。

第四轮端到端复跑:整条链闭环,消耗数据真实。

gates: tsc / eslint / depcruise(336 模块)/ api-report / 429 测试 全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-27 11:44:10 +08:00
co-authored by Claude Opus 5
parent 94f31f267b
commit 61fe181678
8 changed files with 97 additions and 20 deletions
+10 -1
View File
@@ -270,6 +270,7 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
criteria: [{ label: '成果齐备', level: 'L5', pass: false }],
fields: [],
});
await taskStore.addConsumption(input.taskId, { humanCalls: 1 });
return { id: issued.order.id };
}
const fields = Array.isArray(input.card['fields'])
@@ -278,9 +279,11 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
const issued = await deps.humanTool.issueExecution(context, {
title,
basis: basis.length > 0 ? basis : [{ k: '来源', v: '步序声明' }],
ask: String(input.card['reason'] ?? title),
ask: String(input.card['ask'] ?? input.card['reason'] ?? title),
fields,
});
// 打扰率的计量对象:每发一张卡就是调了一次人 —— 不计就等于没有上限
await taskStore.addConsumption(input.taskId, { humanCalls: 1 });
return { id: issued.order.id };
},
};
@@ -348,6 +351,10 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
stepNo: input.stepNo,
label: 'flow-step',
});
// token 计入任务预算 —— 单位成本与预算熔断都靠它,不计就等于没有预算
await taskStore.addConsumption(input.taskId, {
tokens: result.usage.inputTokens + result.usage.outputTokens,
});
// 解析与校验归引擎(它才知道这一步声明了什么);这里只如实上交结果与原文
return {
ok: true,
@@ -373,6 +380,8 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
data: taskData,
agent: createAgentRunner({
gateway: deps.modelGateway,
// loop 的每一回合都要问模型 —— 不计 token,预算熔断就永远不会响
onUsage: (taskId, tokens) => taskStore.addConsumption(taskId, { tokens }).then(() => undefined),
modelOf: async (taskId) => {
const { activityId } = await taskContext.of(taskId);
const manifest = await deps.registry.manifestOf(activityId);