Agent 示例

流式响应

实时显示 Agent 的输出流

流式响应示例

展示如何实时接收和显示 Agent 的流式输出。

完整代码

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/astercloud/aster/pkg/agent"
    "github.com/astercloud/aster/pkg/provider"
    "github.com/astercloud/aster/pkg/sandbox"
    "github.com/astercloud/aster/pkg/store"
    "github.com/astercloud/aster/pkg/tools"
    "github.com/astercloud/aster/pkg/types"
)

func main() {
    ctx := context.Background()

    // 创建依赖
    deps := &agent.Dependencies{
        ToolRegistry:     tools.NewRegistry(),
        SandboxFactory:   sandbox.NewFactory(),
        ProviderFactory:  provider.NewMultiProviderFactory(),
        Store:            store.NewMemoryStore(),
        TemplateRegistry: agent.NewTemplateRegistry(),
    }

    // 创建 Agent
    ag, err := agent.Create(ctx, &types.AgentConfig{
        TemplateID: "assistant",
        ModelConfig: &types.ModelConfig{
            Provider: "anthropic",
            Model:    "claude-sonnet-4-5",
            APIKey:   os.Getenv("ANTHROPIC_API_KEY"),
        },
    }, deps)
    if err != nil {
        log.Fatal(err)
    }
    defer ag.Close()

    // 订阅进度事件
    eventCh := ag.Subscribe([]types.AgentChannel{
        types.ChannelProgress,
    }, nil)

    // 处理事件
    go func() {
        for envelope := range eventCh {
            switch envelope.Event.Type {
            case types.EventTypeTextDelta:
                // 实时打印文本增量
                fmt.Print(envelope.Event.TextDelta)
            case types.EventTypeTextDone:
                fmt.Println("\n--- 完成 ---")
            }
        }
    }()

    // 发送消息(异步)
    err = ag.Send(ctx, "写一首关于 Go 语言的短诗")
    if err != nil {
        log.Fatal(err)
    }

    // 等待完成(简化示例)
    select {}
}

运行示例

export ANTHROPIC_API_KEY="sk-ant-xxx"
go run main.go

输出示例

Go 语言轻盈快,
并发协程齐开花。
简洁优雅易上手,
云端服务遍天下。
--- 完成 ---

关键点

  1. 订阅事件:使用 Subscribe() 订阅 Progress 通道
  2. 异步处理:在 goroutine 中处理事件流
  3. 实时输出:接收 TextDelta 事件即时打印
  4. 非阻塞发送:使用 Send() 而非 Chat()

处理多种事件

go func() {
    for envelope := range eventCh {
        switch envelope.Event.Type {
        case types.EventTypeTextDelta:
            fmt.Print(envelope.Event.TextDelta)

        case types.EventTypeTextDone:
            fmt.Println("\n✓ 文本输出完成")

        case types.EventTypeToolCallRequest:
            fmt.Printf("\n[工具调用] %s\n", envelope.Event.ToolCall.Name)

        case types.EventTypeToolCallResult:
            fmt.Printf("[工具结果] %v\n", envelope.Event.ToolResult.Content)
        }
    }
}()

使用 Stream Reader

更现代的方式:

reader := ag.Stream(ctx, "写一首诗")
for {
    event, err := reader.Recv()
    if err != nil {
        if errors.Is(err, io.EOF) {
            break
        }
        log.Printf("错误: %v", err)
        break
    }

    if event.Type == "text_delta" {
        fmt.Print(event.TextDelta)
    }
}
fmt.Println()

相关资源