yc1838 commited on
Commit
bcecbbe
·
1 Parent(s): dffb981

update improvement plan

Browse files
Files changed (2) hide show
  1. .codex/config.toml +15 -0
  2. IMPROVEMENT_PLAN.md +166 -233
.codex/config.toml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [mcp_servers.codegraph]
2
+ args = [
3
+ "serve",
4
+ "--mcp",
5
+ ]
6
+ command = "codegraph"
7
+
8
+ [mcp_servers.codegraph.tools.codegraph_status]
9
+ approval_mode = "approve"
10
+
11
+ [mcp_servers.codegraph.tools.codegraph_context]
12
+ approval_mode = "approve"
13
+
14
+ [mcp_servers.codegraph.tools.codegraph_explore]
15
+ approval_mode = "approve"
IMPROVEMENT_PLAN.md CHANGED
@@ -3,7 +3,9 @@
3
  > 基于 Marina Wyss "Context Engineering for AI Agents" 视频分析、Anthropic 官方博文、2026 年 5 月最新趋势研究,以及对 lilith-agent 现有代码的逐行审计。
4
  >
5
  > 日期:2026-05-22
6
- > 更新:2026-05-22(整合第一轮 review 反馈)
 
 
7
 
8
  ---
9
 
@@ -14,13 +16,13 @@
14
  - **路线 A(GAIA 提分)**:针对 GAIA benchmark 特点(466 题,全对或全错,三级难度),以最小改动换最大分数提升。当前榜首 Claude Sonnet 4.5 在 Princeton HAL 上 74.6%(有脚手架),裸模型只有 44.8%,说明 agent 框架的价值巨大。
15
  - **路线 B(追赶最新趋势)**:让 Lilith 成为架构上最先进的 agent,不只看分数,还看多 agent 编排、context 管理等能力。
16
 
17
- 下面按优先级排序,每项标注属于哪条路线。
18
 
19
  ---
20
 
21
- ## Phase 0(前置条件):Eval Pipeline 稳定化
22
 
23
- **在所有改动之前,必须先确保评估基础设施可靠、结果可复现。**
24
 
25
  ### 为什么这是 Phase 0
26
 
@@ -28,341 +30,272 @@
28
 
29
  ### 具体任务
30
 
31
- 1. **Baseline 锁定**:在当前代码(无改动)上跑 3 次完整 GAIA eval(`--split test --level 1,2,3 --limit -1`),记录每次分数和各 level 的正确率。如果三次结果波动 > 2%,先排查原因(rate limit retry、模型温度、随机工具失败等)。
32
- 2. **Checkpoint 清理规范**:确保 `--force` 模式行为正确——删除 `.checkpoints/` 下对应文件后重跑避免checkpoint 污染结果。
 
 
 
 
 
 
33
  3. **Eval 报告自动化**:每次 eval 后自动生成 JSON 报告,包含:
34
  - 总正确率、各 level 正确率
35
  - 每题的 tool call 数、耗时、是否触发 fail_safe
36
  - 与上次 run 的 diff(新增正确 / 新增错误的题目列表)
37
- 4. **回归检测**:维护一个 `golden_set`(约 20 题,覆盖各 level 和各工具组合),Phase 1/2/3 的每次 PR 都必须在 golden_set 上 pass 才能合并。
38
 
39
  ### 涉及文件
40
 
41
- - `src/lilith_agent/runner.py`:`run_agent_on_questions()` 增加统计输出
 
 
42
  - 新增:`scripts/eval_report.py`(生成对比报告)
43
  - 新增:`tests/golden_set.json`(稳定题目子集)
44
 
45
  ---
46
 
47
- ## P0里程碑感知压缩(Milestone-Based Compaction)
48
 
49
- **路线:A + B | 预估 GAIA 提升:+2-4%**
50
 
51
- ### 问题
52
 
53
- 当前 `_compact_old_tool_messages()` 按位置压缩——保留最近 4 条 ToolMessage,老 cheap model 总结或截断这是"时间盲":不管 agent 是否完成了一个子任务压缩都机械地按顺序来Level 2/3 题通常需要 15-25 步,后半段会丢失前面关键发现
54
 
55
- 研究数据支撑:arxiv 2604.20911 显示,没有记忆缓解措施时,constraint compliance 从 turn 5 73% 降到 turn 16 的 33%
 
56
 
57
- ### 实现思路
58
 
59
- `src/lilith_agent/app.py` `_compact_old_tool_messages()` 基础上改造:
60
 
61
- 1. **子任务边界检测(用 cheap model,不用关键词匹配)**
62
- 在 model_node 中,每次 agent 产出 AIMessage 后,调用 cheap model 做一次二分类判断:"这条回复是否标志着一个子任务的完成?"返回 yes/no + 一句话摘要。
63
 
64
- **不用关键词匹配的原因**:agent 回复中英文混合,"找到了 X"、"The result is Y"、"根据以上分析"等模式太多太碎,关键词方案脆弱且维护成本高。cheap model 做分类判断更靠谱,虽然多一次 API call,但里程碑检测本身只在长对话中触发(短对话不需要压缩),一次 cheap call 的成本相对可控。
65
 
