By AI Engineering Team

Build a Simple Tool-Using AI Agent - Wiring the LLM

Intermediate 6 min
AI AgentsLLMFunction CallingTypeScriptNode.jsAIOT

Wiring the LLM with Function Calling

Setting Up the OpenAI Client

Create src/agent.ts and set up the client:

import OpenAI from 'openai';
import * as dotenv from 'dotenv';

dotenv.config();

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

Define the System Prompt

The system prompt tells the model what it is and what it should do:

const SYSTEM_PROMPT = `You are a to-do list agent. You help users add, list, and complete tasks using the available tools.

When a user asks you to:
- Add a task: Use the addTodo tool
- List tasks: Use the listTodos tool
- Complete a task: Use the completeTodo tool

Always be helpful and confirm what you've done.`;

Define Tool Schemas

The LLM needs to know what tools are available. We define them as JSON schemas. Here’s how each tool is defined:



              {
type: 'function' as const,
function: {
  name: 'addTodo',
  description: 'Add a new todo item to the list',
  parameters: {
    type: 'object',
    properties: {
      text: {
        type: 'string',
        description: 'The text of the todo item',
      },
      dueDate: {
        type: 'string',
        description: 'Optional due date in YYYY-MM-DD format',
      },
    },
    required: ['text'],
  },
},
}
            

Each tool schema tells the LLM:

  • name: What the function is called
  • description: What it does (the LLM uses this to decide when to call it)
  • parameters: What arguments it needs
  • required: Which parameters are mandatory
const tools = [
  {
    type: 'function' as const,
    function: {
      name: 'addTodo',
      description: 'Add a new todo item to the list',
      parameters: {
        type: 'object',
        properties: {
          text: {
            type: 'string',
            description: 'The text of the todo item',
          },
          dueDate: {
            type: 'string',
            description: 'Optional due date in YYYY-MM-DD format',
          },
        },
        required: ['text'],
      },
    },
  },
  {
    type: 'function' as const,
    function: {
      name: 'listTodos',
      description: 'List all todo items',
      parameters: {
        type: 'object',
        properties: {},
      },
    },
  },
  {
    type: 'function' as const,
    function: {
      name: 'completeTodo',
      description: 'Mark a todo item as completed',
      parameters: {
        type: 'object',
        properties: {
          id: {
            type: 'number',
            description: 'The ID of the todo to complete',
          },
        },
        required: ['id'],
      },
    },
  },
];

Making the First Call

Here’s how to call the model with tools:

async function callAgent(userMessage: string) {
  const messages = [
    { role: 'system' as const, content: SYSTEM_PROMPT },
    { role: 'user' as const, content: userMessage },
  ];

  const response = await client.chat.completions.create({
    model: 'gpt-4o-mini',
    messages,
    tools,
    tool_choice: 'auto',
  });

  return response;
}

Handling Tool Calls

When the model wants to call a tool, it returns tool_calls in the response:

const message = response.choices[0].message;

if (message.tool_calls) {
  // The model wants to call tools
  for (const toolCall of message.tool_calls) {
    const functionName = toolCall.function.name;
    const args = JSON.parse(toolCall.function.arguments);

    // Call the actual function
    let result;
    if (functionName === 'addTodo') {
      result = addTodo(args.text, args.dueDate);
    } else if (functionName === 'listTodos') {
      result = listTodos();
    } else if (functionName === 'completeTodo') {
      result = completeTodo(args.id);
    }

    // Send the result back to the model
    messages.push({
      role: 'tool' as const,
      content: JSON.stringify(result),
      tool_call_id: toolCall.id,
    });
  }

  // Call the model again with the tool results
  const secondResponse = await client.chat.completions.create({
    model: 'gpt-4o-mini',
    messages,
    tools,
    tool_choice: 'auto',
  });

  return secondResponse;
}

Spot the Bug

Here’s a common mistake. What’s wrong with this code?

const args = toolCall.function.arguments;
const result = addTodo(args.text);

Answer: arguments is a string, not an object. You need to JSON.parse it first:

const args = JSON.parse(toolCall.function.arguments);

🔷 TypeScript Parsing Tool Arguments
📟 Console Output
Run code to see output...

Now you understand how to wire tools to the LLM. Let’s build the complete agent loop.


Discussion

Join the conversation and share your thoughts

Discussion

0 / 5000