mcpField
E
eino-agent

eino-agent

github.com/cloudwegoエージェントワークフロー828336 回インストール1 週間前に更新
リポジトリ

eino-agent について

eino-agentは、Einoでエージェントを構築するGo開発者向けのツールキットです。複数のエージェント形式、Runner、ミドルウェアに加え、実行のキャンセルやモデルの再試行・切り替え、人間の入力を挟む一時停止と再開に対応します。

主な機能

  1. 01ChatModelAgent、DeepAgent、カスタムエージェント
  2. 02複数ターンのイベント処理用TurnLoop
  3. 03Runnerのチェックポイントとイベントストリーム
  4. 04安全なキャンセル、再試行、モデル切り替え
  5. 05ミドルウェア拡張とツールとしてのエージェント利用

活用シーン

  1. 01ツールを呼び出す複数ターンのエージェント構築
  2. 02計画、ファイル操作、サブエージェントが必要なタスク
  3. 03対話型アプリで入力をキューイングし、ターンを中断
  4. 04承認や確認の後にエージェントの実行を再開

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cloudwego/eino-ext --skill eino-agent

インストール後、Claude Code で/eino-agentを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
agent-as-tool.md
chat-model-agent.md
deep-agents.md
filesystem.md
human-in-the-loop.md
middleware.md
runner-and-events.md

詳細

Eino ADK の概要

インポート:github.com/cloudwego/eino/adk

Agent Development Kit(ADK)は、Go でエージェントを構築するためのフレームワークです。ADK は MessageType をジェネリックパラメーターとして指定でき、従来の *schema.Message と新しい *schema.AgenticMessage の両方をサポートします。新たに使用する場合は *schema.AgenticMessage を推奨します。

type MessageType interface {
    *schema.Message | *schema.AgenticMessage
}

type TypedAgent[M MessageType] interface {
    Name(ctx context.Context) string
    Description(ctx context.Context) string
    Run(ctx context.Context, input *TypedAgentInput[M], options ...AgentRunOption) *AsyncIterator[*TypedAgentEvent[M]]
}

// Convenience aliases for classic message type
type Agent = TypedAgent[*schema.Message]

エージェントの種類

種類説明判断
ChatModelAgentReAct パターン:LLM が推論し、ツールを呼び出し、完了するまで繰り返します動的(LLM)
DeepAgent計画、ファイルシステム、サブエージェントを備えた事前構築済みのエージェント動的(LLM)
TurnLoopプリエンプションとライフサイクル管理に対応した、複数ターン実行向けのプッシュ型イベントループランタイム
カスタムエージェントTypedAgent インターフェースを直接実装しますカスタム

ChatModelAgent クイックスタート

import (
    "context"
    "fmt"
    "log"

    "github.com/cloudwego/eino-ext/components/model/openai"
    "github.com/cloudwego/eino/adk"
    "github.com/cloudwego/eino/components/tool"
    "github.com/cloudwego/eino/components/tool/utils"
    "github.com/cloudwego/eino/compose"
)

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

    // 1. Create a tool
    searchTool, _ := utils.InferTool("search_book", "Search books by genre",
        func(ctx context.Context, input *struct {
            Genre string `json:"genre" jsonschema_description:"Book genre"`
        }) (string, error) {
            return `{"books": ["The Great Gatsby"]}`, nil
        })

    // 2. Create model (BaseModel[M], not ToolCallingChatModel)
    cm, _ := openai.NewChatModel(ctx, &openai.ChatModelConfig{
        APIKey: "your-key", Model: "gpt-4o",
    })

    // 3. Create agent
    agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Name:        "BookRecommender",
        Description: "Recommends books",
        Instruction: "You recommend books using the search_book tool.",
        Model:       cm,
        ToolsConfig: adk.ToolsConfig{
            ToolsNodeConfig: compose.ToolsNodeConfig{
                Tools: []tool.BaseTool{searchTool},
            },
        },
    })

    // 4. Run with Runner
    runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})
    iter := runner.Query(ctx, "recommend a fiction book")
    for {
        event, ok := iter.Next()
        if !ok {
            break
        }
        if event.Err != nil {
            log.Fatal(event.Err)
        }
        if event.Output != nil && event.Output.MessageOutput != nil {
            msg, _ := event.Output.MessageOutput.GetMessage()
            fmt.Printf("Agent[%s]: %v\n", event.AgentName, msg)
        }
    }
}

キャンセルの仕組み

キャンセル機能により、エージェントの実行を安全かつ制御可能な形で終了できます。

// Create a cancel function alongside the run
cancelOpt, cancelFn := adk.WithCancel()
iter := runner.Query(ctx, "do something", cancelOpt)

