Building a Production Fantasy Football AI Assistant in 8 Weeks

nfl · Media & Entertainment · 2024 · source Agentic: yes · promotional bias: med · source-backed · extracted with prompt 0.5.4 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Production fantasy-football decision assistant for NFL fans

The NFL and AWS needed to ship an NFL+ fantasy-football AI assistant in eight weeks that could give fast, analyst-approved, data-backed roster advice without hallucinating stats, answering out-of-scope betting questions, or failing during game-day traffic spikes.

Constraints:

Architecture

The NFL and AWS built a fantasy-football agent on EKS using Amazon Bedrock models, Strands Agents for model-driven orchestration, S3-backed session memory, and MCP as a semantic data layer over NFL Next Gen Stats and RotoWire. The team built a Semantic Stats Dictionary and broader data-boundary tools so the agent could request the right domain data with fewer calls. Production hardening added a Bedrock fallback provider, circuit breaker, per-turn reasoning instrumentation, guardrails on data volume/scope, and simple sliding-window caching for heavy MCP tool-call results.

Diagram confidence: explicit (topology described by the source).

flowchart LR
  nfl-pro-user-interface[NFL Pro user interface] --> fantasy-ai-agent[Fantasy AI agent]
  fantasy-ai-agent --> strands-agents-runtime[Strands Agents runtime]
  strands-agents-runtime --> amazon-bedrock-model[Amazon Bedrock model]
  fantasy-ai-agent --> s3-session-memory[S3 session memory]
  fantasy-ai-agent --> mcp-semantic-data-layer[MCP semantic data layer]
  mcp-semantic-data-layer --> next-gen-stats-apis[Next Gen Stats APIs]
  mcp-semantic-data-layer --> rotowire-apis[RotoWire APIs]
  mcp-semantic-data-layer --> semantic-stats-dictionary[Semantic Stats Dictionary]
  strands-agents-runtime --> bedrock-fallback-provider[Bedrock fallback provider]
  fantasy-ai-agent --> per-turn-observability[Per-turn observability]
  mcp-semantic-data-layer --> heavy-call-cache[Heavy-call cache]
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
NFL Pro user interface Fan-facing product surface where NFL+ users ask fantasy-football questions. Fantasy AI agent
Fantasy AI agent Agentic assistant that reasons, plans, calls tools, and generates fantasy advice. NFL Pro user interface, Strands Agents runtime, Amazon Bedrock model, S3 session memory, MCP semantic data layer, Bedrock fallback provider, Per-turn observability
Strands Agents runtime Open-source framework handling sessions, prompts, multi-model support, orchestration, and model extensions. Fantasy AI agent, Amazon Bedrock model, MCP semantic data layer, Bedrock fallback provider, Per-turn observability
Amazon Bedrock model Primary LLM reasoning backend for fantasy analysis and tool selection. Strands Agents runtime, Bedrock fallback provider
S3 session memory Session persistence for conversation context and future conversation-history exposure. Fantasy AI agent
MCP semantic data layer Separated data-access layer exposing NFL and partner data through model-understandable tool interfaces. Fantasy AI agent, Next Gen Stats APIs, RotoWire APIs, Semantic Stats Dictionary, Heavy-call cache
Next Gen Stats APIs Structured NFL tracking, player, and contextual statistics used for fantasy analysis. MCP semantic data layer
RotoWire APIs Additional roster, user, and player information for fantasy context. MCP semantic data layer
Semantic Stats Dictionary LLM-readable domain dictionary that maps stats and APIs to question types and narrows runtime context. MCP semantic data layer, Fantasy AI agent
Bedrock fallback provider Strands model extension that intercepts throttling/capacity errors and routes to a secondary Bedrock model family. Strands Agents runtime, Amazon Bedrock model
Per-turn observability Instrumentation showing each reasoning turn, tool call, parameters, returned data, and token-heavy behavior. Fantasy AI agent, Strands Agents runtime
Heavy-call cache Sliding-window cache for the most recent token-heavy MCP tool results in follow-up-heavy conversations. MCP semantic data layer

Data flow

A user asks a fantasy question in NFL Pro. The EKS-hosted Fantasy AI agent uses a Bedrock LLM through Strands Agents, loads session context, consults the Semantic Stats Dictionary, calls MCP tools to retrieve NFL Next Gen Stats and RotoWire data, reasons over the results, and streams an answer. During failures or throttling, a Bedrock fallback provider can route the request to a secondary model; observability records per-turn tool calls, parameters, and returned data.

4 supporting quotes
“From the left, we have the user input a query, and then it feeds into the Fantasy AI, which is hosted on the EKS, that autoscales.”transcript, stated
“It uses the large language model from Amazon Bedrock to reason and post-session memory from every bucket. So it has the context. More importantly, it is connected through MCP to different data sources.”transcript, stated
“it is connected through MCP to different data sources. It connects to the NFL Next Gen Stats to get all the player information about their stats.”transcript, stated
“The agent applies reasoning to tools and data. And between the two of those, it gets intelligence. This is what matters. Don't get caught up in the perfect infrastructure.”transcript, stated

Why this architecture

The team optimized for getting analyst-grade intelligence into production quickly. Strands avoided building agent plumbing, MCP separated reusable data logic from agent logic, the Semantic Stats Dictionary compressed domain context, broad data-boundary tools reduced loop count, and fallback/observability/caching handled production risk without delaying the launch.

4 supporting quotes
“zero-to-prod in eight weeks, 'cause we literally went from an idea to a product for fans to use in just eight weeks.”transcript, stated
“The first is that we decided to go with Strands Agents, which is the open-source framework that make it much easier for you to build a production-level agentic system.”transcript, stated
“Second, we decided to use MCP as our semantic data layer. This way, it give us separate responsibility, and we can scale them independently”transcript, stated
“Get it to production, make it work with the simplest patterns and architecture that produce the results that you can't compromise on.”transcript, stated

Models used: Amazon Bedrock LLM · Anthropic frontier model family on Amazon Bedrock · larger model for LLM-assisted refinement · Strands Agents model-driven orchestration

Scale

Alternatives considered (roads not taken)

Embed data access logic directly in the agent code with Python decorators

Rejected because: The data layer needed parameter filtering, business validation, and parallel processing; embedding all that in the agent would be hard to maintain and scale.

“The simple option is, of course, you can use Python Decorators to just give the tool definitions to the agents inside the agent code base.”transcript, stated
“If we embed all of these code into agent code, it actually makes the code very hard to maintain and very hard to scale.”transcript, stated

Provide rich API specs and all domain context to every question

Rejected because: That would dump hundreds of thousands of tokens, so the team passed only semantically relevant dictionary slices at runtime.

“Otherwise, we'd be dumping hundreds of thousands of tokens. If we tried to provide a vast level of rich domain expertise to every single question.”transcript, stated
“we could pass in just the semantically relevant portions of the dictionary at runtime, and allow the agent to apply the information. Because we were using Strands Agents, which has model-driven orchestration,”transcript, stated

Create narrow tools for each major use case

Rejected because: Many narrow tools caused fragmented answers, more loops, and extra latency; broader tools by data boundary let the agent express richer intent.

“Let's write a tool for each of the major use cases we think we're going to encounter." That should be great, right? Nah. When you're dealing with an agentic loop, and you have 29 different tools”transcript, stated
“Six tools that gave highly fragmented answers. And what we realized was that we needed a much broader tool. We needed tools that looked at data boundaries and gave the agent the autonomy to express rich”transcript, stated

Fail visibly on Bedrock capacity or throttling

Rejected because: Launch-day user experience and NFL Pro's brand mattered more than preserving single-model behavior, so the team added a fallback provider and circuit breaker.

“Can't show a throttling exception to your users. Now, we had planned for a certain number of volume based on NFL Pro traffic. We'd done our service-quoted due diligence,”transcript, stated
“We chose to take 90% reduction in throttling exceptions on launch day to not have a user see a throttling exception”transcript, stated

Ship conversation history, league integrations, feedback loops, and custom preferences in v1

Rejected because: Those features did not prove job number one: analyst-grade advice, timing, and production readiness.

“We didn't ship conversation history. We didn't ship integration with leaks. We didn't ship user feedback loops or custom preferences”transcript, stated
“because these are valuable features that don't prove job number one. And when you're trying to get a product to production, job number one is the only job that matters.”transcript, stated

Patterns

tool-use-orchestration (agent-architecture)

The fantasy assistant uses model-driven orchestration to decide which stats tools to call and in what order for lineup, waiver, trade, and player questions.

“the agent could choose what data it needed and retrieve it.”transcript, stated
“the agent could focus on the logic and the orchestration”transcript, stated

rag-retrieval (domain-context)

A Semantic Stats Dictionary and MCP data layer retrieve only the domain context and stats relevant to the user's fantasy question.

“we could pass in just the semantically relevant portions of the dictionary at runtime”transcript, stated
“We needed just the right information filtered at just the right time to the agent.”transcript, stated

fallback-degradation (resilience)

A Bedrock fallback provider intercepts throttling or quota failures and sends the request to a secondary model, with a circuit breaker to avoid repeatedly hitting an overwhelmed service.

“If the Bedrock service returns anything that looks remotely like a throttling exception account, quote, "Exceeded service not available," we intercept that message”transcript, stated
“We also introduced a circuit breaker”transcript, stated

observability-tracing (agent-operations)

The team added per-turn reasoning instrumentation to inspect tool calls, parameters, data returned, and token-heavy decision patterns before launch.

“We extended the Strands Agent framework to give us per-turn reasoning insight.”transcript, stated
“see what the agent was doing, the tools it was calling, with what parameters returning what data”transcript, stated

semantic-caching (latency-cost)

The system caches the two most recent heavy MCP tool-call results because fantasy users often ask follow-ups about the same player.

“Fantasy users tend to ask open-ended questions and refer back.”transcript, stated
“just caching the most two recent, heavy MCP tool call results increased throughput by two times.”transcript, stated

guardrails-io-filtering (safety-scope)

The assistant is constrained to fantasy-football analysis and uses structured NGS APIs to avoid hallucinated stats and out-of-bounds betting/liability answers.

“we don't want our AI Assistant to be able to answer questions that are outside the bounds of Fantasy Football.”transcript, stated
“we leveraged our APIs that we built that had structured data that we knew that there was a low risk to add a little bit of that error.”transcript, stated

Tradeoffs

Use Strands Agents instead of building all agent scaffolding

Chose Strands Agents framework over custom session, prompt, model, and fallback plumbing.

Rationale: The eight-week deadline made framework scaffolding more valuable than owning every low-level agent runtime detail.

“it handles so many things for us. It will help us with managing the sessions, will help with managing the prompts”transcript, stated
“allows us to focus on building the agent logic for Fantasy AI, rather than the plumbing part of it.”transcript, stated

Separate agent logic from data logic with MCP

Chose MCP semantic data layer over decorator-defined tools embedded in the agent codebase.

Rationale: Separating concerns made complex data validation, filtering, parallel processing, reuse, and independent scaling manageable.

“separate the agent logic with the data logic, and that's actually the choice we decided to make.”transcript, stated
“we can introduce additional agents in the future, say different personas, different agents for different purposes.”transcript, stated

Accept bimodal fallback behavior for launch

Chose fallback provider and circuit breaker over strict single-model behavior that might expose throttling.

Rationale: Launch-day user experience and brand protection were more important than avoiding a temporary anti-pattern.

“That's an anti-pattern. You just introduced bimodal system behavior.”transcript, stated
“we made the decision to introduce something we might not otherwise introduce.”transcript, stated

Cache recent heavy tool calls with a simple sliding window

Chose two most recent heavy MCP calls over predictive cache allocation before observing real users.

Rationale: Simple caching captured the common follow-up pattern and produced throughput/cost wins without over-engineering unlaunched behavior.

“Don't build a incredibly complicated predictive algorithm to try and understand something that hasn't launched yet.”transcript, stated
“That's it, just caching the most two recent, heavy MCP tool call results increased throughput by two times.”transcript, stated

Ship job-one intelligence before nice-to-have features

Chose analyst-grade fantasy advice, timing, resilience, and scope guardrails over conversation history, league integrations, feedback loops, and custom preferences in v1.

Rationale: The launch goal was proving core fantasy advice under real production constraints; extra personalization could wait.

“because these are valuable features that don't prove job number one.”transcript, stated
“job number one is the only job that matters.”transcript, stated

Gotchas (what bit them)

Domain stats are not self-explanatory to a model.

