20 Core Agentic Engineering Concepts Every Developer Should Understand

By Oleksandr Andrushchenko — Published on
0 Likes
0 Dislikes
20 Core Agentic Engineering Concepts Every Developer Should Understand
20 Core Agentic Engineering Concepts Every Developer Should Understand

Agentic engineering is the discipline of building AI systems that can reason about goals, choose actions, use tools, observe results, maintain state, and continue working until a task reaches a useful outcome. The difficult part is not making a model generate text; it is designing the control system around the model so that autonomous behavior remains reliable, observable, secure, and cost-effective.

This article explains 20 core concepts behind production agentic systems, from agents, tools, planning, and memory to orchestration, guardrails, evaluation, observability, and human approval. The focus is the engineering behavior behind each concept and the trade-offs that appear when agents interact with real systems.

Table of Contents

Agentic Systems Foundations

A traditional LLM application often follows a simple request-response pattern: input enters the model and generated text comes back. An agentic system adds a control loop around that model, allowing the application to decide what should happen next based on intermediate results.

The first four concepts describe the mechanics that turn a language model into a system capable of pursuing goals rather than merely answering prompts.

1. AI Agents

An AI agent is a software system in which a model participates in deciding what actions should be taken to accomplish a goal. Actions might include searching documents, querying databases, calling APIs, executing code, creating tickets, or delegating work to another component.

The important distinction is control. In a deterministic application, application code normally decides every transition. In an agent, some transitions are selected dynamically by the model.

For example, a logistics support agent receiving "Why has shipment 83921 not arrived?" might decide to retrieve the shipment, inspect carrier events, check service alerts, calculate whether the delivery SLA has been violated, and only then produce an answer.

Agency should be introduced only where dynamic decision-making creates value. Deterministic validation, authorization, accounting, and other strict business rules usually belong in ordinary application code.

2. Agent Loop

The agent loop is the execution cycle that allows an agent to perform multiple actions instead of producing a single response. A typical iteration consists of observing the current state, deciding what to do, executing an action, recording the result, and deciding whether another iteration is necessary.

Goal → Model → Action → Observation → Model → Action → Result

The loop is usually implemented by application code rather than left entirely to the model. The application controls iteration limits, tool permissions, timeouts, state persistence, and termination.

from dataclasses import dataclass
from typing import Any


@dataclass
class AgentState:
    goal: str
    observations: list[dict[str, Any]]
    steps: int = 0


MAX_STEPS = 12


def run_agent(goal: str) -> str:
    state = AgentState(goal=goal, observations=[])

    while state.steps < MAX_STEPS:
        decision = model_decide(state)

        if decision.type == "finish":
            return decision.answer

        result = execute_tool(decision.tool, decision.arguments)

        state.observations.append({
            "tool": decision.tool,
            "result": result,
        })
        state.steps += 1

    raise RuntimeError("Agent exceeded maximum execution steps")

Without explicit limits, a failing tool or poor reasoning path can create repeated calls, growing token consumption, and unpredictable latency.

3. Goals and Task Decomposition

Agents frequently receive goals that cannot be completed with one operation. Task decomposition converts a broad objective into smaller pieces that can be executed and verified independently.

Consider an engineering agent asked to investigate elevated API latency. The task might require retrieving recent deployments, examining p99 latency, checking database saturation, comparing traces before and after a deployment, and producing a likely root cause.

Decomposition improves reliability because intermediate tasks can have explicit inputs and measurable outputs. It also makes retries cheaper: failure while retrieving traces should not require repeating every successful operation.

The danger is excessive decomposition. Turning a straightforward three-step task into dozens of model decisions increases latency and creates additional opportunities for incorrect branching.

4. Planning

Planning determines the sequence or dependency graph of actions required to reach a goal. Some agents create an explicit plan before execution; others decide one step at a time.

Upfront planning works well when dependencies are predictable. Dynamic planning works better when each action reveals information that changes the next decision.

