feat: 建立知识版本与检索追踪数据模型

This commit is contained in:
2026-07-11 18:59:29 +08:00
parent 0199dd8242
commit 73fdfed0e5
3 changed files with 586 additions and 2 deletions

View File

@@ -2,7 +2,23 @@ from app.models.admin import Admin, Role
from app.models.ai_config import ModelConfig, Prompt, SystemConfig
from app.models.base import Base
from app.models.chat import ChatMessage, ChatSession
from app.models.knowledge import Knowledge, UserKnowledgePermission
from app.models.knowledge import (
HumanAttentionHistory,
HumanAttentionRecord,
Knowledge,
KnowledgeCard,
KnowledgeChunk,
KnowledgeManifest,
KnowledgePublishLog,
KnowledgeRetrievalCandidate,
KnowledgeRetrievalLog,
KnowledgeReviewRecord,
KnowledgeSection,
KnowledgeSourceSnapshot,
KnowledgeSyncJob,
KnowledgeVersion,
UserKnowledgePermission,
)
from app.models.logs import AiRequestLog, OperationLog
from app.models.user import User
@@ -13,6 +29,19 @@ __all__ = [
"ChatMessage",
"ChatSession",
"Knowledge",
"KnowledgeCard",
"KnowledgeChunk",
"KnowledgeManifest",
"KnowledgePublishLog",
"KnowledgeRetrievalCandidate",
"KnowledgeRetrievalLog",
"KnowledgeReviewRecord",
"KnowledgeSection",
"KnowledgeSourceSnapshot",
"KnowledgeSyncJob",
"KnowledgeVersion",
"HumanAttentionHistory",
"HumanAttentionRecord",
"ModelConfig",
"OperationLog",
"Prompt",

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, ForeignKey, String
from sqlalchemy import BigInteger, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import Base, TimestampMixin
@@ -17,6 +17,18 @@ class Knowledge(Base, TimestampMixin):
feishu_node_id: Mapped[str] = mapped_column(String(100), nullable=False)
status: Mapped[int] = mapped_column(default=1, nullable=False)
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
source_title: Mapped[str | None] = mapped_column(String(255), nullable=True)
knowledge_type: Mapped[str] = mapped_column(String(30), default="general", nullable=False)
review_mode: Mapped[str] = mapped_column(String(30), default="manual", nullable=False)
lifecycle_status: Mapped[str] = mapped_column(String(30), default="active", nullable=False)
source_status: Mapped[str] = mapped_column(String(30), default="normal", nullable=False)
source_error: Mapped[str | None] = mapped_column(Text, nullable=True)
manifest_confirmed: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
current_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
pending_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
last_synced_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
last_published_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
migration_status: Mapped[str] = mapped_column(String(30), default="pending", nullable=False)
user_permissions: Mapped[list["UserKnowledgePermission"]] = relationship(
"UserKnowledgePermission", back_populates="knowledge"
@@ -35,3 +47,227 @@ class UserKnowledgePermission(Base, TimestampMixin):
user: Mapped["User"] = relationship("User", back_populates="knowledge_permissions")
knowledge: Mapped[Knowledge] = relationship("Knowledge", back_populates="user_permissions")
class KnowledgeSourceSnapshot(Base):
__tablename__ = "sys_knowledge_source_snapshot"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
sync_job_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
source_title: Mapped[str] = mapped_column(String(255), nullable=False)
source_content: Mapped[str] = mapped_column(Text, nullable=False)
content_hash: Mapped[str] = mapped_column(String(64), index=True, nullable=False)
source_identifier: Mapped[str] = mapped_column(String(255), nullable=False)
fetched_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
created_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
class KnowledgeVersion(Base):
__tablename__ = "sys_knowledge_version"
__table_args__ = (UniqueConstraint("knowledge_id", "version_no", name="uq_kb_version_no"),)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
snapshot_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_source_snapshot.id"), nullable=False)
version_no: Mapped[int] = mapped_column(Integer, nullable=False)
status: Mapped[str] = mapped_column(String(30), index=True, nullable=False)
quality_status: Mapped[str] = mapped_column(String(30), default="pending", nullable=False)
change_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
quality_report: Mapped[str | None] = mapped_column(Text, nullable=True)
processing_rule_version: Mapped[str] = mapped_column(String(50), nullable=False)
generation_model: Mapped[str | None] = mapped_column(String(100), nullable=True)
created_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
published_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
published_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
class KnowledgeManifest(Base):
__tablename__ = "sys_knowledge_manifest"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
purpose: Mapped[str] = mapped_column(Text, nullable=False)
applicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
inapplicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
core_topics: Mapped[str] = mapped_column(Text, nullable=False)
entities: Mapped[str | None] = mapped_column(Text, nullable=True)
boundaries: Mapped[str | None] = mapped_column(Text, nullable=True)
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
change_level: Mapped[str] = mapped_column(String(20), default="major", nullable=False)
confirmed: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
confirmed_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
confirmed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
class KnowledgeSection(Base):
__tablename__ = "sys_knowledge_section"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
section_key: Mapped[str] = mapped_column(String(64), nullable=False)
title: Mapped[str] = mapped_column(String(255), nullable=False)
content: Mapped[str] = mapped_column(Text, nullable=False)
source_start: Mapped[int] = mapped_column(Integer, nullable=False)
source_end: Mapped[int] = mapped_column(Integer, nullable=False)
sort_order: Mapped[int] = mapped_column(Integer, nullable=False)
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
class KnowledgeChunk(Base):
__tablename__ = "sys_knowledge_chunk"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
section_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_section.id"), index=True, nullable=False)
title: Mapped[str] = mapped_column(String(255), nullable=False)
content: Mapped[str] = mapped_column(Text, nullable=False)
normalized_text: Mapped[str] = mapped_column(Text, nullable=False)
keywords: Mapped[str | None] = mapped_column(Text, nullable=True)
synonyms: Mapped[str | None] = mapped_column(Text, nullable=True)
source_start: Mapped[int] = mapped_column(Integer, nullable=False)
source_end: Mapped[int] = mapped_column(Integer, nullable=False)
sort_order: Mapped[int] = mapped_column(Integer, nullable=False)
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
class KnowledgeCard(Base):
__tablename__ = "sys_knowledge_card"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
section_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_section.id"), index=True, nullable=False)
title: Mapped[str] = mapped_column(String(255), nullable=False)
summary: Mapped[str] = mapped_column(Text, nullable=False)
core_conclusion: Mapped[str] = mapped_column(Text, nullable=False)
applicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
inapplicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
keywords: Mapped[str] = mapped_column(Text, nullable=False)
synonyms: Mapped[str | None] = mapped_column(Text, nullable=True)
entities: Mapped[str | None] = mapped_column(Text, nullable=True)
risk_level: Mapped[str] = mapped_column(String(20), default="normal", nullable=False)
source_range: Mapped[str] = mapped_column(String(100), nullable=False)
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
generation_model: Mapped[str | None] = mapped_column(String(100), nullable=True)
generation_rule_version: Mapped[str] = mapped_column(String(50), nullable=False)
review_status: Mapped[str] = mapped_column(String(20), default="pending", nullable=False)
class KnowledgeSyncJob(Base):
__tablename__ = "sys_knowledge_sync_job"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
mode: Mapped[str] = mapped_column(String(30), nullable=False)
status: Mapped[str] = mapped_column(String(30), index=True, nullable=False)
stage: Mapped[str] = mapped_column(String(50), nullable=False)
progress: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
source_error: Mapped[str | None] = mapped_column(Text, nullable=True)
result_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
requested_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
class KnowledgeReviewRecord(Base):
__tablename__ = "sys_knowledge_review_record"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
card_id: Mapped[int | None] = mapped_column(ForeignKey("sys_knowledge_card.id"), nullable=True)
action: Mapped[str] = mapped_column(String(30), nullable=False)
reason: Mapped[str | None] = mapped_column(Text, nullable=True)
reviewed_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
class KnowledgePublishLog(Base):
__tablename__ = "sys_knowledge_publish_log"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
from_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
to_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
action: Mapped[str] = mapped_column(String(30), nullable=False)
keep_open: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
detail_json: Mapped[str | None] = mapped_column(Text, nullable=True)
operated_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
class KnowledgeRetrievalLog(Base):
__tablename__ = "sys_knowledge_retrieval_log"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
session_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
message_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
user_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
question: Mapped[str] = mapped_column(Text, nullable=False)
catalog_snapshot: Mapped[str] = mapped_column(Text, nullable=False)
catalog_hash: Mapped[str] = mapped_column(String(64), nullable=False)
safety_rule_version: Mapped[str] = mapped_column(String(50), nullable=False)
knowledge_called: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
selected_knowledge_ids: Mapped[str | None] = mapped_column(String(500), nullable=True)
query_terms: Mapped[str | None] = mapped_column(Text, nullable=True)
tool_trace: Mapped[str | None] = mapped_column(Text, nullable=True)
final_section_ids: Mapped[str | None] = mapped_column(String(500), nullable=True)
discarded_conflicts: Mapped[str | None] = mapped_column(Text, nullable=True)
final_answer: Mapped[str | None] = mapped_column(Text, nullable=True)
status: Mapped[str] = mapped_column(String(20), nullable=False)
tool_cost_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
total_cost_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
attention_created: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
class KnowledgeRetrievalCandidate(Base):
__tablename__ = "sys_knowledge_retrieval_candidate"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
retrieval_log_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_retrieval_log.id"), index=True, nullable=False)
knowledge_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
version_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
chunk_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
section_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
lexical_score: Mapped[str] = mapped_column(String(30), nullable=False)
rerank_score: Mapped[str | None] = mapped_column(String(30), nullable=True)
selected: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
discard_reason: Mapped[str | None] = mapped_column(String(255), nullable=True)
class HumanAttentionRecord(Base):
__tablename__ = "sys_human_attention_record"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
session_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
message_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
user_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
trigger_message: Mapped[str] = mapped_column(Text, nullable=False)
problem_summary: Mapped[str] = mapped_column(Text, nullable=False)
trigger_reason: Mapped[str] = mapped_column(Text, nullable=False)
priority: Mapped[str] = mapped_column(String(20), index=True, nullable=False)
status: Mapped[str] = mapped_column(String(20), index=True, default="pending", nullable=False)
handler_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
handler_note: Mapped[str | None] = mapped_column(Text, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
class HumanAttentionHistory(Base):
__tablename__ = "sys_human_attention_history"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
attention_id: Mapped[int] = mapped_column(ForeignKey("sys_human_attention_record.id"), index=True, nullable=False)
from_status: Mapped[str | None] = mapped_column(String(20), nullable=True)
to_status: Mapped[str] = mapped_column(String(20), nullable=False)
note: Mapped[str | None] = mapped_column(Text, nullable=True)
operated_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)