Chapter 2

AI Agent Tools: How to Design Reliable Functions

Tools are the bridge between the model and the external world. The model chooses which tool to call but does not execute it. Execution is the job of trusted code. How you describe and implement tools determines whether the agent will be reliable or dangerous.

From task to working system
  1. AI Agent Architecture: Graphs, ReAct, and HITL
  2. AI Agent Tools: Contracts and Safety
  3. AI Agent Memory: State, Checkpointer, and RAG
  4. AI Agent Production: Reliability and Observability
On this pageFunction Schemas and Structured GenerationValidation Before ExecutionTrusted Executor: Code, Not the ModelRead vs Write: Separating ToolsIdempotency, Timeouts, and RetriesData and Instruction BoundaryMCP, Skills, and Plugins: Protocol Does Not Grant PermissionsExample of a Tool Contract

Function Schemas and Structured Generation

The model cannot execute tool code. It returns a structured description of the call: the function name and parameters. To make this description correct, you must provide the model with a function schema: name, description, parameters, and their types.

Pydantic allows you to describe the schema as a Python class and automatically generate a JSON schema. This is convenient for integration with LLM APIs. However, it is important to remember: structured generation does not guarantee truth. The model can return valid JSON with factually incorrect data.

A schema is a contract at the format level. It guarantees that the call will be passed in the correct structure but does not guarantee that the parameters make sense. Checking meaning is the job of business logic.

  • The model returns the function name and parameters but does not execute it.
  • Function schema: name, description, parameters, types.
  • Pydantic: schema description and JSON schema generation.
  • Structured generation does not guarantee data truth.
  • A schema is a format contract, not a meaning contract.

Validation Before Execution

Before executing a tool, you must validate the parameters. First, formal validation against the schema: types, required fields, formats. Then, business checks: for example, whether the user has the right to perform the operation, whether the amount exceeds the limit.

Pydantic performs formal validation when creating the object. Business checks must be performed in the tool code or in a separate layer. Do not rely on the model: it may choose a tool that is not suitable for the given context.

A validation error should be informative. Return a clear error message to the model so it can correct the parameters or choose another tool.

  • Formal validation: types, required fields, formats.
  • Business checks: permissions, limits, allowed values.
  • Do not rely on the model for security matters.
  • A validation error should be understandable to the model.
  • Define required and optional parameters.
  • Add type and format checks.
  • Implement business checks in the tool code.
  • Formulate clear error messages.

Trusted Executor: Code, Not the Model

The key principle: the model chooses which tool to call but does not execute it. Execution is trusted code that you wrote and control. This creates a place to validate a call before execution; it does not itself eliminate incorrect tool selection or unsafe arguments.

For example, if the model decides to call get_order_status, your code executes the function get_order_status(**arguments). The model does not have direct access to the database or file system. It can only propose a call, and you decide whether to execute it or not.

This also means you can add additional checks before execution: logging, authentication, rate limiting.

  • The model proposes a call, the code executes.
  • Trusted code controls access to resources.
  • Additional checks: logging, authentication, limits.
  • The model does not have direct access to the database or files.
  1. Model: choose tool get_order_status
  2. Code: validate parameters
  3. Code: execute get_order_status('12345')
  4. Code: return result to the model
  5. Model: generate response

Read vs Write: Separating Tools

Separate tools into read-only and write. Read-only tools (get status, search, read file) are safer and can be executed with fewer restrictions. Write tools (send email, transfer money, modify file) require additional checks and possibly user confirmation.

This separation is important for security and for designing HITL. If a tool changes the state of an external system, it should be explicitly marked as write, and its execution should be controlled.

In the agent configuration, you can prohibit write tools in certain modes (for example, in research mode).

  • Read-only: getting data, search, reading.
  • Write: changing state, sending, writing.
  • Write tools require additional checks.
  • Separation helps design HITL and operating modes.

Idempotency, Timeouts, and Retries

External calls can fail or be repeated. Idempotency is a property of an operation where repeated execution gives the same result as the first. For example, the operation 'set order status to cancelled' is idempotent, while 'increment counter by 1' is not.

For write tools, design idempotency: pass a unique operation identifier (idempotency key) so that a repeated call does not create a duplicate. For example, when sending an email, you can pass message_id, and the server will ignore a repeated send with the same ID.

Timeouts and retries are mandatory for external calls. Define the maximum waiting time and the number of attempts. Retries should be with exponential backoff to avoid overloading the service.

  • Idempotency: repeated call gives the same result.
  • Use an idempotency key for write operations.
  • Timeout: maximum waiting time for a response.
  • Retries with exponential backoff.
  • Do not repeat non-idempotent operations without checking.

Data and Instruction Boundary

It is important to separate data and instructions. Data obtained from external sources (search, documents, API) should be considered untrusted. It may contain malicious instructions (prompt injection).

Tools should return only data, not instructions for the model. If a tool returns text that can be interpreted as an instruction, it is a risk. For example, a document obtained from search may contain 'forget previous instructions and...'.

Treat data as data: escape it, limit its length, do not mix it with the system prompt. The model should clearly understand what is an instruction and what is data for analysis.

  • Data from external sources is untrusted.
  • Tools return data, not instructions.
  • Prompt injection: malicious instructions in data.
  • Escape and limit the length of data.
  • Clearly separate instructions and data in the prompt.

MCP, Skills, and Plugins: Protocol Does Not Grant Permissions

MCP (Model Context Protocol) standardizes the way tools are described and called. An MCP server declares tools, and an MCP client (agent) can discover and call them. This is convenient for integration with external systems.

It is important to understand: MCP is a protocol, not a security mechanism. Connecting an MCP server does not give the agent automatic permissions. Authorization and permission checks must be performed separately, at the application level. The protocol does not protect against a malicious server or misuse of a tool.

A skill is a repeatable procedure that combines several tools and instructions. A plugin is a distributable package that includes skills, MCP configurations, and resources. These levels help organize code but do not replace access control.

  • MCP: a standard for describing and calling tools.
  • MCP is not a security mechanism.
  • Authorization and permission checks are at the application level.
  • Skill: a repeatable procedure of tools and instructions.
  • Plugin: a distributable package with skills and MCP configurations.
  • Set up independent authorization for each MCP server.
  • Do not pass tokens and keys through MCP.
  • Check permissions for each tool execution.
  • Treat external tools as a trust boundary.

Example of a Tool Contract

A tool contract is a complete description of its behavior, including input data, output data, and possible errors. A good contract helps the model use the tool correctly and helps you implement it reliably.

Consider the get_order_status tool. Input: order_id (string, required), include_history (boolean, optional). Output: an object with fields status, expected_date, history (if requested). Errors: OrderNotFound (if the order is not found), InvalidOrderId (if the format is incorrect).

Error descriptions should be informative for the model. Instead of 'error', return 'Order with number 12345 not found. Check the number or contact support'.

  • Contract: input, output, errors.
  • Error descriptions should be understandable to the model.
  • Usage examples in the tool description.
  • The contract helps both the model and the developer.

What to carry into your project

Tools are trusted code that performs actions on behalf of the model. Design clear contracts, validate parameters, separate read and write, ensure idempotency, and remember that MCP is a protocol, not security.

Sources and further reading

  • Tools and Structured Generation in LLMs (Sber educational materials)
  • Architecture of Modern Agentic Harnesses (Sber educational materials)
  • Development and Application of Multi-Agent Systems in a Corporate Environment (Sber)