企业数据很少整齐地待在一个系统里:客户主数据和交易记录可能位于 Amazon Aurora,分析结果、行为指标又沉淀在 Amazon Redshift。传统客户 360 项目通常先复制数据、统一字段,再交给应用查询;这篇方案展示了另一条路径:让 Stardog 在两个数据源之上提供统一语义层,再由运行在 Amazon Bedrock AgentCore 上的 Strands Agents 智能体调用它,在不建设额外 ETL 流水线的情况下回答跨源问题。
这里的关键并不是让大模型直接猜测数据库结构,而是把业务概念、数据关系和查询能力放进一个受控工具中。AgentCore 则把智能体托管、入站认证和工具凭证管理集中到托管服务里,减少自行拼装运行基础设施的工作。
语义层解决的是“概念不一致”,不只是跨库连接
Aurora 和 Redshift 往往使用不同的数据模型。例如,同一个客户可能分别以 customer_id、account_key 或经过哈希处理的标识出现;“高价值客户”也可能同时依赖交易金额、服务等级和近期互动。
语义层为智能体提供稳定的业务词汇,例如:
Customer表示客户,而不是某张具体表。placedOrder表示客户与订单之间的关系。lifetimeValue、segment和lastInteraction表示可跨来源解析的业务属性。- 数据源变化被映射层吸收,智能体工具接口不必跟着每次表结构调整而变化。
在该架构中,Stardog 的 Semantic AI Application 位于 Aurora 与 Redshift 之上。查询可以通过语义关系访问两个来源,而不必先把所有数据搬到第三个存储系统。这里的“无 ETL”应理解为查询路径不依赖预先复制和转换出一份统一客户表,并不意味着完全不需要治理、标识对齐、语义映射或源端性能设计。
AgentCore 在调用链中的位置
一条典型请求链可以表示为:
客户端
-> AgentCore 入站认证与智能体托管
-> Strands Agents 智能体
-> 受控的 customer_360 查询工具
-> Stardog 语义层
-> Aurora + Redshift
这种分层把职责拆得比较清楚:大模型负责理解问题和决定何时调用工具;工具负责限制参数、生成受控查询并规范化结果;Stardog 负责解析业务语义和联合数据;Aurora 与 Redshift 仍然是记录系统和分析系统。
同一套 Stardog 部署也可以服务运行在 Amazon EKS、Amazon ECS 或 AWS Lambda 上的计算负载。采用 AgentCore 的主要原因,是它把入站认证、托管和工具凭证放进一个托管边界中。实际选型时,仍应根据现有容器平台、冷启动要求、网络拓扑和运维责任决定智能体运行位置。
可以这样实践:把语义查询封装成一个最小工具
下面示例假设 Stardog 已经暴露 SPARQL 查询端点,并且语义模型定义了 Customer、customerId、lifetimeValue、segment 与 lastInteraction 等谓词。谓词名称和认证方式只是可改造示例,需要替换成你的模型与部署配置。
安装依赖并设置连接信息:
python -m venv .venv
. .venv/bin/activate
pip install requests
export STARDOG_QUERY_URL='https://stardog.example.com/customer360/query'
export STARDOG_USERNAME='agent-reader'
export STARDOG_PASSWORD='replace-me'
创建 customer_360.py:
import json
import os
import sys
import requests
QUERY_URL = os.environ["STARDOG_QUERY_URL"]
USERNAME = os.environ["STARDOG_USERNAME"]
PASSWORD = os.environ["STARDOG_PASSWORD"]
def sparql_string(value: str) -> str:
return '"' + value.replace("\\", "\\\\").replace('"', '\\"') + '"'
def get_customer_360(customer_id: str) -> dict:
query = f"""
PREFIX ex: <https://example.com/customer360/>
SELECT ?segment ?lifetimeValue ?lastInteraction
WHERE {{
?customer a ex:Customer ;
ex:customerId {sparql_string(customer_id)} .
OPTIONAL {{ ?customer ex:segment ?segment }}
OPTIONAL {{ ?customer ex:lifetimeValue ?lifetimeValue }}
OPTIONAL {{ ?customer ex:lastInteraction ?lastInteraction }}
}}
LIMIT 10
"""
response = requests.post(
QUERY_URL,
data={"query": query},
headers={"Accept": "application/sparql-results+json"},
auth=(USERNAME, PASSWORD),
timeout=20,
)
response.raise_for_status()
bindings = response.json()["results"]["bindings"]
return {
"customer_id": customer_id,
"matches": [
{name: value["value"] for name, value in row.items()}
for row in bindings
],
}
if __name__ == "__main__":
if len(sys.argv) != 2:
raise SystemExit("Usage: python customer_360.py CUSTOMER_ID")
print(json.dumps(get_customer_360(sys.argv[1]), ensure_ascii=False, indent=2))
运行查询:
python customer_360.py CUST-1042
接入 Strands Agents 时,可以把 get_customer_360(customer_id) 注册为工具,并给模型一条明确约束:
当用户询问具体客户的分群、价值或最近互动时,必须调用 customer_360 工具。
只根据工具返回的数据作答;缺失字段要明确说明未知,不得推断。
不得接受或生成任意 SPARQL,只允许传入 customer_id。
这个边界很重要。让模型提交任意 SPARQL 虽然灵活,却会扩大越权查询、昂贵全表扫描和提示注入的风险。生产工具更适合使用固定查询模板、白名单字段、结果条数上限和超时控制。示例中的基础认证也只适合说明调用方式;生产环境应把凭证放入受控的凭证存储,并通过 AgentCore 的工具凭证机制或等价方案注入,避免进入提示词、代码仓库和日志。
上线前要压测语义查询,而不只是模型响应
无 ETL 减少了数据复制和同步延迟,但把一部分成本转移到了查询时。跨 Aurora 与 Redshift 的联合查询可能受到源端索引、过滤条件、网络延迟和并发量影响。应使用真实问题建立基准集,分别记录语义查询耗时、模型耗时、结果行数和失败类型。
上线检查可以聚焦这些项目:
- 为智能体建立只读、最小权限的 Stardog 身份。
- 用固定工具参数替代任意查询文本,并限制返回行数与执行时间。
- 验证客户标识在 Aurora、Redshift 和语义模型中的对齐规则。
- 对敏感字段执行字段级授权、脱敏和审计,不把原始个人信息写入智能体日志。
- 为无结果、数据源超时、部分字段缺失和重复客户准备明确响应。
- 监控源数据库负载;必要时增加缓存、查询治理或预计算,而不是坚持所有问题都实时联合。
- 建立客户 360 问答评测集,检查答案是否忠于工具结果,而不只评价语言流畅度。
这套架构最适合数据已经分布在多个受治理系统、业务需要接近实时访问,并且不希望再维护一份集中复制数据的场景。如果查询高度固定、数据规模极大或源系统无法承受在线联合访问,传统数仓建模和预计算仍可能更经济。语义层不是取消数据工程,而是把工作重点从搬运数据转向管理业务含义、访问边界和查询性能。