Agentic AI Fundamentals: Planning, Tools, Memory, and Control Loops
Agentic AI systems do more than generate one response. They decompose goals, choose actions, call tools, inspect outcomes, and iterate until completion or stop condition.
This article explains the architecture patterns that make agents useful and safe.
What Makes a System “Agentic”
An agentic system usually has:
- a goal
- an action loop
- tool access
- state/memory
- a stopping policy
Without these, most systems are still prompt-response assistants.
Core Control Loop
A practical loop:
- interpret user goal
- plan next step
- select tool or reasoning action
- execute
- observe result
- update state
- repeat until done/failed/timeout
This is often called a perceive-plan-act loop.
Planning Strategies
Common options:
- reactive planning (decide step-by-step)
- upfront plan then execute
- hybrid (high-level upfront, dynamic re-plan)
Reactive is flexible but can drift. Upfront plans are traceable but brittle under unexpected tool outputs. Hybrid is usually best in production.
Tool Use Patterns
Agents gain capability through tools:
- search/retrieval
- calculators/code execution
- APIs (CRM, billing, ticketing)
- workflow actions (create ticket, send email)
Tool interfaces should be schema-constrained. Free-form tool arguments create reliability and security issues.
Memory Design
Agent memory types:
- short-term: session context and recent tool outputs
- long-term: user preferences, historical outcomes
- external memory: vector retrieval / knowledge store
Memory policies need TTL and access controls. Unbounded memory can cause prompt bloat and privacy risk.
Termination and Guardrails
Agents need explicit stop conditions:
- goal completed
- confidence below threshold
- max steps reached
- repeated tool failure
- policy violation detected
Without stop conditions, agents can loop, hallucinate actions, or create costly tool churn.
Failure Modes
Common failures:
- plan drift (agent chases irrelevant subgoals)
- tool misuse (wrong API, bad params)
- stale memory causing wrong decisions
- infinite loops
- unsafe action execution
Strong observability is required: step logs, tool traces, and decision audit trail.
Architecture Blueprint
A production agent stack usually includes:
- orchestrator/runtime
- planner policy
- tool registry and permission layer
- memory manager
- policy and safety filters
- evaluator/monitoring
Treat each layer as explicit component with ownership.
End-to-End Code Example (Minimal Agent Loop)
from dataclasses import dataclass, field
from typing import Dict, Any, List
MAX_STEPS = 6
@dataclass
class AgentState:
goal: str
steps: List[str] = field(default_factory=list)
context: Dict[str, Any] = field(default_factory=dict)
done: bool = False
# Tool registry
def tool_search_docs(query: str) -> Dict[str, Any]:
# Replace with real retrieval
return {"docs": [f"Result for: {query}"]}
def tool_calculator(expr: str) -> Dict[str, Any]:
return {"value": eval(expr)}
TOOLS = {
"search_docs": tool_search_docs,
"calculator": tool_calculator,
}
def planner(state: AgentState) -> Dict[str, Any]:
# Replace this with LLM planner
if "calculate" in state.goal.lower() and "calc_done" not in state.context:
return {"action": "calculator", "args": {"expr": "(1200*1.18)-200"}}
if "docs_done" not in state.context:
return {"action": "search_docs", "args": {"query": state.goal}}
return {"action": "finish", "args": {"answer": "Task completed with available tools."}}
def run_agent(goal: str) -> AgentState:
state = AgentState(goal=goal)
for step_id in range(1, MAX_STEPS + 1):
decision = planner(state)
action = decision["action"]
args = decision.get("args", {})
state.steps.append(f"step={step_id} action={action} args={args}")
if action == "finish":
state.context["final_answer"] = args.get("answer", "Done")
state.done = True
break
if action not in TOOLS:
state.context["error"] = f"Unknown tool: {action}"
break
try:
result = TOOLS[action](**args)
state.context[f"tool_result_{step_id}"] = result
if action == "search_docs":
state.context["docs_done"] = True
if action == "calculator":
state.context["calc_done"] = True
except Exception as e:
state.context["error"] = str(e)
break
if not state.done and "error" not in state.context:
state.context["error"] = "Stopped: max steps reached"
return state
if __name__ == "__main__":
s = run_agent("Calculate adjusted invoice and find policy docs")
print("DONE:", s.done)
print("STEPS:")
for x in s.steps:
print(" -", x)
print("CONTEXT:", s.context)
This skeleton is intentionally simple; production agents need policy checks and robust tool contracts.
Key Takeaways
- Agentic AI requires looped planning, action, and state updates.
- Tools and memory increase capability but also operational risk.
- Termination conditions and guardrails are mandatory.
- Observability and traceability are essential for debugging and trust.