feat(engine): claude -p 상주 멀티턴 엔진 게이트웨이 + 실동작 검증

- engine_gateway/gateway.py: 회기당 claude -p 상주 프로세스(stream-json), 턴 직렬, budget 제한
- 세션 생성/턴/종료 HTTP API(FastAPI, :9099)
- 검증: 멀티턴 컨텍스트 유지 + prompt caching 재사용(턴2 +$0.07) 실동작 확인
This commit is contained in:
Yun Chan 2026-06-25 21:43:27 +09:00
parent d5b86c5f89
commit 84eb6e2173
20 changed files with 2038 additions and 1 deletions

104
infra/db/init/03_kb.sql Normal file
View file

@ -0,0 +1,104 @@
-- =============================================================================
-- Vignette · 03_kb.sql
-- kb 스키마: 정적 지식 KB (DSM/이론/technique/taxonomy) — app 과 물리 분리
-- ⑤ KNOWLEDGE 계층. 3-AI 가 같은 물리 테이블을 다른 정책(visible_to+sensitivity)으로 검색.
-- 근거: MEMORY_KNOWLEDGE_PERSONA_DESIGN.md §3.6, §4.3 / MASTERPLAN §3.6
-- 전제: 02_schema.sql (app.technique_label_def 존재). 적용 순서: 02 → 03(본 파일).
-- 원칙: app 으로의 FK 없음(read-only 독립). license_class C/D = 외부 LLM 차단.
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS kb;
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
SET search_path TO kb, public;
-- =============================================================================
-- 1. 출처 + 라이선스 (DSM-5 저작권 1차 통제, 설계서 §3.6)
-- =============================================================================
CREATE TABLE IF NOT EXISTS kb.source (
source_id TEXT PRIMARY KEY, -- 'dsm5','theory','taxonomy_0615'
title TEXT NOT NULL,
kb_kind TEXT NOT NULL CHECK (kb_kind IN
('diagnostic','theory','technique','taxonomy',
'supervisor_pattern','template','ko_context','microskill')),
license_class CHAR(1) NOT NULL CHECK (license_class IN ('A','B','C','D')),
-- C=저작권민감 D=미성년파생
origin_path TEXT,
citation TEXT,
external_llm_ok BOOLEAN NOT NULL DEFAULT FALSE, -- C/D면 false → 국내 라우팅
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- =============================================================================
-- 2. 문서 + 버전 (graphify content_hash 증분 인덱싱 차용)
-- =============================================================================
CREATE TABLE IF NOT EXISTS kb.document (
doc_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
source_id TEXT NOT NULL REFERENCES kb.source(source_id),
doc_uri TEXT NOT NULL,
version INT NOT NULL DEFAULT 1,
content_hash TEXT NOT NULL, -- SHA256 → 변경감지(증분)
superseded_by BIGINT REFERENCES kb.document(doc_id),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
indexed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (source_id, doc_uri, version)
);
CREATE INDEX IF NOT EXISTS idx_kb_doc_active
ON kb.document(source_id) WHERE is_active;
-- =============================================================================
-- 3. 청크 + 멀티벡터 (검색 본체, 설계서 §3.6)
-- visible_to + sensitivity 가 3-AI 정보비대칭을 DB WHERE 로 강제.
-- =============================================================================
CREATE TABLE IF NOT EXISTS kb.chunk (
chunk_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
doc_id BIGINT NOT NULL REFERENCES kb.document(doc_id) ON DELETE CASCADE,
source_id TEXT NOT NULL, -- 비정규화(필터 가속)
kb_kind TEXT NOT NULL, -- 비정규화
seq INT NOT NULL,
heading_path TEXT,
chunk_text TEXT NOT NULL, -- 표시·LLM 주입(prefix 미포함)
context_prefix TEXT, -- Contextual Retrieval 주입문
embedding vector(1024), -- BGE-M3 dense
sparse_vec JSONB, -- BGE-M3 sparse
colbert_vecs JSONB, -- 멀티벡터(단일 호출 산출)
visible_to TEXT[] NOT NULL DEFAULT '{client,counselor,evaluator}',
sensitivity SMALLINT NOT NULL DEFAULT 0
CHECK (sensitivity BETWEEN 0 AND 3), -- 0공개 1내부 2평가전용 3원천격리
label_id BIGINT REFERENCES app.technique_label_def(label_id), -- taxonomy 정답라벨
meta JSONB DEFAULT '{}', -- {dsm_category,theory,bias_weight,...}
token_count INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- dense ANN
CREATE INDEX IF NOT EXISTS idx_chunk_hnsw ON kb.chunk
USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
-- sparse/BM25 (한국어: simple + pg_trgm 병용, M10 완화)
CREATE INDEX IF NOT EXISTS idx_chunk_fts ON kb.chunk
USING gin (to_tsvector('simple', chunk_text));
CREATE INDEX IF NOT EXISTS idx_chunk_trgm ON kb.chunk
USING gin (chunk_text gin_trgm_ops);
-- 정보비대칭 사전필터
CREATE INDEX IF NOT EXISTS idx_chunk_visible ON kb.chunk USING gin (visible_to);
CREATE INDEX IF NOT EXISTS idx_chunk_route ON kb.chunk (kb_kind, sensitivity);
-- =============================================================================
-- 4. KB 검색 로그 (환각측정·캐시검증, 람다 cost.json 차용, 설계서 §3.7)
-- =============================================================================
CREATE TABLE IF NOT EXISTS kb.retrieval_log (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
session_id UUID,
turn_id UUID,
ai_role TEXT NOT NULL, -- 'client'|'counselor'|'evaluator'
query_text TEXT,
policy TEXT NOT NULL, -- 4-튜플 정책명
hit_chunk_ids BIGINT[],
rerank_scores REAL[],
top1_score REAL, -- CRAG 게이트
used_in_answer BOOLEAN,
latency_ms INT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_kb_retr_session ON kb.retrieval_log(session_id);