From fea0323d5ed6f72a923296346305bb1c0a90e38e Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 9 Oct 2026 14:16:11 +0900 Subject: [PATCH 1/2] Log Gemini chat request failures --- B01_Dashboard/B01_Dashboard_Knowledge_Chat.py | 27 ++++++++++++++++++- resources/tester/test_b01_knowledge_chat.py | 5 +++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py b/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py index 6ada34528..e6755349c 100644 --- a/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py +++ b/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py @@ -1,10 +1,13 @@ """지식DB Markdown 검색과 Gemini 설명. 제외 폴더는 읽지 않는다.""" import asyncio +import logging import os import re +import time from functools import lru_cache from pathlib import Path +from uuid import uuid4 import httpx from fastapi import APIRouter, Depends, HTTPException @@ -16,6 +19,7 @@ router = APIRouter(prefix="/knowledge-chat", tags=["B01_KnowledgeChat"]) KNOWLEDGE = Path(__file__).resolve().parents[1] / "resources" / "knowledge" EXCLUDED = ("실무문서", "stmate", "다산소프트", "technical_info") MODEL = "gemini-3.8-flash" +logger = logging.getLogger(__name__) class ChatRequest(BaseModel): @@ -149,6 +153,8 @@ async def ask_knowledge_chat(payload: ChatRequest, _session=Depends(verify_sessi f"질문: {payload.question}" ) ) + request_id = uuid4().hex[:8] + started = time.monotonic() try: async with httpx.AsyncClient(timeout=30) as client: for attempt in range(3): @@ -157,13 +163,23 @@ async def ask_knowledge_chat(payload: ChatRequest, _session=Depends(verify_sessi headers={"x-goog-api-key": key}, json={"contents": [{"parts": [{"text": prompt}]}]}, ) + if response.status_code >= 400: + logger.warning( + "Gemini request failed id=%s model=%s attempt=%d status=%d elapsed=%.1fs prompt_chars=%d", + request_id, + MODEL, + attempt + 1, + response.status_code, + time.monotonic() - started, + len(prompt), + ) if response.status_code != 503 or attempt == 2: break await asyncio.sleep(attempt + 1) if response.status_code == 503: raise HTTPException( status_code=503, - detail="Gemini 모델에 요청이 몰려 있습니다. 잠시 후 다시 질문해 주세요.", + detail=f"Gemini 모델에 요청이 몰려 있습니다. 잠시 후 다시 질문해 주세요. (문의번호 {request_id})", ) response.raise_for_status() answer = "".join( @@ -180,12 +196,21 @@ async def ask_knowledge_chat(payload: ChatRequest, _session=Depends(verify_sessi }.get(exc.response.status_code, "Gemini 요청에 실패했습니다. 잠시 후 다시 시도해 주세요.") raise HTTPException(status_code=502, detail=detail) from exc except httpx.TimeoutException as exc: + logger.warning( + "Gemini request timed out id=%s elapsed=%.1fs", request_id, time.monotonic() - started + ) raise HTTPException( status_code=504, detail="Gemini 3.8 Flash 응답이 지연되어 시간 초과됐습니다. " "잠시 후 다시 시도해 주세요.", ) from exc except (httpx.RequestError, ValueError) as exc: + logger.warning( + "Gemini request error id=%s type=%s elapsed=%.1fs", + request_id, + type(exc).__name__, + time.monotonic() - started, + ) raise HTTPException( status_code=502, detail="Gemini 서버에 연결하지 못했습니다. 잠시 후 다시 시도해 주세요.", diff --git a/resources/tester/test_b01_knowledge_chat.py b/resources/tester/test_b01_knowledge_chat.py index fb647702e..5d7e6a1c5 100644 --- a/resources/tester/test_b01_knowledge_chat.py +++ b/resources/tester/test_b01_knowledge_chat.py @@ -36,7 +36,7 @@ def test_missing_api_key_is_reported_before_search(monkeypatch): assert error.value.status_code == 503 -def test_busy_gemini_is_retried_and_reported(monkeypatch): +def test_busy_gemini_is_retried_and_reported(monkeypatch, caplog): monkeypatch.setenv("GEMINI_API_KEY", "test-key") monkeypatch.setattr(chat, "search", lambda _question: []) calls = [] @@ -64,6 +64,9 @@ def test_busy_gemini_is_retried_and_reported(monkeypatch): asyncio.run(chat.ask_knowledge_chat(chat.ChatRequest(question="일위대가가 뭐야"), {})) assert len(calls) == 3 assert "요청이 몰려" in error.value.detail + assert [f"attempt={n} status=503" in caplog.text for n in (1, 2, 3)] == [True] * 3 + assert "test-key" not in caplog.text + assert "일위대가가 뭐야" not in caplog.text def test_gemini_timeout_is_reported(monkeypatch): From 974c7e6cb2173751e03b4cdb4b154a9b79b552f8 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 9 Oct 2026 14:31:12 +0900 Subject: [PATCH 2/2] Lower Gemini chat thinking level --- B01_Dashboard/B01_Dashboard_Knowledge_Chat.py | 5 ++++- resources/tester/test_b01_knowledge_chat.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py b/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py index e6755349c..cea3a1c2a 100644 --- a/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py +++ b/B01_Dashboard/B01_Dashboard_Knowledge_Chat.py @@ -161,7 +161,10 @@ async def ask_knowledge_chat(payload: ChatRequest, _session=Depends(verify_sessi response = await client.post( f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL}:generateContent", headers={"x-goog-api-key": key}, - json={"contents": [{"parts": [{"text": prompt}]}]}, + json={ + "contents": [{"parts": [{"text": prompt}]}], + "generationConfig": {"thinkingConfig": {"thinkingLevel": "low"}}, + }, ) if response.status_code >= 400: logger.warning( diff --git a/resources/tester/test_b01_knowledge_chat.py b/resources/tester/test_b01_knowledge_chat.py index 5d7e6a1c5..be1d819c6 100644 --- a/resources/tester/test_b01_knowledge_chat.py +++ b/resources/tester/test_b01_knowledge_chat.py @@ -135,11 +135,13 @@ def test_chat_searches_all_knowledge_markdown_except_excluded_folders(monkeypatc async def post(self, url, *, headers, json): sent["prompt"] = json["contents"][0]["parts"][0]["text"] + sent["thinking_level"] = json["generationConfig"]["thinkingConfig"]["thinkingLevel"] return Response() monkeypatch.setattr(chat.httpx, "AsyncClient", Client) result = asyncio.run(chat.ask_knowledge_chat(chat.ChatRequest(question="임도 기준"), {})) assert result["answer"] == "설명 [1]" + assert sent["thinking_level"] == "low" paths = {source["path"] for source in result["sources"]} assert paths == {"original/법률/현행.md"} assert "실무문서" not in sent["prompt"]