// ... iterate events ...

// Cancel at a safe point (cancelFn is non-blocking, Wait blocks until complete)
handle, ok := cancelFn(adk.WithAgentCancelMode(adk.CancelAfterChatModel))
if ok {
    handle.Wait()
}

CancelMode(ビットマスク):

モード動作
CancelImmediate (0)直ちに中止し、ストリームを終了します
CancelAfterChatModel現在のモデル呼び出しが完了するまで待機します
CancelAfterToolCalls現在のツール呼び出しが完了するまで待機します

キャンセルオプション:

  • WithAgentCancelMode(mode) -- 安全な中断ポイントを設定します
  • WithAgentCancelTimeout(d) -- 制限時間内に安全な中断ポイントへ到達しなかった場合、即時キャンセルに切り替えます
  • WithRecursive() -- ネストされた AgentTool エージェントにもキャンセルを伝播します

キャンセルが発生すると、イベントストリームに CancelError が出力されます。このエラーには、後で再開するためのチェックポイントデータが含まれます。

モデルの再試行

再試行の判断を完全に制御できる、出力ベースの再試行です。

agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    // ...
    ModelRetryConfig: &adk.ModelRetryConfig{
        MaxRetries: 3,
        ShouldRetry: func(ctx context.Context, retryCtx *adk.RetryContext) *adk.RetryDecision {
            // Retry based on output content (e.g., empty response, bad finish reason)
            if retryCtx.Err != nil {
                return &adk.RetryDecision{Retry: true, Backoff: time.Second}
            }
            if retryCtx.OutputMessage == nil || retryCtx.OutputMessage.Content == "" {
                return &adk.RetryDecision{Retry: true, Backoff: time.Second}
            }
            return &adk.RetryDecision{Retry: false}
        },
    },
})

RetryContext が提供する情報:RetryAttempt、InputMessages、OutputMessage(連結された完全な応答)、Err。

RetryDecision で制御できる項目:Retry、ModifiedInputMessages、AdditionalOptions、Backoff、RejectReason。

ストリーミング中に再試行が発生すると、再試行を通知する WillRetryError がストリームに出力されます。

モデルのフェイルオーバー

プライマリモデルが失敗した場合や、満足できない出力を生成した場合に、モデルを動的に切り替えます。

agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    // ...
    ModelFailoverConfig: &adk.ModelFailoverConfig[*schema.Message]{
        MaxRetries: 2,
        ShouldFailover: func(ctx context.Context, outputMessage *schema.Message, outputErr error) bool {
            return outputErr != nil // failover on any error
        },
        GetFailoverModel: func(ctx context.Context, failoverCtx *adk.FailoverContext[*schema.Message]) (
            model.BaseModel[*schema.Message], []*schema.Message, error) {
            // Return a different model and optionally modified input
            return backupModel, failoverCtx.InputMessages, nil
        },
    },
})

フェイルオーバーは再試行と連携します。両方が設定されている場合、再試行も使い果たされていれば、FailoverContext.LastErr は *RetryExhaustedError になります。

TurnLoop

プリエンプション、アイドルタイムアウト、正常なシャットダウンに対応した、複数ターンのエージェント実行向けのプッシュ型イベントループです。

import "github.com/cloudwego/eino/adk"

loop := adk.NewTurnLoop(adk.TurnLoopConfig[string, *schema.Message]{
    GenInput: func(ctx context.Context, loop *adk.TurnLoop[string, *schema.Message], items []string) (*adk.GenInputResult[string, *schema.Message], error) {
        // Convert pushed items into agent input
        combined := strings.Join(items, "\n")
        return &adk.GenInputResult[string, *schema.Message]{
            RunCtx:   ctx,
            Input:    &adk.TypedAgentInput[*schema.Message]{Messages: []*schema.Message{schema.UserMessage(combined)}},
            Consumed: items,
        }, nil
    },
    PrepareAgent: func(ctx context.Context, loop *adk.TurnLoop[string, *schema.Message], consumed []string) (adk.Agent, error) {
        return myAgent, nil
    },
    OnAgentEvents: func(ctx context.Context, tc *adk.TurnContext[string, *schema.Message], events *adk.AsyncIterator[*adk.AgentEvent]) error {
        for {
            event, ok := events.Next()
            if !ok {
                break
            }
            if event.Err != nil {
                return event.Err
            }
            // Process events (e.g., send to client)
        }
        return nil
    },
})

// Start the loop
loop.Run(ctx)

// Push items (non-blocking, returns (ok bool, resolved <-chan struct{}))
loop.Push("user message 1")

// Preempt current turn with new input
loop.Push("urgent message", adk.WithPreempt[string, *schema.Message](adk.AfterChatModel))

// Stop gracefully
loop.Stop(adk.WithGraceful())

// Wait for exit and get final state
exitState := loop.Wait()

主な概念:

  • Push() でアイテムをキューに追加します。ループはアイテムをまとめて、GenInput を通じて処理します
  • プリエンプション:安全な中断ポイントで現在のターンをキャンセルし、保留中のアイテムを含めて新しいターンを開始します
  • アイドルタイムアウト:UntilIdleFor(d) は、期間 d の間アイテムがなければ自動停止します
  • 正常なシャットダウン:WithGraceful()、WithGracefulTimeout(d)、WithImmediate() を使用します
  • 終了状態:TurnLoopExitState には ExitReason、UnhandledItems、InterruptedItems が含まれます

Runner

Runner はエージェントのライフサイクル、コンテキストの受け渡し、中断と再開を管理します。

runner := adk.NewRunner(ctx, adk.RunnerConfig{
    Agent:           myAgent,
    EnableStreaming:  true,
    CheckPointStore: myStore,  // for interrupt/resume
})

// Query (convenience for single user message)
iter := runner.Query(ctx, "hello")

// Run (full control over input messages)
iter := runner.Run(ctx, []*schema.Message{schema.UserMessage("hello")})

ミドルウェアシステム

ミドルウェアによって ChatModelAgent の動作を拡張できます。Handlers フィールドで設定します。

agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    // ...
    Handlers: []adk.ChatModelAgentMiddleware{fsMiddleware, summarizationMW},
})

組み込みミドルウェアは 8 種類あります(詳細は reference/middleware.md を参照してください)。

ミドルウェアパッケージ用途
FileSystemadk/middlewares/filesystemファイル操作(read/write/edit/glob/grep)とシェル
ToolSearchadk/middlewares/dynamictool/toolsearch正規表現検索による動的なツール選択
ToolReductionadk/middlewares/reduction大きなツール結果の切り詰め・消去
Summarizationadk/middlewares/summarization長い会話履歴の圧縮
PlanTaskadk/middlewares/plantaskタスクの作成と進捗の追跡
Skilladk/middlewares/skillスキルベースの段階的な情報開示
PatchToolCallsadk/middlewares/patchtoolcalls履歴内に残った未完了のツール呼び出しを修正
Agents.mdadk/middlewares/agentsmdAgents.md の指示をモデル入力に挿入

AgentAsTool

任意のエージェントをツールとしてラップし、別のエージェントから利用できるようにします。

subAgent := createMySubAgent()
agentTool := adk.NewAgentTool(ctx, subAgent)

parentAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
    ToolsConfig: adk.ToolsConfig{
        ToolsNodeConfig: compose.ToolsNodeConfig{
            Tools: []tool.BaseTool{agentTool},
        },
    },
})

Human-in-the-Loop

ChatModelAgent は、人間による承認、確認、フィードバックのための中断と再開をサポートしています。詳細については、reference/human-in-the-loop.md を参照してください。

基本パターン:ツールが compose.Interrupt(ctx, info) を返して一時停止し、その後 runner.ResumeWithParams(ctx, checkpointID, params) を呼び出して続行します。

エージェントへの指示

  • ほとんどのユースケースでは、デフォルトで ChatModelAgent を使用します(ツールを備えた単一エージェント)。
  • エージェントの実行には Runner を使用します。本番環境では agent.Run() を直接呼び出さないでください。
  • ミドルウェアの順序は重要です。最初に PatchToolCalls、次に Reduction、最後に Summarization を配置します。
  • 組み込みのプランニング、ファイルシステム、サブエージェントが必要な場合は、DeepAgent(adk/prebuilt/deep)を使用します。
  • サブエージェントに分離されたコンテキスト(共有履歴なし)が必要な場合は、AgentAsTool または DeepAgents の SubAgents を使用します。
  • プリエンプション、アイドル管理、プッシュベースの入力が必要なインタラクティブアプリケーションを構築する場合は、TurnLoop を使用します。
  • Model フィールドは model.BaseModel[M] を受け取ります。従来のパスでは任意の BaseChatModel を、エージェント型のパスでは AgenticModel を使用します。
  • Cancel、Retry、Failover はすべて組み合わせ可能です。Failover は Retry をラップします。
  • WithCancel() は実行オプションであり、設定オプションではありません。実行ごとに新しく作成してください。

参考ファイル

詳細な API、例、応用的な使い方については、必要に応じて以下のファイルを参照してください。

コメント