데스크톱 코파일럿(Copilot)이 승리할 줄 알았는데, Android에서 에이전트를 구축해 보았습니다
요약
데스크톱 중심의 AI 에이전트 개발에서 벗어나 Android 환경을 활용한 에이전트 구축의 이점을 분석합니다. Android가 가진 로그인 세션, 백그라운드 스케줄링, 앱 접근 권한 등의 특성을 활용해 실질적인 워크플로를 자동화하는 방법을 제안합니다.
핵심 포인트
- Android는 이미 로그인된 앱과 인증된 세션을 보유한 최적의 에이전트 환경임
- 데스크톱 에이전트의 브라우징 능력보다 업무 컨텍스트 접근성이 더 중요함
- WorkManager를 활용해 배터리 효율과 지속성을 보장하는 자동화 구현 가능
- 모바일 환경에 최적화된 좁은 범위의 운영자(Narrow operator) 설계 필요
저는 AI 에이전트의 명백한 안식처는 데스크톱일 것이라고 가정해 왔습니다.
Chrome 확장 프로그램. 사이드바 코파일럿 (Sidebar copilot). 커맨드 바 (Command bar)가 있는 로컬 앱. 아마도 Playwright와 LLM (대규모 언어 모델)을 결합한 브라우저 자동화 루프 같은 것들 말이죠.
그것들은 여전히 훌륭한 데모가 될 수 있습니다.
하지만 Android 자동화 패턴을 깊이 파고들고 몇몇 OpenClaw 논의를 읽어본 후, 저는 많은 사람들이 잘못된 기기를 목표로 삼고 있다고 생각합니다.
놀라운 점은 Android가 에이전트를 실행할 수 있다는 사실이 아닙니다.
놀라운 점은 스마트폰이 실제 워크플로 (Workflow)에 필요한 대부분의 기본 요소 (Primitives)를 이미 갖추고 있다는 사실입니다:
- 로그인된 앱
- 백그라운드 스케줄링 (Background scheduling)
- 재시작 시에도 유지되는 지속성 (Persistence)
- 카메라 및 파일 접근 권한
- 푸시 알림 (Push notifications)
- 모바일 인증된 비즈니스 도구
만약 당신의 워크플로가 Gmail, Slack, HubSpot, Google Drive, WhatsApp, Stripe, 현장 앱 (Field apps), 영수증, 사진, 그리고 관리되는 작업 프로필 (Work-profile) 앱 내에서 이루어진다면, 스마트폰은 약한 연결 고리가 아닙니다.
그것이 바로 실제 환경입니다.
진짜 질문은 능력이 아니라 컨텍스트 (Context)입니다.
많은 데스크톱 에이전트 데모들은 에이전트가 다음과 같은 일을 할 수 있는지에 집중합니다:
- 브라우징 (Browse)
- 클릭 (Click)
- 요약 (Summarize)
- 코딩 (Code)
- 양식 채우기 (Fill forms)
그것은 잘못된 첫 번째 질문입니다.
더 나은 질문은 이것입니다:
에이전트가 업무가 발생하는 곳에 이미 로그인되어 있는가?
이 지점에서 Android는 빠르게 흥미로워집니다.
Chrome 확장 프로그램은 여전히 기본적으로 데스크톱 중심의 이야기입니다. 만약 당신의 계획이 확장 프로그램 주입 (Extension injection)에 의존한다면, 모바일은 어색할 수밖에 없습니다.
하지만 당신의 워크플로가 Gmail, Salesforce 모바일, Chrome, 사내 내부 앱, 또는 직원들이 하루 종일 이미 사용 중인 현장 서비스 앱의 인증된 세션 (Authenticated sessions)에 의존한다면, Android는 타협안이 아니라 오히려 네이티브 홈 (Native home)처럼 보이기 시작합니다.
그것은 당신이 에이전트를 설계하는 방식을 바꿉니다.
당신은 아주 작은 데스크톱 코파일럿을 만들려고 시도하는 것을 멈추게 됩니다.
대신 모바일 컨텍스트 내에 존재하는 좁은 범위의 운영자 (Narrow operator)를 구축하기 시작합니다.
WorkManager는 이것이 실용적인 이유입니다
만약 한동안 Android의 백그라운드 실행 (Background execution)을 살펴보지 않았다면, 당신의 사고 모델은 아마 구식일 것입니다.
진지한 Android 자동화는 다음과 같은 것이 아닙:
while(true) {
pollServer()
Thread.sleep(5000)
...
그렇게 하면 배터리 불만, OS 스로틀링 (Throttling), 그리고 앱 오류를 얻게 될 뿐입니다.
진정한 프리미티브 (Primitive)는 WorkManager입니다.
WorkManager는 다음과 같은 기능을 제공합니다:
- 일회성 작업 (one-time work)
- 주기적 작업 (periodic work)
- 재시도 동작 (retry behavior)
- 네트워크/배터리와 같은 제약 조건 (constraints)
- 앱 재시작 시에도 유지되는 지속성 (persistence)
- 기기 재부팅 시에도 유지되는 지속성
- 긴급한 단기 작업을 위한 가속 작업 (expedited jobs)
- 적절히 승격되었을 때의 장기 실행 작업 (long-running work)
최소한의 일회성 작업은 다음과 같습니다:
val request = OneTimeWorkRequestBuilder<SyncWorker>().build()
WorkManager.getInstance(context).enqueue(request)
워커 (Worker)는 간단합니다:
class SyncWorker(
context: Context,
params: WorkerParameters
...
그리고 반복 작업이 필요한 경우:
val periodicRequest = PeriodicWorkRequestBuilder<InboxSummaryWorker>(
15, TimeUnit.MINUTES
).build()
...
이 15분이라는 하한선은 Android가 짜증 나게 구는 것이 아닙니다.
그것은 Android가 당신에게 어떤 종류의 자동화를 원하는지 말해주는 것입니다.
예약된 것. 제약이 있는 것. 재시도에 안전한 것. 지루한 것.
이것이 바로 유용한 에이전트 (Agent)가 갖춰야 할 모습입니다.
장기 실행 작업은 가능하지만, 자격을 증명해야 합니다
많은 사람이 여전히 시간 제한 때문에 휴대폰이 의미 있는 백그라운드 작업을 수행할 수 없다고 생각합니다.
그것은 절반만 맞는 말입니다.
사용자에게 중요한 작업의 경우, WorkManager는 작업을 포그라운드 서비스 (foreground service)로 승격시킬 수 있습니다. 이를 통해 작업을 일반적인 짧은 실행 시간 범위를 넘어 실행할 수 있습니다.
예시:
class UploadWorker(
context: Context,
params: WorkerParameters
...
문제는 최신 Android 버전일수록 포그라운드 서비스에 대해 더 엄격하다는 점입니다:
- Android 12 이상: 백그라운드에서 서비스를 시작할 수 있는 시점을 제한합니다.
- Android 14: 포그라운드 서비스 유형 (foreground service types)과 그에 맞는 권한을 요구합니다.
- Android 15: 일부 서비스 카테고리에 대해 더 많은 타임아웃 규칙을 추가합니다.
- Android 16: 백그라운드 작업에 대한 할당량 (quota) 동작을 계속해서 강화하고 있습니다.
따라서 아니요, Android를 주머니 속에 있는 영구적으로 깨어 있는 Linux 박스처럼 취급할 수는 없습니다.
하지만 그것으로 괜찮습니다.
가장 유용한 에이전트(agent)들은 영구적으로 깨어 있을 필요가 없습니다.
그들에게 필요한 것은 다음과 같습니다:
- 정해진 일정에 따라 깨어나기
- 실제 이벤트에 반응하기
- 적은 양의 작업 수행하기
- 네트워크 상태가 좋지 않을 경우 안전하게 재시도하기
- 더 무거운 추론(reasoning) 작업은 다른 곳으로 넘기기
이러한 패턴은 Android에서 매우 잘 작동합니다.
최고의 Android 에이전트는 좁은 범위의 작업자(narrow operators)입니다
이 지점이 많은 에이전트 프로젝트가 실패하는 부분입니다.
사람들은 범용적인(generalist) 모델을 만들려고 시도합니다.
모든 것을 읽고, 모든 것을 결정하며, 하나의 오케스트레이션 그래프(orchestration graph)로 회사 절반을 운영하는 무언가를 말이죠.
그러한 시도는 대개 자체적인 복잡성 때문에 무너집니다.
Android 에이전트는 제약이 있을 때 더 잘 작동합니다.
다음과 같은 사례를 생각해 보세요:
- 매시간 읽지 않은 Gmail 스레드 요약하기
- 카메라 롤의 영수증을 Google Drive에 업로드하기
- 사진을 분류하고 회계 필드 추출하기
- 연결이 복구되었을 때 현장 메모를 CRM에 동기화하기
- 편지함에서 긴급 키워드를 감시하고 후속 작업 생성하기
- 현장 방문 시의 양식과 사진을 패키징한 후 백그라운드에서 업로드하기
이것들은 화려한 데모가 아닙니다.
오히려 화려한 데모보다 더 낫습니다.
이것들은 실제 업무와 직결됩니다.
실제로 견고하게 버티는 실용적인 아키텍처
제가 발견한 가장 깔끔한 패턴은 다음과 같습니다:
- Android가 컨텍스트(context)와 트리거링(triggering)을 처리합니다.
- WorkManager가 스케줄링과 재시도를 처리합니다.
- 백엔드(backend) 또는 자동화 도구가 오케스트레이션(orchestration)을 처리합니다.
- LLM 레이어가 분류, 요약, 추출 및 라우팅(routing)을 처리합니다.
- Android가 결과를 수신하고 다음 로컬 작업을 수행합니다.
실제로 이는 종종 다음과 같은 구성을 의미합니다:
- Android 앱
WorkManagern8n,Make또는 커스텀 백엔드- OpenAI 호환 API 엔드포인트
예시 흐름
- 사용자가 8장의 영수증 사진을 찍습니다.
- 앱이 이를 로컬에 저장합니다.
WorkManager가 네트워크 사용이 가능할 때 업로드 작업을 대기열에 추가합니다.- 백엔드가 각 이미지를 OCR + 분류를 위해 전송합니다.
- 백엔드가 정규화된 비용 데이터를 반환합니다.
- 앱이 영수증을 동기화됨으로 표시합니다.
- 만약 무언가 실패하면, 워커(worker)가 나중에 재시도합니다.
이러한 분리가 중요한 이유는 휴대폰이 모든 추론(reasoning)을 수행해서는 안 되기 때문입니다.
휴대폰은 컨텍스트(context)를 소유해야 합니다.
백엔드(backend)는 오케스트레이션(orchestration)을 소유해야 합니다.
모델 계층(model layer)은 추론(inference)을 소유해야 합니다.
모바일에서 API 가격 책정이 갑자기 매우 중요해진 이유
이 부분은 사람들이 과소평가하는 지점입니다.
모바일 에이전트(mobile agents)는 수많은 아주 작은 호출(calls)을 생성합니다.
하나의 거대한 프롬프트(prompt)가 아닙니다.
지속적으로 흐르는 작은 작업들입니다:
- 읽지 않은 스레드 5개 요약
- 영수증 3개 분류
- 사진 2장에서 필드 추출
- 메시지 1개가 긴급한지 결정
- 실패한 동기화 재시도
- 15분 후에 동일한 체크 다시 실행
각 호출은 작습니다.
하지만 이들이 모이면 토큰당 과금(per-token billing) 방식을 짜증 나게 만드는 바로 그 유형의 워크로드(workload)가 됩니다.
왜냐하면 워크플로(workflow)의 유용한 버전은 비용 대시보드를 확인하지 않고 하루 종일 실행해 두는 것이기 때문입니다.
모든 재시도, 요약, 분류가 마치 계량기가 돌아가는 것처럼 느껴진다면, 팀들은 실제로 도움이 되었던 자동화 기능들을 비활성화하기 시작합니다.
이것이 바로 백엔드 계층이 Android 아키텍처만큼 중요한 이유입니다.
이러한 반복적인 에이전트 워크로드의 경우, 토큰당 과금에 대한 불안감보다는 OpenAI 호환 정액제 엔드포인트(flat-rate OpenAI-compatible endpoint)가 훨씬 더 적합합니다.
이것이 Standard Compute의 매력입니다.
기존의 OpenAI SDK 형태를 유지하면서도, 지속적으로 실행되는 자동화에 대해 더 나은 경제성을 제공합니다. 모든 백그라운드 요약을 과금 이벤트로 취급하는 대신, 워크플로를 계속 켜둘 수 있습니다. 또한 라우팅(routing)을 GPT-5.4, Claude Opus 4.6, Grok 4.20 사이에서 전환할 수 있으므로, 모든 작업에 대해 앱에 하나의 모델을 하드코딩할 필요가 없습니다.
이는 호출의 80%가 반복적이고 20%가 더 강력한 추론(reasoning)을 필요로 하는 에이전트 시스템에서 매우 중요합니다.
구체적인 예시: Android + WorkManager + n8n + OpenAI 호환 API
다음은 모바일 우선(mobile-first) 에이전트의 간단한 구조입니다.
1. Android가 작업을 스케줄링함
val request = OneTimeWorkRequestBuilder<ReceiptSyncWorker>()
.setConstraints(
Constraints.Builder()
...
2. 워커(Worker)가 자동화 백엔드로 페이로드(payload)를 전송함
class ReceiptSyncWorker(
context: Context,
params: WorkerParameters
...
3. n8n이 이를 수신하고 처리합니다
여러분의 n8n 플로우는 다음과 같은 모습일 것입니다:
Webhook -> 파일 다운로드 (Download Files) -> OCR 단계 -> LLM 분류 (LLM Classification) -> DB에 저장 (Save to DB) -> 콜백 (Callback)
4. 백엔드에서 OpenAI 호환 클라이언트 사용하기
npm install openai
import OpenAI from "openai";
const client = new OpenAI({
...
이 부분이 에이전트 빌더(agent builders)로서 제가 가장 좋아하는 부분입니다. 여러분의 워크로드(workload)가 모바일 우선(mobile-first)이라고 해서 이상하고 복잡한 커스텀 통합(custom integration)을 할 필요가 없기 때문입니다.
여전히 OpenAI 호환 API 플로우를 따릅니다.
현장 팀(Field teams)에서 이 기술이 매우 실질적으로 활용됩니다
이것은 단순히 인디 해커(indie hackers)들을 위한 장난감이 아닙니다.
Android는 이미 많은 최전선 업무(frontline work)를 위한 디바이스 클래스입니다:
- 현장 서비스 (field service)
- 재고 관리 (inventory)
- 물류 (logistics)
- 운송 (transport)
- 점검 (inspections)
- 배송 운영 (delivery operations)
이러한 팀들은 이미 스마트폰이나 전용 Android 디바이스를 기반으로 생활하고 있습니다.
즉, Android 우선 에이전트 패턴은 그들이 이미 보유한 환경에 딱 들어맞는다는 의미입니다.
현장 워크플로우(field workflow)의 예시는 다음과 같습니다:
- 기술자가 사진을 찍습니다.
- 관리형 앱(managed app)에서 양식을 작성합니다.
- 앱이 모든 데이터를 로컬에 저장합니다.
WorkManager가 연결 상태를 기다립니다.- 업로드가 자동으로 시작됩니다.
- 백엔드가 노트를 요약하고 이미지를 분류합니다.
- CRM이 업데이트됩니다.
- 업로드 실패 시 나중에 재시도합니다.
이것이 바로 실제 워크플로우입니다.
그리고 이는 토큰당 과금 방식(per-token pricing) 하에서 팀들이 싫어하는 정확한 비용 패턴을 만들어냅니다. 즉, 여러 디바이스에 걸쳐 발생하는 수백, 수천 개의 아주 작은 모델 호출(model calls)입니다.
자동화 기능을 계속 켜두는 것이 핵심인 상황에서는 정액제 컴퓨팅(Flat-rate compute)을 정당화하기가 훨씬 쉽습니다.
데스크톱이 여전히 가끔 승리하는 경우
네, 물론입니다.
만약 다음과 같은 작업을 하고 있다면:
- 심층적인 브라우저 자동화 (deep browser automation)
- 멀티 윈도우 리서치 (multi-window research)
- IDE 인접 코딩 지원 (IDE-adjacent coding help)
- 브라우저 확장 프로그램 워크플로우 (browser extension workflows)
- 전체 데스크톱 UI 제어에 의존하는 모든 작업
데스크톱 코파일럿(Desktop copilots)이 여전히 승리합니다.
그 점에는 이견이 없습니다.
하지만 워크플로우가 모바일 형태라면, 데스크톱은 빠르게 뒤처지기 시작합니다.
다음은 실질적인 비교입니다:
| 옵션 | 강점 |
|---|---|
| Android WorkManager | 재시작 및 재부팅 후에도 유지되는, 예약 가능하고 재시도에 안전한 모바일 백그라운드 자동화에 최적 |
| ... |
그것이 핵심적인 차이점입니다.
데스크톱은 브라우저 중심의 작업에 더 적합합니다.
Android는 로그인된 모바일 컨텍스트 (context)에 더 적합합니다.
지나치게 야심을 품을 때 발생하는 문제
이 지점이 모바일 에이전트 (agent)에 대한 환상이 깨지는 부분입니다.
에이전트 (agent), 공유 상태 관리자 (shared state managers), 로컬 루프 (local loops)를 휴대폰 위에 영원히 계속 쌓아 올릴 수는 없습니다.
어느 시점에 이르면, 과하게 구축된 데스크톱 오케스트레이션 (orchestration)의 가장 나쁜 부분들을 그대로 재현하게 됩니다:
- 레이스 컨디션 (race conditions)
- 충돌하는 쓰기 작업 (conflicting writes)
- 재시도 폭풍 (retry storms)
- 배터리 소모 (battery drain)
- 이상한 알림 동작 (weird notification behavior)
- 불가능한 디버깅 (impossible debugging)
Android 에이전트 (agent)는 다음과 같은 상태를 유지해야 합니다:
- 개인적이고 (personal)
- 범위가 좁으며 (narrow)
- 이벤트 중심적이고 (event-driven)
- 오프라인을 허용하며 (offline-tolerant)
- 재시도가 쉬워야 합니다 (easy to retry)
만약 당신의 설계가 다섯 개의 협력하는 하위 에이전트 (subagents)와 지속적인 메모리 동기화 루프 (memory sync loop)를 필요로 한다면, 저는 그것을 휴대폰에 올리지 않을 것입니다.
대신 그 기능의 더 많은 부분을 백엔드 (backend)로 옮길 것입니다.
배터리는 대충 넘길 수 없는 엄격한 제약 조건입니다
사용자가 당신의 Android 에이전트 (agent)를 싫어하게 만드는 가장 빠른 방법은, 휴대폰이 마치 유령이라도 들린 것처럼 느껴지게 만드는 것입니다.
당신도 그 증상들을 알고 있을 것입니다:
- 기기 발열 (warm device)
- 무작위 깨어남 (random wakeups)
- 끝없는 동기화 (endless syncing)
- 설명되지 않는 배터리 소모 (unexplained battery drain)
- 마치 도움을 요청하는 듯한 알림 (notifications that feel like a cry for help)
만약 당신의 설계가 지속적인 폴링 (polling)에 의존한다면, 그것은 아마 잘못된 설계일 것입니다.
더 나은 패턴은 다음과 같습니다:
- 가능할 때 실제 이벤트 (real events)에 트리거 (trigger)할 것
WorkManager큐 (queues)를 사용할 것- 긴급하고 짧은 작업에는 가속화된 작업 (expedited work)을 사용할 것
- 의미 있고 사용자에게 보이는 작업에만 포그라운드 서비스 (foreground services)를 사용할 것
- 재시도가 안전하도록 로컬 상태 (local state)를 유지할 것
- 무거운 추론 (reasoning)은 원격 모델 (remote models)로 오프로드 (offload)할 것
- Android 할당량 (quotas)과 API 할당량 (API quotas)을 모두 준수할 것
마지막 지점은 놓치기 쉽습니다.
모바일 에이전트 (agent)는 모델 제한 (model limits) 하에서만 작동하는 것이 아닙니다.
그들은 OS 제한 (OS limits) 하에서도 작동합니다.
그리고 솔직히 말해서, 그것은 건강한 일입니다. 더 나은 엔지니어링을 강제하기 때문입니다.
현재 나의 견해
저는 여전히 데스크톱 코파일럿 (copilots)이 훌륭하다고 생각합니다.
다만 그것이 더 이상 기본 정답(default answer)이라고 생각하지 않을 뿐입니다.
만약 워크플로 (workflow)가 다음과 같다면:
- 개인적이고 (personal)
- 인증되었으며 (authenticated)
- 간헐적이고 (intermittent)
- 모바일 중심이며 (mobile)
- 범위가 좁고 (narrow)
- 백그라운드 친화적이라면 (background-friendly)
Android가 종종 더 나은 환경이 됩니다.
Android가 데스크톱보다 더 강력하기 때문이 아닙니다.
실제 작업에 더 가깝기 때문입니다.
그리고 여기에 수많은 작은 반복 호출 (recurring calls)을 허용하는 OpenAI 호환 백엔드 (OpenAI-compatible backend)를 결합한다면, 전체 아키텍처 (architecture)는 훨씬 더 실용적이 됩니다.
그 부분이 바로 제 생각을 바꾼 지점입니다.
흥미로운 에이전트 (agents)들은 당신의 IDE 옆에 앉아 있는 것들이 아닐지도 모릅니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기