Creating Tools in Sagentic ​
Tools in Sagentic are reusable functions that agents can use to perform specific tasks. In this guide, we'll create a tool that allows an agent to perform a Google search using the SerpApi service.
Setting Up Your Tool ​
First, create a new file in the tools/
directory of your Sagentic project. You can name it something descriptive, like search.ts
.
To ensure that your tool has access to the necessary functionality to perform a Google search, you'll need to install the serpapi
package, which provides a convenient way to interact with the SerpApi service. You can install this dependency by running the following command in your project's root directory:
npm install --save serpapi
yarn add serpapi
Once installed, the serpapi
package will be available for you to require and use within your tool, as demonstrated in the searchTool
code example. This package will handle the complexities of making HTTP requests to the SerpApi service and parsing the response, allowing you to focus on the logic specific to your tool.
Writing the Tool Code ​
Here's the code for the Google search tool, step by step:
import { FunctionTool } from "sagentic";
import { getJson } from "serpapi";
import { z } from "zod";
// Define the arguments your tool will accept using Zod for schema validation
const SearchArgs = z.object({
query: z.string().describe("The query to search for"),
});
// Define the structure of the search results your tool will return
const SearchResult = z
.object({
title: z.string().describe("The title of the result"),
link: z.string().describe("The link of the result"),
snippet: z.string().describe("The snippet of the result"),
})
.array()
.describe("The search results");
// Create the search tool function
export const searchTool = (apiKey: string) =>
new FunctionTool(
"search",
"Searches for a query on Google",
SearchArgs,
SearchResult,
async (_agent, { query }) => {
// Use the SerpApi `getJson` function to perform the search
const results = await getJson({
q: query,
api_key: apiKey,
});
// Map the results to match the SearchResult schema
return results.organic_results.map(
(result: { title: any; link: any; snippet: any }) => ({
title: result.title,
link: result.link,
snippet: result.snippet,
})
);
}
);
Understanding the Code ​
- We import
FunctionTool
from Sagentic, which is a class that helps us define our tool. - We use
getJson
from theserpapi
package to perform the actual search. - We use
zod
to define the input and output schemas for our tool. This ensures that the data passed to and from the tool is correctly typed and structured. - The
searchTool
function takes anapiKey
parameter and returns a newFunctionTool
instance. - The
FunctionTool
constructor takes the name of the tool, a description, the input schema, the output schema, and an asynchronous function that performs the search operation.
Tool Function ​
async (_agent, { query }) => {
// Use the SerpApi `getJson` function to perform the search
const results = await getJson({
q: query,
api_key: apiKey,
});
// Map the results to match the SearchResult schema
return results.organic_results.map(
(result: { title: any; link: any; snippet: any }) => ({
title: result.title,
link: result.link,
snippet: result.snippet,
})
);
};
The tool function is where the actual search is performed. It takes two parameters: the agent that's calling the tool, and the arguments passed to the tool. In this case, the agent is not used, but it's available if needed.
Tools in Sagentic can execute any TypeScript code, leveraging the extensive Node.js library ecosystem. This flexibility allows tools to perform a diverse array of tasks, from simple computations to complex operations involving external APIs.
TypeScript automatically infers the types in tool functions based on Zod schemas, streamlining the development process by reducing manual type annotations and ensuring consistency across the tool's interface.
Zod Schemas ​
Zod is employed within Sagentic to define schemas for tools, ensuring data integrity and type safety. Descriptions within these schemas are crucial; they enable Sagentic to provide feedback to the LLM, facilitating self-correction. Custom validations in Zod enhance this process by enforcing data constraints, leading to more accurate LLM interactions.
Using Your Tool in an Agent ​
To utilize a tool within an agent, you first need to import it. For example, if you have a tool named search
located in the tools
directory, you would import it into your agent file like this:
import searchTool from "../tools/search";
Once imported, you have a couple of options for setting the tool within your agent's class.
Setting Tools in the Constructor ​
You can instantiate and set your tools within the constructor of your agent's class. Here's an example of how to do this:
import { Session } from "sagentic";
import searchTool from "../tools/search";
class SearcherAgent extends BaseAgent {
constructor(session: Session, options: SearcherAgentOptions) {
super(session, options);
// Instantiate the search tool with the necessary API key
const search = searchTool(session.context["serp-api-key"]);
// Set the instantiated tool in the agent's tools array
this.tools = [search];
// ...
}
}
In this example, the searchTool
is instantiated with an API key from the session context and then added to the agent's tools
array.
Setting Tools as a Class Property ​
Alternatively, you can set the tools directly as a property of the agent's class:
import { Tool } from "sagentic";
import searchTool from "../tools/search";
class SearcherAgent extends BaseAgent {
// Instantiate and set the tools array with the search tool
tools: Tool[] = [searchTool("...")];
// ...
}
Here, the tools
property is an array that includes the instantiated searchTool
. The API key or any other required parameters would be passed directly to the searchTool
function.
Both methods are valid, and the choice between them can depend on whether you need to access the agent's context or options to configure your tools, or if you prefer a more straightforward setup.
Conclusion ​
Creating tools in Sagentic is a powerful way to extend the functionality of your agents. By encapsulating common tasks into tools, you can keep your agent code clean and focused while leveraging the full power of TypeScript and the Node.js ecosystem.