Design multi-agent deployment pipelines
GitHub Actions coordinates multi-agent deployments by modeling each agent as a dependent job in a shared workflow. Where single-agent CI/CD follows a linear path—test, build, deploy—multi-agent systems require a dependency graph that enforces deployment order and validates contract compatibility before any agent reaches production. Each agent's pipeline connects to the others through explicit dependency declarations and automated contract tests.
| Deployment Aspect | Single Agent | Multi-Agent System |
|---|---|---|
| Pipeline structure | Linear test → build → deploy | Dependency graph with coordinated stages |
| Version management | Single version tag | Version matrix across agents |
| Integration testing | Agent + external services | Agent + dependent agents |
| Rollback scope | One component | Coordinated multi-component rollback |
Model agent dependencies as a deployment graph
The first step in coordinated deployment is understanding which agents depend on which other agents. In Fabrikam's code review system, the orchestrator agent depends on all specialist agents because it calls their tool interfaces. The reporting agent depends on the orchestrator because it consumes the orchestrator's structured output. The security scanner and style checker don't depend on each other—they work in parallel.
You model these relationships as a directed acyclic graph (DAG). Each node represents an agent, and each edge represents a dependency relationship. Agent A depends on Agent B means that Agent A calls Agent B's tools or consumes Agent B's output schema. If Agent B changes its tool schema, Agent A might break unless it's compatible with the change.
Express this dependency graph in a configuration file that your CI/CD system can parse. Here's an example dependency manifest for Fabrikam's system:
# agent-dependencies.yml
agents:
- name: ingestion
depends_on: []
- name: syntax-analyzer
depends_on: [ingestion]
- name: style-checker
depends_on: [ingestion]
- name: security-scanner
depends_on: [ingestion]
- name: performance-profiler
depends_on: [syntax-analyzer]
- name: orchestrator
depends_on: [syntax-analyzer, style-checker, security-scanner, performance-profiler]
- name: reporting
depends_on: [orchestrator]
The manifest enforces deployment order: you can't deploy the orchestrator before the agents it depends on, unless you've verified backward compatibility.
Validate version compatibility before deployment
Before deploying Agent B version 2.0, check that all agents depending on Agent B can still function with the new version. This requires contract testing: comparing the API contract that Agent B v2.0 exposes against the contracts that dependent agents currently expect.
Contract testing for agents focuses on tool schemas. When Agent A calls Agent B using the Microsoft Foundry Agents service, it expects specific tool input parameters and output structures. If Agent B v2.0 adds a required parameter to an existing tool, Agent A breaks unless it also updates to send that parameter.
Implement contract validation as a GitHub Actions job that runs before any deployment:
# .github/workflows/validate-compatibility.yml
name: Agent Compatibility Validation
on:
pull_request:
paths:
- 'agents/**'
jobs:
validate-contracts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Extract tool schemas from updated agents
run: |
python scripts/extract_agent_schemas.py \
--agent-path agents/ \
--output contracts/current.json
- name: Compare against baseline contracts
run: |
python scripts/validate_compatibility.py \
--baseline contracts/baseline.json \
--current contracts/current.json \
--dependency-graph agent-dependencies.yml
- name: Check for breaking changes
run: |
if [ -f contracts/breaking-changes.txt ]; then
echo "Breaking changes detected:"
cat contracts/breaking-changes.txt
exit 1
fi
The validation script loads the dependency graph, identifies which agents depend on the modified agent, and checks whether the tool schema changes are backward compatible. Adding optional parameters is safe. Changing required parameter types or removing tools are breaking changes that require coordinated updates.
Order deployments based on dependency graph
When deploying a set of related agent updates, order matters. If Agent A depends on Agent B, and both are being updated, you must deploy Agent B first. Otherwise, Agent A tries to call the new tool interface before Agent B exposes it.
Implement deployment ordering using GitHub Actions job dependencies with the needs keyword. Build the deployment DAG directly from your dependency manifest:
# .github/workflows/deploy-agents.yml
name: Deploy Multi-Agent System
on:
workflow_dispatch:
inputs:
environment:
type: choice
options: [staging, production]
required: true
jobs:
deploy-ingestion:
runs-on: ubuntu-latest
steps:
- name: Deploy ingestion agent
run: |
az containerapp update \
--name ingestion-agent \
--resource-group fabrikam-${{ inputs.environment }} \
--image fabrikam.azurecr.io/ingestion:${{ github.sha }}
deploy-syntax-analyzer:
needs: [deploy-ingestion]
runs-on: ubuntu-latest
steps:
- name: Deploy syntax analyzer agent
run: |
az containerapp update \
--name syntax-agent \
--resource-group fabrikam-${{ inputs.environment }} \
--image fabrikam.azurecr.io/syntax-analyzer:${{ github.sha }}
deploy-style-checker:
needs: [deploy-ingestion]
runs-on: ubuntu-latest
steps:
- name: Deploy style checker agent
run: |
az containerapp update \
--name style-agent \
--resource-group fabrikam-${{ inputs.environment }} \
--image fabrikam.azurecr.io/style-checker:${{ github.sha }}
deploy-orchestrator:
needs: [deploy-syntax-analyzer, deploy-style-checker]
runs-on: ubuntu-latest
steps:
- name: Deploy orchestrator agent
run: |
az containerapp update \
--name orchestrator-agent \
--resource-group fabrikam-${{ inputs.environment }} \
--image fabrikam.azurecr.io/orchestrator:${{ github.sha }}
The ingestion agent deploys first because it has no dependencies. The syntax analyzer and style checker then deploy in parallel, and the orchestrator waits until both finish. GitHub Actions ensures no job runs until its prerequisites succeed.
For complex dependency graphs with many agents, generate the workflow YAML programmatically from the dependency manifest rather than maintaining it manually.
Test contracts between dependent agents
Contract tests verify that Agent B's new version produces outputs that Agent A can consume. Unlike unit tests that validate individual agent behavior, contract tests validate the integration boundary between two agents.
Implement contract testing using the Pact framework or custom schema validation. For Microsoft Foundry agents, the contract is the tool schema plus the JSON structure of tool responses. A contract test for the orchestrator calling the style checker looks like this:
# tests/contracts/test_style_checker_contract.py
import json
from azure.ai.agents import AgentsClient
from azure.identity import DefaultAzureCredential
def test_style_checker_returns_expected_schema():
"""Verify style checker tool output matches orchestrator expectations."""
# Initialize agents
agents_client = AgentsClient(
endpoint=os.environ["PROJECT_ENDPOINT"],
credential=DefaultAzureCredential(),
)
style_agent = agents_client.get_agent("style-checker-v2.0")
# Execute tool call with sample input
thread = agents_client.threads.create()
agents_client.messages.create(
thread_id=thread.id,
role="user",
content=json.dumps({
"code_file": "sample.py",
"style_guide": "pep8"
})
)
run = agents_client.runs.create_and_process(thread_id=thread.id, agent_id=style_agent.id)
messages = list(agents_client.messages.list(thread_id=thread.id))
# Validate response structure matches contract
result = json.loads(messages[0].text_messages[0].text.value)
assert "violations" in result, "Missing required field: violations"
assert isinstance(result["violations"], list), "Violations must be a list"
if result["violations"]:
violation = result["violations"][0]
assert "line" in violation, "Missing field: line"
assert "rule" in violation, "Missing field: rule"
assert "severity" in violation, "Missing field: severity"
assert violation["severity"] in ["error", "warning", "info"], \
"Invalid severity value"
Run these contract tests in your validation job before deploying any agent changes. If a contract test fails, the deployment pipeline stops, preventing the incompatible version from reaching production.
Key takeaways
- Dependency graphs model which agents depend on which, defining deployment order constraints as a directed acyclic graph (DAG).
- Contract testing validates that updated agents maintain compatible tool schemas before deployment proceeds.
- Ordered deployments use GitHub Actions
needskeyword to deploy agents in dependency-graph order automatically. - Compatibility validation catches breaking changes—like new required parameters or removed tools—before they reach production.