AI Agents and MCP in Production · Agent Loops That Behave

Tool Definitions the Model Can't Misuse

Ambiguous parameters and overlapping tools cause silent mistakes; precise schemas, enums and strict validation prevent them.

Create a free account to save this page, take notes and track your progress. Sign in

Scenario

Example app: a scheduling agent books meetings with a tool book_meeting(date, duration, room). Customers write dates in every format: "3/4", "next Friday", "2026-04-03".

What you see in production

A customer in London asks for a meeting "on 03/04". The meeting lands on March 4 instead of April 3. Another booking has a duration of "1h30", which the tool reads as 30 minutes. Nobody sees an error: the bookings simply happen on the wrong day.

The naive code

tools = [{
    "name": "book_meeting",
    "description": "Book a meeting.",
    "input_schema": {"type": "object", "properties": {
        "date": {"type": "string"}, "duration": {"type": "string"}, "room": {"type": "string"}}},
}]

def book_meeting(date, duration, room):
    when = parse_any_date(date)            # guesses month/day order
    minutes = int(re.findall(r"\d+", duration)[-1])
    return calendar.book(when, minutes, room)

Reproduce it

The same model output, handled by a lenient tool and by a strict one:

Lenient parsing books the wrong day; strict validation asks againTry it yourself
import re
from datetime import date

def lenient(args):
    m, d = (int(x) for x in args["date"].split("/"))          # assumes US month/day
    minutes = int(re.findall(r"\d+", args["duration"])[-1])
    return f"booked {date(2026, m, d).isoformat()} for {minutes} min in {args['room']}"

ROOMS = {"oak", "maple", "pine"}

def strict(args):
    errors = []
    if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", args.get("date", "")):
        errors.append("date must be ISO 8601 (YYYY-MM-DD); ask the user if the day is ambiguous")
    if not isinstance(args.get("duration_minutes"), int) or not 15 <= args["duration_minutes"] <= 240:
        errors.append("duration_minutes must be an integer between 15 and 240")
    if args.get("room") not in ROOMS:
        errors.append(f"room must be one of {sorted(ROOMS)}")
    if errors:
        return {"is_error": True, "content": "; ".join(errors)}
    return f"booked {args['date']} for {args['duration_minutes']} min in {args['room']}"

print(lenient({"date": "03/04", "duration": "1h30", "room": "Oak"}))
print(strict({"date": "03/04", "duration": "1h30", "room": "Oak"}))
print(strict({"date": "2026-04-03", "duration_minutes": 90, "room": "oak"}))

Output

booked 2026-03-04 for 30 min in Oak
{'is_error': True, 'content': "date must be ISO 8601 (YYYY-MM-DD); ask the user if the day is ambiguous; duration_minutes must be an integer between 15 and 240; room must be one of ['maple', 'oak', 'pine']"}
booked 2026-04-03 for 90 min in oak

Root cause

The model fills parameters from the description and schema it is given. "date: string" and "duration: string" invite free text, and the tool then guesses. Each guess is a silent decision the user never sees. Overlapping or vaguely named tools cause the same problem one level up: the model picks fetch_user when it needed lookup_customer.

The fix

Make the schema carry the rules, validate strictly, and return errors the model can act on:

{
  "name": "book_meeting",
  "description": "Book a meeting room. Use only after the user has confirmed the exact date. "
                 "Dates are ISO 8601 in the user's time zone; if the user wrote a date like 03/04, ask which day they mean.",
  "input_schema": {
    "type": "object",
    "properties": {
      "date": {"type": "string", "format": "date", "description": "YYYY-MM-DD"},
      "duration_minutes": {"type": "integer", "minimum": 15, "maximum": 240},
      "room": {"type": "string", "enum": ["oak", "maple", "pine"]}
    },
    "required": ["date", "duration_minutes", "room"],
    "additionalProperties": false
  }
}

Keep the tool set small and distinct: one tool per job, names that say what they do (search_customers_by_email, not get_data), and descriptions that say when not to use the tool.

Trade-offs

  • Strict schemas cause more back-and-forth with the user, which is the point when a mistake is costly; for low-stakes tools, defaults are fine.
  • Enums must stay in sync with the real data; generate them from the source of truth or validate server-side and return the valid list.
  • Fewer, broader tools reduce confusion but push more logic into parameters; split tools when their safety level differs.

Detect it in production

  • Log validation errors per tool and parameter; a parameter that fails often needs a clearer description.
  • Sample conversations where a tool was called right after another tool with similar purpose (wrong-tool retries).
  • Compare booked values with what the user typed in a review sample.

Key points

  • Parameters should be typed, constrained and described, not free text the tool must guess.
  • Validate strictly and return errors that tell the model how to recover.
  • Keep tools few, distinct and named for what they do.

Further reading: Define tools (input_schema) · Writing tools for agents · JSON Schema reference

Practice questions

Why is a `date: string` parameter risky in a tool definition?

Answer

It invites free-form dates that the tool then has to guess, for example whether 03/04 is March 4 or April 3. The guess is a silent decision. A format like ISO 8601 plus an instruction to ask when ambiguous moves the decision to the user.

What should a tool return when its input fails validation?

Answer

A tool result marked as an error, with a specific message explaining which value was wrong and what is valid, so the model can correct the call or ask the user.

How do overlapping tools hurt an agent, and what is the fix?

Answer

The model picks between similar tools by name and description, so overlap leads to the wrong tool being used. Keep one tool per job with specific names and descriptions that also say when not to use it.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?