AWS for Industries

Build an AI-powered 5G Signaling Trace Analyzer Using Amazon Bedrock

Telecom engineers routinely analyze decoded signaling traces to troubleshoot network issues, validate procedure execution, and accelerate root cause analysis. In 5G networks, even a single registration attempt can span multiple layers such as NAS and NGAP. The registration attempt includes security context establishment and carries identifiers such as Subscription Concealed Identifier (SUCI), Globally Unique Temporary Identity (GUTI), Tracking Area Code (TAC), and Network Slice Selection Assistance Information (NSSAI). Interpreting these traces requires both protocol knowledge and time. In production environments, engineers often work through traces containing hundreds or thousands of messages across multiple interfaces, correlating signaling flows manually to isolate a single failure. This process can take hours per incident, extending Mean Time To Resolution (MTTR).

This post shows how to build a simple solution that uses Amazon Bedrock to analyze decoded 5G traces and generate structured, easy to understand insights. The solution uses the Converse API, which provides a consistent message-based interface across supported models.

The solution extracts a structured representation from a decoded trace, then generates a technical analysis report. It acts as an interpretation aid, not a 3GPP compliance engine.

Solution overview

The solution takes a two-step approach. A decoded 5G trace is unstructured text — timestamps, message headers, and protocol fields in a vendor-specific format. Rather than asking a model to analyze this raw text in a single pass, the solution first converts it into a structured representation, then generates analysis from that structured output.

  1. Structured extraction – A first Amazon Bedrock call converts a decoded 5G trace into structured JSON, capturing message order, protocol layers, identifiers, and security context.
  2. Technical analysis – A second Amazon Bedrock call uses that structured JSON to generate a telecom-focused Markdown report.

Separating extraction from analysis is important for three reasons: it makes the intermediate JSON reusable for other tools or dashboards, it keeps each prompt focused on a single task, and it improves result consistency across runs.

This design also aligns well with the Bedrock Converse API pattern: send structured prompts as messages, receive text output, and chain the results into the next step. AWS recommends using the Converse API for applications that use message-based interactions because it provides a consistent interface across supported models.

Architecture

A decoded 5G trace is the human-readable text output produced when a tool such as Wireshark, tshark, or a vendor protocol analyzer decodes raw PCAP. It contains signaling messages with their fields, timestamps, and direction as plain text. This solution takes that decoded text as input, not the raw binary PCAP.

The following diagram shows the architecture used in this solution.

Architecture diagram showing a decoded 5G trace file as input to a Python CLI application on an engineer's workstation. The application makes two Amazon Bedrock API calls: the first extracts structured JSON, the second generates a Markdown analysis report. Outputs are saved locally with optional storage in Amazon S3.

Figure 1: Solution architecture for the Amazon Bedrock-based 5G trace analyzer

Architecture description

  • The input is a decoded 5G trace. This post demonstrates the solution using Non-Access Stratum (NAS) and Next Generation Application Protocol (NGAP) signaling captured on the N2 interface. The same approach can be adapted to other interfaces and protocols by adjusting the extraction prompt.
  • A Python CLI application runs locally on the engineer’s workstation. It reads a decoded trace file from the local filesystem and invokes Amazon Bedrock through the Bedrock Runtime client in Boto3.
  • The first model call extracts ordered messages, phases, likely procedure, and uncertainty notes into JSON.
  • The second model call generates a Markdown report that explains the observed signaling flow, identifies protocol phases, highlights cross-layer interactions, and flags potential gaps or anomalies. Engineers can view the report directly or include it in incident documentation.
  • Outputs are saved locally on the engineer’s workstation. You can optionally store them in Amazon S3.

The input can come from any tool that produces decoded signaling text (Wireshark, tshark, Netscout, Gigamon). No specific format is required, the model interprets the text semantically and handles vendor variations.

Prerequisites

Before you begin, make sure you have the following:

IAM permissions

At minimum, the IAM identity used to run the script needs permission to invoke the model. The Converse API requires the bedrock:InvokeModel IAM action. For this solution, the following policy is sufficient:

{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "InvokeBedrockModel",
        "Effect": "Allow",
        "Action": "bedrock:InvokeModel",
        "Resource": "arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.anthropic.claude-sonnet-4-20250514-v1:0"
      }
    ]
  }

