You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Trajectory / Experience 经验学习框架重构
1. 总体定位
当前框架把
experiences目录视为一个可优化的 Experience Policy Set:目录中的每个 experience 文件是一个
Experience,整个目录共同构成 agent 的经验策略。训练框架不直接绑定某个 agent loop;它只约束以下抽象链路:其中
PolicyTrainer是训练入口。默认本地实现会在进程内执行analyze -> estimate -> plan -> apply;远程实现可以把 rollout 通过session.commit提交给 OpenViking 服务端,由服务端完成分析和训练。1.1 训练执行细节图
这张图强调三个实现边界:
ExperienceSet.lock()内的reload -> PolicyOptimizer.plan -> PolicyUpdater.apply必须串行。RolloutAnalyzer;experience 读取/合并/写入发生在 optimizer/updater;session archive 和memory_diff.json只出现在session.commit路径。ExtractLoop,包括 trajectory 抽取、experience gradient 估计和 patch merge。2. 代码结构
当前模块结构:
设计边界:
components/放所有具体实现。openviking.session.train顶层继续导出常用类,便于外部使用。3. 核心 Domain Model
3.1 Experience / ExperienceSet
Experience对应 experiences 目录下的一个 experience 文件。ExperienceSet是某个 experiences 根目录的快照:当前实现中,
ExperienceSet还负责提供并发安全能力:约定:
root_uri是 experiences 目录 URI。policies是当前目录下所有 experience 文件解析后的快照。viking_fs/request_context是运行时依赖,用于lock()和reload(),不参与 equality/repr。PolicyTrainingEngine.plan_and_apply(...)会先加 policy tree lock,再 reload 最新 policy set,然后 plan/apply。3.2 Trajectory
Trajectory是从 rollout 中抽取并持久化的可训练轨迹样本,对应 trajectories 目录下的 memory 文件。约定:
Rollout是原始执行记录。Trajectory是从 rollout messages 中抽取出的训练样本。TrajectoryRolloutAnalyzer通过ExtractLoop + MemoryUpdater写入memories/trajectories。3.3 Case / Rubric
Case是可执行、可复现、可评估的训练/评测样例。Rubric定义“什么叫做好”和“怎么检查”。当前不再保留独立Outcome概念。3.4 Rollout
Rollout是某个 policy snapshot 在某个 case 上执行后的记录。当前关键变化:
Rollout.evaluation是一等可选字段。RolloutExecutor应直接填入rollout.evaluation。TrajectoryRolloutAnalyzer优先沿用rollout.evaluation;没有时才通过注入的RolloutEvaluator评估;再没有时用“是否抽取到 trajectory”作为 fallback evaluation。pipeline.eval(...)不再调用RolloutAnalyzer,只依赖RolloutExecutor返回的rollout.evaluation;如果 eval rollout 缺 evaluation,会直接报错。3.5 RubricEvaluation
在 tau2 集成中:
passed = reward >= 1.0score = rewardaccuracy = passed_count / case_count为主,average_reward为辅助指标。4. SemanticGradient
SemanticGradient是针对一个目标 experience 的语义更新信号。当前接口以MemoryFilebefore/after 表达,而不是文本 patch 对象。当前具体实现:
约定:
before_file is None表示建议新建。after_file是建议的目标 memory file 状态。PatchMergeContextProvider在 merge 阶段把 before/after memory file 渲染为字段级 unified diff。5. PolicyUpdatePlan / PolicyUpdater
PolicyOptimizer.plan(...)输出PolicyUpdatePlan,PolicyUpdater.apply(...)负责真正写文件。当前
MemoryFilePolicyUpdater支持:upsert_experiencedelete_experiencebefore_content的轻量 base-content guard,避免覆盖已发散内容。6. 接口定义
6.1 CaseLoader
实现:
ListCaseLoaderRemoteCaseLoader:通过 HTTP 服务拉取 cases。6.2 RolloutExecutor
实现:
SingleTurnLLMRolloutExecutorRemoteRolloutExecutorTau2RolloutExecutor(benchmark/tau2 内部实现,通过 tau2 service 暴露给训练流程)6.3 RolloutEvaluator
用途:环境不能直接提供
rollout.evaluation时,RolloutAnalyzer可注入 evaluator 进行评估。6.4 RolloutAnalyzer
当前实现:
TrajectoryRolloutAnalyzer。职责:
rollout.evaluationRolloutEvaluatorAgentTrajectoryContextProvider + ExtractLoop只抽取trajectoriesmemory type。MemoryUpdater.apply_operations(...)写入 trajectory memory。RolloutAnalysis。6.5 GradientEstimator
当前实现:
ExperienceGradientEstimator。它复用:
AgentExperienceContextProviderExtractLoopMemoryIsolationHandler(allowed_memory_types={"experiences"})但不调用
MemoryUpdater.apply_operations(...)。它把 ExtractLoop 产生的 upsert operations 转成PatchSemanticGradient。6.6 PolicyOptimizer
当前实现:
PatchMergePolicyOptimizer。它不按 target 分组限制输出,而是把一批 gradients 一次性交给
PatchMergeContextProvider + ExtractLoop进行全局 merge。LLM 可以:6.7 PolicyUpdater
实现:
DryRunPolicyUpdaterMemoryFilePolicyUpdater6.8 PolicyTrainer
实现:
BatchPolicyTrainer:显式 batch,本地执行 analyze/estimate/plan/apply。StreamingPolicyTrainer:实时 rollout 输入,先 analyze/estimate,再按梯度数量和时间窗口攒批,批量 plan/apply。SessionCommitPolicyTrainer:把 rollout 写入远端 OpenViking session,通过session.commit让服务端完成训练。6.9 PolicyOptimizationPipeline
当前实现:
OfflinePolicyOptimizationPipeline。7. PipelineContext / ExecutionContext
max_epochs是训练迭代次数。之前文档中的max_iterations已改为 epoch 概念。8. 训练流程
8.1 OfflinePolicyOptimizationPipeline.train
默认
policy_trainer是BatchPolicyTrainer,因此本地训练链路为:8.2 OfflinePolicyOptimizationPipeline.eval
eval 阶段不会调用
RolloutAnalyzer,不会抽 trajectory,也不会写 policy。它要求RolloutExecutor返回带evaluation的 rollout。8.3 train_from_rollouts
实时场景或外部系统已经产生 rollout 时,可以绕过
CaseLoader / PolicySnapshotter / RolloutExecutor:约束:每个 rollout 必须包含
case。9. Batch 与 Streaming
9.1 BatchPolicyTrainer
适合离线训练,输入一批 rollout 后直接完成一次:
9.2 StreamingPolicyTrainer
适合实时 commit / 并发 rollout 场景。
流程:
flush 触发条件:
max_gradients_per_update达到阈值max_wait_secondsclose()时 flush 剩余内容默认配置:
进程内全局共享:
并发安全由
PolicyTrainingEngine.plan_and_apply(...)中的ExperienceSet.lock()保证。10. Patch Merge 机制
10.1 PatchSemanticGradient 到 PatchMergePatch
PatchMergePolicyOptimizer会把每个SemanticGradient转为:10.2 PatchMergeContextProvider
位置:
openviking/session/memory/patch_merge_context_provider.py职责:
MemoryFilebefore/after 渲染为字段级 unified diff。输入文件选择:
字段 diff 规则:
content已在Field Diff: content中展示,因此不会额外在 metadata 中重复塞完整 content。10.3 PatchMergePolicyOptimizer
输出支持:
merge 输入/输出日志通过
tracer.info(..., console=False)记录,避免默认污染 console。11. session.commit 实时训练接入
SessionCompressorV3已把用户记忆抽取和实时训练接起来。11.1 用户记忆抽取
SessionCompressorV3._extract_user_memories(...):ExtractLoop抽取用户记忆。cases。StreamingMemoryUpdater做 patch merge 写入用户记忆。archive_uri,写入memory_diff.json,其中包含顶层trace_id。memory_diff.json顶层结构包含:{ "archive_uri": "...", "trace_id": "...", "extracted_at": "...", "operations": {...}, "summary": {...} }11.2 从 cases 触发 streaming train
SessionCompressorV3.train_from_extracted_cases(...):即真实 session.commit 产生的对话可以被转为 rollout 输入训练框架。
12. SessionCommitPolicyTrainer:远程服务端训练
SessionCommitPolicyTrainer是一个PolicyTrainer实现,用于“训练框架在外部,OpenViking 服务端负责训练”的场景。它会把 rollout 写成一个临时 session:
其中:
CaseSpec放在开头,只含 case/rubric/task context,不含 evaluation。OutcomeEvaluation放在最后,只含 evaluation,作为训练信号。ToolPart的tool_output上传,而不是普通 text。然后执行:
CaseSpec 会做精简,避免传入巨大或重复字段:
policydata_rootrollout_metadatapolicy_snapshot_iddomain/split/data_split/task_id/task_no/user_query/ground_truth/rubric13. Remote HTTP 组件
components/remote.py提供通用 HTTP 组件:RemoteCaseLoaderRemoteRolloutExecutor它们面向一个环境/benchmark service:
其中
/v1/rollouts/execute只负责提交单个 case 的 rollout execution,返回execution_id;RemoteRolloutExecutor会并发提交多个 case,并通过/v1/rollouts/executions/{execution_id}轮询状态。这样长耗时 rollout 不会占用一个超长 HTTP request,也便于未来 benchmark service 做多机部署和负载均衡。
这样训练框架不需要直接依赖 tau2 或其他 benchmark 的代码,只依赖通用
Case/Rollout JSON 协议。
14. tau2 集成
14.1 架构
当前 tau2 训练分为两个进程:
14.2 tau2 service
位置:
启动:
14.3 remote train/eval
位置:
示例:
输出以 accuracy 为主:
14.4 tau2 rollout messages
Tau2RolloutExecutor会把工具结果转成真正的ToolPart:{ "type": "tool", "tool_id": "tau2-tool-0", "tool_name": "get_reservation_details", "tool_input": {...}, "tool_output": "...", "tool_status": "completed" }这样上传到
session.commit后,服务端可以复用已有 tool output 外部化和 memory extraction 逻辑。15. tau2 接入新评测框架示意图
tau2 的接入方式体现了推荐的 benchmark 集成模式:benchmark runtime 独立成 HTTP service,训练框架只通过通用
RemoteCaseLoader/RemoteRolloutExecutor接入。图中需要特别注意:tau2 runtime service 虽然不负责训练写入,但它执行 rollout 时会通过 VikingBot / OpenViking tools 读取当前 OpenViking memories。因此 final_eval 能看到 train epoch 后写入的最新 experiences。
15.1 接入分层
15.2 train/eval 时序
15.3 为什么 eval 不走 RolloutAnalyzer
在 tau2 场景中,环境执行完 rollout 后可以直接给出 reward,因此
Tau2RolloutExecutor会返回:所以
OfflinePolicyOptimizationPipeline.eval(...)只统计rollout.evaluation:eval 不抽 trajectory、不估计 gradient、不写 experience。
15.4 训练如何通过 session.commit 进入服务端
SessionCommitPolicyTrainer会把 rollout 转成临时 session messages:其中:
CaseSpec放在开头,只描述任务和 rubric,不包含 evaluation。OutcomeEvaluation放在最后,作为训练信号。ToolPart.tool_output上传,服务端可以复用已有 tool output 外部化和 memory extraction 逻辑。15.5 指标展示
tau2 runner 的报告以正确率为主:
average_reward保留为辅助指标;主指标是accuracy。15.6 以 tau2 为例:新场景接入需要实现的接口
一个新的 benchmark / domain / environment 接入训练评测框架时,推荐复用 tau2
的分层方式:把场景 runtime 独立成一个 HTTP service,训练进程继续使用通用
RemoteCaseLoader/RemoteRolloutExecutor。训练框架不关心场景内部怎么启动agent、怎么调用工具、怎么计算 reward,只要求 service 实现下面这些协议。
15.6.1 Case 查询接口
请求:
{ "dataset": "tau2", "domain": "airline", "split": "train", "cursor": null, "limit": 100, "filters": {} }响应:
{ "cases": [ { "name": "tau2_airline_train_0", "task_signature": "tau2:airline:train:0", "input": { "domain": "airline", "split": "train", "task_id": "0", "task_no": 0, "user_query": "...", "ground_truth": "..." }, "rubric": { "name": "tau2_airline_train_0_rubric", "description": "...", "criteria": [ { "name": "tau2_reward", "description": "The tau2 environment reward is 1.0.", "required": true, "weight": 1.0, "metadata": {} } ], "metadata": {} }, "metadata": { "dataset": "tau2", "domain": "airline", "source": "tau2", "split": "train" } } ], "next_cursor": "100" }接入要求:
dataset/domain/split用于定位数据集切片。cursor/limit用于分页;没有下一页时next_cursor = null。Case.input只放 rollout 必需的任务输入和场景元信息,不要塞训练框架已经能从上下文拿到的内容,例如完整 system prompt、完整 rollout metadata、evaluation
结果或 policy snapshot。
Case.rubric必须能描述评测目标;如果环境能直接给 reward,也仍然要提供rubric,便于训练侧把 reward 转成统一的
RubricEvaluation。tau2 中对应实现是:
15.6.2 Rollout 提交接口
请求:
{ "case": { "...": "Case JSON" }, "policy_set": { "root_uri": "viking://user/default/memories/experiences", "policies": [], "metadata": {} }, "execution_context": { "policy_snapshot_id": "tau2-policy-snapshot:...", "metadata": { "epoch": 0, "training": true } }, "options": { "config_path": "/path/to/ov.conf", "max_iterations": 30, "keep_default_tools": true, "rollout_language": "default" } }响应:
{ "execution_id": "rollout_exec_...", "status": "running", "case_name": "tau2_airline_train_0", "created_at": 1781097747.0, "updated_at": 1781097747.0, "error": null }接入要求:
worker 或机器。
policy_set.root_uri告诉 runtime 当前 experiences 根目录;tau2 rollout 期间VikingBot 会通过 OpenViking recall 读取这里的最新经验。
execution_context.policy_snapshot_id必须原样写入返回的Rollout.policy_snapshot_id,用于追踪这次 rollout 使用的是哪次 policy snapshot。
tau2 中对应实现是:
15.6.3 Rollout 状态轮询接口
运行中响应:
{ "execution_id": "rollout_exec_...", "status": "running", "case_name": "tau2_airline_train_0", "created_at": 1781097747.0, "updated_at": 1781097750.0, "error": null }完成响应:
{ "execution_id": "rollout_exec_...", "status": "completed", "case_name": "tau2_airline_train_0", "created_at": 1781097747.0, "updated_at": 1781097760.0, "error": null, "rollout": { "case": { "...": "Case JSON" }, "messages": [ { "role": "user", "parts": [ { "type": "text", "text": "..." } ] }, { "role": "assistant", "parts": [ { "type": "tool", "tool_id": "tau2-tool-0", "tool_name": "get_reservation_details", "tool_input": {"reservation_id": "EHGLP3"}, "tool_output": "...", "tool_status": "completed" } ] } ], "policy_snapshot_id": "tau2-policy-snapshot:...", "evaluation": { "passed": false, "score": 0.0, "criterion_results": [ { "criterion_name": "tau2_reward", "passed": false, "score": 0.0, "feedback": ["tau2 environment reward is below 1.0."], "evidence": [], "metadata": {"reward": 0.0} } ], "feedback": ["tau2 environment reward is below 1.0."], "metadata": { "source": "tau2_executor", "reward": 0.0 } }, "metadata": { "memory": "...", "tools_used": [], "iterations": 6 } } }失败响应:
{ "execution_id": "rollout_exec_...", "status": "failed", "case_name": "tau2_airline_train_0", "created_at": 1781097747.0, "updated_at": 1781097752.0, "error": "..." }接入要求:
status至少支持running/completed/failed。completed时必须返回完整rollout。failed时必须返回可读error,训练侧会把它归入该 case 的 rollout 失败。Rollout.messages应使用 OpenVikingMessage/Part结构;工具调用和工具结果用
ToolPart,不要把tool-call:\nname: ...塞进普通 text content。Rollout.evaluation在 eval 阶段是必需字段;如果没有 evaluation,OfflinePolicyOptimizationPipeline.eval(...)会失败。15.6.4 RolloutExecutor 内部职责
新场景自己的 rollout executor 需要完成这些事情:
Case.input初始化环境和用户模拟器。policy_set.root_uri/ OpenViking 配置让 agent 读取当前 experiences。RubricEvaluation。Rollout:tau2 的
Tau2RolloutExecutor就是这个适配层:它一侧依赖 tau2/VikingBot runtime,另一侧只输出训练框架理解的
Rollout。15.6.5 最小接入清单
接入一个新场景,最少需要实现:
POST /v1/cases/queryCase[]POST /v1/rollouts/executeGET /v1/rollouts/executions/{execution_id}RolloutRubricEvaluation转换Message/ToolPart转换GET /health如果新场景不想提供 HTTP service,也可以在同进程内直接实现
CaseLoader/RolloutExecutorProtocol;但跨进程、多机或重 runtime 依赖的场景,推荐采用 tau2 这种 service 方式。
16. 当前主要组件清单
OfflinePolicyOptimizationPipelinepipeline.pyPolicyTrainingEngineengine.pyListCaseLoadercomponents/case_loader.pyRemoteCaseLoadercomponents/remote.pyRemoteRolloutExecutorcomponents/remote.pySingleTurnLLMRolloutExecutorcomponents/rollout_executor.pyTrajectoryRolloutAnalyzercomponents/trajectory_analyzer.pyExperienceGradientEstimatorcomponents/gradient_estimator.pyPatchMergePolicyOptimizercomponents/policy_optimizer.pyDryRunPolicyUpdatercomponents/policy_updater.pyMemoryFilePolicyUpdatercomponents/policy_updater.pyBatchPolicyTrainercomponents/policy_trainer.pyStreamingPolicyTrainercomponents/policy_trainer.pySessionCommitPolicyTrainercomponents/session_commit.pyContentHashPolicySnapshottercomponents/snapshotter.pyExperienceSetLoadercomponents/memory_store.py17. 端到端本地训练伪代码
18. 设计原则
Case是训练/评测样本,不再使用Outcome概念。Rubric定义验收标准;RubricEvaluation是一次 rollout 的评估结果。Rollout保留原始执行消息和可选 evaluation;Trajectory是从 rollout 中抽取的可训练样本。SemanticGradient是 memory-file before/after 级别的语义更新信号。PolicyOptimizer只规划,不写文件;PolicyUpdater才是写入边界。PolicyTrainingEngine。ExperienceSet.lock() + reload()串行化 optimizer/apply 阶段。RemoteCaseLoader / RemoteRolloutExecutor,不要让训练框架直接依赖 benchmark runtime。All reactions