Agent programs range from simple lookup rules to systems that plan, weigh trade-offs and improve themselves. Each type adds one capability to the previous one.
| Agent type | Decides using | Strength | Limitation | Example |
|---|---|---|---|---|
| Simple reflex | Condition–action rules on the current percept | Fast, simple | Fails when the world is partially observable; can loop forever | Thermostat, the vacuum agent above |
| Model-based reflex | Rules + an internal state updated by a model of how the world evolves | Handles partial observability | Still has no explicit goals | Car tracking vehicles it can't currently see |
| Goal-based | A model + goals; searches/plans for action sequences that reach them | Flexible — change the goal, not the rules | Goals are binary: all paths to the goal look equally good | Route planner, puzzle solver |
| Utility-based | A utility function scoring how desirable each state is; maximises expected utility | Trades off speed, safety, cost; handles uncertainty | Utility is hard to specify; heavy computation | Self-driving car choosing a route |
| Learning agent | Any of the above + components that improve it from experience | Works in unknown environments; gets better | Needs data/experience; can learn wrong things | Spam filter, game-playing RL agent |
Why internal state matters
Add a cost of 1 point per move to the vacuum world. The simple reflex agent can't remember that B is already clean, so it shuttles back and forth forever. A model-based agent remembers both squares and stops (NoOp):
def reflex_agent(percept):
location, status = percept
if status == "Dirty":
return "Suck"
return "Right" if location == "A" else "Left"
def make_model_based_agent():
model = {"A": None, "B": None} # internal state: what we believe about each square
def agent(percept):
location, status = percept
model[location] = status # update the model from the percept
if status == "Dirty":
model[location] = "Clean" # predict the effect of our own action
return "Suck"
if model["A"] == model["B"] == "Clean":
return "NoOp"
return "Right" if location == "A" else "Left"
return agent
def run(agent, steps=10):
world, location, score = {"A": "Dirty", "B": "Dirty"}, "A", 0
for _ in range(steps):
action = agent((location, world[location]))
if action == "Suck":
world[location] = "Clean"
elif action in ("Left", "Right"):
location = "B" if action == "Right" else "A"
score -= 1 # moving costs energy
score += sum(s == "Clean" for s in world.values())
return score
print(run(reflex_agent)) # 10 ← keeps paying for pointless moves
print(run(make_model_based_agent())) # 17 ← stops once it knows both squares are cleanGoals vs utilities
A goal-based agent asks “does this reach the goal?”; a utility-based agent asks “how good is this outcome?”. Utility is needed whenever goals conflict (speed vs safety) or success is uncertain — the agent then maximises expected utility (see Utility & Markov Decision Processes).
The learning agent
When is a simple reflex agent enough?
Why would you prefer a utility-based agent over a goal-based one?