Strategy Strength Weakness
Fixed workflow Predictable and inexpensive Cannot adapt easily
Plan first Good visibility into complex tasks Initial plan can become obsolete
Plan incrementally Adapts to observations More model calls and less predictable execution

Production systems commonly combine these approaches: deterministic workflow boundaries contain smaller regions where the model is allowed to plan dynamically.

Actions and Environment Interaction

An agent becomes operationally useful when it can interact with systems outside the model. That ability also introduces the largest difference between a chatbot failure and an agent failure: incorrect generated text is inconvenient, while an incorrect external action can modify production data.

5. Tool Calling

Tool calling exposes controlled application capabilities to the model. Instead of asking the model to invent a shipment status, the application can provide a function such as get_shipment_status.

from typing import Literal
from pydantic import BaseModel, Field


class ShipmentLookup(BaseModel):
    shipment_id: str = Field(min_length=1, max_length=50)


class ShipmentStatus(BaseModel):
    status: Literal["created", "in_transit", "delivered", "exception"]
    carrier: str
    last_event_at: str


def get_shipment_status(request: ShipmentLookup) -> ShipmentStatus:
    shipment = shipment_repository.get(request.shipment_id)

    if shipment is None:
        raise LookupError("Shipment not found")

    return ShipmentStatus(
        status=shipment.status,
        carrier=shipment.carrier,
        last_event_at=shipment.last_event_at.isoformat(),
    )

A tool should have a narrow responsibility, validated arguments, predictable output, explicit authorization, and well-defined failure behavior. Giving a model generic database or shell access when several constrained operations would suffice dramatically increases the blast radius of an incorrect decision.

Tool design is therefore an API-design problem as much as an AI problem.

6. Structured Outputs

Agents need machine-readable decisions. Structured outputs constrain model responses to schemas that application code can validate before execution.

Instead of parsing text such as "I think the refund tool should be called for order 42," the runtime can require a typed decision.

from typing import Literal
from pydantic import BaseModel, Field


class RefundDecision(BaseModel):
    action: Literal["refund", "request_approval", "reject"]
    order_id: str
    amount_cents: int = Field(ge=0)
    reason: str = Field(min_length=1, max_length=500)

Schema validation prevents malformed arguments from reaching downstream services, but it does not prove that a decision is semantically correct. A perfectly valid JSON object can still request a refund for the wrong customer.

Structural correctness and business correctness are separate validation layers.

7. Environment Feedback

Every action produces an observation: an API response, database result, command output, validation error, or external state change. The agent uses these observations to decide what happens next.

Tool responses should therefore be designed for machine reasoning. Returning thousands of lines of raw logs or an entire database record wastes context and can obscure the information required for the next decision.

A better tool might return a bounded result containing status, relevant values, error category, retryability, and a continuation token when more data exists.

Errors are observations too. A rate-limit response should tell the runtime whether retrying is appropriate; an authorization error should generally stop that branch rather than trigger repeated attempts.

8. Reflection and Self-Correction

Reflection introduces a deliberate verification step in which the model or another evaluator examines an intermediate result before it is accepted.

For example, a coding agent can generate a patch, run tests, inspect failures, revise the patch, and run the tests again. The test suite provides objective feedback rather than asking the same model whether its own answer looks correct.

Reflection is most useful when verification has an external signal: tests, schemas, policy checks, compiler output, database constraints, or another measurable criterion.

Repeatedly asking a model to reconsider an answer without new evidence can increase cost without reliably increasing correctness. Self-correction becomes substantially stronger when grounded in deterministic feedback.

Context, State, and Knowledge

Agent quality depends heavily on what information reaches the model at each decision point. Sending everything available is rarely the best strategy: context windows are finite, irrelevant information consumes tokens, and old observations can distract the model from current state.

9. Context Engineering

Context engineering is the deliberate construction of the information presented to a model for a particular decision. It includes system instructions, task state, tool definitions, retrieved knowledge, recent observations, user constraints, and summaries of previous work.

