The standard advice for making data ready for AI agents is to add: add documentation, add metadata, add lineage, add governance. The change that actually improves tool-calling reliability is the opposite. Delete the overlapping fields the model has to guess between.
Tool calling is the mechanism where a model picks a function and fills in its arguments from a schema you hand it. That schema is the entire world the model sees. If it contains three fields that could plausibly answer "when did this order happen," the model picks one on every single call, and there is no guarantee it picks the same one twice.
Why more documentation doesn't fix ambiguity
Writing a description for an ambiguous field doesn't remove the ambiguity. It moves the disambiguation cost from schema design time, where you pay it once, to inference time, where you pay it on every call. The model reads the description, holds it in context, and still has to choose between two fields that look alike. You have not made the decision easier. You have made it recurring.
The mainstream guidance optimizes for the wrong failure mode. Enrichment, context layers, and metadata catalogs solve the human-analyst problem: someone opens a dashboard, doesn't know what amount means, and reads a paragraph once. An analyst can skim past a field they don't need. A model filling a function argument, or reading a result to decide what to do next, does not get to ignore a field for free. Every extra similar-looking field is one more wrong-answer path.
And the failure shape is worse. A missing required argument produces a validation error your caller can catch. An ambiguous field produces a plausible wrong answer that ships to a user.
The article nobody reads as a field-deletion argument
The recent martinfowler.com piece Making Your Data Ready for Agentic AI is mostly read as an addition argument. Its four topics are data contracts and quality, traceability and governance, a context layer that encodes what your metrics and entities mean, and the step from searchable to actionable. Each one is something you build on top of what you already have.
To its credit, the piece already makes the subtraction argument at the tool level, and makes it explicitly. It calls naive one-to-one API-to-MCP conversion an antipattern, describes the resulting sprawl of fifty barely distinguishable wrappers, and argues that five to ten well-described capabilities will outperform them almost every time. Some of that surface area has to stop existing, and the article says so.
Where it stops is one level down. It does not tell you to delete fields. But the arithmetic of "shaped for machines, not humans" works exactly the same way inside a single schema as it does across a tool list: fewer, clearer, non-overlapping things to choose between. If fifty similar tools degrade tool selection, thirteen similar fields degrade argument filling and result reading for the same reason. The consolidation argument doesn't end at the tool boundary. It just usually stops being applied there.
The habit of treating more structure as monotonically good comes from BI tooling, where it mostly is. Add a column to a dashboard and nobody who doesn't need it is harmed. Add a field to a tool schema and every call now carries one more chance of picking it by mistake.
Pruning a real tool schema
Here's a get_order result schema that grew the way real ones do: one field per stakeholder request, none ever removed. Result schemas matter as much as parameter schemas, because whatever comes back lands in the model's context and feeds the next decision.
{
"order_id": "string",
"customer_id": "string",
"created_at": "ISO8601 timestamp",
"order_placed_date": "date the customer submitted the order",
"payment_cleared_at": "ISO8601 timestamp",
"updated_at": "ISO8601 timestamp",
"status": "open | paid | shipped | closed",
"stage": "cart | checkout | fulfillment | done",
"fulfillment_state": "pending | picked | dispatched",
"total": "number",
"total_gross": "number",
"region": "sales territory code",
"ship_region": "physical destination region"
}Three overlaps, each one a coin flip at inference time. Four time-like fields where a question about "when the order happened" has no single right answer. Three fields describing progress through the same pipeline. Two totals that differ by tax, and two regions that differ by meaning, both distinguishable only by reading the description carefully every time.
Pick one winner per concept and drop the rest from the exposed schema.
{
"order_id": "string",
"customer_id": "string",
"placed_at": "ISO8601 timestamp, when the customer submitted the order",
"status": "cart | checkout | paid | picked | dispatched | closed",
"total_gross": "number, includes tax, in order currency",
"currency": "ISO 4217 code",
"ship_region": "physical destination region code"
}The three progress fields collapse into one status enum that spans the whole lifecycle, because they were always describing one pipeline through three teams' vocabularies. total disappears and total_gross stays, with currency added so the number is interpretable without a second call. The sales territory code goes away entirely: it is a reporting dimension, and no agent action depends on it.
Nothing here is a migration. The columns still exist. The reporting layer still reads region. What changed is the slice the model sees.
What to do next
Open the tool schema your agent actually calls, list the fields, and group them by the question they answer. Any group with more than one member is a coin flip you are paying for on every call. Pick the winner, cut the rest from the exposed schema, and run your eval set again before you write a single new description.