---
Description: ""
date: "2026-03-03"
lastmod: ""
tags: []
title: AgenticToolsNode&Tool 使用说明[Beta]
weight: 12
---

> 💡
> 本功能在 [v0.9](https://github.com/cloudwego/eino/releases/tag/v0.9.0-alpha.2) 版本开始提供。

## **基本介绍**

`Tool` 在 eino 框架中的定义是“AgenticModel 能够选择调用的外部能力”，包括本地函数，MCP server tool 等。

`AgenticToolsNode` 是 eino 框架指定的“Tool 执行器”，执行工具的方法定义如下：

> 代码位置：[https://github.com/cloudwego/eino/tree/main/compose/agentic_tools_node.go](https://github.com/cloudwego/eino/tree/main/compose/agentic_tools_node.go)

```go
func (a *AgenticToolsNode) Invoke(ctx context.Context, input *schema.AgenticMessage, opts ...ToolsNodeOption) ([]*schema.AgenticMessage, error) {}

func (a *AgenticToolsNode) Stream(ctx context.Context, input *schema.AgenticMessage,
    opts ...ToolsNodeOption) (*schema.StreamReader[[]*schema.AgenticMessage], error) {}
```

AgenticToolsNode 与 ToolsNode 复用同一套配置，用法相同，如配置执行时序、异常处理、入参处理、middleware 扩展等。

> 代码位置：[https://github.com/cloudwego/eino/tree/main/compose/tool_node.go](https://github.com/cloudwego/eino/tree/main/compose/tool_node.go)

```go
type ToolsNodeConfig struct {
    // Tools specify the list of tools can be called which are BaseTool but must implement InvokableTool or StreamableTool.
    Tools []tool.BaseTool

    // UnknownToolsHandler handles tool calls for non-existent tools when LLM hallucinates.
    // This field is optional. When not set, calling a non-existent tool will result in an error.
    // When provided, if the LLM attempts to call a tool that doesn't exist in the Tools list,
    // this handler will be invoked instead of returning an error, allowing graceful handling of hallucinated tools.
    // Parameters:
    //   - ctx: The context for the tool call
    //   - name: The name of the non-existent tool
    //   - input: The tool call input generated by llm
    // Returns:
    //   - string: The response to be returned as if the tool was executed
    //   - error: Any error that occurred during handling
    UnknownToolsHandler func(ctx context.Context, name, input string) (string, error)

    // ExecuteSequentially determines whether tool calls should be executed sequentially (in order) or in parallel.
    // When set to true, tool calls will be executed one after another in the order they appear in the input message.
    // When set to false (default), tool calls will be executed in parallel.
    ExecuteSequentially bool

    // ToolArgumentsHandler allows handling of tool arguments before execution.
    // When provided, this function will be called for each tool call to process the arguments.
    // Parameters:
    //   - ctx: The context for the tool call
    //   - name: The name of the tool being called
    //   - arguments: The original arguments string for the tool
    // Returns:
    //   - string: The processed arguments string to be used for tool execution
    //   - error: Any error that occurred during preprocessing
    ToolArgumentsHandler func(ctx context.Context, name, arguments string) (string, error)

    // ToolCallMiddlewares configures middleware for tool calls.
    // Each element can contain Invokable and/or Streamable middleware.
    // Invokable middleware only applies to tools implementing InvokableTool interface.
    // Streamable middleware only applies to tools implementing StreamableTool interface.
    ToolCallMiddlewares []ToolMiddleware
}
```

AgenticToolsNode 如何“决策”应该执行哪个 Tool？它不决策，而是依据输入的 `*schema.AgenticMessage` 来执行。AgenticModel 生成要调用的 FunctionToolCall（包含 ToolName，Argument 等），放到 *schema.AgenticMessage 中传给 AgenticToolsNode。AgenticToolsNode 针对每个 FunctionToolCall 实际执行一次调用。

如果配置了 ExecuteSequentially，则 AgenticToolsNode 会按照 []*ContentBlock 中的先后顺序来执行工具。

每个 FunctionToolCall 调用完成后的结果，又会封装为 *schema.AgenticMessage，作为 AgenticToolsNode 输出的一部分。

```go
// https://github.com/cloudwego/eino/tree/main/schema/agentic_message.go

type AgenticMessage struct {
    // role should be 'assistant' for tool call message
    Role AgenticRoleType

    // ContentBlocks is the list of content blocks.
    ContentBlocks []*ContentBlock

     // other fields...
}

type ContentBlock struct {
    Type ContentBlockType

    // FunctionToolCall contains the invocation details for a user-defined tool.
    FunctionToolCall *FunctionToolCall

    // FunctionToolResult contains the result returned from a user-defined tool call.
    FunctionToolResult *FunctionToolResult

    // other fields...
}

// FunctionToolCall is the function call in a message.
// It's used in assistant message.
type FunctionToolCall struct {
    // CallID is the unique identifier for the tool call.
    CallID string

    // Name specifies the function tool invoked.
    Name string

    // Arguments is the JSON string arguments for the function tool call.
    Arguments string
}

// FunctionToolResult is the function call result in a message.
// It's used in user message.
type FunctionToolResult struct {
    // CallID is the unique identifier for the tool call.
    CallID string

    // Name specifies the function tool invoked.
    Name string

    // Result is the function tool result returned by the user
    Result string
}
```

## **Tool 定义**

### **接口定义**

Tool 组件提供了三个层次的接口：

> 代码位置：[https://github.com/cloudwego/eino/components/tool/interface.go](https://github.com/cloudwego/eino/components/tool/interface.go)

```go
// BaseTool get tool info for ChatModel intent recognition.
type BaseTool interface {
    Info(ctx context.Context) (*schema.ToolInfo, error)
}

// InvokableTool the tool for ChatModel intent recognition and ToolsNode execution.
type InvokableTool interface {
    BaseTool
    InvokableRun(ctx context.Context, argumentsInJSON string, opts ...Option) (string, error)
}

// StreamableTool the stream tool for ChatModel intent recognition and ToolsNode execution.
type StreamableTool interface {
    BaseTool
    StreamableRun(ctx context.Context, argumentsInJSON string, opts ...Option) (*schema.StreamReader[string], error)
}
```

#### **Info 方法**

- 功能：获取工具的描述信息
- 参数：
  - ctx：上下文对象
- 返回值：
  - `*schema.ToolInfo`：工具的描述信息
  - error：获取信息过程中的错误

#### **InvokableRun 方法**

- 功能：同步执行工具
- 参数：
  - ctx：上下文对象，用于传递请求级别的信息，同时也用于传递 Callback Manager
  - `argumentsInJSON`：JSON 格式的参数字符串
  - opts：工具执行的选项
- 返回值：
  - string：执行结果
  - error：执行过程中的错误

#### **StreamableRun 方法**

- 功能：以流式方式执行工具
- 参数：
  - ctx：上下文对象，用于传递请求级别的信息，同时也用于传递 Callback Manager
  - `argumentsInJSON`：JSON 格式的参数字符串
  - opts：工具执行的选项
- 返回值：
  - `*schema.StreamReader[string]`：流式执行结果
  - error：执行过程中的错误

### **ToolInfo 结构体**

> 代码位置：[https://github.com/cloudwego/eino/components/tool/interface.go](https://github.com/cloudwego/eino/components/tool/interface.go)

```go
type ToolInfo struct {
    // 工具的唯一名称，用于清晰地表达其用途
    Name string
    // 用于告诉模型如何/何时/为什么使用这个工具
    // 可以在描述中包含少量示例
    Desc string
    // 工具接受的参数定义
    // 可以通过两种方式描述：
    // 1. 使用 ParameterInfo：schema.NewParamsOneOfByParams(params)
    // 2. 使用 JSONSchema：schema.NewParamsOneOfByJSONSchema(jsonschema)
    *ParamsOneOf
}
```

### **公共 Option**

Tool 组件使用 ToolOption 来定义可选参数， AgenticToolsNode 没有抽象公共的 option。每个具体的实现可以定义自己的特定 Option，通过 WrapToolImplSpecificOptFn 函数包装成统一的 ToolOption 类型。

## **使用方式**

ToolsNode 通常不会被单独使用，一般用于编排之中接在 AgenticModel 之后。

```go
import (
    "github.com/cloudwego/eino/components/tool"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/schema"
)

// 创建工具节点
toolsNode := compose.NewAgenticToolsNode([]tool.Tool{
    searchTool,    // 搜索工具
    weatherTool,   // 天气查询工具
    calculatorTool, // 计算器工具
})

// Mock LLM 输出作为输入
input := &schema.AgenticMessage{
    Role: schema.AgenticRoleTypeAssistant,
    ContentBlocks: []*schema.ContentBlock{
       {
          Type: schema.ContentBlockTypeFunctionToolCall,
          FunctionToolCall: &schema.FunctionToolCall{
             CallID:    "1",
             Name:      "get_weather",
             Arguments: `{"city": "深圳", "date": "tomorrow"}`,
          },
       },
    },
}

toolMessages, err := toolsNode.Invoke(ctx, input)
```

### **在编排中使用**

```go
import (
    "github.com/cloudwego/eino/components/tool"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/schema"
)

// 创建工具节点
toolsNode := compose.NewAgenticToolsNode([]tool.Tool{
    searchTool,    // 搜索工具
    weatherTool,   // 天气查询工具
    calculatorTool, // 计算器工具
})

// 在 Chain 中使用
chain := compose.NewChain[*schema.AgenticMessage, []*schema.AgenticMessage]()
chain.AppendAgenticToolsNode(toolsNode)

// graph 中
graph := compose.NewGraph[*schema.AgenticMessage, []*schema.AgenticMessage]()
graph.AddAgenticToolsNode(toolsNode)
```

## **Option 机制**

自定义 Tool 可根据自己需要实现特定的 Option：

```go
import "github.com/cloudwego/eino/components/tool"

// 定义 Option 结构体
type MyToolOptions struct {
    Timeout time.Duration
    MaxRetries int
    RetryInterval time.Duration
}

// 定义 Option 函数
func WithTimeout(timeout time.Duration) tool.Option {
    return tool.WrapImplSpecificOptFn(func(o *MyToolOptions) {
        o.Timeout = timeout
    })
}
```

## **Option 和 Callback 使用**

### **Callback 使用示例**

```go
import (
    "context"

    callbackHelper "github.com/cloudwego/eino/utils/callbacks"
    "github.com/cloudwego/eino/callbacks"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/components/tool"
)

// 创建 callback handler
handler := &callbackHelper.ToolCallbackHandler{
    OnStart: func(ctx context.Context, info *callbacks.RunInfo, input *tool.CallbackInput) context.Context {
       fmt.Printf("开始执行工具，参数: %s\n", input.ArgumentsInJSON)
       return ctx
    },
    OnEnd: func(ctx context.Context, info *callbacks.RunInfo, output *tool.CallbackOutput) context.Context {
       fmt.Printf("工具执行完成，结果: %s\n", output.Response)
       return ctx
    },
    OnEndWithStreamOutput: func(ctx context.Context, info *callbacks.RunInfo, output *schema.StreamReader[*tool.CallbackOutput]) context.Context {
       fmt.Println("工具开始流式输出")
       go func() {
          defer output.Close()

          for {
             chunk, err := output.Recv()
             if errors.Is(err, io.EOF) {
                return
             }
             if err != nil {
                return
             }
             fmt.Printf("收到流式输出: %s\n", chunk.Response)
          }
       }()
       return ctx
    },
}

// 使用 callback handler
helper := callbackHelper.NewHandlerHelper().
    Tool(handler).
    Handler()
 
/*** compose a chain
* chain := NewChain
* chain.appendxxx().
*       appendxxx().
*       ...
*/

// 在运行时使用
runnable, err := chain.Compile()
if err != nil {
    return err
}
result, err := runnable.Invoke(ctx, input, compose.WithCallbacks(helper))
```

## 如何获取 ToolCallID

在 tool 函数体、tool callback handler 中，都可以通过 `compose.GetToolCallID(ctx)` 函数获取当前 Tool 的 ToolCallID。

## **已有实现**

1. Google Search Tool: 基于 Google 搜索的工具实现 [Tool - Googlesearch](/zh/docs/eino/ecosystem_integration/tool/tool_googlesearch)
2. duckduckgo search tool: 基于 duckduckgo 搜索的工具实现 [Tool - DuckDuckGoSearch](/zh/docs/eino/ecosystem_integration/tool/tool_duckduckgo_search)
3. MCP: 把 mcp server 作为 tool[Eino Tool - MCP](/zh/docs/eino/ecosystem_integration/tool/tool_mcp)

## **工具实现方式**

工具的实现方式有多种，可以参考如下方式：

- 基于 HTTP API 的 tool 实现： [如何使用 openapi 创建 tool/function call ?](/zh/docs/eino/usage_guide/how_to_guide/openapi_tool_creation)
- 基于 gRPC 的 tool 实现： [如何使用 proto3 创建 tool/function call ? ](/zh/docs/eino/usage_guide/how_to_guide/proto3_tool_creation)
- 基于 thrift 的 tool 实现： [如何使用 thrift idl 创建 tool/function call ? ](/zh/docs/eino/usage_guide/how_to_guide/thrift_idl_tool_creation)
- 基于本地函数的工具实现： [如何创建一个 tool ?](/zh/docs/eino/core_modules/components/tools_node_guide/how_to_create_a_tool)
- ……
