167 lines
6.5 KiB
PL/PgSQL
167 lines
6.5 KiB
PL/PgSQL
-- LLM Feature Tables (Observability, Costs, Episodic Memory)
|
|
|
|
-- Conversation Cost Tracking
|
|
CREATE TABLE IF NOT EXISTS conversation_costs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
session_id UUID NOT NULL,
|
|
user_id UUID NOT NULL,
|
|
bot_id UUID NOT NULL,
|
|
model_used VARCHAR(100),
|
|
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
cost_usd DECIMAL(10, 6) NOT NULL DEFAULT 0,
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_conv_costs_session ON conversation_costs(session_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_costs_user ON conversation_costs(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_costs_bot ON conversation_costs(bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_conv_costs_time ON conversation_costs(timestamp);
|
|
|
|
-- LLM Metrics
|
|
CREATE TABLE IF NOT EXISTS llm_metrics (
|
|
id UUID PRIMARY KEY,
|
|
request_id UUID NOT NULL,
|
|
session_id UUID NOT NULL,
|
|
bot_id UUID NOT NULL,
|
|
model VARCHAR(200) NOT NULL,
|
|
request_type VARCHAR(50) NOT NULL,
|
|
input_tokens BIGINT NOT NULL DEFAULT 0,
|
|
output_tokens BIGINT NOT NULL DEFAULT 0,
|
|
total_tokens BIGINT NOT NULL DEFAULT 0,
|
|
latency_ms BIGINT NOT NULL DEFAULT 0,
|
|
ttft_ms BIGINT,
|
|
cached BOOLEAN NOT NULL DEFAULT false,
|
|
success BOOLEAN NOT NULL DEFAULT true,
|
|
error TEXT,
|
|
estimated_cost DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
metadata JSONB NOT NULL DEFAULT '{}'
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_llm_metrics_bot_id ON llm_metrics(bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_metrics_session_id ON llm_metrics(session_id);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_metrics_timestamp ON llm_metrics(timestamp DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_metrics_model ON llm_metrics(model);
|
|
|
|
-- LLM Metrics Hourly
|
|
CREATE TABLE IF NOT EXISTS llm_metrics_hourly (
|
|
id UUID PRIMARY KEY,
|
|
bot_id UUID NOT NULL,
|
|
hour TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
total_requests BIGINT NOT NULL DEFAULT 0,
|
|
successful_requests BIGINT NOT NULL DEFAULT 0,
|
|
failed_requests BIGINT NOT NULL DEFAULT 0,
|
|
cache_hits BIGINT NOT NULL DEFAULT 0,
|
|
cache_misses BIGINT NOT NULL DEFAULT 0,
|
|
total_input_tokens BIGINT NOT NULL DEFAULT 0,
|
|
total_output_tokens BIGINT NOT NULL DEFAULT 0,
|
|
total_tokens BIGINT NOT NULL DEFAULT 0,
|
|
total_cost DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
avg_latency_ms DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
p50_latency_ms DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
p95_latency_ms DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
p99_latency_ms DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
max_latency_ms BIGINT NOT NULL DEFAULT 0,
|
|
min_latency_ms BIGINT NOT NULL DEFAULT 0,
|
|
requests_by_model JSONB NOT NULL DEFAULT '{}',
|
|
tokens_by_model JSONB NOT NULL DEFAULT '{}',
|
|
cost_by_model JSONB NOT NULL DEFAULT '{}',
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
UNIQUE(bot_id, hour)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_llm_metrics_hourly_bot_id ON llm_metrics_hourly(bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_metrics_hourly_hour ON llm_metrics_hourly(hour DESC);
|
|
|
|
-- LLM Budget
|
|
CREATE TABLE IF NOT EXISTS llm_budget (
|
|
id UUID PRIMARY KEY,
|
|
bot_id UUID NOT NULL UNIQUE,
|
|
daily_limit DOUBLE PRECISION NOT NULL DEFAULT 100,
|
|
monthly_limit DOUBLE PRECISION NOT NULL DEFAULT 2000,
|
|
alert_threshold DOUBLE PRECISION NOT NULL DEFAULT 0.8,
|
|
daily_spend DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
monthly_spend DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
daily_reset_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
|
monthly_reset_date DATE NOT NULL DEFAULT DATE_TRUNC('month', CURRENT_DATE)::DATE,
|
|
daily_alert_sent BOOLEAN NOT NULL DEFAULT false,
|
|
monthly_alert_sent BOOLEAN NOT NULL DEFAULT false,
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- LLM Traces
|
|
CREATE TABLE IF NOT EXISTS llm_traces (
|
|
id UUID PRIMARY KEY,
|
|
parent_id UUID,
|
|
trace_id UUID NOT NULL,
|
|
name VARCHAR(200) NOT NULL,
|
|
component VARCHAR(100) NOT NULL,
|
|
event_type VARCHAR(50) NOT NULL,
|
|
duration_ms BIGINT,
|
|
start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
end_time TIMESTAMP WITH TIME ZONE,
|
|
attributes JSONB NOT NULL DEFAULT '{}',
|
|
status VARCHAR(50) NOT NULL DEFAULT 'in_progress',
|
|
error TEXT,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_llm_traces_trace_id ON llm_traces(trace_id);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_traces_start_time ON llm_traces(start_time DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_traces_component ON llm_traces(component);
|
|
|
|
-- Episodic Memories
|
|
CREATE TABLE IF NOT EXISTS episodic_memories (
|
|
id UUID PRIMARY KEY,
|
|
bot_id UUID NOT NULL,
|
|
user_id UUID NOT NULL,
|
|
session_id UUID,
|
|
summary TEXT NOT NULL,
|
|
key_topics JSONB DEFAULT '[]',
|
|
decisions JSONB DEFAULT '[]',
|
|
action_items JSONB DEFAULT '[]',
|
|
message_count INTEGER NOT NULL DEFAULT 0,
|
|
start_timestamp TIMESTAMPTZ NOT NULL,
|
|
end_timestamp TIMESTAMPTZ NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_episodic_bot ON episodic_memories(bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_episodic_user ON episodic_memories(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_episodic_session ON episodic_memories(session_id);
|
|
CREATE INDEX IF NOT EXISTS idx_episodic_time ON episodic_memories(bot_id, user_id, created_at);
|
|
|
|
-- Bot Reflections
|
|
CREATE TABLE IF NOT EXISTS bot_reflections (
|
|
id UUID PRIMARY KEY,
|
|
bot_id UUID NOT NULL,
|
|
session_id UUID NOT NULL,
|
|
reflection_type TEXT NOT NULL,
|
|
score FLOAT NOT NULL DEFAULT 0.0,
|
|
insights TEXT NOT NULL DEFAULT '[]',
|
|
improvements TEXT NOT NULL DEFAULT '[]',
|
|
positive_patterns TEXT NOT NULL DEFAULT '[]',
|
|
concerns TEXT NOT NULL DEFAULT '[]',
|
|
raw_response TEXT NOT NULL DEFAULT '',
|
|
messages_analyzed INTEGER NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_bot_reflections_bot ON bot_reflections(bot_id);
|
|
CREATE INDEX IF NOT EXISTS idx_bot_reflections_session ON bot_reflections(session_id);
|
|
CREATE INDEX IF NOT EXISTS idx_bot_reflections_time ON bot_reflections(bot_id, created_at);
|
|
|
|
-- Triggers for Updated At (e.g. Budget)
|
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS update_llm_budget_updated_at ON llm_budget;
|
|
CREATE TRIGGER update_llm_budget_updated_at
|
|
BEFORE UPDATE ON llm_budget
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|