Implement knowledge base management and enhance assistant configuration

Add CRUD functionality for knowledge bases, including routes for listing, creating, updating, and deleting knowledge bases. Update the assistant model to include foreign key references to knowledge bases and modify the assistant configuration to handle external API keys securely. Refactor related services and routes to accommodate these changes, ensuring proper handling of credential resolution and configuration normalization.
This commit is contained in:
Xin Wang
2026-06-09 08:31:39 +08:00
parent 34fba494a3
commit b444ea777c
6 changed files with 304 additions and 56 deletions

View File

@@ -9,7 +9,7 @@
from datetime import datetime
from sqlalchemy import Boolean, DateTime, String, func
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, String, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
@@ -37,19 +37,67 @@ class ProviderCredential(Base):
)
class Assistant(Base):
__tablename__ = "assistants"
class KnowledgeBase(Base):
"""知识库注册表。本身引用一个 Embedding 凭证(用哪个向量模型)。
id: Mapped[str] = mapped_column(String(40), primary_key=True) # asst_xxx
文档/分块(pgvector)是 KB 内部实现,这里先不展开;助手侧只认 knowledge_base_id。
"""
__tablename__ = "knowledge_bases"
id: Mapped[str] = mapped_column(String(40), primary_key=True) # kb_xxx
name: Mapped[str] = mapped_column(String(128))
greeting: Mapped[str] = mapped_column(String(2048), default="")
prompt: Mapped[str] = mapped_column(String(8192), default="")
runtime_mode: Mapped[str] = mapped_column(String(16), default="pipeline")
# 模型/音色的"选项名",不是 key
model: Mapped[str] = mapped_column(String(128), default="")
asr: Mapped[str] = mapped_column(String(128), default="")
voice: Mapped[str] = mapped_column(String(128), default="")
enable_interrupt: Mapped[bool] = mapped_column(Boolean, default=True)
description: Mapped[str] = mapped_column(String(2048), default="")
# 该 KB 用哪个向量模型;凭证被删则置空
embedding_credential_id: Mapped[str | None] = mapped_column(
String(40),
ForeignKey("provider_credentials.id", ondelete="SET NULL"),
nullable=True,
)
status: Mapped[str] = mapped_column(String(16), default="active") # active|archived
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class Assistant(Base):
"""助手(单表,无版本化)。type 为可变普通列,5 种类型共用此表。
模型/KB 以 FK 引用注册表;类型专属字段塞进 config(JSON)。
"""
__tablename__ = "assistants"
id: Mapped[str] = mapped_column(String(40), primary_key=True) # asst_xxx
name: Mapped[str] = mapped_column(String(128))
# prompt|workflow|dify|fastgpt|opencode;创建后可改
type: Mapped[str] = mapped_column(String(16), index=True, default="prompt")
runtime_mode: Mapped[str] = mapped_column(String(16), default="pipeline")
greeting: Mapped[str] = mapped_column(String(2048), default="")
enable_interrupt: Mapped[bool] = mapped_column(Boolean, default=True)
# ---- 引用"注册好的资源":凭证被删 → SET NULL(resolver 有默认/.env 兜底) ----
llm_credential_id: Mapped[str | None] = mapped_column(
String(40), ForeignKey("provider_credentials.id", ondelete="SET NULL"), nullable=True
)
asr_credential_id: Mapped[str | None] = mapped_column(
String(40), ForeignKey("provider_credentials.id", ondelete="SET NULL"), nullable=True
)
tts_credential_id: Mapped[str | None] = mapped_column(
String(40), ForeignKey("provider_credentials.id", ondelete="SET NULL"), nullable=True
)
realtime_credential_id: Mapped[str | None] = mapped_column(
String(40), ForeignKey("provider_credentials.id", ondelete="SET NULL"), nullable=True
)
# KB 引用:被引用时禁止删 KB(RESTRICT),无默认兜底
knowledge_base_id: Mapped[str | None] = mapped_column(
String(40), ForeignKey("knowledge_bases.id", ondelete="RESTRICT"), nullable=True
)
# 类型专属字段(形态各异):prompt / graph / dify|fastgpt|opencode 端点+key(打码)
config: Mapped[dict] = mapped_column(JSON, default=dict)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()