📁

S3 Files x Lambda x Strands Agents でフルサーバーレスエージェンティックファイルサーチ基盤を作る!

に公開

S3 Filesとは

Amazon S3 Files が先日 GA となりました。

https://aws.amazon.com/jp/blogs/news/launching-s3-files-making-s3-buckets-accessible-as-file-systems/

簡潔に言えば、S3 の標準機能やイレブンナインの耐久性はそのままに、EFS のような共有ストレージのようにコンピューティングサービス(EC2、ECS、Lambda)にマウントできるようになりました。これにより、例えば AWS Lambda などサーバーレスのサービスでもローカルストレージのように柔軟に S3 とデータをやり取りできます。

はじめに

このサービスを見たときに、「S3 Files を使えば従来は困難だったフルサーバーレスでのエージェンティックファイルサーチを実現できるのでは....」と思いましたので、そうしてみます。

エージェンティックサーチとは

エージェンティックサーチの定義は厳密には定まっていませんが、下記のような書き方で大凡の見解は一致するでしょう。

「ユーザーの代わりにエージェントが意図を解釈し、検索計画を立て、必要に応じて複数回の検索やツール呼び出しを行い、得た情報を統合・検証し、説明可能な形で返す検索」

RAG や Web 検索などの結果を単純にプロンプトに埋め込んで推論するのではなく、ユーザーのリクエストに応じて検索クエリを組み立て、結果を参照して必要に応じて検索を繰り返し、必要な情報が集まったら応答をする、といった挙動のことをこう呼びます。

エージェンティックファイルサーチの定義

エージェンティックファイルサーチについてはいよいよはっきりした定義はありませんが、この記事では下記のように定めます。

「エージェントが動作するローカル環境のファイルシステムに対して、ユーザーの入力に応じて、grep や ls、cat likeなコマンドを用いてディレクトリ構造、メタデータ、ファイル名、ファイルの中身などを認識して必要な情報を動的に収集して応答するシステム」

Kiro や Claude Code といったコーディングエージェントもこれらのシェルコマンドを用いてコードベースのコンテキストを集めますが、同じような概念だと言えます。

RAGやエージェンティックRAGとの違い

RAG は一般的にベクトルデータベースを構築し、ドキュメントをチャンク化、埋め込み、ベクトルDBへと保存しておき、生成 AI への入力時に入力キーワードをベクトル化して事前に検索し、ヒットしたチャンクをコンテキストに挿入することでナレッジを引き出します。

しかしこの方式は、ユーザーの生成 AI への入力をベクトル化した時に適切なチャンクがヒットすれば有用ですが、そうでない場合は適切な回答ができなかったり、不適切な出力をする可能性があります。そこで、適切なチャンクがヒットするまで、あるいは適切なチャンクが無いと判明するまでエージェントが様々なキーワードで埋め込むキーワードを変更しながら DB を検索し、試行錯誤する形態も出てきており、これをエージェンティック RAG と呼びます。

エージェンティックファイルサーチは上記の方法とは違い、事前にベクトルDBを用意せず、埋め込みやベクトル検索も実施しません。あくまで、必要なのはドキュメントのストレージのみであり、ファイル名の一覧取得や、ドキュメント内の文字列部分一致検索を駆使して必要な情報を集めます。

エージェンティックファイルサーチを実装する従来の困難

従来、このエージェンティックファイルサーチをコスト効率良く、高速に AWS 上で構築することは困難でした。例えば下記のような方式がありますが、どれもコストあるいはスピードのいずれかを犠牲にする必要があります。

  • 永続ストレージを備えたコンピューティングサービス上に実装する
    • Amazon EC2 や Amazon EBS はプロビジョニングされる時間によって課金され続けてしまう
  • コンテナサービスを利用する
    • AWS Lambda や ECS on Fargate、Bedrock AgentCore Runtime などの選択肢はあるが、エフェメラルストレージに大量の文書を毎回ロードするのは困難
  • Amazon EFS や Amazon OpenSearch Service などを利用する
    • 性能は高いが、プロビジョニングする時間で課金が発生する
  • Amazon S3 を利用する
    • S3 Select や Amazon Athena といったサービスが利用できるが、非構造化データのクエリは困難

