AgentBrew代码研读 / 10月28日
正在恢复本地记录…

今天,把AgentBrew的数据流读通。

从一条真实轨迹开始,追到任务回推、动作信用与评测。每一段都对应作者源码和一个可检查的产出。

完整路线约180分钟,按实际理解分段完成。

开始第一段 / 15分钟

八段研读清单

  1. 1

    认清一条轨迹

    区分模型决策、工具结果与最终回答,画出原始JSON的数据形状。

    产出:用自己的话写出tasks[0]里的四个关键字段。
    15分钟
  2. 2

    找准程序入口

    从启动脚本、YAML一路追到Runner和Agent工厂。

    产出:写出一条采集命令对应的脚本、配置、调度器、Agent类。
    20分钟
  3. 3

    追一次工具调用

    从Agent主循环追到模型文本、结构化action与MCP工具结果。

    产出:画出一轮循环并注明三个停止或异常情况。
    25分钟
  4. 4

    回推实际目标

    沿distill_task理解过滤、成功工具证据、变化摘要与任务改写。

    产出:举一个三项任务只完成两项的例子,写出合理的新目标。
    25分钟
  5. 5

    算懂动作信用

    明确评分对象,手算相邻差分,并解释best_prefix的基线更新。

    产出:先手算[1.8,1.9,1.6],再到实验页修改第二个值核对。
    30分钟
  6. 6

    把信用贴回动作

    用两个索引把工具结果上的信用对应回生成动作的模型事件。

    产出:指出pending_action_index与tool_index分别索引哪一份列表。
    20分钟
  7. 7

    看懂批处理边界

    理解并发、断点续跑、原子写回和原始数据保护。

    产出:列出真正运行蒸馏前需要保留的输入与记录。
    25分钟
  8. 8

    划清训练与评测

    区分任务运行完成、verifier评价、信用生成和论文加权训练。

    产出:写一段不超过150字的端到端数据流说明,标出未公开的训练阶段。
    20分钟

先看一条轨迹的形状

15分钟参考

从Tracer认识模型动作和工具反馈,弄清离线学习的数据从哪里来。

agentbrew/tracing

tracer.py

108行
下载原文
1"""Minimal tracer compatible with migrated agents."""
2
3from __future__ import annotations
4
5import json
6import time
7import uuid
8from contextlib import contextmanager
9from pathlib import Path
10from typing import Any
11
12
13class Tracer:
14 """Collect internal spans and training-ready agent trajectory events."""
15
16 def __init__(
17 self,
18 trace_id: str | None = None,
19 *,
20 include_prompts: bool = False,
21 ) -> None:
22 self.trace_id = trace_id or str(uuid.uuid4())
23 self.include_prompts = include_prompts
24 self.records: list[dict[str, Any]] = []
25 self.trajectory: list[dict[str, Any]] = []
26
27 @contextmanager
28 def sprout(self):
29 child = self.__class__(
30 trace_id=self.trace_id,
31 include_prompts=self.include_prompts,
32 )
33 child.add({"type": "span_start", "timestamp": time.time()})
34 try:
35 yield child
36 finally:
37 self.records.extend(child.records)
38 self.trajectory.extend(child.trajectory)
39
40 def add(self, data: dict[str, Any]) -> None:
41 self.records.append({"timestamp": time.time(), "data": data})
42
43 def record_llm(
44 self,
45 parsed_response: dict[str, Any],
46 *,
47 messages: list[dict[str, Any]] | None = None,
48 response: Any = None,
49 ) -> None:
50 """Record one main-agent decision."""
51 event = {
52 "state": "llm",
53 "timestamp": time.time(),
54 "parsed_response": parsed_response,
55 }
56 if self.include_prompts:
57 event["messages"] = messages or []
58 event["response"] = response
59 self.trajectory.append(event)
60
61 def record_tool(
62 self,
63 *,
64 server: str,
65 tool_name: str,
66 arguments: dict[str, Any],
67 content: str,
68 is_error: bool,
69 ) -> None:
70 """Record one tool result."""
71 self.trajectory.append(
72 {
73 "state": "tool",
74 "timestamp": time.time(),
75 "server": server,
76 "tool_name": tool_name,
77 "arguments": arguments,
78 "content": content,
79 "isError": is_error,
80 }
81 )
82
83 def write_trajectory(
84 self,
85 path: str | Path,
86 *,
87 task_id: str,
88 question: str,
89 final_answer: str,
90 ) -> Path:
91 """Write one task trajectory in the legacy-compatible format."""
92 output_path = Path(path)
93 output_path.parent.mkdir(parents=True, exist_ok=True)
94 payload = {
95 "tasks": [
96 {
97 "task_id": task_id,
98 "question": question,
99 "final_answer": final_answer,
100 "trajectory": self.trajectory,
101 }
102 ]
103 }
104 output_path.write_text(
105 json.dumps(payload, ensure_ascii=False, indent=2) + "\n",
106 encoding="utf-8",
107 )
108 return output_path
作者原文 / SHA256已核验L43-59

