105 lines
5.7 KiB
SQL
105 lines
5.7 KiB
SQL
-- =============================================================================
|
|
-- 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);
|
|
CREATE INDEX IF NOT EXISTS idx_chunk_source ON kb.chunk (source_id);
|
|
|
|
-- =============================================================================
|
|
-- 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);
|