在 EKS 上为 NeMo Agent Toolkit 接入 Amazon S3 Vectors 持久记忆

2026-10-02 29 预计阅读时间: 1 分钟
来源: aws.amazon.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:11 分钟

多智能体系统一旦部署到 Kubernetes,就会遇到一个现实问题:Pod 会重启、扩缩容和迁移,但智能体积累的研究材料不能随之消失。NVIDIA NeMo Agent Toolkit(NAT)的内存子系统允许开发者替换底层存储提供者,因此可以把 Amazon S3 Vectors 接入为持久向量记忆层,并将计算留在 Amazon EKS 中。

这套组合尤其适合投资研究类工作流:不同智能体分别检索公司公告、市场数据和新闻,最终由汇总智能体基于共享证据生成报告。关键不是简单地“保存聊天记录”,而是让智能体能够按语义找回带来源、时间和访问范围的研究证据。

记忆层在多智能体工作流中的位置

一个典型的投资研究任务可以拆成四类角色:

  • 规划智能体:把“分析某公司近期风险”拆成财报、行业、市场和新闻任务。
  • 文档智能体:提取年报、季报和监管文件中的事实。
  • 市场智能体:处理价格、成交量或行业指标。
  • 汇总智能体:检索各智能体写入的证据,生成带依据的结论。

NAT 负责智能体、工具和工作流编排,自定义 memory provider 则把统一的写入与检索操作映射到 S3 Vectors。部署在 EKS 中的 Pod 不保存权威状态,只在任务执行期间持有短期上下文。

建议至少区分三类数据:

  1. 短期上下文:当前一次调用的消息和工具输出,可留在进程内。
  2. 语义记忆:可跨任务复用的证据、摘要和结论,写入向量索引。
  3. 审计数据:原始文档、完整报告和调用轨迹,通常应存入独立的对象或日志系统,而不是只放在向量元数据中。

S3 Vectors 承担的是第二类职责。它不应被视为事务数据库,也不应成为原始文件的唯一副本。

自定义 memory provider 要解决什么

一个可用的适配层通常至少暴露 remember、recall 和删除或过期处理能力。写入时需要生成向量和稳定键,查询时则要控制命名空间、元数据过滤与返回数量。

推荐为每条记忆保存这些字段:

  • tenant_id:租户或组织边界。
  • workspace_id:研究项目边界。
  • agent_id:内容由哪个智能体产生。
  • kind:例如 filing_fact、market_signal 或 draft_conclusion。
  • source_uri:原始证据位置。
  • observed_at:信息对应的业务时间。
  • embedding_model:生成向量的模型版本。

记忆键应尽量幂等。例如对 tenant_id + source_uri + chunk_id + embedding_model 做哈希,同一文档重试时就不会无限制造重复记录。

下面是一个可独立改造的 Python 适配器。它展示 S3 Vectors 客户端与 NAT memory provider 之间的核心边界;接入具体 NAT 版本时,需要把 remember 和 recall 方法注册到该版本提供的 memory 插件接口中。不同 boto3 版本的参数名称可能变化,运行前应升级 SDK 并核对当前 S3 Vectors API。

import os
import uuid
from typing import Any

import boto3


class S3VectorMemory:
    def __init__(self) -> None:
        self.client = boto3.client(
            "s3vectors",
            region_name=os.environ.get("AWS_REGION", "us-east-1"),
        )
        self.bucket = os.environ["S3_VECTOR_BUCKET"]
        self.index = os.environ["S3_VECTOR_INDEX"]

    def remember(
        self,
        vector: list[float],
        text: str,
        metadata: dict[str, Any],
        memory_id: str | None = None,
    ) -> str:
        key = memory_id or str(uuid.uuid4())
        item_metadata = {**metadata, "text": text}

        self.client.put_vectors(
            vectorBucketName=self.bucket,
            indexName=self.index,
            vectors=[
                {
                    "key": key,
                    "data": {"float32": vector},
                    "metadata": item_metadata,
                }
            ],
        )
        return key

    def recall(
        self,
        query_vector: list[float],
        top_k: int = 5,
        metadata_filter: dict[str, Any] | None = None,
    ) -> list[dict[str, Any]]:
        request: dict[str, Any] = {
            "vectorBucketName": self.bucket,
            "indexName": self.index,
            "queryVector": {"float32": query_vector},
            "topK": top_k,
            "returnDistance": True,
            "returnMetadata": True,
        }
        if metadata_filter:
            request["filter"] = metadata_filter

        response = self.client.query_vectors(**request)
        return response.get("vectors", [])


if __name__ == "__main__":
    memory = S3VectorMemory()

    # 示例索引必须使用 4 维向量;生产环境应替换为真实 embedding。
    memory_id = memory.remember(
        vector=[0.12, -0.31, 0.88, 0.09],
        text="示例公司本季度自由现金流同比改善。",
        metadata={
            "tenant_id": "demo",
            "workspace_id": "research-001",
            "agent_id": "filing-agent",
            "kind": "filing_fact",
            "source_uri": "s3://research-docs/example-q2.pdf",
            "embedding_model": "demo-4d",
        },
    )
    print("stored:", memory_id)

    results = memory.recall(
        query_vector=[0.10, -0.28, 0.91, 0.11],
        top_k=3,
        metadata_filter={"tenant_id": "demo"},
    )
    print(results)

运行前安装新版 SDK,并设置已经创建好的向量桶和索引:

python -m venv .venv
source .venv/bin/activate
pip install --upgrade boto3 botocore

export AWS_REGION=us-east-1
export S3_VECTOR_BUCKET=agent-memory
export S3_VECTOR_INDEX=investment-research
python s3_vector_memory.py

示例使用四维向量只是为了说明调用边界。实际系统必须让索引维度、写入向量和查询向量完全一致,并固定距离度量与 embedding 模型。模型升级时,最好新建索引或显式记录版本,不要把不同向量空间混在一起。

在 EKS 中部署:身份比密钥更重要

EKS 工作负载不应通过 Kubernetes Secret 长期保存 AWS Access Key。更合适的方式是为 ServiceAccount 绑定 IAM 角色,让 Pod 获取短期凭证。下面的清单可直接改造;需要替换账户 ID、角色名、镜像地址以及环境变量。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nat-research
  namespace: agents
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/nat-s3-vectors-role
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nat-research
  namespace: agents
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nat-research
  template:
    metadata:
      labels:
        app: nat-research
    spec:
      serviceAccountName: nat-research
      containers:
        - name: nat
          image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/nat-research:1.0.0
          env:
            - name: AWS_REGION
              value: us-east-1
            - name: S3_VECTOR_BUCKET
              value: agent-memory
            - name: S3_VECTOR_INDEX
              value: investment-research
          resources:
            requests:
              cpu: "500m"
              memory: 1Gi
            limits:
              cpu: "2"
              memory: 4Gi

应用清单并检查 Pod 使用的身份:

kubectl create namespace agents --dry-run=client -o yaml | kubectl apply -f -
kubectl apply -f deployment.yaml
kubectl -n agents rollout status deployment/nat-research
kubectl -n agents get pods -l app=nat-research

IAM 策略只应允许该角色访问指定的向量桶和索引,并限制为查询、写入以及确实需要的删除操作。具体动作名称应以当前 S3 Vectors 服务文档为准。多租户系统不能只依赖提示词要求智能体“不要访问其他租户”;必须在查询过滤、索引划分或 IAM 资源边界上落实隔离。

检索质量决定智能体是否真的“记得”

存进去不等于能正确找回来。投资研究中尤其要关注以下问题:

  • 时间失真:旧财报与新财报语义相近,但结论可能已经失效。检索后应按 observed_at 做时间约束或重排。
  • 来源混淆:新闻评论不能与监管文件拥有相同证据权重。可用 kind 和 source_uri 做过滤或评分。
  • 重复证据:同一公告可能被多个智能体切分并写入,需要稳定键和去重策略。
  • 提示注入:外部文档中的文字只是数据,不应被当作系统指令执行。
  • 敏感信息泄漏:元数据也可能包含客户名称、投资组合或内部判断,必须纳入访问控制和日志脱敏范围。

可为每次检索记录查询文本哈希、过滤条件、返回键、距离和最终被模型引用的记忆。这样才能判断问题来自 embedding、过滤条件、索引数据,还是生成模型本身。

上线前检查清单

采用这套架构时,可以按以下顺序推进:

  • 先用单个研究智能体验证写入、查询、过滤和重试。
  • 固定 embedding 模型、维度、距离度量与分块策略。
  • 使用确定性记忆键,验证任务重跑不会产生大量重复项。
  • 通过 EKS ServiceAccount 和 IAM 角色提供凭证,不在镜像或 Secret 中保存长期密钥。
  • 强制加入 tenant_id、workspace_id 等范围字段,并测试跨租户查询会失败。
  • 对命中率、查询延迟、空结果率和模型实际引用率建立监控。
  • 为删除、保留期限、模型升级和索引重建准备运维流程。

NAT、EKS 与 S3 Vectors 的组合把智能体计算和持久记忆分离开来,但它不会自动解决记忆质量问题。真正可靠的实现依赖清晰的数据边界、稳定的向量版本、严格的访问控制,以及能够解释“这条结论从哪里来”的检索记录。


相关推荐