在完整仓库中查找

今天怎样读这份代码

从一个数据结构开始

今天的任务是读AgentBrew代码。先在第一段找到模型事件和工具事件,再沿研读路线读到离线蒸馏。8段参考时长共180分钟,可分几轮完成;核心路线保留数据契约、任务回推、信用分配与对齐。

三块区域,一次只解决一个问题

左侧选路线或全仓文件;中间读作者原文;右侧看中文解释、结构索引与自己的笔记。窄屏用“目录”和“查看讲解”切换区域。每一项功能都可离线使用。

覆盖范围

原始文件
795
内嵌文本
632
Python文件
185
二进制资产
163
中文教学注释
82处 / 21文件
类与函数索引
1,189

文本、配置、提示词、sql与空文件都在全仓目录。163个二进制资产以清单、大小、SHA256和原文件下载收录;完整ZIP包含795个文件。其他文件有用途或作者文档字符串,未冒充逐行人工注释。

页面不执行作者Python、访问真实工具或请求模型。三个机制演示使用教学样本,不构成论文训练复现。

术语表
trajectory
交错保存的模型决策与工具事件;不要与压缩给下一轮模型的history混淆。
hindsight_task
根据已有工具结果回推的任务指令;不是补执行失败子任务。
retrospective_task
独立任务回推模块使用的字段名,信用模块也接受hindsight_task。
L_minus_1_prior
没有观察工具动作时,参考模型预测同一个回推任务的平均token NLL。
L_prefix
看到当前工具前缀后,对固定回推任务的NLL。
credit
原始动作信用,可正可负;不等同于已归一化的训练权重。
previous
adjacent算法中的前一NLL,每轮都会更新。
baseline
best_prefix使用的基线,负信用时保留旧值。
pending_action_index
原交错轨迹中,等待工具结果的llm动作位置。
tool_index
当前消费到带信用工具列表的哪个位置。
valid_index
在过滤错误步骤之后的成功步骤序列中读取NLL/信用的位置。
Semaphore
限制同一类并发工作的数量;async with离开后释放名额。
gather
并发等待多个协程,返回结果按输入顺序组织。
await
等待异步操作完成,让事件循环有机会运行其他协程。
isError
工具错误标记,部分环境会结合返回内容重新判断。
include_prompts
决定是否把完整模型提示/响应额外写进轨迹事件。
evaluation
是否调用独立任务验证器的配置。
state
事件类型或运行状态,具体含义要看所在数据结构;tool/llm指轨迹事件类型。
RuntimeState
某次任务或采样准备得到的环境资源与上下文状态。
model_validate
Pydantic根据字段类型与规则把输入数据校验为配置对象。
os.replace
同文件系统内用临时文件替换目标的原子写回关键步骤。
CREDIT_METHODS
字符串到算法函数的映射,函数在Python里也可以作为字典值。
max_iterations
Agent允许的最大迭代次数;达到上限不等同于任务成功。
history_window_steps
保留近期完整步骤的窗口长度;较早步骤由摘要补充。
echo
评分请求要求回显已给定prompt及其token概率,而非只看新生成文本。
logprobs
token的对数概率,取负并平均得到实现中的NLL。
text_offset
返回token在文本中的字符偏移,用来定位目标任务部分。

记录与导出

笔记、书签、自评和自检答案仅保存在当前浏览器。可以导出JSON后换设备合并,也能导出Markdown笔记。导入不匹配提交的记录会被拒绝。页面不会上传你的学习内容。

下载逐文件SHA256清单 下载全部原始文件