Create a basic agent
We want to use await
so we're going to wrap all of our code in a main
function, like this:
// Your imports go here
async function main() {
// the rest of your code goes here
}
main().catch(console.error);
For the rest of this guide we'll assume your code is wrapped like this so we can use await
. You can run the code this way:
npx tsx example.ts
Load your dependencies
First we'll need to pull in our dependencies. These are:
- The OpenAI class to use the OpenAI LLM
- FunctionTool to provide tools to our agent
- OpenAIAgent to create the agent itself
- Settings to define some global settings for the library
- Dotenv to load our API key from the .env file
import { OpenAI, FunctionTool, OpenAIAgent, Settings } from "llamaindex";
import "dotenv/config";
Initialize your LLM
We need to tell our OpenAI class where its API key is, and which of OpenAI's models to use. We'll be using gpt-4o
, which is capable while still being pretty cheap. This is a global setting, so anywhere an LLM is needed will use the same model.
Settings.llm = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
model: "gpt-4o",
});
Turn on logging
We want to see what our agent is up to, so we're going to hook into some events that the library generates and print them out. There are several events possible, but we'll specifically tune in to llm-tool-call
(when a tool is called) and llm-tool-result
(when it responds).
Settings.callbackManager.on("llm-tool-call", (event) => {
console.log(event.detail.payload);
});
Settings.callbackManager.on("llm-tool-result", (event) => {
console.log(event.detail.payload);
});
Create a function
We're going to create a very simple function that adds two numbers together. This will be the tool we ask our agent to use.
const sumNumbers = ({ a, b }) => {
return `${a + b}`;
};
Note that we're passing in an object with two named parameters, a
and b
. This is a little unusual, but important for defining a tool that an LLM can use.
Turn the function into a tool for the agent
This is the most complicated part of creating an agent. We need to define a FunctionTool
. We have to pass in:
- The function itself (
sumNumbers
) - A name for the function, which the LLM will use to call it
- A description of the function. The LLM will read this description to figure out what the tool does, and if it needs to call it
- A schema for function. We tell the LLM that the parameter is an
object
, and we tell it about the two named parameters we gave it,a
andb
. We describe each parameter as anumber
, and we say that both are required. - You can see more examples of function schemas.
const tool = FunctionTool.from(sumNumbers, {
name: "sumNumbers",
description: "Use this function to sum two numbers",
parameters: {
type: "object",
properties: {
a: {
type: "number",
description: "First number to sum",
},
b: {
type: "number",
description: "Second number to sum",
},
},
required: ["a", "b"],
},
});
We then wrap up the tools into an array. We could provide lots of tools this way, but for this example we're just using the one.
const tools = [tool];
Create the agent
With your LLM already set up and your tools defined, creating an agent is simple:
const agent = new OpenAIAgent({ tools });
Ask the agent a question
We can use the chat
interface to ask our agent a question, and it will use the tools we've defined to find an answer.
let response = await agent.chat({
message: "Add 101 and 303",
});
console.log(response);
Let's see what running this looks like using npx tsx agent.ts
Output
{
toolCall: {
id: 'call_ze6A8C3mOUBG4zmXO8Z4CPB5',
name: 'sumNumbers',
input: { a: 101, b: 303 }
},
toolResult: {
tool: FunctionTool { _fn: [Function: sumNumbers], _metadata: [Object] },
input: { a: 101, b: 303 },
output: '404',
isError: false
}
}
{
response: {
raw: {
id: 'chatcmpl-9KwauZku3QOvH78MNvxJs81mDvQYK',
object: 'chat.completion',
created: 1714778824,
model: 'gpt-4-turbo-2024-04-09',
choices: [Array],
usage: [Object],
system_fingerprint: 'fp_ea6eb70039'
},
message: {
content: 'The sum of 101 and 303 is 404.',
role: 'assistant',
options: {}
}
},
sources: [Getter]
}
We're seeing two pieces of output here. The first is our callback firing when the tool is called. You can see in toolResult
that the LLM has correctly passed 101
and 303
to our sumNumbers
function, which adds them up and returns 404
.
The second piece of output is the response from the LLM itself, where the message.content
key is giving us the answer.
Great! We've built an agent with tool use! Next you can: