"""LLM 이 들어가는 자리. ★ 규칙: **이 패키지 밖에서 LLM API 를 직접 부르지 않는다.** `generativelanguage.googleapis.com` · `api.perplexity.ai` 같은 주소가 다른 파일에 나타나면 그건 이 규칙을 어긴 것이다. 한 곳에만 있어야 재시도·타임아웃·인증·비용을 한 번만 고치면 되고, "우리가 LLM 을 몇 번 부르는가"를 세는 자리도 하나가 된다. 실제로 한때 Gemini 호출 코드가 vision 용·copy 용 두 벌로 복사돼 있었다. 타임아웃을 바꾸려면 두 곳을 찾아야 했고, 한쪽만 고치면 조용히 갈렸다. ★ LLM 기능 하나는 네 겹으로 나뉜다. 고칠 것이 생기면 **그 겹으로 바로 간다**: 무엇을 묻는가 services/prompts/<기능>.py 프롬프트·응답 스키마 어떻게 부르는가 services/llm/<제공자>.py ← 여기 (HTTP·재시도·비용) 답을 어떻게 믿는가 services/grounding/<기능>.py 근거 검증·필터 무엇을 돌려주는가 services/external/<기능>.py 위 셋을 엮어 결과를 만든다 예) "FAQ 답이 이상하다" 는 물음은 이렇게 갈린다 — 질문을 잘못 시켰나 → prompts/copy.py 멀쩡한 답이 반려됐나 → grounding/copy.py 호출이 실패·지연되나 → llm/gemini.py 결과를 잘못 엮었나 → external/gemini_text.py """