Root cause: Next Gen Stats has hundreds of fields whose meaning changes by context, so raw names or rich API specs alone were either ambiguous or too large.

Resolution: The team built a Semantic Stats Dictionary from analyst reasoning and LLM-assisted refinement.

“NFL's Next Gen Stats are incredibly vast. There are hundreds of unique data fields, and they mean different things in different contexts.”transcript, stated
“from that, we built a basic data dictionary. Not a data layer, not a third-party service, not another product”transcript, stated

Narrow use-case tools caused fragmented answers and slow loops.

Root cause: Autonomous agents given many narrow tools and thoroughness instructions will make many small calls instead of forming a broad answer.

Resolution: The team consolidated tools around data boundaries and gave the agent broader parameters with compressed data.

“you're going to have dozens of loops and tool calls, each one with narrow bits of information that lack the rich context to answer a broad question.”transcript, stated
“we needed a much broader tool. We needed tools that looked at data boundaries and gave the agent the autonomy to express rich and nuanced intent.”transcript, stated

A correct answer can still be operationally unacceptable.

Root cause: The model's instruction to be complex, thorough, defensible, and backed by data caused one waiver question to request stats for every wide receiver.

Resolution: Per-turn instrumentation exposed the behavior, and the team added guardrails on maximum data pulled and when it could be pulled.

“That's 1.3 million tokens that that question consumed. Why did it consume 1.3 million tokens? It wasn't the answer. The answer was actually really good.”transcript, stated
“put appropriate guardrails around the maximum data it could pull, and under what circumstances it could do it.”transcript, stated

Capacity errors were unacceptable for launch-day users.

Root cause: Sunday traffic and emergent token consumption could exceed planned Bedrock service quotas despite due diligence.

Resolution: The team added fallback routing to another Bedrock-hosted model family and a circuit breaker around overwhelmed primary service calls.

“We couldn't abide a situation where we ran into service capacity or throttling exception. So we build around it.”transcript, stated
“The circuit breaker stays open for a period of time. Reevaluates the primary model.”transcript, stated

Caching was hard because user conversation patterns were unknown before launch.

Root cause: Fantasy users ask open-ended questions and refer back, but the team could not predict exact conversation paths in advance.

Resolution: They studied analyst/user question patterns and used a simple sliding window over the two heaviest recent MCP tool-call results.

“How do you allocate cache when you don't understand what users are going to do when you can't predict the conversation pattern while in advance?”transcript, stated
“We used a simple sliding window mechanism that looked at the heaviest MCP tool calls, and when a new tool call came in, we slid the old one out.”transcript, stated

Evaluation

The team evaluated with thousands of possible questions, analyst expert review, structured-stat correctness, UAT questions from NFL Pro analysts, latency thresholds, production logs, per-turn observability, incident counts, and load/traffic assumptions from NFL Pro.

Metrics: 90% directionally approved by fantasy experts · initial answers under five seconds · complex analysis under 30 seconds at P95 · zero incidents in first month · 10,000 questions in first month · 70% initial token reduction · 90% throttling-exception reduction on launch day · 2x throughput improvement from heavy-call caching · 45% cost reduction

4 supporting quotes
“We went through thousands of possible questions during the Q&A process.”transcript, stated
“we wanted the expert, the Fantasy Expert that we have at Next Gen Stats to be able to say, "Yeah, that passes the Smell Test. I agree with that."”transcript, stated
“hundreds of questions provided to us by NFL Pro analysts that we could use to evaluate quality-to-performance test.”transcript, stated
“this exposed certain decision patterns that allowed us to avoid some pretty unfortunate things on game day.”transcript, stated

Outcomes

The product launched in eight weeks, used hundreds/thousands of analyst questions for evaluation, served 10,000 questions in month one with zero incidents, hit sub-five-second initial streaming, 30-second P95 full responses, 70% token reduction, 2x throughput improvement, and 45% cost reduction.

5 supporting quotes
“we deployed to production in eight weeks.”transcript, stated
“We're able to achieve 90% analyst approved responses.”transcript, stated
“We're able to stream those responses in under five seconds initially.”transcript, stated
“Full response with complex analysis by the end of 30 seconds at high throughput”transcript, stated
“we have had zero incidents since launch.”transcript, stated