Replace 123456789012 with your AWS account ID and adjust the Region if needed. This policy follows least-privilege by scoping access to a single inference profile.

Note: The Converse API does not require a separate bedrock:Converse IAM action. The bedrock:InvokeModel action authorizes both the InvokeModel and Converse API operations.

Solution walkthrough

Step 1: Configure your local environment

This solution runs on any environment with Python and network access to Amazon Bedrock for example, your local workstation, an Amazon EC2 instance, or AWS CloudShell.

Configure the AWS CLI with credentials that can invoke Amazon Bedrock. Use temporary credentials through IAM Identity Center (SSO):

aws configure sso
aws sso login --profile your-profile-name

On EC2 instance, attach an IAM role with AWS Bedrock permissions instead.

Step 2: Create the project structure

Use the following structure:

telco-bedrock-poc/
├── app.py
├── prompts.py
├── bedrock_utils.py
├── requirements.txt
├── input/
│   ├── sample_5g_registration_trace.txt
│   └── incomplete_5g_registration_trace.txt
└── output/
    ├── extracted_trace.json
    └── analysis_report.md

Step 3: Prepare a sample decoded 5G trace

Create the input file input/sample_5g_registration_trace.txt. In a real scenario, you would generate this by decoding a PCAP capture from your test environment for example, using tshark:

tshark -r capture.pcap -d sctp.port==38412,ngap -V > input/sample_5g_registration_trace.txt

For this post, use the following sample trace that represents a complete 5G initial registration procedure:

========== TRACE START: 5G REGISTRATION (NR, 3GPP ACCESS) ==========

  --- NGAP: Initial UE Message ---
  [2025-03-10 10:15:23.112] gNB → AMF
      Procedure: Initial UE Message
      RAN UE NGAP ID: 0x00001001
      NAS-PDU: Registration Request
      User Location Info:
          PLMN: 001-01
          TAC: 0x00A1
          NR Cell ID: 0xABCDE12345
  
  --- NAS: Registration Request ---
  [2025-03-10 10:15:23.113] UE → AMF
      Extended Protocol Discriminator: 5GS Mobility Management (0x7E)
      Security Header Type: Plain NAS (0x0)
      Message Type: Registration Request (0x41)
      Registration Type: Initial Registration
      ngKSI: Not Available
      5GS Mobile Identity:
          Type: SUCI
          MCC: 001, MNC: 01
          Routing Indicator: 0000
          Protection Scheme: Null
          MSIN: 1234567890
      UE Security Capability:
          5G-EA: 128-NEA1, 128-NEA2
          5G-IA: 128-NIA1, 128-NIA2
      Requested NSSAI:
          - SST=1, SD=0x010203
  
  ... (Authentication Request, Authentication Response, Security Mode Command,
       Security Mode Complete, Initial Context Setup Request) ...
  
  --- NAS: Registration Accept ---
  [2025-03-10 10:15:23.601] AMF → UE
      Message Type: Registration Accept
      5G-GUTI: assigned
      TAI List:
          - TAC=0x00A1
          - TAC=0x00A2
      Allowed NSSAI:
          - SST=1, SD=0x010203
      Timer T3512: 3600
      Timer T3502: 720
  
  --- NAS: Registration Complete ---
  [2025-03-10 10:15:23.801] UE → AMF
      Message Type: Registration Complete

========== TRACE END ==========

Note: This sample uses test network PLMN 001-01 and a null SUCI protection scheme. In production 5G deployments, operators use ECIES Profile A or B as defined in 3GPP TS 33.501 to conceal the subscriber identity.

Step 4: Install dependencies

Create and activate a Python virtual environment, and then install dependencies:

python3 -m venv .venv
source .venv/bin/activate
pip install boto3

Step 5: Create the extraction and analysis prompts

The prompts are the most important part of this solution. They should be explicit enough to guide the model.

prompts.py

