使用 Amazon Quick 和 Adjudicated Query 模式扫描数千份租约以确保合规
英文标题:Sweep thousands of leases for compliance using Amazon Quick and the Adjudicated Query pattern
AWS 提出 Adjudicated Query 设计模式,将 Amazon Quick 聊天 Agent 与受限的 MCP 服务器及确定性规则引擎结合,用于大规模、可证明完整的合规审查。该模式要求所有租约均被纳入扫描,并通过“完整性回执”验证合规、违规、存疑和不可读记录之和等于已扫描总数。生成式 AI 仅负责将自然语言问题映射到预定义操作并叙述结果,不能生成查询、缩小审查范围或作出合规判断。文章提供了基于 Amazon Cognito、API Gateway、Lambda、Aurora Serverless v2、Bedrock 和 Amazon Quick Sight 的参考架构,以及可部署的 AWS CDK 示例。
1.3 MB
1.3 MB
2.4 KB
345.0 KB
141.2 KB
346.5 KB
66.0 KB
84.4 KB
186.6 KB
54.4 KB
23.1 KB
115.6 KB
中文
对数万份公寓租约进行核查,使其符合不断变化的各州房东—租客法律,并证明确实检查了全部租约,过去一直超出大多数合规团队的能力范围。但现在,借助 Amazon Quick 中的生成式 AI,并搭配合适的后端,这已成为可能。本文介绍一种名为 Adjudicated Query 的设计模式。业务用户可以通过聊天界面(Amazon Quick)提出合规问题,而实际的通过/失败判定则始终由确定性(非 AI)规则引擎完成。我们将介绍实现该模式的 AWS 参考架构,并部署一个可端到端运行的示例。该模式同样适用于其他高风险合规领域,例如制裁筛查、保险理赔裁决和出口管制;本文则以租约合规作为具体示例。
大规模合规面临的挑战
某资产组合运营商在多个州持有 50,000 份租约。每个州都会发布房东—租客法规(如滞纳金上限、通知期限和保证金限制),其更新节奏由立法机关决定,而非运营商。当法规发生变化时,负责合规的团队必须确定哪些租约已不再符合要求。
在规模较小时,由律师助理阅读租约。由于有人工为结论负责,答案值得信赖。但超过某一规模阈值后,这种做法便不再可行。工作转由软件完成,随之出现一个新问题:答案变成屏幕上的一个数字,且没有人能够独立核实它。
这一现实带来两个关键属性:
- 可证明的完整性:“我们检查了全部 22,910 份得州租约”这样的主张必须真实且可被证明。任何未被评估的记录都必须被标记为未评估,而不能被悄然遗漏。
- **可辩护性:**某项发现可能会在数月后的诉讼、审计或监管检查中受到质疑。要为其辩护,就必须知道:在哪一天、由谁、使用什么方法,将哪个版本的哪条规则应用于哪段条款文本。
这两个属性正是此问题区别于企业搜索的所在。检索增强生成(RAG)可以解决可访问性缺口,却无法满足上述任一属性。相似度搜索不存在一个代表 全部记录 的阈值。一个按排名返回的样本永远无法知道自己排除了什么。
Text-to-SQL 在一定程度上缩小了这一差距,但存在类别级风险:一个幻觉生成的谓词可能悄然缩小总体范围,而即使范围错误,最终得出的数字看上去仍然精确。
Adjudicated Query 模式如何解决这一问题
Adjudicated Query 模式是在确定性规则引擎之上构建的一层受限对话层。模型只做两件事:将自然语言问题转换为对一组固定类型操作的调用,以及叙述返回结果。它绝不编写查询、绝不确定审查总体范围,也绝不执行判定。
边界之后是规则引擎。规则是版本化数据,而不是代码。引擎了解通用比较运算符(gte、lte、equals、exists),且不包含任何按辖区或主题命名的分支。法律发生变化时,只需编辑规则手册中的一行,而不需要部署代码。
每次合规扫描都会生成一份完整性回执:这是一个经过断言的不变量,即合规数 + 违规数 + 存疑数 + 不可读数必须等于已扫描数。该值由计数结果计算得出,并在任何内容持久化之前进行断言。无法说明其总体范围的运行不会完成。不存在任何让记录被悄然跳过的路径。
对话界面承载计数、回执和带标签的样本。完整结果集(可能包含数万行)则位于读取同一数据存储的仪表板界面中,可逐条记录深入查看。这种分离意味着模型永远无法通过摘要抹去这一保证。
为什么不使用 RAG 或 text-to-SQL?
| 方法 | 总体范围 | 完整性 | 可辩护性 |
|---|---|---|---|
| 语义检索(RAG) | 一个按排名返回的样本 | 在结构上不可能实现 | 部分具备 |
| 生成查询(text-to-SQL) | 声称完整但无法证明 | 存在悄然缩小范围的风险 | 若经过建模则具备 |
| 规则引擎 + BI(无聊天) | 精确且可证明 | 是 | 是 |
| Adjudicated Query | 精确且可证明 | 是 | 是 |
Adjudicated Query 模式在不牺牲保证的前提下,为“规则引擎 + 商业智能(BI)”方式增加了自然语言访问能力。当需要承担责任的用户需要对话式访问,并且漏掉一条记录意味着责任风险而非轻微不便时,这是正确的选择。
参考架构
下图展示了各组件如何端到端协同工作。合规官员在 Amazon Quick 中使用两个界面:一个用于提问的聊天 Agent,以及一个用于浏览完整结果集的 Amazon Quick Sight 仪表板。聊天 Agent 首先从 Amazon Cognito 获取 OAuth 令牌,随后通过 Amazon API Gateway HTTP API 发送模型上下文协议(Model Context Protocol,MCP)请求;该 API 在转发给 AWS Lambda 函数前验证令牌。Lambda 函数托管 MCP 服务器和规则引擎,通过 RDS Data API 对 Amazon Aurora Serverless v2 进行读写,并且仅在探索性条款搜索路径中调用 Amazon Bedrock。Amazon Quick Sight 仪表板则通过虚拟私有云(VPC)连接直接读取同一个 Aurora 存储。两个界面因此都从同一数据存储读取数据,这使完整性回执能够成为唯一可信来源。
图 1:Adjudicated Query 模式的参考架构
两个界面读取同一个存储。聊天 Agent 承载完整性回执和仪表板链接;仪表板承载数据量,因为 10,800 行内容无法在一条聊天消息中呈现。Amazon Bedrock 仅由 AWS Lambda 在探索性操作中调用。没有任何模型参与合规扫描,Amazon Aurora Serverless v2 也不会调用模型。
受限的操作界面
MCP 服务器恰好公开六个工具,每个工具具有不同的语义:
| 工具 | 功能 | 结果含义 |
|---|---|---|
| sweep_compliance | 针对指定日期生效的规则,对完整总体执行穷尽扫描 | 正式结果。每份租约均在计算得出的回执中得到说明。写入发现结果 |
| simulate_rule_change | 使用拟议值,对一条规则相对于已批准基线进行测试 | 探索性结果。仅提供方向性计数,不记录任何内容 |
| explore_clauses | 在已过滤的总体中,按语义相似度返回前 K 项 | 解释性结果。属于按排名返回的样本,不能回答“有多少” |
| get_finding | 获取一项发现的完整证据链 | 深入查看单项判定 |
| list_rules | 获取某一日期生效的规则手册,包括版本、引文和批准人 | 参考查询 |
| check_connection | 存活检查,不触及任何数据 | 传输健康状态 |
这一受限界面消除了生成查询中悄然缩小范围的风险路径。由于模型只能从一组固定操作中选择,而这些操作的人群逻辑由人工编写、审查和测试,因此模型无法组合出错误的总体范围。
核心架构组件
借助 Amazon Quick 对话界面和 Agent 编排层,你可以提出自然语言合规问题,由 Amazon Quick 聊天 Agent 将其转换为对受限 MCP 操作界面的调用。Amazon Quick 通过 Amazon Cognito 使用 OAuth 2LO 向 MCP 服务器进行身份验证,并处理工具发现和响应叙述。确定性引擎负责处理合规逻辑。
Amazon Aurora Serverless v2(Postgres + pgvector)在一个关系型存储中保存规则手册、租约记录、提取状态、判定和运行记录。将所有内容置于同一个数据库中,使完整性回执成为一项 SQL 计数,这是一种经济高效的方式,可让核心保证接受检查。
AWS Lambda 托管 MCP 服务器(基于 Streamable HTTP 的 JSON-RPC 2.0,并使用 Amazon Quick 客户端所需的服务器发送事件 Server-Sent Events 帧格式返回响应)和规则引擎。受限操作通过使用作为参数绑定的规则值,转换为基于集合的 SQL。不会有自然语言进入查询层。
Amazon API Gateway HTTP API 提供前端入口,并采用由 Amazon Cognito 支持的 JSON Web Token(JWT)授权器。不存在任何未经身份验证的路由。
Amazon Cognito 通过双腿式(客户端凭证)流程颁发 OAuth 令牌。客户端密钥会在注册时从 Amazon Cognito 读取,而不会写入磁盘。
Amazon Bedrock 仅为探索性路径提供支持:使用 Amazon Titan Text Embeddings V2(amazon.titan-embed-text-v2:0)进行语义相似度排序,并通过跨区域推理配置文件调用 Anthropic Claude Sonnet 5,执行定性的条款评估。它不会参与正式的合规判定。包括 Amazon Titan Text Embeddings V2 和 Anthropic Claude Sonnet 5 在内的 Amazon Bedrock 模型可用性因 AWS 区域而异,因此请在部署前确认这些模型可在你的区域中使用。
Amazon Quick Sight 通过 VPC 连接 Aurora,并渲染完整的发现结果表。该表可按扫描批次和严重性分段筛选,每一行已包含为判定进行辩护所需的全部列。
不可妥协的设计规则
- 规则即数据。法律变更对应规则手册中的一行。引擎不包含任何特定辖区的分支。
- 不让自然语言进入 SQL。运算符选择固定 SQL 模板,规则值作为参数绑定。
- 先确定性,后 AI。扫描由数值比较得出答案,不调用任何模型。
- 使用精确过滤保证完整性,仅使用向量进行排序。相似度绝不决定成员资格。
- 回执通过计算得出,而不是人工填写。在一次扫描提交前,必须对该不变量进行断言。
- 不可读文档必须被明确标记,而不是丢弃。每份租约都恰好落入一个分类桶。
- 发现结果为仅追加。代码库中不存在针对发现结果的 UPDATE 或 DELETE 操作。
将摘要模型视为不可信的渲染器
有一个设计元素值得单独说明,因为它看起来可能并不常见:为应对聊天模型改述而设计的工程防护措施。
虽然将模型排除在决策路径之外,但在交付路径中重新引入模型,会在链路末端再次带来风险。实践中,我们观察到:
- **模型删除了一个限定前缀。**ILLUSTRATIVE 引文标签在改述过程中被删除,模型将虚构的引文表述为法规。
- **模型从样本进行外推。**在获得 20 个预览行后,模型推断出了数据中并不存在的、面向总体的范围。
可通过三种技术应对这些问题:
- **将限定语表达为不可轻易删除的方括号后缀,**并在多个负载层级重复,而不要使用容易被视为可移除元数据的前置标签。
- **提供能让诚实回答成为最容易回答的数据。**针对每条记录计算真实聚合结果并交给模型。拥有真实数字的模型无需从样本中猜测。
- 在多个结构层级重复模式标签(字段、字符串、摘要),确保至少有一个标签能在改述中保留下来。
其原则是:负载中的防护措施,其强度只取决于它在改述后仍能保留的程度。
部署并运行示例
完整参考实现可在 GitHub 上获取。它附带合成数据(不包含真实客户租约数据)、确定性的语料生成,以及针对已部署堆栈的验收测试。
前提条件
部署前,请确认你具备:
- 一个 AWS 账户,并且已在美国东部(弗吉尼亚北部)区域(us-east-1)启用 Amazon Titan Text Embeddings V2 和 Anthropic Claude Sonnet 5 的 Amazon Bedrock 模型访问权限。
- 已配置凭证的 AWS Command Line Interface(AWS CLI)v2(
aws sts get-caller-identity应能成功执行)。 - Python 3.12。
- 用于 AWS Cloud Development Kit(AWS CDK)CLI 的 Node.js 24。mise 为可选项,仅用于配置 Node 24。你可以选择任意方式安装 Node 24(Node 18 对 CDK 的支持已终止)。
步骤 1:克隆仓库
克隆示例仓库并配置 Python 环境:
git clone https://github.com/aws-samples/sample-quick-adjudicated-query.git
cd sample-quick-adjudicated-query
python3 -m venv .venv && .venv/bin/pip install -q -r requirements.txt
步骤 2:部署基础设施
引导 CDK(如果尚未完成),然后部署堆栈。Aurora 的预置通常需要大约 11 分钟,但具体时间因账户和区域而异。
eval "$(mise env -s zsh)"
export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
npx aws-cdk@2.261.0 bootstrap aws://$CDK_DEFAULT_ACCOUNT/us-east-1
npx aws-cdk@2.261.0 deploy --outputs-file outputs.json
CDK 版本固定为 2.261.0,以匹配 requirements.txt。该堆栈会部署:
- Amazon Cognito(2LO 客户端)。
- 配置 JWT 授权器的 Amazon API Gateway。
- AWS Lambda(MCP 服务器 + 规则引擎)。
- Amazon Aurora Serverless v2。
- Amazon Quick Sight 网络配置。
步骤 3:写入数据并验证
依次运行迁移、语料生成、摄取和 Amazon Quick Sight 设置脚本:
PY=.venv/bin/python
$PY db/migrate.py # schema, rulebook, views (7 checks)
$PY gen_corpus.py
English / 原文
Checking tens of thousands of apartment leases against constantly changing state landlord-tenant laws, and proving you actually checked all of them, has been beyond the reach of most compliance teams. But with generative AI in Amazon Quick, paired with the right backend, it’s now possible. In this post, we introduce a design pattern called Adjudicated Query. Business users can use it to ask compliance questions in a chat interface (Amazon Quick), while the actual pass/fail decisions stay in a deterministic (non-AI) rules engine. We walk through an AWS reference architecture that implements the pattern, and deploy a working sample you can run end to end. The pattern applies to other high-stakes compliance domains as well (sanctions screening, insurance claims adjudication, export control), but lease compliance serves as our concrete example.
The compliance challenge at scale
A portfolio operator holds 50,000 leases across multiple states. Each state publishes landlord-tenant statutes (late-fee caps, notice periods, security-deposit limits) that change on the legislature’s schedule, not the operator’s. When a regulation changes, the team responsible for compliance must determine which leases are now out of line.
At small volume a paralegal reads the leases. The answer is trustworthy because a human stands behind it. Past some threshold, that stops being possible. The work moves to software, and a new problem appears: the answer is now a number on a screen that nobody can independently verify.
Two properties follow from that reality:
- Provable completeness: A claim like “we checked all 22,910 Texas leases” must be true and demonstrable. A record never assessed must be reported as unevaluated rather than silently omitted.
- Defensibility: A finding may be challenged months later in litigation, an audit, or a regulatory examination. Defending it means knowing which version of which rule was applied, to which clause text, by what method, on what date, and by whom.
These two properties are what distinguish this problem from enterprise search. Retrieval Augmented Generation (RAG) addresses the accessibility gap but cannot satisfy either property. Similarity search has no threshold that means all of them. A ranked sample never knows what it excluded.
Text-to-SQL narrows this gap, but carries a category-level risk: a hallucinated predicate can silently reduce the population, and the resulting number looks exact even when the scope is wrong.
How the Adjudicated Query pattern solves it
The Adjudicated Query pattern is a bounded conversational layer over a deterministic rules engine. The model does exactly two things: translate a natural-language question into a call on a fixed set of typed operations, and narrate the result that comes back. It never writes a query, never fixes the population, and never performs a determination.
Behind the boundary sits a rules engine. Rules are versioned data, not code. The engine knows generic comparison operators (gte, lte, equals, exists) and contains no branch naming a jurisdiction or topic. A law change is a rulebook row edit, not a code deployment.
Every compliance sweep produces a completeness receipt: an asserted invariant where compliant + in-breach + ambiguous + unreadable must equal scanned. This is computed from counts and asserted before anything persists. A run that can’t account for its population never finishes. There’s no path by which a record is silently skipped.
The conversational surface carries counts, the receipt, and a labeled sample. The full result set (potentially tens of thousands of rows) lives on a dashboard surface reading the same data store, drillable per record. This separation means the model never summarizes away the guarantee.
Why not RAG or text-to-SQL?
| Approach | Population | Completeness | Defensibility |
|---|---|---|---|
| Semantic retrieval (RAG) | A ranked sample | Structurally impossible | Partial |
| Generated queries (text-to-SQL) | Claimed but unprovable | Silent narrowing risk | If modeled |
| Rules engine + BI (no chat) | Exact and proven | Yes | Yes |
| Adjudicated Query | Exact and proven | Yes | Yes |
The Adjudicated Query pattern adds natural-language access to the rules engine plus business intelligence (BI) approach without sacrificing the guarantee. It’s the right choice when accountable users need conversational access, and a missed record is a liability rather than a mild inconvenience.
Reference architecture
The following diagram shows how the components fit together end to end. A compliance officer interacts with two surfaces in Amazon Quick: a chat agent for asking questions and an Amazon Quick Sight dashboard for browsing the full result set. The chat agent first fetches an OAuth token from Amazon Cognito. It then sends Model Context Protocol (MCP) requests over an Amazon API Gateway HTTP API, which validates the token before forwarding to an AWS Lambda function. The Lambda function hosts the MCP server and the rules engine, reads and writes to Amazon Aurora Serverless v2 through the RDS Data API, and calls Amazon Bedrock only for the exploratory clause-search path. The Amazon Quick Sight dashboard reads the same Aurora store directly through a virtual private cloud (VPC) connection. Both surfaces therefore read from one store, which is what makes the completeness receipt a single source of truth.
Figure 1: Reference architecture for the Adjudicated Query pattern
Both surfaces read the same store. The chat agent carries the completeness receipt and a link to the dashboard. The dashboard carries the volume, because 10,800 rows don’t render in a chat message. Amazon Bedrock is called from AWS Lambda only by the exploratory operation. No model is involved in compliance sweeps, and Amazon Aurora Serverless v2 doesn’t call a model.
The bounded operation surface
The MCP server exposes exactly six tools, each with a distinct semantic:
| Tool | What it does | Result means |
|---|---|---|
| sweep_compliance | Exhaustive population sweep against rules in force on a stated date | Official. Every lease accounted for in a computed receipt. Writes findings |
| simulate_rule_change | One rule tested at a proposed value against the approved baseline | Exploratory. Directional counts only. Records nothing |
| explore_clauses | Top K by semantic similarity within a filtered population | Interpretive. A ranked sample. Cannot answer “how many” |
| get_finding | One finding’s complete evidence chain | Drill-down into a single determination |
| list_rules | The rulebook in force on a date, with versions, citations, approvers | Reference lookup |
| check_connection | Liveness check, touches no data | Transport health |
This bounded surface removes the path to the silent-narrowing risk of generated queries. Because the model can only select from a fixed set of operations whose population logic was written, reviewed, and tested by people, it has no way to compose a wrong population.
Key architecture components
With the Amazon Quick conversational interface and agent orchestration layer, you can ask natural-language compliance questions that the Amazon Quick chat agent translates into calls on the bounded MCP operation surface. Amazon Quick authenticates to the MCP server by using OAuth 2LO through Amazon Cognito and handles tool discovery and response narration. The deterministic engine handles the compliance logic.
Amazon Aurora Serverless v2 (Postgres + pgvector) stores the rulebook, lease records, extraction status, determinations, and runs in a single relational store. Putting everything in one database makes the completeness receipt a SQL count, a cost-effective way to make the central guarantee inspectable.
AWS Lambda hosts the MCP server (JSON-RPC 2.0 over Streamable HTTP, using Server-Sent Events framing for responses, which the Amazon Quick client requires) and the rule engine. Bounded operations translate to set-based SQL by using rule values bound as parameters. No natural language reaches the query layer.
Amazon API Gateway HTTP API provides the front door with a JSON Web Token (JWT) authorizer backed by Amazon Cognito. No unauthenticated route exists.
Amazon Cognito issues OAuth tokens through a two-legged (client credentials) flow. The client secret is read from Amazon Cognito at registration time and not written to disk.
Amazon Bedrock powers the exploratory path only, using Amazon Titan Text Embeddings V2 (amazon.titan-embed-text-v2:0) for semantic similarity ranking and Anthropic Claude Sonnet 5, invoked through a cross-region inference profile, for qualitative clause assessment. It isn’t consulted for an official compliance determination. Amazon Bedrock model availability, including Amazon Titan Text Embeddings V2 and Anthropic Claude Sonnet 5, varies by AWS Region, so confirm the models are available in your Region before deploying.
Amazon Quick Sight connects to Aurora through a VPC connection and renders the full findings table, filterable by sweep and severity band, with every column needed to defend a determination already on the row.
Design rules that are non-negotiable
- Rules are data. A law change is a rulebook row. The engine contains no jurisdiction-specific branch.
- No natural language reaches SQL. Operators select fixed SQL templates. Rule values bind as parameters.
- Deterministic before AI. A numeric comparison answers the sweep. No model is consulted.
- Exact filtering for completeness, vectors only for ranking. Similarity never decides membership.
- Receipts are computed, not written by hand. The invariant is asserted before a sweep commits.
- Unreadable documents are named, not dropped. Every lease lands in exactly one bucket.
- Findings are append-only. No UPDATE or DELETE against findings exists in the code base.
Treating the summarizing model as an untrusted renderer
One design element deserves its own section because it will look unfamiliar: engineering safeguards to survive paraphrase by the chat model.
Excluding the model from the decision path but putting one back in the delivery path reintroduces risk at the end of the chain. In practice, we observed:
- A model stripped a caveat prefix. An ILLUSTRATIVE citation tag was removed during paraphrase, and the model presented an invented citation as statute.
- A model extrapolated from a sample. Given 20 preview rows, the model inferred a population-wide range that did not exist in the data.
Three techniques address this:
- Phrase caveats as un-strippable bracketed suffixes repeated at several payload levels, not leading labels that read as removable metadata.
- Supply the data that makes the honest answer the easy one. Compute real aggregates over every record and hand them to the model. A model that has the real number doesn’t need to guess from a sample.
- Repeat mode labels at multiple structural levels (field, string, summary) so that at least one survives paraphrase.
The principle: a safeguard in the payload is only as strong as its survival through paraphrase.
Deploy and run the sample
The complete reference implementation is available on GitHub. It ships with synthetic data (no real customer lease data), deterministic corpus generation, and acceptance tests against the deployed stack.
Prerequisites
Before deploying, verify that you have:
- An AWS account with Amazon Bedrock model access enabled for Amazon Titan Text Embeddings V2 and Anthropic Claude Sonnet 5 in the US East (N. Virginia) Region (us-east-1).
- AWS Command Line Interface (AWS CLI) v2 with credentials configured (
aws sts get-caller-identityshould succeed). - Python 3.12.
- Node.js 24 for the AWS Cloud Development Kit (AWS CDK) CLI. mise is optional and only used to provision Node 24. You can install Node 24 by your choice of method (Node 18 has reached end of life for CDK).
Step 1: Clone the repository
Clone the sample repository and set up the Python environment:
git clone https://github.com/aws-samples/sample-quick-adjudicated-query.git
cd sample-quick-adjudicated-query
python3 -m venv .venv && .venv/bin/pip install -q -r requirements.txt
Step 2: Deploy the infrastructure
Bootstrap CDK (if not already done) and deploy the stack. Aurora provisioning typically takes around 11 minutes, though timing varies by account and Region.
eval "$(mise env -s zsh)"
export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
npx aws-cdk@2.261.0 bootstrap aws://$CDK_DEFAULT_ACCOUNT/us-east-1
npx aws-cdk@2.261.0 deploy --outputs-file outputs.json
The CDK version is pinned to 2.261.0 to match requirements.txt. The stack deploys:
- Amazon Cognito (2LO client).
- Amazon API Gateway with JWT authorizer.
- AWS Lambda (MCP server + rule engine).
- Amazon Aurora Serverless v2.
- Amazon Quick Sight networking.
Step 3: Seed data and verify
Run the migration, corpus generation, ingestion, and Amazon Quick Sight setup scripts in sequence:
PY=.venv/bin/python
$PY db/migrate.py # schema, rulebook, views (7 checks)
$PY gen_corpus.py # deterministic corpus + manifest
$PY ingest.py # load + embed (timing varies by environment)
$PY setup_dashboard.py # Quick Sight wiring
$PY acceptance.py # 28 checks against the live stack
The corpus is deterministic, so a rebuilt stack reproduces identical results.
Step 4: Register the MCP integration in Amazon Quick
Amazon Quick snapshots the tool list at registration time. Amazon Quick doesn’t detect new or renamed tools until you delete and recreate the integration. Deploying the Lambda alone isn’t enough.
Print the registration inputs from your deployment outputs:
python3 - <<'PY'
import json
o = json.load(open('outputs.json'))['QuickPocStack']
for k in ('McpUrl', 'TokenEndpoint', 'ClientId', 'Scope'):
print('%-14s %s' % (k, o[k]))
PY
Retrieve the client secret (read from Amazon Cognito each time, not written to disk). Use the user pool ID from the Issuer URL in your outputs:
aws cognito-idp describe-user-pool-client \
--user-pool-id <UserPoolId> \
--client-id <ClientId> \
--query UserPoolClient.ClientSecret --output text
Then in Amazon Quick: Connectors > Create for your team > Model Context Protocol. Delete any existing entry first, then create a new one with those values (OAuth client-credentials/2LO). Copy the client secret into Amazon Quick directly rather than into a file or shell variable.
Step 5: Verify the integration
Verify the deployment end to end, in this order:
$PY show_payload.py check_connection # transport alive
$PY acceptance.py # 28/28 checks
The acceptance suite proves the server works. The next section walks through the Amazon Quick chat experience to confirm Amazon Quick picks the right tool.
Walking through the experience
With the stack deployed and verified, you can now run a compliance sweep from Amazon Quick chat and inspect the results.
Ask a compliance question
In Amazon Quick chat, enter: “Which Texas leases violate the late fee cap? Use rules effective 01/01/2026.”
Amazon Quick identifies this as a compliance sweep and selects the sweep_compliance tool. The tool runs an exhaustive check against every Texas lease in the population, applying rules in force on the stated date. No model is involved in the determination.
Amazon Quick narrates the structured result. Figure 2 shows the chat response: a short sample of noncompliant findings in a table, the completeness receipt rendered as counts, a synthetic-data caveat, and a link to open the full dashboard.
Figure 2: Amazon Quick chat response with the completeness receipt and a sample of findings
The response includes a sample of noncompliant findings and the completeness receipt as counts: 10,111 violations, 689 ambiguous, and 20 unreadable. It also includes a synthetic-data caveat and a link into the Amazon Quick Sight dashboard. It deliberately does not try to render all 10,111 rows.
Verify the completeness receipt by checking the invariant: compliant + in-breach + ambiguous + unreadable should equal the total scanned population. In this example, the counts sum to the total Texas lease population, confirming that every record landed in exactly one bucket.
Inspect the full population on the dashboard
Follow the dashboard link in the chat response to open the Amazon Quick Sight dashboard. Figure 3 shows the findings tab, where every lease-rule pair from the sweep appears as its own row with the full evidence chain.
Figure 3: Amazon Quick Sight dashboard listing every finding from the sweep
The dashboard displays every finding from the sweep, one row per lease-rule pair. Use the severity band filter to isolate in-breach findings. Each row carries the lease ID, the rule that fired, the extracted value, and the expected value. Sort by rule to group related violations and identify patterns across the portfolio.
Drill into a single finding
Selecting a row opens the finding detail. Figure 4 shows a single finding, with the verbatim lease clause on one side and the rule that fired on the other, including its version, citation, and the compared values.
Figure 4: Finding detail showing the lease clause alongside the rule that fired
This is what defensibility looks like in practice. The finding shows the extracted value (7 percent late fee), the required value (5 percent cap), and the rule citation (TX Prop. Code ch. 92 subch. B, as amended eff. 2026-01-01). All of this appears alongside the clause text verbatim from the lease, so nothing needs to be reconstructed.
Test additional routing paths
Confirm Amazon Quick routes to the correct tool by testing the remaining operations:
- “Find Texas clauses that read like liability waivers.” (should invoke
explore_clauses). - “What if the Texas late fee cap dropped to 3%?” (should invoke
simulate_rule_change).
Cleanup
To avoid ongoing charges, destroy the stack when you are finished:
npx aws-cdk@2.261.0 destroy
Aurora Serverless v2 can scale to 0 Aurora Capacity Units (ACU) and automatically pause after a period of inactivity (see Amazon Aurora pricing). This sample sets a small non-zero minimum capacity instead, as a deliberate choice, because a paused cluster adds resume latency to the first question of a session. No NAT gateway is deployed.
If you plan to return to the stack later but want to minimize cost between sessions, set serverless_v2_min_capacity=0 in infra/stack.py and redeploy to enable scale-to-zero with auto-pause. Expect a short resume delay on the first query after the cluster has paused. The corpus is deterministic, so a fully destroyed and redeployed stack reproduces identical results.
Security considerations
Because this pattern is built for compliance work, security is part of the design rather than an add-on. The sample applies the following practices, and you should review each one against your own requirements before adapting it.
- Authenticated access only. Every request from Amazon Quick reaches the MCP server through an Amazon API Gateway HTTP API protected by a JSON Web Token (JWT) authorizer backed by Amazon Cognito. No unauthenticated route exists, and the two-legged (client credentials) OAuth flow issues short-lived tokens rather than long-lived keys.
- Secret handling. The Amazon Cognito client secret is read at registration time and isn’t written to disk or committed to source control. Store it only in the Amazon Quick connector configuration, and rotate it on your normal schedule.
- Least-privilege model access. The AWS Lambda execution role grants Amazon Bedrock InvokeModel only for the specific Amazon Titan Text Embeddings V2 and Anthropic Claude Sonnet 5 model ARNs the sample uses, not a wildcard over all models. Scope AWS Identity and Access Management (IAM) permissions the same way in your own build.
- Network isolation for the data path. Amazon Quick Sight reaches Amazon Aurora Serverless v2 through a VPC connection rather than a public endpoint, and the database security group admits only the expected sources. Keep the store off the public internet.
- No natural language in the query path. The rules engine assembles SQL only from a fixed operator-to-template table with rule values bound as parameters, which removes the injection surface that a model-written query would create. This is a security property as much as a correctness one.
- Auditable, append-only findings. Findings are append-only, with no UPDATE or DELETE path in the code base, so the compliance record cannot be silently altered after the fact. Each determination carries its evidence chain for later review.
- Synthetic data boundary. The sample ships with synthetic lease data and clearly labeled placeholder rules and citations. Before running against real records, complete your organization’s data classification, access review, and legal validation of any rule content.
- Human attribution of a sweep. Amazon Quick authenticates to the MCP server machine-to-machine through the two-legged (client credentials) flow, so the token identifies the Amazon Quick application, not the individual who asked the question in chat. The engine records what was decided, the rule version, the evidence, the method, and the date, but it doesn’t receive an end-user identity to store alongside a finding. For the “by whom” part of defensibility, attribution lives in the Amazon Quick audit layer, which records which user ran which chat action. A finding ties back to a person by correlating its sweep ID and timestamp with that record. If you need attribution recorded in the compliance store itself, thread an end-user ID from Amazon Quick into the tool call and persist it on the sweep row. The “who” then travels with the finding rather than living only in the Amazon Quick audit layer.
When to use this pattern
The Adjudicated Query pattern applies whenever:
- A missed record is a liability rather than a mild inconvenience.
- Answers might be challenged months later by someone who was not in the room.
- The governing logic is externally owned and changes on its own schedule.
- The body of records is enumerable (you can list every record a question covers).
That description covers a wide range of domains. Examples include lease compliance, insurance claims adjudication, sanctions screening, export control, clinical trial protocol monitoring, building code inspection, financial reporting controls testing, and credential verification.
RAG is the simpler choice when plausible answers suffice and users can re-ask. Text-to-SQL works well for teams that can verify generated queries and tolerate occasional incorrect results. If accountable users will accept dashboards without a conversational layer, consider a rules engine plus BI directly: it delivers the same guarantee at lower cost.
When this is the wrong choice
The pattern is heavy: a rules engine, a bounded tool surface, and a completeness receipt. That machinery earns its keep only on the right problem, and copying it onto the wrong one adds cost without adding trust. Avoid the pattern in three cases.
- The rules aren’t really deterministic. The pattern works when compliance is a clean comparison, such as fee is less than or equal to a cap, or notice is greater than or equal to a required number of days. When the call is a genuine judgment, such as whether a clause is unconscionable or a disclosure is adequate, forcing it into this pattern hides the subjectivity inside rule-authoring and makes the result look exact when it is not. Keep a human in the loop for those determinations rather than dressing them as deterministic ones.
- Completeness doesn’t matter for the question. If the user only wants a few representative examples, or is exploring rather than adjudicating, the completeness receipt is overhead for a guarantee they don’t need. RAG is the simpler, correct answer for that kind of question.
- The population itself is fuzzy. The receipt proves you covered every record in the population, not that the population is the right one. If the definition of “all Texas leases” is itself contestable, the guarantee is precise about the wrong denominator. Make sure the population can be drawn by an exact, defensible predicate before you rely on the receipt.
Conclusion
In this post, we introduced the Adjudicated Query pattern and demonstrated how it delivers provably complete, defensible compliance answers through the Amazon Quick conversational interface. The pattern pairs a bounded MCP operation surface with a deterministic rules engine, so the model translates questions and narrates results but does not touch the decisions that produce the guarantee.
By deploying the sample stack, asking a compliance question in Amazon Quick chat, and following the results through the Amazon Quick Sight dashboard, you walked through the full pattern end to end. The completeness receipt accounts for every record, findings carry their full evidence chain, and the split-surface delivery keeps the guarantee intact through paraphrase.
To get started, clone the sample repository, deploy the stack, register the MCP integration in Amazon Quick, and try asking your first compliance question.
Resources
About the author
Anand Komandooru
Anand is a Principal Solutions Architect on the Well-Architected Solutions Innovation team at AWS, with over 20 years of experience building software and helping customers design and deliver cloud-native and AI applications. Outside of work, he writes about AI architecture patterns on AWS Builder Center and enjoys time with family, music, cooking, and nature.



