From f7b9cb22f0357e4a9bc6e934a028c6d0d2330b71 Mon Sep 17 00:00:00 2001 From: KimDongAn Date: Tue, 29 Sep 2026 15:52:24 +0900 Subject: [PATCH] =?UTF-8?q?feat(llm):=20=ED=99=94=EB=AC=BC=20=ED=98=BC?= =?UTF-8?q?=EC=9E=AC=20=EC=8B=AC=EC=82=AC=20=EC=A0=84=EC=9A=A9=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20SAFETY=5FLLM=5FMODEL=20(=EB=B9=84=EC=9A=B0=EB=A9=B4?= =?UTF-8?q?=20LLM=5FMODEL)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /safety/assess 는 화물 특성·체크리스트만 LLM 이라 작은 모델로 응답 시간을 줄인다. 종합 판정(LLM_MODEL)·챗봇(CHATBOT_LLM_MODEL)은 그대로. Co-Authored-By: Claude Opus 5.5 --- .env.example | 2 ++ app/api/v1/safety.py | 4 ++-- app/config.py | 3 +++ app/core/deps.py | 5 +++++ app/llm/factory.py | 16 +++++++++++++++- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index add7425..7e2e50b 100644 --- a/.env.example +++ b/.env.example @@ -22,6 +22,8 @@ LLM_PROVIDER=openai LLM_MODEL=gpt-4.1-mini # 챗봇만 쓰는 모델(같은 provider). 비우면 LLM_MODEL. 도구를 고르는 에이전트라 nano 로는 불안정하다. CHATBOT_LLM_MODEL=gpt-4.1-mini +# 화물 혼재 심사(/safety/assess)만 쓰는 모델. 비우면 LLM_MODEL. 서술(화물 특성·체크리스트)만 LLM 이라 nano 로 충분. +SAFETY_LLM_MODEL=gpt-4.1-nano # ── 공공 API ─────────────────────────────────────────────────────────────── KMA_API_KEY= diff --git a/app/api/v1/safety.py b/app/api/v1/safety.py index 26520a0..a31c414 100644 --- a/app/api/v1/safety.py +++ b/app/api/v1/safety.py @@ -7,7 +7,7 @@ SafetyVerdict, ) from app.agents.safety.service import assess_safety, assess_verdict -from app.core.deps import get_llm_client, get_session +from app.core.deps import get_safety_llm_client, get_session from app.core.exceptions import LLMGenerationError, MsdsNotFoundError, MsdsUpstreamError from app.llm.base import LLMClient from app.neo4j_client import neo4j_client @@ -57,7 +57,7 @@ async def assess( request: SafetyAssessmentRequest, db: AsyncSession = Depends(get_session), - llm_client: LLMClient = Depends(get_llm_client), + llm_client: LLMClient = Depends(get_safety_llm_client), ) -> SafetyAssessmentResult: try: return await assess_safety(db, neo4j_client.driver, llm_client, request) diff --git a/app/config.py b/app/config.py index 99e31fb..8a4c4f9 100644 --- a/app/config.py +++ b/app/config.py @@ -35,6 +35,9 @@ class Settings(BaseSettings): # 고르는 에이전트라(27번 설계안 C단계) 작은 모델로는 도구 선택이 불안정하고, 판정 잡은 # 결과가 바뀔 때만 LLM 을 부르므로 작은 모델로 충분해 둘을 나눈다. chatbot_llm_model: str | None = None + # [2026-09-29] 화물 혼재 심사(POST /safety/assess)만 쓰는 모델. 비우면 llm_model. 등급은 규칙엔진이 + # 정하고 LLM 은 화물 특성·체크리스트만 쓰므로 작은 모델로 응답 시간을 줄인다. + safety_llm_model: str | None = None # 임베딩은 llm_provider와 독립적으로 고른다. 챗봇 RAG의 벡터 공간은 적재 # 시점(scripts/embed_msds.py)과 조회 시점이 반드시 같은 모델이어야 하는데, # llm_provider는 답변 품질/비용 사정으로 자유롭게 바뀔 수 있기 때문이다. diff --git a/app/core/deps.py b/app/core/deps.py index e211047..8404fc0 100644 --- a/app/core/deps.py +++ b/app/core/deps.py @@ -7,6 +7,7 @@ from app.llm.factory import get_chatbot_llm_client as _get_chatbot_llm_client from app.llm.factory import get_embedding_client as _get_embedding_client from app.llm.factory import get_llm_client as _get_llm_client +from app.llm.factory import get_safety_llm_client as _get_safety_llm_client async def get_session(session: AsyncSession = Depends(get_db)) -> AsyncSession: @@ -21,5 +22,9 @@ def get_chatbot_llm_client() -> LLMClient: return _get_chatbot_llm_client() +def get_safety_llm_client() -> LLMClient: + return _get_safety_llm_client() + + def get_embedding_client() -> EmbeddingClient: return _get_embedding_client() diff --git a/app/llm/factory.py b/app/llm/factory.py index fe3142f..8011d14 100644 --- a/app/llm/factory.py +++ b/app/llm/factory.py @@ -36,8 +36,22 @@ def get_chatbot_llm_client() -> LLMClient: provider 는 get_llm_client 와 같다 — 챗봇만 다른 provider 를 쓸 이유가 아직 없다. """ settings = get_settings() - model = settings.chatbot_llm_model or settings.llm_model + return _client_for(settings.chatbot_llm_model or settings.llm_model) + +@lru_cache +def get_safety_llm_client() -> LLMClient: + """화물 혼재 심사(POST /safety/assess)용 LLMClient. safety_llm_model 이 있으면 그 모델, 없으면 llm_model. + + [2026-09-29] 종합 문장 품질 때문에 llm_model 을 mini 로 올리자 혼재 심사 화면(화물 특성·체크리스트만 + LLM)이 느려졌다 — 등급은 규칙엔진이 정하므로 이 서술은 작은 모델로 충분하다. + """ + settings = get_settings() + return _client_for(settings.safety_llm_model or settings.llm_model) + + +def _client_for(model: str) -> LLMClient: + settings = get_settings() if settings.llm_provider == "gemini": if not settings.gemini_api_key: raise RuntimeError("GEMINI_API_KEY가 설정되지 않았습니다 (.env 확인).")