66
- 实现方式:
67
- ```python
68
- _MILESTONE_DETECT_PROMPT = (
69
- "Does this agent message indicate completion of a sub-task or discovery of a key fact? "
70
- "Answer JSON: {\"is_milestone\": true/false, \"summary\": \"one-line summary if true\"}"
71
- )
72
- ```
73
 
74
- 2. **里程碑摘要生成**:当 cheap model 判断 `is_milestone=true` 时,将其 summary 包装为结构化标记注入消息流:
75
- ```
76
- [MILESTONE @ step N]
77
- - 已完成:{summary}
78
- - 下一步 agent 自行决定
79
- ```
80
- 3. **压缩时保留里程碑**:修改 `_compact_old_tool_messages()` 逻辑——以 `[MILESTONE` 开头的消息永远不被压缩普通 ToolMessage 正常压缩。这样即使在 turn 20,agent 仍然能看turn 3 发现的关键事实
81
- 4. **可选:接入 Anthropic Compaction API**(`compact-2026-01-12`目前 beta)替代自研总结逻辑。注意 beta 状态有稳定性风险,建议作为可选后端。
 
 
82
 
83
  ### 涉及文件
84
 
85
- - `src/lilith_agent/app.py`:`_compact_old_tool_messages()`、`model_node()`
86
- - 新增`_detect_milestone()` 函数(调用 cheap model 做二分类)
87
 
88
  ---
89
 
90
- ## P1Sub-Agent 架构
91
 
92
- **路线:A(Level 3 题)+ B | 预估 GAIA 提升:+2-3%**
93
 
94
  ### 问题
95
 
96
- Lilith 本质是单 agent 循环Supervisor 只是一个 cheap model 做的旁观者,不能分派子任务对于 Level 3 题(需要数十步 + 多种工具)单 agent 在长链推理中不避免地遭遇 "lost in the middle" 效应
97
-
98
- Anthropic 自己的研究表明,子 agent 各自在干净的 context window 中做深度探索,最后只返回 1000-2000 token 的浓缩摘要,在复杂研究任务上表现显著优于单 agent。
99
 
100
  ### 实现思路
101
 
102
- 利用 LangGraph 现有能力,在 `build_react_agent()` 中增加子 agent 调度:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- 1. **新增 `spawn_sub_agent` 工具**:主 agent 可以调用这个工具,传入一个聚焦的子任务描述和任务类型(如 `type="research"` 或 `type="compute"`),spawn 一个独立的 ReAct agent 实例:
105
- - 子 agent 有自己干净的 context window
106
- - **精简工具集(按任务类型裁剪)**:子 agent 不应该拿到全部工具,工具越多走偏概率越大。按类型分配:
107
- - `research` 类型:`web_search`, `fetch_url`, `read_file`, `inspect_pdf`
108
- - `compute` 类型:`run_python`, `read_file`, `write_file`
109
- - `vision` 类型:`inspect_visual_content`, `read_file`
110
- - 所有类型都**不包含** `spawn_sub_agent`(防止递归爆炸,depth=1 硬限制)
111
- - 子 agent 有独立的、更小的 budget(如 cap=10)
112
- - **摘要长度按任务类型动态调整**:`research` 类型可能需要更多空间来传递多个发现(≤3000 chars),`compute` 类型通常一个数字就够了(≤500 chars)。不用一刀切 2000 chars。
113
- 2. **主 agent 综合结果**:子 agent 的摘要作为 ToolMessage 返回给主 agent,主 agent 基于多个子 agent 的汇报做最终推理。
114
- 3. **并行 vs 串行**:初期实现串行 spawn(简单可靠),后续可考虑并行。
115
 
116
  ### 涉及文件
117
 
118
- - `src/lilith_agent/app.py`:`build_react_agent()` 中注册新工具
119
- - 新增:`src/lilith_agent/tools/sub_agent.py`(包含工具集裁剪逻辑
120
- - `src/lilith_agent/config.py`:新增 `sub_agent_budget`、`sub_agent_summary_caps` 等配置
121
-
122
- ### 注意事项
123
 
124
- - agent 不应该再 spawn agent(防止递归爆炸)加一个 depth=1 限制
125
- - GAIA 的 Level 1 题不需要子 agent,可以通过 supervisor 或 heuristic 判断何时触发
126
- - 子 agent 的 system prompt 应该更聚焦:只描述子任务目标,不包含主 agent 的完整指令集
127
 
128
  ---
129
 
130
- ## P2经验反思学习(ERL)
131
 
132
- **路线:A | 预估 GAIA 提升:+5-8%**
133
 
134
  ### 问题
135
 
136
- Lilith `memory.py` 有长期记忆存储SQLite),但只存事实性记忆没有"从失败中学习"的反思机制每次任务都从零开始,不会利用过往任务经验
137
 
138
- ERL(arxiv 2603.24639)在 GAIA2 上比 ReAct baseline 提高了 7.8%,且完全在 prompt-time 运行,不需要梯度更新。
139
-
140
- ### 澄清:ERL 不是强化学习
141
-
142
- 尽管名字里有 "Learning",ERL 不涉及 reward signal 或参数更新。流程是:
143
- 1. 跑完一个任务后,让 LLM 回顾轨迹(成功或失败)
144
- 2. 提炼出文字形式的启发式规则(heuristics),例如:
145
- - "遇到 Wikipedia 表格数据时,用 `run_python` + pandas 解析比直接读文本更准确"
146
- - "当搜索返回付费墙页面时,立即换搜索词而非重试同一 URL"
147
- - "多步数学题必须在 Python 中验证,不要心算"
148
- 3. 将规则存入数据库,标注适用的任务类型/关键词
149
- 4. 下次遇到类似任务时,检索相关规则注入 system prompt
150
-
151
- ### 实现思路(分两步:先验证上限,再自动化)
152
-
153
- **Step 1:Golden Heuristics 验证上限(1-2 天)**
154
-
155
- 在投入自动化反思管线之前,先手动验证 ERL 的潜力上限:
156
 
157
- 1. 手动挑选 20-30 条高质量 heuristics,源包括:
158
- - 分析 `.last_failures.txt` 中的失败题目轨迹,人工总结失败原因
159
- - 复盘已有的成功题目,提取可复用的策略
160
- - 参考 ERL 论文中的 heuristic 示例
161
- 2. 将这些 golden heuristics 硬编码注入 system prompt
162
- 3. 跑一轮完整 GAIA eval,对比 baseline
163
- 4. 如果提升 < 2%,需要重新审视检索精度和规则质量,再决定是否投入 Step 2
164
 
165
- **Step 2:自动化反思管线**
 
 
 
 
166
 
167
- 上限足够高之后再搭建:
168
-
169
- 1. **任务后反思**(Post-Task Reflection):在 `runner.py` 的 `run_agent_on_questions` 中,每个任务完成后(无论成功失败),调用 cheap model 分析轨迹,生成 heuristics。
170
- 2. **规则存储**:在 `memory.py` 的 `MemoryStore` 中新增 `heuristics` 表:
171
- ```sql
172
- CREATE TABLE heuristics (
173
- id TEXT PRIMARY KEY,
174
- rule TEXT NOT NULL, -- 启发式规则文本
175
- source_task_id TEXT, -- 来源任务
176
- success BOOLEAN, -- 该任务是否成功
177
- keywords TEXT, -- 适用关键词(用于检索)
178
- times_applied INTEGER DEFAULT 0, -- 被检索注入的次数
179
- times_helped INTEGER DEFAULT 0, -- 注入后任务成功的次数
180
- times_hurt INTEGER DEFAULT 0, -- 注入后任务失败的次数
181
- confidence REAL DEFAULT 0.5, -- 动态置信度 = helped / (helped + hurt)
182
- created_at TEXT,
183
- retired_at TEXT -- 被淘汰的时间(NULL = 活跃)
184
- );
185
- ```
186
- 3. **规则检索与注入**:在 `model_node()` 的 iteration 0 阶段,除了现有的 `retrieve_relevant_context()` 之外,额外检索匹配的 heuristics 并注入 system prompt。只注入 `confidence >= 0.4` 且 `retired_at IS NULL` 的规则。
187
- 4. **规则淘汰机制(必须在 Step 2 一开始就设计好)**:
188
- - 每次任务结束后,回溯本次注入了哪些 heuristics,更新 `times_applied`、`times_helped` 或 `times_hurt`
189
- - 当 `confidence < 0.3` 且 `times_applied >= 5` 时,自动 retire(设置 `retired_at`)
190
- - 保留 retired 规则不删除(方便分析),但不再注入
191
- - 定期(每 50 个任务)输出一次规则健康报告:活跃/退役/低置信度分布
192
-
193
- **为什么淘汰机制要早做**:低质量规则积累起来会污染 system prompt。一条错误的 heuristic(如"Wikipedia 表格总是在第二个 section")可能让 agent 在本来能做对的题上反而出错。
194
 
195
  ### 涉及文件
196
 
197
- - `src/lilith_agent/memory.py`:扩展 `MemoryStore`,新增 heuristics 表和淘汰逻辑
198
- - `src/lilith_agent/runner.py`:任务后反思 + heuristic 效果追踪
199
- - `src/lilith_agent/app.py`:`model_node()` 中的规则注入(带置信度过滤)
200
- - 新增:`src/lilith_agent/reflection.py`(反思逻辑独立模块)
201
- - 新增:`scripts/heuristic_health_report.py`(规则健康报告)
202
 
203
  ---
204
 
205
- ## P3Supervisor 升 Strong Model
206
 
207
- **路线:A | 预估 GAIA 提升:+1-2%**
208
 
209
  ### 问题
210
 
211
- 当前 supervisor 用的 cheap model判断质量有限特别是在 Level 2/3 题上cheap model 可能无法准确评估 agent 是否已经收集到足够证据
212
 
213
  ### 实现思路
214
 
215
- 在 `src/lilith_agent/app.py` 的 `build_react_agent()`
216
 
217
- 1. `supervisor_model = get_cheap_model(cfg)` 改为 `supervisor_model = get_extra_strong_model(cfg)` 或新增一个 `get_strong_model(cfg)` 中间档
218
- 2. 由于 strong model 更贵可以提高 supervisor 触发阈值:`_SUPERVISOR_MIN_TOOL_CALLS` 5 提到 8,减少不必要的调用
219
- 3. 同时给 supervisor prompt 更明确的评判标准比如:
220
- - "如果 agent 已经找到了一个具体数字/名字/日期且该答案与已收集的证据一致 status=finalize"
221
- - "如果 agent 在最近 3 次 tool call 中没有获得新信息,则 status=finalize"
222
 
