Using an AI Agent to Inspect, Configure, and Troubleshoot a Cisco Network Lab Setup
Ok, I admit I was probably living under a rock that I am publishing this article this late, but that is the thing with being a father and just jumping between the real work and family. So only after this holiday I finally had the time to put together something I was hoping to explore for a year now. In this article, I explore a small Python application I built allow AI to evaluate how useful an AI agent can be for a traditional (“legacy”) network administrator. The goal was not to replace network engineers, but to see how far an AI can go helping us manage physical traditional networks when given structured context, read-only access, and—critically—guardrails for making changes.
To do this, I created a lightweight Python tool that exposes a set of functions (“tools”) to OpenAI. These tools allow the AI to:
- Read and understand my lab topology in JSON format.
- Retrieve device configuration and state:
show running-configfrom Cisco devicesip addrandip routefrom Linux endpoints
- Execute arbitrary commands on devices only after explicit human approval.
You can find the tool here:
https://github.com/zerxen/AINetworkhttps://github.com/zerxen/AINetworkHelperForContainerLabHelper
Let’s walk through how this works and what I learned along the way.
OpenAI’s ChatGPT used here (actually chatgpt-5-mini), but locally running LLM like DeepSeek using LMStudio is not hard to replace here with a little bit of python code changes, if you want to use something like this (in read-only way) in your production network, it might be a better idea with local LLM model to nothave your configuraiton secrets somewhere in public LLMs mind.
Contents of Article
Lab Prerequisites and Environment
Containerlab Topology
The entire setup is based on a Containerlab topology. The repository contains a topology.clab.yml file that defines a small network composed of:

- Two Cisco IOL routers
- Two Ubuntu virtual machines acting as endpoints
If you want to follow along, you need a working Containerlab setup with Cisco IOL images. I have covered this in an earlier guide:
ContainerLab – Hello World with Cisco IOL
https://networkgeekstuff.com/networking/containerlab-hello-world-quick-setup-using-cisco-iol-containers/
Once you have Containerlaband the required images, deploy the lab from the topology_docs directory:
containerlab deploy ./topology.clab.yml
This creates a directory named clab-lab_topology, which contains inventory data such as management IP addresses, usernames, and passwords. My Python code parses these files and feeds a JSON representation of the topology to the AI, giving it situational awareness of the lab.
You are free to extend the topology, but do not rename the file or change the first line:
name: lab_topology
The code relies on this structure to locate topology data.
OpenAI API Key
You will also need an OpenAI API key. At the time of writing, this requires a paid account with minimum credit.
API keys can be generated here:
https://platform.openai.com/account/api-keys
Place your key into config.py using the provided example-config.py template.
If you are considering using something like this beyond a lab environment (at your own risk), the code can be adapted to run against a local LLM. I tested this with DeepSeek running on a GPU. It requires changes to the interface and prompt handling, but it is absolutely feasible.
Starting the python code’s main.py
If you already have the containerlab running, or you want to run my prototype code. Start by entering the folder of the repository downloaded from the github and first install prerequisites using python’s pip like this:
pip install -r ./requirements.txt
This used requirements.txt with a list of libraries you need in your python env.
Secondly, copy the config.py_template as config.py and place your OpenAI API key there. Then just make sure all the containerlab files are really in the topology_docs/clab-lab_topology directory (e.g. easiest is to edit my topology.clab.yml file where it is instead of starting your own topology somewhere else).
python ./main.py
And you should be greated with a prompt like
Interactive ChatGPT CLI (type 'exit' or Ctrl-C to quit)
you:
Exercise #1 – Asking AI to Describe the Topology
I started by asking the AI to describe the topology and produce a simple ASCII diagram.
You: Can you describe my topology in one paragraph please?
And maybe include below an ascii based simplified topology diagram ?
ChatGPT: None
Tokens used:
- completion_tokens: 20
- prompt_tokens: 501
- total_tokens: 521
Tool executed called: getTopologyInformation
.. results of tool call provided to the contex
ChatGPT (after tools): Your lab_topology contains four nodes: two Cisco IOL routers (cisco1 and cisco2) connected in the middle, and two Ubuntu VMs (ubuntu1 and ubuntu2) acting as edge hosts. cisco1 and cisco2 are linked via Ethernet0/1 (core link). Each router has an edge link to an Ubuntu VM: cisco1:Ethernet0/2 ↔ ubuntu1:eth1, and cisco2:Ethernet0/2 ↔ ubuntu2:eth1.
Simplified ASCII topology diagram:
ubuntu1
|
(eth1)
|
[cisco1]
|
(Ethernet0/1)
|
[cisco2]
|
(eth1)
|
ubuntu2
The AI correctly identified:
- All four nodes
- Physical connectivity
- Management IPs
- Device images
- Credentials from the inventory
It also produced a coherent ASCII diagram and interface summary. This demonstrated that the agent had a usable mental model of the network purely from structured JSON input.
Validating Connectivity Using Read-Only Tools
Next, I asked the AI to determine whether ubuntu1 could reach ubuntu2.
You: Can you check the configuration of the devices in the topology
and comment if ubuntu1 would be able to reach ubuntu2?
Limit your answer to 2–3 paragraphs.
ChatGPT: None
Tool executed called: getTopologyInformation
.. results of tool call provided to the context
Follow-up response contains tool_calls, processing recursively...
Tool executed called: getDeviceConfiguration with target = ubuntu1
Connecting to Linux device at 172.20.20.5 to execute 'ip addr' and 'ip route'
.. results of tool call provided to the context
Tool executed called: getDeviceConfiguration with target = ubuntu2
Connecting to Linux device at 172.20.20.2 to execute 'ip addr' and 'ip route'
.. results of tool call provided to the context
Tool executed called: getDeviceConfiguration with target = cisco1
Connecting to Cisco device at 172.20.20.3 to execute 'show running-configuration'
.. results of tool call provided to the context
Tool executed called: getDeviceConfiguration with target = cisco2
Connecting to Cisco device at 172.20.20.4 to execute 'show running-configuration'
.. results of tool call provided to the context
ChatGPT (after tools): Short answer: No — as configured now ubuntu1 cannot reach ubuntu2.
Why:
- On both Ubuntu hosts the interface expected for the lab dataplane (ens2) is down and has no IPv4 address.
- The Cisco interfaces that connect to the VMs and the link between the two routers are administratively down
and have no IP addresses. Because those links are shutdown and the VM dataplane interfaces are down,
there is no layer‑2/3 path between the two Linux hosts.
If you want, I can apply these changes now (or run the verification commands) — tell me which devices to configure or which checks to run.
The AI correctly concluded that connectivity would not work and identified the reasons:
- Ubuntu dataplane interfaces were down
- Cisco interfaces were administratively shut
- No IP addressing was configured on the forwarding links
This is a key point: with read-only tools, the AI can already provide meaningful troubleshooting insight without any risk because here it used my pre-prepared “getDeviceConfiguration” functions with static show run and other basic commands. This is safe to use in production method.
Exercise #2 – AI Configuring the Network with Human Approval Process
The more interesting part begins when allowing the AI to make changes using a bit more dangerous tool called “executeCommandsOnDevice” that I have written in python as SSH interface towards devices in this topology.In tools.py, I added a function with this signature:
def executeCommandsOnDevice(target: str,
commands: str,
expected_string: str = None) -> str:
Key design decisions:
- Devices are referenced only by logical names as “target” (
cisco1,ubuntu2, etc.). - The AI never sees real IPs beyond what Containerlab provides.
- Commands are displayed to the human operator before execution.
- A mandatory yes/no approval is required before anything is executed o the target device.
If the admin responds with no, the AI receives feedback that the commands were rejected and must propose alternatives.
Letting the AI Review My Intended Configuration
Here is the L3 extension of the topology that I want the final configuraiton to look like, with routing being for now only static routes:

Because I want to focus on just one device type, I am hiding the parts of this communication for configuring the ubuntu1 and ubuntu2 linux nodes with the AI, it works the same just using some ip addr and ip route add commands.
As communication way for the AI, I deliberately provided an incomplete configuration (missing no shutdown and configure terminal in places) and asked the AI to review it before applying.
You: ok, I want you to configure my network for me, here is my guidance for the
configuration, please double check for any mistakes before applying:
#cisco1:
interface Ethernet0/1
ip address 20.20.20.1 255.255.255.0
!
interface Ethernet0/2
ip address 10.10.10.1 255.255.255.0
!
ip route 30.30.30.0 255.255.255.0 20.20.20.2
#cisco2:
conf t
interface Ethernet0/1
ip address 20.20.20.2 255.255.255.0
!
interface Ethernet0/2
ip address 30.30.30.2 255.255.255.0
!
ip route 10.10.10.0 255.255.255.0 20.20.20.1
The catch here is that if you are a network admin, you immediately flagged some issues here like:
- Cisco interfaces were not being enabled because there is no “no shutdown” command
- Configuration mode was missing to enter these at the beginning
It then produced a corrected, copy/paste-ready configuration plan with this kind of response:
ChatGPT: I reviewed your planned configuration. It is logically consistent
(networks, next-hops and router-to-router link match) — there are no routing or
addressing mistakes — **but you omitted enabling the interfaces on the Cisco devices
(no shutdown).** Also you must bring up the Ubuntu ens2 interface before assigning
the address. I list the final commands to run on each device (including the missing
no shutdown) and can apply them when you confirm.
Commands to apply (copy/paste-ready)
- cisco1 (config mode)
configure terminal
interface Ethernet0/1
ip address 20.20.20.1 255.255.255.0
no shutdown
exit
interface Ethernet0/2
ip address 10.10.10.1 255.255.255.0
no shutdown
exit
ip route 30.30.30.0 255.255.255.0 20.20.20.2
end
write memory
- cisco2 (config mode)
configure terminal
interface Ethernet0/1
ip address 20.20.20.2 255.255.255.0
no shutdown
exit
interface Ethernet0/2
ip address 30.30.30.2 255.255.255.0
no shutdown
exit
ip route 10.10.10.0 255.255.255.0 20.20.20.1
end
write memory
Post-apply checks I will run
- On each Cisco: show ip interface brief; show ip route
- On each Ubuntu: ip addr show ens2; ip route show
- Ping tests:
- From ubuntu1 -> 10.10.10.1 (cisco1)
- From ubuntu2 -> 30.30.30.2 (cisco2)
- From ubuntu1 -> 30.30.30.30 (ubuntu2) and vice versa
This alone is already valuable: the AI acted as a second pair of eyes for a badly prepared configuraiton. Also the fact that it wants to do some ping tests from the ubuntu VMs is great as doing post change tests is always something engineers like to skip.
Allowing AI to Apply the Configuration (With Approval Process Example)
The session with the AI therefore continued like this …
You: ok, apply the configurations.
ChatGPT: None
Tokens used:
- completion_tokens: 902
- prompt_tokens: 4954
- total_tokens: 5856
Tool executed called: executeCommandsOnDevice target=cisco1
Commands to execute:
configure terminal
interface Ethernet0/1
ip address 20.20.20.1 255.255.255.0
no shutdown
exit
interface Ethernet0/2
ip address 10.10.10.1 255.255.255.0
no shutdown
exit
ip route 30.30.30.0 255.255.255.0 20.20.20.2
end
write memory
show ip interface brief
show ip route
approved? [yes/no]
The approval prompt appeared, this is not comming from the AI, this approval process ia a old school python code stopping the execution right when the AI triggers the executeCommandsOnDevice function. I have manually reviewed the commands it produced and honstly it looks good, so I allowed it to proceed.
.. continuing from previous session. ...
approved? [yes/no] yes
Outputs obtained from device:
{'configure terminal': 'Enter configuration commands, one per line. End with CNTL/Z.', 'interface Ethernet0/1': '', ' ip address 20.20.20.1 255.255.255.0': '', ' no shutdown': '', 'exit': '', 'interface Ethernet0/2': '', ' ip address 10.10.10.1 255.255.255.0': '', 'ip route 30.30.30.0 255.255.255.0 20.20.20.2': '', 'end': '', 'write memory': 'Building configuration...\n[OK]', 'show ip interface brief': 'Interface IP-Address OK? Method Status Protocol\nEthernet0/0 172.20.20.3 YES TFTP up up \nEthernet0/1 20.20.20.1 YES manual up up \nEthernet0/2 10.10.10.1 YES manual up up \nEthernet0/3 unassigned YES unset administratively down down ', 'show ip route': 'Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP\n D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area \n N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2\n E1 - OSPF external type 1, E2 - OSPF external type 2, m - OMP\n n - NAT, Ni - NAT inside, No - NAT outside, Nd - NAT DIA\n i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2\n ia - IS-IS inter area, * - candidate default, U - per-user static route\n H - NHRP, G - NHRP registered, g - NHRP registration summary\n o - ODR, P - periodic downloaded static route, l - LISP\n a - application route\n + - replicated route, % - next hop override, p - overrides from PfR\n & - replicated local route overrides by connected\n\nGateway of last resort is not set\n'}
.. results of tool call provided to the context
Tokens used:
- completion_tokens: 128
- prompt_tokens: 5728
- total_tokens: 5856
Follow-up response contains tool_calls, processing recursively...
Tool executed called: executeCommandsOnDevice target=cisco2
Commands to execute:
configure terminal
interface Ethernet0/1
ip address 20.20.20.2 255.255.255.0
no shutdown
exit
interface Ethernet0/2
ip address 30.30.30.2 255.255.255.0
no shutdown
exit
ip route 10.10.10.0 255.255.255.0 20.20.20.1
end
write memory
show ip interface brief
show ip route
approved? [yes/no] yes
Outputs obtained from device:
{'configure terminal': 'Enter configuration commands, one per line. End with CNTL/Z.', 'interface Ethernet0/1': '', ' ip address 20.20.20.2 255.255.255.0': '', ' no shutdown': '', 'exit': '', 'interface Ethernet0/2': '', ' ip address 30.30.30.2 255.255.255.0': '', 'ip route 10.10.10.0 255.255.255.0 20.20.20.1': '', 'end': '', 'write memory': 'Building configuration...\n[OK]', 'show ip interface brief': 'Interface IP-Address OK? Method Status Protocol\nEthernet0/0 172.20.20.4 YES TFTP up up \nEthernet0/1 20.20.20.2 YES manual up up \nEthernet0/2 30.30.30.2 YES manual up up \nEthernet0/3 unassigned YES unset administratively down down ', 'show ip route': 'Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP\n D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area \n N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2\n E1 - OSPF external type 1, E2 - OSPF external type 2, m - OMP\n n - NAT, Ni - NAT inside, No - NAT outside, Nd - NAT DIA\n i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2\n ia - IS-IS inter area, * - candidate default, U - per-user static route\n H - NHRP, G - NHRP registered, g - NHRP registration summary\n o - ODR, P - periodic downloaded static route, l - LISP\n a - application route\n + - replicated route, % - next hop override, p - overrides from PfR\n & - replicated local route overrides by connected\n\nGateway of last resort is not set\n'}
.. results of tool call provided to the context
Follow-up response contains tool_calls, processing recursively...
Tool executed called: executeCommandsOnDevice target=ubuntu1
.... omitted ubuntu1 and ubuntu2 configuraitons - START....
<< AI configured via commands the ubuntu1 and ubuntu2, it also did pings between the two ubuntus >>
.... omitted ubuntu1 and ubuntu2 configuraitons - END ....
ChatGPT (after tools): Changes applied and verified.
Summary of actions performed
- cisco1: configured Ethernet0/1 (20.20.20.1/24) and Ethernet0/2 (10.10.10.1/24), enabled interfaces, added static route for 30.30.30.0/24 via 20.20.20.2, saved config.
- show ip interface brief shows Ethernet0/1 and Ethernet0/2 up.
- show ip route shows connected networks and the static route to 30.30.30.0/24.
- cisco2: configured Ethernet0/1 (20.20.20.2/24) and Ethernet0/2 (30.30.30.2/24), enabled interfaces, added static route for 10.10.10.0/24 via 20.20.20.1, saved config.
- show ip interface brief shows Ethernet0/1 and Ethernet0/2 up.
- show ip route shows connected networks and the static route to 10.10.10.0/24.
- ubuntu1: brought ens2 up, assigned 10.10.10.10/24 and added route to 30.30.30.0/24 via 10.10.10.1.
- ping to 10.10.10.1 succeeded.
- ping to 30.30.30.30 initially failed before other devices were configured; after routers configured, ping to 30.30.30.30 succeeded (0% loss).
- ubuntu2: brought ens2 up, assigned 30.30.30.30/24 and added route to 10.10.10.0/24 via 30.30.30.2.
- ping to 30.30.30.2 succeeded.
- ping to 10.10.10.10 succeeded (0% loss).
Done. Do you need anything else to adjust or make persistent?
After approval, the AI configured each device, validated interface status, routing tables, and ran ping tests between endpoints. Connectivity was fully working and since the I have seen the ping commands outputs in the detailed logs, I could thrust the AI.
Exercise #3 – AI Troubleshooting a Broken Network
To test AI’s troubleshooting capabilities on cisco networks, I restarted the AI (clearing its memory/context) and manually introduced an error: a more specific static route on cisco2 pointing to a non-existent next-hop.
cisco2#sh run | include ip route
ip route 10.10.10.0 255.255.255.0 20.20.20.1
cisco2#conf t
Enter configuration commands, one per line. End with CNTL/Z.
cisco2(config)#ip route 10.10.10.0 255.255.255.240 20.20.20.5
cisco2(config)#do sh run | include ip route
ip route 10.10.10.0 255.255.255.0 20.20.20.1
ip route 10.10.10.0 255.255.255.240 20.20.20.5
This broke connectivity between ubuntu1 and ubuntu2.
I then asked the AI to investigate and fix the issue.
You: There is some issue with my network configuration. ubuntu1 and ubuntu2 cannot communicate with each other. Please investigate and fix.
ChatGPT: None
Tool executed called: getTopologyInformation
.. results of tool call provided to the context
Tool executed called: getDeviceConfiguration with target = ubuntu1
Connecting to Linux device at 172.20.20.5 to execute 'ip addr' and 'ip route'
.. results of tool call provided to the context
Tool executed called: getDeviceConfiguration with target = ubuntu2
Connecting to Linux device at 172.20.20.2 to execute 'ip addr' and 'ip route'
.. results of tool call provided to the context
Follow-up response contains tool_calls, processing recursively...
Tool executed called: getDeviceConfiguration with target = cisco1
Connecting to Cisco device at 172.20.20.3 to execute 'show running-configuration'
.. results of tool call provided to the context
Follow-up response contains tool_calls, processing recursively...
Tool executed called: getDeviceConfiguration with target = cisco2
Connecting to Cisco device at 172.20.20.4 to execute 'show running-configuration'
.. results of tool call provided to the context
Follow-up response contains tool_calls, processing recursively...
Tool executed called: executeCommandsOnDevice target=cisco2
Commands to execute:
configure terminal
no ip route 10.10.10.0 255.255.255.240 20.20.20.5
end
show ip route 10.10.10.0
show running-config | include ^ip route 10.10.10.0
approved? [yes/no] yes
Outputs obtained from device:
{'configure terminal': 'Enter configuration commands, one per line. End with CNTL/Z.', 'no ip route 10.10.10.0 255.255.255.240 20.20.20.5': '', 'end': '', 'show ip route 10.10.10.0': 'Routing entry for 10.10.10.0/24\n Known via "static", distance 1, metric 0\n Routing Descriptor Blocks:\n * 20.20.20.1\n Route metric is 0, traffic share count is 1', 'show running-config | include ^ip route 10.10.10.0': 'ip route 10.10.10.0 255.255.255.0 20.20.20.1'}
.. results of tool call provided to the context
ChatGPT (after tools): I found a bad static on cisco2 that was sending 10.10.10.0 to the wrong next-hop (an extra /28 pointing at 20.20.20.5), which prevented proper routing between 10.10.10.0/24 (ubuntu1) and 30.30.30.0/24 (ubuntu2); I removed that erroneous route with "configure terminal" / "no ip route 10.10.10.0 255.255.255.240 20.20.20.5" and verified the routing table now shows 10.10.10.0/24 via 20.20.20.1 (the expected path), while cisco1 already had a route to 30.30.30.0 via 20.20.20.2 and both Ubuntu hosts have correct directly-connected addresses and host routes (ubuntu1: 10.10.10.10/24, route to 30.30.30.0 via 10.10.10.1; ubuntu2: 30.30.30.30/24, route to 10.10.10.0 via 30.30.30.2), so inter-host connectivity should now be restored.
Tokens used:
- completion_tokens: 847
- prompt_tokens: 4277
- total_tokens: 5124
The AI correctly identified that on cisco2 box was a bad static route. After approval, it removed the route and verified the routing table. Connectivity was restored.
Final Thoughts: AI in Network Operations
First and foremost: never run this on a production network unsupervised.
The approval prompt is a bare minimum safeguard. AI lacks historical context and institutional knowledge. Before I explicitly told it to ignore the ContainerLab’s management network, it repeatedly tried to “solve” problems by routing traffic over the OOB network. In a real environment, that could be catastrophic.
That said, the potential is undeniable.
For labs, testing, validation, and read-only inspection, this approach is already extremely useful. Even for configuration, with strong guardrails, it can accelerate routine work. Imagine some firewall rules migrations or config consolidation a system like this can help with.
This exercise is admittedly biased toward older, well-documented technologies (Cisco IOS, static routing, CCNA-level material). When I tested newer platforms—such as Aruba CX10K with Pensando and EVPN—the AI struggled, produced partially incorrect configurations, and ignored mandatory GUI-based steps.
So, are we there yet?
No.
Should we be afraid of losing network jobs?
First-line support roles, possibly.
Should we start treating AI as a serious tool for network automation and operations?
Absolutely.
Used carefully, AI can become a powerful assistant—just not an unsupervised one.
Possible next steps:
- Replace the containerLab source of topology with something more general, so that we can use this in production giving it our legacy documentation (like how cool would it be if we can give is some old MS Visio file to process to understand our network, right?)
- Replace with local LLM like DeepSeek to avoid secrets going to public AI LLM’s memory
- Extend with RAG to allow it to understand newer and less dominant NW vendors hardware that the public model like chatgpt will have trouble with by default. E.g. imagine compiling some “Aruba EVPN configuration guide” or “Broadcom NSX configuration guide” into a vector database for AI to use for managing these things.


