Интеграция Amazon Bedrock AgentCore со Slack: полный гайд на 2026 | AiManual
AiManual Logo Ai / Manual.
23 Мар 2026 Гайд

Пошаговый гайд: интеграция Amazon Bedrock AgentCore со Slack для бизнес-агентов

Подробная инструкция по подключению AI-агента из Bedrock AgentCore к Slack с использованием AWS CDK и Lambda. Разбор ошибок и лучшие практики.

Почему каждый второй агент в Slack сходит с ума (и как этого избежать)

Вы видели это: коллега добавляет в общий чат "умного помощника". Первые два вопроса он отрабатывает блестяще. На третий — начинает цитировать внутренний wiki, на пятый — путает контекст и предлагает уволить тимлида. К седьмому сообщению чат превращается в цифровую помойку.

Проблема не в модели. Проблема в мосте между ней и Slack. Этот мост часто строят на скорую руку: вебхук, пара строк кода, надежда на лучшее. Контекст теряется, безопасность — на уровне "ну вроде работает", управление состояниями — в лучшем случае через глобальную переменную. Результат — агент-шизофреник, которого стыдно показывать клиентам.

Решение — не просто "отправить запрос в API". Нужна архитектура. Та, что держит контекст диалога, проверяет права доступа, обрабатывает таймауты и умеет сказать "я не знаю". Сегодня мы построим её на Amazon Bedrock AgentCore и AWS CDK. Это не quickstart, который сломается через неделю. Это production-решение, которое я выстрадал на трёх проектах.

💡
Контекст 2026: Bedrock AgentCore к этому моменту обзавелся встроенной поддержкой долгой памяти (Long-Term Memory) и нативными инструментами для работы с внешними API. Мы будем использовать самую свежую версию на март 2026 года. Если вы читаете это позже — проверьте, не добавили ли в AgentCore готовый Slack-коннектор (но я бы не надеялся).

1 Готовим площадку: Slack App и AWS аккаунт

Сначала забудьте про код. Настройте стороны диалога. В Slack это означает создание приложения с правильными scope и вебхуками. В AWS — создание IAM-роли, которая не будет иметь прав на весь интернет.

В Slack: создаем App с Event Subscription

  1. Идите на api.slack.com/apps и жмите "Create New App". Выбирайте "From scratch".
  2. В "Basic Information" добавьте app_mentions:read, chat:write, и im:history в OAuth & Permissions -> Scopes.
  3. Перейдите в "Event Subscriptions". Включите их. В "Request URL" пока введите любой URL (например, https://example.com). Мы обновим его позже, после развертывания API Gateway.
  4. В "Subscribe to bot events" добавьте app_mention. Это даст боту слушать сообщения, где его упомянули.
  5. Установите приложение в workspace (OAuth & Permissions -> Install App). Сохраните Bot User OAuth Token и Signing Secret. Они понадобятся Lambda.

Первая ловушка: Не берите все scope подряд "на всякий случай". Каждый лишний scope — дыра в безопасности и лишние вопросы при утверждении приложения. Берите минимум. Если позже нужно больше — добавите.

В AWS: готовим IAM политику для агента

Агент в Bedrock должен уметь вызывать свои инструменты (Actions) и, возможно, писать в CloudWatch для логирования. Создайте политику вручную через IAM Console или сразу опишите её в CDK-коде. Пример минимальной политики:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "bedrock:InvokeModel",
                "bedrock:InvokeAgent",
                "bedrock:RetrieveAndGenerate"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        }
    ]
}

Запоминайте: политика для агента и политика для Lambda, которая будет вызывать агента, — это две разные сущности. Не смешивайте.

2 Лепим агента в Bedrock: не просто кнопки нажать

Теперь создадим самого агента. Если вы раньше не работали с AgentCore, посмотрите мой гайд про полный стек для агентов на Amazon Bedrock. Там основы. Здесь — кратко и по делу.

  1. В консоли AWS найдите "Bedrock" -> "AgentCore".
  2. "Create agent". Выберите последнюю доступную модель (на март 2026 это, скорее всего, Claude 3.7 Sonnet или что-то мощнее).
  3. В "Instructions" пропишите роль агента. Например: "Ты — помощник в Slack-чате компании. Отвечай кратко, по делу. Если не уверен в ответе, уточни. Не придумывай информацию о внутренних процессах, которых нет в предоставленных данных."
  4. Здесь же, в разделе "Knowledge Bases", привяжите базу знаний, если она есть. Без неё агент будет работать только на общей эрудиции модели.
  5. В "Action Groups" определите инструменты, которые может использовать агент. Например, для интеграции с Salesforce или Redshift.
  6. Сохраните агента. Запишите его Agent ID и Agent Alias ID. Они понадобятся для вызова из Lambda.
💡
Про базу знаний: Если у вас нет готовой, но есть документы в Notion или Confluence, используйте встроенные коннекторы Bedrock. Это тема для отдельной статьи, но суть в том, что без базы знаний ваш агент будет безоружен в вопросах специфики компании.

3 Lambda-функция: мозг, который всё соединит

Эта функция — сердце интеграции. Она получает события от Slack, проверяет подпись, дергает агента в Bedrock, форматирует ответ и отправляет его обратно в чат. Пишем на Python 3.12 (самая свежая LTS на 2026 год).

Вот скелет функции. Полный код я выложу в конце, а пока разберем ключевые части.

import os
import json
import hmac
import hashlib
import time
import boto3
from botocore.exceptions import ClientError
from typing import Dict, Any

# Инициализация клиентов
def get_bedrock_agent_client():
    return boto3.client('bedrock-agent-runtime', region_name='us-east-1')

def lambda_handler(event: Dict[str, Any], context) -> Dict[str, Any]:
    # 1. Верификация подписи от Slack
    slack_signing_secret = os.environ['SLACK_SIGNING_SECRET'].encode('utf-8')
    request_body = event.get('body', '{}')
    timestamp = event['headers'].get('x-slack-request-timestamp', '')
    
    if abs(time.time() - int(timestamp)) > 60 * 5:
        return {'statusCode': 403, 'body': 'Request timeout'}
    
    sig_basestring = f'v0:{timestamp}:{request_body}'.encode('utf-8')
    my_signature = 'v0=' + hmac.new(slack_signing_secret, sig_basestring, hashlib.sha256).hexdigest()
    slack_signature = event['headers'].get('x-slack-signature', '')
    
    if not hmac.compare_digest(my_signature, slack_signature):
        return {'statusCode': 403, 'body': 'Invalid signature'}
    
    # 2. Парсим событие от Slack
    body = json.loads(request_body)
    if body.get('type') == 'url_verification':
        return {'statusCode': 200, 'body': body.get('challenge')}
    
    # 3. Извлекаем текст сообщения, где упомянули бота
    event_data = body.get('event', {})
    if event_data.get('type') != 'app_mention':
        return {'statusCode': 200, 'body': 'Not an app_mention event'}
    
    user_text = event_data.get('text', '').replace('<@UXXXBOTID>', '').strip()
    channel_id = event_data.get('channel')
    
    # 4. Вызываем агента Bedrock
    try:
        agent_client = get_bedrock_agent_client()
        response = agent_client.invoke_agent(
            agentId=os.environ['AGENT_ID'],
            agentAliasId=os.environ['AGENT_ALIAS_ID'],
            sessionId=channel_id,  # Используем ID канала как сессию
            inputText=user_text,
        )
        
        # 5. Собираем потоковый ответ от агента
        completion = ""
        for event in response.get('completion', []):
            chunk = event.get('chunk', {})
            completion += chunk.get('bytes', b'').decode('utf-8')
        
    except ClientError as e:
        completion = f"Ошибка при обращении к агенту: {str(e)}"
    
    # 6. Отправляем ответ обратно в Slack
    slack_token = os.environ['SLACK_BOT_TOKEN']
    # ... (код для вызова chat.postMessage)
    
    return {'statusCode': 200, 'body': 'OK'}

Обратите внимание на sessionId=channel_id. Это хак, который позволяет агенту хранить контекст в пределах одного канала. Bedrock AgentCore автоматически управляет состоянием сессии. Если хотите персональный контекст для каждого пользователя, используйте user_id вместо channel_id.

Вторая ловушка: Не храните токены и секреты в коде. Используйте Environment Variables Lambda или, лучше, AWS Secrets Manager. В CDK-шаблоне ниже я покажу, как их безопасно внедрить.

4 API Gateway: дверь, в которую стучится Slack

Slack будет отправлять события на публичный URL. Мы создадим HTTP API Gateway, который проксирует запросы в нашу Lambda. Это просто, но есть деталь: Slack требует ответ на challenge при верификации URL.

Мы уже обработали это в Lambda (блок url_verification). В CDK мы создадим API с одним POST-методом, привязанным к нашей функции.

# Фрагмент CDK-кода для API Gateway
from aws_cdk import (
    aws_apigatewayv2 as apigw,
    aws_apigatewayv2_integrations as integrations,
)

# ...

slack_integration = integrations.HttpLambdaIntegration(
    "SlackIntegration",
    handler=slack_lambda
)

api = apigw.HttpApi(self, "SlackAgentApi",
    default_integration=slack_integration
)

# Выведем URL, чтобы скопировать его в настройки Slack
CfnOutput(self, "ApiEndpoint", value=api.url)

После развертывания CDK вы получите URL типа https://xxx.execute-api.region.amazonaws.com. Вот его нужно вставить в настройки Slack App в "Event Subscriptions -> Request URL". Slack сразу проверит его и скажет "Verified".

5 CDK: развернуть всё одной командой

Теперь соберем все компоненты в один CDK-стек. Я использую TypeScript, но вы можете адаптировать под Python. Основные моменты:

// lib/slack-agent-stack.ts - основные части
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigw from 'aws-cdk-lib/aws-apigatewayv2';
import * as secrets from 'aws-cdk-lib/aws-secretsmanager';

export class SlackAgentStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Секреты из Secrets Manager (создайте заранее)
    const slackSecrets = secrets.Secret.fromSecretNameV2(this, 'SlackSecrets', 'slack/credentials');
    const bedrockAgentSecrets = secrets.Secret.fromSecretNameV2(this, 'BedrockAgentSecrets', 'bedrock/agent');

    // Lambda функция
    const slackHandler = new lambda.Function(this, 'SlackAgentHandler', {
      runtime: lambda.Runtime.PYTHON_3_12,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'slack_handler.handler',
      timeout: cdk.Duration.seconds(30),
      memorySize: 256,
      environment: {
        SLACK_SIGNING_SECRET: slackSecrets.secretValueFromJson('signing_secret').unsafeUnwrap(),
        SLACK_BOT_TOKEN: slackSecrets.secretValueFromJson('bot_token').unsafeUnwrap(),
        AGENT_ID: bedrockAgentSecrets.secretValueFromJson('agent_id').unsafeUnwrap(),
        AGENT_ALIAS_ID: bedrockAgentSecrets.secretValueFromJson('agent_alias_id').unsafeUnwrap(),
      },
    });

    // Даем Lambda право читать секреты и вызывать Bedrock
    slackSecrets.grantRead(slackHandler);
    bedrockAgentSecrets.grantRead(slackHandler);
    slackHandler.addToRolePolicy(new iam.PolicyStatement({
      actions: ['bedrock:InvokeAgent', 'bedrock:InvokeModel'],
      resources: ['*'],
    }));

    // HTTP API Gateway
    const api = new apigw.HttpApi(this, 'SlackAgentApi', {
      defaultIntegration: new integrations.HttpLambdaIntegration('SlackIntegration', slackHandler),
    });

    new cdk.CfnOutput(this, 'ApiEndpoint', { value: api.url! });
  }
}

Развертывание: cdk deploy. После успеха скопируйте вывод ApiEndpoint и обновите URL в настройках Slack App. Всё, интеграция жива.

💡
Если CDK для вас новинка, посмотрите мой гайд про CI/CD для AI-агентов. Там я подробно разбираю, как автоматизировать развертывание таких стеков через GitHub Actions.

Где собака зарыта: ошибки, которые съедят ваше время

Ошибка Почему происходит Как исправить
"Invalid signature" от Slack Lambda получает тело запроса в формате строки, а не JSON. Проверка подписи использует сырую строку, но API Gateway может её модифицировать. В настройках API Gateway отключите "Request validation" и убедитесь, что Lambda получает тело как строку (в событии body).
Агент не отвечает, таймаут Lambda Bedrock AgentCore может думать больше 30 секунд, особенно с большими контекстами. Стандартный таймаут Lambda — 3 секунды. Увеличьте таймаут Lambda до 30-60 секунд. И настройте в Slack задержку ответа (используйте response_url для асинхронного ответа).
Контекст сбрасывается между сообщениями Вы используете случайный sessionId или не сохраняете его между вызовами. Используйте стабильный идентификатор (например, ID канала Slack) как sessionId. Bedrock сам хранит историю сессии до 24 часов.
Агент не использует базу знаний База знаний не привязана к агенту или у неё нет прав на чтение. В консоли Bedrock проверьте, что агенту назначена Knowledge Base и у его IAM-роли есть bedrock:Retrieve права на её индекс.

Частые вопросы от тех, кто уже обжёгся

Можно ли использовать не app_mention, а все сообщения в канале?

Можно, но не нужно. Подписка на все сообщения (message.channels) создаст лавину событий и счёт от AWS. Бот будет пытаться отвечать на каждый пост. Используйте app_mention или, в крайнем случае, реагируйте только на сообщения с определёнными ключевыми словами.

Как сделать, чтобы бот отвечал в треде, а не в общем чате?

В API Slack есть параметр thread_ts. При отправке ответа через chat.postMessage передавайте thread_ts: event_data.get('thread_ts') || event_data.get('ts'). Это привяжет ответ к треду.

Bedrock AgentCore дорогой? Как контролировать стоимость?

Цена складывается из вызовов модели (per token) и хранения сессий. Контролируйте: 1) Установите максимальную длину ответа в агенте. 2) Очищайте сессии через 1 час, если не нужна долгая память. 3) Используйте более лёгкие модели (например, Claude 3 Haiku) для простых вопросов. Настройте маршрутизацию между моделями в зависимости от сложности.

А если я хочу, чтобы агент запускал workflows в Slack (например, создавал тикет)?

Опишите это как Action в агенте. Action будет вызывать другую Lambda, которая через Slack API создаст тикет в Jira или запустит workflow через интеграцию с Notion. Только дайте агенту чёткие инструкции, когда этот Action использовать.

Финальный совет: Первый запуск — всегда в отдельном тестовом канале с парой доверенных коллег. Дайте им инструкцию: "Если бот начинает нести чушь, пишите @bot reset". Реализуйте эту команду в Lambda — она будет очищать сессию. Это спасёт репутацию вашего проекта, пока вы отлаживаете prompt'ы.

Интеграция готова. Ваш агент теперь не просто игрушка в консоли AWS, а полноправный участник рабочих чатов. Он помнит контекст, не болтает лишнего и умеет вызывать реальные инструменты. Осталось самое сложное — убедить коллег, что это не шпион от руководства.

Подписаться на канал