← Docs hub

Cloud LLM Integration Source Guide

이 문서는 On-device Agent와 Cloud LLM Lambda가 어떤 계약으로 연결되는지 설명합니다. 핵심은 Cloud LLM이 제품 기능을 직접 실행하지 않고, Case 구조와 rewrite_query를 통해 다시 온디바이스 기능 라우팅으로 들어온다는 점입니다.

1. 관련 저장소와 파일

Cloud integration source

On-device Agent

파일 역할
ForegroundService.kt Cloud 호출 진입, request message 구성, response 처리, 로컬 재진입
ChatRepository.kt Cloud API HTTP 호출
NetworkModule.kt 네트워크 모듈/클라이언트 구성
LLM_PROMPT_ko.text, LLM_PROMPT_en.text 온디바이스에서 Cloud로 보내는 system prompt

Cloud LLM Lambda

파일 역할
lambda_function.py Lambda handler, body 파싱, 응답 포맷 래핑
gemini/gemini_full_rag_api.py Gemini RAG 전체 경로
gemini/gemini_file_rag_api.py File RAG
gemini/gemini_rag_judge_api.py 최신 정보/RAG 필요 여부 판단
gemini/gemini_gsearch_rag_api.py Google Search 기반 Web RAG
gemini/search_keyword_generator.py 검색 키워드 생성
gemini/prompt_formatting.py prompt/message 포맷 보조

2. Cloud 호출 진입 조건

2. Cloud 호출 진입 조건

On-device에서 Cloud LLM은 대표적으로 아래 상황에서 호출됩니다.

1. `isCloudContinue == true`이고 Wi-Fi 연결됨
2. 로컬 `processLLAMA()` 결과가 `error_answer`이고 Wi-Fi 연결됨
3. 특정 기능 토큰에서 `foregroundService.tossToCloudLlm()`를 호출하는 분기
4. 시간/일부 지식성 질의처럼 Cloud 위임 경로가 구현된 경우

Cloud 호출 전에는 아래 상태가 기록됩니다.

setLlmStatus(STATE_CLOUD_LLM_RUN)
Detected <sk_19>, switching to cloud LLM API
REQ size=...
REQ token_estimate=...
send json: ...

3. 요청 메시지 구조

Cloud request 구성

callCloudLLMAPI()는 system message를 세 덩어리로 분리합니다.

1. personaSystemMessage
   - loadPrompt()
   - LLM_PROMPT_ko/en 또는 외부 prompt 파일

2. informationSystemMessage
   - Date
   - Time
   - DayOfWeek
   - TimeZone

3. environmentSystemMessage
   - Weather data
   - Current Location
   - Humidity
   - Temperature low/high
   - PM10 / PM2.5

4. currentUserMessage
   - originalSttResult 기반 user content

요청 JSON 개념:

{
  "request_type": "chat.completions",
  "model": "gpt-4o-mini",
  "max_tokens": 2048,
  "stream": false,
  "temperature": 0,
  "top_p": 1,
  "device_id": "DEVICE_SERIAL",
  "response_format": {"type": "json_object"},
  "messages": [
    {"role": "system", "content": "Persona..."},
    {"role": "system", "content": "#Information..."},
    {"role": "system", "content": "#Environment..."},
    {"role": "user", "content": "사용자 STT 원문"}
  ]
}

4. Case 응답 계약

Case 응답 계약

Case 1

일반 답변입니다. 제품 기능 실행 없이 Cloud 응답을 TTS로 말합니다.

{
  "case": 1,
  "response": "답변 문장",
  "there_is_question_mark": false
}

there_is_question_mark == true이거나 response가 ?로 끝나면 Cloud continue 상태가 유지됩니다.

Case 2

제품 기능 재해석입니다. Cloud가 직접 Device API를 호출하지 않고 rewrite_query를 만듭니다.

{
  "case": 2,
  "function": "Air quality map",
  "available_function": "check for status",
  "rewrite_query": "Check the air quality map history, please"
}

On-device 처리:

1. 현재 user turn을 conversationHistory에서 제거
2. resetMultiturn()
3. resetCloudMultiturn()
4. runCloudResolvedQueryThroughLocalPipeline(rewrite_query)
5. processLLAMA(rewrite_query)
6. 딕셔너리/로컬 LLM이 다시 `<sk_xx>` 생성

Case 3

준비 질문 번호 기반 응답입니다. 일부 번호는 로컬 string resource로 즉시 답변하고, 그 외에는 getRewriteQuery()로 문장화해 로컬 재진입합니다.

Case 4

미지원 기능 또는 음성 미지원 안내입니다. 보통 Cloud 응답을 그대로 TTS로 사용합니다.

5. Cloud RAG 흐름

RAG 선택 기준

Cloud Lambda 기본 구조는 아래와 같이 설명합니다.

lambda_handler
  ├─ request body 파싱
  ├─ CloudLLMRequest 구성
  ├─ full_rag()
  │   ├─ 기본 Gemini 응답 후보
  │   ├─ RAG 필요 여부 판단
  │   ├─ File RAG 후보
  │   ├─ Web Search RAG 후보
  │   └─ 최종 응답 선택
  └─ OpenAI ChatCompletion 스타일로 반환

Cloud 운영에서 중요한 점:

RAG는 제품 기능 실행을 위한 경로가 아닙니다.
RAG는 최신성/외부 지식/문서 기반 답변 품질을 높이는 경로입니다.
제품 기능 실행은 Case 2 -> rewrite_query -> 온디바이스 재진입으로 처리해야 합니다.

말레이시아 Custom RAG 확인 항목:

항목 확인 기준
문서셋 현지 FAQ, 고객센터, 보증, 앱 사용법, 국가별 제한 기능 포함 여부
검색 기준 File RAG와 Web Search가 필요한 질문을 분리했는지
제품 기능 분리 기능 실행 요청을 RAG 답변으로 처리하지 않는지
근거성 답변이 현지 문서에 없는 내용을 추정하지 않는지
최신성 연락처/요금/정책은 문서 버전 또는 Web Search 필요 여부를 기록하는지

6. 테스트 판정 기준

6. 테스트 판정 기준

Cloud 테스트는 아래 네 가지를 동시에 봐야 합니다.

항목 정상 기준
Case 의도에 맞는 case가 나와야 함
response 사용자에게 바로 말해도 되는 문장이어야 함
rewrite_query 온디바이스 딕셔너리에서 기대 토큰으로 매칭 가능해야 함
there_is_question_mark 추가 질문이 필요한 경우에만 true여야 함

7. 대표 장애 분석

7. 대표 장애 분석

Cloud Case는 맞지만 온디바이스 실행 실패

Cloud: case=2, rewrite_query 정상처럼 보임
On-device: parsedLlamaResponse가 error_answer

원인 후보:

1. rewrite_query 표현이 온디바이스 딕셔너리에 없음
2. 영어 rewrite_query가 너무 일반적임
3. Cloud가 기능명을 바꿔서 표현함
4. On-device dictionary가 한국어 위주로만 보강됨

개선:

Cloud prompt에 rewrite_query 표현을 온디바이스 dictionary 기준으로 제한합니다.
동시에 온디바이스 contains_token에 Cloud rewrite 표현을 positive case로 추가합니다.

Cloud가 Case 1로 답변해버림

사용자: 공기질 맵 히스토리 보여줘
Cloud: case=1, response="공기질 맵은..."

원인 후보:

제품 기능 실행 요청을 일반 설명 요청으로 분류했습니다.
Cloud prompt의 function router 예시/우선순위가 부족합니다.

개선:

제품 기능 요청은 Case 2로 보내고, Cloud가 직접 실행한 것처럼 말하지 않도록 prompt에 제약을 추가합니다.

8. Cloud 테스트 리포트 필수 필드

8. Cloud 테스트 리포트 필수 필드

입력 발화:
언어:
On-device originalSttResult:
Cloud request messages 요약:
Cloud response raw:
case:
response:
rewrite_query:
prepared_question_list_number:
there_is_question_mark:
온디바이스 재진입 토큰:
최종 TTS:
판정:
개선 필요 위치:

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date