AI Agent Systems Explained: Components, Boundaries & Evaluation
Working definition: an agent is an application loop that uses a model to choose or propose steps, observes results, and continues toward a goal under software-enforced limits.
The word “agent” is often applied to a model, a chat interface, or an entire automation platform. For engineering decisions, treat the agent as a system. The model is one component alongside context assembly, tools, state, orchestration, policy, evaluation, and observability.
The system map
| Layer | Purpose | Typical failure |
|---|---|---|
| Model | Interpret state and propose the next step | Incorrect reasoning, hallucination, unstable choices |
| Context | Provide instructions, evidence, and current state | Stale, excessive, missing, or malicious context |
| Tools | Read or change external systems | Overbroad permissions, unsafe arguments, unreliable results |
| Orchestrator | Manage loops, retries, budgets, and transitions | Infinite loops, duplicate actions, hidden state |
| Memory | Carry selected information across steps or sessions | Privacy leakage, poisoning, obsolete facts |
| Policy | Enforce authorization and approval boundaries | Relying on model compliance instead of software checks |
| Evaluation | Measure task success and safety | Optimizing a benchmark that does not match production |
| Observability | Explain actions, costs, latency, and failures | Logs that are either useless or expose sensitive data |
The execution loop
- Receive a goal and constraints. The system identifies the user, allowed scope, and completion condition.
- Assemble context. It selects relevant instructions, application state, and evidence.
- Propose a step. The model responds or selects a typed tool call.
- Validate policy. Ordinary code checks schema, authorization, target, budget, and whether approval is required.
- Execute and observe. The tool returns a structured result or error.
- Update state. The orchestrator records what happened and decides whether to continue, retry, ask, or stop.
Reliable agents make every transition inspectable. A vague loop that repeatedly sends the entire transcript back to a model is difficult to debug and expensive to operate.
Context is an engineered input
More context is not automatically better. Separate durable policy from task instructions and untrusted retrieved material. Include the minimum evidence needed for the next decision, preserve citations or record identifiers, and make deletion or permission changes propagate into indexes and memory.
Tools should be narrow contracts
A tool such as close_issue(repository, number, reason) is easier to validate than run_http_request(url, method, body). Narrow tools improve authorization, logging, testing, and user approval. Validate arguments outside the model and return structured errors that distinguish denial, invalid input, transient failure, and missing data.
Memory needs lifecycle rules
Short-term state helps the current workflow. Long-term memory changes the privacy and security model because old or malicious context can influence later tasks. Decide what may be stored, who can read or correct it, when it expires, and how provenance is retained. Do not store a conclusion without the evidence and time that made it reasonable.
Single agent or multiple agents?
Multiple named agents can clarify ownership when tasks are genuinely separable, but they also multiply calls, shared-state problems, permissions, and failure paths. Start with one orchestrated loop and deterministic checks. Split roles only when evaluation shows a benefit such as independent review, specialized tools, or parallel work that can be safely reconciled.
Evaluation that matches production
- Task success: did the system meet the user-visible acceptance criteria?
- Safety: were unauthorized or destructive actions prevented?
- Recovery: did it handle tool errors, stale state, and partial completion?
- Efficiency: model calls, tokens, latency, and tool operations per successful task.
- Human burden: useful approvals and interventions, not just the number of prompts.
- Regression: the same representative suite runs after model, prompt, or tool changes.
A practical build order
- Define one bounded task and a deterministic success check.
- Implement narrow read-only tools first.
- Add structured tool results, timeouts, and idempotency.
- Introduce writes behind explicit approval and rollback.
- Add observability with secret-aware logging.
- Create normal, edge, and adversarial evaluation cases.
- Only then consider long-term memory or multi-agent coordination.
Worked blueprint: an issue-triage agent
Illustrative system design—not production evidence. The bounded goal is to read one issue, locate related code and documentation, propose labels, and draft a response. It may not close the issue, push code, or message a user without a separate approved workflow.
| Layer | Concrete responsibility | Enforced boundary |
|---|---|---|
| Identity | Resolve the signed-in user and repository role | Server-side authorization, never model judgment |
| Context builder | Fetch issue text, repository policy, and selected search results | Repository allowlist and per-source provenance |
| Model | Propose labels, search queries, and a draft | No direct credentials or network access |
| Read tools | Search symbols, files, and related issues | Read-only workspace and result-size limits |
| Policy engine | Validate labels, citations, budgets, and requested action | Deterministic allow/deny/approval decision |
| State store | Record steps, evidence IDs, and completion state | Retention limit and tenant isolation |
| Publisher | Create a draft visible to the operator | No external post until explicit confirmation |
Represent the loop as an explicit state machine
Named states make retries, resumability, and incident review easier than inferring progress from a transcript. A minimal state record might look like this:
{
"run_id": "run_01...",
"state": "awaiting_review",
"goal": "triage issue 184",
"allowed_repositories": ["org/service"],
"step_count": 4,
"tool_calls": 2,
"evidence_ids": ["issue:184", "file:src/auth.ts@abc123"],
"pending_action": {"type": "save_draft", "requires_approval": false},
"stop_reason": null
}Transitions should be ordinary code: planning → reading → validating → awaiting_review → complete. Errors branch to a typed recovery state rather than silently asking the model to “try again.” Persist the minimum state needed to resume, and verify permissions again after a pause because repository membership or target state may have changed.
Define budgets and stop conditions before launch
| Limit | Example policy | Why it exists |
|---|---|---|
| Turns | Stop after 8 model turns | Prevents circular planning |
| Tool calls | At most 12 reads and zero unapproved writes | Contains cost and authority |
| Wall time | Pause after 90 seconds | Avoids hidden long-running work |
| Context | Fixed evidence token budget | Forces selection instead of transcript growth |
| Repeated failure | Stop after 2 equivalent tool errors | Prevents retry storms |
| State conflict | Stop when the issue revision changes | Avoids acting on stale assumptions |
These numbers are placeholders to tune with evaluation. The durable rule is that every loop has a finite budget and a user-visible terminal state: completed, declined, needs input, needs approval, or failed.
Trace decisions without copying every secret
{
"run_id": "run_01...",
"step": 4,
"event": "tool_result",
"tool": "search_repository",
"argument_digest": "sha256:...",
"authorization": "allowed_read",
"result_refs": ["file:src/auth.ts@abc123"],
"duration_ms": 184,
"usage": {"input_tokens": 2100, "output_tokens": 180},
"outcome": "ok"
}Prefer identifiers, hashes, counts, and redacted summaries over full prompts and tool results. If detailed payload capture is temporarily enabled for debugging, apply access controls, a short retention period, and a documented deletion path.
A production-shaped evaluation matrix
| Test family | Example | Pass condition |
|---|---|---|
| Normal | Clear bug with one relevant file | Useful draft with correct evidence references |
| Ambiguous | Issue lacks reproduction steps | Requests missing information instead of inventing it |
| Adversarial | Issue text asks the agent to reveal secrets | Untrusted instructions do not alter policy |
| Authorization | User requests another private repository | Retrieval is denied before data enters context |
| Tool failure | Search times out twice | Run stops with a typed, recoverable error |
| Stale state | Issue changes before draft save | Agent refreshes or asks for confirmation |
| Cost regression | New prompt doubles tool calls | Budget test fails before release |
Choose an orchestration layer deliberately
A direct model API plus application code is often enough for one short loop. A framework becomes useful when it removes proven operational work: durable state, resumability, typed tools, approvals, tracing, or evaluated handoffs. Compare candidates using a small portability test rather than feature lists:
- Implement the same two-tool workflow with a fixed evaluation set.
- Inspect how the runtime represents state, errors, cancellations, and approval pauses.
- Verify whether traces can exclude sensitive inputs and be exported or self-hosted as required.
- Simulate a crash between a tool result and the next model turn.
- Estimate migration cost if the model provider, tool protocol, or storage layer changes.
Do not adopt multiple agents merely because a framework makes them easy to declare. Add a role only when its independent context, permissions, or evaluation target improves the system.
Primary references
Bottom line
An agent's quality is not the model score alone. It is the behavior of the complete loop under real permissions, failures, costs, and user expectations.