Reinforcement Learning Q-learning and SARSA
In the field of artificial intelligence, reinforcement learning is a method that allows an agent to learn how to achieve goals by interacting with the environment.
Imagine teaching a puppy a new command: when it performs an action (such as sitting), you give it a reward (a treat), and it gradually learns to respond correctly when it hears the command. Q-learning and SARSA are two classic and crucial algorithms in reinforcement learning; they are the core tools for the agent to learnwhat action is best in what statecore tools.
Reinforcement Learning and Markov Decision Process Basics
Before diving into Q-learning and SARSA, we need to understand the common theoretical framework they share.
Core Concepts
Reinforcement learning problems are usually modeled asa Markov decision process. It contains the following key elements:
- Agent: The entity that makes decisions and learns.
- Environment: The external world with which the agent interacts.
- State: A description of the environment at a particular moment.
- Action: An operation the agent can perform in a given state.
- Reward: The immediate payoff signal fed back by the environment after the agent performs an action.
- Policy: The rule by which the agent selects actions in a given state; it is the learning target.
Goals and Value Functions
The agent's ultimate goal is to maximize long-term cumulative reward, not just immediate reward. To this end, we introducevalue functions.。
- State-value function V(s): Represents, starting from state
s, the expected cumulative reward obtainable by following a specific policy. - Action-value function Q(s, a): Represents, in state
staking actiona, and then following a specific policy, the expected cumulative reward that can be obtained.The core of Q-learning and SARSA is to learn this Q function.
To balance immediate and future rewards, we usediscount factor γ(usually in the range [0, 1]). The reward at future step k is multiplied by γ^k, which means the agent places more importance on near-term rewards.
Q-learning: Off-Policy Temporal Difference Learning
Q-learning is anoff-policyalgorithm, proposed by Watkins in 1989. Its core idea is that the agent indirectly finds the optimal policy by learning an optimal Q-value table.
Algorithm Core: Q-Value Update Formula
The learning process of Q-learning is driven by the following formula:Q(s_t, a_t) ← Q(s_t, a_t) + α * [ r_{t+1} + γ * max_{a} Q(s_{t+1}, a) - Q(s_t, a_t) ]
Let's break down this formula:
Q(s_t, a_t)Q(s, a): at time tt, in state ss_ttaking action aa_t, the current estimate.α: Learning rate α, controls the degree to which new information overrides old information (0 < α ≤ 1).r_{t+1}r: after executing an actiona_t, the immediate reward obtained.γ: Discount factor γ, measures the importance of future rewards.max_{a} Q(s_{t+1}, a)max Q(s', a'): in thenext states_{t+1}, the largest Q value among all possible actions. This represents the best possible future return estimated based on the current Q table.[ r_{t+1} + γ * max_{a} Q(s_{t+1}, a) - Q(s_t, a_t) ]TD error: calledtemporal difference error. It is the difference between the "target value" (immediate reward plus the best future estimate) and the "current estimate". The algorithm updates Q by reducing this error.
The Meaning of Off-Policy
Q-learning is calledoff-policy, because when it updates Q values, the action used to evaluate future value (max_{a} Q(s_{t+1}, a)) and the action the agent actually performs for explorationare separate.。
- Behavior policy: The policy used to select actions actually performed (e.g., ε-greedy, which explores randomly with a certain probability).
- Target policy: The policy used to update Q-values; it is a fully greedy policy (always selecting the action with the largest current Q-value).
This separation allows Q-learning to boldly learn using its estimate of the optimal path, even while it is currently performing random exploration.

Algorithm Procedure

SARSA: On-Policy Temporal Difference Learning
The name SARSA comes from the state-action sequence involved in its update process:(S_t, A_t, R_{t+1}, S_{t+1}, A_{t+1}). It is anon-policyalgorithm.
Algorithm Core: Q-Value Update Formula
SARSA's update formula is very similar to Q-learning's, but there is one key difference:Q(s_t, a_t) ← Q(s_t, a_t) + α * [ r_{t+1} + γ * Q(s_{t+1}, a_{t+1}) - Q(s_t, a_t) ]
Notice the second part:
- Q-learning uses max_{a'} Q(s', a'):
γ * max_{a} Q(s_{t+1}, a) - SARSA uses Q(s', a'):
γ * Q(s_{t+1}, a_{t+1})
In SARSA, the agent inthe next states_{t+1}will actually take an actiona_{t+1}whose Q-value is used to estimate future value.
The Meaning of On-Policy
SARSA is calledon-policy, because the policy it uses to update Q-values (target policy) and the policy it uses to select actions (behavior policy)are the same, both usually being the ε-greedy policy.
- It evaluates and optimizes the policy itis currently executing.
- What it learns is a policy that accounts for the risk of future exploration, so it is usually more "conservative".
Comparison of Q-learning and SARSA
Understanding the difference between the two is key to mastering them. The table below clearly summarizes the core differences:
| Feature | Q-learning | SARSA |
|---|---|---|
| Policy type | Off-policy | On-policy |
| Update target | Based on the optimal action:r + γ * max Q(s', a') |
Based on the actual action:r + γ * Q(s', a_{t+1}) |
| Learning objective | Learnthe optimal policy'sQ-function. | Learnthe behavior policy (e.g., ε-greedy)'s Q-function. |
| Risk tendency | More "bold", assumes optimal actions will be taken in the future | More "conservative", considers the risk that future exploration may bring |
| Update timing | In(s, a, r, s')can be updated immediately after (S, A, R, S') |
requires(s, a, r, s', a')the five-tuple (S, A, R, S', A') to update. |
| Typical applications | Discrete environments, seeking the global optimal solution | Environments with high safety requirements, where dangerous states need to be avoided |
Classic Cliff Walking Example
This example vividly illustrates the difference between the two. Suppose a grid world where the agent walks from start S to goal G; below is a cliff. Falling off gives a large negative reward and returns to the start.

- Q-learningQ-learning: Since it assumes the future will always take the optimal (safest) path, it quickly learns the shortest path along the cliff edge (Path 1), because it "believes" it will not fall off.
- SARSASARSA: Since it considers that there is still a probability ε of random exploration in the future, it may fall off the cliff. Therefore, it learns a safer path further up (Path 2). Although longer, its long-term expected return is higher.
Conclusion: In environments where exploration and exploitation need to be balanced and mistakes are costly, SARSA usually learns a safer and more robust policy.
Code Practice: Implementing Q-learning and SARSA in Python
We will use a simple4x4grid world to demonstrate both algorithms. The goal is for the agent to move from the top-left corner(0,0)to the bottom-right corner(3,3)。
Environment Setup
Example
import random
class GridWorld:
def __init__(self, size=4):
self.size = size
self.state = (0, 0) # Starting point
self.goal = (size-1, size-1) # Ending point
self.actions = ['up', 'down', 'left', 'right']
self.action_map = {'up': (-1, 0), 'down': (1, 0), 'left': (0, -1), 'right': (0, 1)}
def reset(self):
"""Reset environment to starting point"""
self.state = (0, 0)
return self.state
def step(self, action):
"""Execute action, return (next state, reward, terminated)"""
move = self.action_map[action]
next_state = (self.state[0] + move[0], self.state[1] + move[1])
# Boundary check: if out of bounds, stay in place
if not (0 <= next_state[0] < self.size and 0 <= next_state[1] < self.size):
next_state = self.state
self.state = next_state
# Reward setup: reward 10 for reaching goal, -1 for other moves (encourage reaching quickly)
if next_state == self.goal:
reward = 10
done = True
else:
reward = -1
done = False
return next_state, reward, done
def get_actions(self):
return self.actions
Q-learning Algorithm Implementation
Example
"""
Implement Q-learning algorithm
env: environment object
episodes: number of training episodes
alpha: learning rate
gamma: discount factor
epsilon: exploration probability in ε-greedy policy
"""
# Initialize Q table with shape [grid rows, grid cols, number of actions]
q_table = np.zeros((env.size, env.size, len(env.actions)))
for episode in range(episodes):
state = env.reset()
done = False
while not done:
# 1. Choose action using ε-greedy policy
if random.uniform(0, 1) < epsilon:
action_idx = random.randint(0, len(env.actions)-1) # Exploration: randomly choose
else:
action_idx = np.argmax(q_table[state[0], state[1], :]) # Exploitation: choose the one with maximum Q value
action = env.actions[action_idx]
# 2. Take action, get feedback
next_state, reward, done = env.step(action)
# 3. Q-learning core update
# Q value of the current state-action pair
current_q = q_table[state[0], state[1], action_idx]
# Maximum Q value of the next state (key for off-policy)
next_max_q = np.max(q_table[next_state[0], next_state[1], :])
# Compute target Q value
target_q = reward + gamma * next_max_q
# Update Q table
q_table[state[0], state[1], action_idx] = current_q + alpha * (target_q - current_q)
# Transition to next state
state = next_state
return q_table
SARSA Algorithm Implementation
Example
"""
Implement SARSA algorithm
Parameter meanings same as Q-learning
"""
q_table = np.zeros((env.size, env.size, len(env.actions)))
for episode in range(episodes):
state = env.reset()
done = False
# SARSA needs to first choose an action for the initial state
if random.uniform(0, 1) < epsilon:
action_idx = random.randint(0, len(env.actions)-1)
else:
action_idx = np.argmax(q_table[state[0], state[1], :])
action = env.actions[action_idx]
while not done:
# 1. Execute the action chosen in the previous step
next_state, reward, done = env.step(action)
# 2. Choose an action for the next state (on-policy, still using ε-greedy)
if random.uniform(0, 1) < epsilon:
next_action_idx = random.randint(0, len(env.actions)-1)
else:
next_action_idx = np.argmax(q_table[next_state[0], next_state[1], :])
next_action = env.actions[next_action_idx]
# 3. SARSA core update
current_q = q_table[state[0], state[1], action_idx]
# Key difference: use the Q value of the **actual action to be executed** in the next state
next_q = q_table[next_state[0], next_state[1], next_action_idx]
target_q = reward + gamma * next_q
q_table[state[0], state[1], action_idx] = current_q + alpha * (target_q - current_q)
# 4. Update state and action for the next iteration
state = next_state
action_idx = next_action_idx
action = next_action
return q_table
Testing and Policy Visualization
Example
"""Test the learned policy"""
total_rewards = []
for _ in range(episodes):
state = env.reset()
done = False
total_reward = 0
steps = []
while not done:
# Use greedy policy during testing (no exploration)
action_idx = np.argmax(q_table[state[0], state[1], :])
action = env.actions[action_idx]
next_state, reward, done = env.step(action)
steps.append(action[0].upper()) # Record the first letter of each action
total_reward += reward
state = next_state
total_rewards.append(total_reward)
print(f"Episode steps: {steps}, Total reward: {total_reward}")
print(f"Average reward: {np.mean(total_rewards):.2f}")
# Create environment
env = GridWorld(size=4)
print("=== Training and testing Q-learning ===")
q_table_ql = q_learning(env, episodes=1000)
test_policy(env, q_table_ql)
print("\n"=== Training and testing SARSA ===")
env.reset() # Reset environment state
q_table_sarsa = sarsa(env, episodes=1000)
test_policy(env, q_table_sarsa)
# Simply compare the final policies
print("\n=== Policy comparison (actions from starting point (0,0)) ===)
start_q_values = q_table_ql[0, 0, :]
start_sarsa_values = q_table_sarsa[0, 0, :]
print(f"Q-learning Q-values: {dict(zip(env.actions, start_q_values))}")
print(f"Recommended action: {env.actions[np.argmax(start_q_values)]}")
print(f"SARSA Q-values: {dict(zip(env.actions, start_sarsa_values))}")
print(f"Recommended action: {env.actions[np.argmax(start_sarsa_values)]}")