23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
최근 삼성과 애플 같은 주요 모바일 제조사들이 AI 기술을 활용한 다양한 기능을 선보이면서, 모바일 환경에서의 AI 활용에 대한 관심이 크게 높아지고 있습니다.
특히 주목받는 것은 서버와 별도로 통신할 필요 없이 모바일 기기의 자원만으로 AI 기술을 활용할 수 있는 On-Device AI 기능입니다.
삼성의 Galaxy AI, 애플의 Apple Intelligence 같은 기능들이 좋은 예시입니다.
구글의 MediaPipe나 애플의 Core ML과 같은 프레임워크들이 이런 추세를 뒷받침하고 있습니다.
빅테크 기업들도 On-Device AI용 모델을 꾸준히 공개하며, 이 분야가 모바일 환경에서 얼마나 중요한 영역인지를 보여주고 있습니다.
물론 기기의 처리 능력 한계로 인해 복잡한 AI 모델을 실행하는 데 제약이 있지만, 칩셋 기술의 발전과 더 효율적인 AI 모델 개발로 이런 간극이 점점 좁아지고 있습니다.
이번 글에서는 에이닷 오토 차량제어 기능에 On-Device AI를 활용한 경험을 여러분과 공유하려고 합니다.
오늘날 모바일에서 에이닷, 구글 어시스턴트와 같은 어시스턴트 앱을 다양한 상황에서 편리하게 사용하는 것이 우리에게 익숙한 일상이 되었습니다.
안드로이드 오토모티브 OS가 설치된 차량에서도 모바일과 동일하게 어시스턴트 앱을 사용할 수 있습니다.
이에 차량에서도 모바일과 같이,
보다 편리한 사용자 경험을 제공하기 위해 개발 중인 차량용 어시스턴트 에이닷 오토는 다양한 차량 제조사와의 계약 및 요구사항 논의를 진행하고 있습니다.
On-Device로 동작하는 STT(Speech-to-Text), LLM(Large Language Model), TTS(Text-to-Speech) 에 대한 요구사항도 지속적으로 받고 있는 상황입니다.
On-Device AI의 발전은 네트워크가 오프라인 상태에서도 온라인과 동일한 기능을 구현할 수 있는 가능성을 열어주고 있습니다.
이에 따라 상용화를 목표로 개발을 진행하고 있으며, 가장 먼저 대표 기능인 차량 제어에 On-Device AI를 적용해 보려고 합니다.
현재 에이닷 오토는 서버 베이스로 동작하고 있으며, 차량제어 기능은 다음과 같은 순서로 동작합니다:
사용자가 차량제어 관련 음성 명령을 하면 앱은 서버(플랫폼)로부터 차량제어 관련 응답을 받습니다.
이 응답에서 차량제어에 필수적인 propertyName, areaName, value 값을 추출합니다.
앱의 Adaptation Layer에서 이 값들을 현재 차량 환경에 맞게 재구성합니다.
재구성된 값을 Car Service API에 매개변수로 전달하여 호출합니다.
이 과정에서 1번 단계, 즉 서버(플랫폼)의 역할을 LLM과 프롬프팅을 활용하여 On-Device AI로 대체해보겠습니다.
이를 위해서는 LLM에 사용자의 명령을 전달하고, 여기서 propertyName, areaName, value 정보를 추출할 수 있어야하기때문에 LLM으로부터 얻고자 하는 정보를 다음과 같은 JSON 형식으로 정의하겠습니다:
LLM의 기대 응답
{
"propertyName" : "제어하려는 기능의 이름",
"areaName" : "제어하려는 기능의 위치",
"value" : "설정하려는 값"
}이 글에서는 MediaPipe를 활용하여 On-Device LLM을 사용해보겠습니다.
구글은 MediaPipe 라이브러리를 통해 안드로이드 환경에서도 On-Device AI용 LLM을 쉽게 활용할 수 있도록 지원하고 있습니다.
공식 문서와 예제가 잘 정리되어 있어 개발 환경을 구성하는 데 큰 어려움은 없습니다.특히 다음 자료들이 많은 도움이 됩니다:
위 자료들을 참고하면 기본적인 설정은 충분히 따라 할 수 있으므로, 이 글에서는 환경 설정과 코드 구성에 대한 자세한 설명은 생략하겠습니다.
다양한 LLM 중 별도의 변환 과정 없이 MediaPipe 라이브러리를 이용해 바로 사용할 수 있는 gemma2-2b-it-gpu-int8.bin 모델을 사용해 보겠습니다.
아래의 테스트는 모두 Galaxy S23(Android 13) 환경에서 수행되었습니다.
먼저 모델에 기본적인 정보를 제공하기 위해 Instruction을 작성합니다.
Instruction은 크게 네 부분으로 구성했습니다:
모델의 역할을 정의하는 base instruction
제어하려는 기능의 이름 propertyName
제어하려는 기능의 위치 areaName
기대하는 응답 형식을 나타낸 JSON 형식 response json format
Instruction
### Instruction:
[base instruction]
너는 차량제어를 담당하는 agent 야.
차량에 존재하는 property 중 <available propertyName> 에 있는 기능만 제어할 수 있어.
각 기능들은 제어 가능한 area 가 존재하는데,
area 는 <available areaName> 에 있는 area 만 제어할 수 있어.
요청에 대한 결과는 반드시 아래 <response json format> 과 동일한 형식의 valid json format 으로 응답해줘.
[available propertyName]
- HVAC_POWER_ON
- HVAC_RECIRC_ON
- HVAC_TEMPERATURE_SET
- HVAC_SEAT_TEMPERATURE
- HVAC_STEERING_WHEEL_HEAT
- HVAC_MAX_DEFROST_ON
[available areaName]
- ALL
- SEAT_ROW_1_LEFT
- SEAT_ROW_1_RIGHT
- SEAT_ROW_2_LEFT
- SEAT_ROW_2_CENTER
- SEAT_ROW_2_RIGHT
[response json format]
{
"propertyName" : "",
"areaName" : "",
"value" : "",
}LLM Response
히터 꺼줘 {"propertyName": "HVAC_MAX_DEFROST_ON","areaName": "ALL","value ": "off"}
에어컨 켜줘 {"propertyName": "HVAC_POWER_ON ","areaName ": "ALL ","value": "true"}
공기순환기 켜줘 {"propertyName": "HVAC_RECIRC_ ON","areaName": " ALL","value ": "true"}
온도 30도 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName ": "ALL ","value": "30"}
온도 올려줘 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "20"}
온도 내려줘 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "20"}
핸들열선 켜줘 {"propertyName": "HVAC_STEERING_WHEEL_HEAT ","areaName": "ALL ","value": "ON"}
열선 켜줘 {"propertyName": "HVAC_POWER_ON ","areaName": "ALL ","value": "true"}
성애제거 켜줘 {"propertyName": "HVAC_MAX_DEFROST_ON","areaName": " ALL","value ": "on"}LLM 에 해당 Instruction 과 함께 차량제어 관련 요청을 해본 결과 위과 같이 응답하는것을 확인할 수 있었습니다.
간단한 형식의 요청이지만 Instruction과 요청을 한글로 작성했고, 별도의 파인 튜닝 없이 기본 모델을 사용한 것치고는 괜찮은 수준의 응답인 것 같습니다.
하지만 이 응답에는 몇 가지 개선이 필요합니다.
먼저, propertyName이 기대한 것과 다르게 응답하는 부분입니다.
'히터 꺼줘' 라는 요청의 경우, 제어하려는 property는 공조기 전원에 해당하는 HVAC_POWER_ON이어야 합니다.
마찬가지로, '열선 켜줘' 라는 요청의 경우, 제어하려는 property는 좌석의 열선에 해당하는 HVAC_SEAT_TEMPERATURE이어야 합니다.
Instruction에 propertyName 관련 설명을 추가하여 다시 결과를 확인 해 보겠습니다.
Instruction
...
[available propertyName]
- HVAC_POWER_ON : 공조기(에어컨, 히터) 전원 제어.
- HVAC_RECIRC_ON : recirculator (공기순환) 전원 제어.
- HVAC_TEMPERATURE_SET : 공조기 온도 제어.
- HVAC_SEAT_TEMPERATURE : seat heat(열선, 좌석 열선, 시트 열선) 전원 제어.
- HVAC_STEERING_WHEEL_HEAT : steering wheel heat(핸들 열선) 전원 제어.
- HVAC_MAX_DEFROST_ON: max defroster(김서림제거) 전원 제어.
...LLM Response
히터 꺼줘 {"propertyName": "HVAC_POWER_ON ","areaName": "ALL ","value": "off"}
에어컨 켜줘 {"propertyName": "HVAC_POWER_ON ","areaName": "ALL ","value": "ON"}
공기순환기 켜줘 {"propertyName": "HVAC_RECIRC_ ON","areaName": " ALL","value ": "ON"}
온도 30도 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "30"}
온도 올려줘 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "20"}
온도 내려줘 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "20"}
핸들열선 켜줘 {"propertyName": "HVAC_STEERING_WHEEL_HEAT ","areaName: : "ALL ","value": "ON"}
열선 켜줘 {"propertyName": "HVAC_SEAT_TEMPERATURE ","areaName ": "ALL ","value": "ON"}
성애제거 켜줘 {"propertyName": "MAX_DEFROST_ON", " areaName": "ALL", "value": "ON"}각 propertyName에 설명을 추가해 보니 '히터 꺼줘' 와 '열선 켜줘' 라는 요청에 대해 각각 HVAC_POWER_ON 와 HVAC_SEAT_TEMPERATURE 로 propertyName 이 기대한 결과로 응답되는 것을 확인했습니다.
이번에는 value를 살펴보겠습니다.
Test #1의 LLM Response를 살펴보면 전원 제어에 해당하는 요청에 대해 모델은 value에 boolean타입을 넣기도 하고, on/off 텍스트를 넣어 응답하기도 합니다.
또한 온도 제어의 경우 '올려줘' 또는 '내려줘' 라고 요청하면 예상치 못한 수치를 반환하기도 합니다.
이러한 불일치를 개선하기 위해, 모델이 응답하는 value의 형식을 통일하고 증가/감소에 대한 제어를 구분할 수 있도록 Instruction에 value 정보를 추가해 보겠습니다.
Instruction
...
[value]
요청이 켜기/끄기 또는 설정/해제 등의 전원 제어에 대한 요청일 경우, value 에는 ON/OFF 중 적절한 값을 선택해서 넣어줘.
전원을 켜는 요청일 경우에는 ON을, 전원을 끄는 요청일 경우에는 OFF를 넣어줘.
요청이 증가/감소 에 해당한다면 value에는 INCREASE 또는 DECREASE를 넣어줘.
증가 요청일 경우에는 INCREASE, 감소 요청일 경우에는 DECREASE를 넣어줘.
...LLM Response
히터 꺼줘 {"propertyName": "HVAC_POWER_ON ","areaName": "ALL ","value": "OFF"}
에어컨 켜줘 {"propertyName": "HVAC_POWER_ON ","areaName": "ALL ","value": "ON"}
공기순환기 켜줘 {"propertyName": "HVAC_RECIRC_ ON","areaName": " ALL","value ": "ON"}
온도 30도 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "30"}
온도 올려줘 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "INCREASE"}
온도 내려줘 {"propertyName": "HVAC_TEMPERATURE_SET ","areaName":ALL ","value": "DECREASE"}
핸들열선 켜줘 {"propertyName": "HVAC_STEERING_WHEEL_HEAT ","areaName: : "ALL ","value": "ON"}
열선 켜줘 {"propertyName": "HVAC_SEAT_TEMPERATURE ","areaName ": "ALL ","value": "ON"}
성애제거 켜줘 {"propertyName": "MAX_DEFROST_ON", " areaName": "ALL", "value": "ON"}Instruction에 value 관련 내용을 추가한 결과, 전원 제어 요청에 대해서는 value가 ON/OFF로, 증가/감소 요청에 대해서는 INCREASE/DECREASE로 응답하는 것을 확인할 수 있었습니다.
이렇게 기본적인 차량 제어 요청에 대해 모델이 원하는 데이터를 반환하는 것을 확인했지만, 여전히 가끔씩 예상치 못한 이상한 응답을 하는 경우가 있습니다.
이 경우, 모델에 기대하는 결과의 예시를 몇가지 제공하는것(Few Shot)을 통해 응답의 정확성과 일관성을 조금 더 개선할 수 있었습니다.
Instruction
첫번째 예시로,
'에어컨 켜줘' 라고 요청할 경우 '에어컨' 은 공조기 기능이므로 property_name 은 HVAC_POWER_ON 가 되고,
요청한 area 가 없을때는 모든 area 에 대한 제어요청으로 판단하고 area 에는 ALL 을 넣어줘.
'켜줘' 는 전원을 켜는 의미이므로 value 는 ON을 넣어줘.
이와 같은 이유로 '에어컨 켜줘' 에 대한 응답은 example1 for response json 과 같아야돼.
[example1 for response json]
{
"property_name" : "HVAC_POWER_ON",
"area" : "ALL",
"control_value" : "ON"
}
두번째 예시로,
'운전석 에어컨 온도 28도' 라고 요청한 경우 '에어컨 온도' 는 공조기 온도에 대한 기능이므로 property_name 은 HVAC_TEMPERATURE_SET 이 되고,
area 에는 '운전석' 에 해당하는 SEAT_ROW_1_LEFT 를, 28도를 요청했기 때문에 value 에는 28을 넣어줘.
이와 같은 이유로 '운전석 에어컨 온도 28도' 에 대한 응답은 example2 for response json 과 같아야돼.
[example2 for response json]
{
"property_name" : "HVAC_TEMPERATURE_SET",
"area" : "SEAT_ROW_1_LEFT",
"control_value" : "28"
}
세번째 예시로,
'에어컨 온도 내려줘' 라고 요청한 경우 '에어컨 온도' 는 공조기 온도에 대한 기능이므로 property_name 은 HVAC_TEMPERATURE_SET 이 되고,
요청한 area 가 없을때는 모든 area 에 대한 제어요청으로 판단하고 area 에는 ALL 을 넣어줘.
'내려줘' 라고 요청했으므로 value 에는 'DECREASE' 을 넣어줘.
만약 '올려줘' 라고 요청한다면 'INCREASE' 를 넣어줘.
이와 같은 이유로 '에어컨 온도 내려줘' 에 대한 응답은 example3 for response json 과 같아야돼.
[example3 for response json]
{
"property_name" : "HVAC_TEMPERATURE_SET",
"area" : "ALL",
"control_value" : "DECREASE"
}LLM Response
에어컨 켜줘 {"property_name" : "HVAC_POWER_ON", "area" : "ALL", "control_value" : "ON"}
운전석 에어컨 온도 28도 {"property_name" : "HVAC_TEMPERATURE_SET", "area" : "SEAT_ROW_1_LEFT", "control_value" : "28"}
에어컨 온도 내려줘 {"property_name" : "HVAC_TEMPERATURE_SET", "area" : "ALL", "control_value" : "DECREASE"}
동승석 열선 켜줘 {"property_name" : "HVAC_SEAT_TEMPERATURE", "area" : "SEAT_ROW_1_RIGHT", "control_value" : "ON"}
운전석 열선 켜줘 {"property_name" : "HVAC_SEAT_TEMPERATURE", "area" : "SEAT_ROW_1_RIGHT", "control_value" : "ON"}이렇게 몇 차례 프롬프트의 Instruction을 개선하며 테스트를 진행한 결과,
'운전석 열선 켜줘' 와 같은 요청에서 area 정보가 의도한 값으로 응답하지 않는 등의 한계점이 존재하지만 모델이 비교적 정확한 응답을 제공하는 것을 확인할 수 있었습니다.
On-Device AI 적용 과정에서 기본 Gemma 모델과 간단한 프롬프팅만으로도 괜찮은 수준의 응답을 기대할 수 있음을 확인했습니다.
이는 향후 서비스 개발 시 간단한 기능에 대해 부분적으로 On-Device AI를 적용할 수 있는 가능성을 보여줍니다.
다만 LLM은 본질적으로 동일한 요청에 대해 상황과 맥락에 따라 다양하게 응답하는 특성이 있습니다.
Instruction을 수정하더라도 유사한 요청을 반복하다 보면 때로는 다른 응답이나 의도치 않은 결과를 반환할 수 있으며,
token size의 제약으로 Instruction의 내용을 무제한으로 확장할 수 없다는 한계도 있습니다.
이러한 한계를 극복하기 위해서는 더욱 정교한 프롬프팅과 파인튜닝 과정이 필요합니다.
'에이닷 오토'의 On-Device AI 서비스 상용화를 위해서는 프롬프팅, 모델 파인튜닝, 그리고 모델 응답의 정확도와 성능 평가가 선행되어야 합니다.
이번 글에서는 On-Device AI 적용을 위한 프롬프팅 관련 내용을 공유 드렸습니다.
다음 기회에는 모델의 정확성을 높이기 위한 파인튜닝 과정에 대해 공유 드리겠습니다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.