information_gain:Luduan 的一个新进度标尺
摘要
Luduan 电子取证智能体某次完整跑完 12 次 Action,工具全部调用成功,终端持续输出运行状态,可是最终却产出三份大小为 0 的证据文件。
问题不在于大模型推理能力,而在于运行时把动作执行完成等同于调查取得进展。
ok:true 只代表工具没崩溃,不代表拿到了新认知。为此引入 information_gain 分层标尺,区分新增事实、证据,不再单纯依靠动作计数判断是否继续下一步的调查;同时留存 no‑match 原始观测指标,避免重复无效搜索,允许 Agent 诚实输出 PARTIAL,而不是一直在原地踏步,耗光预算。
我在甪端电子取证智能体开发的过程中,跑过一个真实的测试。这个任务花了很久,用光了12次动作预算,最后留下三个空结果:
facts.jsonl 0
claims.jsonl 0
evidence.jsonl 0看日志文件,Agent 已经把 12 个 action 全用完了:——两次 strings,一次 FLOSS,几次 literal locator,还有 PE 和反汇编相关的操作。终端一直刷状态,没死锁,模型也在正常的调用,从日志上大致看不到问题。
但事实就是,在 Agent 跑完了 12 个动作额度,最终一条能进答案的东西都没有。
看了 Agent 的模型调用记录才发现,这并非所给的"证据不足",是 runtime 对"进度"的理解出了根本性偏差————它把"动作跑完了"等质于"调查有进展",最后都一股脑塞给了模型,在提示词的强制要求下,模型不得不给出了后续完全无意义的动作。
问题的根源 ok: true
Luduan 的工具层设计里都有一个最基本的状态:调用成功还是失败。
{"ok": true}单独看这个设计,包括我在设计时,都觉得没什么问题。
但是问题就出现了,出现在当Agent将它传给了模型,模型理解为了“调查成功“。
假设 strings 正常退出,却没有任何跟当前问题相关的匹配。对进程来说,它执行得完美,没有任何问题;对调查来说,这一步啥也没改变,没获得任何有价值的线索。
好巧不巧的是,若 Planner 下一轮只收到一句:
Previous action completed successfully.那Agent就会更加坚定不移的向这个方向走。
随后进行了几轮测试,这个问题被复现了多次。
这证明了一个问题,agent 没有把两件事拆开,"动作有没有执行完" 和 "执行完以后我们新知道了什么",这是两条完全不同的指标。
把它俩混为一谈,是后面所有"假繁忙"的起点。
空结果的价值存在不确定性
这里不能硬定一条"没找到 = 没进展"。
比如已经确认搜索/调查的范围完整:只查 classes.dex 的 const-string,目标是从抓包里已经观察到的字段名。若扫完没发现匹配字段,这个 negative result 其实是有用的,它排掉了一个很具体的可能性,目标并不以明文的形式出现在这个字段中。
但下面这种就两码事:
模型猜可能是 PBKDF2
→ 全盘搜 PBKDF2
→ 没找到这一步几乎没排除什么。算法名可能动态拼接,可能在 native 层,可能压根不是 PBKDF2。这个 PBKDF2 是模型猜测的,这样一来这个动作就更没有什么价值。
所以"空结果"的价值只取决于两件事:scope 是否明确,query 是否有来源。 缺了任何一点,no match 往往只是一次失败的猜测。
动作预算烧得太简单
Luduan 的默认配置是max_actions=12。在这个案例中,Agent把12次全部用尽了。
设置最大动作次数来控资源,可以有效避免在一些情况下 AI 闷头乱跑。但是在甪端重,不少动作纯粹是白跑一趟,没有给调查带来任何实质变化。
于是,我在甪端的动作结果中,单独加一层类似 information_gain 的字符:
NEW_FACT
NEW_EVIDENCE
SCOPE_REDUCTION
CONFLICT
ZERO如果某条 run 长这样:
+ evidence
+ scope reduction
+ fact继续跑很合理。
如果长这样:
zero
zero
zero这时候最不该做的,就是单纯再将其给到模型,由模型自己瞎给出一个 Action。它需要的是 strategy switch,或者直白地停在 PARTIAL。
"还在忙" 的UI设计其实也有问题
在甪端还没跑通的时候,我最怕 Agent 卡住。现在反而更怕它不卡。
Analyzing...
Searching...
Inspecting...
Cross-checking...只要状态一直动,人就会天然以为系统在推进。Round 也很像进度条:4/18、8/18,总给人"快做完了"的错觉。
但 Round 只说明花了多少预算,不说明 Evidence Gap 缩了多少。
现在我反而更愿意在 UI 里看到些"不好看"的东西:
Required evidence: 3
Confirmed: 1
Unresolved: 2
Last 3 actions: zero gain因为至少它诚实。
如果系统已经连续三轮没做出任何的东西,我反而希望它告诉我,而不是在哪里继续滚动播放流畅的运行动画。
no match
还有个很实际的细节:很多 Agent 只存正结果。没找到,就不存。下一轮模型拿不到这段历史,于是又搜一次。
所以在甪端中我设计了一个特别的 observation:
operation: strings_search
scope: app-owned dex strings
query: activity_code
result: no_match
execution: completed这个不是 Claim,它不能直接被改写成"程序不存在 activity_code"。它只是在说:这个位置、这个方法,我已经看过了。
在后面案件案例中,这种记录会非常琐碎,却是防重复最便宜的方式。
结语
说到底,ok: true只代表工具没有报错,绝不代表调查有所收获。
动作预算可以约束资源消耗,但不能用来判断任务的真实进展。把执行状态和信息增益拆分开,留存 no‑match 的观测记录,把未解决的证据缺口直观暴露出来,才能避免智能体陷入看似忙碌实则原地打转的假繁忙。
取证智能体的目标不是用尽每一次动作额度,而是产出可信、可复现的调查结果。当连续多轮无法拿到新信息时,坦然停止,远比强行生成一份虚假完整的结论更加重要。