Tool calling

Lecture 22

Dr. Benjamin Soltoff

Cornell University
INFO 5001 - Fall 2026

November 12, 2026

Announcements

Announcements

TODO

Learning objectives

  • Identify the value of calling external tools from LLMs
  • Define and call tools using {ellmer}
  • Define an AI agent
  • Identify the basic tools for AI agents
  • Implement a simple AI agent in R
  • Provide an AI agent with skills to complete a task

Application exercise

ae-20

Instructions

  • Go to the course GitHub org and find your ae-20 (repo name will be suffixed with your GitHub name).
  • Clone the repo in Positron, run renv::restore() to install the required packages, open the Quarto document in the repo, and follow along and complete the exercises.
  • Render, commit, and push your edits by the AE deadline – end of the day

🔓 Decrypt the .Renviron.secret → .Renviron

  1. source("secret.R")
  2. The special phrase is:
    info-5001

Recall: How do LLMs work?

  1. You write some words

  2. The LLM writes some more words

  3. You use those words

On their own, can LLMs… access the internet? send an email? interact with the world?

Let’s try it

library(ellmer)

chat <- chat("openai/gpt-6-luna")

chat$chat("What's the weather like in Ithaca, NY?")
chat$chat("What day is it?")

Tools

a.k.a. functions, tool calling or function calling

  • Bring real-time or up-to-date information to the model
  • Let the model interact with the world
  • Foundation for agentic AI

Chatbot systems

How do tool calls work?

What should I wear to campus tomorrow?

Human in the loop

👨‍💻 _demos/18_manual-tools/app.R

Wait… I can write code!

library(ellmer)

ellmer::create_tool_def(weathR::point_forecast, verbose = TRUE)
tool(
  weathR::point_forecast,
  name = "point_forecast",
  description = "Retrieve point forecast meteorological data for a latitude and longitude.",
  arguments = list(
    lat = type_number("Latitude."),
    lon = type_number("Longitude."),
    timezone = type_string(
      "Nominal timezone for the forecast, either an Olson timezone name or '-1' for local time. 
Defaults to '-1'.",
      required = FALSE
    ),
    dir_numeric = type_boolean(
      "Whether wind directions should be returned numerically rather than as character directions. 
Defaults to FALSE.",
      required = FALSE
    )
  )
)

Wait… I can write code!

get_weather <- tool(
  \(lat, lon) weathR::point_forecast(lat, lon),
  name = "point_forecast",
  description = "Get forecast data for a specific latitude and longitude.",
  arguments = list(
    lat = type_number("Latitude of the location."),
    lon = type_number("Longitude of the location.")
  )
)

Wait… I can write code!

get_weather(lat = 42.4397, lon = -76.4953)
Simple feature collection with 156 features and 8 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -76.4953 ymin: 42.4397 xmax: -76.4953 ymax: 42.4397
Geodetic CRS:  WGS 84
First 10 features:
                      time temp  dewpoint humidity p_rain wind_speed wind_dir         skies
1  2026-11-02 11:00:00 EST   62  8.888889       60      4          3        S  Partly Sunny
2  2026-11-02 12:00:00 EST   67  8.888889       50      4          5       SW  Partly Sunny
3  2026-11-02 13:00:00 EST   69  9.444444       49      4          3        S  Partly Sunny
4  2026-11-02 14:00:00 EST   69 10.000000       51      4          3        S  Mostly Sunny
5  2026-11-02 15:00:00 EST   71 10.000000       47      4          3        S  Mostly Sunny
6  2026-11-02 16:00:00 EST   69 10.555556       53      4          2        S  Partly Sunny
7  2026-11-02 17:00:00 EST   66  9.444444       54      4          3        S  Partly Sunny
8  2026-11-02 18:00:00 EST   62  8.888889       60      4          3        S Mostly Cloudy
9  2026-11-02 19:00:00 EST   59  8.888889       67      1          3       SE Mostly Cloudy
10 2026-11-02 20:00:00 EST   57  8.333333       69      1          3       SE Partly Cloudy
                   geometry
