2026-07-07 21:52:11 +08:00
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 企微IT智能服务台 — 阶段5 自动化闭环 数据模型
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 说明:自动化引擎相关表,表名统一前缀 auto_。
|
|
|
|
|
|
# 模型清单:
|
|
|
|
|
|
# 1. AutoSession — 自动化处置会话(生命周期/状态机)
|
|
|
|
|
|
# 2. AutoAction — 单个处置动作(与场景动作计划对应)
|
|
|
|
|
|
# 3. ApprovalTicket — 审批单(高危动作 / 员工二次确认)
|
|
|
|
|
|
# 4. ScenarioConfig — 场景配置(开关 + 触发条件 + 动作 + 审批策略)
|
|
|
|
|
|
# 5. RuleVersion — 规则版本(P1 灰度发布)
|
|
|
|
|
|
# 6. ActionLog — 外部调用审计日志(出入参全记录)
|
|
|
|
|
|
# 7. MappingCache — 终端/员工映射缓存(联软>eHR,TTL)
|
|
|
|
|
|
#
|
|
|
|
|
|
# 风格:沿用项目既有模型写法(SQLAlchemy 2.0 Mapped / mapped_column + 注释)。
|
|
|
|
|
|
# 关联:AutoSession 与工单(conversation)为「弱关联」(仅存 conversation_id,
|
|
|
|
|
|
# 不建外键约束,便于阶段5 独立演进)。
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
import uuid
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
|
2026-07-11 23:13:10 +08:00
|
|
|
|
from sqlalchemy import JSON, Boolean, DateTime, Float, Integer, Numeric, SmallInteger, String, Text
|
2026-07-07 21:52:11 +08:00
|
|
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
|
|
|
|
|
|
|
|
from app.database import Base
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _uuid() -> str:
|
|
|
|
|
|
"""生成 UUID 字符串主键(兼容 PostgreSQL 与 SQLite)。"""
|
|
|
|
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 1. 自动化处置会话
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class AutoSession(Base):
|
|
|
|
|
|
"""自动化处置会话 — 对应 auto_sessions 表。
|
|
|
|
|
|
|
|
|
|
|
|
一个员工的一次自动化处置诉求对应一个会话,贯穿「意图识别→动作编排→
|
|
|
|
|
|
执行/审批→处置成功→静默关单」全过程。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
id: 会话唯一ID
|
|
|
|
|
|
conversation_id: 关联工单ID(弱关联,可空)
|
|
|
|
|
|
employee_id: 发起员工企微 UserID
|
|
|
|
|
|
agent_id: 接管坐席ID(转人工后填入)
|
|
|
|
|
|
scenario_key: 命中场景(password_reset/software_install/virus_dispose/terminal_locate)
|
|
|
|
|
|
status: 会话状态机(created/running/paused/resolved/closed/handoff/error)
|
|
|
|
|
|
mode: 执行模式(plan_only/real_exec)
|
|
|
|
|
|
confidence: 意图识别置信度(0-1)
|
|
|
|
|
|
intent: 意图识别原始结果(JSON)
|
|
|
|
|
|
current_action_id: 当前正在执行的动作ID
|
|
|
|
|
|
title: 会话标题(展示用)
|
|
|
|
|
|
auto_close_at: 静默关单触发时间(写入 Redis TTL 同步)
|
|
|
|
|
|
resolved_at: 处置成功时间
|
|
|
|
|
|
closed_by: 关单/接管操作人
|
|
|
|
|
|
meta: 扩展上下文(原始消息、映射结果等)
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_sessions"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
conversation_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
|
|
|
|
|
employee_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
|
|
|
|
agent_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True, index=True)
|
|
|
|
|
|
scenario_key: Mapped[Optional[str]] = mapped_column(String(64), nullable=True, index=True)
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, default="created", index=True)
|
|
|
|
|
|
mode: Mapped[str] = mapped_column(String(20), nullable=False, default="real_exec")
|
|
|
|
|
|
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
|
|
|
|
|
intent: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
current_action_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True)
|
|
|
|
|
|
title: Mapped[str] = mapped_column(String(256), nullable=False, default="")
|
|
|
|
|
|
auto_close_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
resolved_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
closed_by: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
meta: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
2026-07-11 23:13:10 +08:00
|
|
|
|
# 复杂场景重构:暂停时间戳,用于超时计算;恢复后置 NULL
|
|
|
|
|
|
paused_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
2026-07-07 21:52:11 +08:00
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
|
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<AutoSession(id={self.id}, scenario={self.scenario_key}, status={self.status})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 2. 处置动作
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class AutoAction(Base):
|
|
|
|
|
|
"""单个处置动作 — 对应 auto_actions 表。
|
|
|
|
|
|
|
|
|
|
|
|
每个动作对应场景动作计划中的一步,由 action_registry 的适配器真正执行。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
id: 动作ID
|
|
|
|
|
|
session_id: 所属会话
|
|
|
|
|
|
action_index: 动作在计划中的顺序
|
|
|
|
|
|
action_type: 语义动作类型(password_reset_guide/software_install/virus_quarantine/terminal_locate...)
|
|
|
|
|
|
adapter: 执行适配器(huorong/lianruan/ehr/atrust/...)
|
|
|
|
|
|
risk_level: 风险等级(read/low/high)
|
|
|
|
|
|
title/description: 展示信息
|
|
|
|
|
|
status: 动作状态机
|
|
|
|
|
|
payload: 动作入参
|
|
|
|
|
|
result: 动作执行结果
|
|
|
|
|
|
error: 错误信息
|
|
|
|
|
|
approved_by/approved_at: 审批人/时间
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_actions"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
|
|
|
|
action_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
|
|
|
|
action_type: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
|
|
|
|
adapter: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
|
|
|
|
|
risk_level: Mapped[str] = mapped_column(String(16), nullable=False, default="read")
|
|
|
|
|
|
title: Mapped[str] = mapped_column(String(256), nullable=False, default="")
|
|
|
|
|
|
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending", index=True)
|
|
|
|
|
|
payload: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
result: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
approved_by: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
approved_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
|
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<AutoAction(id={self.id}, type={self.action_type}, status={self.status})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 3. 审批单
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class ApprovalTicket(Base):
|
|
|
|
|
|
"""审批单 — 对应 auto_approval_tickets 表。
|
|
|
|
|
|
|
|
|
|
|
|
高危动作需坐席审批,或写操作需员工 H5 二次确认时生成审批单。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
id: 审批单ID
|
|
|
|
|
|
action_id: 关联动作
|
|
|
|
|
|
session_id: 关联会话
|
|
|
|
|
|
approver_id: 审批人(坐席/员工)
|
|
|
|
|
|
channel: 审批渠道(agent/h5)
|
|
|
|
|
|
status: 审批状态(pending/approved/rejected/expired)
|
|
|
|
|
|
reason: 申请理由
|
|
|
|
|
|
decision_note: 审批意见
|
|
|
|
|
|
decided_at: 决定时间
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_approval_tickets"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
action_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
|
|
|
|
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
|
|
|
|
approver_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
channel: Mapped[str] = mapped_column(String(16), nullable=False, default="agent")
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending", index=True)
|
|
|
|
|
|
reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
decision_note: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
decided_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<ApprovalTicket(id={self.id}, action={self.action_id}, status={self.status})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 4. 场景配置
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class ScenarioConfig(Base):
|
|
|
|
|
|
"""场景配置 — 对应 auto_scenario_configs 表。
|
|
|
|
|
|
|
|
|
|
|
|
本期(Q5)管理后台结构化简易配置:场景开关 + 触发条件 + 动作 + 审批策略。
|
|
|
|
|
|
编排引擎列为 P2,本期动作计划为静态模板。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
scenario_key: 场景键(唯一,password_reset/software_install/virus_dispose/terminal_locate)
|
|
|
|
|
|
name/description: 展示信息
|
|
|
|
|
|
enabled: 是否启用
|
|
|
|
|
|
trigger_conditions: 触发条件({"intents":[],"keywords":[]})
|
|
|
|
|
|
actions: 动作计划(有序列表,每项 {action_type, adapter, risk_level, params})
|
|
|
|
|
|
approval_strategy: 审批策略({"read":"auto","low":"auto","high":"approval"})
|
|
|
|
|
|
current_version_id: 当前生效版本ID
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_scenario_configs"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
scenario_key: Mapped[str] = mapped_column(String(64), nullable=False, unique=True, index=True)
|
|
|
|
|
|
name: Mapped[str] = mapped_column(String(128), nullable=False, default="")
|
|
|
|
|
|
description: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
|
|
|
|
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
|
|
|
|
trigger_conditions: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
actions: Mapped[Optional[list]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
approval_strategy: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
current_version_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
|
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<ScenarioConfig(key={self.scenario_key}, enabled={self.enabled})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 5. 规则版本(P1 灰度)
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class RuleVersion(Base):
|
|
|
|
|
|
"""规则版本 — 对应 auto_rule_versions 表。
|
|
|
|
|
|
|
|
|
|
|
|
支持场景配置的版本化与灰度发布(P1):每次新建/修改生成快照,
|
|
|
|
|
|
canary_percent 控制灰度比例,status 控制 draft/published/archived。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
scenario_key: 所属场景
|
|
|
|
|
|
version: 版本号(同场景内递增)
|
|
|
|
|
|
content: 配置快照(actions + approval_strategy + trigger_conditions)
|
|
|
|
|
|
status: 版本状态(draft/published/archived)
|
|
|
|
|
|
canary_percent: 灰度比例(0-100,100 表示全量)
|
|
|
|
|
|
created_by: 创建人
|
|
|
|
|
|
remark: 版本说明
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_rule_versions"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
scenario_key: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
|
|
|
|
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
|
|
|
|
|
content: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, default="draft", index=True)
|
|
|
|
|
|
canary_percent: Mapped[int] = mapped_column(Integer, nullable=False, default=100)
|
|
|
|
|
|
created_by: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
remark: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<RuleVersion(key={self.scenario_key}, v={self.version}, status={self.status})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 6. 外部调用审计日志
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class ActionLog(Base):
|
|
|
|
|
|
"""外部调用审计日志 — 对应 auto_action_logs 表。
|
|
|
|
|
|
|
|
|
|
|
|
所有外部系统调用的出入参全量落表,满足审计与排障需求。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
session_id: 关联会话
|
|
|
|
|
|
action_id: 关联动作(可选)
|
|
|
|
|
|
employee_id: 关联员工(可选)
|
|
|
|
|
|
event: 事件名(如 huorong.isolate / dify.intent / lianruan.query)
|
|
|
|
|
|
direction: 方向(in/out)
|
|
|
|
|
|
system: 外部系统(huorong/lianruan/dify/ragflow/ehr/internal)
|
|
|
|
|
|
request/response: 出入参(脱敏后)
|
|
|
|
|
|
status: 状态(success/error/http_xxx)
|
|
|
|
|
|
latency_ms: 耗时
|
|
|
|
|
|
error: 错误
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_action_logs"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
session_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
|
|
|
|
|
action_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
|
|
|
|
|
employee_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
|
|
|
|
|
event: Mapped[str] = mapped_column(String(128), nullable=False, default="")
|
|
|
|
|
|
direction: Mapped[str] = mapped_column(String(8), nullable=False, default="out")
|
|
|
|
|
|
system: Mapped[str] = mapped_column(String(32), nullable=False, default="internal")
|
|
|
|
|
|
request: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
response: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
|
|
|
|
|
latency_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
|
|
|
|
|
error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<ActionLog(event={self.event}, system={self.system}, status={self.status})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 7. 终端/员工映射缓存
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class MappingCache(Base):
|
|
|
|
|
|
"""映射缓存 — 对应 auto_mapping_cache 表。
|
|
|
|
|
|
|
|
|
|
|
|
联软(主)解析员工→终端结果缓存,TTL 过期后回退 EHR 兜底并刷新。
|
|
|
|
|
|
避免每次处置都打联软,降低外部依赖压力。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
employee_id: 员工ID
|
|
|
|
|
|
source: 映射源(lianruan/ehr)
|
|
|
|
|
|
mapped_data: 映射结果(终端列表/部门/资产等)
|
|
|
|
|
|
expires_at: 过期时间
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_mapping_cache"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
employee_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
|
|
|
|
source: Mapped[str] = mapped_column(String(32), nullable=False, default="lianruan")
|
|
|
|
|
|
mapped_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
|
|
|
|
|
expires_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<MappingCache(employee={self.employee_id}, source={self.source})>"
|
2026-07-11 23:13:10 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 8. 信息项(复杂场景重构第一阶段)
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class InformationItem(Base):
|
|
|
|
|
|
"""信息项 — 对应 auto_information_items 表。
|
|
|
|
|
|
|
|
|
|
|
|
管理对话中收集的信息项及其变更历史,支持更正(CORRECT)与补充(SUPPLEMENT)。
|
|
|
|
|
|
|
|
|
|
|
|
修饰符(modifiers)取值:
|
|
|
|
|
|
固定 — 动作执行后锁定,不可更正
|
|
|
|
|
|
增量 — 补充时追加而非覆盖
|
|
|
|
|
|
明确 — 用户明确提供的值
|
|
|
|
|
|
隐含 — 从上下文推断的值
|
|
|
|
|
|
复述 — 更正后需向员工发送确认消息
|
|
|
|
|
|
必需 — 流程阻塞项,未填写时不可继续执行
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
id: UUID 主键
|
|
|
|
|
|
session_id: 关联会话ID(弱关联,不建外键)
|
|
|
|
|
|
name: 信息项名称(如"用户名"、"终端ID"、"部门")
|
|
|
|
|
|
value: 当前值
|
|
|
|
|
|
modifiers: 修饰符列表,如 ["固定","必需"]
|
|
|
|
|
|
is_filled: 是否已填写
|
|
|
|
|
|
is_locked: 是否已锁定(固定修饰符 + 关联动作已执行 → True,不可更正)
|
|
|
|
|
|
version: 版本号,每次更正/补充 +1
|
|
|
|
|
|
update_history: 变更历史数组
|
|
|
|
|
|
created_at: 创建时间
|
|
|
|
|
|
updated_at: 最后更新时间
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
__tablename__ = "auto_information_items"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
|
|
|
|
|
|
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
|
|
|
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
|
|
|
|
value: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
|
|
|
|
modifiers: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
|
|
|
|
|
is_filled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
|
|
|
|
is_locked: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
|
|
|
|
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
|
|
|
|
|
update_history: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
|
DateTime(timezone=True), nullable=False, default=datetime.now, onupdate=datetime.now
|
|
|
|
|
|
)
|
|
|
|
|
|
# Phase 2: 复杂场景重构第二阶段新增
|
|
|
|
|
|
derived_from: Mapped[Optional[list]] = mapped_column(JSON, nullable=True) # 推导来源 item_key 数组
|
|
|
|
|
|
correction_reason: Mapped[Optional[str]] = mapped_column(String(200), nullable=True) # 更正备注
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<InformationItem(session={self.session_id}, name={self.name}, v={self.version})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 9. 上下文压缩记录(复杂场景重构第二阶段 P2)
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class ContextCompression(Base):
|
|
|
|
|
|
"""上下文压缩记录 — 对应 auto_context_compressions 表。
|
|
|
|
|
|
|
|
|
|
|
|
每次上下文压缩操作的日志记录,包含压缩前后 token 数、压缩比、耗时等。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
session_id: 关联会话ID
|
|
|
|
|
|
tokens_before: 压缩前 token 数
|
|
|
|
|
|
tokens_after: 压缩后 token 数
|
|
|
|
|
|
compression_ratio: 压缩比(after/before)
|
|
|
|
|
|
task_node: 压缩时任务节点
|
|
|
|
|
|
duration_ms: 压缩耗时(毫秒)
|
|
|
|
|
|
compression_level: 压缩级别(1/2/3)
|
|
|
|
|
|
summary: 压缩摘要内容
|
|
|
|
|
|
"""
|
|
|
|
|
|
__tablename__ = "auto_context_compressions"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
|
|
|
|
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
|
|
|
|
tokens_before: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
|
|
|
|
tokens_after: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
|
|
|
|
compression_ratio: Mapped[float] = mapped_column(Numeric(5, 2), nullable=False)
|
|
|
|
|
|
task_node: Mapped[Optional[str]] = mapped_column(String(128), nullable=True)
|
|
|
|
|
|
duration_ms: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
|
|
|
|
compression_level: Mapped[int] = mapped_column(SmallInteger, nullable=False, default=1)
|
|
|
|
|
|
summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<ContextCompression(session={self.session_id}, {self.tokens_before}→{self.tokens_after})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
# 10. 信息项快照(复杂场景重构第二阶段 P3)
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
class InformationSnapshot(Base):
|
|
|
|
|
|
"""信息项快照 — 对应 auto_information_snapshots 表。
|
|
|
|
|
|
|
|
|
|
|
|
每次更正发生前创建快照,记录该 session 全部信息项的完整状态,
|
|
|
|
|
|
用于支持更正撤销(undo)功能。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
session_id: 关联会话ID
|
|
|
|
|
|
trigger_item_key: 触发更正的信息项 key
|
|
|
|
|
|
snapshot_data: 全部信息项快照 {item_key: {value, version}}
|
|
|
|
|
|
correction_ids: 本次更正涉及的信息项版本 ID 列表
|
|
|
|
|
|
is_undone: 是否已被撤销
|
|
|
|
|
|
"""
|
|
|
|
|
|
__tablename__ = "auto_information_snapshots"
|
|
|
|
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
|
|
|
|
session_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
|
|
|
|
trigger_item_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
|
snapshot_data: Mapped[dict] = mapped_column(JSON, nullable=False)
|
|
|
|
|
|
correction_ids: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
|
|
|
|
|
is_undone: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=datetime.now)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
|
return f"<InformationSnapshot(session={self.session_id}, trigger={self.trigger_item_key}, undone={self.is_undone})>"
|