223
  ### 涉及文件
224
 
225
- - `src/lilith_agent/app.py`:`build_react_agent()` 中的 supervisor 初始化
226
- - `src/lilith_agent/config.py`:新增 `supervisor_model_tier` 配置(cheap/strong/extra_strong)
227
 
228
  ---
229
 
230
- ## P4fetch_url 结果二次清洗
231
 
232
- **路线:A | 预估 GAIA 提升:+0.5-1%**
233
 
234
  ### 问题
235
 
236
- `fetch_url` trafilatura 提取正文后截断到 `max_chars=8000`。但 trafilatura 输出常还残留航栏文字、cookie 提示、重复 header、社交分享按钮文字等噪音。同样 8000 字符,噪音越少有效信息密度越高。
237
 
238
- ### 实现思路
239
 
240
- `src/lilith_agent/tools/web.py` `fetch_url` 函数中,trafilatura 提取之后、截断之前,加一步轻量清洗。
241
-
242
- **Noise patterns 外置成配置文件**(不硬编码在函数里):
243
-
244
- ```yaml
245
- # config/noise_patterns.yaml
246
- # 不同语言的页面噪音模式差异大,外置方便维护和扩展
247
- en:
248
- - cookie
249
- - privacy policy
250
- - terms of service
251
- - subscribe
252
- - newsletter
253
- - follow us
254
- - share on
255
- - tweet this
256
- - skip to content
257
- - advertisement
258
- - sponsored
259
- zh:
260
- - 隐私政策
261
- - 使用条款
262
- - 订阅
263
- - 关注我们
264
- - 分享到
265
- - 跳转到主内容
266
- - 广告
267
- ```
268
 
269
- 清洗函数从配置文件读patterns:
270
-
271
- ```python
272
- import yaml
273
- from pathlib import Path
274
-
275
- _NOISE_CONFIG = Path(__file__).parent.parent / "config" / "noise_patterns.yaml"
276
-
277
- def _load_noise_patterns() -> list[str]:
278
- """Load all noise patterns from config, flattened across languages."""
279
- if not _NOISE_CONFIG.exists():
280
- return [] # graceful fallback: no cleaning if config missing
281
- with open(_NOISE_CONFIG) as f:
282
- data = yaml.safe_load(f) or {}
283
- patterns = []
284
- for lang_patterns in data.values():
285
- if isinstance(lang_patterns, list):
286
- patterns.extend(lang_patterns)
287
- return patterns
288
-
289
- def _post_clean(text: str) -> str:
290
- """Remove common trafilatura residual noise."""
291
- noise_patterns = _load_noise_patterns()
292
- lines = text.split('\n')
293
- cleaned = []
294
- for line in lines:
295
- stripped = line.strip()
296
- if not stripped or len(stripped) < 3:
297
- continue
298
- lower = stripped.lower()
299
- if any(p in lower for p in noise_patterns) and len(stripped) < 80:
300
- continue
301
- cleaned.append(line)
302
- return '\n'.join(cleaned)
303
- ```
304
 
305
  ### 涉及文件
306
 
307
- - `src/lilith_agent/tools/web.py`:`fetch_url()` / `_fetch_url()`
308
- - 新增:`src/lilith_agent/config/noise_patterns.yaml`(噪音模式配置)
 
 
309
 
310
  ---
311
 
312
- ## P5动态 Budget 管理
313
 
314
- **路线:A | 预估 GAIA 提升:+0.5-1%**
315
 
316
  ### 问题
317
 
318
- 当前 `budget_hard_cap=25` `budget_warn_at=15` 是固定值,不区分题目难度。Level 1通常 3-5 步就能回答,但 agent能因不够果断而用掉 10+ 步Level 3 题可能真的需要 30+ 步
319
 
320
  ### 实现思路
321
 
322
- 1. 在任务开始时,让 model 或 cheap model 快速评估目难度(Level 1/2/3 风格)设置对应的 budget:
323
- - 简单题:warn=8, cap=12
324
- - 中等题warn=15, cap=25当前默认
325
- - 复杂题warn=25, cap=40(合更积极压缩)
326
- 2. 或者更简单如果 GAIA 数据集本身带 level 标签,直接用标签设 budget。
 
 
 
 
327
 
328
  ### 涉及文件
329
 
330
- - `src/lilith_agent/app.py`:`_route_after_model()``model_node()`
331
- - `src/lilith_agent/config.py`:新增 per-level budget 配置
332
- - `src/lilith_agent/runner.py`:传递 level 信息给 agent
333
 
334
  ---
335
 
336
  ## 实施顺序建议
337
 
338
  ```
339
- Phase 0(前置条件,2-3 天)
340
- ── Eval Pipeline 稳定化
341
- ├── 3 次 baseline锁定当前分数
342
- ── 搭建 eval 报告脚本
343
- └── 建立 golden_set 回归测试
344
 
345
  Phase 1(快速见效,1-2 周)
346
- ├── P3:Supervisor 升级(改一行代码 + prompt)
347
- ├── P4:fetch_url 清洗(加函数 + 外置 noise config
348
- ├── P5:动态 Budget(按 level 调参数)
349
- └── ⚡ 跑完整 GAIA eval,对比 Phase 0 baseline
350
-
351
- Phase 2(核心改造,2-4 周)
352
- ├── P2 Step 1Golden Heuristics 手动验证1-2
353
- │ └── 如果提升 < 2%,暂停 P2重新审视
354
- ├── P0:里程碑压缩(cheap model 做分类 + 改造 compaction)
355
- ├── P2 Step 2:自动化反思管线(含淘汰机制)
356
  └── ⚡ 跑完整 GAIA eval,对比 Phase 1
357
 
358
- Phase 3(架构升级,3-5 周)
359
- ├── P1:Sub-Agent (精简工具集 + 动态摘要上限)
360
- ── 跑完整 GAIA eval,对比 Phase 2
 
361
  ```
362
 
363
- **关键原则**:每个 Phase 结束时必须跑完整 GAIA eval。如果某个改动导致 golden_set 回归,立即 revert 并分析原因,不带入下一个 Phase
364
-
365
- Phase 0 是所有后续工作的基础。Phase 1 的三项改动都很小、风险低,适合快速验证。Phase 2 的 ERL 先用手动 golden heuristics 验上限再决定是否投入自动化——避免花两周搭管线结果发现提升不大。Phase 3 改动最大但对 Level 3 长链题帮助最显著。
366
 
367
  ---
368
 
 
3
  > 基于 Marina Wyss "Context Engineering for AI Agents" 视频分析、Anthropic 官方博文、2026 年 5 月最新趋势研究,以及对 lilith-agent 现有代码的逐行审计。
4
  >
5
  > 日期:2026-05-22
6
+ > 更新:2026-05-23(整合深度 Code Review 反馈与工程落地可行性调整
7
+
8
+ > **Review note:** 以下新增的 `Review note` 只补充 repo 审计后发现的工程落地风险,不删除或改写原计划内容;实现时应把这些 caveat 当作验收条件的一部分。
9
 
10
  ---
11
 
 
16
  - **路线 A(GAIA 提分)**:针对 GAIA benchmark 特点(466 题,全对或全错,三级难度),以最小改动换最大分数提升。当前榜首 Claude Sonnet 4.5 在 Princeton HAL 上 74.6%(有脚手架),裸模型只有 44.8%,说明 agent 框架的价值巨大。
17
  - **路线 B(追赶最新趋势)**:让 Lilith 成为架构上最先进的 agent,不只看分数,还看多 agent 编排、context 管理等能力。
18
 
19
+ 下面按最新的执行顺排列,每项标注属于哪条路线。
20
 
21
  ---
22
 
23
+ ## Phase 0(前置条件):Eval Pipeline 稳定化与 Blockers 修复
24
 
25
+ **在所有改动之前,必须先确保评估基础设施可靠、结果可复现,同时修复目前存在的严重状态泄露和参数解析 Bug。**
26
 
27
  ### 为什么这是 Phase 0
28
 
 
30
 
31
  ### 具体任务
32
 
33
+ 1. **修复 Blockers**:
34
+ - **`--force` 状态泄露**:当前仅删除 JSON 文件,未清理 checkpointer 的 SQLite persistence。旧 thread state 在 SQLite 中依然存活,会严重污染重跑结果。
35
+ - **CLI `--level` 解析错误**:`dev_run_gaia.py` 传入的是字符串,而数据集匹配需要严格类型,导致 `--level 1,2,3` 匹配出空集。
36
+ > **Review note:** repo 当前在 `gaia_dataset.py` 中已经把 `row.get("Level")` 和 `level` 都转成字符串比较;真正的缺口不是严格类型,而是 `--level 1,2,3` / `--level all` 这类多 level 输入没有被解析成集合过滤。
37
+ - **`scoring API split` 冲突**:`os.getenv("GAIA_DATASET_SPLIT","test")` 的 fallback 逻辑会与本地 validation runs 冲突,也可能影响 leaderboard 提交脚本,需显式隔离。
38
+ - **Checkpoint 职责分离**:当前的 checkpoint 混杂了 leaderboard payload 和 debug 状态。需要剥离 metadata 到 `runs/<run_id>/<task_id>.json` 中。
39
+ > **Review note:** 如果 metadata 或 per-run checkpoint 迁移到 `runs/<run_id>/...`,必须同步更新 `scripts/build_leaderboard_submission.py` 和相关测试;该脚本当前只从单一 checkpoint 目录 glob `*.json` 生成 submission。
40
+ 2. **Baseline 锁定与回归**:跑 3 次精简的 stratified golden set (约 20 题,覆盖各 level) 和 1 次 full GAIA eval,记录分数和各 level 的正确率。
41
  3. **Eval 报告自动化**:每次 eval 后自动生成 JSON 报告,包含:
42
  - 总正确率、各 level 正确率
43
  - 每题的 tool call 数、耗时、是否触发 fail_safe
44
  - 与上次 run 的 diff(新增正确 / 新增错误的题目列表)
 
45
 
46
  ### 涉及文件
47
 
48
+ - `src/lilith_agent/runner.py`:`run_agent_on_questions()` 增加统计输出与 env var 修复
49
+ - `src/lilith_agent/app.py`:修复 checkpointer clear 逻辑
50
+ - `scripts/dev_run_gaia.py`:修复 level parse 逻辑
51
  - 新增:`scripts/eval_report.py`(生成对比报告)
52
  - 新增:`tests/golden_set.json`(稳定题目子集)
53
 
54
  ---
55
 
56
+ ## Phase 0.5Normalizer 鲁棒性审计
57
 
58
+ **路线:A | 预估 GAIA 提升:免费加分项**
59
 
60
+ ### 问题与思路
61
 
62
+ GAIA 评分是严格exact-match如果经历了复杂多步推理,仅仅因为提取��答案多了一个空格、或者大小写不匹配而丢分是非常不划算的在进行任何复杂的架构改动前,提升答案 Normalizer保真度(fidelity)是最便宜的"免费加分项"
63
 
64
+ 1. 审计并强化 Supervisor`best_answer` 提取逻辑
65
+ 2. 确保对比与最终提取时,正确处理空白字符、大小写归一化及标点符号过滤。
66
 
67
+ ---
68
 
69
+ ## P3:Supervisor 升级与安全拦截 (Guard)
70
 
71
+ **路线:A | 预估 GAIA 提升:+1-2%**
 
72
 
73
+ ### 问题
74
 
75
+ 当前 supervisor 用的是 cheap model,判断质量有限。特别是在 Level 2/3 题上,cheap model 可能无法准确评估 agent 是否已经收集到足够的证据。此外,它可能会错误地抽取出诸如 "unknown", "N/A" 的 placeholder,导致提前放弃任务。
 
 
 
 
 
 
76
 
77
+ ### 实现思路
78
+
79
+ `src/lilith_agent/app.py` `build_react_agent()` 中:
80
+
81
+ 1. **模型升级** `supervisor_model = get_cheap_model(cfg)` 改为 `supervisor_model = get_extra_strong_model(cfg)` 或新增一个 `get_strong_model(cfg)` 中间档。
82
+ 2. **安全拦截 (Placeholder Guard)**:增加护栏(Guard)逻辑,如果 Supervisor 提取出 "unknown/n/a" 等无意义的 placeholder,强制拒绝结束任务,要求 agent 继续探索。
83
+ 3. **阈值调整**:由于 strong model 更贵提高 supervisor 触发阈值:`_SUPERVISOR_MIN_TOOL_CALLS` 5 8
84
+ 4. 同时给 supervisor prompt 加入更明确的评判标准比如:
85
+ - "如果 agent 已经找到了一个具体的数字/名字/日期,且该答案与已收集的证据一致,则 status=finalize"
86
+ - "如果 agent 在最近 3 次 tool call 中没有获得新信息,则 status=finalize"
87
 
88
  ### 涉及文件
89
 
90
+ - `src/lilith_agent/app.py`:`build_react_agent()` 中的 supervisor 初始化与 guard 逻辑
91
+ - `src/lilith_agent/config.py`:新增 `supervisor_model_tier` 配置
92
 
93
  ---
94
 
95
+ ## P4fetch_url 结果二次清洗
96
 
97
+ **路线:A | 预估 GAIA 提升:+0.5-1%**
98
 
99
  ### 问题
100
 
101
+ `fetch_url` 提取正文后截断到 `max_chars=8000`但网页输出经常残留导航栏、cookie 提示、重复 header 等噪音同样 8000 字符噪音越少有效信息密度越高。当前逻辑能只处理了 trafilatura fallback,遗漏了 Jina Reader 主路径
 
 
102
 
103
  ### 实现思路
104
 
105
+ `src/lilith_agent/tools/web.py` `fetch_url` 函数,对 Jina Reader 和 trafilatura 提取的结果,在截断之前,加一步���量清洗。
106
+
107
+ **Noise patterns 外置成 JSON 配置文件**(不使用 YAML,避免引入新依赖):
108
+
109
+ ```json
110
+ {
111
+ "en": [
112
+ "cookie",
113
+ "privacy policy",
114
+ "terms of service",
115
+ "subscribe",
116
+ "newsletter",
117
+ "follow us",
118
+ "share on",
119
+ "tweet this",
120
+ "skip to content",
121
+ "advertisement",
122
+ "sponsored"
123
+ ],
124
+ "zh": [
125
+ "隐私政策",
126
+ "使用条款",
127
+ "订阅",
128
+ "关注我们",
129
+ "分享到",
130
+ "跳转到主内容",
131
+ "广告"
132
+ ]
133
+ }
134
+ ```
135
 
136
+ 清洗函数从 JSON 配置文件读取 patterns 进行清洗。
 
 
 
 
 
 
 
 
 
 
137
 
138
  ### 涉及文件
139
 
140
+ - `src/lilith_agent/tools/web.py`:`fetch_url()` / `_fetch_url()`
141
+ - 新增:`src/lilith_agent/config/noise_patterns.json`(噪音模式配置
 
 
 
142
 
143
+ > **Review note:** `src/lilith_agent/config.py` 目前是模块文件,`pyproject.toml` 也没有 package-data 配置;如果把 JSON 放到 `src/lilith_agent/config/noise_patterns.json`,打包后可能无法被可靠读取。优先考虑放到明确的 packaged data 路径或同步补充 setuptools package-data 配置与读取测试。
 
 
144
 
145
  ---
146
 
147
+ ## P5动态 Budget 管理
148
 
149
+ **路线:A | 预估 GAIA 提升:+0.5-1%**
150
 
151
  ### 问题
152
 
153
+ 当前 `budget_hard_cap=25` `budget_warn_at=15` 是全局配置固定值),不区分题目难度。Level 1 题通常 3-5 步就能回答而 Level 3 可能需要 30+ 步由于 graph 编译一次性,无法在 runtime 随意修改 cfg
154
 
155
+ ### 实现思路
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
+ 放弃修改 cfg,直接在 `AgentState` 中新增 field 管理。放弃调用模型来猜测难度。
 
 
 
 
 
 
158
 
159
+ 1. **直接使用 Level 标签**:在任务开始时,直接读取 GAIA 数据集自带的 Level 标签。
160
+ 2. **状态驱动的 Budget**:在 `AgentState` 内维护 `current_budget_warn` 和 `current_budget_cap`。
161
+ - Level 1:warn=8, cap=12
162
+ - Level 2:warn=15, cap=25
163
+ - Level 3:warn=25, cap=40(配合更积极的压缩)
164
 
165
+ > **Review note:** 需要一个统一的 state-derived budget helper 同时驱动 `model_node()` 的 warning prompt、`_route_after_model()` 的 hard cap,以及 graph compile 时的 recursion sizing;只在 `AgentState` 加字段会留下 cfg 默值继续生效的路径。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
  ### 涉及文件
168
 
169
+ - `src/lilith_agent/app.py`:`AgentState` 定义,路由逻辑 `_route_after_model()`
170
+ - `src/lilith_agent/runner.py`:传递 level 标签到状态中
 
 
 
171
 
172
  ---
173
 
174
+ ## P0状态里程碑感知压缩(State-Level Milestone)
175
 
176
+ **路线:A + B | 预估 GAIA 提升:+2-4%**
177
 
178
  ### 问题
179
 
180
+ 当前 `_compact_old_tool_messages()` 按位置压缩,这"时间盲"的会丢失关键发现如果直接往消息流强行插入 `SystemMessage` 来标记里程碑会破坏 `AIMessage(tool_calls)` `ToolMessage` 必须相邻 LLM 厂商协议,极易触发 API 400 报错
181
 
182
  ### 实现思路
183
 
184
+ 在 `src/lilith_agent/app.py` 中改造,**绝不直接向消息流插入标记**,而是维护一个独立的事实账本。
185
 
186
+ 1. **State-Level Ledger**:在 `AgentState` 新增一个独立的 `facts_ledger` 列表
187
+ 2. **复用压缩器检测以控制成本**:为了节省 extra cheap model 调用不在每次 AIMessage 产出时检测。将里程碑检测逻辑合并到已有的 compaction summarizer 流程中,或者当 `tool_calls >= 6` 时才触发检测。炼出的关键事实追加`facts_ledger` 中
188
+ 3. **注入上下文**:在生成 prompt 时,将 `facts_ledger` 作为整体系统上下文注到前端保证早期的关键发现不会被后续的时间盲压缩丢失。
189
+ > **Review note:** `facts_ledger` 来源是 tool/web 输出属于 untrusted evidence不应被提升成高优先级指令。实现时要用明确的 evidence wrapper、保留来源/provenance,并增加恶意网页内容不能注入系统指令的测试。
190
+ 4. **可选:接入 Anthropic Compaction API** 替代自研总结逻辑。
191
 
192
  ### 涉及文件
193
 
194
+ - `src/lilith_agent/app.py`:`AgentState` 定义、`_compact_old_tool_messages()` 改造
 
195
 
196
  ---
197
 
198
+ ## P2经验反思学习(ERL)
199
 
200
+ **路线:A | 预估 GAIA 提升:+5-8%**
201
 
202
  ### 问题
203
 
204
+ Lilith 当前的 `ephemeral_memory` 会在任务结束后被完全清空,无法跨任务继承验,致无法实现"从失败中学习"。ERL(arxiv 2603.24639)在 GAIA2 上比 baseline 提了 7.8%,且完全在 prompt-time 运行
205
 
206
+ ### 实现思路(分两步)
207
 
208
+ **Step 1:Golden Heuristics 验证上限(1-2 天)**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
+ 1. 人工挑选 20-30 条高质量 heuristics(分析 `.last_failures.txt` 失败轨迹提),写入 JSON 格式的种子文件。
211
+ 2. 直接注入 system prompt,跑一轮 stratified golden eval,验证 ERL 在当前架构下的理论上限。若提升 < 2%,需重新审视。
212
+
213
+ **Step 2:自动化反思管线与独立持久化**
214
+
215
+ 1. **独立持久化 DB**:新增 `src/lilith_agent/heuristics.py`,建立独立的 SQLite 表(不与 ephemeral memory 混用),记录 rule、成功率等统计数据。
216
+ ```sql
217
+ CREATE TABLE heuristics (
218
+ id TEXT PRIMARY KEY,
219
+ rule TEXT NOT NULL,
220
+ source_task_id TEXT,
221
+ success BOOLEAN,
222
+ keywords TEXT,
223
+ times_applied INTEGER DEFAULT 0,
224
+ times_helped INTEGER DEFAULT 0,
225
+ times_hurt INTEGER DEFAULT 0,
226
+ confidence REAL DEFAULT 0.5,
227
+ created_at TEXT,
228
+ retired_at TEXT
229
+ );
230
+ ```
231
+ 2. **任务后反思**:`run_agent_on_questions` 结束后,不管成功失败,调用 cheap model 分析轨迹,生成规则并存入。
232
+ > **Review note:** `run_agent_on_questions()` 当前没有 ground-truth success signal;validation/golden 以外的 leaderboard/test split 任务不能可靠判断 `success`、`times_helped`、`times_hurt`。自动学习应限制在有 expected answer / 显式 scoring 结果的 run,或把 unlabeled run 只作为候选规则来源而不更新置信度。
233
+ 3. **规则检索与自动淘汰**:每次任务记录 applied heuristic IDs;当 `confidence < 0.3` 且 `times_applied >= 5` 时,自动 retire。必须在起步阶段就做好淘汰机制,防止低质量规则污染 prompt。
 
 
 
 
 
 
 
 
 
 
 
234
 
235
  ### 涉及文件
236
 
237
+ - 新增:`src/lilith_agent/heuristics.py`(独立持久化存储)
238
+ - `src/lilith_agent/runner.py`:任务后反思调用与 heuristic 效果追踪
239
+ - `src/lilith_agent/app.py`:`model_node()` 中的规则检索与注入
240
+ - 新增:`scripts/heuristic_health_report.py`(规则健康报告)
241
 
242
  ---
243
 
244
+ ## P1Sub-Agent 架构
245
 
246
+ **路线:A(Level 3 题)+ B | 预估 GAIA 提升:+2-3%**
247
 
248
  ### 问题
249
 
250
+ agent 在几十步的 Level 3中极易"lost in the middle"。引入独立 context 的子代理以缓解。但当前工具注册机制(如 `build_tools`)较monolithic,直接引入会导致循环依赖同时,所有任务共享同一线程 state 会导致严重污染
251
 
252
  ### 实现思路
253
 
254
+ 必须先解决工程底座问题,才能安全引入 `spawn_sub_agent`。
255
+
256
+ 1. **前置重构工具与 Agent 解耦**:重构 `build_react_agent()` 和 `build_tools()` 的绑定关系。工具构建必须支持按需裁剪如 `build_tools(cfg, allowed_names)`,解决循环依赖。
257
+ 2. **Checkpointer 隔离** Agent **绝不能**使用主线程的同一个 SQLite checkpointer。必须为子任务分独立 `in-memory checkpointer`,或唯一的 `child thread ID`,或设为无持久化状态,确保上下文纯净。
258
+ 3. **硬限制保护**
259
+ - 最大深度:`depth=1`,防止递归爆炸。
260
+ - 操作限制:子代理禁止调用 `write_file`,除非明确分配。
261
+ - 独立的 budget 和 timeout。
262
+ 4. **精简的子工具集与动态摘要**:子 agent 根据任务类型(research, compute, vision)拿到裁剪后的纯净工具集。返回摘要时按任务类型动态限制长度(research ≤ 3000 chars, compute ≤ 500 chars),汇总回主代理。
263
 
264
  ### 涉及文件
265
 
266
+ - `src/lilith_agent/app.py`:解耦并重构工具组装注册新工具
267
+ - 新增:`src/lilith_agent/tools/sub_agent.py`(包含工具集裁剪逻辑)
268
+ - `src/lilith_agent/config.py`:新增子代理配置
269
 
270
  ---
271
 
272
  ## 实施顺序建议
273
 
274
  ```
275
+ Phase 0 & 0.5基础设施与提分低垂果实,2-3 天)
276
+ ── 修复所有 Blockers (状态泄露, CLI bug)
277
+ ├── 剥离 Checkpoint Metadata跑 Baseline
278
+ ── 强化 Normalizer 和 best_answer 提取逻辑
 
279
 
280
  Phase 1(快速见效,1-2 周)
281
+ ├── P3:强模型 Supervisor + Placeholder Guard
282
+ ├── P4:fetch_url 清洗(覆盖 Jina 主路径,JSON 配置
283
+ ├── P5:基于 Level AgentState Budget 控制
284
+ └── ⚡ 跑完整 GAIA eval,对比 baseline
285
+
286
+ Phase 2(状态记忆与反思,2-4 周)
287
+ ├── P0State-level 里程碑事实提炼复用 Summarizer 控制成本
288
+ ── P2 Step 1:建立独立持久化 DBJSON 注入验证 Golden ERL 上限
289
+ ├── P2 Step 2:自动化任务后反思与淘汰管线
 
290
  └── ⚡ 跑完整 GAIA eval,对比 Phase 1
291
 
292
+ Phase 3(高���架构,3-5 周)
293
+ ├── P1 前置:重Tool Registry,解耦循环依赖
294
+ ── P1 核心:Checkpointer 隔离与 Sub-agent 实现
295
+ └── ⚡ 跑完整 GAIA eval,验收最终成果
296
  ```
297
 
298
+ **关键原则**:每个 Phase 结束时必须跑评估。如果改动导致 golden_set 回归,立即 revert 并分析。
 
 
299
 
300
  ---
301