아키텍처 노트 · 2026-05

BFF가 chat_message / chat_feedback
테이블을 가지는 이유

ai_engine = stateless LLM 추론. BFF = stateful 대화 상태 + 피드백 + 관리 집계.
호진 / 박찬호의 계층 아키텍처 정책에 따른 정확한 책임 분리.

TL;DR

ai_engine은 매 요청마다 새 workflow 를 spin up 하는 무상태 inference layer다. 대화 히스토리·피드백·관리자 집계는 어딘가에 영속화돼야 하고, 그 역할은 BFF 가 맡는다. Chan 의 질문 "ai_engine session_store 와 중복 아니냐?" 에 대한 답은 아니다: 둘은 책임도 다르고 수명도 다르다.

5 가지 이유

  1. 1. 호진의 T4 프롬프트가 명시적으로 요구

    message.txt 69-83 줄에서 한 문장도 빠짐없이 동일하게 요구됨:

    "Persist the user message AND the agent response (including the returned UIAction[] and any tool-call trace metadata) in a new Postgres table chat_message (session_id, role, content, ui_actions JSONB, created_at)."
    "PATCH /api/chat/sessions/{sid}/messages/{mid}/feedback — persist thumbs up/down into a chat_feedback table."
  2. 2. ai_engine 은 stateless inference layer

    services/ai_engine/online/eval_chatbot/service.pychat() 은 매 요청마다 fresh workflow 를 spin up 한다. conversation_history 는 caller (BFF) 가 매 턴 주입해야 한다. ai_engine 자체는 chat memory 가 없다. 누군가는 history 를 persist 해야 하고 → BFF.

  3. 3. FE 가 과거 대화를 BFF 에서 직접 fetch

    GET /api/chat/sessions/{sid}/messages — 페이지 리로드 시, 혹은 다른 평가자가 같은 세션을 열 때 사용. BFF 는 ai_engine 에 물어서 이걸 재구성할 수 없다 (ai_engine 도 모름).

  4. 4. 관리자 화면이 BFF DB 를 직접 read

    frontend/src/lib/api/client.tsapiGetAdminChatSessions(), apiGetAdminChatFeedbacks(), apiGetAdminChatSummariesByBidId() 가 BFF 의 chat_message / chat_feedback 를 그대로 읽는다. 평가자 usage 통계, feedback adoption rate, 입찰별 대화 요약 — 전부 DB 집계지 LLM 호출이 아니다. BFF 의 일.

  5. 5. "BFF 에 LLM SDK 금지" 룰은 그대로 유지

    chat_message 는 그냥 Postgres row 다. BFF 가 호출하는 건 services/ai_engine/online/eval-chatbot/chat 하나뿐. apps/eval-system-premium/backend/ 어디에도 openai, anthropic, google.generativeai, groq import 없음. T4-c4 test (test_bff_does_not_import_llm_sdks) 가 매 커밋마다 정적으로 검증.

한 줄 요약

ai_engine = LLM 호출 (stateless).
BFF = 대화 상태 + 피드백 + 관리 집계 (stateful).

분리는 호진 / 박찬호의 layered architecture policy 와 정확히 일치한다 — chat 호출만 ai_engine 을 거치고, 영속화는 전부 BFF.

Chan 의 "ai_engine session_store 와 중복 아니냐?" 에 대해

답: 아니다.

ai_engine session_store

  • 1 회 inference 내부의 LLM call caching
  • rate-limiting
  • context windowing
  • 수명: 한 요청

BFF chat_message

  • 평가자 대화 히스토리 영속화
  • 관리자 통계 / 피드백 집계
  • 다중 사용자 / 다중 세션 read
  • 수명: 영구

책임도 다르고 수명도 다르다.