本技能用于在 Python 项目需要增加本地数据持久化(缓存、关系型存储、文档存储等)时,提供一个默认的存储技术选型表,避免每个新会话或模型无理由地选择不同方案。它的定位是本地优先、个人规模、Python 优先的项目,不适用于生产、多租户或面向公网的场景。
选型标准(适用于下列每一条目):仅采用 MIT/Apache-2.0/BSD 类宽松许可;流行且活跃维护(以真实的 GitHub/PyPI 活动为依据);可在纯 pytest 运行中完整测试(内存或 tmp_path 范围内,无需 Docker、云账号或 CI 服务);低样板化 API,便于编码智能体正确使用。选型倾向按具体关注点选择最合适的工具,而非刻意减少项目中的技术数量。由于这些存储可在测试中真实启动,测试中不应再对其打桩(mock),否则会浪费该选择带来的可测试性价值。安全被有意不列为选型因素,因为此处均为本地个人规模默认,不应视为生产/多租户/公网建议;每个类别的“升级(Escalate to)”一行即为对应场景的选择。
主要类别与默认选择如下:
进程内临时状态:默认使用标准库(threading.Lock、time.monotonic、dict),无需库;一旦需要跨重启存活,则归入缓存或关系型类别。
缓存(TTL/淘汰):默认 diskcache(Apache-2.0,纯 Python),磁盘支撑、自带 TTL/淘汰,易于用 pytest tmp_path 测试;当多进程/多机器需共享缓存时升级到 Redis。
关系型——简单(少量表、KV 形态):默认标准库 sqlite3 + 原生 SQL,零依赖;升级到 Postgres。
关系型——复杂/OLTP(多表、真实 join、迁移、频繁写入):默认 sqlalchemy + alembic(均为 MIT)。文中说明应通过声明式基类的 type_annotation_map 为普通类型、以及 Annotated 别名为需要逐列参数的类型,统一定义列词汇表。文中还详述了 SQLite 层面的两个隐患:Numeric 会经由 float 往返而静默损坏 Decimal(举例 1234567890123456789.000000001 会变为 1234567890123456768.0000000000),带时区的 datetime 会返回 naive(dialects/sqlite/base.py 的 DATETIME.bind_processor 不读取 tzinfo)。修复方式包括用 TypeDecorator 存储精确字符串、在 table_args 传入 sqlite_strict=True,并指出 STRICT 只接受 INT/INTEGER/REAL/TEXT/BLOB/ANY,因此 create_all 会在 NUMERIC(38, 10)、DATETIME 及 String(64) 渲染出的 VARCHAR(64) 上失败(均基于 SQLAlchemy 2.0.52 实测);String(64).with_variant(Text(), "sqlite") 可在 Postgres 上保留真实边界。文中还提示 Alembic 在 SQLite 上的 batch_alter_table 通过重建表实现变更,会丢失该表触发器(Alembic 全程无触发器感知),并会跳过既被反射又未命名的 CheckConstraint;给出的缓解方式是命名每个约束,或决定 SQLite 层永不迁移、始终由当前元数据创建。
分析/OLAP(读/聚合密集):默认 duckdb(MIT),duckdb.connect(":memory:") 原生 SQL、零 ORM 仪式、join/聚合快;单写入者;2026 年 5 月发布的“Quack”多写入者协议仍属新生;升级到 Postgres+DuckDB 扩展或 MotherDuck。
文档存储(无模式/半结构化 JSON):默认 tinydb(MIT,纯 Python),类 dict API,无 SQL;维护者称其为“维护模式”(功能完备且稳定),仍有缺陷修复版本;备选 sqlitedict(Apache-2.0),但其有多年提交空白;升级到 MongoDB。
全文检索:默认 SQLite FTS5 虚拟表,随标准库 sqlite3 提供、零新依赖、内置 bm25() 排序;备选 bm25s(MIT)、tantivy(MIT,注意安装包名是 tantivy 而非已陈旧的 tantivy-py);避免 Whoosh(长期未维护);升级到 Elasticsearch 或 Meilisearch。
向量/嵌入相似度检索:默认 qdrant-client(Apache-2.0),QdrantClient(":memory:") 或 path=tmp_path 无需服务器,后续升级仅需换构造参数;备选 chromadb(Apache-2.0),社区更大、API 更简单;升级到 Qdrant Cloud 或 Pinecone/Weaviate。
后台任务/消息队列:默认 huey(MIT),SqliteHuey(..., immediate=True) 同步在进程内执行任务,pytest 可直接调用函数;升级到 Celery/RQ/Dramatiq。
定时/周期任务:默认 apscheduler 3.x(MIT),SQLAlchemyJobStore 指向 sqlite:/// URL 可跨重启持久化;提示其维护者单一(1,134 次提交 vs 次高 6 次)、约两年未审查的 PR、v4 自 2020 年起 alpha 且无稳定版,但 3.x 仍持续打补丁(最近 2026 年 6 月)。备选 schedule(MIT),零依赖但无持久化且自 2024 年 5 月起未更新;升级到托管调度器。
发布订阅/事件流:默认 blinker(MIT),进程内信号分发;升级到 NATS(Apache-2.0),但需单独配置 nats-server 且无官方维护的 pytest fixture 包。
图数据:默认 ladybug(MIT,pip install ladybug),嵌入式、Cypher 查询、无服务器,是 Kuzu(2025 年 10 月因 Apple 收购而归档)被社区 fork 后持续维护的延续,引擎相同、换了维护方,项目名仍不足一年,宜视为有潜力但年轻。轻量替代:关系型库中的 edges(src, dst, relation) 表;可搭配 networkx(BSD-3-Clause);升级到 Neo4j Aura、Amazon Neptune。
Blob/对象存储:默认用 pathlib.Path 写文件,无需库;当云存储成为实际计划时升级到 fsspec(BSD-3-Clause)+ s3fs/gcsfs。
时间序列数据:默认 duckdb(MIT),其窗口函数、time_bucket、缺口填充、ASOF join 对时序分析很强;轻量替代为带时间戳索引列的 SQLite 表;升级到 InfluxDB、TimescaleDB。
关于编辑技能:该文件在安装时被复制到 ~/.agents/skills/db-defaults-taudelta,从不使用符号链接,因此直接编辑已部署副本属于本地漂移;应在安装来源的仓库中修改、推送,并重新运行 skills add <source> --global --skill db-defaults-taudelta 以刷新各项目的副本;若从他人仓库安装,则来源归其所有,应在其处开 issue 或 PR。
起始代码片段:references/snippets/ 中每个类别各有一个真实、ruff 干净、自包含的 Python 文件,docstring 内含已核实的 pip install 命令,以及展示 pytest 本地模式的可运行 test_* 函数,可直接复制粘贴。该目录也记录了写作时遇到的两个真实命名陷阱:full-text-search.py(tantivy 与 tantivy-py 的 PyPI 混用)和 cron-scheduler.py(不存在的 SQLiteJobStore 类名)。完整论证见 references/rationale.md,包含 GitHub/PyPI 证据、各类别考虑过并否决的选项及每个分支/替代项的理由。