Skip to main content
In this lesson we show a complete, practical example that uses DynamoDB to persist conversational state for a chat application while calling a stateless model via the Bedrock Runtime SDK for inference. At the top of the Python file the example creates two AWS SDK clients:
  • A Bedrock Runtime client to perform inference requests.
  • A DynamoDB resource client to read and write conversation history.
This sample assumes a DynamoDB table called ChatSessions already exists and uses sessionId as its partition key.
Make sure the DynamoDB table named ChatSessions exists and its partition key is sessionId. This code does not create the table; it only reads from and writes to it.
Overview
  • Purpose: Persist and retrieve chat history per session so a stateless model can be given conversational context on each inference call.
  • Key idea: Store messages as an ordered list per sessionId, trim history to a bounded size to control model context usage, and overwrite the session item when saving updated history.
Complete example (Python)
  • The code below demonstrates loading and saving message history from DynamoDB, trimming history to the most recent messages before sending it to the model, and includes minimal error handling.
Notes on the example
  • load_messages calls table.get_item with Key={"sessionId": session_id} to fetch the DynamoDB item that contains the message list. If the item or messages attribute is missing, it returns an empty list.
  • save_messages uses table.put_item to write the entire item (partition key plus messages). DynamoDB writes are unconditional by default, so this call overwrites any previous item for that sessionId. Conditional writes are possible but are unnecessary for this simple conversation-history use case.
  • trim_messages keeps only the most recent N messages (controlled by MAX_MESSAGES) so you don’t exceed the model context window or send unnecessary history.
table.put_item overwrites the item for sessionId unconditionally. If you require concurrency control (to avoid lost updates), consider using conditional writes or version attributes (IfNotExists, ConditionExpression, or atomic counters).
Usage patterns and session semantics
  • Using session IDs lets the same user (or conversation) keep state across multiple requests:
    • chat("user123", "hello") → persists the conversation under session user123.
    • chat("user123", "what did I just say?") → loads and continues the same conversation.
    • chat("user456", "hi there") → starts a separate conversation stored under user456.
  • Session IDs can be user IDs, conversation IDs, or any identifier that correlates messages to a specific conversational context.
What to expect when persisting conversational context
  • Persisted context enables more natural multi-turn interactions, personalization, and fewer repeated prompts for the same information.
A slide titled "Results" with five numbered dark-blue panels. Each panel lists a benefit—natural/intuitive user interaction; personalized customer experiences; scalable support without linear staffing growth; integration of AI assistants with enterprise workflows; and improved response times and service availability.
Key points to keep in mind
  • Engineering the user experience is as important as model selection. Users expect continuity across turns.
  • Models are stateless by default. Your application must provide conversation history on each request to achieve multi-turn continuity.
  • Using a sessionId as the datastore key is a straightforward, effective pattern. Choose the datastore that matches your scale and latency needs — DynamoDB, Redis, Aurora, etc.
  • Structure stored messages clearly (e.g., role: user / assistant / system), include timestamps when helpful, keep messages ordered chronologically, and always append new messages so the prompt built for the model reflects the proper sequence.
  • Bedrock’s chat-style runtime APIs (sometimes referenced as “Converse” in docs and examples) support a unified message format that simplifies supplying history and adding guardrails or system instructions.
A presentation slide titled "Key Takeaways" listing four numbered points about chatbot development. The points note that chatbots aren't just complex AI, conversation state management and correct request structuring are essential, and message history/Converse API support effective conversational apps.
Best practices and extensions
  • Trim history to a bounded length or use summarization to control token usage and cost.
  • Consider storing metadata (timestamps, message source, embeddings, or flags) alongside messages to support search, retrieval, or tool routing.
  • For complex multi-step workflows or tool access, evaluate Bedrock Agents to orchestrate steps, call external APIs, and manage permissions—at the cost of additional design considerations.
  • Monitor and audit stored conversations for privacy and compliance; consider encryption at rest and access controls for your datastore.
This lesson wraps up managing conversational state and supplying that history as context when calling stateless models. Properly storing and supplying history is essential to delivering engaging, personalized conversational experiences. Coming up next: release management and a feature called shadow release.
A presentation slide titled "What's Next? Release management with Shadow Release" with a teal circuit/brain icon on a dark curved background and a small "© Copyright KodeKloud" note in the corner.
Links and references

Watch Video