EXTRACTION_SYSTEM_PROMPT = """
You are a senior telecom signaling analyst specializing in 5G core and RAN procedures.

You are analyzing decoded 5G signaling traces that may include NAS and NGAP messages.

Your task is to extract a structured representation of the observed procedure.

Rules:
- Use only information explicitly supported by the trace.
- Do not invent messages, fields, or phases.
- Preserve message order.
- Include both NAS and NGAP messages when present.
- Normalize message names to standard telecom-friendly names.
- If the trace appears incomplete, reflect that in uncertainty_notes.
- If a release can only be inferred indirectly, keep the minimum_release_confidence low or medium.
- Return valid JSON only.
- Do not use markdown fences.
"""

def build_extraction_user_prompt(trace_text: str) -> str:
    return f"""
Analyze the following decoded 5G trace.

Return JSON using this exact schema:
{{
  "procedure_name": "string",
  "procedure_confidence": "high|medium|low",
  "access_type": "string",
  "network_functions": ["string"],
  "messages": [
    {{
      "order": 1,
      "layer": "NAS|NGAP|RRC|OTHER",
      "message_name": "string",
      "source": "string",
      "target": "string",
      "important_fields": ["string"]
    }}
  ],
  "phases": ["string"],
  "key_identifiers": {{
    "subscriber_identity": ["string"],
    "session_or_context_ids": ["string"],
    "mobility_or_location_ids": ["string"]
  }},
  "security_context": {{
    "authentication_observed": true,
    "security_mode_observed": true,
    "selected_algorithms": ["string"]
  }},
  "minimum_release": "string",
  "minimum_release_confidence": "high|medium|low",
  "uncertainty_notes": ["string"]
}}

Additional guidance:
- For procedure_name, prefer telecom-standard procedure naming.
- For access_type, identify the most likely access type from the trace.
- For network_functions, include entities such as UE, gNB, AMF when observed.
- For important_fields, capture only the most relevant fields for that message.
- For key_identifiers, group values such as SUCI, GUTI, RAN UE NGAP ID, AMF UE NGAP ID, TAC, and NR Cell ID.
- For phases, infer high-level stages such as Registration, Authentication, Security, Context Setup, and Completion when supported.
- For minimum_release, identify the earliest 3GPP release required to support all observed features. Do not attempt to identify the actual deployed release.

Trace:
{trace_text}
"""

Analysis prompt

ANALYSIS_SYSTEM_PROMPT = """
You are a senior telecom engineer with expertise in 5G signaling analysis across NAS and NGAP.

You are writing for telecom professionals such as test engineers, packet-core engineers, and RAN engineers.

Your task is to explain the extracted procedure in precise engineering language.

Rules:
- Be technical and concise.
- Explain what happened across UE, gNB, and AMF when applicable.
- Use telecom terminology correctly.
- Distinguish observed facts from inference.
- Do not claim formal 3GPP compliance or conformance certification.
- If the trace is incomplete, state that clearly.
- Return Markdown only.
"""

def build_analysis_user_prompt(extracted_json: str) -> str:
    return f"""
Using the structured extraction below, generate a Markdown report with the following sections:

# Telecom Trace Analysis Report
## Procedure identified
## Technical summary
## Observed signaling flow
## Key protocol phases
## Cross-layer observations
## Security context observations
## Potential gaps or anomalies
## Baseline specification compatibility
## Suggested next checks

Guidance:
- In "Observed signaling flow", describe the message progression in order.
- In "Cross-layer observations", explain how NAS and NGAP interact in this trace.
- In "Baseline specification compatibility", identify the minimum 3GPP release required to support the observed features. Do not claim to identify the actual deployed release.
- In "Potential gaps or anomalies", only mention items supported by the extracted data.

Structured extraction:
{extracted_json}
"""

Step 6: Create the Bedrock invocation helper

Create bedrock_utils.py:

import json
import re

import boto3


def call_bedrock_converse(region, model_id, system_prompt, user_prompt):
    client = boto3.client("bedrock-runtime", region_name=region)
    response = client.converse(
        modelId=model_id,
        system=[{"text": system_prompt}],
        messages=[{"role": "user", "content": [{"text": user_prompt}]}],
        inferenceConfig={"temperature": 0.1, "maxTokens": 4096},
    )
    return response["output"]["message"]["content"][0]["text"]


