Skip to content
← All guides

Building Agents

MDX

Build Your First Tool-Using Agent

A framework-neutral implementation path from one verifiable job to a controlled agent loop with a typed tool and trajectory tests.

14 min readAgentic Systems Editorial Team

Editorial review: clarity, operational relevance, safety boundaries, and source quality.

Choose one verifiable job

Do not begin with “build a support agent” or “automate research.” Those labels hide many users, policies, systems, and definitions of success. Pick one job that can be described and tested independently.

A strong first job has:

  • one authenticated user or actor;
  • one observable outcome;
  • one authoritative source of truth;
  • one or two read-only tools;
  • explicit unsupported cases;
  • an independent way to verify completion.

“Explain the current state of an order to the authenticated customer” is a reasonable pilot. “Handle customer service” is not. The narrow version can succeed by reading one current record and translating typed status into a supported explanation. It does not need refund authority, outbound messaging, memory, multi-agent coordination, or an open-ended plan.

Build fixture cases before the loop. Include normal records, missing identifiers, multiple matches, denied access, stale state, a tool timeout, misleading user claims, and requests for adjacent actions. A dozen representative cases are more useful than one polished demonstration.

Write the task contract

The task contract is the boundary between product intent and system behavior. It should be understandable by product, engineering, operations, and security—not only by the prompt author.

Specify:

  1. Supported users and inputs.
  2. The system that owns each required fact.
  3. Actions the model may propose.
  4. Actions the runtime may execute.
  5. Evidence required for completion.
  6. Valid terminal states and escalation routes.
  7. Step, time, token, and tool budgets.
  8. Explicit exclusions and prohibited effects.
  9. Owners for quality and incidents.

Keep the contract outside the prompt as a versioned product artifact. The prompt may explain the job, but the runtime must enforce its permissions and limits.

Design one narrow tool

The first tool should be boring. Give it one unmistakable purpose, typed inputs, representative fixture data, and explicit result states. Keep credentials and authorization in the host application.

For an order-status agent, prefer:

type FindOrderResult =
  | { status: "found"; order: OrderSummary; observedAt: string }
  | { status: "not_found" }
  | { status: "denied"; reason: "wrong_account" }
  | { status: "unavailable"; retryAfterMs?: number };

async function findCustomerOrder(
  actorId: string,
  orderId: string,
): Promise<FindOrderResult>;

Avoid returning arbitrary database rows, generic exceptions, or a large prose dump. The next model decision needs the outcome, relevant fields, source time, and safe recovery options.

Schema validation is only the first boundary. After parsing, confirm that the order exists, belongs to the authenticated actor, and is current enough for the claim being made. Treat model-generated arguments as untrusted input even when they satisfy the type.

Implement the control loop

Persist a run record containing the goal, confirmed facts, open questions, tool events, step budget, and terminal state. Each model call receives only the state required for the next decision.

The model may return either a proposed tool action or a candidate final answer. The host then:

  • checks the proposal against the allowlist;
  • validates arguments and cross-field rules;
  • authorizes the actor, task, resource, and action;
  • executes with a timeout;
  • records a structured observation;
  • verifies any completion claim;
  • stops at the configured budget.

Separate model failure from tool failure. A not_found result can be a healthy observation. A timeout may permit a bounded retry. A permission denial should terminate or escalate rather than encourage the model to search for another route. An indeterminate write must be reconciled before retrying—but the first pilot should avoid writes entirely.

Evaluate complete trajectories

Final-answer grading cannot tell you whether the system used the wrong account, attempted a prohibited action, repeated a tool unnecessarily, or invented success after a timeout. Record and grade the trajectory.

For each case, assert:

  • the terminal state is valid;
  • required evidence is present;
  • only allowed tools were requested;
  • tool arguments are semantically correct;
  • denied and unavailable results produce the right recovery;
  • step and retry budgets are respected;
  • unsupported requests are refused or handed off cleanly;
  • the final explanation is faithful to tool evidence.

Run the same set after changing the model, prompt, tool schema, policy, or retrieval source. Add generalized cases from incidents and reviewer corrections. Keep a small hidden holdout so repeated prompt tuning does not overfit the visible examples.

Optional course companion

Complete Agentic AI Course

Use this long-form walkthrough after completing the framework-neutral loop above. It extends the implementation path into LangChain, LangGraph, retrieval, guardrails, and evaluation while the article remains your compact control-system reference.

External video by Krish Naik · approximately 10 hoursWatch on YouTube

Field checklist

Apply it in practice

  • Write the task contract before implementing the loop.
  • Start with one read-only tool and one source of truth.
  • Represent tool outcomes with typed, recoverable states.
  • Validate and authorize every proposed action outside the model.
  • Require external evidence before returning completed.
  • Test actions, observations, budgets, and stop reasons—not only wording.

Field manual

Implementation blueprint

  1. 01

    Freeze the first scope

    Choose one job with one source of truth and no write access. Write normal, ambiguous, unavailable, and prohibited cases first.

    Deliverable: A task contract plus 12–20 representative test cases.

  2. 02

    Design the tool result

    Return a discriminated result such as found, not_found, denied, or unavailable instead of throwing undifferentiated prose.

    Deliverable: A typed tool boundary with fixture data and recovery semantics.

  3. 03

    Implement the run state

    Persist goal, confirmed facts, open questions, step budget, tool events, and stop reason for each run.

    Deliverable: A traceable run record that can be replayed during evaluation.

  4. 04

    Test the trajectory

    Assert permitted tools, argument validity, retry count, evidence use, and terminal state—not only final wording.

    Deliverable: A regression suite that identifies whether failure occurred in reasoning, tooling, or control.

Reusable working artifact

Framework-neutral control loop

The model proposes actions; the host application authorizes, executes, records, and verifies them.

type Stop = "completed" | "needs_input" | "denied" | "exhausted" | "failed";

for (let step = 0; step < MAX_STEPS; step++) {
const proposal = await decide({ goal, state, allowedTools });

if (proposal.kind === "answer") {
  const verification = verifyCompletion(proposal, state);
  if (verification.ok) return finish("completed", verification.evidence);

  state.events.push({
    type: "verification_failed",
    reason: verification.reason,
  });
  continue;
}

const authorization = authorize(
  user,
  task,
  proposal.tool,
  proposal.arguments,
);
if (!authorization.ok) return finish("denied", authorization.reason);

const result = await executeValidated(proposal, { timeoutMs: 5_000 });
state.events.push({ type: "tool_result", proposal, result });
}

return finish("exhausted", "step_budget_reached");

Measurement

Operational scorecard

Task completionCorrect terminal state plus every required evidence referenceScore completed, safe escalation, denial, and failure separately.
Tool precisionValid and necessary tool calls divided by all requested callsSplit wrong-tool, wrong-argument, and unnecessary-call errors.
Recovery qualityCorrect behavior after not-found, timeout, and denial resultsRepeated identical calls indicate weak result semantics or missing loop control.
EfficiencySteps, latency, and cost per verified completionInclude retries and failed runs; do not report only per-call cost.

Failure drills

Rehearse before the system has real authority

  • Return a timeout after an indeterminate tool call and confirm the agent does not assume success.
  • Give two records with similar names and require a stable identifier before continuing.
  • Insert instructions into tool data and verify they are treated as untrusted content, not authority.
  • Remove access to the only allowed tool and confirm the run terminates cleanly instead of searching for an unapproved path.

Selected primary references

Continue with the source material

These sources inform the wider editorial perspective for this topic. They are not presented as line-by-line citations for every statement.

↑ Back to top