eino-agent について
eino-agentは、Einoでエージェントを構築するGo開発者向けのツールキットです。複数のエージェント形式、Runner、ミドルウェアに加え、実行のキャンセルやモデルの再試行・切り替え、人間の入力を挟む一時停止と再開に対応します。
主な機能
- 01ChatModelAgent、DeepAgent、カスタムエージェント
- 02複数ターンのイベント処理用TurnLoop
- 03Runnerのチェックポイントとイベントストリーム
- 04安全なキャンセル、再試行、モデル切り替え
- 05ミドルウェア拡張とツールとしてのエージェント利用
活用シーン
- 01ツールを呼び出す複数ターンのエージェント構築
- 02計画、ファイル操作、サブエージェントが必要なタスク
- 03対話型アプリで入力をキューイングし、ターンを中断
- 04承認や確認の後にエージェントの実行を再開
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cloudwego/ eino-ext --skill eino-agentインストール後、Claude Code で/eino-agentを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
reference/agent-as-tool.mdchat-model-agent.mddeep-agents.mdfilesystem.mdhuman-in-the-loop.mdmiddleware.mdrunner-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]
エージェントの種類
| 種類 | 説明 | 判断 |
|---|---|---|
| ChatModelAgent | ReAct パターン: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 を参照してください)。
| ミドルウェア | パッケージ | 用途 |
|---|---|---|
| FileSystem | adk/middlewares/filesystem | ファイル操作(read/write/edit/glob/grep)とシェル |
| ToolSearch | adk/middlewares/dynamictool/toolsearch | 正規表現検索による動的なツール選択 |
| ToolReduction | adk/middlewares/reduction | 大きなツール結果の切り詰め・消去 |
| Summarization | adk/middlewares/summarization | 長い会話履歴の圧縮 |
| PlanTask | adk/middlewares/plantask | タスクの作成と進捗の追跡 |
| Skill | adk/middlewares/skill | スキルベースの段階的な情報開示 |
| PatchToolCalls | adk/middlewares/patchtoolcalls | 履歴内に残った未完了のツール呼び出しを修正 |
| Agents.md | adk/middlewares/agentsmd | Agents.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、例、応用的な使い方については、必要に応じて以下のファイルを参照してください。
- reference/chat-model-agent.md -- ChatModelAgentConfig のリファレンス、ReAct パターン、ToolsConfig、ストリーミング、Cancel/Retry/Failover の詳細
- reference/deep-agents.md -- DeepAgent の概念、設定、アーキテクチャ、ChatModelAgent との比較
- reference/middleware.md -- インターフェース、設定、例を含む 8 種類すべてのミドルウェア
- reference/runner-and-events.md -- Runner の作成、AgentEvent/AgentOutput、イベントの反復パターン
- reference/agent-as-tool.md -- 別のエージェントで使用するために Agent を Tool としてラップする方法
- reference/human-in-the-loop.md -- 中断 API、ResumableAgent、CheckPointStore、再開パターン
- reference/filesystem.md -- Filesystem Backend インターフェース、Local と AgentKit の実装、DeepAgent での使用方法