Chapter 4: Tools and File System Access
Goal of this chapter: add Tool capabilities so the Agent can access the file system.
Why We Need Tools
In the first three chapters, the Agent we built can only chat — it cannot perform real actions.
Agent limitations:
- Can only generate text replies
- Cannot access external resources (files, APIs, databases, etc.)
- Cannot execute real tasks (compute, query, modify, etc.)
Tool’s role:
- Tool is a capability extension for Agent: enabling the Agent to perform concrete operations
- Tool encapsulates specific implementations: the Agent doesn’t care how the Tool works internally, only about inputs and outputs
- Tools are composable: an Agent can have multiple Tools and choose which to call as needed
Simple analogy:
- Agent = “intelligent assistant” (understands instructions, but needs tools to act)
- Tool = “toolbox” (file operations, network requests, database queries, etc.)
Why File System Access
This example is ChatWithDoc (chat with documentation), aimed at helping users learn the Eino framework and write Eino code. So what’s the best documentation?
The answer is: the Eino repository’s code itself.
- Code: source code shows the real framework implementation
- Comments: code comments provide design rationale and usage instructions
- Examples: example code demonstrates best practices
With file system access, the Agent can directly read Eino source code, comments, and examples, providing users with the most accurate and up-to-date technical support.
Key Concepts
Tool Interface
Tool is the interface in Eino that defines executable capabilities:
// BaseTool provides tool metadata that ChatModel uses to decide whether and how to call the tool
type BaseTool interface {
Info(ctx context.Context) (*schema.ToolInfo, error)
}
// InvokableTool is a tool that can be executed by ToolsNode
type InvokableTool interface {
BaseTool
// InvokableRun executes the tool; arguments are a JSON-encoded string, returns a string result
InvokableRun(ctx context.Context, argumentsInJSON string, opts ...Option) (string, error)
}
// StreamableTool is the streaming variant of InvokableTool
type StreamableTool interface {
BaseTool
// StreamableRun executes the tool in streaming mode, returns a StreamReader
StreamableRun(ctx context.Context, argumentsInJSON string, opts ...Option) (*schema.StreamReader[string], error)
}
Interface hierarchy:
BaseTool: base interface, only provides metadataInvokableTool: executable tool (extends BaseTool)StreamableTool: streaming tool (extends BaseTool)
Backend Interface
Backend is Eino’s abstract interface for file system operations:
type Backend interface {
// List file info in a directory
LsInfo(ctx context.Context, req *LsInfoRequest) ([]FileInfo, error)
// Read file content, supports line offset and limit
Read(ctx context.Context, req *ReadRequest) (*FileContent, error)
// Search for matching content in files
GrepRaw(ctx context.Context, req *GrepRequest) ([]GrepMatch, error)
// Match files by glob pattern
GlobInfo(ctx context.Context, req *GlobInfoRequest) ([]FileInfo, error)
// Write file content
Write(ctx context.Context, req *WriteRequest) error
// Edit file content (string replacement)
Edit(ctx context.Context, req *EditRequest) error
}
LocalBackend
LocalBackend is the local file system implementation of Backend, directly accessing the OS file system:
import localbk "github.com/cloudwego/eino-ext/adk/backend/local"
backend, err := localbk.NewBackend(ctx, &localbk.Config{})
Characteristics:
- Directly accesses the local file system using Go standard library
- Supports all Backend interface methods
- Supports executing shell commands (ExecuteStreaming)
- Path safety: requires absolute paths to prevent directory traversal attacks
- Zero configuration: works out of the box with no additional setup
Implementation: Using DeepAgent
This chapter uses the DeepAgent prebuilt agent, which provides first-class configuration for Backend and StreamingShell, making it convenient to register file-system-related tools.
From ChatModelAgent to DeepAgent: When to Switch?
Previous chapters used ChatModelAgent, which can handle multi-turn conversations. But to access the file system, we need to switch to DeepAgent.
ChatModelAgent vs DeepAgent comparison:
| Capability | ChatModelAgent | DeepAgent |
| Multi-turn conversation | ✅ | ✅ |
| Add custom Tools | ✅ Manual registration of each Tool | ✅ Manual or automatic registration |
| File system access (Backend) | ❌ Must manually create and register all file tools | ✅ First-class config, auto-registered |
| Command execution (StreamingShell) | ❌ Must manually create | ✅ First-class config, auto-registered |
| Built-in task management | ❌ | ✅ write_todos tool |
| Sub-Agent support | ❌ | ✅ |
Selection guidance:
- Pure conversation scenarios (no external access) → use
ChatModelAgent - Need file system access or command execution → use
DeepAgent
Why Use DeepAgent?
Compared to using ChatModelAgent directly, DeepAgent advantages:
- First-class configuration: Backend and StreamingShell are first-class configs — just pass them in
- Automatic tool registration: configuring Backend automatically registers file system tools, no manual creation needed
- Built-in task management: provides the
write_todostool for task planning and tracking - Sub-Agent support: can configure specialized sub-Agents for specific tasks
- More powerful: integrates file system, command execution, and other capabilities
Code Implementation
import (
localbk "github.com/cloudwego/eino-ext/adk/backend/local"
"github.com/cloudwego/eino/adk/prebuilt/deep"
)
// Create LocalBackend
backend, err := localbk.NewBackend(ctx, &localbk.Config{})
// Create DeepAgent with automatic file system tool registration
agent, err := deep.New(ctx, &deep.Config{
Name: "Ch04ToolAgent",
Description: "ChatWithDoc agent with filesystem access via LocalBackend.",
ChatModel: cm,
Instruction: agentInstruction,
Backend: backend, // Provides file system operation capabilities
StreamingShell: backend, // Provides command execution capabilities
MaxIteration: 50,
})
Tools Automatically Registered by DeepAgent
When Backend and StreamingShell are configured, DeepAgent automatically registers the following tools:
read_file: read file contentwrite_file: write file contentedit_file: edit file contentglob: find files by glob patterngrep: search content in filesexecute: execute shell commands
Code Location
- Entry code: cmd/ch04/main.go
Prerequisites
Same as Chapter 1: you need a configured and available ChatModel (OpenAI or Ark).
This chapter also requires setting PROJECT_ROOT (optional, see run instructions below).
Running
In the examples/quickstart/chatwitheino directory:
# Optional: set the root directory path of the Eino core library
# When not set, the Agent defaults to using the current working directory (the chatwitheino directory)
# To let the Agent search the full Eino codebase, point to the eino core library root
export PROJECT_ROOT=/path/to/eino
# Verify the path is correct (you should see directories like adk, components, compose, etc.)
ls $PROJECT_ROOT
go run ./cmd/ch04
PROJECT_ROOT explanation:
- When not set:
PROJECT_ROOTdefaults to the current working directory (wherechatwitheinoresides), and the Agent can only access files from this example project. This is sufficient for quick experimentation. - When set: points to the Eino core library root, and the Agent can search the complete Eino framework codebase (core lib, extensions, examples). This is the full ChatWithEino use case.
Recommended three-repo directory structure (for the full experience):
eino/ # PROJECT_ROOT (Eino core library)
├── adk/
├── components/
├── compose/
├── ext/ # eino-ext (extension components like OpenAI, Ark implementations)
├── examples/ # eino-examples (this repo, where this example lives)
│ └── quickstart/
│ └── chatwitheino/
└── ...
You can use the dev_setup.sh script to automatically set up this directory structure:
# Run in the eino root directory to auto-clone extensions and examples repos to the correct locations
bash scripts/dev_setup.sh
Example output:
you> List the files in the current directory
[assistant] Let me list the files in the current directory...
[tool call] glob(pattern: "*")
[tool result] Found 5 files:
- main.go
- go.mod
- go.sum
- README.md
- cmd/
you> Read the content of main.go
[assistant] Let me read the main.go file...
[tool call] read_file(file_path: "main.go")
[tool result] File content:
...
Note: if you encounter a Tool error that interrupts the Agent during execution, don’t panic — this is normal. Tool errors are common (e.g., wrong arguments, file not found). How to gracefully handle Tool errors will be covered in detail in the next chapter.
Tool Call Flow
When the Agent needs to call a Tool:
┌─────────────────────────────────────────┐
│ User: list files in current directory │
└─────────────────────────────────────────┘
↓
┌──────────────────────┐
│ Agent analyzes intent│
│ Decides to call glob │
└──────────────────────┘
↓
┌──────────────────────┐
│ Generate Tool Call │
│ {"pattern": "*"} │
└──────────────────────┘
↓
┌──────────────────────┐
│ Execute Tool │
│ glob("*") │
└──────────────────────┘
↓
┌──────────────────────┐
│ Return Tool Result │
│ {"files": [...]} │
└──────────────────────┘
↓
┌──────────────────────┐
│ Agent generates reply│
│ "Found 5 files..." │
└──────────────────────┘
Chapter Summary
- Tool: a capability extension for Agent, enabling it to perform concrete operations
- Backend: abstract interface for file system operations, providing unified file operation capabilities
- LocalBackend: local file system implementation of Backend, directly accessing the OS file system
- DeepAgent: a prebuilt advanced Agent providing first-class Backend and StreamingShell configuration
- Automatic tool registration: configuring Backend auto-registers file system tools
- Tool call flow: Agent analyzes intent → generates Tool Call → executes Tool → returns result → generates reply
Extended Thinking
Other Tool types:
- HTTP Tool: call external APIs
- Database Tool: query databases
- Calculator Tool: perform calculations
- Code Executor Tool: run code
Other Backend implementations:
- Other storage backends can be implemented based on the Backend interface
- For example: cloud storage, database storage, etc.
- LocalBackend already provides complete file system operation capabilities
Custom Tool creation:
If you need to create custom Tools, you can use utils.InferTool to automatically infer from functions. See: