Tool Design

Agents are only as good as their tools. Descriptions drive selection, validation blocks chaos, errors teach recovery. Tool design IS agent design.

▶ Watch this reel

What you'll learn

  1. Schemas & descriptions
  2. Validation
  3. Errors the model can fix
  4. Idempotency, parallelism & tool overload

Remember this

Schemas & descriptions

Validation

Errors the model can fix

Craft

Code: A production-grade tool: validated, idempotent, self-explaining errors

from pydantic import BaseModel, Field
from typing import Literal

class SearchDocs(BaseModel):
    query: str = Field(min_length=2, max_length=200,
                       description="standalone keywords, not a question")
    top_k: int = Field(default=5, ge=1, le=10)
    date_after: str | None = Field(
        default=None, pattern=r"^\d{4}-\d{2}-\d{2}$")

def search_documents(args: SearchDocs, user: User):
    if not user.can_search:
        raise ToolError("permission denied: search requires the 'kb' role")
    try:
        hits = vdb.search(embed(args.query), k=args.top_k,
                          where={"acl": {"$in": user.groups}})
    except IndexUnavailable:
        raise ToolError("search index temporarily unavailable — "
                        "retry in ~30s or answer from general knowledge")
    if not hits:
        raise ToolError(
            f"no results for '{args.query}'. Try broader keywords "
            "(e.g. drop qualifiers) or a date filter reset.")
    return [{"id": h.id, "snippet": h.text[:300]} for h in hits]

# Note: ToolError messages are written FOR THE MODEL — constraints,
# received values, next steps. They are the loop's feedback signal.