The goal is not maximum context. The goal is minimum sufficient context with high signal density.

For example, an incident-response agent diagnosing database latency may need recent query metrics, deployment changes, connection-pool saturation, and relevant runbook sections. Supplying months of unrelated infrastructure documentation makes reasoning slower and potentially less reliable.

Context engineering becomes increasingly important as agent execution grows longer because blindly appending every observation eventually creates both token pressure and attention noise.

10. Memory

Memory allows information to survive beyond the current model call. Different memory scopes solve different problems and should usually be implemented separately.

Memory Type Purpose Example
Working memory Current execution Results collected during an incident investigation
Session memory Current interaction Previously selected project or environment
Long-term memory Information across sessions Stable application preferences
Episodic memory Previous executions How a similar operational problem was resolved

Memory creates difficult lifecycle questions: what deserves persistence, when does it expire, who can modify it, and how can incorrect information be corrected?

Persisting every conversation indefinitely is not a memory strategy. It is unbounded storage with retrieval problems.

11. Retrieval

Retrieval selects relevant information from external knowledge sources when the agent needs it. Sources might include vector indexes, relational databases, search engines, documentation systems, previous executions, or application APIs.

Retrieval quality often matters more than raw model capability. If the correct runbook never reaches the model, stronger reasoning cannot recover information that was never supplied.

Production retrieval pipelines need to consider relevance, freshness, authorization, source trust, result count, and context size. Metadata filters are particularly important in multi-tenant systems because semantic similarity must never bypass access boundaries.

Retrieval-Augmented Generation is covered separately in RAG (Retrieval-Augmented Generation).

12. Agent State

Agent state is the durable representation of execution progress. It is different from conversational history: state should describe what the system currently knows and what has already happened in a form application code can inspect.

A long-running task might persist the current plan, completed steps, tool results, retry counts, approvals, generated artifacts, and termination status.

from dataclasses import dataclass, field
from typing import Any


@dataclass
class ExecutionState:
    execution_id: str
    status: str = "running"
    completed_steps: set[str] = field(default_factory=set)
    results: dict[str, Any] = field(default_factory=dict)
    retry_counts: dict[str, int] = field(default_factory=dict)
    approved_actions: set[str] = field(default_factory=set)

Durable state makes agent executions resumable. If a worker crashes after seven completed operations, another worker can continue from a checkpoint rather than reconstructing the task from an enormous transcript.

Agent Orchestration

Real applications rarely consist of one unconstrained model loop. Orchestration defines how deterministic application logic, model decisions, tools, specialized agents, queues, and human approvals cooperate to complete larger tasks.

13. Workflows

An agentic workflow combines predefined execution structure with model-driven decisions. This is often safer than giving one agent complete freedom over the entire task.

Consider processing a customer refund. Identity verification, order lookup, refund limits, transaction creation, and audit logging can remain deterministic. The model might classify the customer's request, extract evidence, or decide which policy branch requires investigation.

This produces an important production principle: use models for ambiguity and software for invariants.

Workflow engines also provide useful infrastructure around retries, persistence, deadlines, idempotency, and recovery that would otherwise need to be recreated inside the agent runtime.

14. Multi-Agent Systems

A multi-agent system divides work among multiple specialized agents. One might research information, another analyze code, and another review the resulting changes.

Specialization can improve context isolation and permissions. A database-analysis agent can receive database tools without exposing those capabilities to an unrelated documentation agent.

However, additional agents create communication overhead, duplicated context, more model calls, harder debugging, and new failure boundaries. Multi-agent architectures should therefore solve a concrete isolation, specialization, or parallelization problem.

One capable agent with well-designed tools is often simpler than several agents communicating through natural language.

15. Delegation and Routing

Routing selects the appropriate model, tool, workflow, or specialized agent for a task. Delegation passes a bounded subtask to that component.

