Archived
调优:并发推进的真根因 + loop 的三处行为修正
E2E 跑 loop 时 A3 一口气发了八张一模一样的「请处理」卡。逐层查下去,四处: ① **并发推进的真根因**:`pg_try_advisory_lock` 是**会话级**的,而我们经连接池取连接 —— 加锁与解锁多半落在不同连接上,解锁解不掉自己那把;同一连接被复用时又因可重入而直接放行。 两头都不对,于是同一任务被并发推进(现象:同一步跑两遍、同一张卡发两张、 同一行草稿写出两条互相打架的版本)。前一轮「共用同一把锁」的修法方向对、器械错。 改用**进程内按目标互斥**(MVP 单进程,确定且够用),推进器与派发器共用一把; 多进程部署时再叠事务级 `pg_try_advisory_xact_lock`(随事务释放,不依赖连接归属)。 实测:同一单从 8 张卡降到 1 张,2 回合后落到等待。 ② **非法行动会把回合打死**:AI 提了不合法的生命周期迁移(Available → Disabled), `applyAction` 抛出、运行时没落笔、推进器一遍遍重来。引擎拒绝它是对的 ——「语义忠实:引擎不得私改迁移拓扑」——但不该因此崩掉。 改为:拒绝 + 留痕 + 把理由喂回下一回合的上下文。AI 提出非法行动是预期内的事。 ③ **副作用抢在校验之前**:卡在迁移合法性判定**之前**就发出去了,于是每个被拒的回合 都白发一张卡 —— 卡收不回,负责人工作台上堆起一摞没人知道怎么答的「请处理」。 human / tool 两个分支改为**先验迁移再动手**。 ④ **裸调用**:模型只回一个「请处理」。按「调用必附上下文,裸调用不得发出」(AM 06) 把卡面结构写进出参 schema(title / ask / basis / fields 必填),提示里讲明要求, 归一时用当下局面兜底;卡片装配也修了 —— 结构化 basis 优先,嵌套对象转 JSON, 不再出现一行 `[object Object]`。 实测卡面:「请确认 NE555P 历史报价并判定采用策略」+ 三个回填字段。 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:
@@ -248,9 +248,20 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring {
|
||||
}) {
|
||||
const context = { taskId: input.taskId, ownerId: input.ownerId, humanCallCap: input.humanCallCap };
|
||||
const title = String(input.card['title'] ?? '请处理');
|
||||
const basis = Object.entries(input.card)
|
||||
.filter(([k]) => k !== 'title' && k !== 'fields')
|
||||
.map(([k, v]) => ({ k, v: String(v) }));
|
||||
|
||||
/*
|
||||
* 依据快照:优先用活动给的结构化 `basis`(`{k,v}[]`);没给才把卡面其余键铺成依据。
|
||||
* 铺的时候要跳过 `ask`(它是问题不是依据)与空值,嵌套对象转 JSON ——
|
||||
* 不然人看到的是一行 `[object Object]`,那还不如不给。
|
||||
*/
|
||||
const declared = input.card['basis'];
|
||||
const basis = Array.isArray(declared)
|
||||
? declared
|
||||
.filter((b): b is { k: unknown; v: unknown } => typeof b === 'object' && b !== null && 'k' in b)
|
||||
.map((b) => ({ k: String(b.k), v: String(b.v) }))
|
||||
: Object.entries(input.card)
|
||||
.filter(([k, v]) => !['title', 'fields', 'ask', 'basis'].includes(k) && v !== null && v !== undefined && v !== '')
|
||||
.map(([k, v]) => ({ k, v: typeof v === 'object' ? JSON.stringify(v) : String(v) }));
|
||||
if (input.workOrder === 'acceptance') {
|
||||
const issued = await deps.humanTool.issueAcceptance(context, {
|
||||
title,
|
||||
|
||||
Reference in New Issue
Block a user