Files
zclaw_openfang/crates/zclaw-saas/migrations/20260402000002_knowledge_base.sql
iven 1048901665
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
fix(saas): industry template audit fixes + pgvector optional + relay timeout
- Fix seed template tools to match actual runtime tool names
  (file_read/file_write/shell_exec/web_fetch)
- Persist system_prompt/temperature/max_tokens via identity system
  in agentStore.createFromTemplate()
- Fire-and-forget assignTemplate() in AgentOnboardingWizard
- Fix saas-relay-client unused variable warning
- Make pgvector extension optional in knowledge_base migration
- Increase StreamBridge timeout from 30s to 90s for thinking models
2026-04-03 15:10:13 +08:00

137 lines
5.3 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Migration: Knowledge Base tables with optional pgvector support
-- 5 tables: knowledge_categories, knowledge_items, knowledge_chunks,
-- knowledge_versions, knowledge_usage
--
-- pgvector is optional: if the extension is not installed, the embedding
-- column and HNSW index are skipped. All other tables work normally.
-- 行业分类树
CREATE TABLE IF NOT EXISTS knowledge_categories (
id TEXT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
parent_id TEXT REFERENCES knowledge_categories(id) ON DELETE RESTRICT,
icon VARCHAR(50),
sort_order INT DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
CHECK (id != parent_id)
);
CREATE INDEX IF NOT EXISTS idx_kc_parent ON knowledge_categories(parent_id);
-- 知识条目
CREATE TABLE IF NOT EXISTS knowledge_items (
id TEXT PRIMARY KEY,
category_id TEXT NOT NULL REFERENCES knowledge_categories(id) ON DELETE RESTRICT,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
keywords TEXT[] DEFAULT '{}',
related_questions TEXT[] DEFAULT '{}',
priority INT DEFAULT 0,
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'archived', 'deprecated', 'draft')),
version INT DEFAULT 1,
source VARCHAR(50) DEFAULT 'manual',
tags TEXT[] DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES accounts(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
CHECK (length(content) <= 100000)
);
CREATE INDEX IF NOT EXISTS idx_ki_category ON knowledge_items(category_id);
CREATE INDEX IF NOT EXISTS idx_ki_status_updated ON knowledge_items(status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_ki_keywords ON knowledge_items USING GIN(keywords);
-- 知识分块RAG 检索核心)
-- 基础表不含 embedding 列;若 pgvector 可用则后续通过 DO 块添加
CREATE TABLE IF NOT EXISTS knowledge_chunks (
id TEXT PRIMARY KEY,
item_id TEXT NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
chunk_index INT NOT NULL,
content TEXT NOT NULL,
keywords TEXT[] DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_kchunks_item_idx ON knowledge_chunks(item_id, chunk_index);
CREATE INDEX IF NOT EXISTS idx_kchunks_item ON knowledge_chunks(item_id);
CREATE INDEX IF NOT EXISTS idx_kchunks_keywords ON knowledge_chunks USING GIN(keywords);
-- 条件添加 embedding 列和 HNSW 索引(仅当 pgvector 可用时)
DO $$ BEGIN
PERFORM set_config('client_min_messages', 'warning', true);
CREATE EXTENSION IF NOT EXISTS vector;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'knowledge_chunks' AND column_name = 'embedding'
) THEN
ALTER TABLE knowledge_chunks ADD COLUMN embedding vector(1536);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_kchunks_embedding') THEN
CREATE INDEX idx_kchunks_embedding ON knowledge_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 128);
END IF;
RAISE NOTICE 'pgvector enabled for knowledge base';
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'pgvector not available, vector features disabled: %', SQLERRM;
END $$;
-- 版本快照
CREATE TABLE IF NOT EXISTS knowledge_versions (
id TEXT PRIMARY KEY,
item_id TEXT NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
version INT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
keywords TEXT[] DEFAULT '{}',
related_questions TEXT[] DEFAULT '{}',
change_summary TEXT,
created_by TEXT NOT NULL REFERENCES accounts(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_kv_item ON knowledge_versions(item_id);
-- 使用追踪
CREATE TABLE IF NOT EXISTS knowledge_usage (
id TEXT PRIMARY KEY,
item_id TEXT REFERENCES knowledge_items(id) ON DELETE SET NULL,
chunk_id TEXT REFERENCES knowledge_chunks(id) ON DELETE SET NULL,
session_id VARCHAR(100),
query_text TEXT,
relevance_score FLOAT,
was_injected BOOLEAN DEFAULT FALSE,
agent_feedback VARCHAR(20) CHECK (agent_feedback IN ('positive', 'negative')),
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_ku_item ON knowledge_usage(item_id) WHERE item_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_ku_created_brin ON knowledge_usage USING brin(created_at);
-- 权限种子数据(使用 jsonb 操作避免 REPLACE 脆弱性)
UPDATE roles
SET permissions = (
SELECT '[' || string_agg('"' || elem || '"', ', ') || ']'
FROM (
SELECT DISTINCT elem
FROM json_array_elements_text(permissions::json) AS elem
UNION ALL SELECT 'knowledge:read'
UNION ALL SELECT 'knowledge:write'
UNION ALL SELECT 'knowledge:admin'
UNION ALL SELECT 'knowledge:search'
) sub
)
WHERE id = 'super_admin'
AND permissions NOT LIKE '%knowledge:read%';
UPDATE roles
SET permissions = (
SELECT '[' || string_agg('"' || elem || '"', ', ') || ']'
FROM (
SELECT DISTINCT elem
FROM json_array_elements_text(permissions::json) AS elem
UNION ALL SELECT 'knowledge:read'
UNION ALL SELECT 'knowledge:write'
UNION ALL SELECT 'knowledge:search'
) sub
)
WHERE id = 'admin'
AND permissions NOT LIKE '%knowledge:read%';