Почему CI/CD для AI-агентов — это не просто "еще один пайплайн"
Вы настраиваете агента на LangGraph или CrewAI. Он работает локально. Вы довольны. Потом пытаетесь задеплоить — и все ломается. Промпты ведут себя иначе, инструменты требуют других пермишенов, а версии моделей на продакшене отличаются от тех, что были в тестах.
Типичная история? Да. Решение — CI/CD пайплайн, который не просто копирует файлы, а понимает специфику AI-агентов. Сегодня разберем, как настроить автоматический деплой на Amazon Bedrock AgentCore через GitHub Actions с enterprise-безопасностью.
Ключевая проблема: большинство команд пытаются адаптировать под агентов стандартные MLOps-пайплайны. Это ошибка. Агенты — это не статические модели, а динамические системы с инструментами, промптами и графами принятия решений.
Архитектура: что на самом деле происходит при деплое агента
Представьте агента как трехслойный пирог:
- Слой 1: Конфигурация агента — промпты, инструкции, параметры модели (Claude 3.5 Sonnet, GPT-4o, Command R+ — на 20.01.2026 это самые актуальные модели в Bedrock)
- Слой 2: Инструменты и графы — LangGraph workflow, CrewAI задачи, кастомные инструменты (API-клиенты, базы данных)
- Слой 3: Инфраструктура — IAM роли, политики доступа, VPC конфигурация, мониторинг
CI/CD пайплайн должен обрабатывать все три слоя одновременно. Нельзя сначала задеплоить агента, а потом настраивать ему доступ к S3 — он сломается при первом же запуске.
1 Подготовка AWS: OIDC вместо статических ключей
Первая ошибка — хранение AWS credentials в секретах GitHub. Устаревший подход. На 20.01.2026 стандарт — OpenID Connect (OIDC). GitHub Actions аутентифицируется в AWS через временные токены.
# Создаем OIDC провайдер в AWS (делается один раз)
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
Почему OIDC? Безопасность. Токены живут минуты, а не годы. Нет риска утечки долгоживущих ключей. Least-privilege принцип из коробки.
2 Настройка IAM роли для пайплайна
Создаем роль с минимальными привилегиями. Не даем FullAccess ни к чему. Типичная ошибка — давать bedock:*, когда нужен только bedock:CreateAgent и bedock:UpdateAgent.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:CreateAgent",
"bedrock:UpdateAgent",
"bedrock:CreateAgentAlias",
"bedrock:ListAgents",
"bedrock:GetAgent"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::your-agent-configs-bucket/*"
}
]
}
Заметьте: нет bedrock:DeleteAgent. Пайплайн не должен удалять агентов в продакшене. Для cleanup используем отдельный процесс с ручным подтверждением.
3 Структура репозитория: где что лежит
Плохая структура:
/agents
/my-agent
agent.py
requirements.txt
README.md
# Где промпты? Где конфиги Bedrock? Где инструменты?
Хорошая структура:
/agents/my-agent
/bedrock-config
agent-definition.json # Конфиг агента для Bedrock
instruction.md # Системный промпт
alias-config.json # Алиасы версий
/tools
weather_tool.py # Кастомные инструменты
db_query_tool.py
tool-registry.json # Реестр инструментов
/workflows
langgraph-flow.json # LangGraph определение
crewai-tasks.yaml # CrewAI задачи
/tests
test_agent_integration.py
/infrastructure
iam-policy.json # IAM политика для агента
cloudwatch-alarms.yaml # Алерты
agent-version.txt # Версия агента (семвер)
deploy-manifest.yaml # Манифест деплоя
Каждый каталог — отдельный слой. Пайплайн обрабатывает их в правильном порядке: сначала инфраструктура, потом инструменты, потом агент.
GitHub Actions workflow: пошаговый разбор
Создаем .github/workflows/deploy-agent.yml:
name: Deploy AI Agent to Bedrock
on:
push:
branches: [ main ]
paths:
- 'agents/**'
- '.github/workflows/deploy-agent.yml'
permissions:
id-token: write # Критично для OIDC
contents: read
jobs:
validate-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
role-to-assume: arn:aws:iam::123456789012:role/github-actions-bedrock
role-session-name: GitHubActions-DeployAgent
- name: Validate Agent Configuration
run: |
python scripts/validate_agent.py \
--config agents/my-agent/bedrock-config/agent-definition.json \
--tools agents/my-agent/tools/tool-registry.json
echo "Validation passed"
- name: Upload Tools to S3
run: |
aws s3 sync agents/my-agent/tools/ \
s3://your-agent-tools-bucket/my-agent/v${GITHUB_SHA::7}/ \
--exclude "*.pyc" --exclude "__pycache__/*"
- name: Deploy Agent to Bedrock
run: |
# Читаем текущую версию
AGENT_VERSION=$(cat agents/my-agent/agent-version.txt)
# Создаем или обновляем агента
if aws bedrock list-agents --query "agentSummaries[?agentName=='my-agent']" --output text | grep -q my-agent; then
echo "Updating existing agent"
aws bedrock update-agent \
--agent-id $(aws bedrock list-agents --query "agentSummaries[?agentName=='my-agent'].agentId" --output text) \
--agent-name "my-agent" \
--instruction file://agents/my-agent/bedrock-config/instruction.md \
--foundation-model "anthropic.claude-3-5-sonnet-20241022"
else
echo "Creating new agent"
aws bedrock create-agent \
--agent-name "my-agent" \
--instruction file://agents/my-agent/bedrock-config/instruction.md \
--foundation-model "anthropic.claude-3-5-sonnet-20241022" \
--agent-resource-role-arn "arn:aws:iam::123456789012:role/my-agent-execution-role"
fi
- name: Create Agent Alias
run: |
AGENT_ID=$(aws bedrock list-agents --query "agentSummaries[?agentName=='my-agent'].agentId" --output text)
AGENT_VERSION=$(cat agents/my-agent/agent-version.txt)
aws bedrock create-agent-alias \
--agent-id $AGENT_ID \
--agent-alias-name "production" \
--description "Production alias for version ${AGENT_VERSION}"
- name: Run Integration Tests
run: |
python agents/my-agent/tests/test_agent_integration.py \
--agent-alias production \
--region us-east-1
- name: Notify on Failure
if: failure()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Agent deployment failed: ${context.workflow}`,
body: `Workflow run: ${context.runId}\nCommit: ${context.sha}`
})
Важный нюанс: обратите внимание на foundation-model. На 20.01.2026 в Bedrock доступны Claude 3.5 Sonnet (последняя версия), GPT-4o, Command R+, и новые модели от Amazon Titan. Всегда указывайте полный идентификатор модели, включая версию.
Особенности работы с LangGraph и CrewAI агентами
Если ваш агент использует LangGraph (а многие продвинутые агенты его используют), нужно сериализовать граф в формат, который понимает Bedrock.
Проблема: Bedrock AgentCore не запускает Python код напрямую. Решение: конвертировать LangGraph workflow в набор инструментов и промптов.
# scripts/convert_langgraph_to_bedrock.py
import json
from langgraph.graph import StateGraph
def convert_graph_to_bedrock_config(graph: StateGraph, output_path: str):
"""Конвертирует LangGraph граф в конфиг для Bedrock AgentCore"""
config = {
"agentName": "my-langgraph-agent",
"instruction": "Выполняй задачи используя следующий workflow...",
"tools": [],
"workflowDefinition": {
"nodes": [],
"edges": []
}
}
# Извлекаем узлы и связи из графа
# ... конверсионная логика ...
with open(output_path, 'w') as f:
json.dump(config, f, indent=2)
print(f"Конфиг сохранен в {output_path}")
Для CrewAI аналогично — преобразуем задачи и агентов в Bedrock-совместимый формат. Ключевой момент: сохраняем семантику workflow, даже если техническая реализация отличается.
Тестирование агентов в пайплайне: что и как проверять
Типичная ошибка — тестировать только деплой. «Агент создался? Отлично, работает». А потом в продакшене он не может вызвать инструмент из-за неправильных IAM пермишенов.
Многоуровневое тестирование:
- Валидация конфигурации — проверяем JSON-схемы, обязательные поля
- Юнит-тесты инструментов — каждый инструмент тестируем изолированно
- Интеграционные тесты — агент + инструменты + моки внешних сервисов
- End-to-end тесты — реальные вызовы Bedrock API (осторожно с costs!)
- Тесты на регрессию — сравниваем ответы с предыдущей версией
Пример интеграционного теста:
import boto3
import pytest
from datetime import datetime
@pytest.mark.integration
class TestAgentDeployment:
def test_agent_can_process_request(self):
"""Проверяем, что агент может обработать типичный запрос"""
bedrock = boto3.client('bedrock-agent-runtime', region_name='us-east-1')
response = bedrock.invoke_agent(
agentId='YOUR_AGENT_ID',
agentAliasId='production',
sessionId=f'test-session-{datetime.now().isoformat()}',
inputText='Какая погода в Москве?'
)
# Проверяем, что ответ содержит ожидаемую структуру
assert 'completion' in response
assert response['sessionState'] is not None
# Важно: не проверяем точный текст ответа (модель вариативна)
# Вместо этого проверяем, что агент вызвал нужный инструмент
tool_calls = extract_tool_calls(response)
assert any(t['name'] == 'get_weather' for t in tool_calls)
Мониторинг и откат: когда что-то пошло не так
Деплой прошел успешно. Через час получаете алерт: агент использует 100% квоты Bedrock. Что делать?
Во-первых, настройте мониторинг до деплоя:
# infrastructure/cloudwatch-alarms.yaml
Alarms:
- AlarmName: "Agent-High-Error-Rate"
MetricName: "InvocationErrors"
Namespace: "AWS/Bedrock"
Statistic: "Sum"
Period: 300
EvaluationPeriods: 2
Threshold: 10
ComparisonOperator: "GreaterThanThreshold"
Dimensions:
- Name: "AgentId"
Value: !Ref AgentId
- Name: "AgentAliasId"
Value: "production"
Во-вторых, реализуйте автоматический откат в пайплайне:
# В GitHub Actions workflow добавляем шаг
- name: Rollback if Errors Detected
if: always() # Выполняем даже если предыдущие шаги упали
run: |
# Проверяем метрики CloudWatch за последние 15 минут
ERROR_COUNT=$(aws cloudwatch get-metric-statistics \
--namespace AWS/Bedrock \
--metric-name InvocationErrors \
--dimensions Name=AgentId,Value=$AGENT_ID Name=AgentAliasId,Value=production \
--start-time $(date -u -d '15 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics Sum \
--query "Datapoints[0].Sum" \
--output text)
if [[ $ERROR_COUNT -gt 20 ]]; then
echo "High error rate detected. Rolling back..."
# Возвращаем предыдущий алиас
PREVIOUS_ALIAS=$(find_previous_alias $AGENT_ID)
aws bedrock update-agent-alias \
--agent-id $AGENT_ID \
--agent-alias-id production \
--routing-configuration "$PREVIOUS_ALIAS"
exit 1 # Падаем, чтобы остановить пайплайн
fi
Чего не хватает в этом гайде (но нужно знать)
1. Multi-region деплой — Bedrock доступен не во всех регионах. Нужна стратегия для глобальных приложений.
2. A/B тестирование агентов — как одновременно запускать две версии и сравнивать метрики.
3. Cost контроль — агенты могут сжечь бюджет быстрее, чем вы успеете получить алерт. Нужны лимиты на уровне агента.
4. Версионирование промптов — если меняете инструкцию агента, нужно сохранять старые версии для воспроизведения багов.
Последний совет: начните с простого пайплайна. Не пытайтесь сразу реализовать все best practices. Сначала автоматизируйте деплой, потом добавьте тесты, потом мониторинг. Как в том эксперименте с автономным AI-разработчиком — итеративно улучшайте процесс.
Прогноз на 2026: CI/CD для AI-агентов станет стандартной практикой. Но следующий вызов — CI/CD для swarm-агентов (оркестровка множества взаимодействующих агентов). Готовьте инфраструктуру уже сейчас.