Skip to content

Latest commit

Β 

History

298 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AgentCore Deep Research

Sample open-source app that automates deep research on Amazon Bedrock AgentCore. Given a user question, the AI agent iteratively queries data sources, cross-references findings, and generates a structured report with citations and visualizations. The app features a frontend with real-time streaming, over 10 configurable data connectors spanning enterprise data on AWS and external APIs, and a modular architecture based on the FAST template. Read more in our blog.

Workflow

✨ Key features:

  • Multi-source analysis: Search across enterprise data, Internet, and specialized APIs (10+ built-in sources)
  • Iterative workflow: AI agent scaffolds report, researches the data, and creates a detailed report
  • Data visualization: Agent generates charts and diagrams to enrich reports with quantitative insights
  • Real-time report display: Split-pane UI shows the report being built in real-time and allows follow-ups
  • Fact-checking and citations: Every factual claim includes inline source citations with the references section
  • RL fine-tuning: Train and deploy your own model with reinforcement learning to optimize report quality at lower cost

AgentCore Deep Research demo

πŸ“Š Benchmarks

Evaluation results on standard deep research benchmarks from TTD-DR (correctness %):

System HLE-Search GAIA Avg. Rank Includes Diagrams
TTD-DR 33.9 69.1 1.0 βœ—
OpenAI Deep Research 29.1 67.4 2.0 βœ—
AgentCore Deep Research** 24.0 49.6* 3.5 βœ“
Perplexity Deep Research 14.5 54.5 4.0 βœ—
Grok DeeperSearch 19.3 47.9 4.5 βœ—
AgentCore Deep Research (all tools)** 24.0 41.7* 5.5 βœ“
GPT-Researcher 2.0 37.7 6.5 βœ—
Open Deep Search 3.0 20.9 7.5 βœ—

*GAIA evaluated on 127/165 validation questions (file-based questions excluded since the agent only has search tools).

**Our results use Claude Sonnet 4 with Nova Web Grounding + Tavily Web Search (default web search tools), following our scaffold→research→write→verify workflow designed for comprehensive reports.

Run the evaluation yourself with uv run test-scripts/eval-agent.py (see eval script for details).

πŸš€ Deployment

Prerequisites: Node.js 20+, AWS CLI, AWS CDK, Python 3.10+, uv, and Docker. See deployment guide for details.

Deploying AgentCore Deep Research stack requires a few commands:

cd infra-cdk
cp .config_example.yaml config.yaml  # Create your config (edit as needed)
npm install
cdk bootstrap  # Once per account/region
npm run deploy

Available deploy commands (run from infra-cdk/):

npm run deploy            # Backend + frontend
npm run deploy:frontend   # Frontend only
cdk deploy                # Backend only

See the deployment guide for detailed instructions.

▢️ Usage

UI Screenshot

  1. Open the application URL (from CDK outputs)
  2. Log in with Cognito credentials
  3. Toggle data sources (AlphaVantage, Tavily, Nova, ArXiv, etc.) as needed
  4. Enter a research question
  5. Watch as the agent:
    • Scaffolds report structure with key themes
    • Researches across enabled data sources
    • Writes all sections with citations
    • Verifies completeness and fills gaps
    • Generates charts and diagrams when the report has quantitative data
  6. Ask follow-up questions and download the report (including any generated charts)

ℹ️ Architecture

Architecture Diagram

The architecture uses Amazon Cognito in four places:

  1. User-based login to the frontend web application on CloudFront
  2. Token-based authentication for the frontend to access AgentCore Runtime
  3. Token-based authentication for the agents in AgentCore Runtime to access AgentCore Gateway
  4. Token-based authentication when making API requests to API Gateway.

Gateway Tools

The application includes multiple Lambda-based tools behind AgentCore Gateway with OAuth authentication:

Tool Domain Description API Key Required
AlphaVantage Research Finance Commodity prices, US economic indicators, and market news with sentiment analysis Yes
ArXiv Search Science Search academic papers on arXiv by topic, author, or keywords with category filtering No
ClinicalTrials.gov Search Life Science Search clinical studies worldwide by condition, intervention, phase, and recruitment status No
FRED Economic Search Finance Search 800,000+ economic time series from the Federal Reserve (GDP, CPI, unemployment, and more) No
Knowledge Base Search Generic Query Amazon Bedrock Knowledge Bases (requires configuration) No
Nova Web Grounding Generic AWS-powered web search via Amazon Nova with citations No
OpenFDA Drug Search Life Science Search FDA drug label database for pharmaceutical information No
PubMed Search Life Science Search peer-reviewed biomedical literature for abstracts, journal articles, and meta-analyses No
S3 File Reader Generic Read text files and PDFs from S3 (PDFs auto-converted to markdown via pymupdf4llm) No
SEC EDGAR Search Finance Search SEC company filings (10-K, 10-Q, 8-K) with optional full-text content retrieval No
Tavily Web Search Generic Search the web for current information with relevance scoring and domain filtering Yes

The modular architecture makes it easy to integrate additional data sources for developers.

Note: Several tools connect to external (non-AWS) APIs: Tavily, ArXiv, OpenFDA, AlphaVantage, FRED, PubMed, SEC EDGAR, and ClinicalTrials.gov. Of these, Tavily and AlphaVantage require API keys obtained through external registration. All external APIs, whether free or paid, are subject to the terms and conditions of their respective providers. We are not responsible for the availability, accuracy, or usage policies of third-party APIs. Please review each provider's terms before use. See the deployment guide for stack setup instructions and which tools require API keys.

Tech Stack

  • Frontend: React with TypeScript, Vite, Tailwind CSS, and shadcn components
  • Agent: Strands Agents SDK with BedrockModel
  • Authentication: AWS Cognito User Pool with OAuth support
  • Infrastructure: CDK deployment with Amplify Hosting for frontend and AgentCore backend

πŸ’» Local Development

Local development requires a deployed stack because the agent depends on AWS services that cannot run locally:

  • AgentCore Memory - stores conversation history
  • AgentCore Gateway - provides tool access via MCP
  • SSM Parameters - stores configuration (Gateway URL, client IDs)
  • Secrets Manager - stores Gateway authentication credentials

You must first deploy the stack with npm run deploy (from infra-cdk/), then you can run the frontend and agent locally using Docker Compose while connecting to these deployed AWS resources:

# Set required environment variables (see below for how to find these)
export MEMORY_ID=your-memory-id
export STACK_NAME=your-stack-name
export AWS_DEFAULT_REGION=us-east-1

# Start the full stack locally
cd docker
docker compose up --build

Finding the environment variable values:

  • STACK_NAME: Use the stack_name_base value from your infra-cdk/config.yaml
  • MEMORY_ID: Extract from the MemoryArn CloudFormation output (the ID is the last segment after /)
    aws cloudformation describe-stacks --stack-name <your-stack-name> \
      --query 'Stacks[0].Outputs[?OutputKey==`MemoryArn`].OutputValue' --output text
    # Returns: arn:aws:bedrock-agentcore:region:account:memory/MEMORY_ID
  • AWS_DEFAULT_REGION: The region where you deployed the stack (e.g., us-east-1)

See the local development guide for detailed setup instructions.

πŸŽ“ SFT Distillation (Experimental)

Distil a frontier model's research behaviour into a small open model with LoRA SFT, then serve it self-hosted. The student learns the full agentic trajectory β€” which tools to call, in what order, how to build a report incrementally, and how to cite sources β€” not just what a finished report looks like.

Measured result (98 held-out questions, identical harness for every model: same agent code, same tools, same prompt, same judge, greedy decoding):

Stage Score Rubric Citation Format Training compute
Qwen3.5-9B base 0.538 0.524 0.308 0.990 β€”
Qwen3.5-9B + trajectory SFT 0.744 0.687 0.953 0.986 138 GPU-h
Teacher model (frontier) 0.743 0.683 0.966 1.000 β€”

Trajectory SFT gains +0.208 over the base model (95% CI [+0.174, +0.242], p=1.2e-20, 92 wins / 6 losses). Most of that is provenance: citation validity moves 0.308 β†’ 0.953, measured by a deterministic check against the URLs the tools actually returned, so it needs no judge at all. The base model emits unresolvable bare domains; the distilled model cites pages it genuinely retrieved.

One caveat on the teacher comparison. The judge is the same model used for the RL reward below, chosen because it is cheap enough to run inside a training loop rather than because it is the strongest available evaluator. Scored by a larger independent judge every score drops and the teacher's lead widens.

Why trajectories, not final reports

An earlier version of this pipeline trained on question β†’ final_report pairs. That teaches report-shaped prose without the research behaviour behind it, which is a good recipe for confident fabrication. Every paper in this area (DR-Venus, DeepSearch-World, DeepRubric, RΒ²-Searcher) trains on full multi-step trajectories with tool observations masked out of the loss β€” otherwise the model learns to invent search results.

Masking depends on a detail in the chat template that is easy to miss. TRL's assistant_only_loss builds its mask from {% generation %} markers in the template, and most published templates β€” Qwen3.5's included β€” have none. Enabling the flag against such a template does not error: it silently trains on the whole sequence, observations included, which is precisely the failure being avoided. Observations are roughly half the tokens in a trajectory, so the loss curve looks plausible either way; the only visible signal is that loss starts much higher (4.06 versus 0.56 on a one-step probe).

TRL handles this for recognised model families by swapping in a marked-up training template (see trl/chat_templates/), so there is nothing to configure. What this pipeline adds is an assertion: training refuses to start if neither the model's own template nor TRL provides generation markers, because for an unlisted family the failure would otherwise be silent.

The same detail bites in reverse at inference time: {% generation %} is a training-only construct, so the merged checkpoint is written with the published template restored. Shipping the training template would either break a serving stack that does not understand the tag, or silently change the prompt format the model was tuned on.

How it works

DATA GENERATION (teacher agent on Bedrock)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ sft_generate_data.py │───►│ Production agent          │───►│ AgentCore Gateway  β”‚
β”‚ captures the full    β”‚    β”‚ (teacher model + tools)   β”‚    β”‚ (Nova, ArXiv,      β”‚
β”‚ SSE trajectory       │◄───│ emits tool calls+results  β”‚    β”‚  PubMed, EDGAR...) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ TRL tool-calling format; observations kept but masked at train time
           β–Ό
TRAINING (SageMaker ml.g6e.12xlarge β€” 4Γ— L40S 48GB)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ TRL SFTTrainer       β”‚  LoRA r=32 Ξ±=64, FSDP, max_seq_len 32768,
β”‚ assistant_only_loss  β”‚  observations masked via {% generation %} template
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β†’ merged HF checkpoint (model.tar.gz)
           β–Ό
INFERENCE (SageMaker ml.g6e.16xlarge β€” 1Γ— L40S)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ vLLM endpoint        │◄───│ AgentCore Runtime         β”‚  same agent code and
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚ (same tools as prod)      β”‚  same tools as production
                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Hardware requirements

Stage Instance Why not smaller
Training ml.g6e.12xlarge (4Γ— L40S 48GB) A trajectory is ~20K tokens, so max_seq_length must be 32768. That OOMs on 4Γ— A10G 24GB (ml.g5.12xlarge).
Serving ml.g6e.16xlarge (1Γ— L40S 48GB) 9B in BF16 plus KV cache for a 64K context.

GPU capacity for these instance types fluctuates by region, and available capacity is not the same as having quota β€” a job can sit Pending for hours in one region while starting immediately in another. Launching in several regions and keeping whichever starts first is the pragmatic approach.

Steps

# 1. Generate research questions (seeded, so this is reproducible)
uv run test-scripts/sft_generate_questions.py --count 1000 --eval-count 0 --seed 7 \
    --output test-scripts/results/rl_train_data_1k.jsonl

# 2. Collect teacher trajectories. Resume-safe; ~550 trajectories/hour at
#    --max-concurrent 45. AgentCore parallelises well; Bedrock is the limit.
export EVAL_USERNAME=<cognito-user> EVAL_PASSWORD=<cognito-password>
uv run test-scripts/sft_generate_data.py \
    --questions test-scripts/results/rl_train_data_1k.jsonl \
    --max-concurrent 45 --observation-chars 1200 \
    --output test-scripts/results/sft_traces_1k.jsonl

# 3. Deploy training infra and build the training image
cd infra-cdk && npm run deploy:rl && cd ..
./training/build_and_push.sh sft

# 4. Train (LoRA). ~37h for 1,963 trajectories x 2 epochs on 4x L40S.
#    --lora-alpha defaults to 2x rank; do not pin it independently.
uv run test-scripts/sft_train.py \
    --data test-scripts/results/sft_traces_2k_fitted.jsonl \
    --s3-bucket <sagemaker-bucket-in-training-region> \
    --role-arn <RLTrainingRole ARN> \
    --hf-model-id Qwen/Qwen3.5-9B \
    --lora-rank 32 --epochs 2 --max-seq-length 32768 \
    --eval-fraction 0.05 --max-runtime 259200 \
    --instance-type ml.g6e.12xlarge

# 5. Serve the merged checkpoint (must be in the agent's region)
uv run test-scripts/deploy_model.py --job-name <training-job> \
    --endpoint-name dr-sft --instance-type ml.g6e.16xlarge \
    --tensor-parallel-degree 1 --max-model-len 65536 \
    --tool-call-parser qwen3_coder --reasoning-parser qwen3 \
    --enable-capacity-fallback --region us-west-2

# 6. Point the agent at it, then WAIT ~15 min (AgentCore does not hot-swap
#    images mid-session; evaluating too early scores an empty runtime)
uv run test-scripts/deploy_finetuned_agent.py --endpoint-name dr-sft

# 7. Evaluate against the frozen question set, and the base model for comparison
uv run test-scripts/eval-agent.py --benchmark rubric --max-questions 98 \
    --parallel 8 --tag sft --model qwen3.5-9b-sft --runtime-arn <finetuned runtime ARN>

🧠 RL Fine-Tuning (Experimental)

Sharpen the distilled model against a rubric reward using GRPO, powered by AgentCore RL Toolkit with the verl backend.

RL runs on top of an SFT checkpoint, not the base model, so run that stage first.

Measured result (same 98 questions, same harness and judge as the SFT table above):

Stage Score Rubric Citation Format Training compute
Qwen3.5-9B + trajectory SFT 0.744 0.687 0.953 0.986 138 GPU-h
+ GRPO, 50 steps 0.772 0.726 0.906 1.000 168 GPU-h
+ GRPO, 100 steps 0.770 0.721 0.929 1.000 198 GPU-h
+ GRPO, 150 steps 0.782 0.737 0.919 1.000 228 GPU-h
+ GRPO, 200 steps 0.677 0.604 0.946 0.980 258 GPU-h
Teacher model (frontier) 0.743 0.683 0.966 1.000 β€”

GRPO adds +0.038 over SFT by step 150 (95% CI [+0.016, +0.060], p=0.001), then over-optimises: by step 200 the score falls to 0.677, which is 0.104 below step 150 (p<0.0001) and below SFT. The in-training reward was still climbing at that point, so the reward gave no warning. The failure is not uniform degradation β€” median report length barely moves, but reports scoring under 0.5 on the rubric jump from 4 to 20 out of 98. Checkpoint often (--save-freq) and evaluate every checkpoint; a rising training reward is not evidence that the policy is still improving.

How it works

TRAINING (SageMaker ml.g6e.12xlarge β€” 4Γ— L40S 48GB)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  verl GRPO (FSDP)   │────►│  AgentCore Runtime       │────►│  AgentCore Gateway  β”‚
β”‚  train.py on Ray    β”‚     β”‚  (RL agent with tools)   β”‚     β”‚  (Tavily, Nova,     β”‚
β”‚                     │◄────│  returns rubric rewards   β”‚     β”‚   ArXiv, PubMed...) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
           β”‚ rllm-model-gateway captures token IDs + logprobs
           β”‚ vLLM serves current policy weights
           β”‚
           β–Ό --save-hf β†’ model.tar.gz (HF safetensors + tokenizer)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  S3 Bucket          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
INFERENCE (SageMaker ml.g6e.16xlarge β€” 1Γ— L40S 48GB)
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  SageMaker Endpoint │◄────│  AgentCore Runtime       │────►│  AgentCore Gateway  β”‚
β”‚  (DJL/vLLM)        β”‚     β”‚  (finetuned agent, same  β”‚     β”‚  (same tools as     β”‚
β”‚                     β”‚     β”‚   code as production)    β”‚     β”‚   production)       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β–²
                                        β”‚
                                   Eval / Users
                               (same auth as production)

Each training step: prompts β†’ agent produces full research reports using tools β†’ reports scored against the shared rubric in research_rubric.py β†’ GRPO computes advantages across N samples β†’ model weights updated.

Prerequisites

  • Deployed deep research stack (npm run deploy from infra-cdk/)
  • AWS account with SageMaker GPU quota (ml.g6e.12xlarge for training jobs β€” 4Γ— L40S 48GB GPUs)
  • Cognito user credentials exported as EVAL_USERNAME and EVAL_PASSWORD (for eval)
  • Docker or Finch installed (for building the training container)
  • AgentCore CLI installed (npm install -g @aws/agentcore)

Check your GPU quotas:

aws service-quotas list-service-quotas --service-code sagemaker \
  --query 'Quotas[?contains(QuotaName, `training`) && (contains(QuotaName, `ml.g`) || contains(QuotaName, `ml.p`))].{Name:QuotaName,Value:Value}' \
  --output table

Training data

Generate research questions that exercise tool use (shared with SFT pipeline):

# Generate 500 training + 100 eval questions across multiple domains
uv run test-scripts/sft_generate_questions.py --count 500 --eval-count 100

This produces test-scripts/results/rl_train_data.jsonl with one prompt per line:

{"prompt": [{"role": "user", "content": "Research question here"}], "enabled_sources": ["tavily", "nova"], "metadata": {"prompt": "Research question here", "domain": "general", "tools": ["tavily", "nova"]}}

The prompt field is a chat-format message list. The enabled_sources field controls which tools the agent uses during training rollouts. Questions span 6 domains (general, finance, science, medical, policy, technology) to ensure broad tool-use coverage.

Steps

# 1. Deploy RL training infrastructure (S3 bucket, RL agent runtime, IAM roles)
cd infra-cdk && npm run deploy:rl

Note the stack outputs β€” you'll need RLAgentRuntimeArn and RLBucketName:

aws cloudformation describe-stacks --stack-name deep-research-rl \
    --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' --output table
# 2. Build and push training container to ECR (builds for linux/amd64)
./training/build_and_push.sh rl

# 3. Train with GRPO (launches SageMaker job, runs ~2-4 hours)
uv run test-scripts/rl_train.py \
    --data test-scripts/results/rl_train_data.jsonl \
    --agent-arn <RLAgentRuntimeArn> \
    --s3-bucket <RLBucketName> \
    --sft-job-name <completed-sft-job> \
    --instance-type ml.g6e.12xlarge

# 4. Deploy fine-tuned model as a SageMaker endpoint (vLLM)
uv run test-scripts/deploy_model.py --job-name <training-job-name> \
    --endpoint-name dr-finetuned --instance-type ml.g6e.16xlarge

# 5. Deploy a separate agent with the fine-tuned model
uv run test-scripts/deploy_finetuned_agent.py --endpoint-name dr-finetuned

# 6. Eval fine-tuned agent (runs alongside production agent)
export EVAL_USERNAME=<your-cognito-username>
export EVAL_PASSWORD=<your-cognito-password>
uv run test-scripts/eval-agent.py --benchmark hle-search --max-questions 50 \
    --tag finetuned

Monitor the training job in the SageMaker console or via CLI:

aws sagemaker describe-training-job --training-job-name <job-name> \
    --query '{Status:TrainingJobStatus,SecondaryStatus:SecondaryStatus}'

Training runs on the verl backend with the FSDP engine, so the model architecture is read from config.json β€” there is no per-model script to maintain. Attention comes from HuggingFace transformers, which is what allows unusual head dimensions to train without a fused-kernel fallback.

Reward function

