← 返回
AI技术

哪个 AWS 限制才是当前的?一个证明它的代理,32 对 5 对 16

✍️ zhirenhun 📅 2026/10/2 👁 239 阅读 ⏱ 21 分钟
哪个 AWS 限制才是当前的?一个证明它的代理,32 对 5 对 16

这是针对 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 项目详情

如果你也曾遇到过文档和控制台说法不一的情况,告诉我:是哪个数字坑了你。

——

广告 广告
🧑‍💻

zhirenhun

一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。

devchallenge sanitychallenge sanity ai