System Settings
관리자가 서버를 내리지 않고도 시스템 핵심 파라미터를 즉시 조정할 수 있도록 만든 설정 관리 체계입니다.
배경과 목적
이 기능이 존재하는 이유
FLOPI는 이상탐지, AI Chat, RAG 검색, 워크플로우 등 다양한 AI 모듈이 동작하는 시스템입니다. 각 모듈에는 운영 상황에 따라 조정이 필요한 하이퍼파라미터가 있습니다 — LLM 응답 속도, 동시 탐지 수, 문서 검색 정밀도 같은 값들입니다.
이 값들을 관리자가 UI에서 즉시 변경할 수 있어야 합니다. 서버를 내리면 운영 중인 탐지 스케줄러까지 같이 중단되기 때문에, 무중단으로 설정을 반영하는 것이 핵심입니다.
관리 대상: 6개 카테고리, 20개 파라미터
모든 상수를 설정화하면 오히려 혼란을 초래합니다. "운영 중 실제로 조정이 필요한 값"만 선별하여 6개 카테고리로 구성했습니다.
| 카테고리 | 항목 수 | 대상 |
|---|---|---|
| LLM | 4개 | Timeout, Max Tokens, Temperature, Top P |
| 이상탐지 | 2개 | 동시 규칙 평가 수, 에이전트 최대 라운드 |
| AI Chat | 3개 | 도구 호출 라운드, 도구 후보 수, 도구 선택 전략 |
| RAG | 3개 | 청크 크기, 청크 겹침, 검색 결과 수 |
| 시스템 | 2개 | SQL 최대 행 수, 도구 모드 |
| 프롬프트 | 6개 | 시스템 프롬프트, 카테고리 프롬프트 5종 (재공/설비/물류/이상탐지/지식검색) |
설계 목표
- 무중단 반영 — 설정을 바꾸면 다음 동작부터 즉시 적용. 서버 재시작 불필요.
- 한 곳에서 관리 — 흩어진 파라미터를 한 화면에서 카테고리별로 정리.
- 실수 방지 — 타입 검증, 범위 제한으로 잘못된 값이 들어가지 않도록.
- 장애 내성 — 설정 시스템에 문제가 생겨도 기존 기본값으로 안전하게 동작.
- 모든 상수의 설정화 — 프롬프트, 색상, URL 같은 것까지 설정에 넣으면 관리자가 혼란스럽습니다. "운영 중 조정이 필요한 값"만 엄선했습니다.
- 설정 파일 방식 — 이미 DB + UI 체계가 있는 시스템에서 별도 YAML/JSON 파일은 이중 관리일 뿐입니다.
- 다중 프로필 — "개발/운영" 프로필 분리는 현재 단일 서버 환경에서 불필요한 복잡도입니다.
대안 검토
이 기능을 구현하는 방법은 여러 가지였습니다. 각 접근법의 장단점을 비교하고 최적안을 선택한 과정을 기록합니다.
방법 A: 환경변수 (.env)
장점
- 구현이 가장 단순
- 기존
config.py패턴과 일관 - Docker/K8s 배포 시 친숙
단점
- 서버 재시작 필수 — 핵심 목표 위반
- UI 없이 SSH로 .env 편집 필요
- 변경 이력 추적 불가
- 폐쇄망에서 SSH 접근 제한적
방법 B: 설정 파일 (YAML/JSON) + 파일 감시
장점
- 파일 변경 시 자동 리로드 가능 (watchdog)
- Git으로 설정 변경 이력 관리
- 사람이 읽기 편함
단점
- UI에서 파일 쓰기 = 보안 리스크
- 파일 감시 → 이벤트 지연 (최대 수초)
- 동시 쓰기 충돌 처리 필요
- 이미 DB + ORM이 있는데 또 다른 저장소
방법 C: DB + 인메모리 캐시 (채택)
장점
- 즉시 반영 — 캐시 갱신 = 메모리 dict 업데이트
- 기존 DB 인프라 재활용
- REST API + UI로 안전한 변경
- 타입/범위 검증 가능
- updated_at/updated_by로 이력 추적
- 서버 재시작해도 DB에서 복원
단점
- 구현 복잡도 약간 높음
- 다중 인스턴스 시 캐시 동기화 필요 (현재 단일 인스턴스)
- DB 쿼리 하나 추가됨 (시작 시 1회)
방법 D: Redis 기반 설정 저장소
아키텍처
전체 구조
설정 변경이 즉시 반영되려면, 각 모듈이 매번 DB를 읽는 것이 아니라 메모리에 캐싱된 값을 참조하도록 해야 합니다. 관리자가 값을 바꾸면 DB에 저장되면서 동시에 캐시도 갱신되므로, 다음 동작부터 새 값이 적용됩니다.
핵심 설계 원칙 3가지
설정 읽기는 매우 빈번합니다 — 이상탐지 60초마다, AI Chat 요청마다, RAG 검색마다. 매번 DB 쿼리를 하면 불필요한 I/O가 발생합니다. 반면 설정 쓰기는 매우 드묾니다 — 관리자가 가끔 UI에서 조정할 뿐입니다.
따라서 읽기는 Python dict 조회로 즉시 처리하고, 쓰기는 DB에 영속 저장 후 dict를 갱신합니다. 서버를 재시작해도 DB에서 다시 로드되므로 설정이 유실되지 않습니다.
모든 설정 조회에는 fallback 기본값이 함께 전달됩니다. DB에 설정이 없거나, 캐시가 로드되지 않았거나, 값 변환에 실패하면 기본값이 반환됩니다. 시스템은 설정 인프라에 의존하지 않고 독립적으로 동작할 수 있습니다.
설정 변경은 admin 역할만 가능합니다. 각 설정에 최솟값/최댓값이 정의되어 있어 범위 밖의 값은 거부됩니다. 예를 들어 Temperature를 5.0으로 설정하려 하면 "최댓값: 1.0" 오류가 반환됩니다.
데이터 모델
단일 key-value 테이블을 선택한 이유
카테고리별 테이블(llm_settings, detection_settings, ...)을 만드는 방법도 있지만,
새 설정을 추가할 때마다 ALTER TABLE이 필요하고 테이블이 늘어납니다.
단일 key-value 테이블이면 설정 추가가 INSERT 한 줄이므로 확장이 자유롭습니다.
테이블 구조
| 컬럼 | 용도 |
|---|---|
key | 설정 식별자. {카테고리}.{파라미터} 형식 (예: llm.timeout) |
value | 설정값 (TEXT). 모든 타입을 문자열로 저장 |
category | UI 카테고리 그룹핑 (llm, detection, ai_chat, rag, system, prompt) |
label | 사람이 읽는 한글 라벨 (예: "Timeout (초)") |
data_type | 타입 힌트 (int, float, str) — API 검증에 사용 |
min_val / max_val | 허용 범위 (NULL이면 제한 없음) |
updated_at / updated_by | 마지막 변경 이력 |
data_type 컬럼에 "int", "float", "str"을 저장하고,
API가 이 정보를 읽어 검증합니다. 스키마 변경 없이 새로운 타입의 설정도 추가할 수 있습니다.
설정 항목 선정
선정 기준
"운영 중 조정이 필요한 값인가?"를 기준으로 엄선했습니다. 시스템 구조에 영향을 주는 값(URL, 포트, DB 경로)은 환경변수로 남겨두었습니다.
LLM — AI 모델 제어
LLM은 FLOPI의 모든 AI 기능(이상탐지, AI Chat, RCA, 워크플로우)에 사용됩니다. 운영 중 응답 품질과 속도를 조정할 수 있어야 합니다. 모델명은 환경변수(LLM_MODEL)로 설정하며, Settings에 llm.model 키를 수동 등록하면 동적 전환도 가능합니다.
| 설정 키 | 기본값 | 범위 | 조정이 필요한 상황 |
|---|---|---|---|
| llm.timeout | 60.0 | 5~300 | 네트워크 느릴 때 늘리거나, 빠른 응답이 필요할 때 줄이기 |
| llm.max_tokens | 2048 | 64~32768 | 복잡한 RCA 분석에서 응답이 잘릴 때 늘리기 |
| llm.temperature | 0.1 | 0~1 | 탐지는 보수적(0.1), 채팅은 창의적(0.7)으로 조정 |
| llm.top_p | 1.0 | 0~1 | Temperature와 함께 미세 조정 |
이상탐지 — 탐지 부하 조절
규칙이 많아지면 동시 평가 부하가 증가합니다. 서버 사양에 맞게 동시성을 조절하고, 복잡한 규칙의 분석 깊이를 늘릴 수 있습니다.
| 설정 키 | 기본값 | 범위 | 조정이 필요한 상황 |
|---|---|---|---|
| detection.max_concurrent | 10 | 1~100 | 서버 부하가 높을 때 줄이기, 여유 있을 때 늘리기 |
| detection.max_agent_rounds | 3 | 1~20 | 복잡한 규칙이 도구를 더 많이 호출해야 할 때 늘리기 |
AI Chat — 대화 품질 조정
AI Chat은 사용자 질문에 도구를 호출하며 답변합니다. 복잡한 질문일수록 더 많은 도구 호출과 후보가 필요합니다. Knowledge Base 자동 검색은 항상 활성화되어 있으며, KB 주입 수(ai_chat.kb_auto_top_k)는 코드에서 기본값 3으로 참조됩니다.
| 설정 키 | 기본값 | 범위 | 조정이 필요한 상황 |
|---|---|---|---|
| ai_chat.max_tool_rounds | 5 | 1~30 | "WIP 조회 → 추세 분석 → 원인 파악"처럼 연쇄 호출이 필요할 때 |
| ai_chat.tool_selector_top_k | 15 | 1~100 | 도구가 89개+ 일 때 선별 범위 조정 |
| ai_chat.tool_selector_strategy | keyword | all/keyword/embedding | 폐쇄망(keyword), 임베딩 서버 구축 후(embedding), 소규모(all) |
RAG — 지식 검색 품질
Knowledge Base의 문서를 어떻게 자르고 몇 개 검색할지를 결정합니다. 문서 종류에 따라 최적값이 다릅니다.
| 설정 키 | 기본값 | 범위 | 조정이 필요한 상황 |
|---|---|---|---|
| rag.chunk_size | 500 | 100~5000 | SOP(짧은 항목) vs 매뉴얼(긴 문단)에 따라 조정 |
| rag.chunk_overlap | 50 | 0~500 | 문맥 손실을 줄이려면 늘리기, 중복을 줄이려면 줄이기 |
| rag.search_top_k | 5 | 1~50 | 정밀도(적게) vs 재현율(많이) 트레이드오프 |
시스템 — 공통 제한 및 모드
SQL 실행 결과의 행 수 제한과 도구 모드(시뮬레이터/운영)를 제어합니다. 도구 모드 변경은 AI Chat과 Tool Studio에 즉시 반영됩니다.
| 설정 키 | 기본값 | 범위 | 조정이 필요한 상황 |
|---|---|---|---|
| system.max_result_rows | 200 | 10~10000 | 대량 데이터 분석 시 제한 완화, 네트워크 부담 시 축소 |
| system.tool_mode | all | all/simulator/production | 운영환경 전환 시 — all(전체), simulator(SQLite+Internal), production(Oracle+Internal) |
프롬프트 — AI Chat 시스템 프롬프트 및 카테고리 프롬프트
AI Chat의 시스템 프롬프트와 범주별 카테고리 프롬프트를 Settings UI에서 직접 편집할 수 있습니다. 시스템 프롬프트는 버전 관리가 적용되며, 카테고리 프롬프트는 Chat Start Card 범주 선택 시 시스템 프롬프트에 추가 주입됩니다.
| 설정 키 | 카테고리 | 설명 |
|---|---|---|
| ai_chat.system_prompt | prompt | AI Chat 메인 시스템 프롬프트 (버전 관리, v3 현재) |
| ai_chat.category_prompt.wip | prompt | 재공/WIP 범주 프롬프트 |
| ai_chat.category_prompt.equipment | prompt | 설비 범주 프롬프트 |
| ai_chat.category_prompt.logistics | prompt | 물류 범주 프롬프트 |
| ai_chat.category_prompt.anomaly | prompt | 이상탐지 범주 프롬프트 |
| ai_chat.category_prompt.knowledge_base | prompt | 지식검색 범주 프롬프트 |
llm.detection.temperature 같은
모듈별 오버라이드 키를 추가할 계획입니다.
또한 ai_chat.kb_auto_top_k(KB 자동 검색 주입 수) 등 코드에서 참조하지만
아직 DB에 기본값이 시딩되지 않은 설정도 향후 정식 등록할 수 있습니다.
인메모리 캐시 — SettingsManager
설정을 빠르게 읽기 위한 싱글턴 캐시
8개 모듈이 설정을 참조하므로 모든 모듈이 같은 캐시를 보아야 합니다. 모듈 하나에서 값이 바뀌면 다른 모듈에서도 즉시 반영되어야 하기 때문입니다. 이를 위해 싱글턴 인스턴스를 사용합니다 — 모든 모듈이 동일한 dict를 참조합니다.
타입별 접근 메서드를 분리한 이유
get_int, get_float, get_str 세 가지 메서드를 제공합니다.
하나의 범용 get으로 통합하지 않은 이유:
- 명시성: 호출 코드에서 "이 값은 정수다"가 드러남 — 가독성 향상
- 안전성: DB에서 가져온 값은 모두 문자열이므로, 변환 실패 시 자동으로 기본값 반환
- IDE 지원: 반환 타입이 명확하여 자동완성과 타입 체크에 유리
쓰기 순서의 원자성
LLM 동적 전환
LLM 설정을 무중단으로 바꾸려면
LLM 클라이언트는 서버 시작 시 한 번 생성되어 계속 사용됩니다. 이 상태에서 "사용 모델을 gemini-2.5-flash로 바꾸고 싶다"면 어떻게 해야 할까요?
검토한 방법들
self.model을 property로 만들면, 기존에 self.model을 사용하는 코드는 한 줄도 바꾸지 않아도
매번 접근할 때마다 캐시에서 최신 설정값을 읽어옵니다. 캐시에 값이 없으면 원래 기본값으로 fallback합니다.
모델 전환 흐름
self.model, self.timeout으로 접근합니다.
"설정이 동적으로 바뀔 수 있다"는 사실을 모듈들이 알 필요가 없습니다 — 투명하게 동작합니다.
통합 전략
8개 모듈을 어떻게 연결했는가
각 모듈이 설정값을 참조하는 방식은 모듈의 특성에 따라 다릅니다. 상황별로 가장 적합한 패턴을 선택했습니다.
가장 일반적인 패턴입니다. 함수가 실행될 때마다 캐시에서 최신 설정을 읽습니다. 예를 들어 이상탐지 스케줄러는 매 사이클마다 "동시 규칙 평가 수"를 읽어 동시성을 조절합니다. 관리자가 값을 10에서 5로 줄이면, 다음 사이클부터 즉시 반영됩니다.
LLM 클라이언트는 속성 접근(self.model)이 자동으로 최신값을 반환하도록 설계했습니다.
기존 코드는 그대로 self.model을 사용하지만, 내부적으로 매번 캐시를 조회합니다.
기존 인터페이스를 전혀 수정하지 않고 동적 설정이 가능해집니다.
"기본값은 설정에서 읽되, 호출 시 명시적으로 지정하면 그 값을 우선"하는 패턴입니다. RAG 청킹 함수는 청크 크기를 지정하지 않으면 설정에서 읽고, 워크플로우에서 특별히 1000자로 호출하면 그 값을 사용합니다. 설정의 유연성과 개별 호출의 자유도를 모두 보장합니다.
SQL 최대 행 수는 Tool Studio의 여러 모듈에서 참조합니다. 헬퍼 함수로 감싸서 캐시가 로드되지 않은 시점에도 안전하게 기본값을 반환합니다. 시스템 초기화 순서에 의존하지 않는 안전한 접근을 제공합니다.
안전 장치
잘못된 값이 시스템을 죽이지 않도록
설정 시스템은 프로덕션 환경에서 동작하므로, 어떤 상황에서도 시스템이 멈추면 안 됩니다. 이를 위해 3중 방어 계층을 구성했습니다.
- 권한 검증: admin이 아니면 403 거부
- 타입 검증: 정수 설정에 "abc"를 넣으면 400 거부
- 범위 검증: Temperature에 5.0을 넣으면 "최댓값: 1.0" 오류
- 존재 검증: 없는 key를 변경하려 하면 404 거부
- 캐시에 키가 없으면 → 기본값 반환
- 값 변환이 실패하면 → 기본값 반환
- 캐시가 아예 로드되지 않았으면 → 모든 호출이 기본값 반환
- PRIMARY KEY로 중복 key 방지
- NOT NULL로 빈 값 방지
- 초기화 시 INSERT OR IGNORE로 기존 값 보존
UI 설계
관리자가 한 화면에서 모든 설정을 조정
5개 카테고리를 카드 형태로 구분하고, 숫자값은 number input(범위 제한 포함), 문자열은 text input으로 제공합니다. 변경된 항목만 서버에 전송하여 네트워크를 절약합니다.
접근 제어
설정 페이지는 admin 역할만 접근할 수 있습니다. 사이드바의 "관리" 그룹에 "설정" 메뉴로 등록되어 있으며, admin이 아닌 사용자에게는 메뉴 자체가 보이지 않습니다.
시스템 프롬프트 버전 관리
버전 히스토리
시스템 프롬프트(ai_chat.system_prompt)는 Settings UI에서 Admin이 편집할 수 있으며,
변경 시 이전 버전이 자동 보관됩니다.
롤백이 필요하면 버전 목록에서 이전 버전을 선택하여 복원할 수 있습니다.
| 버전 | 날짜 | 변경 내용 |
|---|---|---|
| v3 (현재) | 2026-03-24 | 선택적 파라미터 제거 → 모든 파라미터 필수, 도구 미보유 시 적극적 안내 + submit_tool_request 등록 흐름 추가 |
| v2 | 2026-03-15 | Knowledge Base 도구 활용 지침 추가, 도구 결과 시각화 포맷 안내 |
| v1 | 2026-02-28 | 초기 시스템 프롬프트 — FAB 역할 정의 + 도구 사용 방침 |
버전 저장 구조
system_settings 테이블의 ai_chat.system_prompt 키에 현재 버전이 저장되고,
이전 버전은 system_settings_history 테이블에 version, value, updated_by, updated_at으로 보관됩니다.
연결 검증 탭
Settings 페이지의 "연결 검증" 탭에서 LLM, 임베딩, 벡터 저장소, DB의 연결 상태를 한 화면에서 점검할 수 있습니다. 각 컴포넌트에 실제 요청을 보내고 응답 시간을 측정하여 결과를 실시간 표시합니다.
| 검증 항목 | 테스트 방법 | 성공 기준 |
|---|---|---|
| LLM | "ping" 메시지 전송 → 응답 수신 | HTTP 200, latency < 5초 |
| 임베딩 | "test" 텍스트 임베딩 요청 | 벡터 반환, 차원 수 확인 |
| ChromaDB | 컬렉션 목록 조회 | 응답 정상, 컬렉션 존재 |
| DB (FLOPI) | SELECT 1 실행 | 쿼리 응답 정상 |
| Tool Studio DB | 연결별 테스트 쿼리 실행 | 연결 성공 + latency |
POST /api/system-settings/verify-connections달성한 것
관리자가 UI에서 값을 바꾸면, 이상탐지/AI Chat/RAG 등 모든 모듈이 다음 동작부터 즉시 새 값을 사용합니다. 서버 재시작이 필요한 경우는 0건입니다.
설정 DB가 비어있어도, 캐시 로드에 실패해도, 값 변환이 실패해도 — 시스템은 기본값으로 정상 동작합니다. 3중 방어 계층이 모든 실패 시나리오를 흡수합니다.
8개 모듈 모두 기존 인터페이스를 유지합니다. 특히 LLM 클라이언트는 property 패턴 덕분에 호출 코드 수정 없이 동적 설정이 가능해졌습니다.
향후 확장
이 문서는 FLOPI System Settings의 설계 배경과 아키텍처를 기록합니다.
전체 모듈 문서도 참고하세요.
© 2026 FLOPI — Semiconductor FAB AI Platform