본문 바로가기

이 포트폴리오의 원본은 https://ai.iruyo.com (심재빈) 입니다 · 출처 식별자 jbx-7f3a2e9b

← 기술 블로그

개인 OSS

온디바이스 AI와 단축어로 만든 음성 기반 홈 제어 (IntentCP)

스마트홈 기기를 음성으로 제어하기 위한 온디바이스 AI 파이프라인을 iPhone 단축어와 결합해 구축한 과정이다. LLM에 직접 기기를 연결하는 방식이 토큰 비용, 지연, 상시 서버 운용 문제로 현실적이지 않음을 검증하고, 폰을 개인 AI 실행 환경으로 전환하는 접근으로 전환했다. 자연어 명령을 검증 가능한 형식(intention code pattern)으로 정규화하는 구조를 설계하며, 홈 제어 명령의 안정성과 재현성을 확보하기까지의 기술적 시행착오와 설계 의도를 정리했다.

혼자 사는 집을 말로 켜고 싶었다

1인 자취다. 문을 열며 “불 좀 켜줘”, 침대에 눕기 전에는 “다 꺼줘”라고 말하고 싶었다. 그게 시작이었다. 특별한 설계 의도나 거창한 목적은 없었고, 단지 손 대신 입으로 집을 움직여보고 싶었다.

이 글은 그 단순한 욕심에서 출발해 IntentCP라는 중계 서버에 닿기까지의 과정을 그대로 적는다. 결론인 해석과 실행을 나눈 구조부터 이야기하지 않는다. 그건 애초의 설계가 아니라, 두 번 막히고 나서야 도달한 자리였기 때문이다.

첫 발상은 LLM에 기기를 통째로 붙이는 것이었다 — 두 군데에서 막혔다

가장 단순한 구상은 이랬다. 자연어 명령을 LLM에 던지면 LLM이 기기를 직접 제어한다. 요즘 식으로 말하면 MCP처럼 도구를 손에 쥔 하나의 에이전트가 집 전체를 관리하는 형태다.

그런데 두 가지 벽이 있었다.

  • 반복 호출마다 외부 토큰 비용이 든다. “불 켜줘” 한 번이 곧 API 호출 한 번이고, 집 제어는 하루에도 수십 번 이루어진다. 매번 외부 모델에 비용을 지불하는 구조를 단순한 조명 스위치에 붙이는 건 부담스럽다.
  • 집 안에 상시 GPU 서버가 필요하다. 토큰 비용을 피하려면 모델을 직접 돌려야 하는데, 그러려면 GPU가 24시간 켜진 서버가 있어야 한다. 자취방에 그런 장비를 둘 이유가 없으며, 전기료도 자리도 소음도 모두 부담이다.

결국 두 방법 모두 “실행은 되지만 자취방에 맞지 않는다”는 판단으로 접었다. 여기서 첫 번째 막힘이 생겼다.

폰이 이미 충분히 좋은 개인 AI 머신이었다

막힌 자리에서 불현듯 떠오른 생각이 있었다. 스마트폰은 누구나 들고 다니는, 이미 충분히 잘 작동하는 개인 AI 머신이다. 별도 서버를 마련하지 않고도 주머니 속 기계로 충분히 해결할 수 있다.

폰의 온디바이스 모델을 통해 자연어를 해석하면 GPU 사용도, 외부 토큰 비용도 0으로 줄어든다. 앞에서 가로막고 있던 두 장벽이 동시에 사라진 셈이다. 이 깨달음이 프로젝트의 실제 출발점이 되었다.

iOS에서 그 기능을 어떻게 활용할 수 있을지가 다음 과제였다. 2025년 시점 기준으로, 별도 앱을 만들지 않고 아이폰의 온디바이스 AI에 접근할 수 있는 거의 유일한 방법은 iOS 단축어였다. 앱을 따로 쓰지 않는다는 전제라면 단축어가 가장 간단한 접근 방식이다. Apple Intelligence가 단축어 액션 형태로 제공되어 있어, “시리야”로 호출한 자연어 명령을 단축어 안에서 모델로 전달할 수 있다.

