Skip to content

AI 资料前后端 schema 不一致导致字段保存后丢失 #5

Description

@Maple0517

问题描述

AI 资料的前端 schema 和后端 Rust schema 不一致,导致部分 AI 资料字段在保存/读取 round-trip 后被后端丢弃。

这会影响世界观分类、重要性过滤、地点层级和地图降级说明等功能。

为什么看起来不是 by design

前端并不是把这些字段当临时字段使用,而是在多个核心流程里依赖它们:

  • prompt 要求模型输出:
    • worldview.category
    • importance: high|medium|low
    • locations.parentName
  • 前端类型定义包含:
    • AiBookNote.category
    • AiBookNote.importance
    • AiBookCharacter.importance
    • AiBookRelationship.importance
    • AiBookLocation.parentName
    • AiBookLocation.importance
    • AiBookMap.fallback
    • AiBookMap.fallbackReason
  • UI 展示和过滤依赖:
    • 世界观按 category 分组
    • 角色/关系/地点按 importance 过滤 low-value 项
    • 地点树按 parentName 构建层级
    • 地图 fallback 区域展示 fallbackReason

但 Rust 后端模型没有这些字段。

前端字段示例

frontend/src/types/index.ts 中包含:

export interface AiBookNote {
  title: string
  content: string
  category?: string
  confidence?: string
  importance?: string
}

export interface AiBookCharacter {
  name: string
  aliases?: string[]
  status: string
  faction?: string
  location?: string
  description?: string
  lastSeenChapter?: string
  importance?: string
}

export interface AiBookRelationship {
  source: string
  target: string
  relation: string
  status?: string
  description?: string
  importance?: string
}

export interface AiBookLocation {
  name: string
  kind?: string
  parentName?: string
  description: string
  status?: string
  relatedCharacters?: string[]
  firstSeenChapter?: string
  importance?: string
}

export interface AiBookMap {
  imageUrl?: string
  prompt?: string
  updatedAt?: number
  sourceChapterIndex?: number
  fallback?: 'relationship-graph'
  fallbackReason?: string
}

后端缺失字段

src/model/ai_book.rs 中目前缺少对应字段,例如:

pub struct AiBookNote {
    pub title: String,
    pub content: String,
    pub confidence: Option<String>,
}

pub struct AiBookCharacter {
    pub name: String,
    pub aliases: Vec<String>,
    pub status: String,
    pub faction: Option<String>,
    pub location: Option<String>,
    pub description: Option<String>,
    pub last_seen_chapter: Option<String>,
}

pub struct AiBookRelationship {
    pub source: String,
    pub target: String,
    pub relation: String,
    pub status: Option<String>,
    pub description: Option<String>,
}

pub struct AiBookLocation {
    pub name: String,
    pub kind: Option<String>,
    pub description: String,
    pub status: Option<String>,
    pub related_characters: Vec<String>,
    pub first_seen_chapter: Option<String>,
}

pub struct AiBookMap {
    pub image_url: Option<String>,
    pub prompt: Option<String>,
    pub updated_at: Option<i64>,
    pub source_chapter_index: Option<i32>,
}

实际影响

因为 /reader3/saveAiBookMemory 接收的是 Json<AiBookMemory>,serde 反序列化时会忽略 Rust struct 中不存在的字段;随后 AiBookService::save_for_book() 又把 Rust struct 序列化成 JSON 保存。

因此前端传来的未知字段会在保存时被静默删除。

影响包括:

  1. worldview.category 丢失后,世界观分组退化为默认分类。
  2. importance 丢失后,低价值角色/关系/地点过滤不稳定。
  3. locations.parentName 丢失后,地点层级树无法可靠保存。
  4. map.fallbackReason 丢失后,关系图 fallback 无法展示真实降级原因。
  5. map.fallback 丢失后,前端无法区分“图片地图缺失”与“主动降级关系图”。

本地观察

本地生成 AI 资料后,SQLite 中 ai_book_memories.json 里的相关字段为 null/缺失,例如:

bookName | worldview[0].title | worldview[0].category | worldview[0].importance | locations[0].name | locations[0].parentName | locations[0].importance | map.fallback | map.fallbackReason
没钱修什么仙? | 昆墟层级结构 | null | null | 昆墟 | null | null | null | null
奥术神座 | 亚伦黑帮的地盘与行事边界 | null | null | 阿尔托 | null | null | null | null

这些字段前端生成逻辑正常会携带或默认补齐,因此更像后端保存时被丢弃。

期望结果

前端 AI 资料 schema 和后端 Rust AiBookMemory schema 应保持一致,保存后不应丢字段。

建议补齐:

  • AiBookNote.category
  • AiBookNote.importance
  • AiBookCharacter.importance
  • AiBookRelationship.importance
  • AiBookLocation.parentName
  • AiBookLocation.importance
  • AiBookMap.fallback
  • AiBookMap.fallbackReason

建议测试

增加后端 round-trip 测试:

  1. 构造包含上述字段的 AiBookMemory JSON。
  2. 通过 save_for_book() 或 API 保存。
  3. 再读取。
  4. 断言这些字段仍然存在。

这样可以防止之后前端扩展 AI 资料字段时再次出现静默丢字段。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions