
Most enterprise AI agent failures do not start with the model choosing a tool.
They start with a weak contract around what that tool means. A function schema says send_email(to, subject, body). It does not say who is allowed to send, whether the recipient is external, what approval state is required, whether the operation is idempotent, how retries behave, what evidence must be logged, what happens on partial failure, or how the action is reversed.
That missing contract is where a helpful assistant becomes an uncontrolled production actor.
The practical question for CIOs, CISOs, enterprise architects, AI platform engineers, and product teams is:
What must a tool contract define before an enterprise AI agent is allowed to call business systems, write records, send messages, trigger workflows, or touch privileged APIs?
The answer is not “better prompting.” Treat every agent tool as a governed interface with five parts: a typed schema, an authority model, execution semantics, evidence requirements, and failure behavior. The model may propose a call. The tool contract tells the runtime what must be validated, authorized, approved, executed, logged, retried, compensated, or denied.
This article complements the broader safe tool registry, policy-as-code, Zero Trust delegation, agent audit logs, human approval patterns, and access reviews. The registry says which tools exist. Policy says whether an action is allowed. The contract defines exactly what a valid action is.
The Contract In One Paragraph
An enterprise AI tool contract is a versioned runtime specification for a tool an agent may request. It defines the input and output schema, allowed operations, actor and resource attributes, data classes, side-effect level, approval requirements, idempotency behavior, retry rules, timeout budget, rate limits, compensation path, audit fields, and contract tests. A tool contract should be enforced by the orchestration or broker layer before execution. It should never rely on the model to interpret a natural-language tool description correctly.
Function Schemas Are Not Enough
A narrow function schema is useful. It gives the model and runtime a structured shape:
1 | { |
That shape is not a production contract.
It leaves out the questions that matter when the call changes enterprise state:
| Missing question | Why it matters |
|---|---|
| Who is acting? | The same tool is different when called by an HR assistant, support agent, or security copilot. |
| What authority is delegated? | A human may have broader rights than the agent should inherit. |
| What resource is touched? | Updating one case is not the same as bulk-updating a customer segment. |
| Is the operation reversible? | Reversible notes and irreversible external sends need different controls. |
| Can it be retried? | Retrying a read is harmless; retrying a payment or email may duplicate impact. |
| What evidence is required? | Security and process owners need reconstructable facts, not a chat transcript. |
| What does failure mean? | Timeout, policy denial, partial write, and downstream conflict are different states. |
The OpenAPI Specification is a useful reference because API descriptions let humans and machines understand service capabilities without reading implementation code. JSON Schema is useful because validation should be explicit, machine-checkable, and versioned. But enterprise AI agents need additional control semantics around authority and side effects. A JSON object can be valid and still unsafe.
A Useful Contract Has Five Layers
Think of the tool contract as five layers around the downstream API.
1 | agent proposal |
| Layer | What it defines | Example |
|---|---|---|
| Interface | Inputs, outputs, enums, required fields, formats, version | case_id, new_status, reason_code, customer_visible |
| Authority | Who may propose, approve, execute, and review | support agent may propose; manager approves customer-visible close |
| Execution | Side effects, idempotency, retries, timeout, rate limit | one execution per approval ID; no automatic retry for external email |
| Evidence | What must be logged before and after execution | policy decision, approval ID, before/after state, result class |
| Failure | Denial, validation error, conflict, timeout, partial success, compensation | hold pending action; restore previous status if downstream write fails |
This split prevents teams from burying production controls in tool descriptions. The model receives enough description to propose valid arguments. The runtime receives enough contract metadata to enforce the boundary.
The Minimum Tool Contract
A practical contract can start with this shape:
1 | { |
This is intentionally more than a model-facing tool schema. Some fields guide the model. Most fields guide the runtime, policy engine, approval service, audit pipeline, and reviewer.
Separate Proposal From Execution
The safest enterprise pattern is to treat model output as a proposal:
1 | model proposes: |
That distinction matters because the model should not decide whether its own call is allowed. OWASP’s AI Agent Security Cheat Sheet calls out least privilege, tool authorization, high-impact action controls, monitoring, and adversarial validation for agents. My engineering interpretation is direct: a model-facing schema is the request surface, not the authority surface.
For Tier 0 and Tier 1 tools, proposal and execution may happen in one brokered step. For Tier 3 and Tier 4 tools, the proposal should become a pending action with a narrow approval scope.
| Tool class | Agent may propose | Agent may execute | Required contract behavior |
|---|---|---|---|
| Read public status | yes | yes | schema validation, standard audit |
| Read internal record | yes | yes, scoped | user-context access, data-class filtering |
| Write internal note | yes | conditional | field allowlist, idempotency key, after-state log |
| Send external message | yes | rarely direct | preview, approval, recipient policy, no automatic duplicate send |
| Update customer-visible state | yes | conditional | workflow state, approval, before/after state |
| Modify IAM or production config | yes | no by default | privileged workflow handoff, separation of duties |
| Delete, refund, commit, deploy | yes | exceptional | dual control, compensation path, incident-grade evidence |
The contract lets useful AI work continue while keeping the final authority in deterministic systems.
Idempotency Is A Safety Control
Retries are one of the places where agent systems become quietly dangerous.
An agent runtime may retry because the model asked again, the network timed out, a queue redelivered a message, the user clicked twice, or the orchestrator recovered after a crash. If the tool contract does not define idempotency, the same apparent request can create duplicate tickets, send duplicate emails, issue duplicate refunds, or apply a state transition twice.
RFC 9110 on HTTP Semantics is a useful baseline because it distinguishes safe and idempotent method semantics. Do not assume those semantics survive once an AI tool wraps a business workflow. A POST /send-email tool is not safe because the agent call is JSON-shaped. A crm.update_case_status tool may be idempotent only if the contract binds the call to a stable action hash and downstream state.
Use explicit retry classes:
| Operation pattern | Automatic retry? | Contract rule |
|---|---|---|
| Pure read | usually yes | retry with trace correlation and timeout budget |
| Deterministic lookup | yes | no side effect, cache-aware |
| Draft generation | yes | store as draft version, not final output |
| Internal reversible write | only with idempotency key | one effect per action hash |
| External send | no by default | manual review after uncertain timeout |
| Payment, refund, deletion, IAM change | no by default | use privileged workflow with explicit state reconciliation |
For any side-effectful tool, the contract should define:
- required idempotency key;
- idempotency scope;
- duplicate-call behavior;
- timeout reconciliation path;
- downstream correlation ID;
- whether a retry is allowed after unknown execution status.
If the runtime cannot tell whether an action happened, do not let the model “try again.” Move the action into reconciliation or human review.
Validate Inputs, Then Normalize Outputs
Input validation gets most of the attention. Output contracts matter just as much.
An AI agent often feeds one tool result into the next step. If the first tool returns an ambiguous object, raw HTML, untrusted instructions, excessive data, or a downstream error disguised as success, the next model call may treat it as trusted context.
Use a normalized output envelope:
1 | { |
The output contract should decide what the model may see. Raw downstream responses may contain sensitive data, system prompts, support notes, legal content, customer identifiers, or HTML/script fragments. Treat tool output as untrusted input unless the contract normalizes it.
The NCSC secure AI system development guidance is useful because it frames secure design, development, deployment, and operation as a lifecycle concern. Tool contracts are one place where that lifecycle becomes executable: validation, secure defaults, logging, update management, and operations are not separate afterthoughts.
Evidence Belongs In The Contract
If a tool can change business state, its contract should define the evidence emitted before and after execution. Do not leave audit fields to each product team.
At minimum, log these fields for side-effectful tools:
| Evidence field | Why it exists |
|---|---|
trace_id and parent_event_id | reconstructs the full workflow |
human_user_id and agent_id | separates requester, delegate, and runtime actor |
tool_id and contract_version | proves which contract governed execution |
arguments_hash and redaction profile | supports review without over-storing sensitive payloads |
policy_decision_id | proves authorization occurred outside the model |
approval_id and scope | proves the action stayed inside approved bounds |
idempotency_key | distinguishes retry from duplicate action |
before_state_hash and after_state_hash | supports replay and reconciliation |
downstream_request_id | joins the agent trace to the source system |
result_class | separates success, denial, conflict, timeout, partial success |
OpenTelemetry’s logs data model is a useful reference for trace IDs, timestamps, severity, resources, instrumentation scope, attributes, and event names. You do not need every AI event to look like every infrastructure log, but you do need correlation. Agent tool execution should be visible in the same operational universe as application traces, policy decisions, incidents, and downstream API calls.
The NIST Generative AI Profile reinforces the broader point: generative AI risk management has to account for lifecycle, actors, measurement, and controls. A contract that cannot produce evidence cannot support governance, incident response, or access review.
Failure Modes To Design For
A serious tool contract names failure modes instead of collapsing everything into error.
| Failure mode | Runtime response | Why a generic error is dangerous |
|---|---|---|
| Schema validation failure | return correctable error, no side effect | model can repair arguments safely |
| Policy denial | return denial reason code, no side effect | model should not bypass with another tool |
| Missing approval | create pending action | preserves useful work without executing |
| Approval scope mismatch | deny and require fresh approval | prevents approval reuse |
| Downstream conflict | hold for reconciliation | state may have changed since proposal |
| Timeout before execution | safe retry if contract allows | no side effect occurred |
| Timeout after uncertain execution | reconcile before retry | duplicate side effect risk |
| Partial success | emit incident-grade event | business state may be inconsistent |
| Output normalization failure | quarantine raw result | prevents polluted context |
| Compensation failure | escalate to owner | rollback assumptions are invalid |
This table is often where teams discover that a “simple tool” is actually a workflow boundary. Good. That discovery should happen before production, not during an incident.
Contract Tests Before Production
Every high-risk tool contract should have automated tests that exercise the controls, not only the happy path.
Useful test cases include:
- unknown enum value is denied before execution;
- additional JSON property is rejected;
- user from wrong region cannot delegate the tool;
- agent can propose but not execute a privileged operation;
- customer-visible action creates pending approval;
- approval expires and cannot be reused;
- idempotency key prevents duplicate side effects;
- automatic retry is disabled after uncertain timeout;
- before/after state evidence is emitted;
- raw downstream response is not passed back into model context;
- contract version change triggers review;
- policy denial cannot be bypassed by choosing an adjacent tool.
These are not model evals in the narrow sense. They are contract tests for the execution boundary. They should run when the tool schema changes, when policy changes, when the downstream API changes, when the agent version changes, and after incidents.
How To Roll This Out
Do not start by writing a universal contract specification for every possible tool. Start with the tools that can cause the most damage.
- Inventory side-effectful tools: external messages, writes to customer records, financial actions, IAM changes, production changes, deletes, and bulk exports.
- Add contract metadata to the existing tool registry: risk tier, side effect, reversibility, idempotency, approval, evidence, and owner.
- Put a broker in front of execution if agents currently call APIs directly.
- Convert the top five high-risk tools to proposal-first execution.
- Add idempotency keys and uncertain-timeout reconciliation.
- Normalize tool outputs before they re-enter model context.
- Write contract tests for denial, approval, retry, logging, and partial failure.
- Feed contract fields into policy-as-code and audit logs.
- Review contract drift during AI access reviews.
The first milestone is not elegance. It is removing ambiguous authority from the highest-risk tool calls.
The Line I Would Draw
If an AI agent can call a tool that reads restricted data, writes enterprise records, sends external messages, triggers money movement, changes permissions, modifies production systems, or affects a customer-visible workflow, that tool needs a contract stronger than a function schema.
The model should understand the interface. The runtime should enforce the contract. Security should review the authority. Operations should see the evidence. Business owners should own the risk. And retries should never be allowed to invent a second side effect because the first one was poorly specified.
That is the practical boundary: AI agents can be useful production actors only when their tools are designed like production interfaces.