그 시점에 “시리야, 거실 불 꺼줘”처럼 자연어로 집을 제어할 수 있는 앱은 내가 알기로 존재하지 않았다. 정해진 버튼이나 문구가 아닌, 사람이 말하듯 던지는 명령을 받아주는 도구가 없었다. 이 공백을 직접 메운 것이 바로 이 프로젝트의 출발이었다.

단순 명령부터 굴리고, 거기에 자연어를 끼웠다

처음부터 AI를 붙인 건 아니다. 먼저 단축어에 Tuya 앱을 연동해 AI가 전혀 개입하지 않는 단순 로직 명령부터 돌려봤다. “시리야, 에어컨 켜줘” 같은 구문을 특정 기기의 특정 동작에 1:1로 매핑하는 방식이다.

동작은 했다. 그러나 자연어가 주는 유연함이 없었다. “에어컨 켜줘”는 인식되는데 “좀 덥다”는 통하지 않았다. “거실 불”은 작동하지만 “거실 좀 환하게”는 불가능했다. 결국 사람이 명령어를 외워야 하는 순간부터, 말로 제어하려던 본래 의도가 절반쯤 무너진다.

그래서 단축어의 온디바이스 AI(Apple Intelligence)를 끼워 넣었다. 자연어를 모델이 먼저 해석하고, 그 결과를 기기 제어 명령으로 넘기는 구조로 바꾼 것이다. 바로 그 지점에서 진짜 문제가 드러났다.

자연어를 서버가 곧장 실행하면 무엇이 실행될지 모른다

자연어 해석 기능을 붙이면서, 해석된 결과가 서버에서 그대로 실행되는 경로가 생겼다. 문제는 그 순간 어떤 동작이 실제로 일어날지 미리 알 수 없다는 점이다.

같은 문장이라도 모델의 버전이나 컨텍스트에 따라 의미가 달라진다. 예를 들어 “전부 꺼”라는 문장은 해석에 따라 포함 범위가 달라질 수 있다. 입력을 받아 곧장 실행하는 구조는 결국 입력 자체를 신뢰해야 하는데, 자연어는 그중에서도 가장 신뢰하기 어려운 형태의 입력이다.

이 지점에서 두 번째 막힘이 생겼다. 그리고 이 막힘을 풀어가는 과정 끝에 IntentCP의 구조에 도달했다.

해석(폰)과 실행(서버) 사이에 검증 가능한 형식을 끼웠다

결론은 다음과 같다. 해석과 실행을 분리하고, 그 사이에 검증 가능한 중간 형식을 둔다.

폰의 Apple Intelligence와 iOS 단축어는 자연어를 ‘Control URL’이라는 정해진 한 줄 주소 형식으로 먼저 변환한다. 서버는 이 형식만 받으며, 형식에 정의된 동작만 수행한다. 자연어 자체가 서버 입구까지 들어오는 일은 없다. 입구에는 이미 정규화된 한 줄만 도착한다.

폰 (해석) 서버 (실행)

Siri 음성 단축어 자동화 Control URL 정규화된 한 줄 형식 검증 정의된 동작만 기기 정의되지 않은 형식은 실행 경로 자체가 없다

이 한 줄 형식이 전체 설계의 축이다. 자연어 해석은 폰에서 끝나며, 서버에 도착할 때는 이미 ‘거실등 켜기’ 같은 약속된 형식으로 정리된 상태다.

정의되지 않은 형식은 실행 경로 자체가 없다. 의도가 모호하거나 모델이 엉뚱하게 해석해도 통제 범위를 벗어나지 않는다. 입력 검증을 모델의 판단이 아니라 형식의 존재 여부로 강제한 셈이다.

이 방식에는 부수 효과로 호출 경로가 하나로 통합되는 결과가 있다. Siri 음성이든 단축어 자동화든 결국 같은 Control URL을 만들어 전달한다. 따라서 입력 출처에 관계없이 동일한 제약과 실행 절차를 거친다. 이 포맷을 통해 처리하는 동작은 클라우드 스마트홈 기기의 켜기·끄기, 밝기 조정, 상태 조회, 그리고 여러 동작을 묶는 시퀀스다. 기기 응답은 다시 폰의 LLM이 사람이 읽을 한 줄로 요약한다. 이때 LLM은 실행 권한이 없는 마지막 단계에만 위치한다.

권한을 가진 코어에는 LLM을 두지 않는다

요약하면 해석은 양 끝에 두고, 실행은 가운데에 둔다. 폰에서 입력을 해석하고 응답을 요약하는 일은 LLM이 맡지만, 실제로 기기를 제어할 권한을 가진 코어 내부에는 LLM이 들어가지 않는다.

입력 해석 LLM · 권한 없음 실행 코어 형식 검증 · 권한 보유 응답 요약 LLM · 권한 없음

권한이 있는 가운데에는 LLM이 없다

해석은 양 끝, 실행은 가운데

이렇게 구조를 나누자 초기에 부딪혔던 두 가지 제약도 함께 풀렸다. 서버가 자연어를 해석하지 않으니 서버 자체는 모델을 둘 필요가 없다. GPU도, 상시 가동되는 LLM 서버도 없이 동작한다.

코어는 Python과 FastAPI로 짠 REST 서버다. 해석의 부담을 전부 폰에 넘겼기 때문에 코어가 하는 일은 하나, 도착한 Control URL의 형식을 검증하고 스마트홈 기기로 명령을 전달하는 것뿐이다. 이 구조 덕분에 저전력 미니 서버에서도 GPU 없이 24시간 유지된다. 저장소에는 설정과 테스트용 웹 패널, 운영용 CLI를 담았고, 코어 서버·단축어 배포·프롬프트 구성을 하나의 monorepo로 묶어 띄움 비용을 줄였다. 집에 고성능 LLM이 없어도 누구나 직접 올릴 수 있게 하는 것, 그것이 ‘가벼움’의 핵심 목표였다.

뒤늦게 깨달은 점이 하나 있다. 자연어 처리를 서버에서 걷어내고 실행 직전에 형식을 강제하는 판단은 보안 영역에서 신뢰되지 않는 입력에 경계를 두던 습관 그대로였다. 신뢰할 수 없는 입력을 실행 직전 정해진 형식으로 묶는 발상은 익숙한 개념이다. 그 방식을 AI 기기 제어에 가져오니 같은 구조가 겹쳐 보였을 뿐이다. 이는 처음부터 보안을 노린 설계가 아니라 시행착오 끝에 드러난 결과다. 막혀 있던 흐름을 풀다 보니 익숙한 원리에 닿게 된 것이다.

매일 쓰는 자취 자동화로 검증한다

2025년 12월 8일 GitHub에 공개했다. 이후 유튜브 채널 영상에 노출된 뒤 2026년 5월 기준으로 22개의 stars를 얻었다. 프로덕션 규모도 아니고, 실사용자 트래픽이 있는 서비스도 아니다.

영상은 유튜브 “자취남” 채널의 “IOT 천재의 집” 편(2026.01.30 게시, 조회수 약 40만)에서 비전문가에게 직접 시연한 내용이다. 코드 입력 없이 “자연어로 말하면 → 안전한 실행 포맷으로 변환 → 서버가 정의된 동작만 수행”하는 구조를 설명하고, 실제 동작 화면을 보여줬다.

검증이라 부를 수 있는 건 하나뿐이다. 지금도 내 자취방 자동화를 통해 매일 사용하고 있다는 점이다. 형식을 강제하는 구조가 실제 거실의 조명이나 전원을 켜고 끄는 일을 막힘없이 견디고 있다. 개인 오픈소스의 유효성은 결국 만든 사람이 계속 그것을 쓰느냐에 달려 있다.

저장소는 github.com/je-empty/IntentCP 에 있다.