2026年10月4日 2 分钟阅读

Go Agent 一旦崩溃就重跑?Agent SDK for Go 用持久化执行接住中断

tinyash 0 条评论

许多 AI Agent 的问题不在于不会调用模型,而在于任务太长:它已经完成了检索、调用工具和部分写入,进程却因为部署、超时或机器重启中断。下一次启动后,Agent 往往只能从头再来,重复消耗模型额度,也可能重复执行有副作用的工具。

Agent SDK for Go 针对的正是这个运行时问题。它是 Apache-2.0 开源 Go SDK,提供 Agent、LLM、工具、MCP、子代理和人工审批等接口;更关键的是,本地运行时默认启用持久化执行,也可以切换到 Temporal 或 Restate 做分布式执行。项目 README 标注要求 Go 1.26+,实际接入前应以仓库最新说明为准。

先区分:持久化执行不是聊天记录

普通的多轮会话保存的是消息;持久化执行还要记录一次运行中已经完成的步骤、工具调用和事件偏移量。这样进程重启后,系统可以恢复运行,而不是再次执行已经完成的工作。

Agent SDK for Go 将运行时做成可替换配置:本地模式适合单进程和零基础设施场景;Temporal 适合把客户端触发和 Worker 执行拆开;Restate 则提供另一种分布式执行方案。三者不是模型能力的差异,而是可靠性和部署边界的差异。

最小示例:先把 Agent 跑起来

官方 Quick Start 使用 agent.NewAgent 创建 Agent,再通过 Run 启动任务、用 Get 等待结果:

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/agenticenv/agent-sdk-go/pkg/agent"
    "github.com/agenticenv/agent-sdk-go/pkg/llm"
    "github.com/agenticenv/agent-sdk-go/pkg/llm/openai"
)

func main() {
    llmClient, _ := openai.NewClient(
        llm.WithAPIKey(os.Getenv("OPENAI_API_KEY")),
        llm.WithModel("gpt-4o"),
    )

    a, _ := agent.NewAgent(
        agent.WithSystemPrompt("You are a helpful assistant."),
        agent.WithLLMClient(llmClient),
    )
    defer a.Close()

    run, _ := a.Run(context.Background(), "Reply with a short greeting.", nil)
    result, _ := run.Get(context.Background())
    fmt.Println(result.Content)
}

生产代码当然不应忽略错误;这里省略错误处理只是为了突出生命周期。SDK 的本地运行时默认把日志写入 ./agent_data/。如果需要调整目录、自动清理周期或超时,可以配置 local.LocalConfig;如果明确不需要日志,也可以选择 local.DurabilityOff()。

长任务为什么应该使用 Stream

Run 适合等待最终结果,但代码审查、文档分析和多工具编排通常需要实时进度。SDK 提供 Stream,通过事件流输出文本增量、工具调用和生命周期事件:

stream, _ := a.Stream(
    context.Background(),
    "Write a four-line poem about the ocean.",
    nil,
)

events, _ := stream.Events(context.Background())
for event := range events {
    switch e := event.(type) {
    case *agent.AgentTextMessageContentEvent:
        fmt.Print(e.Delta)
    case *agent.AgentToolCallStartEvent:
        fmt.Println("\n[tool call]", e.ToolCallName)
    }
}

需要审批时,事件流还可以解析自定义审批事件,并用 stream.Approve 回传批准结果。这个设计比在业务层轮询一个布尔字段更稳妥:审批、工具调用和文本输出都在同一条事件语义里。

分布式场景:用 Temporal 或 Restate 承接执行

当 Agent 从单机服务升级为多个 Worker,关键是保存运行 ID 和事件偏移量。官方示例使用 GetAgentStream 重新取得流,并通过 agent.WithOffset 从保存的位置继续消费:

savedRunID := stream.ID()
// 把 savedRunID 持久化后,再消费事件。

savedOffset := int64(0)
s, _ := a.GetAgentStream(context.Background(), savedRunID)
ch, _ := s.Events(context.Background(), agent.WithOffset(savedOffset))
for event := range ch {
    _ = event
}

Temporal 配置通过 temporal.WithTemporalConfig 注入,Restate 则使用 restate.WithRestateConfig;两者互斥。不要因为“支持分布式”就默认需要它们:如果 Agent 仍然是单进程服务,本地持久化模式更简单,也更容易排错。

接入时的三个边界

第一,幂等性仍然由业务负责。持久化执行能减少重复步骤,但“发送邮件”“扣款”“创建工单”这类副作用操作,仍应使用幂等键或业务去重。

第二,恢复不等于无限重试。为每个操作设置超时和最大尝试次数,并为 LLM 失败准备明确的 fallback 策略。

第三,审批要靠策略而不是示例代码。Quick Start 为演示可以自动批准,但真实系统应根据工具类型、用户身份和预算阈值决定是否放行。

如果你的 Go Agent 已经开始执行长任务,Agent SDK for Go 值得作为运行时层评估:它把本地持久化、流式事件和可替换的分布式后端放进同一套接口,先用零基础设施模式验证业务,再按可靠性需求逐步升级。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。