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'],
},
},
}
{
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'],
},
},
}
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.
Progress 75%
Page 6 of 8
← Previous
→ Next