1  POINT (-76.4953 42.4397)
2  POINT (-76.4953 42.4397)
3  POINT (-76.4953 42.4397)
4  POINT (-76.4953 42.4397)
5  POINT (-76.4953 42.4397)
6  POINT (-76.4953 42.4397)
7  POINT (-76.4953 42.4397)
8  POINT (-76.4953 42.4397)
9  POINT (-76.4953 42.4397)
10 POINT (-76.4953 42.4397)

Wait… I can write code!

chat <- chat_openai(model = "gpt-6-luna", echo = "output")

# Register the tool with the chatbot
chat$register_tool(get_weather)

chat$chat("What should I wear to class tomorrow in Ithaca, NY?")
◯ [tool call] point_forecast(lat = 42.4444, lon = -76.5016)
#> [{"time":"2026-04-29 09:00:00 EDT","temp":55,"dewpoint":10,"humidity":83,"p_rain":3,"wind_speed":5,"wind_dir":"S","skies":"Cloudy","geometry":{"type":"Point","coordinates":[-76.5016,42.4444]…
#> In Ithaca tomorrow, expect cool temps and at least a chance of rain—especially around the day—roughly **mid-40s to low/mid-50s °F** with a **breezy NW wind**.
#> 
#> **Wear:**
#> - **Layers:** long-sleeve shirt + **sweater/hoodie**
#> - **Outerwear:** a **water-resistant/windproof jacket** (or shell)
#> - **Bottoms:** jeans or other long pants
#> - **Shoes:** **water-resistant** shoes/boots (mud/soggy sidewalks likely)
#> - **Carry:** a **small umbrella** or just rely on your rain jacket
#> 
#> If you tell me what time you have class (morning vs afternoon) and whether you’ll be walking a lot, I can fine-tune it.

Recap: Tool definitions in R

tool_get_weather <- tool(
  tool_fn,
  description = "How and when to use the tool",
  arguments = list(
    .... = type_string(),
    .... = type_integer(),
    .... = type_enum(
      c("choice1", "choice2"),
      required = FALSE
    )
  )
)

Agents

What’s an agent?

  • An LLM, in a harness, that calls tools repeatedly in a loop

  • Deciding each next step from the last result

How many tools does it take
to make an agent?

TODO drop if we don’t do the quiz game sound exercise

Did we just make a quiz game agent?

What kind of tools?

  • read tools to observe the world

  • write tools to change it

The agent loop

  • Explore: the agent reads to understand the world

  • Act: the agent writes to change it

  • Observe: the agent reads again to see what changed

  • …and repeat until the task is done

Brainstorm: tools for agents

Read tools

  • Read a file

Write tools

  • Write a file

Oh, and prompting!

Welcome to the Last Blockbuster

  • You work at the Last Blockbuster in the universe, in Bend, Oregon.

  • The store runs on its annual membership renewal drive.

  • Your job is to find members who have gone quiet and win them back.

Your Turn 19_agent-1

  1. Your agent works in the Last Blockbuster’s records folder.

  2. Wrap up a read tool and a write tool for it to use, then ask it to build the win-back list.

  3. Run the script it writes, then inspect the trace. Did it read the store rules before it wrote code?

05:00

Discussion: Did your agent…?

  • Read README.md and notes.md before it decided anything?

  • Write a script, instead of reading all 1,500 rentals through its tools?

  • Say things about the store’s rules that it never actually read?

  • Would you hand this list to your manager?

  • If you ran the code: how many lapsed members did it find?

Your Turn 20_agent-2

  1. Give your agent a list files tool and an edit tool.

  2. Build the win-back list script again. Do these tools make your agent more effective?

  3. Your manager found an old paper register!

  4. Without naming the file, ask the agent to bring the list up to date.

05:00

