AI多Agent协作系统实战(十五):当AI Agent说“测试通过“时,它到底做了什么?——从“感性复核“到“理性证据链“的重构》
系列第15篇 | 一个DB空壳引发的测试机制革命
背景
7月13号晚上,用户问了我一个问题:
“你们的测试和复核,是感性的还是理性的?”
这个问题让我愣住了。我们有test_steps表,有record_step()函数,有review.py检查DB记录——机制明明都在啊。
但用户紧接着说:
“做了就是做了,没做就是没做。”
我查了一下DB——test_steps表里只有1条demo记录。所有真实的FIX/RETEST任务,零记录。
建了机制,≠机制在运行。
问题1:DB空壳——表建了,函数写了,但没人调
现象
test_steps表结构完整:
CREATE TABLE test_steps (
id INTEGER PRIMARY KEY,
task_id TEXT NOT NULL,
step_name TEXT NOT NULL,
step_type TEXT NOT NULL,
result TEXT DEFAULT 'not_done',
evidence_type TEXT,
evidence_data TEXT,
executed_by TEXT,
executed_at TEXT
)
record_step()函数能用:
task_db.record_step(
task_id='TEST-FIX-xxx',
step_name='avatar_click_test',
step_type='test',
result='pass',
evidence_type='browser_console',
executed_by='小牛'
)
review.py会检查:
def verify_db_audit(task_id):
steps = task_db.get_steps_for_task(task_id)
if not steps:
results.append("⚠️ 无DB执行记录(警告)")
return True, results # 降级为警告,不阻塞复核
原因
三个层面全部断裂:
- Agent不调用:小牛测试时从未调用过record_step()——它不知道要调用
- review.py只警告:无记录时输出⚠️但不阻塞,复核照样通过
- 没有强制约束:没有任何机制阻止Agent跳过DB直接报完成
整个机制是空壳。
修复
不能依赖Agent"记得"调用。必须让脚本自动完成。
新建evidence_collector.py——自动采集证据的唯一入口:
import evidence_collector as ec
# 开始会话(自动清空旧记录)
ec.start_test_session('TEST-FIX-xxx', 'test', '小牛')
# 每步记录证据(自动写DB + 存文件)
ec.record_screenshot('TEST-FIX-xxx', 'avatar_after', '/path/to/screenshot.png')
ec.record_console('TEST-FIX-xxx', 'page_load', console_output)
ec.record_api_call('TEST-FIX-xxx', 'user_api', url, 200)
ec.record_interaction('TEST-FIX-xxx', 'click_test', '点击头像', '弹出上传框', '弹出上传框', True)
# 结束会话
ec.end_test_session('TEST-FIX-xxx', 'pass')
review.py改为阻塞模式:
def verify_db_audit(task_id):
steps = task_db.get_steps_for_task(task_id)
if not steps:
return False, ["❌ 无DB执行记录 — 必须有证据链"] # 阻塞!
# ... 检查完整性 + 证据文件
ws_server.py增加强制检查:
# 小牛完成时,先检查DB记录
steps = db.execute(
"SELECT COUNT(*) FROM test_steps WHERE task_id=? AND step_type NOT IN ('metadata','summary')",
(task_id,)
).fetchone()[0]
if steps == 0:
# 无证据 → 自动标记失败,不执行review
db.execute("UPDATE tasks SET review_status='failed' WHERE task_id=?", (task_id,))
return
问题2:RETEST无限循环——15层嵌套的任务名
现象
复核失败→自动重派RETEST→又失败→又重派…
任务名越来越长:
RETEST-RETEST-RETEST-RETEST-RETEST-RETEST-RETEST-RETEST-TEST-FIX-0712-PC-AUTH-HEADER
DB里堆了15个循环任务。
原因
dispatch_retest()没有重试次数限制:
def dispatch_retest(task_id, reason):
retest_id = f"RETEST-{task_id}" # 无限嵌套
# ... 派发
修复
加最大重试3次:
def dispatch_retest(task_id, reason):
retry_count = task_id.count('RETEST-')
if retry_count >= 3:
return f"⚠️ 已达最大重试次数(3次),跳过重派"
retest_id = f"RETEST-{task_id}"
# ...
问题3:RETEST通过后,报告还是显示❌
现象
RETEST复核通过了(review=passed),但统筹报告还是显示:
结论:❌ 共1个任务,0个已通过,1个复核失败
原因
三个bug叠加:
Bug 1:review.py不处理RETEST前缀
# 只处理TEST-FIX-xxx,不处理RETEST-TEST-FIX-xxx
if task_id.startswith('TEST-FIX-'):
dev_id = 'FIX-' + task_id[9:]
else:
dev_id = None # RETEST任务走到这里,DEV任务没被同步
Bug 2:format_report.py偏移量错误
# RETEST- 是7个字符,不是8个
inner = tid[8:] # 错!得到 "EST-FIX-xxx"
inner = tid[7:] # 对!得到 "TEST-FIX-xxx"
Bug 3:FIX- 是5个字符,不是4个
# RETEST-TEST-FIX- 是16个字符,不是17个
dev_id = 'FIX-' + tid[17:] # 错!得到 "FIX-714-AVATAR-xxx"
dev_id = 'FIX-' + tid[16:] # 对!得到 "FIX-0714-AVATAR-xxx"
修复
三处全部修正偏移量,RETEST正确映射到FIX任务。
经验总结
1. 建了机制 ≠ 机制在运行
test_steps表建了、record_step()写了、review.py检查了——但整个系统从头到尾没有任何Agent调用过record_step()。
教训:建完基础设施后,必须验证Agent实际在调用函数、DB有真实数据,才能说"机制生效"。
2. 不能依赖Agent"自觉"
evidence_collector.py需要Agent主动调用→Agent可以不调用。
正确做法:ws_server在关键节点强制检查DB记录,无记录=自动失败。不给Agent绕过的机会。
3. RETEST前缀处理是容易忽略的边界case
RETEST-TEST-FIX-xxx需要剥两层前缀才能得到FIX-xxx。只剥一层会得到错误的dev_id,导致DEV任务的review_status不被同步。
4. 字符串偏移量要手动验证
len('RETEST-') = 7,不是8。len('RETEST-TEST-FIX-') = 16,不是17。不要凭直觉写偏移量,用len()验证。
更多推荐
所有评论(0)