윤정민 fd504738eb
All checks were successful
Build and Deploy Teams Planner Bot / build-and-run (push) Successful in 14s
initial: teams planner bot with gemini classifier and docker deploy
2026-05-15 16:53:08 +09:00

4.7 KiB
Raw Permalink Blame History

Teams Planner Bot

MS Teams 봇. 사용자의 자연어 작업 보고를 LLM으로 분류해서 Microsoft Planner에 자동으로 task를 생성하거나 업데이트한다.

동작 개요

사용자 (Teams) → 봇 → OAuthPrompt 로그인 (최초 1회)
              → Graph로 본인 Plans/Buckets/최근 Tasks 조회
              → LLM(Claude 또는 Azure OpenAI)에게 발화 + 컨텍스트 전달
              → tool/function call로 {action, planId, ...} JSON 강제 추출
              → Planner Graph API로 create / patch
              → Adaptive Card로 결과 응답

구성

src/
  index.ts                       # restify 서버, CloudAdapter
  config/index.ts                # 환경변수 로딩/검증
  bot/PlannerBot.ts              # 메시지 핸들러 + OAuth 다이얼로그 + 오케스트레이션
  graph/
    graphClientFactory.ts        # 사용자 토큰을 받아 Graph Client 생성
    plannerClient.ts             # Plans/Buckets/Tasks 조회·생성·업데이트 (ETag 처리 포함)
  llm/
    types.ts                     # ClassifiedAction 등 공용 타입
    prompt.ts                    # 시스템 프롬프트 + tool/function 스키마
    coerce.ts                    # LLM JSON → ClassifiedAction 검증
    claudeClassifier.ts          # Anthropic Claude 구현 (tool_use 강제)
    azureOpenAiClassifier.ts     # Azure OpenAI 구현 (function calling 강제)
    factory.ts                   # LLM_PROVIDER 기반 분기
  cards/confirmationCard.ts      # 결과 Adaptive Card
appPackage/manifest.json         # Teams 앱 매니페스트 (개발자 포털에 업로드)

사전 준비 (Azure / Microsoft 365)

  1. Azure AD 앱 등록 (Graph 위임 권한)

    • Azure Portal → App registrations → New
    • API permissions → Microsoft Graph → Delegated:
      • Tasks.ReadWrite
      • Group.Read.All
      • User.Read
      • offline_access
    • Grant admin consent
    • Certificates & secrets → Client secret 발급
    • 노트: tenantId, clientId, clientSecret
  2. Azure Bot 리소스

    • Azure Portal → Create resource → Azure Bot (Multi Tenant)
    • Microsoft App ID/Password 발급 → 노트
    • Configuration → OAuth Connection Settings → Add
      • Name: GraphConnection (이 이름이 .envOAUTH_CONNECTION_NAME)
      • Service Provider: Azure Active Directory v2
      • Client id / secret: 1번에서 만든 값
      • Tenant ID: 1번의 tenantId
      • Token Exchange URL: 비워두기 (SSO 안 쓸 경우)
      • Scopes: Tasks.ReadWrite Group.Read.All User.Read offline_access
    • "Test Connection" 으로 토큰이 떨어지는지 확인
  3. Teams 앱 매니페스트

    • appPackage/manifest.jsonREPLACE_WITH_YOUR_BOT_APP_ID 를 Azure Bot의 App ID로 치환
    • color.png (192×192), outline.png (32×32) 아이콘을 appPackage/에 추가
    • 폴더를 zip 으로 압축 → Teams 관리자 센터(또는 개발자 포털)에서 사이드로딩

로컬 실행

npm install
cp .env.example .env
# .env 채우기
npm run dev

다른 터미널에서 ngrok 등으로 외부 노출:

ngrok http 3978

ngrok URL을 Azure Bot의 Messaging endpointhttps://<ngrok>/api/messages 형태로 설정.

LLM 교체

.envLLM_PROVIDER 만 바꾸면 됨:

  • claudeANTHROPIC_API_KEY, CLAUDE_MODEL 사용
  • azure-openaiAZURE_OPENAI_* 사용

두 구현 모두 동일한 LlmClassifier 인터페이스를 구현하므로 호출부 변경 없음.

알아두면 좋을 점 / 함정

  • Planner write는 ETag 필수. plannerClient.ts 가 PATCH 직전 항상 GET으로 ETag를 받아 If-Match에 넣는다. 만약 동시 편집이 잦은 환경이면 412 에러를 retry 로 감싸야 한다.
  • /me/planner/plans 는 사용자가 속한 그룹의 Plan 만 반환한다. 봇이 "보이지 않는다" 면 Teams 채널에 그 사용자가 멤버인지부터 확인.
  • OAuthPrompt 의 토큰은 Bot Framework 의 토큰 서비스(token.botframework.com)에 캐시된다. logout 명령으로 강제 갱신 가능.
  • MemoryStorage 는 개발용. 프로덕션은 CosmosDB/Blob 백엔드로 교체.
  • 확장 아이디어:
    • 다중 후보일 때 카드의 Action.Submit 으로 사용자가 직접 plan 선택
    • Plans/Buckets 캐시 (현재는 매 발화마다 다시 조회)
    • 일/주간 요약 발송 (proactive messaging)

다음 단계

  1. npm install → 의존성 받기
  2. Azure AD 앱 등록 + Azure Bot 리소스 + OAuth Connection 설정
  3. .env 채우기
  4. npm run dev 로 띄우고 ngrok 으로 노출
  5. Teams 매니페스트 사이드로딩 → 개인 채팅으로 봇과 대화
  6. "오늘 견적서 초안 작성 시작했어" 같은 첫 발화로 테스트