S3 Files を使うと何が嬉しい?

  • ベクトル DB がいらない
    • S3 Vector など、ベクトル DB は安価に構築する選択肢も増えましたが、事前の埋め込みや、チャンクの調整といった運用は発生します。エージェンティックファイルサーチではこれらは不要です
  • Amazon EFS などファイルサーバーも不要
    • S3 Files は従量課金かつサーバーレスで利用可能なため、利用時間で課金されるファイルサーバーよりも多くのケースでコスト最適化を達成できます。
  • Lambdaにマウントしてフルサーバーレスで作れる
    • 利用するコンピューティングサービスもサーバーレスを利用することで、コスト最適化を達成しやすくなります

既に S3 にドキュメントを保管している組織なら、バケットに S3 Files を紐づけるだけで即座にエージェンティックファイルサーチが使えるようになるのも魅力的です。

ソリューションの全体像

やりたいこと

フルサーバーレスでエージェンティックファイルサーチ基盤を作ります。
さらに、せっかくなので簡易フロントエンドを用意して、エージェントが S3 の中のドキュメントを自律探索して正確な情報を提供するところをリアルタイムに見られるようにします。

アーキテクチャ

最終的にこういったものを作ります

Amazon CloudFront と Amazon S3 でフロントエンドをホストします。
S3 Files をマウントできるのは VPC 内のリソースのみなので、VPC を立て、中に AWS Lambda を配置、S3 Files を mount target を使ってマウントします。AWS Lambda には Strands Agents によって実装した AI エージェントを定義し、Amazon Bedrock で駆動させます。会話履歴は Amazon DynamoDB に配置します。
S3 Files にはAmazon Bedrockのドキュメントを配置します。

尚、本実装はこちらで公開しています。
https://github.com/Hikotty/S3-Files-lambda-agentic-file-search-sample
(利用、改変、頒布など自由ですが、当方は一切責任を負いません。)

S3 Files と Lambda を繋ぐ PoC

まず、S3 Files と Lambda を繋ぐ部分をハンズオンで体感してみましょう。

下準備

まず、VPC を立てます。PoC なので、AZ は1、プライベートサブネット1の最小構成で結構です。

次に、security groupを作ります。
NFS(port 2049)を Inbound Rule に追加し、ソースをこの Security Group自身に指定します。この Security Groupを後ほど mount target とLambda にアタッチすることで両者が通信可能になります。

S3 Files のプロビジョニング

まず適当なファイルを用意します。

hello.txt
hello world!

これを適当なバケットを新規で作成し、フォルダ「docs」配下にこのファイルを配置します。

次に、マネコンの S3 ダッシュボードの左ペインに新しく現れた「ファイルシステム」をクリックし、設定画面に移動します。

「ファイルシステムを作成」ボタンから飛んで、先ほど作ったバケットとVPCを指定します。

ステータスが「利用可能」になるのを待ちましょう。(少し待ちます)

S3 Files をセットアップする

S3 で先ほどの画面を開き(閉じてしまった場合は、作成したバケットから「ファイルシステム」を選択する)、マウントターゲットに移動すると、すでに一つできていることが分かります。選択し、編集ボタンを押します。

セキュリティグループに先ほど作った NFS を許可するルールを追加します。

次に、アクセスポイントに移動し、「アクセスポイントを作成」します。

/をアクセスポイントスコープに設定します。

S3 Files の中身を Lambda からのぞいてみる

Lambda関数を適当な名前で定義し、x86_64 アーキテクチャ、ランタイムをpython 3.14とします。
そして、下記の IAM Policy を Role に追加しておきます(今回広めに権限を与えているため必要に応じて調整してください)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::YOUR_BUCKET_NAME",
        "arn:aws:s3:::YOUR_BUCKET_NAME/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3files:*",
        "ec2:CreateNetworkInterface",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DescribeSubnets",
        "ec2:DeleteNetworkInterface",
        "ec2:AssignPrivateIpAddresses",
        "ec2:UnassignPrivateIpAddresses"
      ],
      "Resource": "*"
    }
  ]
}

設定>VPCから Lambda は先ほど作った VPC の中に入れておきます。

設定>ファイルシステムから「ファイルシステムを追加」を選択

先ほど作ったファイルシステムとアクセスポイントを指定します。マウントパスは変更しません。

最後に、コードを書いていきます。Lambda 関数の中身はシンプルにこのようにします。

import json
from pathlib import Path

MOUNT_PATH = Path("/mnt/s3demo")
TARGET_FILE = MOUNT_PATH / "docs/hello.txt"

def lambda_handler(event, context):
    files = sorted([p.name for p in MOUNT_PATH.iterdir()])

    content = TARGET_FILE.read_text(encoding="utf-8")

    return {
        "statusCode": 200,
        "body": json.dumps(
            {
                "mount_path": str(MOUNT_PATH),
                "files": files,
                "hello_txt": content
            },
            ensure_ascii=False
        )
    }

空のテストイベントを作成し、実行してみましょう。

するとこのように、ファイルの中身にアクセスできていることが分かりました。

システムの実装

では S3 Files と Lambda をつなげるイメージができたところで、早速エージェンティックファイルサーチシステムを作っていきます。

AIエージェント

S3 Files と Lambda が無事に接続できることが確認できました。
Strands Agents にこのようにして S3 Files を走査するツールを渡すことでエージェンティックファイルサーチを実現できるはずなので、実装していきます。

Strands Agents とは

Strands Agents はモデル駆動型アプローチの AI エージェント開発フレームワークです。シンプルなチャットエージェントから、複雑な自律型 AI エージェントの構築まで、Production-Ready な AI エージェントの開発をサポートします。
シンプルさと柔軟さを兼ね備え、マルチエージェントから MCP、ストリームレスポンスまで幅広い機能をサポートしています。

https://strandsagents.com/

エージェントの全体像

エージェントは下記のようなツールとプロンプトを持たせ、実装します。

ツール

「人間がファイルサーバーを探索するときの操作をそのままツール化する」ことを意識して、下記のようなツールを用意してみました。

ツール 何をするか 人間でいうと
list_tree ディレクトリ一覧取得 フォルダを開いて中身を見る
grep_tree 正規表現で横断検索 IDE で Ctrl+Shift+F
read_file テキストファイル読み取り ファイルを開いて中身を読む
read_pdf PDF テキスト抽出 PDF を開いて中身を読む
stat_path メタデータ取得 ファイルのプロパティを確認

各ツールの実装

list_tree
@tool
def list_tree(path: str = ".") -> list[str]:
    """Mounted S3 Files 配下のディレクトリ一覧を返す。

    Args:
        path: mount root からの相対パス
    """
    base = safe_resolve(path)
    logger.info("[list_tree] path=%s resolved=%s", path, base)
    if not base.is_dir():
        raise ValueError(f"not a directory: {path}")

    items: list[str] = []
    for child in sorted(base.iterdir(), key=lambda p: (p.is_file(), p.name.lower())):
        suffix = "/" if child.is_dir() else ""
        items.append(str(child.relative_to(MOUNT_ROOT)) + suffix)
    logger.info("[list_tree] result: %d items", len(items))
    return items
grep_tree
@tool
def grep_tree(pattern: str, path: str = ".", max_matches: int = 50) -> list[dict]:
    """Mounted S3 Files 配下のテキストファイルを再帰検索する。

    Args:
        pattern: 正規表現
        path: mount root からの相対パス
        max_matches: 最大一致件数
    """
    base = safe_resolve(path)
    logger.info("[grep_tree] pattern=%s path=%s resolved=%s max_matches=%d", pattern, path, base, max_matches)
    if not base.exists():
        raise ValueError(f"path not found: {path}")

    regex = re.compile(pattern, re.IGNORECASE)
    hits: list[dict] = []

    for f in base.rglob("*"):
        if not f.is_file():
            continue
        if not is_text_file(f):
            continue
        try:
            with f.open("r", encoding="utf-8", errors="replace") as fp:
                for line_no, line in enumerate(fp, start=1):
                    if regex.search(line):
                        hits.append(
                            {
                                "path": str(f.relative_to(MOUNT_ROOT)),
                                "line": line_no,
                                "text": line.rstrip("\n"),
                            }
                        )
                        if len(hits) >= max_matches:
                            return hits
        except Exception:
            continue

    logger.info("[grep_tree] result: %d matches", len(hits))
    return hits
read_file

@tool
def read_file(path: str, start_line: int = 1, end_line: int = 200) -> str:
    """Mounted S3 Files 配下のテキストファイルを行範囲で読む。

    Args:
        path: mount root からの相対ファイルパス
        start_line: 開始行
        end_line: 終了行
    """
    f = safe_resolve(path)
    logger.info("[read_file] path=%s resolved=%s lines=%d-%d", path, f, start_line, end_line)
    if not f.is_file():
        raise ValueError(f"not a file: {path}")

    lines: list[str] = []
    with f.open("r", encoding="utf-8", errors="replace") as fp:
        for line_no, line in enumerate(fp, start=1):
            if line_no < start_line:
                continue
            if line_no > end_line:
                break
            lines.append(f"{line_no}: {line.rstrip()}")

    logger.info("[read_file] result: %d lines read", len(lines))
    return "\n".join(lines)
read_pdf
@tool
def read_pdf(path: str, start_page: int = 1, end_page: int = 5) -> str:
    """Mounted S3 Files 配下のPDFファイルからテキストを抽出する。

    Args:
        path: mount root からの相対ファイルパス(.pdf)
        start_page: 開始ページ番号(1始まり)
        end_page: 終了ページ番号(デフォルト5ページ分)
    """
    import pdfplumber

    f = safe_resolve(path)
    logger.info("[read_pdf] path=%s resolved=%s pages=%d-%d", path, f, start_page, end_page)
    if not f.is_file():
        raise ValueError(f"not a file: {path}")
    if not f.suffix.lower() == ".pdf":
        raise ValueError(f"not a PDF file: {path}")

    pages_text: list[str] = []
    with pdfplumber.open(str(f)) as pdf:
        total = len(pdf.pages)
        s = max(1, start_page)
        e = min(total, end_page)
        for i in range(s - 1, e):
            text = pdf.pages[i].extract_text() or ""
            pages_text.append(f"--- Page {i + 1}/{total} ---\n{text}")

    logger.info("[read_pdf] result: %d pages extracted, total=%d", len(pages_text), total)
    return "\n\n".join(pages_text)
stat_path

@tool
def stat_path(path: str) -> dict:
    """ファイルやディレクトリのメタデータを返す。

    Args:
        path: mount root からの相対パス
    """
    p = safe_resolve(path)
    logger.info("[stat_path] path=%s resolved=%s", path, p)
    if not p.exists():
        raise ValueError(f"path not found: {path}")

    st = p.stat()
    return {
        "type": "directory" if p.is_dir() else "file",
        "size": st.st_size,
        "modified": datetime.fromtimestamp(st.st_mtime, tz=timezone.utc).isoformat(),
    }

システムプロンプト

最低限の動作だけ定義しておきます。

SYSTEM_PROMPT = """\
あなたはファイル検索アシスタントです。
マウントされた S3 Files ファイルシステム内のファイルを検索し、ユーザーの質問に回答します。

利用可能なツール:
- list_tree: ディレクトリの内容一覧を取得する
- grep_tree: 正規表現でファイルを再帰検索する
- read_file: ファイルの内容を行範囲指定で読み取る(テキストファイル用)
- read_pdf: PDFファイルからテキストを抽出する(ページ範囲指定可能)
- stat_path: ファイルやディレクトリのメタデータを取得する

手順:
1. まず list_tree でディレクトリ構造を把握する
2. grep_tree でキーワード検索し、関連ファイルを特定する
3. テキストファイルは read_file、PDFファイルは read_pdf で内容を確認する
4. 見つけた情報を元にユーザーの質問に回答する

注意事項:
- シェルコマンドは実行できません。必ず上記のツールのみを使用してください。
- ファイルパスは mount root からの相対パスで指定してください。
- 大きなファイルは行範囲やページ範囲を指定して部分的に読み取ってください。
- PDFファイルに対して read_file を使わないでください。read_pdf を使ってください。
"""

エージェントの定義

先ほどのツールとシステムプロンプトを渡すだけで簡単にエージェントを定義できます。

    model = BedrockModel(
        model_id="us.anthropic.claude-sonnet-4-6",
        streaming=True,
    )

    agent = Agent(
        model=model,
        tools=[list_tree, grep_tree, read_file, read_pdf, stat_path],
        system_prompt=SYSTEM_PROMPT,
        callback_handler=None,
    )

フロントエンド

フロントエンドはバニラ JavaScript + HTML5 + CSS3 で、簡易的な画面を用意しています。

https://github.com/Hikotty/S3-Files-lambda-agentic-file-search-sample/blob/main/frontend/index.html

バックエンド

Lambda

リアルタイムでトレースを表示したかったので、バックエンドは FastAPI で書いて、Lambda Web Adapter(LWA)でデプロイしています。Dockerfile に1行追加するだけで Web フレームワークが Lambda で動くので非常に便利です。

lambda/Dockerfile
FROM public.ecr.aws/docker/library/python:3.12-slim
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:1.0.0 /lambda-adapter /opt/extensions/lambda-adapter

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]

環境変数 AWS_LWA_INVOKE_MODE=response_stream でレスポンスストリーミングを有効化し、エージェントの思考過程をリアルタイムで配信しています。

https://github.com/Hikotty/S3-Files-lambda-agentic-file-search-sample/blob/main/lambda/app.py

アプリのデモ

今回、3つの AWS ドキュメントをバケットに配置してみました(2026/04/12付)。

amazon-bedrock-userguide.pdf 59.4 MiB https://docs.aws.amazon.com/pdfs/bedrock/latest/userguide/bedrock-ug.pdf
amazon-ec2-userguide.pdf 36.4 MiB https://docs.aws.amazon.com/pdfs/AWSEC2/latest/UserGuide/ec2-ug.pdf
amazon-s3-userguide.pdf 28.9 MiB https://docs.aws.amazon.com/pdfs/AmazonS3/latest/userguide/s3-userguide.pdf

早速、S3 Files に関する記述を見つけられるのか検証してみましょう。

実行時間は4分ほどかかりましたが(早送りしています)、きちんと根拠資料を元に正しい情報を提供しました。

出力

まず、S3 Files に関連するファイルをマウントされたファイルシステム内で検索します。

S3 Files に関する詳細情報が amazon-s3-userguide.pdf に含まれていることが確認できました。次に、S3 Files の主要なセクションを読み込みます。

S3 Files のセクションがどのページにあるかを TOC から特定します。

TOC で S3 Filesのページを PDF から検索します。

S3 Files のセクションは PDF のページ1486から始まることがわかりました。詳細を読み込みます。

S3 Files のセクションが次のページから始まることがわかりました。詳細を読み込みます。

続きのページ(パフォーマンス、セキュリティ、課金など)も読み込みます。

十分な情報が収集できました。S3 Files の概要をまとめます。

📁 Amazon S3 Files とは?
Amazon S3 Filesは、AWSの新しい共有ファイルシステム機能です。AWSの公式ドキュメント(Amazon S3 User Guide, 2026年版)をもとに詳しく解説します。

🔑 概要
S3 Files は、任意のAWSコンピューティングリソースをAmazon S3上のデータに直接接続する共有ファイルシステムです。データをS3から外に出すことなく、完全なファイルシステムセマンティクスと低レイテンシでS3データにアクセスできます。

