跳转到内容

持续目标跨轮次保持

持续目标跨轮次保持

学习目标

理解 Nanobot 如何通过 Session metadata 和 goal_state 实现跨 Turn 的长程目标保持,以及目标续传机制。

前置知识

下文假设你已理解上述概念,直接聚焦 Nanobot 的具体实现。

项目实践

Goal State 存储模型

目标状态存储在 Session metadata 中:

session.metadata["_goal_state"] = {
"objective": "分析项目代码并编写文档",
"status": "active", # active | completed | abandoned
"steps": [
{"description": "读取 README", "status": "done"},
{"description": "编写教程", "status": "in_progress"}
],
"wall_timeout": 300.0, # 超时秒数
"created_at": "2026-05-15T..."
}

跨轮次注入

当目标处于 active 状态时,AgentRunner 在每个 Turn 的 final response 阶段检查目标并注入续传消息:

if not injections and allow_goal_continue and assistant_message is not None:
predicate = spec.goal_active_predicate
if predicate is not None and predicate():
injections = [build_goal_continue_message(spec.goal_continue_message)]

注入的消息格式:

You have an active sustained goal:
Objective: 分析项目代码并编写文档
Steps: 2/2 completed
Please continue working toward the objective using your tools,
or call complete_goal if the work is truly finished.

超时管理

每个目标有独立的超时限制(NANOBOT_LLM_TIMEOUT_S),当目标活跃时可以突破默认的超时限制:

llm_timeout_s=runner_wall_llm_timeout_s(
self.sessions,
session.key,
metadata=session.metadata,
)

这允许长程目标合法地超过普通对话的超时阈值。

问题与规避

目标完成检测

问题:如何判断一个持续目标已完成?

规避:Agent 通过 complete_goal 工具明确标记完成,或者当 LLM 在续传消息后不再调用任何工具时,目标自然终止。

设计取舍

为什么将目标存储在 Session metadata 而非独立文件

原因:Session metadata 已经通过原子写入和 fsync 保证了持久化,复用同一存储避免了额外的文件系统复杂性和一致性问题。

参考来源