Routing can improve both quality and economics. A small model may classify incoming support requests while a stronger model handles complex investigations. Deterministic requests might bypass an LLM entirely.

A delegated task should have a clear contract: objective, allowed resources, required output schema, deadline, and failure behavior. Vague delegation such as "investigate this" makes completion difficult to evaluate.

Routing itself should be monitored. Misrouting rates, escalation frequency, cost by route, latency, and task success rate reveal whether specialization actually improves the system.

Production Control and Reliability

Autonomy introduces operational risk because the number and order of actions are not always known in advance. Production agent engineering therefore requires explicit mechanisms that bound what the system can do, verify outcomes, and expose execution behavior.

16. Guardrails

Guardrails constrain agent behavior before and after model decisions. They can enforce permissions, validate arguments, filter unsafe input, limit accessible resources, or reject actions that violate business policy.

Guardrails should exist outside the model whenever possible. Telling a model "never refund more than $500" is weaker than enforcing that limit in application code.

MAX_AUTONOMOUS_REFUND_CENTS = 50_000


def authorize_refund(amount_cents: int) -> bool:
    if amount_cents < 0:
        return False

    return amount_cents <= MAX_AUTONOMOUS_REFUND_CENTS

Defense in depth can combine prompt-level instructions, schema constraints, application authorization, tool-specific permissions, downstream business rules, and audit logs.

17. Human-in-the-Loop

Human-in-the-loop systems require approval or review at selected execution boundaries. Human involvement is especially valuable for high-impact actions that are difficult to reverse.

Approval should normally be risk-based rather than required for every operation. Reading documentation may proceed automatically, while sending payments, deleting production resources, or communicating externally may require confirmation.

An approval request should contain enough structured information for a reviewer to make a decision: proposed action, affected resource, expected impact, evidence, and relevant execution history.

Human approval is not merely a user-interface feature. It becomes part of the workflow state and must handle expiration, rejection, duplicate approvals, resumed execution, and changes in underlying data while approval is pending.

18. Agent Evaluation

Agent evaluation measures whether the entire system accomplishes tasks correctly, not merely whether individual model responses sound reasonable.

Useful evaluation dimensions include task success, tool selection accuracy, argument correctness, unnecessary actions, policy violations, recovery from tool failures, latency, token consumption, and monetary cost.

Agent evaluations should include failure scenarios. A system that works only when every tool succeeds has not been evaluated against realistic production behavior.

For deterministic tasks, exact assertions are preferable. For open-ended tasks, evaluation can combine programmatic checks, reference outcomes, model-based graders, and human review.

Evaluate trajectories, not only final answers. Two executions can produce the same final response while one performs three appropriate read operations and another makes twenty unnecessary calls with risky side effects.

19. Observability

Traditional application metrics are necessary but insufficient for agents. Agent observability must expose both infrastructure behavior and the logical execution trajectory.

A trace should make it possible to reconstruct which model was called, what context was supplied, which tools were selected, how long each operation took, which retries occurred, and why execution stopped.

Useful production metrics include:

  • Task success rate. Measures whether executions actually accomplish their objectives.
  • Steps per task. Detects inefficient or looping behavior.
  • Tool error rate. Reveals unreliable integrations and invalid arguments.
  • p95 and p99 task latency. Captures long-tail execution caused by multi-step reasoning.
  • Tokens per successful task. Connects context growth to useful outcomes.
  • Cost per successful task. Prevents cheap individual calls from hiding expensive workflows.
  • Human escalation rate. Shows how often autonomy reaches its configured limits.

Logs containing prompts, retrieved documents, and tool results can contain sensitive data. Observability pipelines therefore need redaction, retention policies, access control, and tenant isolation just like other production data systems.

20. Budgets and Termination

Every autonomous loop needs a definition of when execution must stop. Otherwise a confused agent can repeatedly search, retry, reflect, or delegate while accumulating latency and cost.

Useful budgets include maximum model calls, tool calls, execution time, tokens, retries, delegated tasks, and monetary cost.

