后端核心变更: - API 层: 新增 AppError 枚举统一错误类型,替代散落的 (StatusCode, String) - Agent 工具域: 重组为 astro/system/ 和 astro/research/ 两级域,新增 ProcessPaperTool 流水线工具 - 安全: 新增 SSRF 双层防护 (同步字符串级 + 异步 DNS 解析级),覆盖 IPv4/IPv6 私网段 - 弱密码检测: 扩展弱密码列表并增加最小长度检查 - LLM 客户端: 新增 ChatCompleter/Embedder trait,支持依赖注入与批量向量化 embed_batch - 批量处理: AssetBatch 从串行改为 Semaphore 并发池 (BATCH_CONCURRENCY=3) - 分块器: 重写为三阶段结构化管线 (章节解析→短节合并→带标题路径子块) - RAG: embedding 计算移出事务,RetrievalResult 新增 headings/section_index 字段 - 检索: ADS/arXiv 并行检索 (tokio::join!),去重改用 HashSet,本地库回填批量 IN 查询 - 天体查询: Sesame API 升级到 v4,新增视差误差/自行/视向速度/多波段测光字段 - 迁移: 14 个增量文件合并为单一 init.sql,支持 sqlx::migrate! 内存库集成测试 - 测试: circuit_breaker/hooks/task_board/session/memory/streaming_executor 新增修正 15+ 测试 前端架构重构: - 目录重组: features/ → pages/ + components/ + hooks/ 三层分离 - App.tsx 从 1181 行压缩至 ~174 行 (逻辑抽入 9 个自定义 Hook) - Agent 面板拆分为 AgentSessionSidebar/AgentMessageList/AgentInputArea 子组件 - 新增 GlobalDialog/PaperDetailModal/UncachedPaperModal 通用对话框组件 - 工具函数抽取: celestial.ts (天体坐标格式), paper.tsx (文献信息渲染)
14 KiB
AstroResearch Database Schema / 数据库设计
AstroResearch 使用轻量级、零配置的 SQLite 数据库作为持久化存储。数据库文件默认保存在项目根目录下的 astro_research.db(可通过 .env 中的 DATABASE_URL 配置),由 Rust 中的 sqlx 驱动管理并自动执行迁移。
1. 实体关系图 (Entity-Relationship Diagram)
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-> 基于doiidx_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 时:
- 在
migrations/下新建文件,命名YYYYMMDDHHMMSS_<简短描述>.sql(取当前时间) - 编写增量 SQL(
ALTER TABLE ADD COLUMN、CREATE TABLE IF NOT EXISTS等) - 运行
cargo build && cargo test验证 - 更新本文档的 3.2 节和对应的表结构说明
SQLite 约束:SQLite 不支持事务性 DDL 的全部语义,且 ALTER TABLE 能力有限(不支持 DROP COLUMN、RENAME COLUMN 等旧版本的常见操作)。新增字段时务必使用 DEFAULT 值以保证向后兼容。
3.4 迁移 Squash
开发期产生的增量迁移应在 首次正式发布前 squash 为单一 init.sql,避免迁移文件线性膨胀。Squash 流程:
- 导出完整 schema:
sqlite3 library/astro_research.db .schema - 移除以下内容:
_sqlx_migrations表(sqlx 自动管理)sqlite_sequence表(SQLite 内部表)vec_paper_chunks及其关联内部表(由 main.rs 运行时创建)- 所有 FTS5 内部表(
_data、_idx、_docsize、_config,由 FTS5 自动管理)
- 写入
migrations/00000000000000_init.sql:确保所有 DDL 带IF NOT EXISTS/IF EXISTS - 删除所有旧迁移文件
- 重建二进制:
cargo build(新迁移文件需嵌入) - 更新已有数据库(保留数据):
DELETE FROM _sqlx_migrations; -- 重启应用后 sqlx 自动应用新的 init 迁移(所有 IF NOT EXISTS 均为 no-op) - 验证:
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: 前缀的记录(以保留诊断线索)。