5G Network Anomaly Detection Agent

Build a Python agent that detects 5G network anomalies and generates AI diagnostic reports.

Introduction

30 Second Summary

5G networks generate thousands of performance measurements every minute. When signal strength drops or latency spikes, network operations teams need to catch it fast. Today, engineers still scan dashboards of raw numbers looking for problems buried in the noise.

In this project, you will build a Python agent that automatically detects anomalies in 5G network data and uses Claude to generate structured diagnostic reports that a network engineer could act on.

What You'll Build

You can run a single command and watch your agent ingest simulated 5G cell site data, flag the measurements that deviate from healthy baselines, and print a full AI-powered diagnostic report with severity classifications and recommended actions.

By the end of this project, you'll have:

  • A working anomaly detection pipeline that flags measurements deviating from normal across five simulated 5G cell sites.
  • Hands-on experience calling Claude's API from Python, including authentication, message handling, and reading structured responses.
  • A prompt engineering transformation you can see side-by-side: a vague prompt that produces generic output versus a telecom-specific prompt that produces actionable diagnostics.
  • Secret Mission: Add a per-cell health scorecard that ranks cell sites and identifies which needs immediate attention.

Are there any prerequisites?

You need basic comfort with a terminal (running commands, navigating folders). No prior experience with AI APIs or telecom concepts is required. You will also need a free Anthropic Console account, which you will create in Step 1.

Before We Start

Before We Start...

Before we dive in, let's lock in what you're about to build and why it matters. This is the moment you commit to the goal before any code hits the screen.

Set Up Your Environment

Your anomaly detection agent needs two core capabilities: calling Claude's API for AI-powered diagnosis, and crunching network data with statistical methods.

In this step, you'll create an isolated project environment, install the required packages, and configure your API key so the agent can talk to Claude.

In this step, get ready to:
  • Create a project folder with a Python virtual environment.
  • Install the Anthropic SDK and pandas.
  • Configure your Claude API key.
Create your project folder and virtual environment

