迭代逼近目标#

goal_mode 外部事件会选定接下来的某一次请求。随后一个私有评估器先报告未完成,最终报告已达成。这里演示的是控制流,而不是真实模型的评估质量。

运行#

在仓库根目录下执行:

uv run python docs/_examples/goal.py

输出包含:

Implementation and tests are complete.

这个程序在需要时使用确定性的离线模型和临时存储。它不需要 API 密钥,并由文档测试套件执行。

把执行者与审查者分开#

应用为某个即将发出的请求选择目标模式。审查者检查执行者的结果,并可以要求再试一次:

async def main() -> None:
    reviewer = ReviewModel()
    definition = SubAgentDefinition(
        name="review",
        description="verify goal completion",
        system_prompt="Inspect evidence and call report_goal_evaluation.",
        model=reviewer,
    )
    config = AgentRunConfig(session_id="goal-example", request_id="request-1")
    client = await create_agent(
        DraftModel(),
        config=config,
        extensions=[GoalExtension(definition, max_iterations=2)],
        event_dispatcher=GoalEvents(),
    )
    accepted = client.agent.emit_external_event(ExternalEvent(GOAL_MODE_EVENT_NAME, {}), config=config)
    assert accepted == ["GoalExtension"]
    result = await client.run("Implement the change with tests", config=config)
    assert reviewer.reviews == 2
    print(result.content)

这里审查者故意只报告一次缺少测试,然后接受第二次作答。在真实的工作流中,应让它检查具体的证据,而不是接受执行者的说法。请用迭代次数上限来限制继续执行,并为用户提供取消的途径;评估器并不能保证结果正确。

完整源码#

下载 goal.py。

  1"""Run a bounded goal review using the normal Agent as a private evaluator."""
  2
  3import asyncio
  4from collections.abc import AsyncIterator
  5
  6from zett_agent.agent import AgentRunConfig
  7from zett_agent.client import create_agent
  8from zett_agent.dispatcher import AgentEventDispatcher
  9from zett_agent.events import AgentEvent
 10from zett_agent.extensions.external import ExternalEvent
 11from zett_agent.extensions.goal import (
 12    GOAL_MODE_EVENT_NAME,
 13    GoalExtension,
 14)
 15from zett_agent.extensions.subagent import SubAgentDefinition
 16from zett_agent.messages import (
 17    AssistantMessage,
 18    ToolCall,
 19    ToolMessage,
 20)
 21from zett_agent.model import (
 22    ModelEvent,
 23    ModelRequest,
 24    ModelResponse,
 25    RetryOptions,
 26)
 27
 28
 29class DraftModel:
 30    retry = RetryOptions(max_retries=0)
 31
 32    def __init__(self) -> None:
 33        self.attempt = 0
 34
 35    async def stream(self, request: ModelRequest) -> AsyncIterator[ModelEvent]:
 36        self.attempt += 1
 37        answer = "A draft without tests." if self.attempt == 1 else "Implementation and tests are complete."
 38        yield ModelEvent.text(answer)
 39        yield ModelEvent.completed(ModelResponse(AssistantMessage(content=answer)))
 40
 41
 42class ReviewModel:
 43    """Script review decisions; real evaluators must inspect actual evidence."""
 44
 45    retry = RetryOptions(max_retries=0)
 46
 47    def __init__(self) -> None:
 48        self.reviews = 0
 49
 50    async def stream(self, request: ModelRequest) -> AsyncIterator[ModelEvent]:
 51        if isinstance(request.messages[-1], ToolMessage):
 52            message = AssistantMessage(content="Decision submitted.")
 53        else:
 54            self.reviews += 1
 55            achieved = self.reviews > 1
 56            message = AssistantMessage(
 57                tool_calls=(
 58                    ToolCall(
 59                        "review-1",
 60                        "report_goal_evaluation",
 61                        {
 62                            "achieved": achieved,
 63                            "summary": "Verified" if achieved else "Tests missing",
 64                            "remaining_work": [] if achieved else ["Add tests"],
 65                            "next_instruction": None if achieved else "Add and run the tests.",
 66                        },
 67                    ),
 68                )
 69            )
 70        yield ModelEvent.completed(ModelResponse(message))
 71
 72
 73class GoalEvents(AgentEventDispatcher):
 74    async def on_internal_message_started_event(self, event: AgentEvent) -> None:
 75        print("Continuing after private review")
 76
 77
 78async def main() -> None:
 79    reviewer = ReviewModel()
 80    definition = SubAgentDefinition(
 81        name="review",
 82        description="verify goal completion",
 83        system_prompt="Inspect evidence and call report_goal_evaluation.",
 84        model=reviewer,
 85    )
 86    config = AgentRunConfig(session_id="goal-example", request_id="request-1")
 87    client = await create_agent(
 88        DraftModel(),
 89        config=config,
 90        extensions=[GoalExtension(definition, max_iterations=2)],
 91        event_dispatcher=GoalEvents(),
 92    )
 93    accepted = client.agent.emit_external_event(ExternalEvent(GOAL_MODE_EVENT_NAME, {}), config=config)
 94    assert accepted == ["GoalExtension"]
 95    result = await client.run("Implement the change with tests", config=config)
 96    assert reviewer.reviews == 2
 97    print(result.content)
 98
 99
100if __name__ == "__main__":
101    asyncio.run(main())

下一步:普通的工作委派见运行一个隔离的子智能体,目标模式的选择和限制见GoalExtension。