# AstroResearch Database Schema / 数据库设计 AstroResearch 使用轻量级、零配置的 **SQLite** 数据库作为持久化存储。数据库文件默认保存在项目根目录下的 `astro_research.db`(可通过 `.env` 中的 `DATABASE_URL` 配置),由 Rust 中的 `sqlx` 驱动管理并自动执行迁移。 --- ## 1. 实体关系图 (Entity-Relationship Diagram) ```mermaid erDiagram PAPERS { text bibcode PK text title text authors "JSON Array" text year text pub "Journal/Publisher" text keywords "JSON Array" text abstract text doi text arxiv_id integer citation_count integer reference_count text doctype "文献类型" text pdf_path "PDF 物理路径 或 error:诊断" text html_path "HTML 物理路径 或 error:诊断" text markdown_path "Markdown 物理路径" text translation_path "翻译文件物理路径" datetime created_at } NOTES { integer id PK text bibcode FK integer paragraph_index text note_text text highlight_color text selected_text datetime created_at } CITATIONS_REFERENCES { text source_bibcode PK text target_bibcode PK } SYNC_QUERIES { integer id PK text query "检索关键词" text source "数据源" integer limit_count "拉取上限" datetime last_run "最近运行时间" datetime created_at "创建时间" } PAPER_CHUNKS_CONTENT { integer rowid PK text bibcode FK integer paragraph_index text content text headings "章节路径" integer section_index "章节编号" } PAPER_TARGETS { integer id PK text bibcode FK text target_name "标准化天体名称" text ra "赤经" text dec "赤纬" real parallax "视差 mas" text spectral_type "光谱分类" real v_magnitude "视星等" text aliases "JSON Array" text otype "天体类型" text oname "SIMBAD 主名称" real pm_ra "自行 RA" real pm_de "自行 Dec" real radial_velocity "视向速度" real parallax_err "视差误差" text photometry "测光数据 JSON" } AGENT_SESSIONS { text session_id PK text title text model integer turn_count text last_error text summary text metadata datetime deleted_at integer rewind_count "回退计数" text parent_session_id FK "分支来源" text branch_metadata "分支元数据" text mode "模式标识符" } AGENT_MESSAGES { integer id PK text session_id FK integer turn_index integer step_index text role "system/user/assistant/tool" text content text thought "思考链" text tool_calls "工具调用 JSON" text tool_call_id "工具调用 ID" integer token_count text metadata text raw_json text agent_name "消息归属" integer active "软删除标记" } AGENT_TASKS { integer id PK text session_id FK text task_id text content text status "pending/in_progress/completed" text blocked_by "JSON Array — DAG 依赖" text owner "分配目标 agent 名称" } AGENT_AUDIT_LOG { integer id PK text session_id FK integer step text tool_name text status "OK / FAIL / SESSION_STOP" integer elapsed_ms text output_preview text agent_name } AGENT_TEAM_MEMBERS { integer id PK text session_id FK text agent_name text agent_role text status "spawning / active / idle / shutdown" } PAPERS ||--o{ NOTES : "has" PAPERS ||--o{ CITATIONS_REFERENCES : "cites / cited_by" PAPERS ||--o{ PAPER_CHUNKS_CONTENT : "chunked into" PAPERS ||--o{ PAPER_TARGETS : "contains" AGENT_SESSIONS ||--o{ AGENT_MESSAGES : "contains" AGENT_SESSIONS ||--o{ AGENT_TASKS : "owns" AGENT_SESSIONS ||--o{ AGENT_AUDIT_LOG : "records" AGENT_SESSIONS ||--o{ AGENT_TEAM_MEMBERS : "members" AGENT_SESSIONS ||--o| AGENT_SESSIONS : "branches from" ``` --- ## 2. 数据表结构详述 (Table Schema Details) ### 2.1 papers 表 (文献元数据) 存储文献的核心元数据和本地物理存储路径。 - **特殊字段说明**: - `pdf_path` / `html_path`:正常情况下存储相对路径(如 `library/PDF/2024arXiv.pdf`)。当下载失败时,会以 `error:` 前缀存储诊断信息(如 `error:Cloudflare 拦截`)。特殊值 `error:no_resource` 表示用户手动标记了"无有效全文资源"。 - `doctype`:文献类型标识,如 `article`、`eprint`、`proceedings`、`phdthesis`、`catalog`、`software`、`circular`、`book` 等。 - **索引**: - `idx_papers_doi` -> 基于 `doi` - `idx_papers_arxiv_id` -> 基于 `arxiv_id` ### 2.2 citations_references 表 (引文与参考文献拓扑) 多对多关联表,存储文献之间的引用网络(即拓扑星系图的基础数据)。 - **复合主键**:`(source_bibcode, target_bibcode)` - **索引**: - `idx_citations_ref_source` -> 优化以 `source_bibcode` 查询参考文献 - `idx_citations_ref_target` -> 优化以 `target_bibcode` 查询被引文献 ### 2.3 notes 表 (高亮与阅读笔记) 存储学者在阅读器中对特定段落创建的高亮和笔记。 - **外键**:`bibcode` 级联删除 (`ON DELETE CASCADE`)。 - **索引**: - `idx_notes_bibcode` -> 优化单篇文献的笔记列表查询。 ### 2.4 sync_queries 表 (同步检索条件) 存储用户保存的批量同步检索条件,支持快速重新同步。 - **唯一约束**:`UNIQUE(query, source, limit_count)` 确保相同条件的检索不会重复保存。 ### 2.5 paper_chunks_content 表 (RAG 文本切片) 存储文献 Markdown 段落的文本切片,用于向量嵌入和混合检索。 - `rowid`:自增主键,与 `vec_paper_chunks` 虚拟表的 rowid 保持 1:1 对齐。 - `headings`:章节路径,如 `"Introduction > Background"`,用于结构化检索。 - `section_index`:章节内的段落编号。 - **外键**:`bibcode` 级联删除 (`ON DELETE CASCADE`)。 - **关联 FTS5**:`paper_chunks_fts` 虚拟表通过触发器自动同步 `content` 字段。 ### 2.6 paper_targets 表 (天体目标缓存) 存储从文献中提取并通过 CDS Sesame 解析的天体物理参数。 - `target_name`:标准化天体名称(如 `GD 358`)。 - `ra` / `dec`:赤道坐标(赤经/赤纬)。 - `parallax`:视差(mas,毫角秒)。 - `spectral_type`:光谱分类(如 `DA1`)。 - `otype` / `oname`:Sesame v4 返回的天体类型和 SIMBAD 官方主名称。 - `pm_ra` / `pm_de`:自行分量(mas/yr)。 - `radial_velocity`:视向速度。 - `photometry`:多波段测光数据(JSON 文本)。 - **唯一约束**:`UNIQUE(bibcode, target_name)`。 - **索引**:`idx_paper_targets_name`。 ### 2.7 agent_sessions 表 (Agent 会话) 存储 ReAct 智能体对话会话的元数据。 - `deleted_at`:软删除时间戳(NULL 表示活跃会话)。 - `rewind_count`:会话回退(undo)次数,用于追踪重做历史。 - `parent_session_id`:分支来源会话 ID,支持会话分叉(branch)。 - `branch_metadata`:分支元数据(JSON 文本)。 - `mode`:会话模式标识符(`default`、`deep-research`、`literature-reader`),控制 Agent 的行为配置。 - **索引**:`idx_agent_sessions_updated`(WHERE deleted_at IS NULL,仅索引活跃会话)。 ### 2.8 agent_messages 表 (Agent 消息) 存储 Agent 会话的完整对话历史,包括思考链和工具调用。 - `role`:`system` / `user` / `assistant` / `tool`。 - `thought`:LLM 思考链内容(CoT)。 - `tool_calls`:工具调用 JSON(函数名 + 参数)。 - `tool_call_id`:工具调用唯一标识(用于 SSE 流中 tool_call ↔ tool_result 配对)。 - `agent_name`:消息归属(`lead` / 子代理名 / teammate 名),支持身份隔离。 - `active`:软删除标记(`0` = 已回退隐藏,`1` = 正常可见),用于 session rewind。 - **索引**:`idx_agent_messages_session`、`idx_agent_messages_turn`、`idx_agent_messages_agent`、`idx_agent_messages_active`。 - **关联 FTS5**:`agent_messages_fts` 虚拟表通过触发器自动同步 `content`、`thought`、`tool_calls` 字段。 ### 2.9 agent_tasks 表 (Agent 任务追踪) 持久化智能体的结构化待办任务,支持 DAG 依赖模式。 - `blocked_by`:JSON 数组,前置任务 ID 列表。 - `status` 生命周期:`pending` → `in_progress` → `completed`。 - `owner`:分配目标 agent 名称(多 Agent 团队协作路由)。 - **索引**:`idx_agent_tasks_session`、`idx_agent_tasks_status`、`idx_agent_tasks_session_task` (UNIQUE)。 ### 2.10 agent_audit_log 表 (Agent 工具审计) 记录所有工具调用的审计信息:工具名称、执行状态、耗时 (ms)、输出预览。 - `status`:`OK` / `FAIL` / `SESSION_STOP`。 - `agent_name`:区分 lead/子代理/teammate 的调用来源。 - **用途**:`GET /api/chat/metrics` 聚合指标、会话审计回溯。 ### 2.11 agent_team_members 表 (多 Agent 团队) 管理多智能体团队中每个成员的生命周期。 - `status`:`spawning` → `active` → `idle` → `shutdown`。 - `agent_role`:区分 team lead / teammate 等角色。 - **唯一约束**:`UNIQUE(session_id, agent_name)`。 ### 2.12 全文搜索 (FTS5) 系统在以下实体表上建立了 FTS5 全文索引,通过触发器自动保持同步: | FTS5 虚拟表 | 实体表 | 索引字段 | 用途 | |:---|:---|:---|:---| | `papers_fts` | `papers` | title, authors, keywords, abstract, pub | 本地文献 BM25 全文检索 | | `paper_chunks_fts` | `paper_chunks_content` | content | 段落级稀疏检索,配合 `vec_paper_chunks` 向量做混合搜索 | | `agent_sessions_fts` | `agent_sessions` | session_id, title, summary, metadata | 会话历史搜索 | | `agent_messages_fts` | `agent_messages` | session_id, role, content, thought, tool_calls | 对话内容搜索 | 每个 FTS5 虚拟表通过 `content='<实体表>'` 声明为外部内容表,并配套 `_insert`、`_update`、`_delete` 三个触发器保持数据同步。 --- ## 3. 数据库迁移说明 ### 3.1 迁移机制 迁移脚本存放在 `migrations/` 目录下,使用 `sqlx` 的 **change-based 迁移** 模型: - **编译期嵌入**:`sqlx::migrate!("./migrations")` 宏在编译时将 `.sql` 文件嵌入二进制 - **启动时自动执行**:`src/main.rs`、`src/bin/cli.rs` 以及所有测试的 in-memory 数据库在启动时调用 `.run(&pool)`,对比 `_sqlx_migrations` 追踪表,按版本号顺序执行未应用的迁移 - **版本号规则**:文件名格式 `YYYYMMDDHHMMSS_description.sql`,时间戳前缀保证全局唯一排序 - **幂等性**:所有 DDL 必须使用 `IF NOT EXISTS` / `IF EXISTS`,确保可重复执行 - **checksum 校验**:sqlx 对每个迁移文件计算 SHA-256 校验和并存入 `_sqlx_migrations`;若文件内容在已应用后被修改,启动时将拒绝执行(防止 schema 漂移) ### 3.2 当前迁移 | 迁移文件 | 说明 | |:---|:---| | `00000000000000_init.sql` | **完整初始化**:包含所有表、索引、FTS5 虚拟表及同步触发器,详见第 2 节各表结构。 | > **注意**:`vec_paper_chunks` 向量虚拟表由 `src/main.rs` 在迁移之后动态创建,维度由 `EMBEDDING_DIM` 环境变量控制(默认 1536),不在迁移文件中管理。 ### 3.3 新增迁移 开发新功能需要变更数据库 schema 时: 1. 在 `migrations/` 下新建文件,命名 `YYYYMMDDHHMMSS_<简短描述>.sql`(取当前时间) 2. 编写增量 SQL(`ALTER TABLE ADD COLUMN`、`CREATE TABLE IF NOT EXISTS` 等) 3. 运行 `cargo build && cargo test` 验证 4. 更新本文档的 3.2 节和对应的表结构说明 **SQLite 约束**:SQLite 不支持事务性 DDL 的全部语义,且 `ALTER TABLE` 能力有限(不支持 `DROP COLUMN`、`RENAME COLUMN` 等旧版本的常见操作)。新增字段时务必使用 `DEFAULT` 值以保证向后兼容。 ### 3.4 迁移 Squash 开发期产生的增量迁移应在 **首次正式发布前** squash 为单一 `init.sql`,避免迁移文件线性膨胀。Squash 流程: 1. **导出完整 schema**:`sqlite3 library/astro_research.db .schema` 2. **移除以下内容**: - `_sqlx_migrations` 表(sqlx 自动管理) - `sqlite_sequence` 表(SQLite 内部表) - `vec_paper_chunks` 及其关联内部表(由 main.rs 运行时创建) - 所有 FTS5 内部表(`_data`、`_idx`、`_docsize`、`_config`,由 FTS5 自动管理) 3. **写入 `migrations/00000000000000_init.sql`**:确保所有 DDL 带 `IF NOT EXISTS` / `IF EXISTS` 4. **删除所有旧迁移文件** 5. **重建二进制**:`cargo build`(新迁移文件需嵌入) 6. **更新已有数据库**(保留数据): ```sql DELETE FROM _sqlx_migrations; -- 重启应用后 sqlx 自动应用新的 init 迁移(所有 IF NOT EXISTS 均为 no-op) ``` 7. **验证**:`cargo test --lib && cargo run` > 本项目在 2026-06-25 执行了一次 squash,将 18 个开发期增量迁移合并为 1 个 `00000000000000_init.sql`,同时保留了已有的 1341 条文献记录和 6477 条引用关系。 --- ## 4. 错误诊断存储约定 系统使用 `papers` 表的 `pdf_path` 和 `html_path` 字段的双重语义来同时存储正常路径和错误诊断: | 字段值模式 | 含义 | 前端展示 | |:---|:---|:---| | `NULL` | 尚未尝试下载 | 琥珀色"未下载"角标 | | `library/PDF/xxx.pdf` | 下载成功,正常物理路径 | 蓝色"已下载"角标 | | `error:具体原因` | 下载失败,原因为前缀后的文本 | 红色"下载失败"角标,悬浮显示原因 | | `error:no_resource` | 用户手动标记为无有效全文资源 | 灰色"无资源"角标 | `health_check` 工具在 `--fix` 模式下会清理损坏文件并将路径重置为 `NULL`,但**不会**清除 `error:` 前缀的记录(以保留诊断线索)。