A virtual environment gives your project its own isolated set of Python packages. This prevents conflicts with other projects on your machine.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • Open a terminal inside VS Code by pressing Ctrl+` (backtick key, top-left of your keyboard).
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir 5g-anomaly-agent
cd 5g-anomaly-agent
  • Confirm the folder exists by running:
ls

The folder will be empty for now. That is expected.

  • Create a Python virtual environment by running:
python -m venv .venv
  • Activate the virtual environment:

macOS

source .venv/bin/activate

Windows

.venv\Scripts\activate

You should see (.venv) appear at the start of your terminal prompt. This confirms you are inside the virtual environment.

Don't see (.venv) in your prompt?

On Windows, if you get a "running scripts is disabled" error in PowerShell, switch to Command Prompt by typing cmd and pressing Enter, then try the activation again.

Make sure you are inside the 5g-anomaly-agent folder. Run pwd (macOS) or cd (Windows) to check your current directory.

Help me activate my Python virtual environment

Install the required packages

Your agent needs two packages: the Anthropic SDK to communicate with Claude, and pandas to work with tabular network data.

  • Install both packages by running:
pip install anthropic pandas

You should see download progress bars and a "Successfully installed" message listing both packages and their dependencies.

Seeing a permissions error or packages installing globally?

Make sure your terminal prompt still shows (.venv) before running pip install. If it disappeared, re-run the activation command from the previous substep.

Help me fix my pip install

Set up your Anthropic API key

The Anthropic SDK needs an API key to authenticate your requests to Claude. You will store this key as an environment variable so the SDK picks it up automatically.

  • Open your browser and go to console.anthropic.com.
  • Create an account if you do not have one, or sign in.
  • Navigate to the API keys section and click Create Key.
  • Copy the key immediately. You will not be able to see it again after closing the dialog.

Why an environment variable?

The Anthropic SDK automatically reads the ANTHROPIC_API_KEY environment variable when you create a client. This keeps your secret out of your source code.

  • Back in your VS Code terminal, set the environment variable by running this command (paste your own key in place of the placeholder):

macOS

export ANTHROPIC_API_KEY=your-api-key-here

Windows

set ANTHROPIC_API_KEY=your-api-key-here

No spaces around the equals sign

Make sure there are no spaces before or after the = sign. The key must start immediately after the equals sign with no quotes around it.

Before you verify, what do you think will happen if you try to import both packages and print a message? Will it succeed, or will something fail?

  • Verify your entire setup by running:
python -c "import anthropic; import pandas; print('Ready!')"

You should see Ready! printed to the terminal. This confirms both packages installed correctly and your environment is working.

Seeing ModuleNotFoundError?

This means the packages did not install into your active environment. Check that (.venv) still shows in your prompt, then re-run pip install anthropic pandas.

If you see python: command not found, try python3 instead. Some systems use python3 as the command name.

Help me debug my Python environment setup

Your environment is locked and loaded. Next up, you will generate realistic 5G network data that your agent can analyze for anomalies.

Generate Synthetic 5G Network Data

Your environment is set up and ready to go. Now you need data to work with.

Real 5G networks produce KPI measurements every 15 minutes per cell. You need realistic data to detect anomalies in, but you do not have access to a live network. Generating synthetic data that follows real 5G parameter ranges lets you simulate what a Network Operations Center (NOC) monitoring system would see.

In this step, get ready to:
  • Create network_agent.py with a function that generates realistic 5G KPI measurements.
  • Inject hidden anomalies simulating coverage holes, interference, and congestion.
  • Run the script and observe the synthetic network data.
Create the data generation function

5G cell sites report key performance indicators (KPIs) like signal strength, signal quality, throughput, and latency. Your function will simulate these measurements across 5 cell sites using realistic value ranges drawn from 3GPP standards.

  • Create a new file called network_agent.py inside your 5g-anomaly-agent folder, and paste the following code:
import anthropic
import pandas as pd
from datetime import datetime, timedelta
import random

def generate_5g_data(num_records=100, num_anomalies=8):
    """Generate synthetic 5G network KPI data with injected anomalies."""
    base_time = datetime(2026, 7, 15, 8, 0, 0)
    cell_ids = ["gNB-001", "gNB-002", "gNB-003", "gNB-004", "gNB-005"]

    # Build a list of measurements with realistic 5G KPI ranges
    data = []
    for i in range(num_records):
        timestamp = base_time + timedelta(minutes=15 * i)
        cell_id = random.choice(cell_ids)
        rsrp = random.gauss(-85, 8)
        rsrq = random.gauss(-11, 3)
        sinr = random.gauss(15, 5)
        throughput_dl = random.gauss(150, 40)
        latency = random.gauss(8, 2)
        data.append({
            "timestamp": timestamp,
            "cell_id": cell_id,
            "rsrp_dbm": round(rsrp, 1),
            "rsrq_db": round(rsrq, 1),
            "sinr_db": round(sinr, 1),
            "throughput_dl_mbps": round(max(throughput_dl, 1), 1),
            "latency_ms": round(max(latency, 0.5), 1),
        })

    df = pd.DataFrame(data)

What does this code do?

  • generate_5g_data() creates 100 simulated measurements spread across 5 cell sites (gNB-001 through gNB-005), each 15 minutes apart.
  • Each measurement uses random.gauss() to generate values around realistic 5G baselines: RSRP around -85 dBm, RSRQ around -11 dB, SINR around 15 dB, DL throughput around 150 Mbps, and latency around 8 ms.
  • The results are packed into a pandas DataFrame for easy analysis later.

The function generates normal data so far, but anomalies are what makes the agent useful. Next, you will inject hidden anomalies that simulate real network failures.

  • Still in network_agent.py, add the following code directly below the df = pd.DataFrame(data) line, still inside the generate_5g_data function:
    # Inject anomalies: coverage holes, interference, congestion
    anomaly_indices = random.sample(range(num_records), num_anomalies)
    for idx in anomaly_indices:
        anomaly_type = random.choice(["coverage", "interference", "congestion"])
        if anomaly_type == "coverage":
            df.at[idx, "rsrp_dbm"] = round(random.uniform(-115, -105), 1)
            df.at[idx, "throughput_dl_mbps"] = round(random.uniform(5, 20), 1)
        elif anomaly_type == "interference":
            df.at[idx, "sinr_db"] = round(random.uniform(-5, 2), 1)
            df.at[idx, "rsrq_db"] = round(random.uniform(-22, -18), 1)
        elif anomaly_type == "congestion":
            df.at[idx, "latency_ms"] = round(random.uniform(25, 50), 1)
            df.at[idx, "throughput_dl_mbps"] = round(random.uniform(10, 30), 1)

    return df

What do these anomaly types simulate?

  • Coverage holes: RSRP drops to -115 to -105 dBm and throughput crashes. This simulates a user moving into a dead zone.
  • Interference: SINR drops below 0 dB and RSRQ degrades severely. This simulates pilot pollution from overlapping cells.
  • Congestion: Latency spikes to 25-50 ms and throughput drops. This simulates too many users on one cell.
  • Save network_agent.py.
  • Verify the function works by running this command:
python -c "from network_agent import generate_5g_data; print(generate_5g_data().head())"

You should see the first 5 rows of a table with columns for timestamp, cell_id, rsrp_dbm, rsrq_db, sinr_db, throughput_dl_mbps, and latency_ms.

Seeing an ImportError or ModuleNotFoundError?

  • Make sure you are running the command from inside the 5g-anomaly-agent folder where network_agent.py lives.
  • Check that your virtual environment is still activated. You should see (.venv) at the start of your terminal prompt.
  • Confirm the indentation of the anomaly injection code. Every line inside generate_5g_data must be indented with 4 spaces.

help me fix an import error in my network_agent.py file

Add the main function

Your data generation function works. Now you need a main() function that calls it and prints a human-readable summary of what was generated.

  • Add the following code at the bottom of network_agent.py, below the generate_5g_data function:
def main():
    print("=" * 60)
    print("  5G Network Anomaly Detection Agent")
    print("  Powered by Claude AI")
    print("=" * 60)
    print()

    # Generate synthetic 5G KPI data
    print("[1/3] Generating 5G network KPI data...")
    df = generate_5g_data(num_records=100, num_anomalies=8)
    print(f"  Generated {len(df)} measurements across {df['cell_id'].nunique()} cells")
    print(f"  Time range: {df['timestamp'].min()} to {df['timestamp'].max()}")
    print()


if __name__ == "__main__":
    main()

What does this code do?

  • main() prints a header banner, then calls generate_5g_data() to create 100 measurements with 8 hidden anomalies.
  • It prints a summary showing how many records were generated, how many cells are represented, and the time range.
  • The if __name__ == "__main__" block ensures main() only runs when you execute the file directly.
Run the script and observe the output

Before you run this, think about what you expect to see. You generated 100 measurements across 5 cells. What will the summary look like?

  • Save network_agent.py and run it:
python network_agent.py

You should see a banner, then a summary showing 100 measurements across 5 cells with a time range spanning about 25 hours.

Can you spot the anomalies?

Look at the numbers in your output. The 8 anomalies are hidden somewhere in those 100 rows. This is what NOC engineers do manually today: scan tables of numbers looking for values that seem off. It is slow, error-prone, and does not scale to thousands of cells.

In the next step, you will automate this detection with z-scores.

Seeing a SyntaxError or IndentationError?

  • Python is strict about indentation. Make sure every line inside a function uses exactly 4 spaces (not tabs).
  • Check that def main(): is at the far left of the file (no leading spaces) and that all lines inside it are indented by 4 spaces.
  • Verify that return df at the end of generate_5g_data is indented with 4 spaces (inside the function), not 8 (inside the for loop).

help me fix a syntax or indentation error in my network_agent.py

✔️ Awesome, I've got everything!

Great. Double check you have saved network_agent.py and the output shows 100 measurements across 5 cells.

ⓧ I'd like to double check the full code

Your network_agent.py should contain these sections in order. Scroll up and confirm each is present:

  • Imports (anthropic, pandas, datetime, timedelta, random).
  • generate_5g_data() function: builds a list of 100 measurements in a for loop, creates a DataFrame, injects 8 anomalies, returns df.
  • main() function: prints the banner, calls generate_5g_data(), prints the summary.
  • if __name__ == "__main__": block at the very bottom calling main().

Your agent can now produce realistic 5G network data on demand. Next up, you will build the anomaly detection engine that automatically flags which measurements are suspicious.

Detect Anomalies with Z-Scores

In the previous step, you generated 100 rows of 5G KPI data with hidden anomalies baked in. Try scanning that output by eye and spotting which rows are anomalous. It is surprisingly hard.

Real networks have thousands of cells each producing data every 15 minutes. You need an automated method to flag measurements that deviate significantly from normal. Z-scores are the standard first-pass technique used in telecom anomaly detection.

In this step, get ready to:
  • Build a z-score based anomaly detection function that flags outlier measurements.
  • Display a table of flagged anomalous records with details of which KPIs triggered the flag.
Add the anomaly detection function

A z-score measures how many standard deviations a value is from the mean. If a measurement's z-score is above 2.0 (meaning it is more than 2 standard deviations from what is normal), something unusual is happening at that cell site.

  • In network_agent.py, find the line that says def main():.
  • Add the following function directly above def main():, with a blank line separating it from the function above and below:
def detect_anomalies(df, threshold=2.0):
    """Detect anomalies using z-score method on numeric KPI columns."""
    kpi_columns = ["rsrp_dbm", "rsrq_db", "sinr_db", "throughput_dl_mbps", "latency_ms"]

    anomalies = pd.DataFrame(index=df.index)
    anomalies["is_anomaly"] = False
    anomalies["anomaly_details"] = ""

    for col in kpi_columns:
        mean = df[col].mean()
        std = df[col].std()
        z_scores = (df[col] - mean) / std

        flagged = z_scores.abs() > threshold

        for idx in df[flagged].index:
            anomalies.at[idx, "is_anomaly"] = True
            detail = f"{col}={df.at[idx, col]} (z={z_scores[idx]:.1f})"
            if anomalies.at[idx, "anomaly_details"]:
                anomalies.at[idx, "anomaly_details"] += "; " + detail
            else:
                anomalies.at[idx, "anomaly_details"] = detail

    return anomalies

What does this code do?

  • kpi_columns lists the five numeric columns to check: signal strength, signal quality, interference ratio, throughput, and latency.
  • For each column, the function calculates the mean and standard deviation, then computes how far each row deviates from normal (its z-score).
  • Any row with an absolute z-score above the threshold (2.0) gets flagged, and the specific KPI that triggered is recorded in anomaly_details.
  • A single row can be flagged by multiple KPIs (e.g., both low RSRP and low throughput), which helps identify the type of failure.
  • Save network_agent.py.
Update main to display flagged records

The detection function exists, but main() does not call it yet. You need to wire it up and print the results so you can see which measurements got flagged.

  • In network_agent.py, scroll down to your main() function and find this line:
    print(f"  Time range: {df['timestamp'].min()} to {df['timestamp'].max()}")
    print()
  • Add the following code directly below those lines, inside main():
    print("[2/3] Running anomaly detection (z-score threshold: 2.0)...")
    anomalies = detect_anomalies(df, threshold=2.0)
    num_anomalies_found = anomalies["is_anomaly"].sum()
    print(f"  Detected {num_anomalies_found} anomalous measurements")
    print()

    if num_anomalies_found > 0:
        anomaly_mask = anomalies["is_anomaly"]
        print("  Flagged records:")
        flagged_display = df[anomaly_mask][["timestamp", "cell_id", "rsrp_dbm", "sinr_db", "throughput_dl_mbps", "latency_ms"]].copy()
        print(flagged_display.to_string(index=False))
        print()

What does this code do?

  • It calls detect_anomalies() with the DataFrame from the previous step, using a threshold of 2.0 standard deviations.
  • It prints the total count of flagged measurements so you immediately know how many outliers exist.
  • It displays only the anomalous rows with the most relevant columns (timestamp, cell ID, and the KPIs most likely to show deviation).
Run the detector and observe the output

Before you run the script, think about what you expect to see. You injected 8 anomalies in the data generation step. Do you think all 8 will be caught, or might the z-score method miss some?

  • Save network_agent.py and run your script with this command:
python network_agent.py

You should see the data generation summary from before, followed by a new section showing how many anomalies were detected and a table of the flagged records with their cell IDs, timestamps, and KPI values.

Why might the count differ from 8?

You injected 8 anomalies, but the detector might find more or fewer. Some injected values may land close enough to normal that their z-score stays below 2.0. Other normal measurements generated by random.gauss() might randomly land far from the mean and get flagged too.

This is realistic. Real anomaly detectors have false positives and false negatives. The threshold value (2.0) controls the tradeoff between catching everything and over-alerting.

Seeing a NameError or empty output?

  • If you see NameError: name 'detect_anomalies' is not defined, make sure the detect_anomalies() function is placed above def main(): in the file.
  • If you see 0 anomalies detected, check that the indentation inside your for col in kpi_columns: loop uses 4 spaces consistently. Mixed tabs and spaces can cause silent logic errors.
  • If you see an IndentationError, confirm the new code inside main() is indented with 4 spaces (one level inside the function).

Why isn't my anomaly detection finding any results?

You can now see which records are anomalous and which KPIs are off. But the output is raw numbers and z-scores. A NOC engineer needs to know: is this a coverage hole? Is it interference? What should they do about it? That interpretation is what you will automate next with Claude.

✔️ Awesome, I've got everything!

Great. Double check you have saved network_agent.py and your terminal shows flagged records with their KPI values.

ⓧ I'd like to double check the full code

Your network_agent.py should now contain these sections in order. Scroll through your file and confirm each is present:

  • Imports at the top (anthropic, pandas, datetime, timedelta, random).
  • The generate_5g_data() function (from the previous step).
  • The new detect_anomalies() function with z-score logic.
  • The main() function, now calling detect_anomalies() and printing flagged records.
  • The if __name__ == "__main__": block at the bottom.

Your agent can now automatically flag which measurements are abnormal. Next up, you will connect Claude to interpret those raw flags and produce a diagnostic report that a NOC engineer could actually act on.

Connect Claude for AI Diagnosis

Your anomaly detector flags measurements that are statistically unusual. But raw z-scores and column names do not tell a NOC engineer what is wrong or what to do about it.

In this step, you will connect your agent to Claude so it can interpret the anomaly data and produce a human-readable diagnosis. You will start with a simple, generic prompt to see what happens.

In this step, get ready to:
  • Add a function that sends anomaly data to Claude's API.
  • Update your main function to call the analysis and print the result.
  • Run the agent and observe Claude's response quality.
Add the Claude analysis function

You need a function that takes the DataFrame and anomaly results, filters down to just the flagged records, and sends them to Claude for interpretation.

  • In network_agent.py, find the main() function at the bottom of the file.
  • Add the following function above main():
def analyze_with_claude(df, anomalies):
    """Send detected anomalies to Claude for telecom-specific diagnosis."""
    client = anthropic.Anthropic()

    # Filter the full DataFrame to only anomalous rows
    anomaly_mask = anomalies["is_anomaly"]
    anomaly_records = df[anomaly_mask].copy()
    anomaly_records["anomaly_details"] = anomalies.loc[anomaly_mask, "anomaly_details"].values

    if anomaly_records.empty:
        return "No anomalies detected in the current dataset."

    # Convert anomaly records to a readable string
    anomaly_summary = anomaly_records.to_string(index=False)

    # Send a basic prompt with the data
    prompt = f"Here are some network anomalies I detected: {anomaly_summary}. What do you think is wrong?"

    message = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=2000,
        messages=[{"role": "user", "content": prompt}],
    )

    return message.content[0].text

What does this code do?

This function handles the full flow of getting anomaly data to Claude and getting a response back.

  • anthropic.Anthropic() creates a client that automatically reads your ANTHROPIC_API_KEY environment variable.
  • The function filters the full DataFrame down to only the flagged rows and converts them to a string Claude can read.
  • client.messages.create() sends your prompt to claude-sonnet-5 and returns the response text.
  • Save network_agent.py. You will test this function in the next chunk when you wire it into main().
Update main() to call the analysis

The function exists but nothing calls it yet. You need to add the call at the end of main() so the agent sends anomalies to Claude after detecting them.

  • In network_agent.py, scroll down to the main() function.
  • Find this block at the end of the function:
    if num_anomalies_found > 0:
        anomaly_mask = anomalies["is_anomaly"]
        print("  Flagged records:")
        flagged_display = df[anomaly_mask][["timestamp", "cell_id", "rsrp_dbm", "sinr_db", "throughput_dl_mbps", "latency_ms"]].copy()
        print(flagged_display.to_string(index=False))
        print()
  • Add the following code below that block, at the same indentation level as the if statement (inside main(), not inside the if):
    # Send anomalies to Claude for interpretation
    print("[3/3] Sending anomalies to Claude for diagnosis...")
    print()
    report = analyze_with_claude(df, anomalies)
    print(report)

What does this addition do?

These lines call your new function with the data and anomaly results, then print whatever Claude sends back directly to the terminal. The [3/3] label keeps the progress indicators consistent.

  • Save network_agent.py.

Seeing an indentation error?

Make sure the new print() and report = lines are indented with 4 spaces (inside main()), not 8 spaces (which would put them inside the if block above).

help me fix the indentation in my main() function

✔️ Awesome, I've got everything!

Great. Make sure you have saved network_agent.py before running.

ⓧ I'd like to double check the full code

Your network_agent.py should now contain these sections in order. Scroll through and confirm each is present:

  • Imports (anthropic, pandas, datetime, random) at the top.
  • generate_5g_data() function generating 100 records with 8 anomalies.
  • detect_anomalies() function using z-score detection.
  • analyze_with_claude() function (new) that sends data to Claude with a basic prompt.
  • main() function with three stages: generate, detect, and now the Claude call at the end.
  • if __name__ == "__main__": main() at the very bottom.
Run the agent and read Claude's response

Your agent now generates data, detects anomalies, and asks Claude to interpret them. Before you run it, think about what kind of response you expect from such a simple prompt.

  • Before running, predict: will Claude give you a structured diagnostic with severity levels, root causes, and specific NOC actions? Or something more generic?
  • Run your agent by entering this command:
python network_agent.py

Claude responds with general observations about the numbers. It might mention that some values look low or high, but it will not classify by severity, will not use proper 5G terminology like "coverage hole" or "pilot pollution", and will not give specific actions a NOC team could follow.

This is intentional. The prompt said "What do you think is wrong?" with no context about what these numbers mean in a 5G network. That vagueness produces vague output. This is the prompt engineering problem you will solve in the next step.

Why is the response generic?

Claude is a general-purpose model. Without telecom-specific context (reference thresholds, the NOC engineer persona, a required output format), it has no way to know what counts as "critical" versus "minor" in a 5G network.

The difference between this basic prompt and a production-quality prompt is exactly what separates a toy demo from a useful AI tool. The next step fixes this.

Seeing an authentication error?

If you see a message about an invalid API key or authentication failure, your ANTHROPIC_API_KEY environment variable may not be set in your current terminal session. Re-run the set command from Step 1.

help me fix my Anthropic API key authentication error

You have a working AI integration. Claude reads your anomaly data and responds. But the response reads like a general assistant guessing at what numbers mean. In the next step, you will engineer a telecom-specific prompt that transforms this generic output into a structured diagnostic report.

Engineer a Telecom-Specific Prompt

In the previous step, you connected your anomaly data to Claude and got a response. But that response was generic. It did not use proper 5G terminology, did not classify severity, and did not give specific actions a NOC team could act on.

The problem is the prompt. In real AI/ML telecom systems, prompt engineering is how you inject domain expertise into LLM workflows. By giving Claude the 5G NR reference thresholds, a NOC engineer persona, and a required output structure, you transform a generic chatbot response into an actionable diagnostic tool.

In this step, get ready to:
  • Replace the generic prompt with a structured telecom-specific prompt.
  • Update the output display to show a professional diagnostic report header.
  • Run the final agent and compare the output to the generic response from Step 4.
Replace the generic prompt with a telecom-specific prompt

The key difference between a toy demo and a production AI system is context. You need to tell Claude exactly what role it plays, what reference data to use, and what format you expect back.

  • In network_agent.py, find the analyze_with_claude() function.
  • Find this line:
    prompt = f"Here are some network anomalies I detected: {anomaly_summary}. What do you think is wrong?"
  • Replace that entire line with the following structured prompt:
    prompt = f"""You are a 5G network operations center (NOC) engineer AI assistant.
Analyze the following anomalous KPI measurements from a 5G NR network and provide a structured diagnostic report.

Reference thresholds for healthy 5G NR performance:
- SS-RSRP: >= -90 dBm (Good), >= -80 dBm (Excellent), < -100 dBm (Weak), < -110 dBm (Critical)
- SS-RSRQ: >= -10 dB (Excellent), -10 to -15 dB (Good), < -20 dB (Severely degraded)
- SS-SINR: >= 20 dB (Excellent), 13-20 dB (Good), 0-13 dB (Acceptable), < 0 dB (Critical)
- DL Throughput: >= 100 Mbps (mid-band target)
- Latency: <= 10 ms (eMBB target)

Anomalous measurements detected:
{anomaly_summary}

For each anomaly, provide:
1. Severity (Critical / Major / Minor)
2. Probable root cause (coverage hole, interference/pilot pollution, congestion, handover issue, or equipment fault)
3. Affected KPIs and their relationship
4. Recommended action for the NOC team

End with a summary of overall network health and priority actions."""

What does this prompt do differently?

This prompt has four parts that the generic one lacked:

  • Persona: Telling Claude it is a NOC engineer AI assistant frames all its reasoning in telecom context.
  • Reference thresholds: The 5G NR KPI thresholds from 3GPP standards give Claude concrete benchmarks to compare measurements against.
  • Data: The anomaly summary is injected via the f-string, same as before.
  • Output format: Specifying severity, root cause, KPIs, and recommended actions forces Claude to produce structured output instead of a rambling paragraph.
Update the output display

A real NOC tool presents its output with clear visual framing. Adding a header makes the diagnostic report stand out from the rest of the terminal output.

  • In the main() function, find this line near the end:
    report = analyze_with_claude(df, anomalies)
    print(report)
  • Replace print(report) with a formatted header block, so the lines now look like this:
    report = analyze_with_claude(df, anomalies)
    print("=" * 60)
    print("  DIAGNOSTIC REPORT")
    print("=" * 60)
    print()
    print(report)

What does this change?

The "=" * 60 lines print a row of 60 equals signs above and below the title. This visually separates the AI-generated report from the data pipeline output above it, just like a real monitoring dashboard would.

  • Save network_agent.py.
Run the final agent

Before you run this, think back to the generic response from Step 4. It gave general observations without 5G terminology, severity levels, or specific NOC actions. Do you think the new prompt will produce something more structured?

  • Run the agent by entering this command:
python network_agent.py

Under the DIAGNOSTIC REPORT header, you should see a structured response with severity classifications (Critical, Major, or Minor), probable root causes (coverage hole, interference, congestion), affected KPIs with their relationships explained, and recommended NOC actions for each anomaly.

Why is this output so different from Step 4?

The difference between the two runs demonstrates why prompt engineering matters in production AI systems. Same model, same data, same API call. The only change is the prompt structure.

By providing domain context (the 3GPP thresholds), a persona (NOC engineer), and a required output format, you transformed a generic chatbot response into an actionable diagnostic tool.

Not seeing structured output?

  • Check that your triple-quoted f-string starts with f""" and ends with """. A missing quote will cause a syntax error.
  • Make sure the {anomaly_summary} variable is still inside the f-string. Without it, Claude has no data to analyze.
  • If you see a rate limit error, wait a moment and try again. The Anthropic API may throttle requests if you ran Step 4 recently.

Need more help debugging?

✔️ Awesome, I've got everything!

Great. Double check you have saved network_agent.py and that your diagnostic report shows severity classifications and recommended actions.

ⓧ I'd like to double check the full code

Here is the full analyze_with_claude() function with the updated prompt:

def analyze_with_claude(df, anomalies):
    """Send detected anomalies to Claude for telecom-specific diagnosis."""
    client = anthropic.Anthropic()

    anomaly_mask = anomalies["is_anomaly"]
    anomaly_records = df[anomaly_mask].copy()
    anomaly_records["anomaly_details"] = anomalies.loc[anomaly_mask, "anomaly_details"].values

    if anomaly_records.empty:
        return "No anomalies detected in the current dataset."

    anomaly_summary = anomaly_records.to_string(index=False)
    prompt = f"""You are a 5G network operations center (NOC) engineer AI assistant.
Analyze the following anomalous KPI measurements from a 5G NR network and provide a structured diagnostic report.

Reference thresholds for healthy 5G NR performance:
- SS-RSRP: >= -90 dBm (Good), >= -80 dBm (Excellent), < -100 dBm (Weak), < -110 dBm (Critical)
- SS-RSRQ: >= -10 dB (Excellent), -10 to -15 dB (Good), < -20 dB (Severely degraded)
- SS-SINR: >= 20 dB (Excellent), 13-20 dB (Good), 0-13 dB (Acceptable), < 0 dB (Critical)
- DL Throughput: >= 100 Mbps (mid-band target)
- Latency: <= 10 ms (eMBB target)

Anomalous measurements detected:
{anomaly_summary}

For each anomaly, provide:
1. Severity (Critical / Major / Minor)
2. Probable root cause (coverage hole, interference/pilot pollution, congestion, handover issue, or equipment fault)
3. Affected KPIs and their relationship
4. Recommended action for the NOC team

End with a summary of overall network health and priority actions."""
    message = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=2000,
        messages=[{"role": "user", "content": prompt}],
    )

    return message.content[0].text

And here is the updated end of main():

    print("[3/3] Sending anomalies to Claude for diagnosis...")
    print()
    report = analyze_with_claude(df, anomalies)
    print("=" * 60)
    print("  DIAGNOSTIC REPORT")
    print("=" * 60)
    print()
    print(report)

You now have a working 5G anomaly detection agent. It generates realistic network data, automatically flags deviations, and produces AI-powered diagnostic reports that a NOC engineer could act on. Next up, the Secret Mission challenges you to extend this agent with a per-cell health scorecard.

Secret mission

Per-Cell Health Scorecard

Real NOC teams don't just react to individual anomalies. They need to know which cell sites are performing worst overall so they can prioritize field engineering resources. Can you extend your agent with a per-cell scorecard and AI-powered prioritization?

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally and uses a pay-per-call API. If you do not run the script, you pay nothing. Decide whether to keep your resources, pause them, or delete them entirely.

Resources you used:

  • 5g-anomaly-agent project folder (contains your virtual environment, installed packages, and network_agent.py).
  • Anthropic API key (stored on console.anthropic.com, no ongoing cost unless you make API calls).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with the agent or want to re-run it later.

  • Your project folder stays on your Desktop. You can re-run the agent anytime by activating the virtual environment and running python network_agent.py.
  • Your Anthropic account has no subscription fee. You are only charged per API call.
  • The ANTHROPIC_API_KEY environment variable you set with set only lasts for that terminal session. Once you close the terminal, it is gone.

Pause - I'll come back to this later

Free up terminal resources while keeping your files intact. You can pick up right where you left off.

  • If your virtual environment is still active, deactivate it by running:
  • Close any terminal windows running the agent.
  • Your project folder and API key remain available for next time.
deactivate

Delete - I don't want to use this again

Remove all project files and optionally disable your API key. This frees up disk space and revokes access.

  • Delete the project folder by running the command for your operating system:

macOS

rm -rf ~/Desktop/5g-anomaly-agent

Windows

rmdir /s /q %USERPROFILE%\Desktop\5g-anomaly-agent
  • To disable your API key, go to console.anthropic.com, navigate to the API Keys section, find the key you created for this project, and disable or revoke it. This prevents any future charges from accidental use.
  • Your Anthropic account itself has no subscription. You do not need to delete the account unless you want to.

That's a Wrap!

That's a Wrap!

Nice work! You just built a fully functional 5G Network Anomaly Detection Agent that generates synthetic network data, flags anomalies using statistical methods, and produces AI-powered diagnostic reports.

You've learned how to:

  • Built a Python agent that generates realistic 5G network KPI data and detects anomalies automatically using z-score analysis.
  • Integrated Claude's API into a Python workflow to transform raw anomaly flags into structured, actionable diagnostic reports.
  • Demonstrated prompt engineering by evolving a generic prompt into a telecom-specific one that produces severity classifications, root causes, and NOC actions.
  • Secret Mission: Built a per-cell health scorecard with AI-powered prioritization recommendations.

Ready to quiz yourself?