Logo
Guide/Agents

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
  • tool to provide tools to our agent
  • agent to create the single agent
  • Settings to define some global settings for the library
  • Dotenv to load our API key from the .env file
  • Zod to define the schema for our tool
import "dotenv/config";
import {
  agent,
  AgentStream,
  tool,
  openai,
  Settings,
} from "llamaindex";
import { z } from "zod";

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 = openai({
  apiKey: process.env.OPENAI_API_KEY,
  model: "gpt-4o",
});

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 tool. 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 and b. We describe each parameter as a number, and we say that both are required.
  • You can see more examples of function schemas.
const addTool = tool({
  name: "sumNumbers",
  description: "Use this function to sum two numbers",
  parameters: z.object({
    a: z.number({
      description: "First number to sum",
    }),
    b: z.number({
      description: "Second number to sum",
    }),
  }),
  execute: sumNumbers,
});

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 = [addTool];

Create the agent

With your LLM already set up and your tools defined, creating an agent is simple:

const myAgent = agent({ 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.

const context = myAgent.run("Sum 101 and 303");
const result = await context;
console.log(result.data);

You will see the following output:

Output

{ result: 'The sum of 101 and 303 is 404.' }

To stream the response, you can use the AgentStream event which provides chunks of the response as they become available. This allows you to display the response incrementally rather than waiting for the full response:

const context = myAgent.run("Add 101 and 303");
for await (const event of context) {
  if (event instanceof AgentStream) {
    process.stdout.write(event.data.delta);
  }
}

Streaming Output

The sum of 101 and 303 is 404.

Logging workflow events

To log the workflow events, you can check the event type and log the event data.

const context = myAgent.run("Sum 202 and 404");
for await (const event of context) {
  if (event instanceof AgentStream) {
    // Stream the response
    for (const chunk of event.data.delta) {
      process.stdout.write(chunk);
    }
  } else {
    // Log other events
    console.log("\nWorkflow event:", JSON.stringify(event, null, 2));
  }
}

Let's see what running this looks like using npx tsx agent.ts

Output

Workflow event: {
  "data": {
    "userInput": "Sum 202 and 404"
  },
  "displayName": "StartEvent"
}

Workflow event: {
  "data": {
    "input": [
      {
        "role": "user",
        "content": "Sum 202 and 404"
      }
    ],
    "currentAgentName": "Agent"
  },
  "displayName": "AgentInput"
}

Workflow event: {
  "data": {
    "input": [
      {
        "role": "system",
        "content": "You are a helpful assistant. Use the provided tools to answer questions."
      },
      {
        "role": "user",
        "content": "Sum 202 and 404"
      }
    ],
    "currentAgentName": "Agent"
  },
  "displayName": "AgentSetup"
}

....

We're seeing several workflow events being logged:

  1. AgentToolCall - Shows the agent preparing to call our tool with the numbers 202 and 404
  2. AgentToolCallResult - Shows the result of calling the tool, which returned "606"
  3. AgentInput - Shows the original user input
  4. AgentOutput - Shows the agent's response

Great! We've built an agent that can understand requests and use tools to fulfill them. Next you can:

Edit on GitHub

Last updated on

On this page