Having explored the necessity for agents to interact with their environment, let's get practical by building a simple file manipulation tool. This exercise will demonstrate how to empower an LLM agent to read from and write to text files, a fundamental capability for many tasks. We'll focus on creating two Python functions: one for reading file content and another for writing content to a file. While these tools will be basic, they form the building blocks for more sophisticated file management operations.
Our goal is to create two distinct functions:
read_file(filepath: str)
: This function will take a file path as input and return the content of the file as a string.write_file(filepath: str, content: str)
: This function will take a file path and a string of content as input, write the content to the specified file, and confirm success.For both functions, robust error handling is important, as file operations can fail for various reasons (e.g., file not found, permission issues). The feedback provided to the LLM in case of an error should be clear and informative.
read_file
ToolLet's start by implementing the read_file
function. This function needs to open a file in read mode, extract its content, and handle potential errors like the file not existing.
import os
def read_file(filepath: str) -> str:
"""
Reads the content of a specified text file.
Args:
filepath: The path to the file to be read.
Returns:
The content of the file as a string, or an error message if an issue occurs.
"""
try:
# Basic security: Prevent directory traversal for this simple example
# In a real system, use an allowlist of directories or more robust path validation.
if ".." in filepath:
return "Error: Relative paths with '..' are not allowed."
# For simplicity, we assume files are in a specific 'agent_files' subdirectory.
# In a production environment, this path would be configurable and secured.
base_directory = "agent_files"
safe_filepath = os.path.join(base_directory, os.path.basename(filepath))
# Create the base directory if it doesn't exist for this example
if not os.path.exists(base_directory):
os.makedirs(base_directory)
with open(safe_filepath, 'r', encoding='utf-8') as f:
content = f.read()
return content
except FileNotFoundError:
return f"Error: File not found at '{filepath}' (resolved to '{safe_filepath}')."
except Exception as e:
return f"Error reading file '{filepath}': {str(e)}"
In this function:
".."
in the filepath
. A production system would require much more sophisticated path validation and sandboxing.base_directory
(e.g., agent_files
) where the agent is allowed to read files from. This helps contain file operations. os.path.basename(filepath)
is used to ensure only the filename part is considered, preventing the agent from specifying paths outside the intended directory.try-except
block to catch FileNotFoundError
specifically, providing a tailored message.except Exception
catches other potential I/O errors, returning a generic error message that includes the original exception.utf-8
encoding, a common standard for text files.When this tool is invoked by an LLM, if the file agent_files/example.txt
exists and contains "Hello World", a call to read_file("example.txt")
would return "Hello World"
. If the file doesn't exist, it would return "Error: File not found at 'example.txt' (resolved to 'agent_files/example.txt')."
write_file
ToolNext, let's implement the write_file
function. This tool will allow the agent to save text to a file. Writing files carries more risk than reading, so careful consideration of permissions and target locations is even more significant in a real application.
import os
def write_file(filepath: str, content: str) -> str:
"""
Writes the given content to a specified text file.
If the file exists, it will be overwritten.
Args:
filepath: The path to the file to be written.
content: The text content to write to the file.
Returns:
A success message or an error message if an issue occurs.
"""
try:
# Basic security: Prevent directory traversal
if ".." in filepath:
return "Error: Relative paths with '..' are not allowed for writing."
# Confine writes to a specific subdirectory
base_directory = "agent_files"
safe_filepath = os.path.join(base_directory, os.path.basename(filepath))
# Create the base directory if it doesn't exist
if not os.path.exists(base_directory):
os.makedirs(base_directory)
with open(safe_filepath, 'w', encoding='utf-8') as f:
f.write(content)
return f"Successfully wrote content to '{filepath}' (resolved to '{safe_filepath}')."
except Exception as e:
return f"Error writing file '{filepath}': {str(e)}"
Key points for write_file
:
read_file
, it includes basic path safety by using os.path.basename
and a base_directory
.'w'
), which means if the file already exists, it will be overwritten. For a more advanced tool, you might consider adding an append
mode or a parameter to control overwrite behavior.try-except
block handles potential IOError
or other exceptions during the write operation.If an agent decides to use this tool with filepath="report.txt"
and content="This is the agent's report."
, the tool will attempt to create or overwrite agent_files/report.txt
with the given content.
For an LLM agent to use these Python functions, it needs clear descriptions of what each tool does, what parameters it expects, and what it returns. Here’s how you might define these for an agent framework:
Tool 1: Read File
read_file
filepath
(string, required): "The name of the file to read (e.g., 'notes.txt'). Do not include directory paths like '../' or '/'; all files are relative to a pre-configured 'agent_files' directory."Tool 2: Write File
write_file
filepath
(string, required): "The name of the file to write to (e.g., 'summary.txt'). Do not include directory paths like '../' or '/'; all files are relative to a pre-configured 'agent_files' directory. If the file exists, it will be overwritten."content
(string, required): "The text content to write into the file."These descriptions are designed to guide the LLM in using the tools correctly, including hints about the file system structure (the agent_files
directory) and potential outcomes (like overwriting files).
To test these tools:
Direct Python Testing: Call the functions directly from a Python script.
agent_files
subdirectory (e.g., agent_files/my_test_file.txt
) with some content.read_file("my_test_file.txt")
and verify the output.read_file
with a non-existent filename to check error handling.write_file("new_test_file.txt", "Hello from the agent!")
. Check if agent_files/new_test_file.txt
is created with the correct content.write_file
by trying to write to a restricted path (if you were to implement more complex path validation) or simulate a permissions error if possible (though this is harder to unit test without manipulating actual file permissions).Agent Integration Testing (Conceptual): While full agent integration is covered later, you can mentally walk through how an agent might use these.
read_file("project_update.txt")
, then process the content, and finally call write_file("summary_v1.txt", "...")
.read_file
(e.g., if project_update.txt
doesn't exist).The file tools we've built are illustrative. For any real-world application, especially if the LLM can determine filenames or content, security is of utmost importance:
os.path.basename
and base_directory
approach is a very basic first step. Production systems must use strict allowlists for readable/writable directories and potentially for filenames or file extensions. Never allow arbitrary path construction from LLM outputs without sanitization and validation.These simple file manipulation tools, when properly secured and described, significantly expand an agent's ability to interact with persistent storage and manage information. As you build more complex agents, you might extend these tools to handle directories, list files, check for existence, or append to files, always keeping security at the forefront of your design.
Was this section helpful?
© 2025 ApX Machine Learning