안드로이드에서 Tasker와 n8n을 이용해서 구글 캘린더와 Tasks 사용하기.

소개

시도하고자 했던 것과 그 이유

지난번에 올렸던 사례글에서 발전을 시켜서 안드로이드에 음성으로 "내일 오후 2시에 회의 일정 잡아줘"라고 말하면 자동으로 구글 캘린더에 등록되고, "할일에 장보기 추가해줘"라고 하면 구글 Tasks에 등록되는 개인 AI 비서를 만들고 싶었습니다.

왜 이 프로젝트를 시작했나요?

  • 기존 음성 비서(구글 어시스턴트, 시리)는 한국어 지원이 제한적

  • 복잡한 명령이나 개인화된 워크플로우 처리가 어려움

  • n8n과 AI를 활용해 완전히 커스터마이징 가능한 음성 비서를 만들고 싶었음

목표:

음성 입력 → AI 분석 → 자동 실행 → 음성 응답
"할 일 추가" → 구글 Tasks 등록 → "할일에 등록했습니다"
"일정 추가" → 구글 캘린더 등록 → "캘린더에 일정을 등록했습니다"

진행 방법

사용한 도구

핵심 스택:

  • n8n (1.102.3): 워크플로우 자동화 플랫폼

  • Tasker: 안드로이드 자동화 앱

  • OpenAI GPT-4o-mini: AI 모델

  • MCP (Model Context Protocol): n8n과 AI 도구 연동

  • Google Calendar/Tasks API: 실제 데이터 저장

아키텍처 설계

[안드로이드 Tasker] 
        ↓ (HTTP POST)
[n8n Webhook] → [AI Agent] → [MCP Tools] → [Google APIs]
        ↓ (HTTP Response)
[Tasker 음성 출력]

1단계: n8n 기본 워크플로우 구성

Webhook 노드 설정:

HTTP Method: POST
Path: /voice-command
Respond Mode: Using 'Respond to Webhook' Node

AI Agent 프롬프트 (핵심):

markdown

당신은 한국어 음성 명령을 처리하는 개인 비서 AI입니다.

## 일정 vs 할일 구분 규칙
- "일정", "스케줄", "약속", "회의", "미팅" → Google Calendar
- "할일", "과업", "작업", "해야할", "하기" → Google Tasks
- "할일" + 시간 범위 → 자동으로 Calendar로 변경

## 응답 형식
- Calendar 작업: "캘린더에 일정을 등록했습니다"
- Tasks 작업: "할일에 등록했습니다"
- 마크다운 문법 금지, 자연스러운 한국어만 사용

명령 처리: {{ $json.body.command }}를 분석하고 적절한 도구를 실행하세요.

2단계: MCP를 활용한 도구 분리

Context7를 통해 n8n-MCP 라이브러리를 활용하여 Google Calendar와 Tasks를 분리된 클라이언트로 구성:

Calendar Client (MCP): google-calendar 관련 모든 작업
Tasks Client (MCP): google-tasks 관련 모든 작업

3단계: Tasker 안드로이드 앱 설정

Profile 생성:

Event: UI → Button Widget Clicked
Label: Voice Assistant

Task 구성:

javascript

// Action 1: Get Voice (음성 인식)
Category: Media
Action: Get Voice
Language: ko-KR
Output Variable: %gv_heard

// Action 2: HTTP Request (n8n 전송)
Category: Net
Action: HTTP Request
Method: POST
URL: 각자의 접속 URL로 등록 필요
Headers: Content-Type:application/json
Body: {"command": "%VOICE", "timestamp": "%TIMES", "device_id": "android_tasker"}

// Action 3: Say Response (음성 출력)
Category: Media
Action: Say
Text: %http_data
Engine: com.google.android.tts:kor-kor

4단계: 메모리 및 세션 관리

Simple Memory 설정:

Session Key: {{ $json.body.device_id }}
Context Window: 5

이렇게 하면 각 디바이스별로 대화 컨텍스트가 유지됩니다.


결과와 배운 점

🎯 최종 결과

성공적으로 작동하는 기능들:

  • ✅ "내일 오후 2시에 팀 회의 일정 잡아줘" → 자동 캘린더 등록

  • ✅ "할일에 장보기 추가해줘" → Tasks 등록

  • ✅ "이번 주 일정 알려줘" → 캘린더 조회 및 음성 응답

  • ✅ "할일 목록 보여줘" → Tasks 목록 음성 출력

  • ✅ 한국어 자연어 처리 및 시간 정보 파싱

🔍 주요 배운 점

1. Google Tasks API의 한계 Google Tasks는 시간 정보를 지원하지 않습니다. 따라서 시간이 포함된 할일은 자동으로 캘린더 일정으로 변경하도록 설계했습니다.

2. Tasker 음성 변수의 중요성 초기에 %voice_input을 사용했지만 작동하지 않았습니다. Tasker의 실제 출력 변수는 %voice입니다.

3. AI 응답 신뢰성 문제 AI가 실제 도구 실행 결과를 확인하지 않고 성공했다고 가정 응답하는 문제가 있었습니다. 프롬프트에 결과 검증 규칙을 강화해서 해결했습니다.

  1. 처음에는 server trigger을 한개로 전부 처리를 하다가 최종적으로는 나누어서 사용을 하고 프롬프트에서 할일과 일정이라는 키워드로 자동 분류가 되어서 실행이 되도록 수정해서 사용을 하고 있습니다.

⚠️ 시행착오

문제 1: 마크다운 문법이 음성으로 출력

잘못된 응답: "**제목**: 회의, **시간**: 오후 2시"
해결된 응답: "회의 일정이 오후 2시에 등록되었습니다"

→ 프롬프트에 "마크다운 문법 금지" 규칙 추가

문제 2: 일정 수정시 제목이 사라짐 Update Fields에서 Summary를 포함했더니 기존 제목이 AI 변수로 덮어써짐 → Update Fields에서 Summary 제거, Start/End만 수정

문제 3: 구글 캘린더 인증 만료 EAUTH 오류 발생 → Google Calendar 크리덴셜 재생성 및 OAuth 재인증

💡 나만의 꿀팁

1. MCP 활용으로 도구 분리 Google Calendar와 Tasks를 별도 MCP 클라이언트로 분리하면 AI가 더 정확하게 도구를 선택합니다.

2. 키워드 기반 구분의 중요성 시간 여부보다는 명령어의 키워드("일정" vs "할일")로 구분하는 것이 더 정확합니다.

3. Device ID를 메모리 키로 사용 IP 대신 device_id를 메모리 키로 사용하면 네트워크 변경과 무관하게 대화 컨텍스트가 유지됩니다.

🚀 앞으로의 계획

단기 목표:

  • 에러 처리 강화 (실제 도구 실행 결과 검증)

  • 음성 인식 정확도 개선

🆘 도움이 필요한 부분

  1. AI 응답 신뢰성: AI가 실제 실행 결과를 무시하고 추측으로 응답하는 문제

  2. 한국어 음성 인식: Tasker의 한국어 음성 인식 정확도 개선 방법

  3. 에러 처리: n8n 워크플로우에서 더 견고한 에러 처리 방법

시연 영상 추가 합니다.

tasker_voice_2025-07-20.mp4
7.64MB

2
2개의 답글

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요