The Usage of AI in Network Operations - CI/CD with Cisco
As every vendor adds the AI sticker to their product lineup, day-to-day practicality of using these tools remains. Another important factor is the trust in the output.
Having a tool ‘build’ a configuration might seem appealing from the offset, but what if that time saved upfront is spent parsing and editing the configuration for errors and manually rectifying each one. Is that really saving time?
What if you shorten that phase of trust but verify and create an outage scenario? Was any time really saved?
That doesn’t mean these tools are useless and should be put aside for traditional methods of manually writing every configuration.
We’ll look at an example of using multiple models to ensure we perform the two main factors: Building the configuration & Verifying the configuration.
Why two models? Simply because we don’t want to be in a position of correcting our own homework. AI models are notorious for being confident even when they’re wrong. The onus is completely on the end user to perform the validation. However, one model can verify the work of another so we can shorten that time further.

Building the configuration
At the time of this article (Oct 2025), GitHub Copilot would be an ideal candidate for building the configuration.
Why? Two main factors:
Familiarity – YAML/Ansible will feel like home for anyone in NetOPS and will give them the confidence to quickly parse the output for accuracy
Template repository – Having everything in a central repository makes workflows easier to build and distribute to other members of the team

Verifying the Configuration
Now that we have built the configuration, how do we know it’s valid? How do we ensure our syntax matches up to what we need it do?
Now we need to use a couple of different tools to bounce the configuration against. Why multiple tools? Simply because more than one set of eyes has a higher probability to discover potential issues.
pyATS/Genie parsing - This will help us test the configuration for syntax accuracy in Cisco’s database
Batfish - This tool helps us perform offline network intent validation. We need a way to understand to the output matches our goal. Batfish helps with that
Using a combination of tools, we can not only speed up our configuration time and scale well beyond any manual approach, but we can also validate the test within the same container before moving to production.
Conclusion / Summary
With most things in this area, the best way to learn is to start playing with the tools available. Since you don’t require hardware or expensive labs to test your configurations and designs, you can work on an exploratory and almost trial and error method.
We’ll leave you with an example of a workflow of a BGP neighbour configuration going through the tools above, so you can visualize and use it as a baseline to build configurations of your own. Feel free to use this example as you wish.
For additional information on this topic, or for assistance with something specific please reach out to us directly.
Example Workflow
Repo Structure
.Bash
├── ansible/
│ ├── templates/
│ │ └── bgp.j2
│ ├── playbooks/
│ │ └── edge_bgp.yml
├── configs/
│ ├── candidate/
│ │ └── edge_bgp.cfg # generated config candidate
│ └── golden/
│ └── edge_bgp.cfg # known-good reference
├── tests/
│ ├── intents/
│ │ └── reachability.yml # Batfish intent checks
│ ├── pyats/
│ │ └── test_bgp.py # pyATS/Genie test cases
├── .github/
│ └── workflows/
│ └── validate.yml # GitHub Actions pipeline
GitHub Workflow:
name: Validate Cisco Configs
on:
pull_request:
push:
branches: [ main ]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
pip install pyats[full] genie batfish pybatfish ansible
# 1. Lint templates / playbooks
- name: Lint Ansible playbooks
run: ansible-lint ansible/playbooks/
# 2. Parse candidate configs with pyATS
- name: Validate configs with pyATS
run: |
pyats parse "configs/candidate/*.cfg" --output parsed/
# Example: check if parsing succeeded
if [ ! -s parsed/ ]; then
echo "Parsing failed!"
exit 1
fi
# 3. Run Batfish analysis for intent verification
- name: Run Batfish
run: |
pybatfish-config init-snapshot configs/candidate --network testNet --snapshot pr${{ github.run_id }}
pybatfish-assert --tests tests/intents/reachability.yml
# 4. Run pyATS functional tests (optional lab/sandbox)
- name: Run pyATS tests
run: |
pyats run job tests/pyats/test_bgp.py
pyATS review:
from pyats.aetest import Testcase, test
from genie.testbed import load
testbed = load("testbed.yaml") # defines CSR1kv/NX-OSv sandbox
class BGPTest(Testcase):
@test
def check_bgp_neighbors(self, steps):
device = testbed.devices["edge-router"]
device.connect()
output = device.parse("show ip bgp summary")
assert "Established" in str(output), "No established BGP sessions"
Batfish Intent Validation:
tests:
- name: Verify reachability to Internet via edge
type: reachability
parameters:
source: "10.1.1.0/24"
destination: "8.8.8.8"
action: permit
