Библиотека · Ассистенты и боты в мессенджерах

Microsoft 365 + Claude — полная интеграция

Строитель90 минОбновлено: октябрь 2026
59 из 105 в библиотеке

Время: ~30 мин теории + 60 мин практики


Суть урока

Корпоративный клиент живёт в Microsoft. Teams вместо Slack, SharePoint вместо Google Drive, Outlook вместо Gmail, Power Automate вместо Zapier. Если ты хочешь продавать AI в корпорации — учишь язык Microsoft. Это не сложнее обычного, просто другой диалект.

🎨 Образ: Ты отлично говоришь по-русски. Твой клиент живёт в Испании. Продукт тот же — просто нужно объяснить его на испанском. Microsoft 365 — это корпоративный испанский.


Ключевые концепции

  • Microsoft Graph API — единая точка входа ко всем данным Microsoft 365
  • Вебхуки Teams (приложение Workflows) — Claude отправляет уведомления в Teams без бота
  • Office интеграция — Word, Excel, PowerPoint через Python-библиотеки
  • Power Platform — Power Automate + Claude без кода
  • Azure и Microsoft Foundry — инфраструктура для корпоративного Claude
  • Microsoft 365 Agents SDK (раньше Bot Framework) — полноценный бот в Teams

Теория

Архитектура Microsoft 365

Код
Microsoft 365 экосистема
├── Коммуникации: Teams, Outlook
├── Документы: Word, Excel, PowerPoint, OneNote
├── Хранилище: SharePoint, OneDrive
├── Автоматизация: Power Automate, Power Apps
├── Данные: Power BI, Dataverse
└── Инфраструктура: Azure, Active Directory

Microsoft Graph API — это один API который даёт доступ ко всему. Один токен, одна точка входа.

Код
https://graph.microsoft.com/v1.0/
├── /me                        → данные текущего пользователя
├── /users/{id}/messages       → Outlook письма
├── /teams/{id}/channels       → Teams каналы
├── /sites/{id}/drives         → SharePoint файлы
└── /me/calendar/events        → Calendar события

Microsoft Teams + Claude

Способ 1: Incoming Webhook (самый простой)

Webhook — это ссылка. Отправляешь POST запрос на эту ссылку — сообщение появляется в Teams канале. Никакого бота, никакой регистрации приложения.

⚠️ Старые вебхуки через Office 365 Connectors Microsoft выводит из эксплуатации, и создание новых скоро будет блокироваться. Вебхук теперь делают через приложение Workflows в Teams: оно построено на Power Automate.

Получить webhook:

  1. Teams → Канал → ... → Workflows
  2. Выбрать шаблон «Send webhook alerts to a channel», настроить параметры и нажать Save
  3. Скопировать ссылку вебхука (названия пунктов меню Teams меняются: актуальные шаги в документации Microsoft Learn)

Ограничения: сообщение не больше 28 КБ, а если запросов больше четырёх в секунду, Teams притормаживает соединение. Workflow привязан к своему владельцу: если он уйдёт из организации, вебхук останется без владельца, поэтому добавь соавторов.

Базовая отправка:

python
import os
import requests

def notify_teams(webhook_url: str, message: str):
    """Простое текстовое сообщение в Teams."""
    payload = {"text": message}
    response = requests.post(webhook_url, json=payload)
    return response.status_code in (200, 202)

# Пример
notify_teams(
    webhook_url=os.environ["TEAMS_WEBHOOK_URL"],
    message="✅ Отчёт за неделю готов. Claude проанализировал 1,247 транзакций."
)

Адаптивные карточки (богатый формат):

Вебхук Workflows принимает Adaptive Card. Старый формат MessageCard с кнопками он не отображает, поэтому кнопки делают через Action.OpenUrl. Проверь, как карточка выглядит в твоём канале.

python
import os
import json
import requests
import anthropic
from datetime import datetime

def notify_teams_rich(webhook_url: str, title: str, facts: dict, actions: list = None):
    """
    Адаптивная карточка с таблицей фактов и кнопками.
    facts = {"Ключ": "Значение", ...}
    actions = [{"title": "Открыть", "url": "https://..."}]
    """
    card = {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "type": "AdaptiveCard",
        "version": "1.2",
        "body": [
            {"type": "TextBlock", "text": title, "weight": "Bolder", "size": "Medium", "wrap": True},
            {"type": "TextBlock", "text": f"Сгенерировано: {datetime.now().strftime('%d.%m.%Y %H:%M')}",
             "isSubtle": True, "wrap": True},
            {"type": "FactSet", "facts": [{"title": k, "value": v} for k, v in facts.items()]}
        ]
    }

    if actions:
        card["actions"] = [
            {"type": "Action.OpenUrl", "title": a["title"], "url": a["url"]} for a in actions
        ]

    payload = {
        "type": "message",
        "attachments": [{
            "contentType": "application/vnd.microsoft.card.adaptive",
            "content": card
        }]
    }
    requests.post(webhook_url, json=payload)

# Claude анализирует данные → отправляет в Teams
def weekly_sales_report():
    data = get_weekly_sales()
    
    client = anthropic.Anthropic()
    analysis = "".join(b.text for b in client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=300,
        messages=[{
            "role": "user",
            "content": f"Кратко проанализируй: продажи {data['total']}, новые клиенты {data['new_clients']}, лучший продукт: {data['top_product']}"
        }]
    ).content if b.type == "text")
    
    notify_teams_rich(
        webhook_url=os.environ["TEAMS_WEBHOOK_URL"],
        title="📊 Еженедельный отчёт продаж",
        facts={
            "Выручка": f"${data['total']:,}",
            "Новые клиенты": str(data['new_clients']),
            "Топ продукт": data['top_product'],
            "AI-анализ": analysis[:200]
        },
        actions=[{"title": "Полный отчёт", "url": "https://dashboard.company.com"}]
    )

Способ 2: AI-бот в Teams (полноценный)

Настоящий бот который отвечает на сообщения в Teams. Старый Bot Framework SDK Microsoft заменяет на Microsoft 365 Agents SDK: для него есть руководство по миграции, а новые боты разумно начинать сразу на нём (есть ещё Teams SDK). Ниже вариант на Agents SDK для Python.

python
# bot.py — бот для Teams на Microsoft 365 Agents SDK (нужен Python 3.10+)
# pip install microsoft-agents-hosting-core microsoft-agents-hosting-aiohttp \
#             microsoft-agents-hosting-teams microsoft-agents-authentication-msal anthropic
#
# AGENT_APP (AgentApplication) создаётся по документации Agents SDK:
# CloudAdapter, MsalAuth.from_environment(), хранилище состояния.
from microsoft_agents.hosting.core import AgentApplication, TurnState, TurnContext
import anthropic

claude = anthropic.AsyncAnthropic()
conversations = {}  # История по conversation_id (в продакшне — база или Redis)

@AGENT_APP.activity("message")
async def on_message(context: TurnContext, _state: TurnState):
    user_message = context.activity.text
    conversation_id = context.activity.conversation.id

    # Загрузить историю разговора
    history = conversations.get(conversation_id, [])
    history.append({"role": "user", "content": user_message})

    # Claude отвечает
    response = await claude.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1000,
        system="Ты корпоративный AI-ассистент компании. Отвечай кратко и по делу.",
        messages=history
    )

    reply = "".join(b.text for b in response.content if b.type == "text")
    history.append({"role": "assistant", "content": reply})

    # Сохранить историю (только последние 20 сообщений)
    conversations[conversation_id] = history[-20:]

    await context.send_activity(reply)

Регистрация бота в Azure:

  1. portal.azure.com → Bot Services → Create
  2. Выбрать "Azure Bot"
  3. Получить App ID и App Password
  4. Настроить Teams Channel
  5. Задеплоить через Azure App Service

Названия пунктов портала Azure меняются, актуальные шаги смотри в документации Microsoft 365 Agents SDK.

Microsoft Office + Claude

Word: генерация документов

python
import json
from datetime import datetime
from docx import Document
from docx.shared import Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
import anthropic

def generate_word_report(topic: str, data: dict, output_path: str):
    """Claude пишет контент → python-docx создаёт документ."""
    client = anthropic.Anthropic()
    
    # Claude генерирует структурированный контент
    content_response = "".join(b.text for b in client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=3000,
        messages=[{
            "role": "user",
            "content": f"""
            Напиши деловой отчёт на тему: {topic}
            
            Данные для включения:
            {json.dumps(data, ensure_ascii=False, indent=2)}
            
            Формат (строго):
            ЗАГОЛОВОК: [название]
            РЕЗЮМЕ: [3-4 предложения]
            РАЗДЕЛ1: [название]
            [текст раздела]
            РАЗДЕЛ2: [название]  
            [текст раздела]
            ВЫВОДЫ: [2-3 пункта]
            """
        }]
    ).content if b.type == "text")
    
    # Парсим и создаём Word документ
    doc = Document()
    
    # Стили
    style = doc.styles['Normal']
    style.font.name = 'Arial'
    style.font.size = Pt(11)
    
    lines = content_response.split('\n')
    for line in lines:
        if line.startswith('ЗАГОЛОВОК:'):
            title = doc.add_heading(line.replace('ЗАГОЛОВОК:', '').strip(), 0)
            title.alignment = WD_ALIGN_PARAGRAPH.CENTER
        
        elif line.startswith('РЕЗЮМЕ:'):
            p = doc.add_paragraph()
            run = p.add_run(line.replace('РЕЗЮМЕ:', '').strip())
            run.italic = True
            p.paragraph_format.space_after = Pt(12)
        
        elif line.startswith('РАЗДЕЛ'):
            section_title = line.split(':', 1)[1].strip() if ':' in line else line
            doc.add_heading(section_title, level=1)
        
        elif line.startswith('ВЫВОДЫ:'):
            doc.add_heading('Выводы', level=1)
        
        elif line.strip() and not any(line.startswith(k) for k in ['ЗАГОЛОВОК', 'РЕЗЮМЕ', 'РАЗДЕЛ', 'ВЫВОДЫ']):
            doc.add_paragraph(line.strip())
    
    # Добавить дату и подпись
    doc.add_page_break()
    doc.add_paragraph(f"Сгенерировано: {datetime.now().strftime('%d.%m.%Y')}")
    doc.add_paragraph("Подготовлено с использованием Claude AI")
    
    doc.save(output_path)
    return output_path

# Использование
generate_word_report(
    topic="Квартальный отчёт по продажам",
    data={"выручка": "100 000", "рост": "8%", "топ_регионы": ["Север", "Юг"]},  # условные данные
    output_path="sales_report.docx"
)

Excel: анализ данных через Claude

python
import json
import anthropic
import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.chart import BarChart, Reference

def analyze_excel_with_claude(excel_path: str) -> str:
    """Claude анализирует данные из Excel и возвращает insights."""
    wb = openpyxl.load_workbook(excel_path)
    ws = wb.active
    
    # Извлечь данные как текст
    data_rows = []
    headers = [cell.value for cell in ws[1]]
    
    for row in ws.iter_rows(min_row=2, values_only=True):
        if any(cell is not None for cell in row):
            data_rows.append(dict(zip(headers, row)))
    
    # Первые 50 строк для анализа
    sample = data_rows[:50]
    
    client = anthropic.Anthropic()
    analysis = "".join(b.text for b in client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1500,
        messages=[{
            "role": "user",
            "content": f"""
            Проанализируй данные из Excel:
            Колонки: {headers}
            Строк всего: {len(data_rows)}
            Первые записи: {json.dumps(sample[:10], ensure_ascii=False, default=str)}
            
            Дай:
            1. Краткое описание что в таблице
            2. Ключевые наблюдения (3-5 пунктов)
            3. Аномалии если есть
            4. Рекомендации
            """
        }]
    ).content if b.type == "text")
    
    return analysis

def generate_excel_report(data: list, output_path: str, title: str = "AI Report"):
    """Создать красивый Excel отчёт с данными и графиком."""
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Данные"
    
    # Заголовок
    ws.merge_cells('A1:E1')
    title_cell = ws['A1']
    title_cell.value = title
    title_cell.font = Font(bold=True, size=14, color="FFFFFF")
    title_cell.fill = PatternFill(start_color="0076D7", fill_type="solid")
    title_cell.alignment = Alignment(horizontal='center')
    
    # Заголовки колонок
    if data:
        headers = list(data[0].keys())
        for col, header in enumerate(headers, 1):
            cell = ws.cell(row=2, column=col, value=header)
            cell.font = Font(bold=True)
            cell.fill = PatternFill(start_color="E0E7FF", fill_type="solid")
    
    # Данные
    for row_idx, row_data in enumerate(data, 3):
        for col_idx, value in enumerate(row_data.values(), 1):
            ws.cell(row=row_idx, column=col_idx, value=value)
    
    wb.save(output_path)
    return output_path

PowerPoint: автоматические презентации

python
from datetime import datetime
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
import anthropic

def generate_pptx_from_claude(topic: str, key_points: list, output_path: str):
    """Claude создаёт контент → python-pptx строит презентацию."""
    client = anthropic.Anthropic()
    
    # Генерируем слайды
    slides_content = "".join(b.text for b in client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=2000,
        messages=[{
            "role": "user",
            "content": f"""
            Создай структуру презентации из 5 слайдов на тему: {topic}
            
            Ключевые тезисы: {', '.join(key_points)}
            
            Формат для каждого слайда:
            СЛАЙД N:
            ЗАГОЛОВОК: [название]
            ТЕЗИСЫ:
            - [тезис 1]
            - [тезис 2]
            - [тезис 3]
            ЗАМЕТКИ: [для спикера]
            ---
            """
        }]
    ).content if b.type == "text")
    
    prs = Presentation()
    prs.slide_width = Inches(13.33)
    prs.slide_height = Inches(7.5)
    
    # Титульный слайд
    slide = prs.slides.add_slide(prs.slide_layouts[0])
    slide.shapes.title.text = topic
    slide.placeholders[1].text = f"Подготовлено: {datetime.now().strftime('%d.%m.%Y')}"
    
    # Парсим и добавляем слайды
    current_slide_data = {}
    for line in slides_content.split('\n'):
        if line.startswith('СЛАЙД'):
            if current_slide_data.get('title'):
                _add_content_slide(prs, current_slide_data)
            current_slide_data = {'title': '', 'bullets': [], 'notes': ''}
        elif line.startswith('ЗАГОЛОВОК:'):
            current_slide_data['title'] = line.replace('ЗАГОЛОВОК:', '').strip()
        elif line.startswith('- '):
            current_slide_data['bullets'].append(line[2:].strip())
        elif line.startswith('ЗАМЕТКИ:'):
            current_slide_data['notes'] = line.replace('ЗАМЕТКИ:', '').strip()
    
    if current_slide_data.get('title'):
        _add_content_slide(prs, current_slide_data)
    
    prs.save(output_path)
    return output_path

def _add_content_slide(prs, data):
    slide = prs.slides.add_slide(prs.slide_layouts[1])
    slide.shapes.title.text = data['title']
    tf = slide.placeholders[1].text_frame
    tf.text = ''
    for bullet in data['bullets']:
        p = tf.add_paragraph()
        p.text = bullet
        p.level = 0

Power Platform + Claude

Power Automate: HTTP connector

В Power Automate создай Flow:

Код
Trigger: Manual / Schedule / Email received
    ↓
Action: HTTP
    Method: POST
    URL: https://api.anthropic.com/v1/messages
    Headers:
        x-api-key: [твой ключ]
        anthropic-version: 2023-06-01
        content-type: application/json
    Body: {
        "model": "claude-haiku-4-5",
        "max_tokens": 500,
        "messages": [{"role": "user", "content": "@{triggerBody()?['text']}"}]
    }
    ↓
Action: Send email / Post to Teams / Update SharePoint

Это простейшая no-code интеграция — Claude без единой строки кода. Действие HTTP относится к premium-коннекторам Power Automate, поэтому нужна подходящая лицензия. Ключ API не вставляй в поток открытым текстом: храни его в защищённом хранилище секретов (например, Azure Key Vault).

Power Apps: кастомный коннектор

  1. Power Apps → Custom Connectors → New
  2. Добавить Anthropic API как коннектор
  3. Настроить actions: sendMessage, etc.
  4. Использовать в любом Power App как компонент

Microsoft Graph API: единая точка данных

python
from msal import ConfidentialClientApplication
import requests

class MSGraphClient:
    def __init__(self):
        app = ConfidentialClientApplication(
            client_id=os.environ["AZURE_CLIENT_ID"],
            client_credential=os.environ["AZURE_CLIENT_SECRET"],
            authority=f"https://login.microsoftonline.com/{os.environ['AZURE_TENANT_ID']}"
        )
        token_result = app.acquire_token_for_client(
            scopes=["https://graph.microsoft.com/.default"]
        )
        self.headers = {
            "Authorization": f"Bearer {token_result['access_token']}",
            "Content-Type": "application/json"
        }
        self.base = "https://graph.microsoft.com/v1.0"
    
    def get_recent_emails(self, user_id: str, count: int = 10) -> list:
        url = f"{self.base}/users/{user_id}/messages"
        params = {"$top": count, "$orderby": "receivedDateTime desc"}
        r = requests.get(url, headers=self.headers, params=params)
        return r.json().get("value", [])
    
    def send_teams_message(self, team_id: str, channel_id: str, message: str):
        # Отправка в канал через Graph работает только с делегированным токеном (от имени пользователя).
        # С токеном приложения, как в этом классе, Graph вернёт 403: для уведомлений используй вебхук Workflows.
        url = f"{self.base}/teams/{team_id}/channels/{channel_id}/messages"
        payload = {"body": {"content": message}}
        requests.post(url, headers=self.headers, json=payload)
    
    def get_sharepoint_files(self, site_id: str, folder: str = "root") -> list:
        url = f"{self.base}/sites/{site_id}/drive/root:/{folder}:/children"
        r = requests.get(url, headers=self.headers)
        return r.json().get("value", [])

# Claude обрабатывает корпоративные данные
def process_emails_with_claude(user_id: str):
    graph = MSGraphClient()
    emails = graph.get_recent_emails(user_id, count=20)
    
    email_texts = [
        f"От: {e['from']['emailAddress']['address']}\nТема: {e['subject']}\n"
        f"Дата: {e['receivedDateTime'][:10]}"
        for e in emails
    ]
    
    client = anthropic.Anthropic()
    summary = "".join(b.text for b in client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=500,
        messages=[{
            "role": "user",
            "content": f"Сделай краткое резюме этих писем, выдели срочные:\n" + "\n---\n".join(email_texts)
        }]
    ).content if b.type == "text")
    
    return summary

Azure + Claude: корпоративная инфраструктура

Два подхода:

1. Claude API напрямую из Azure инфраструктуры:

Код
Azure App Service → Claude API (api.anthropic.com)
Azure Functions → Claude API
Azure Container Apps → Claude API

Твой код работает в Azure, вызывает Anthropic напрямую. Просто, надёжно.

2. Claude в Microsoft Foundry (раньше Azure AI Foundry):

Если клиент говорит "нам нельзя данные выпускать за Azure" — Claude доступен в Microsoft Foundry. Есть два варианта размещения: на инфраструктуре Azure («Hosted on Azure») и на инфраструктуре Anthropic («Hosted on Anthropic infrastructure»); не каждая модель есть в обоих. Нужны платная подписка Azure в поддерживаемой стране и подписка на модель через Azure Marketplace. Где именно обрабатываются данные и какие регионы доступны, проверяй в документации Microsoft Learn и в договоре: само слово «Azure» ещё не закрывает требования compliance.

python
# Claude через Microsoft Foundry: тот же Anthropic SDK, другой клиент и адрес
import os
from anthropic import AnthropicFoundry

client = AnthropicFoundry(
    api_key=os.environ["AZURE_AI_KEY"],
    base_url=os.environ["AZURE_AI_ENDPOINT"],  # https://<имя-ресурса>.services.ai.azure.com/anthropic
)

response = client.messages.create(
    model=os.environ["AZURE_DEPLOYMENT_NAME"],  # имя развёртывания, выбранное при деплое
    max_tokens=500,
    messages=[{"role": "user", "content": "Привет"}]
)
print("".join(b.text for b in response.content if b.type == "text"))

Вместо ключа лучше использовать Microsoft Entra ID (DefaultAzureCredential): пример смотри в документации Microsoft Learn («Deploy and use Claude models in Microsoft Foundry»).


Практика

Шаг 1: Teams Webhook (15 мин)

  1. Создай тестовый Teams канал
  2. Создай вебхук через приложение Workflows и скопируй ссылку
  3. Запусти базовый пример из урока
  4. Убедись что сообщение появилось

Шаг 2: Word через python-docx (20 мин)

bash
pip install python-docx anthropic

Сгенерируй Word документ на любую тему используя код из урока. Открой файл, проверь форматирование.

Шаг 3: Excel анализ (15 мин)

bash
pip install openpyxl

Возьми любой Excel файл с данными. Запусти analyze_excel_with_claude(). Посмотри что Claude скажет о данных.

Шаг 4: Power Automate (опционально, нужен M365)

Если есть доступ к Microsoft 365:

  1. Создай Flow в Power Automate
  2. Триггер: вручную
  3. HTTP action → Claude API (premium-коннектор)
  4. Отправить результат в Teams

Шаг 5: Задание для практики

Выбери один реальный сценарий:

Вариант А: Еженедельный отчёт в Teams. Скрипт собирает данные из любого источника, Claude анализирует, результат — карточка в Teams канале.

Вариант Б: Word-отчёт по шаблону. Claude генерирует контент под конкретную задачу, python-docx оформляет в корпоративный документ.

Вариант В: Email-дайджест. Graph API читает почту, Claude делает резюме, результат в Outlook или Teams.


Инструменты и ресурсы

  • python-docx: pip install python-docx
  • openpyxl: pip install openpyxl
  • python-pptx: pip install python-pptx
  • MSAL (Microsoft auth): pip install msal
  • Microsoft Graph Docs: learn.microsoft.com/graph
  • Teams Webhooks Docs: learn.microsoft.com/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook
  • Microsoft Foundry (раньше Azure AI Foundry): ai.azure.com
  • Microsoft 365 Agents SDK: learn.microsoft.com/microsoft-365/agents-sdk
  • Power Automate: make.powerautomate.com
  • Adaptive Cards Designer: adaptivecards.io/designer

Ключевые выводы

Корпоративный рынок живёт в Microsoft. Умение интегрировать Claude с Teams, Office и Power Platform — полезный навык для работы с корпоративными клиентами. Начни с самого простого: вебхук Workflows для Teams — это несколько десятков строк кода. Дальше — Graph API открывает данные организации (в рамках выданных прав). Microsoft Foundry помогает ответить на вопрос о размещении данных для enterprise-клиентов, но требования compliance проверяй в документации и договоре.


Связанные уроки

Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс