TrueForge Hackathon作品,通过移除「导出」工具本身而非约束prompt来防止AI Agent泄露数据,实现了即使被prompt注入也无法调用导出功能的架构。
你的 AI Agent 能读取你的数据库。这正是它有用的地方——问它上周收到了多少工单,它写查询语句、执行、回答:1,284 条。
现在有人让它导出客户邮箱。
同样的访问权限。同样的服从。邮箱、电话、私人工单备注——一个查询就能全部拿走。

在 TrueForge Agent Harness Hackathon 期间(为期一周,截止于今天),我构建了 Need-to-Know:一个让上述导出不会遭到拒绝——而是不可能实现的系统。那个会导出数据的工具根本不存在,所以没有任何东西可以被骗。
这篇文章是诚实的构建日志:它如何工作、TrueForge 实际为我们提供了什么、review bot 捕获的三个 bug,以及十三次运行中失败的那一次。
仓库(你可以在下面自行验证所有内容):https://github.com/MachineLearning-Nerd/need-to-know
大多数系统如今如何保护数据?在 system prompt 里礼貌地请求 AI:
"不要导出个人数据。不要泄露邮箱。请务必谨慎。"
三个问题,且没有一个罕见:
Prompt 注入。有人在消息、文档或工具返回值中藏入一行——"忽略你的规则"——规则就翻转了。
长对话。对话越长,AI 对一小时前读到的某条规则的注意力就越少。
只需要一次失误。AI 可以表现 999 次。一次糟糕的回答,数据就出去了——对于泄露的邮箱列表,没有撤销可言。

prompt 是一条请求。真正的边界必须在 AI 被迷惑、被欺骗或仅仅出错时仍然成立。所以我们没有请求 AI 守规矩,而是改变了它物理上能做的事。
所有原始行都存放在金库(一个 Agent 连接的 MCP server)内的一个小型数据库中。Agent 恰好获得五个工具:
注意到少了什么吗:没有"导出行"工具。不是被阻止——是不存在。随便欺骗 AI;危险的请求没有工具可以落脚。
询问"按周和地区统计工单",金库在内部完成分组和计数,然后只输出总数:

在任何数据被释放之前,validate_release 运行一张检查清单。这是 plain code、无趣的代码——里面没有任何 AI。同样的输入,每次都得到同样的答案。它检查:
为什么要释放它?只允许一个批准的理由。
谁会看到它?只允许一个批准的受众。
哪些列?每列都必须在预批准列表上。
每个分组都足够大吗?每个计数必须覆盖至少 3 个人——2 人的"分组"小到可以猜出是谁,所以被阻止。
最后它计算一个指纹(sha256 哈希)——即被释放的确切数字的独特印章。改一个数字,指纹就变了。

AI 提问。Plain code 决定。
release 工具不是直接运行。TrueForge 暂停整个 turn,向人类精确展示要出去的内容:理由、受众、列、最小分组大小,以及指纹。人类点击 Allow 或 Deny。
这是我最在乎的部分:在它实际运行的时刻,金库再次检查一切——每条规则,以及从头重新计算的指纹。如果有任何内容与人类批准的哪怕有微小差异:什么都不运行,并在审计日志中写入一条记录。

你批准的内容和实际运行的内容完全一致。
每次释放都生成一张收据,与产生它的存储服务器事件打包在一起。一个小型命令行工具重新检查整个故事:prepare → validate → approval → release 是否按确切顺序发生?重新计算时指纹是否仍然匹配?它可以离线工作——不需要服务器、不需要 AI key,只需要 Node:
git clone https://github.com/MachineLearning-Nerd/need-to-know && cd need-to-know
npm install
npm test # 365 tests
npm run verify-receipt -- evidence/attempt-9-bundle.json
# verify-receipt: PASS receipt=r-4ed4eb7a-... query=q-7ca61fb7-...

你可以读一百篇"构建于 X 之上的"帖子,却永远学不到 X 真正做了什么。以下是真实的分工。
杀手级特性:内置工具审批。在 Agent 配置中加一行——require_approval_for_tools: ["release_result"]——harness 就包办其余所有:真正的操作上暂停、待处理调用及其完整参数出现在 API 和 UI 中、人类的决定被保存为事件。我们没有构建暂停系统、审批队列或恢复路径。整个项目都依赖于此,而这只需要一行。
保存的事件是收据成为可能的原因。TrueForge 存储每个 turn 的每个事件,并允许你取回它们。我们的验证器从不信任我们现场看到的内容——它总是重新获取服务器存储的内容。没有这个,"这是一张收据"就只是"相信我"。
冻结的 Agent 配置。当会话启动时,TrueForge 对 Agent 的设置进行快照。我们的验证器将该快照与我们发布的版本进行比对——所以会话不会悄悄使用与我们声称的不同工具列表。
MCP 支持。金库作为 Agent 唯一的工具服务器接入,通过一个 setup 脚本注册。那五个工具就是整个攻击面——这是设计如此。
Ask User Questions。如果请求缺少某些内容(比如这些数字是给谁的),Agent 在接触金库之前会暂停并提供一组固定选项——而不是去猜测。
Generative UI。金库编写自己的结果卡片,Agent 必须原样传递——我们逐字节检查,所以 AI 不能重新措辞证据。
重连不丢事件。在 turn 中途断开连接、重连,你会按顺序获得每一个遗漏的事件。我们为这个写了一个证明脚本,因为一个遗漏事件的审批屏幕比没有更糟糕。
沙箱。释放之后,Agent 在 TrueForge 的沙箱中重新相加释放的数字并重新计算指纹——而我们自己的检查也从存储的字节重新计算。没有人的说法被采信,沙箱的也不信。
我们故意关闭的东西——以及一个坑。子 Agent 被禁用:在 trueforge 0.1.4 中,子 Agent 继承父 Agent 的工具,这会在我们的审批链旁边开一扇侧门——所以验证器拒绝任何使用了子 Agent 的运行。还有一个节省你一小时的小提示:0.1.4 只监听 IPv6——用 http://localhost:8891,不要用 127.0.0.1。
每个 pull request 都经过了 Qodo review。三个发现是真实的,而它们是我最喜欢的部分:
离线的检查器(PR #8)。我们的测试 harness 忘记将服务器地址传给验证器——所以它在离线模式下悄悄检查运行,而我们将其记录为"已针对实时服务器验证"。运行没问题;我们的声明比我们的检查更强。已修复,正确地重新验证,并写在运行日志中。
死掉的收据(PR #9)。开始新分析没有清除控制台屏幕上旧的收据——所以旧收据可能出现在新问题旁边。通过在每次新分析时清除证据面板来修复,并将每张收据绑定到它自己的查询 ID。
那个通过的"not"(PR #11)。我们的一项检查只是在 AI 的消息中查找指纹出现。这意味着句子"这不等于 <fingerprint>"会通过。一个否认证明的句子会通过证明检查。通过要求确认必须以消息开头并拒绝"not"和"unless"等词来修复。
最后一个就是整个项目的缩影:不要检查正确的词语是否出现——检查事物本身。
对限制保持诚实是设计的一部分,所以:我们可以证明审批以正确顺序发生——但不能密码学地证明是谁点击的。离线检查比实时检查弱(bundle 携带它自己的事件)。这些都不能防御服务器自己的管理员重写存储历史。完整细节在仓库中:docs/THREAT_MODEL.md 和 docs/LIMITATIONS.md。
仓库:https://github.com/MachineLearning-Nerd/need-to-know——60 秒离线检查只需 Node ≥ 24。
Prompt 是一条请求。边界是在 AI 犯错时仍然成立的东西。
只给 Agent 它需要的工具——让危险的工具不存在。
让 plain code,不是 AI,决定什么可以出去。
为真正的操作暂停,让人类介入——然后在运行时再次检查一切。
发出任何人都可以验证的收据。
你无法泄露你无法调用的东西。
在 TrueFoundry × WeMakeDevs 的 TrueForge Agent Harness Hackathon 中用一周构建,Qodo 审查了每个 PR。以 AI 编码助手作为结对程序员构建;每个更改都经过人工审查。所有数据均为合成数据。动画由 Manim 制作。