跳到主要内容
版本:0.10(最新)

Goal

GoalMiddleware 让 agent 自主运行直到完成条件满足为止。一个独立的 评估模型(例如 Haiku)来判断条件是否达成——不让工作模型自己给自己 打分。

灵感来自 Claude Code 的 /goal 命令:设定一个条件,让 agent 干活, 直到第二个模型说条件满足时停下。

基础用法

from cubepi import Agent
from cubepi.providers.anthropic import AnthropicProvider
from cubepi.middleware.goal import GoalMiddleware

provider = AnthropicProvider(api_key="...")

goal = GoalMiddleware(
evaluator=provider.model("claude-haiku-4-5-20251001"),
max_evaluations=10,
)

agent = Agent(
model=provider.model("claude-sonnet-4-6"),
middleware=[goal],
tools=[...],
)

# /goal 前缀激活 goal 模式
await agent.prompt("/goal all tests in tests/auth pass and ruff check is clean")

# 查看结果
print(agent.state.extra["goal"])
# {"status": "achieved", "condition": "all tests in ...", "evaluations": 2, ...}

工作方式

激活

用户消息以 /goal 开头时 GoalMiddleware 激活。前缀之后的全部内容是 完成条件。

# Goal 模式——评估模型会判断这个条件
await agent.prompt("/goal make the homepage load in under 2 seconds")

# 普通模式——中间件完全透明
await agent.prompt("fix the bug in auth.py")

/goal 前缀在 worker 看到消息前被剥离。worker 只拿到条件文本作为 工作指令。

评估循环

每次 worker 跑完一次完整 run(所有 tool 调用都用尽)之后:

  1. 评估模型读条件 + 对话的最后 20 条消息。
  2. 通过 structured output 返回 {achieved: bool, reason: str}
  3. 如果 achieved——循环结束,状态是 "achieved"
  4. 如果 not achieved 且还有评估次数——把反馈 ("Goal not yet met: {reason}. Continue working.")注入回去, worker 继续。
  5. 如果到 max_evaluations——循环结束,状态是 "exhausted"
Worker run → on_run_end → 评估模型判断
├─ achieved=True → 停(状态:"achieved")
├─ achieved=False → 注入反馈,继续
└─ 达到最大评估次数 → 停(状态:"exhausted")

参数

参数类型默认说明
evaluatorBoundModel必填判断条件的模型
max_evaluationsint10评估调用次数的安全上限

evaluator 建议用便宜快速的模型(如 Haiku)。它只读对话脚本——不能 调工具。

读取结果

agent.prompt() 返回后,看 agent.state.extra["goal"]

goal_state = agent.state.extra["goal"]

match goal_state["status"]:
case "achieved":
print(f"Done in {goal_state['evaluations']} evaluations")
print(f"Reason: {goal_state['last_reason']}")
case "exhausted":
print(f"Gave up after {goal_state['max_evaluations']} evaluations")
print(f"Last reason: {goal_state['last_reason']}")

完整的状态结构:

{
"status": "achieved" | "active" | "exhausted",
"condition": "all tests pass...",
"evaluations": 3,
"max_evaluations": 10,
"last_reason": "2 tests still failing in test_auth.py",
}

Tracing

GoalMiddleware 通过 extra_llm_calls() 声明自己的 evaluator,所以 tracing 的 Recorder 能订阅 evaluator 的 provider 并正确归属评估 span ——它们会作为 evaluator 的调用出现,而不是 worker 的调用。

小贴士

  • 条件要具体、可验证。 "All tests pass" 比 "code works well" 好得多。 evaluator 是从对话脚本判断的,不是真的去跑工具。
  • 用便宜的 evaluator。 Haiku 通常足够——判断是二选一(达成与否) 加一句简短理由。
  • max_evaluations 设保守点。 默认 10 防止失控循环。只有当你确实 需要多次迭代时才提高。
  • 可以和其他中间件叠加。 GoalMiddleware 通过标准中间件组合规则 与 TodoListMiddleware、compaction 等组合。