内部的にはAmazon EFSをベースとして構築されており、ファイルシステムのシンプルさとS3のスケーラビリティ・耐久性・コスト効率を組み合わせたサービスです。
NFS 4.1 / 4.2 プロトコルをサポートしており、Linuxの標準mountコマンドでマウント可能です。
🏗️ 仕組み(How it works)
操作 動作
ファイル読み取り 小ファイル(デフォルト128KB未満)→ 高性能ストレージ(低レイテンシ)からサービス。128KB以上はS3から直接ストリーミング(高スループット)
ファイル書き込み まず高性能ストレージに書き込み → 約60秒後にS3バケットへ自動同期
未使用データ デフォルト30日間アクセスされないデータは高性能ストレージから自動削除(S3上のデータは保持)
競合時 S3バケットが"真実の源"(source of truth)として扱われ、競合ファイルは「lost+found」ディレクトリへ移動
✨ 主要機能
機能 説明
高性能(Full replication不要) アクティブなワーキングセットのみをキャッシュ。サブミリ秒〜数ミリ秒のレイテンシ
インテリジェント読み取りルーティング 小ファイルは高性能ストレージ、大ファイルはS3から直接配信を自動選択
自動双方向同期 ファイルシステム↔S3バケットの両方向で自動同期
スケーラブルなパフォーマンス プロビジョニング不要で自動スケール
リージョナル耐久性 複数のAZにデータを冗長保存(Amazon S3と同等の耐久性)
暗号化 転送中はTLS暗号化、保管中はAWS KMS(デフォルトはAWS所有キー)で暗号化
POSIXセマンティクス Read-after-write整合性、ファイルロック、POSIXパーミッションをサポート
💻 対応コンピューティング環境
Amazon EC2(マウントヘルパー amazon-efs-utils を使用)
AWS Lambda
Amazon EKS(EFS CSI Driverを使用)
Amazon ECS(FargateおよびECS Managed Instance対応)
⚡ パフォーマンス仕様
項目 値
集約読み取りスループット 最大テラバイト/秒
集約書き込みスループット 1〜5 GiB/s(リージョン依存)
最大読み取りIOPS/ファイルシステム 250,000
最大書き込みIOPS/ファイルシステム 50,000
クライアント毎の最大読み取りスループット 3 GiB/s
S3からのインポート速度 2,400 オブジェクト/秒、700 MB/s
S3へのエクスポート速度 800 ファイル/秒、2,700 MB/s
💰 料金モデル
高性能ストレージの使用量(GB-month): ファイルシステム上にある実際のアクティブデータ分のみ課金
ファイルシステム操作料金: 読み取り・書き込み操作ごとに課金(最小32KB/操作)
128KB以上の大ファイルをS3から直接読む場合はS3 GETリクエスト料金のみ(ファイルシステムデータ読み取り料金は不要)
🔒 セキュリティ
通信の暗号化: TLS(必須・無効化不可)
保管データの暗号化: AWS KMS(AWS所有キー or カスタマー管理キー)
アクセス制御: IAMポリシー + ファイルシステムポリシー(リソースベース)+ POSIXパーミッション
ネットワーク: セキュリティグループでNFSポート2049のトラフィック制御
📋 前提条件
S3バージョニングの有効化が必要(同期に利用)
S3暗号化: SSE-S3またはSSE-KMSが必須
クライアントツール: amazon-efs-utils バージョン3.0.0以上をインストール
⚠️ 制限・注意事項
制限項目 内容
ハードリンク 非サポート
ファイル名/パスコンポーネント 最大255バイト
S3オブジェクトキーサイズ 最大1,024バイト
ディレクトリのリネーム 各ファイルをCopy&Delete処理するため、大規模ディレクトリのリネームはコスト・時間増大
Glacierストレージクラス アクセス不可(事前にS3 APIでリストア必要)
S3 ACL ファイルシステム経由の変更後は保持されない
接続数 ファイルシステムあたり最大25,000
🌟 主なユースケース
ML/AIトレーニング: 大量の小ファイルへの繰り返しアクセス
AIエージェント: 大規模なドキュメント・ファイルリポジトリの探索
開発チームの共有データストア: コード・設定ファイル・データセットの共有
サーバーレス(Lambda)での大規模参照データアクセス: 関数をまたいだデータ共有
コンテナ(EKS/ECS)での永続ストレージ: コンテナ間のデータ共有

ユースケースと考察

S3 Files を用いてフルサーバーレス構成でエージェンティックファイルサーチを組んでみました。これにより、従来コンピューティングサービスにEBSやファイルストレージをマウントするなどしか実現方法がなかった部分に、コスト効率が高い手法が新たな選択肢として入りました。

様々なユースケースが考えられますが、S3 をデータソースとして利用しつつ、生成 AIの知識を拡張したい場合に広く使えると思います。特に今回の手法は、

  • ベクトル DB は不要で、ドキュメントを S3 に入れればすぐに始められる
  • フルサーバーレスのため、完全に従量課金となり多くのケースでコスト最適化を達成できる
  • チャンクに分割されない元ファイルの記述を元にするため、正確な引用が可能

といったメリットがあります。一方で、

  • 正確な情報の位置を特定するために時間を要する
  • 大規模なデータセットの場合、単一のコンテキストの中で必要な情報を収集しきれないケースがある
  • エージェンティックにファイル検索を繰り返すため、入出力コンテキストが大きくなる傾向にある

というデメリットもあります。従って、

  • 小中規模のドキュメント群を対象とする
  • システムの管理負荷、運用コストを最小化したい
  • 正確な引用に基づく回答を生成したい

といったケースで有用と考えられます。
また、今回は特に実装していませんが、下記のような方法である程度エージェントの動作を高速化/コンテキストを節約できると考えられます。

  • S3 に格納するデータにメタデータを付与してエージェントがアクセス可能にする
  • 簡易的なインデックスをシステムプロンプトに与え、エージェントが検索範囲を絞れるようにする
  • ツールを並列実行できるように改良する
  • ファイルの中から記述位置を見つけるのがボトルネックになりやすいため、ドキュメントをある程度小さく分割する

まとめ

本記事では S3 Files とLambda を使ってフルサーバーレスエージェンティックファイルサーチ基盤を作ってみました。
本記事が何かの形でお役に立てれば幸いです。
では!

アマゾン ウェブ サービス ジャパン (有志)

Discussion