def extract_json(text):
    """Parse JSON from model output, stripping markdown fences or preamble."""
    cleaned = re.sub(r"^```(?:json)?\s*\n?", "", text.strip())
    cleaned = re.sub(r"\n?```\s*$", "", cleaned)
    brace = cleaned.find("{")
    if brace > 0:
        cleaned = cleaned[brace:]
    return json.loads(cleaned)

The temperature is set to 0.1 to produce deterministic, consistent extractions higher values introduce variability that is undesirable for structured data extraction. The maxTokens is set to 4096, which is sufficient for the registration traces. For longer traces with more messages, increase this value to avoid truncated output.

Step 7: Build the main application

Create app.py:

  import json
  import sys

  from pathlib import Path

  import botocore.exceptions

  from prompts import (
      EXTRACTION_SYSTEM_PROMPT,
      ANALYSIS_SYSTEM_PROMPT,
      build_extraction_user_prompt,
      build_analysis_user_prompt,
  )
  from bedrock_utils import call_bedrock_converse, extract_json

  # Update to your preferred Region where the model is available
  REGION = "us-east-1"

  # Cross-region inference profile ID. Check Amazon Bedrock documentation
  # for supported models and current inference profile IDs in your Region.
  MODEL_ID = "us.anthropic.claude-sonnet-4-20250514-v1:0"

  INPUT_FILE = "input/sample_5g_registration_trace.txt"


  def main():
      input_file = sys.argv[1] if len(sys.argv) > 1 else INPUT_FILE
      trace_text = Path(input_file).read_text()
      Path("output").mkdir(exist_ok=True)

      stem = Path(input_file).stem
      output_json = f"output/{stem}_extracted.json"
      output_md = f"output/{stem}_analysis.md"

      print(f"Using model: {MODEL_ID}")
      print(f"Reading trace: {input_file}")

      print("Step 1: Extracting structured telecom data...")
      try:
          extracted_text = call_bedrock_converse(
              REGION, MODEL_ID, EXTRACTION_SYSTEM_PROMPT,
              build_extraction_user_prompt(trace_text),
          )
      except botocore.exceptions.ClientError as e:
          error_code = e.response["Error"]["Code"]
          if error_code == "AccessDeniedException":
              print(f"Access denied. Verify IAM permissions for bedrock:InvokeModel.")
          elif error_code == "ThrottlingException":
              print(f"Request throttled. Wait and retry, or request a quota increase.")
          elif error_code == "ResourceNotFoundException":
              print(f"Model not found. Verify the model ID and Region.")
          else:
              print(f"Bedrock call failed: {e}")
          sys.exit(1)

      try:
          extracted_obj = extract_json(extracted_text)
      except json.JSONDecodeError as e:
          print(f"Failed to parse extraction JSON: {e}")
          print(f"Raw output:\n{extracted_text[:500]}")
          sys.exit(1)

      extracted_pretty = json.dumps(extracted_obj, indent=2)
      Path(output_json).write_text(extracted_pretty)
      print(f"  → Saved: {output_json}")

      print("Step 2: Generating analysis report...")
      try:
          analysis_text = call_bedrock_converse(
              REGION, MODEL_ID, ANALYSIS_SYSTEM_PROMPT,
              build_analysis_user_prompt(extracted_pretty),
          )
      except botocore.exceptions.ClientError as e:
          error_code = e.response["Error"]["Code"]
          print(f"Bedrock analysis call failed ({error_code}): {e}")
          sys.exit(1)

      Path(output_md).write_text(analysis_text)
      print(f"  → Saved: {output_md}")
      print("Done.")


  if __name__ == "__main__":
      main()

This solution uses Claude Sonnet 4 through a cross-Region inference profile, which routes requests across multiple Regions for higher availability. If your workload has data residency requirements, verify that the Regions included in the inference profile align with your compliance boundary.

Step 8: Run the application

Run the solution:

python app.py

If successful, the application generates two files:

  • output/extracted_trace.json
  • output/analysis_report.md

Example structured output

A successful extraction should produce structured JSON similar to the following:

Screenshot of extracted JSON output showing procedure_name, procedure_confidence, access_type, network_functions, messages array with protocol layers and fields, phases, key_identifiers, security_context, minimum_release, and minimum_release_confidence fields.

Figure 2: Example structured JSON extraction from a 5G initial registration trace

Example analysis report

The analysis report generates a Markdown document with telecom-focused observations. The following shows a representative excerpt:

Screenshot of a Markdown analysis report showing sections for procedure identified, technical summary, observed signaling flow, key protocol phases, cross-layer observations, and security context observations.

Figure 3: Example Markdown analysis report generated from the structured extraction

Testing with an incomplete trace

To demonstrate how the solution handles imperfect data, create a second trace with a missing message in this case, Security Mode Complete is absent, simulating a capture that ended prematurely.

Run the same workflow:

python app.py input/incomplete_5g_registration_trace.txt

This demonstrates two important properties:

  • The solution can still reconstruct the most likely procedure
  • The analysis explicitly calls out uncertainty and missing phases

Real telecom traces are often partial or incomplete, making this a more realistic test.

The extraction correctly flags the gap in the phases and uncertainty_notes fields:

{
    "phases": [
      "Registration Initiation",
      "Authentication",
      "Security Establishment (Incomplete)"
    ],
    "uncertainty_notes": [
      "Trace ends abruptly after Security Mode Command; Security Mode Complete not captured",
      "Registration procedure incomplete; subsequent messages not observed"
    ]
}

The analysis report shows clear incomplete status and identifies exactly what is missing without hallucinating messages that were not in the trace.

Technical considerations

Prompt specificity matters

The quality of the solution depends on the prompt design. For telecom traces, vague prompts tend to produce shallow summaries. Better results come from prompts that:

  • ask for protocol-aware structure
  • include layer awareness
  • request cross-layer reasoning
  • enforce a technical tone
  • explicitly forbid unsupported claims

Keep the scope narrow

This implementation focuses on decoded 5G registration traces. You can extend it to PDU session establishment, handover, or service request by adjusting the prompts. The output is not a 3GPP conformance verdict.

Results and value

The solution analyzed a 10-message 5G registration trace and produced structured JSON and a technical report in under 10 seconds. For complex traces spanning hundreds of messages across multiple interfaces, manual correlation typically takes 30 minutes to several hours depending on engineer experience and trace complexity. This solution reduces initial interpretation to seconds while maintaining consistency, the same trace produces the same structured output regardless of who runs it or when.

Why Amazon Bedrock

Amazon Bedrock provides several advantages for this type of solution:

  • No infrastructure to manage — Amazon Bedrock is a fully managed service. There are no models to host, GPUs to provision, or endpoints to scale.
  • Model flexibility — If a newer model improves telecom reasoning, you change one model ID. The Converse API provides a consistent interface, so the application code typically does not change.
  • Security and privacy — Amazon Bedrock does not use customer inputs or outputs to train AWS or third-party models. Decoded traces stay within your AWS account boundary. For details, see Data protection in Amazon Bedrock.

This solution demonstrates that Amazon Bedrock adds value in telecom engineering workflows by acting as an interpretation layer over decoded signaling data accelerating trace triage, surfacing missing phases, and reducing the time required to understand complex control-plane interactions.

Cleanup

No persistent AWS resources are created, charges occur only when you invoke the model. To cleanup, delete the project directory and remove any IAM user or role created for this solution.

Conclusion

This post showed how to build a solution that uses Amazon Bedrock and the Converse API to automate trace interpretation, reducing analysis time from minutes to seconds.

The solution reads a decoded 5G trace, extracts a structured telecom-specific representation, and generates a technical report tailored to telecom engineers. When tested with an incomplete trace, it correctly identified missing messages and flagged uncertainty demonstrating that the approach handles real-world imperfect data.

Next Steps

  • Clone the repository to run the solution with your own traces.
  • Experiment with different trace types by adjusting the extraction prompt.

The next step is an agent-based architecture using Amazon Bedrock Agents that autonomously selects analyses, correlates findings across traces, and invokes external tools such as protocol validators.

Mohamed Daoud

Mohamed Daoud

Mohamed Daoud is a Senior Technical Account Manager at AWS Enterprise Support, specializing in Telecom and Media & Entertainment workloads. He helps customers apply generative AI to solve telecom and media engineering challenges at scale.