from dataclasses import dataclass


@dataclass
class ExecutionBudget:
    max_steps: int = 15
    max_tool_calls: int = 25
    max_tokens: int = 80_000
    max_duration_seconds: int = 120


def budget_exceeded(
    budget: ExecutionBudget,
    *,
    steps: int,
    tool_calls: int,
    tokens: int,
    elapsed_seconds: float,
) -> bool:
    return (
        steps >= budget.max_steps
        or tool_calls >= budget.max_tool_calls
        or tokens >= budget.max_tokens
        or elapsed_seconds >= budget.max_duration_seconds
    )

Termination also needs semantic conditions. Execution should stop when the goal is satisfied, required information is unavailable, permission is denied, a human decision is required, or further attempts are unlikely to improve the outcome.

Bounded autonomy is easier to operate than unlimited autonomy.

Putting the Concepts Together

The 20 concepts are most useful when treated as parts of one execution architecture rather than independent AI features.

Consider an agent responsible for investigating a failed payment. The initial goal is decomposed into payment lookup, event inspection, and policy evaluation. Context engineering supplies only the relevant transaction and policy information. Retrieval loads documentation when necessary.

The model selects constrained tools using validated structured outputs. Tool results become environment feedback and are stored in durable agent state. If the evidence contradicts an earlier hypothesis, the agent can perform bounded self-correction.

A surrounding workflow keeps deterministic payment rules outside the model. Guardrails prevent unauthorized actions, while a refund above an autonomous threshold enters a human approval state.

Throughout execution, observability records the trajectory and budgets limit cost and looping. Offline evaluation later measures whether similar executions selected the right tools, reached correct conclusions, and avoided unnecessary operations.

This separation is what turns an LLM experiment into an engineering system.

Production Design Principles

Agent architectures vary significantly, but several design principles consistently reduce operational risk.

  • Keep deterministic rules deterministic. Authorization, monetary limits, schema validation, and other invariants should not depend solely on model reasoning.
  • Prefer narrow tools. Small capabilities with explicit schemas reduce ambiguity and limit the impact of incorrect actions.
  • Persist execution state. Long-running work should survive process crashes, worker replacement, and approval delays.
  • Make side effects idempotent. Retries must not accidentally duplicate payments, messages, tickets, or infrastructure changes.
  • Bound every loop. Configure limits for steps, retries, tokens, duration, and cost.
  • Design errors as data. Tool failures should communicate whether an operation is retryable, terminal, or requires escalation.
  • Minimize context deliberately. Supply information relevant to the current decision rather than accumulating the complete execution transcript forever.
  • Require approval according to impact. Irreversible or expensive operations deserve stronger controls than read-only actions.
  • Trace the complete trajectory. Production debugging requires visibility into decisions and actions, not only the final response.
  • Measure outcomes. Optimize task success, reliability, latency, and cost per successful task rather than isolated model-call metrics.

The central architectural trade-off is autonomy versus control. More autonomy can handle unpredictable tasks but increases the execution space that must be secured, evaluated, observed, and paid for. More deterministic orchestration reduces flexibility but improves predictability and debuggability.

Strong production designs rarely maximize either extreme. They create controlled regions of autonomy inside deterministic system boundaries.

Conclusion

Agentic engineering extends ordinary LLM applications with goals, planning, tools, feedback, state, memory, retrieval, orchestration, and controlled autonomy. The model is an important component, but production quality depends just as heavily on the runtime surrounding it.

The most reliable systems give models freedom where reasoning is valuable while keeping permissions, invariants, persistence, retries, budgets, and high-impact decisions under explicit application control. Agent quality should ultimately be judged by whether complete tasks are performed correctly, safely, observably, and at an acceptable cost.

Author

Enjoyed this article?

Support Oleksandr Andrushchenko

Buy me a coffee

This helps Oleksandr Andrushchenko continue creating useful content

Related articles

Comments (0)