Repository navigation
LLM Memory 1 · Build the notepad: statelessness, RAIL and session isolation #15
akash-coded
started this conversation in
Exercises
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Exercise 1: Build the Notepad
Language: Python
Topics: statelessness, RAIL, LCEL, MessagesPlaceholder, InMemoryChatMessageHistory, RunnableWithMessageHistory, session isolation
Level: Intermediate
Work in pairs. Run the scaffold once, then attempt each question before you open its answer. Fourteen questions across five formats: read, predict, trace, debug, and build. Every code block is real and runs offline with no API key.
The customer for every question: Rao, PNR
JX48Q2, Gold tier, BLR to DEL leg cancelled.Scaffold (run once)
Part A: Read and predict
Q1. Predict the output · Predict
Write the two printed lines. Why does the second call not know the PNR?
Show answer
invokewith a fresh one message list. Nothing carries the PNR over.Q2. Predict the output · Predict
Show answer
Q3. Read the code · Read
The pipe does what?
Show answer
(b). Output of
promptfeedsmodel, whose output feedsStrOutputParser. Same runnable interface at every stage is what lets them compose.Q4. Multi-select · Read
Which are real members of
InMemoryChatMessageHistory? Pick all that apply..messages.add_user_message().append().add_ai_message().get_last().clear().add_messages([...])Show answer
Real: (a), (b), (d), (f), (g).
Not real: (c)
.append()and (e).get_last(). You add turns withadd_user_message,add_ai_message, oradd_messages, not a listappend.Q5. True or false · Read
Mark each.
MessagesPlaceholderkeeps history role-typed (human vs ai).MessagesPlaceholder("history")must matchhistory_messages_keyinRunnableWithMessageHistory.MessagesPlaceholderflattens history into one string.("human", "{input}")changes nothing.Show answer
1 True.
2 True.
3 False (flattening is the exact derailment the placeholder prevents).
4 False (history belongs before the new input; that order is part of correctness now, and part of the caching discount later).
Part B: Trace and match
Q6. Trace the flow · Trace
Correct RAIL, two turns already done. On turn 3 the user asks a new question.
flowchart LR Q[turn 3 question] --> AP[append human] AP --> INV[invoke on full list] INV --> AL[append ai reply] AL --> NEXT[turn 4]The list already holds:
system, h1, a1, h2, a2. What exact messages doesinvokereceive on turn 3?Show answer
system, h1, a1, h2, a2, h3(six messages). Append human runs before invoke, so the turn 3 question is included. The ai reply is appended after the call, so it is not in this call.Q7. Match the code to the RAIL step · Match
Bank: Retrieve, Augment, Invoke, Log.
get_session_history(session_id)MessagesPlaceholder("history")model.invoke(messages)history.add_ai_message(reply)Show answer
get_session_historymodel.invokeadd_ai_messagePart C: Debug and fix
Each snippet has one defect. Name the bad line, give a one line fix.
Q8. Debug · Debug
Symptom: the bot re-asks for details the customer already gave.
Show answer
Bad: the AI reply is never logged.
Fix: add
messages.append(reply)beforereturn. This is the missing Log step.Q9. Debug · Debug
Symptom: every answer is one turn late.
Show answer
Bad line:
reply = model.invoke(messages)runs before the new question is appended, so Augment happens on stale history.Fix: append the human message first, then invoke. Move
messages.append(HumanMessage(user_text))above the invoke.Q10. Debug · Debug
Symptom: history is fetched but the bot still forgets.
Show answer
Bad line:
history_messages_key="chat_history"does not matchMessagesPlaceholder("history"). History lands in a slot that does not exist, so the model never sees it.Fix:
history_messages_key="history".Q11. Debug · Debug
Symptom: customer B is told Rao's PNR.
Show answer
Bad: one shared history for every
session_id, so all customers write to and read from the same notepad.Fix: key a dict by
session_idand create per session:Part D: Diagram to code
Q12. Boilerplate, fill the TODOs · Build
Wire this routing so two ids never mix.
flowchart LR RAO[Rao id cust-rao] --> GS[get_session_history keyed by id] OTH[other id cust-x] --> GS GS --> HR[history cust-rao] GS --> HX[history cust-x] HR --> M1[model sees only cust-rao] HX --> M2[model sees only cust-x]Complete the two TODOs:
Show answer
Quick test:
Q13. Bare code, write from scratch · Build
Build this pipeline in four lines or fewer. No boilerplate given.
flowchart LR IN[input dict] --> P[prompt system, history slot, human input] P --> M[model] M --> S[StrOutputParser] S --> OUT[final string]Requirements:
You are a concise airline support agent.historyinputShow answer
The slot name
historyis exactly what you pass later tohistory_messages_key. Mismatch it and you have rebuilt Q10.Part E: Predict, harder
Q14. Predict the output · Predict
Show answer
mehtasession, which only holds Mehta's turns, so the answer is ZZ90Q1, not Rao's.raohas one turn (human + ai = 2).mehtahas two turns (4). The system message lives in the prompt template, not the stored history, so it is never counted.Skeptic asks: if the store never held the system message, how did the model still behave like an airline agent? Because the system line is re-added by the prompt template on every call, then dropped. It is re-sent, never remembered. That is the entire session in one sentence.
If Q8 through Q11 felt easy, you own RAIL. If Q14 surprised you, re-read where the system message actually lives.
All reactions