Reports are scored on a 0–1 scale combining three signals. The weights and all scoring logic live in patterns/strands-deep-research/research_rubric.py, which is the single source of truth shared by evaluation and RL:

Signal Weight Method
Rubric quality 80% LLM judge scores 6 criteria, including grounding of claims in sources
Citation validity 10% Counts distinct well-formed URLs, and rejects citations absent from the URLs the tools actually returned
Format compliance 10% Each expected section must carry real body text, not just a heading

Architecture

Component Role Managed by
AgentCore Runtime Runs parallel agent rollouts in isolated microVMs AWS (serverless)
SageMaker Training GPU cluster for GRPO weight updates CDK stack
rllm-model-gateway Captures token IDs/logprobs from inference Training container
vLLM Serves current policy weights during training and inference Training container / SageMaker endpoint
S3 Data exchange: prompts ↔ rewards ↔ checkpoints CDK stack
rl_app.py RL-adapted agent (same tools, OpenAIModel instead of BedrockModel) This repo

See test-scripts/rl_train.py for the training script and patterns/strands-deep-research/rl_app.py for the RL-adapted agent.

πŸ“‚ Project Structure

agentcore-deep-research/
β”œβ”€β”€ frontend/                 # React frontend application
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ components/     # React components (shadcn/ui)
β”‚   β”‚   β”œβ”€β”€ hooks/          # Custom React hooks
β”‚   β”‚   β”œβ”€β”€ lib/            # Utility libraries
β”‚   β”‚   β”œβ”€β”€ services/       # API service layers
β”‚   β”‚   └── types/          # TypeScript type definitions
β”‚   β”œβ”€β”€ public/             # Static assets and aws-exports.json
β”‚   └── package.json
β”œβ”€β”€ infra-cdk/               # CDK infrastructure code
β”‚   β”œβ”€β”€ lib/                # CDK stack definitions
β”‚   β”œβ”€β”€ bin/                # CDK app entry point
β”‚   β”œβ”€β”€ lambdas/            # Lambda function code
β”‚   β”œβ”€β”€ .config_example.yaml # Example deployment configuration (copy to config.yaml)
β”‚   └── config.yaml         # Your deployment configuration (gitignored)
β”œβ”€β”€ patterns/               # Agent pattern implementations
β”‚   └── strands-deep-research/ # Deep Research agent
β”‚       β”œβ”€β”€ deep_research_agent.py  # Main agent with Gateway tools
β”‚       β”œβ”€β”€ report_upload_hook.py   # S3 upload for real-time display
β”‚       β”œβ”€β”€ system_prompt.txt       # 5-step research workflow
β”‚       β”œβ”€β”€ requirements.txt        # Agent dependencies
β”‚       └── Dockerfile              # Container configuration
β”œβ”€β”€ tools/                  # Agent tool implementations
β”‚   β”œβ”€β”€ code_interpreter/   # Code interpreter for chart generation
β”‚   └── data_analysis/      # Data analysis advisor prompt
β”œβ”€β”€ gateway/                # Gateway utilities and tools
β”‚   └── tools/              # Gateway tool implementations
β”œβ”€β”€ docker/                 # Local development Docker setup
β”‚   └── docker-compose.yml  # Docker Compose for local stack
β”œβ”€β”€ scripts/                # Deployment and test scripts
β”‚   └── deploy-frontend.py  # Cross-platform frontend deployment
β”œβ”€β”€ docs/                   # Documentation source files
β”œβ”€β”€ tests/                  # Test suite
└── README.md

πŸ”’ Security

Note: this asset represents a proof-of-value for the services included and is not intended as a production-ready solution. You must determine how the AWS Shared Responsibility applies to your specific use case and implement the needed controls to achieve your desired security outcomes. AWS offers a broad set of security tools and configurations to enable our customers.

Ultimately it is your responsibility as the developer to ensure all aspects of the application are secure. We provide security best practices in repository documentation and provide a secure baseline but Amazon holds no responsibility for the security of applications built from this tool.

πŸ‘€ Team

image image image image
Nikita Kozodoi Aiham Taleb Jack Butler Elizaveta Zinovyeva

About

πŸ”¬ Agentic deep research application template on AWS

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages