The Agent-Computer Interface: Designing Tools for LLM Agents

A ReAct agent's behavior is determined by two things: the model's choices and the tools the model chooses from. Teams typically invest in the first and leave the second alone. Anthropic's engineering team, reporting on their SWE-bench agent, inverts this implicitly when they note that "we actually spent more time optimizing tools than the overall prompt" (Anthropic, 2024). Their multi-agent research team is blunter: "Agent-tool interfaces are as critical as human-computer interfaces. Bad descriptions send agents down completely wrong paths."

The discipline that addresses this is called the Agent-Computer Interface, or ACI. The phrase is a deliberate parallel to Human-Computer Interface: the ACI is the surface through which the agent observes the world and acts on it. This article covers the principles of good ACI design, the anti-patterns that cause agents to flail, and two advanced extensions Anthropic shipped in late 2025 to reduce token overhead at scale. The stakes are concrete. A tool-testing agent that iteratively rewrote tool descriptions produced a 40 percent decrease in task completion time on the same benchmark, without changing the underlying model.

Tools as a contract

A tool has three observable parts: a name, a description, and a parameter schema. The agent sees all three and nothing more. Whatever the tool actually does on the backend is invisible; only the contract is visible. Good ACI design treats that contract the way good API design treats a public interface: clear names, tight schemas, honest documentation, and no surprises.

The checklist below reorganizes the principles from Anthropic's writeups into a form usable at review time.

The name and description alone must convey what the tool does. An agent reading only those two fields should make the same decision a capable engineer would.

Parameter names are docstrings for a junior developer. Prefer absolute_file_path over path, max_results over limit, and user_email over email.

Descriptions should include edge cases and examples. The model learns from the examples as it would from a few-shot prompt.

Output format should be easy for the LLM to parse. Natural text is safest; structured JSON is fine; custom DSLs need justification.

Error messages should be descriptive enough for the model to self-correct. "File not found: /tmp/foo.txt (did you mean /tmp/Foo.txt?)" is far more useful than "404".

Tools should be poka-yoke (mistake-proof). Require absolute paths, not relative; require explicit scopes, not default-all; require the argument the model most often forgets to state.

Toolset should minimize overlap. If a human cannot decide between two tools for a request, the agent cannot either.

Tools should allow room to think. A tool whose first parameter is the final answer forces the model to commit without reasoning. Prefer tools that accept intermediate artifacts.

What the interface looks like

flowchart LR
A[Agent LLM] -->|tool call: name + args| T[Tool runtime]
T -->|validated args| IMPL[(Tool implementation)]
IMPL -->|result or descriptive error| T
T -->|observation| A
META[Description, param schema, examples] -.drives choice.-> A

The description, the parameter schema, and the example text are not metadata in the traditional sense. They are the input through which the agent chooses among available tools. A change to the description is a change to agent behavior.

Two versions in code

The excerpt below is a well-specified tool without a framework. Note the description length, the absolute-path requirement, and the descriptive error.

def read_file_spec():
return {
"type": "function",
"function": {
"name": "read_file",
"description": (
"Read the contents of a file at an ABSOLUTE path. "
"Returns the file contents as text. "
"Use this when the user asks about the contents of a specific file "
"or when you need to inspect configuration. "
"Example: read_file(absolute_file_path='/etc/hosts'). "
"Errors are returned as descriptive strings, not thrown."
),
"parameters": {
"type": "object",
"properties": {
"absolute_file_path": {
"type": "string",
"description": "Absolute filesystem path. Must start with '/'. "
"Relative paths are rejected.",
}
},
"required": ["absolute_file_path"],
},
},
}

def read_file_impl(absolute_file_path: str) -> str:
if not absolute_file_path.startswith("/"):
return f"error: path must be absolute. Got: {absolute_file_path}"
try:
with open(absolute_file_path) as f:
return f.read()
except FileNotFoundError:
return f"error: file not found at {absolute_file_path}"

The LangChain version achieves the same contract through a decorator. The docstring becomes the description; the type hints become the parameter schema; the function body is the implementation.

from langchain_core.tools import tool

@tool
def read_file(absolute_file_path: str) -> str:
"""Read the contents of a file at an ABSOLUTE path.

Returns the file contents as text. Use this when the user asks about
the contents of a specific file or when you need to inspect configuration.

Example: read_file(absolute_file_path="/etc/hosts").

Errors are returned as descriptive strings, not thrown.
"""
if not absolute_file_path.startswith("/"):
return f"error: path must be absolute. Got: {absolute_file_path}"
try:
with open(absolute_file_path) as f:
return f.read()
except FileNotFoundError:
return f"error: file not found at {absolute_file_path}"

Full runnable versions live at github.com/subodhjena/agentic-patterns under examples/07_tool_use.py and examples/07_tool_use_langgraph.py.

Anti-patterns that break the loop

Each of the patterns below has a named failure mode. All are drawn from Anthropic's design principles and from observed production traces.

Relative file paths. The agent loses track of the current working directory across tool calls. Absolute paths remove the ambiguity and are a classic poka-yoke.

Diff format for edits. Diffs require accurate line counting; models are unreliable at it. Prefer search-and-replace or full-file rewrites.

Code inside JSON strings. Escaping is a minefield. Use a separate parameter for code, or accept code as a fenced block in a text field.

Generic "do anything" tools. A tool that takes a free-text command and does something with it removes the model's ability to reason about when to invoke it. Split into specific, named tools.

Missing error messages. A tool that returns only "failed" gives the model nothing to correct. Return what failed, why, and, where possible, what the model should try next.

Bloated toolsets. Twenty or more tools in one agent produce decision paralysis. Either split the agent or add a tool-search layer, discussed next.

Each anti-pattern has a symptom and a fix, and the fix is almost always cheap to ship. Unlike prompt tuning, tool design changes are usually one-line edits that affect many traces at once.

Advanced tool use at scale

Anthropic shipped two features in late 2025 that address ACI problems specific to agents with large tool inventories (Anthropic, 2025).

Tool Search Tool. Tools marked defer_loading: true are discoverable but not preloaded into the context. A special search_tools tool returns matching tool definitions on demand. In a test with over fifty tools, the technique reduced tool-related token overhead from 72,000 to 8,700, an 85 percent reduction, while preserving access to every tool.

Programmatic Tool Calling. Instead of emitting a single tool call per turn, the agent writes Python that orchestrates multiple tool calls inside a code-execution environment. The results stay in the environment rather than flowing through the context window, which removes token pressure on intermediate artifacts. On complex tasks, a 37 percent token reduction was reported, often using asyncio.gather for parallelism.

Both features address the same underlying issue: tool metadata and tool outputs compete with reasoning for scarce window space. The fixes are structural rather than prompt-level.

Investing in ACI versus prompt tuning

The case for investing in tool design is the case against investing in prompt tuning as the first lever. The table names the trade.

Axis | Prompt tuning | Tool design
Scope of effect | One agent's behavior | Every agent using the tool
Compounding | Low; prompts drift across tasks | High; better tools help every later agent
Cost of iteration | High; each test requires running the agent | Lower; tool specs are static
Feedback loop | Usually manual | Can be automated, as Anthropic's tool-testing agent did
Visibility of failure | Traces with awkward outputs | Model ignores the tool or uses the wrong one

The takeaway is not that prompt tuning is wasted effort; it is that tool design is often underinvested relative to its impact. When an agent underperforms, the first question to ask is what the tool descriptions look like.

Neighbors in the series

Structured output, earlier in the Foundations stage, is the syntactic cousin of tool design: one fixes the shape of the model's response, the other fixes the shape of the model's actions. ReAct and the tool-calling agent loop, the previous two articles, depend on the quality of this interface more than on any other single factor. Guardrails, covered later in the Safety stage, inspect tool inputs and outputs as part of a broader defensive posture. Protocol standards (MCP), in the Production stage, formalize tool discovery across agents and frameworks.

References

Anthropic. Building effective agents. December 2024.

Anthropic. Raising the bar on SWE-bench Verified with Claude. 2024.

Anthropic. Advanced tool use: programmatic tool calling and tool search. November 2025.

OpenAI. Function calling and tool design. 2024.

LangChain. Defining tools with @tool. 2024.