Discussion: Did your agent…?

  • Write a better find_lapsed script than in the last exercise, even before the export arrived?

  • Use list_files to find the export, instead of guessing the filename?

  • Patch the find_lapsed script with edit_file, or rewrite the whole script?

  • Hit an edit_file error — and was the error loud and safe?

  • Still get the right answer even when it skipped a tool?

Agents, recap

  • An agent is an LLM, in a harness, calling tools in a loop

  • Read tools observe; write tools change

  • The harness does the busy work — you write the tools and the system prompt

Agent Skills

Have you used a skill today?

If you asked Posit Assistant for /help today, you have!

Let’s look at it in .agents/skills/help/SKILL.md

SKILL.md

---
name: renewal-letters
description: Draft a renewal letter for a lapsed Last Blockbuster member.
---

# Renewal letters

Offer Basic members a free-rental code.
Offer Family members a family-night bundle.
Offer Founders members a commemorative card.

Anatomy of a skill

.agents/skills/
└── renewal-letters/
    ├── SKILL.md      # Required: metadata + instructions
    ├── references/   # Optional: documentation
    ├── scripts/      # Optional: executable code
    └── assets/       # Optional: templates, data files

Progressive disclosure

  1. Discovery
    the agent starts with name and description

  2. Activation
    when it decides to, the agent reads the full SKILL.md

  3. Execution
    after that, it’s in the agent’s robot hands

Why not just use the system prompt?

System prompt

instructions for every session

Skills

on-demand instructions

System prompt vs. user prompt

Short answer: Put instructions and background knowledge in the system prompt.

Put the current task in the user prompt.

The scene: win-back letters

Your win-back work paid off and found three Founders members we really want to keep. Your job is to write those letters.

Member Tier Last rented
Elaine Wu Founders The Princess Bride
Theo Bennett Founders The Matrix
Marisol Vega Founders The Goonies

Your Turn 21_skills-1

  1. Your Blockbuster agent gets a skill: renewal-letters holds the letter-writing instructions.

  2. List the skill in the system prompt, and give the agent a tool to read it.

  3. Draft letters for the top three lapsed members. Watch the agent read the skill before it starts drafting — and check them against the scene we just saw.

05:00

Discussion: Did your agent…?

  • Read the skill before it drafted a single letter?

  • Pick the right top three members from lapsed.csv?

  • Invent tier facts — a Founders perk for someone who isn’t one?

  • Mention overdue fees, even though the skill forbids it?

  • Leave the data files untouched?

Writing a skill that works

  • Add what the agent lacks; omit what it knows

  • The description is the trigger

  • Concrete beats generic

  • Keep it short

Your Turn 22_skills-2

  1. The skill has been swapped for a first draft with common problems.

  2. Use the diagnostic questions to fix SKILL.md, then re-run the letter task.

  3. Compare: same agent, same tools, different skill, different letters and token spend.

05:00

Discussion: Did your agent…?

  • Pick renewal-letters first, out of the four skills on offer?

  • Read a second skill before it started writing?

  • Follow the bad skill’s rules straight past the letter checklist?

  • Treat a vague description as a reason to hedge?

  • Write the same letters before and after your fix?

Skills in Posit Assistant

  • Built-ins: create-skill, r-package-development, quarto-authoring, …

  • Yours: ~/.posit/assistant/skills/ (all projects) or .agents/skills/ (this project)

  • Most skills also run as slash commands: /check-my-work

Skills in the ecosystem

npx skills add

Can you install the skill from…

Skills, recap

  • A skill is 📂 with SKILL.md: metadata plus instructions

  • Progressive disclosure: descriptions init, body on demand

  • Same format in Posit Assistant, Claude Code, Codex

Wrap-up

Recap

  • Tool calling lets LLMs access real-time information and interact with the world
  • We can define tools in R using {ellmer}
  • The Model Context Protocol (MCP) standardizes how LLMs can access tools

Acknowledgments