"""管理会计OS — 知识摘要模块 仿 OpenCode 的持久记忆机制(summarizer + SummaryMessageID),但做了三处改进: 1. 分层压缩(日→周→月→全部),不是一次性全量压缩 2. 结构化存储(MySQL 关系表),不是 SQLite JSON 消息 3. 保留版本链,不是覆盖式压缩 参考:OpenCode SummarizeProvider 的 prompt 框架 + CMA OperationLog 的审计日志 """ from sqlalchemy import Column, Integer, String, Text, DateTime, JSON, ForeignKey, Float, func from app.database import Base class KnowledgeEvent(Base): """关键事件记录 自动从 OperationLog 和其他数据源抽取的"值得记住"的事件。 每个事件是一个结构化记录,包含类型、级别、关联对象、摘要描述。 这是增量压缩的输入——摘要 agent 只处理"未摘要过"的新事件。 """ __tablename__ = "knowledge_events" id = Column(Integer, primary_key=True, index=True) event_type = Column(String(30), nullable=False, comment="事件类型: kpi_change/alert/decision/plan/map/import/user_action") event_level = Column(String(20), default="info", comment="info/warning/important/critical") source = Column(String(50), nullable=True, comment="来源: operation_log/api/erp_sync/manual") source_id = Column(Integer, nullable=True, comment="源记录ID(如 operation_log.id)") target_type = Column(String(50), nullable=True, comment="关联对象类型: kpi/map/budget/alert/plan") target_id = Column(Integer, nullable=True, comment="关联对象ID") title = Column(String(300), nullable=False, comment="事件标题(一句话概括)") description = Column(Text, nullable=True, comment="事件详细描述") delta = Column(JSON, nullable=True, comment="变更字段和前后值: {field: {old: X, new: Y}}") occurred_at = Column(DateTime, nullable=False, comment="事件发生时间") created_at = Column(DateTime, server_default=func.now()) # 摘要追踪——记录该事件被哪些摘要(id列表)包含 summarized_in = Column(JSON, nullable=True, comment="包含此事件的摘要ID列表") class KnowledgeSummary(Base): """知识摘要 分层存储:daily/weekly/monthly/cumulative 参考 OpenCode 的 summary_message_id 机制,但用结构化字段代替 message 指针。 """ __tablename__ = "knowledge_summaries" id = Column(Integer, primary_key=True, index=True) level = Column(String(20), nullable=False, comment="摘要层级: daily/weekly/monthly/cumulative") period_key = Column(String(20), nullable=False, comment="期间标识: 2026-06-12 / 2026-W24 / 2026-06 / cumulative") title = Column(String(300), nullable=False, comment="摘要标题") content = Column(Text, nullable=False, comment="摘要正文(纯文本/Markdown)") event_ids = Column(JSON, nullable=True, comment="包含的事件ID列表") # 核心指标变化(精简提取,用于快速问答) kpi_changes = Column(JSON, nullable=True, comment="摘要期内的KPI变化统计: [{kpi_code, kpi_name, old_value, new_value, direction, alert_level}]") decision_points = Column(JSON, nullable=True, comment="决策点: [{time, action, actor, result}]") key_metrics = Column(JSON, nullable=True, comment="摘要期内的关键指标快照: {kpi_code: value}") # 元信息 prev_summary_id = Column(Integer, nullable=True, comment="上一级摘要ID(如 daily→weekly 的链路)") next_compressed_by = Column(Integer, nullable=True, comment="被哪个更高层摘要包含") token_estimate = Column(Integer, default=0, comment="估算token数(用于触发压缩阈值判断)") model = Column(String(50), nullable=True, comment="生成摘要使用的模型名") generated_by = Column(String(100), nullable=True, comment="生成方式: auto_scheduler/manual_trigger") is_stale = Column(Integer, default=0, comment="0=最新 1=已被上层摘要覆盖") created_at = Column(DateTime, server_default=func.now())