这是针对 Sanity 挑战赛,路径一:构建可查询真实内容的代理
我构建了什么
哪个 AWS 配额才是当前的? 你从 AWS 文档复制了默认的 vCPU 上限,交付后在生产环境中出错。我也曾这样做过。该数字已经过时,且没有任何提醒。
以下是导致问题的原因。对于同一个 AWS 事实,三个官方页面可能会给出不同的数字。旧版用户指南说一种说法。服务配额控制台又说另一种。定价页面又给出第三种。它们都看起来很官方,但没有一个告诉你今天哪个是真实的。
于是我构建了一个代理,它能回答“哪个 AWS 值是当前的?”并予以验证。它从 Sanity Context Knowledge Base 读取已输入的事实,使用模型不得覆盖的 确定性规则 选出胜者,并展示当前值及其被取代的值,每个都带有来源。随后它完成了大多数内容代理会跳过的步骤:调用 实时 AWS API(只读)来核对即使经过调和的记录仍然是否正确。在 EC2 vCPU 配额上,它发现了三个不同的数字:文档显示 32,记录显示 5,实时显示 16,并将这三个数字全部呈现在屏幕上。
技术栈:在 Bedrock 上运行的 Amazon Nova Pro,Strands Agents(Python),通过托管的 Context MCP 读取的 Sanity Context Knowledge Base,以及只读的实时 AWS 交叉验证。
为什么关键字搜索会返回错误的 AWS 值
挑战设定了高标准:“最强的投稿展示出一个代理,只有在内容被结构化时才能工作。如果关键字搜索就能得到相同答案,那就要追求更高。”
公平。于是我特意构造了一个事实,使得关键字搜索会得到错误结果。事实上也是如此:EBS 通用目的 SSD 每卷的最大 IOPS。当前数值是 80,000(gp3,来自 EBS 控制台)。旧值是 16,000,即遗留的 gp2 上限,仍然记载在较旧的 SSD 指南中。该旧指南重复了你在搜索框中会输入的确切短语:"maximum IOPS per volume for a general purpose SSD EBS volume." 它既过时又冗长,因而关键字评分机制偏爱它。
观察它如何选择错误答案。相同内容,真实的 TF-IDF,正是一个人实际会提出的问题:
Keyword/TF-IDF baseline for: "maximum IOPS per volume general purpose SSD"
0.8626 EBS/limit: Maximum IOPS per volume for a general purpose SSD ... = 16000 <-- WRONG (old)
0.2026 EBS/limit: Maximum provisioned IOPS per gp3 volume = 80000 <-- right, ranked lower
0.0218 S3/price: S3 Standard storage, first 50 TB / month = 0.023
0.0185 EC2/quota: Running On-Demand Standard ... = 5
...
过时的 16,000 胜出数量遥遥领先。关键词搜索会给你错误的数字,而且言之凿凿。
演示
在不到一分钟内,您可以自行运行免凭证的核心(使用公开数据集通过匿名 GROQ,本地协调,只读实时 AWS 检查,无需模型或令牌):
# 1. clone + install
git clone https://github.com/simplynadaf/aws-source-of-truth-agent
cd aws-source-of-truth-agent
pip install -r requirements.txt
# 2. the credential-free path (public dataset + local reconcile + live AWS check)
python -m agent.reconcile_offline --service EBS --type limit --region us-east-1
# -> Verdict: 80000 IOPS (serviceQuotasConsole wins over officialDocs)
# 3. the keyword control that returns the WRONG answer:
python -m agent.baseline "maximum IOPS per volume general purpose SSD"
要通过 Context MCP 使用完整的 LLM 代理,请将 .env.example 复制为 .env,并添加 Bedrock 区域以及 Sanity Context Viewer 令牌(README 中有说明)。此外还有 JSON 模式,可用于输出到其他地方:
python -m agent.ask --json "What is the maximum IOPS per volume for a gp3 EBS volume?"
实际运行,Nova Pro,us-east-1,全程只读:
| 事实 | 对账(来自记录) | 被取代 | 实时 AWS | 结果 |
|---|---|---|---|---|
| EC2 按需标准 vCPU 配额 | 5 (控制台) | 32 (旧用户指南) | 16 | 漂移 |
| EBS gp3 每卷最大 IOPS | 80,000 (控制台) | 16,000 (旧 SSD 指南) | 不可用 | 可信(不存在这样的实时配额) |
| S3 标准存储 $/GB‑月 | 0.023 (定价页面) | 0.021 (过时博客) | 0.023 | 一致 |
| RDS PostgreSQL 最老的主要版本 | 13 (发布说明) | 11 (旧教程) | 11 | 漂移 |
| Lambda 并发执行数 | 1000 (开发指南) | 不适用 | 不可用 | 可信 |
| Graviton4 (R8g) 可用性 | 可用(实例类型) | 不适用 | 可用 | 一致 |
看一下 EC2 行。文档说是 32。对账记录说是 5。实际账户说是 16。同一个配额有三个数字,代理展示了这三个数字及其来源,而不是挑选一个并希望正确。漂移并不是失败。这是诚实的答案:这是当前记录,而这里正是现实已经超越它的地方。
代码
🌊 AWS 事实来源
当 AWS 文档、定价页面和 Service Quotas 控制台各执一词时,有一个智能体能分辨哪一方说的是真话,然后还会去查实时 API,看看连这份记录本身是否也已经过时。
Sanity 项目 ID: 0q5ohtvv · ⭐ 如果过时的 AWS 数据曾在生产环境坑过你,就给这个项目点个 Star 吧。
📖 目录
🤔 问题所在
你直接照搬了 AWS 文档里的一个配额……
附完整源码,还有一条免凭证路径,评委无需任何令牌即可运行。
我如何使用 Sanity
我让 Sanity Context 指向的对象: 我自己的 Sanity 内容。每个事实都是一个类型为 awsFact 的文档,位于 production 数据集中,而不是一堆散文:
{
"_type": "awsFact",
"service": "EBS", "factType": "limit", "region": "us-east-1",
"key": "Maximum provisioned IOPS per gp3 volume",
"currentValue": "80000", "unit": "IOPS",
"effectiveDate": "2026-01-15",
"source": { "name": "EBS gp3 volume limits (Service Quotas / EBS console)",
"kind": "serviceQuotasConsole", "url": "..." }
}
// ...plus a separate record for the old 16,000 (kind: officialDocs, 2020).
source.kind 和 effectiveDate 是真实字段,因而决定胜者的规则既清晰又易懂:
最高 来源优先级 获胜(控制台和定价页面胜过更改日志,后者又胜过官方文档,后者又胜过博客),而最新的 生效日期 打破平局。
普通文本无法实现这一点。关键在于模式。
知识库: Sanity Context 的知识库 会索引这些事实。构建会提前读取它们并写出简短的带引用条目。当两条记录发生冲突时,条目会将两个数字和两个来源并列保存。
代理使用了哪些 Context 工具: 代理通过托管的 Context MCP 使用 knowledge_base_search(排名查找)然后 knowledge_base_read(完整条目)拉取事实。这证明答案来源于 Sanity 而非模型的记忆。(它也可以回退到公共数据集上的匿名 GROQ,以实现无需 token 的路径。)
代理如何处理其检索到的内容: Nova Pro 会运行这些工具并写出句子,但它无法决定数值。一个普通函数会调和该值,而一个守卫会将模型的答案与之对比。如果不一致,守卫会丢弃模型的散文,而是交付确定性的答案。在一次 EBS 运行中,Nova 自己把表述弄混了,守卫捕获到了这一点,并在没有我的帮助下用正确答案替换了它。即使模型尝试,也无法虚构该数值。
工具轨迹证明了在每个问题上都经过了 Sanity 的路径:
- [Sanity Context MCP] knowledge_base_search('EC2 quota us-east-1 ...') -> top='ec2/quotas_and_limits'; knowledge_base_read(['ec2/quotas_and_limits'])
- fetch_candidate_facts(service='EC2', fact_type='quota', region='us-east-1') -> 2 rows
- reconcile_facts(n=2) -> current=5
- verify_live(EC2/quota) -> drift
那么:即使已调和的记录也过时了怎么办?(实时 AWS 漂移)
调和这些来源能够得到文档所能提供的最佳答案。但文档会过时。于是代理会做一件纯内容代理不会做的事:它以只读方式调用 实时 AWS API,询问调和后的值此刻是否仍然成立。服务配额、价目表 API、EC2、RDS。结果位于上面的演示表中。实时层是累加的且明确标注;它不是 Sanity 的一部分,且是特定于账户的。
哪些做法没有成功(诚实部分)
- 我本来打算在仪表板中截图一个已解决的冲突。但构建从未给我这样的结果。 知识库读取了输入的记录,将 32 对 5 的冲突调和为一个同时引用两个数字的干净条目,并将问题队列清空。这就是知识库在做它的工作,但这意味着没有可展示的“我已解决一个问题”的截图,所以我不声称拥有这样的截图。
-
Nova 向我传递了一个空的工具参数。
fetch_candidate_facts返回了一行数据,随后 Nova 向reconcile_facts传递了一个空字符串,后者看到零个事实。防护机制故障闭合为 "未验证",而不是进行猜测。我通过在服务器端缓存最后一次真实的获取来修复它,因此事实始终来自 Sanity,而永远不会来自模型中继的内容。 -
错误的
factType猜测曾导致真实事实丢失。 当字段值为regionalAvailability时,Nova 猜测为instanceType,类型过滤未匹配任何内容,导致事实消失。现在,零行的类型获取会仅基于服务和区域进行重试。 - 实时检查不是 Sanity 的一部分,且特定于账户。 不同 AWS 账户的审查者会看到不同的实时数字。该层是累加的,并如此标注。两个事实(EBS 最大 IOPS、Lambda)没有对应的 Service Quotas 条目,因此代理会返回 "不可用",而不是伪造检查。顶部的种子数据被标注为演示数据。
在 AWS 之外重用该模式
去掉 AWS 相关部分,剩下的结构是通用的:对你的来源进行类型化,将它们索引到知识库中,按照优先级和日期进行调和,保护答案以防模型伪造胜者,并在存在时检查真实的系统记录。它适用于 API 版本支持、定价、合规条款和法律条款。只要真正的问题是“哪个版本是当前的?”,就可以使用此模式。
我最大的收获是:这一局赢就赢在不是用了更聪明的模型,而是结构化的内容,再加上敢直言“记录上写着 5,现实却是 16”的胆量。
Sanity 项目详情
-
Sanity 项目 ID:
0q5ohtvv -
数据集:
production(公开) - 公开数据集查询(无需令牌): https://0q5ohtvv.api.sanity.io/v2023-05-03/data/query/production?query=*%5B_type%3D%3D%22awsFact%22%5D
如果你也曾遇到过文档和控制台说法不一的情况,告诉我:是哪个数字坑了你。



