Module 3: `search_docs` as an Agent Tool

Writing the `description` So the Model Knows When

Description

You've already declared search_docs's complete input_schema (Lesson 03) and already know what shape its return value has (Lesson 04). What's missing is the piece that decides whether the model uses it at the right moment: the description. In agent-fundamentals-and-tool-calling Module 2, Lesson 04 you already saw, by running it, why that field isn't a comment that "would be nice" to write carefully — it's the only prose the model reads to choose between available tools. This lesson applies that same criterion to a new case: a Reservo agent that has, at the same time, structured tools (get_quote, book_room) and a retrieval tool (search_docs) — and needs to tell them apart, from the description alone, when each one applies.

You're going to reuse the description-quality checker (check_description) exactly as you left it in agent-fundamentals-and-tool-calling, and you're going to see, as a concept, how the same user question leads the model to a different decision depending on how clear search_docs's description is.

Connection to the module

Lesson 03 declared search_docs's description without dwelling on it. This lesson revisits it in depth, with the same rigor agent-fundamentals-and-tool-calling gave book_room's. Lesson 06 keeps building on this foundation: a description that says clearly what the tool does also makes it clearer why it needs to be bounded.


Analogy: the desk's complete sign

The internal-archive help desk already had, since Lesson 03, its name and its request form. What it was missing was the explanatory text under the name — the one that tells anyone who approaches what kind of questions this particular desk handles, and which other desk to go to if the question is different. "Document Inquiries: policies, FAQs, and room manuals. To quote a price or make a booking, go to the Reservations desk." Without that sign, someone with a price question might end up in the wrong line — not because the document desk couldn't answer it, but because nobody told them where they should be asking. search_docs's description is exactly that sign.


What a retrieval tool's description has to say

The same double question from agent-fundamentals-and-tool-calling still applies: what the tool does and when to use it. But search_docs adds a third question get_quote didn't need to answer as forcefully, because Reservo already has other tools it could be confused with:

WHAT it does   -> searches document fragments by lexical relevance
WHEN to use it -> when the question needs to cite a policy, FAQ, or manual
WHEN NOT       -> not for quoting a price (get_quote) or booking/cancelling (book_room/cancel_booking)

The third question matters especially here because search_docs and get_quote can look, at first glance, related: a question like "how much does it cost to cancel my Boardroom booking?" has a price part (get_quote) and a policy part (search_docs) mixed into the same sentence. Without a description that draws the line clearly, the model has no way of knowing it needs both tools, or which of the two answers which part.


Worked example: the reused checker, on two versions of the description

We reuse check_description exactly as it was left in agent-fundamentals-and-tool-calling Module 2, Lesson 04 — same code, unadapted.

import re


def check_description(description):
    """Minimal quality heuristic for a tool's `description`.
    Returns a list of warnings; empty list = passes the basic heuristics."""
    warnings = []
    text = description.strip()

    if len(text) < 20:
        warnings.append("too short: not enough to say WHAT it does and WHEN to use it")

    if not re.search(r"use this tool when|when the user|when the question|when this", text, re.IGNORECASE):
        warnings.append("doesn't say WHEN to use it (missing a cue like 'use this tool when...')")

    words = re.findall(r"[a-z]+", text.lower())
    if len(set(words)) <= 3:
        warnings.append("only repeats a handful of words, adds almost no information")

    return warnings

We test it against a deliberately vague version and against SEARCH_DOCS_SCHEMA's complete description, which you already declared in Lesson 03.

VAGUE_DESCRIPTION = "Searches documents."

GOOD_DESCRIPTION = (
    "Searches Reservo's internal documents (cancellation/refund/no-show "
    "policies, booking/membership/payment FAQs, room manuals) for fragments "
    "that might contain the answer to a natural-language question. Returns "
    "at most `k` fragments, each with its source doc_id and a lexical "
    "relevance score. Use this tool when the user's question requires "
    "citing a policy, an FAQ, or a manual; do not use it to quote a price "
    "or create a booking (use get_quote/book_room for that)."
)

for label, text in [("vague", VAGUE_DESCRIPTION), ("good", GOOD_DESCRIPTION)]:
    print(f"{label!r:10} -> {check_description(text)}")

What to expect:

'vague'    -> ['too short: not enough to say WHAT it does and WHEN to use it', "doesn't say WHEN to use it (missing a cue like 'use this tool when...')", 'only repeats a handful of words, adds almost no information']
'good'     -> []

"Searches documents." triggers all three warnings, the same as "Quote it." did in agent-fundamentals-and-tool-calling. search_docs's complete description passes clean: it says what it does (searches fragments, with what limit and what result shape), says when to use it, and says explicitly when not to — the final clause about get_quote/book_room isn't filler, it's exactly the kind of boundary that avoids the confusion the previous section talks about.


Concept: the model choosing between search_docs and get_quote

This part is conceptual: no model actually runs — it's a realistic example of how claude-sonnet-5 would reason with Reservo's available tools (get_quote, book_room, cancel_booking from agent-fundamentals-and-tool-calling, plus search_docs from this guide).

Suppose that, besides SEARCH_DOCS_SCHEMA with VAGUE_DESCRIPTION, the model also has GET_QUOTE_TOOL with its complete description ("Quotes a room's price for a tier and a number of hours, without booking anything. Use this tool when the user asks how much a booking costs."). The user asks: "What's the cancellation policy for Boardroom?"

[user]  What's the cancellation policy for Boardroom?

[model·concept, with VAGUE_DESCRIPTION on search_docs]
The available tools are "get_quote" (quotes a room's price) and
"search_docs" ("Searches documents." - no further context on what kind of
documents or when it applies). The question mentions "Boardroom," the
same word that appears in get_quote's room enum. Without a description
that clarifies search_docs covers policies, the strongest signal
available is "Boardroom" matching a known get_quote argument.
decision -> tries to answer with generated text, without calling any tool,
            or calls get_quote with incomplete data (missing tier and hours,
            which the question never gave)

Without a description that tells the model that "cancellation policy" is exactly the kind of question search_docs handles, the model has no clear signal that a tool built for this even exists — and ends up either inventing an answer with no source, or forcing a tool that doesn't fit. Now the same question, with GOOD_DESCRIPTION:

[model·concept, with GOOD_DESCRIPTION on search_docs]
"get_quote" quotes prices; its description explicitly says it doesn't
book anything or resolve anything else. "search_docs" also explicitly
says it covers "cancellation ... policies" -verbatim- and that it's the
tool for questions that require citing a policy. The user's question is
literally about a cancellation policy, not a price.
decision -> use_tool "search_docs" with {"query": "What is the cancellation
            policy for Boardroom bookings?", "k": 3}

Nothing changed about the user or the available tools — only the text of a description. That is, again, the weight of what you write in that field: it isn't reference documentation for a developer who already knows the system, it's the operational signal that decides whether the agent searches the right documents or improvises an answer with no source.


Checklist for a retrieval tool's description

Besides agent-fundamentals-and-tool-calling's general checklist (what it does, when to use it, when not to, whether it has real effects, no internal jargon), a retrieval tool like search_docs benefits from two specific points:

  1. Does it say what kind of content the corpus covers? "Searches documents" says nothing; "cancellation/refund/no-show policies, booking/membership/payment FAQs, room manuals" gives the model a concrete list of topics to recognize when a question fits.
  2. Does it clarify the result comes with a score, not a final answer? The model needs to know what it receives are candidate fragments, not an already-written answer — that shapes how it should use the result (read and synthesize, not repeat verbatim without checking relevance).

Common mistakes

  1. Copying get_quote's checklist without adapting the third question. "When NOT to use it" for a structured tool like get_quote is different from "when NOT to use it" for a retrieval tool — in the second case, the typical risk isn't confusing two actions (quoting vs. booking), it's confusing "I need data from a document" with "I need a structured calculation." Explicitly naming get_quote/book_room in search_docs's description (and vice versa, if you wrote them together) is what resolves that specific ambiguity.

  2. Promising that search_docs "always finds the answer." The description shouldn't suggest the tool is infallible — BM25 is lexical retrieval, and an honest description doesn't create expectations the index can't meet. Lesson 07 shows a real 0-result case.

  3. Forgetting to mention the k limit in the description. If the model doesn't know the result comes bounded to a maximum number of fragments, it might be surprised to receive fewer than expected. Saying it explicitly ("at most k fragments") avoids that surprise.

  4. Writing a generic description that would work for any search tool, not specifically for Reservo's corpus. "Searches for relevant information" is almost as vague as "Searches documents." — naming the corpus's real topics (policies, FAQs, manuals) is what makes it actionable for the model in this specific domain.


Exercises

Exercise 1: Vague or good (Easy)

For each description of a hypothetical search tool, say whether it's "vague" or "good" and why, without running anything: (a) "Look up info."; (b) "Searches Reservo's room manuals (Focus, Studio, Boardroom, Lounge, Phonebooth) for capacity and equipment details. Use this tool when the user asks what's in a specific room, not to quote its price."; (c) "Document tool.".

See solution
  • (a) Vague. Doesn't say what documents it searches, doesn't say when to use it, and is almost as short as the worked example's VAGUE_DESCRIPTION.
  • (b) Good. Says the what (searches room manuals, with concrete examples of the five rooms), says when to use it (questions about what's in a room), and says when not (quoting a price, setting it apart from get_quote).
  • (c) Vague. It's a label ("Document tool"), not a description — it doesn't say what kind of documents, or when it applies versus another tool.

Exercise 2: Run the checker on three variants (Medium)

Using check_description, evaluate and run: (a) "Searches fragments of Reservo's policies and manuals. Use this tool when the user asks about a policy or a manual."; (b) "Documents."; (c) "This tool searches for things related to Reservo in general.".

See solution
cases = [
    "Searches fragments of Reservo's policies and manuals. Use this tool when the user asks about a policy or a manual.",
    "Documents.",
    "This tool searches for things related to Reservo in general.",
]

for text in cases:
    print(f"{text!r}\n  -> {check_description(text)}\n")

Expected output:

"Searches fragments of Reservo's policies and manuals. Use this tool when the user asks about a policy or a manual."
  -> []

'Documents.'
  -> ['too short: not enough to say WHAT it does and WHEN to use it', "doesn't say WHEN to use it (missing a cue like 'use this tool when...')", 'only repeats a handful of words, adds almost no information']

'This tool searches for things related to Reservo in general.'
  -> ["doesn't say WHEN to use it (missing a cue like 'use this tool when...')"]

Explanation: (a) passes all three heuristics. (b) fails all three, as you'd expect from a single word. (c) is long and uses varied vocabulary, so it passes two heuristics, but "searches for things related to Reservo in general" doesn't say when it applies versus another tool — exactly the same pattern NAME_ONLY_DESCRIPTION showed in agent-fundamentals-and-tool-calling.

Exercise 3: Rewrite it and explain the risk (Hard)

Take this real search_docs description, deliberately poorly written for this exercise: "Searches for things in Reservo.". (a) Rewrite it following this lesson's checklist. (b) Confirm it with check_description. (c) In one sentence, explain what could go wrong if the agent had this tool with the vague description, facing the question "Does Reservo accept bank transfer?".

See solution

(a) Rewrite:

SEARCH_DOCS_DESCRIPTION_FIXED = (
    "Searches fragments of Reservo's internal documents (policies, "
    "payment and membership FAQs, room manuals) relevant to a "
    "natural-language question. Use this tool when the user asks "
    "something a Reservo document could answer; do not use it to "
    "quote prices or create a booking."
)

(b) Confirmed by running it:

print(check_description("Searches for things in Reservo."))
print(check_description(SEARCH_DOCS_DESCRIPTION_FIXED))

Expected output:

["doesn't say WHEN to use it (missing a cue like 'use this tool when...')"]
[]

(c) The risk (concept): with "Searches for things in Reservo." as its only clue, the model has no way of knowing that questions about payment methods are covered by this tool — "things" doesn't mention payments, policies, or FAQs. Faced with "Does Reservo accept bank transfer?", the model might not recognize search_docs as the right tool and answer from memory, with no real source, risking an invented answer about payment methods when the real payment-methods-faq corpus has a correct, verifiable one.


Summary and next step

  • search_docs's description answers three questions, not two: what it does, when to use it, and when NOT to — that last one explicitly naming get_quote/book_room, because they're the tools a mixed question (price + policy) is most easily confused with.
  • We reused check_description from agent-fundamentals-and-tool-calling unchanged and confirmed, by running it, that SEARCH_DOCS_SCHEMA's description passes clean while a vague version triggers all three warnings.
  • We saw, as a concept, how the same question about Boardroom's cancellation policy leads the model to different decisions — inventing an answer with no source vs. correctly calling search_docs — just from changing the description's text.

Next lesson: 06 — Bounding the tool: k and truncation. The description already makes clear what the tool does and when to use it; now we put real limits on how much it returns every time it runs.


Additional resources

  1. Anthropic — Implement tool use — Anthropic's best practices for writing descriptions, including being explicit about when NOT to use a tool.
  2. agent-fundamentals-and-tool-calling-guide, Module 2, Lesson 04 (Writing descriptions) — the exact source of check_description, reused unchanged in this lesson.
  3. Anthropic — Tool use (function calling) overview — The official reference confirming description is the only natural-language field guiding tool selection.
  4. Python — re (Regular expressions)re.search, the function the checker uses to look for "when to use it" cues in the text.