mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 04:31:58 +00:00
多 agent 节点不再永远转圈,调度决策也说出来了
运行 #6038f5:supervisor 节点跑完 31.7s 之后,researcher 那一行还在转圈。 agent.step.start / agent.step.end 是这套事件里**唯一**一对没做配对的 (node、llm、tool、sandbox、human 都配了)。start 那条建出来就是 running, end 另起一行,于是没人去关它。这正是 decode.ts 自己文档里的第 2 条原则 ——成对事件合并成一行——我写了却没用在 agent 上。 配对键用 (node_id, agent, round):光用 agent 名不够,supervisor 会在多轮里 反复派给同一个 agent,第二轮的 end 会错配到第一轮的 start 上。 顺带把 supervisor 的调度决策捞出来。后端把它标成 info 日志,而 info 是整类 丢弃的,结果"为什么派给 researcher"、"为什么只跑一轮就结束"在界面上完全 没有交代——那个节点就是一个跑了 31 秒的黑盒。带 round 字段的 info 才是调度 决策,和普通排查日志区分得开。FINISH 译成"结束协作"而不是"交给 FINISH", 后者会让人以为还有个叫 FINISH 的成员。 真实运行已收进 fixtures,check-decode 加 9 条(含"普通 info 日志仍然不进 主流程"和"warn 日志照常显示"这两条反向约束)。
This commit is contained in:
@@ -118,6 +118,38 @@ console.log('\n=== 循环里的多轮审批 ===')
|
||||
check('跑完了没有还在转的行', !all.some((s) => s.status === 'running'))
|
||||
}
|
||||
|
||||
console.log('\n=== 多 agent 协作 ===')
|
||||
{
|
||||
// 真实运行 #6038f5:supervisor 派给 researcher 一次就 FINISH 了。
|
||||
// 界面上那个多智能体节点跑完 31.7s 之后,researcher 那行还在转圈。
|
||||
const steps = mod.decodeRun(fixtures.supervisor)
|
||||
const all = flatten(steps)
|
||||
|
||||
const agentRows = all.filter((s) => s.title.startsWith('researcher'))
|
||||
check('一个 agent 步骤就是一行,不是"派任务"+"回复"两行',
|
||||
agentRows.length === 1, `${agentRows.length} 行:${agentRows.map((s) => s.title.slice(0, 20)).join(' | ')}`)
|
||||
check('回复挂在同一行里可展开', !!agentRows[0]?.result)
|
||||
check('跑完了就不转圈了', agentRows[0]?.status === 'done', agentRows[0]?.status)
|
||||
|
||||
// supervisor 的调度理由被后端标成了 info 日志,整类丢掉的话,
|
||||
// 多 agent 节点在界面上就是一个跑了 31 秒的黑盒
|
||||
const routes = all.filter((s) => s.kind === 'branch')
|
||||
check('调度决策要说出来', routes.length === 2, `${routes.length} 条`)
|
||||
check('说清楚第几轮交给谁',
|
||||
routes[0]?.title.includes('第 1 轮') && routes[0]?.title.includes('researcher'),
|
||||
routes[0]?.title)
|
||||
// FINISH 是协议里的收尾标记,不是某个 agent
|
||||
check('为什么结束也要有交代,且不说"交给 FINISH"',
|
||||
routes[1]?.title.includes('结束协作') && !routes[1]?.title.includes('FINISH')
|
||||
&& !!routes[1]?.detail,
|
||||
`${routes[1]?.title} / ${routes[1]?.detail?.slice(0, 24)}`)
|
||||
check('普通 info 日志仍然不进主流程',
|
||||
!all.some((s) => s.title.includes('校验通过')))
|
||||
check('warn 日志照常显示', all.some((s) => s.title.includes('校验失败')))
|
||||
check('整条流跑完没有转圈的行', !all.some((s) => s.status === 'running'),
|
||||
all.filter((s) => s.status === 'running').map((s) => s.title.slice(0, 24)).join(','))
|
||||
}
|
||||
|
||||
console.log('\n=== 出具判定 ===')
|
||||
{
|
||||
const steps = mod.decodeRun(fixtures.issue)
|
||||
|
||||
@@ -12,7 +12,7 @@ const WEB = process.env.AGENTLAB_WEB ?? 'http://localhost:5273'
|
||||
// 不用 playwright install:它既下不动也会动到已有缓存。系统 Chrome 就够了。
|
||||
const CHROME = process.env.CHROME_PATH
|
||||
?? '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
|
||||
const CASES = ['db', 'think', 'human', 'issue', 'failed', 'loop_approve']
|
||||
const CASES = ['db', 'think', 'human', 'issue', 'failed', 'loop_approve', 'supervisor']
|
||||
|
||||
let failed = 0
|
||||
const check = (name, cond, detail = '') => {
|
||||
|
||||
Reference in New Issue
Block a user