开发者为解决提示词迭代版本混乱问题,基于内容寻址对象模型实现了一款轻量提示词版本控制工具,支持追踪、对比和回滚Prompt版本。
你在迭代一个 LLM 的 prompt。每次改一个词,输出就变好一点。再改一个,又变差了。粘贴到 ChatGPT 里,勉强能用。把"简洁地"改成"用 3 条要点",突然总结就完美了。
然后第二天来了。你完全不知道哪个版本是好的那个。
你的文件夹看起来是这样的:
prompts/
├── summarize.txt
├── summarize_old.txt
├── summarize_v2.txt
├── summarize_v2_final.txt
├── summarize_v2_final_FINAL.txt
├── summarize_REALLY_final.txt
└── summarize_use_this_one.txt
最糟糕的是?"好的"那个可能在它们当中任意一个。😭
你无法 diff 它们。你说不出 v2_final 和 v2_final_FINAL 之间改了什么。你也无法回滚到那个真正起作用的版本。
🤔 为什么不用 git?
好问题。我也问过自己同样的问题。
可以用。技术上,PromptVault 借用了 git 的整套模型——内容寻址对象、树、提交。但实际上,prompts 是和代码混在一起的。它们混合在仓库、笔记本、聊天导出文件,还有你桌面上的各种 .txt 文件里。
Prompts 值得拥有自己的版本控制,要满足:
📂 专门跟踪 .txt/.md/.prompt/.j2/.yaml 文件
📁 存在于 .pv/ 文件夹里,不会和你代码仓库的 .git/ 冲突
🔄 为 prompt 工程实际上的"迭代—对比"工作流而生
🚫 不需要 GitHub 仓库,不同步到云端,不需要注册账号
PromptVault 就是专为 prompts 打造的 git。它用 Rust 编写,打包成单个约 2MB 的静态二进制文件,完全运行在你自己的机器上。无账号、无云端、无遥测。
$ pv init
Initialized empty prompt vault in ./.pv
$ pv add prompts/summarize.md
added: prompts/summarize.md
$ pv commit -m "refine: summarize now reports tone + title"
[main 791151d] refine: summarize now reports tone + title
1 prompt
现在可以迭代了。精确看到改了什么:
$ pv diff prompts/summarize.md
diff -- prompts/summarize.md
You are a precise summarizer.
-Summarize the text below in 3 concise bullets, then propose a title.
+Summarize the text below in 3 concise bullets, propose a title, and note the tone.
{{text}}
回溯每一步迭代:
$ pv log
commit 791151d…
parent 4100199…
Date: Mon Aug 10 10:04:33 2026 +0000
refine: summarize now reports tone + title
commit 4100199…
Date: Mon Aug 10 10:04:33 2026 +0000
feat: initial prompt set
通过 hash、tag 或 branch 恢复任意历史版本:
$ pv show 4100199 # prefix also works 🔍
$ pv revert v1.0 # restore working tree to a tagged version ⏪
🌿 用于 A/B 测试的分支
这是 prompt 工程的杀手功能。想要测试同一个 prompt 的两个变体?建分支。
$ pv branch experiment
$ pv checkout experiment
# ... tweak the prompt, commit it ...
$ pv checkout main # working tree restores to main's version
$ pv checkout experiment # ...and back to experiment's version
切换分支,工作树立即恢复。不用复制文件,不用重命名,不用"等等,experiment 在哪个文件夹来着?" 🎯
做完了,用数据集对比它们:
$ pv ab main:summarize.md experiment:summarize.md -d cases.jsonl --show
A/B: A=main:summarize.md B=experiment:summarize.md (3 cases)
[1/3] DIFF differs
--- A vs B ---
-A You are a precise summarizer.
+B You are a concise summarizer.
hello world
--- end ---
Summary: 0 identical, 3 differing (of 3)
纯本地。不调用模型。不需要 API key。🔒
💸 不花 API 钱的 Eval
现有 prompt 工具让我不爽的一点:什么都想调用模型。每次 eval 运行都要花钱。每次测试都往 OpenAI 发送数据。
PromptVault 采取了不同立场:它从不调用模型。它只渲染模板和检查断言。
$ pv eval summarize.md --dataset cases.jsonl --show
Eval: summarize.md (3 cases)
[1/3] PASS contains "3 concise bullets"
--- rendered prompt ---
You are a precise summarizer.
...
--- end ---
Summary: 2/2 passed (100%)
你写一个 JSON Lines 数据集,每行填充 prompt 的 {{variables}},PromptVault 渲染并做断言。✅
如果你真的想通过模型运行 prompt,把渲染后的输出 pipe 给你信任的任意 runner(curl、OpenAI CLI、ollama、你自己的脚本)。
这分开了现有工具混为一谈的两个关注点:
我的模板渲染正确吗?(便宜、本地、确定性)⚡
模型输出质量好吗?(昂贵、非确定性、依赖模型)💰
PromptVault 做第 1 点。第 2 点由你决定怎么做。
📋 完整功能列表
作为一个"prompts 的小型 git",最后它比我计划的要多:
📸 带消息的快照(类似 git commit)
📊 行级 diff,可以看到你具体改了哪条指令。pv diff --stat 输出每个文件的一行摘要。
🌿 分支与合并——pv branch experiment, pv merge experiment(快进或三方合并,带冲突标记)
🏷️ Tag 和回滚——pv tag v1.0, pv revert v1.0
🚫 .pvignore——gitignore 风格,让草稿不进入保险库
🔀 Ref 到 ref 的 diff——pv diff v1 v2 比较任意两个 commit/tag/branch
📂 Ref:path 访问——pv show HEAD:summarize.md 读取任意 ref 下的任意文件
🧰 Stash / reset / clean / grep / export / stats / blame——日常 git 类工具
🖥️ TUI——pv tui 启动交互式提交浏览器
🐚 Shell 补全——bash / zsh / fish / elvish / powershell
☁️ 远程同步——pv push / pv pull 将保险库同步到任意 git 主机作为后端存储
🤖 模型 runner(可选,编译时加 --features run)——pv run 对接 OpenAI/Anthropic/Ollama。API key 只存在于 env 变量中;从不记录或存储任何内容。
⚖️ A/B 测试——pv ab main:x experiment:x -d dataset.jsonl 对同一数据集渲染两个版本并 diff
🔧 内部原理
PromptVault 就是一个小型 git。pv init 后创建:
.pv/
├── HEAD → "ref: refs/heads/main"
├── index.json → staging area (path → blob hash)
├── objects/ → content-addressed store (SHA-256)
│ └── ab/cdef… → "<type>\0<data>" (blob / tree / commit)
└── refs/heads/main → latest commit hash
每个 prompt 版本都是一个 blob,通过 SHA-256(blob\0<content>) 寻址。树将路径映射到 blob。提交指向一棵树 + 父提交 + 消息。相同内容只存储一份。除非你显式执行 pv push,否则任何内容都不会离开你的机器。📦
它使用 Myers diff 算法做行级更改(与 git 相同算法),.pvignore 的 glob 匹配器是动态规划实现,避免了朴素递归匹配器在 aaa 这类模式上遭遇的指数级回溯。🧠
# 1. 预编译二进制(无需 Rust 工具链)📥
# 从 https://github.com/lululuhu/PromptVault/releases 下载
# 支持:Linux/macOS/Windows,x86_64 和 aarch64
# 2. cargo 🦀
cargo install promptvault
# 3. 从源码编译 🔧
git clone https://github.com/lululuhu/PromptVault
cd PromptVault
cargo build --release
# binary: target/release/pv (加入 PATH)
然后,在任何存放 prompts 的文件夹里:
pv init
就这样。你在给 prompts 做版本控制了。🎉
简单说一下这个,因为我觉得这很重要。
PromptVault 是本地优先的。一切都存在于你机器上的 .pv/ 里。无账号、无云端、无遥测、无分析、无"回家看看"。唯一的网络调用是你显式发起的:
☁️ pv push / pv pull 同步到你配置的 git 远程仓库
🤖 pv run(可选功能)将渲染后的 prompt 发送到模型 API
pv run 命令只从环境变量读取 API key。不记录任何内容。除了渲染后的 prompt 本身,不存储任何内容。🔐
重要警告:如果你的 prompts 包含密钥、个人身份信息或机密内容,将它们提交到保险库会将这些数据以明文形式存储在磁盘上(内容寻址的,但未加密)。推送到远程会将数据发送到那个 git 主机。和 git 一样的规则——不要 commit 你不会放进 git 的秘密。⚠️
当前是 v0.2.0。后续路线图:
🤝 更好的冲突解决 UX(目前三方合并会产生冲突标记;计划做 pv mergetool)
📜 带条件/循环的 prompt 模板(目前只是 {{var}} 替换)
🌐 历史浏览 Web UI(TUI 不错,但浏览器分享体验更好)
🪝 Hooks(pre-commit、post-checkout)用于自动化
如果你有意见,issue 跟踪器开放。🚪
如果你曾经丢失过一个好的 prompt,只因"v2_final_FINAL.txt"综合症,试一下:
🐙 GitHub: https://github.com/lululuhu/PromptVault
📦 crates.io: cargo install promptvault
🚀 Releases(预编译二进制): https://github.com/lululuhu/PromptVault/releases
⭐ 如果有用就 star 一下。🐛 如果不好用就开 issue。我公开开发,好点子上线很快。
PromptVault 采用 MIT 许可证,用 Rust 🦀 编写,运行在 Linux/macOS/Windows 上。作者与任何 AI 实验室均无关联。