Multi-Turn Conversations
Learning Outcomes
- Build context effectively across multiple messages without repetition
- Recognise when to continue a conversation vs start fresh
- Use reference and callback patterns to maintain coherence
- Manage and correct conversation drift
- Architect conversations for large, multi-step tasks
Lesson Plan
| Segment | Duration | Topic |
|---|---|---|
| Intro | 3 min | Why multi-turn matters |
| Explain | 8 min | How AI context windows work |
| Demo | 10 min | Building context effectively |
| Demo | 8 min | Reference and callback patterns |
| Explain | 6 min | When to continue vs start fresh |
| Demo | 7 min | Conversation architecture for large tasks |
| Wrap-up | 3 min | Key takeaways |
Before You Begin
Pre-work:
- Complete Lesson 7 on Chain-of-Thought Prompting
- Have a medium-to-large task in mind (e.g., building a feature end-to-end)
- Think about conversations where you lost context or got confused results
Shopping List:
- An AI coding tool (Claude Code, Cursor, Codex, or similar)
- A project that requires multiple steps to implement a feature
- A task complex enough that it can't be done in a single prompt
- Understanding of your tool's context window limits
Every message you send adds to the conversation's context. The AI remembers everything said so far (within its context window) and uses it to inform future responses.
The context window mental model:
┌─────────────────────────────────────────────────┐
│ Context Window │
├─────────────────────────────────────────────────┤
│ System Prompt / Rules File │
│ ───────────────────────────────── │
│ Message 1: You set up the task │
│ Response 1: AI establishes understanding │
│ Message 2: You refine the requirements │
│ Response 2: AI adjusts approach │
│ Message 3: You request implementation │
│ Response 3: AI generates code │
│ ... │
│ Message N: You're still here │
│ Response N: AI has ALL the above as context │
└─────────────────────────────────────────────────┘
What accumulates in context:
- Every message you've sent
- Every response the AI has generated
- Files the AI has read
- Tool outputs (command results, search results)
- Corrections and clarifications you've provided
Why this matters for prompting:
Each new message doesn't exist in isolation. The AI interprets it in light of everything that came before. This means:
- You don't need to repeat yourself — the AI remembers earlier instructions
- Earlier statements influence later responses — an error early on compounds
- You can build progressively — start broad, then narrow down
- Context can get "polluted" — irrelevant tangents dilute focus
Progressive context building example:
Message 1: "I'm building a task management API with Express and PostgreSQL"
→ AI now knows the tech stack for all future messages
Message 2: "The main entity is a Task with title, description, status,
assignee, and due date"
→ AI now knows the data model
Message 3: "Create the database migration for the tasks table"
→ AI uses both prior messages to generate the right migration
→ It knows to use PostgreSQL syntax, not MySQL
→ It includes all the fields mentioned
One of the most important skills in multi-turn prompting is knowing when your current conversation is still serving you — and when it's time to start over.
Continue the conversation when:
- You're iterating on the same piece of code
- The AI has built up context you'd need to re-explain
- You're in the middle of a multi-step task
- You're refining output (making adjustments to previous generations)
- The conversation is focused and on-topic
Start fresh when:
- You're switching to a completely different task
- The conversation has drifted far from the original intent
- The AI seems "stuck" in a wrong mental model
- You've accumulated many corrections and the context is confusing
- The AI keeps repeating the same mistake despite corrections
- You want to try a completely different approach
Signs your conversation is "poisoned":
You: "Don't use class components"
AI: [generates class component]
You: "I said NO class components. Use functional components with hooks"
AI: [generates functional component but with class-style patterns]
You: "Hooks! useState, useEffect!"
AI: [finally correct but now overly reliant on hooks where not needed]
When corrections pile up, the AI can get confused about what you actually want. Starting fresh with clear initial instructions is often faster.
The "summary and restart" technique:
When you need to start fresh but preserve important decisions:
New conversation:
> I'm continuing work on a task management API.
> Key decisions made so far:
> - Express + PostgreSQL + Knex
> - Tasks have: title, description, status (enum: todo/in-progress/done),
> assignee (FK to users), due_date
> - Using repository pattern (controllers → services → repositories)
> - Authentication via JWT with 1-hour expiry
>
> I now need to implement the task assignment endpoint.
This gives you a clean slate with the important context preserved.
How to judge context window health:
| Signal | Meaning | Action |
|---|---|---|
| Responses are accurate and contextual | Context is healthy | Continue |
| AI forgets earlier decisions | Context may be overflowing | Summarise and continue |
| AI contradicts itself | Context is confused | Start fresh |
| Responses are getting slower | Context is very large | Start fresh with summary |
| AI repeats the same mistake | Correction isn't sticking | Start fresh with clear rules |
When building across multiple messages, you need ways to reference previous work without repeating everything. These patterns keep conversations efficient.
Pattern 1: Named references
Give things names early, then reference those names later:
Message 1: "Let's call our validation approach the 'Zod schema pattern' —
define the schema, infer the type, validate at the boundary."
Message 5: "Apply the Zod schema pattern to the new /teams endpoint"
The AI remembers the named pattern and applies it consistently.
Pattern 2: "Like you did for X"
Reference previous work directly:
> Create the teams controller like you did for the users controller —
> same structure, same error handling pattern, same response format.
> Add validation to this endpoint the same way you added it to
> the task creation endpoint in message 3.
Pattern 3: "With these differences"
Copy a pattern but specify variations:
> Create the teams service like the users service, with these differences:
> - Teams have a many-to-many relationship with users
> - Team creation requires at least one owner
> - Teams can be archived instead of deleted
Pattern 4: Numbered anchors
When planning a multi-step task, number the steps. Then reference by number:
Message 1: "Here's our plan:
1. Create the database migration
2. Build the repository layer
3. Implement the service with business logic
4. Add the controller with validation
5. Write integration tests"
Message 2: "Let's do step 1"
Message 3: "Good. Now step 2, using the schema from step 1"
Message 4: "Step 3 — remember the validation rules we discussed"
Pattern 5: Explicit corrections
When you need to override something from earlier:
> Earlier I said to use UUID for IDs. I've changed my mind —
> use auto-incrementing integers instead. Apply this to everything
> going forward, and update the migration from earlier.
Be explicit that you're changing a previous decision, not adding a new one.
Pattern 6: Context checkpoints
Periodically verify the AI's understanding:
> Before we continue, summarise your understanding of:
> 1. The data model so far
> 2. The API endpoints we've defined
> 3. Any constraints or rules we've established
This surfaces misunderstandings before they compound.
Conversation drift happens when the focus gradually shifts away from your original goal. It's the most common way multi-turn conversations go wrong.
How drift happens:
Original goal: "Build a user registration endpoint"
Message 1: Build the endpoint ← on track
Message 2: "Also add email verification" ← reasonable extension
Message 3: "What email service should we use?" ← exploring tangent
Message 4: "How do we set up SendGrid?" ← deeper into tangent
Message 5: "Can you also handle bounced emails?" ← fully off track
Message 6: "Actually, let's build a complete email system" ← lost original goal
By message 6, you're building an email system instead of a registration endpoint.
Technique 1: State the goal at each turn
> Continuing with our goal of building the registration endpoint:
> Now add the email verification step.
Restating the goal keeps both you and the AI anchored.
Technique 2: Park tangents explicitly
> Good question about email services, but let's park that for now.
> For this conversation, mock the email sending and we'll integrate
> a real service later. Continue with the registration flow.
Technique 3: Scope boundaries
Set them early and enforce them:
> We're ONLY building the registration endpoint in this session.
> The scope is: POST /api/register → validate input → create user →
> send verification email → return 201.
>
> If we need email infrastructure, we'll handle that separately.
> For now, just call a sendVerificationEmail() function that we'll
> implement later.
Technique 4: Redirect after tangents
If you've already drifted, pull back explicitly:
> We went down a tangent about email services. Let's get back on track.
> Where were we? We had the user creation working and needed to add
> the verification token generation. Continue from there.
Technique 5: Recognise productive vs unproductive tangents
Not all tangents are bad. Some lead to important discoveries:
Productive tangent: "Wait, we need to hash the password before storing it" — this is relevant to registration and should be addressed now.
Unproductive tangent: "What's the best password hashing algorithm across all languages?" — interesting but not actionable right now.
The "one decision per message" rule:
For complex tasks, make one decision or take one step per message. This keeps the conversation focused and makes it easy to backtrack if something goes wrong.
Message 1: "Create the user model" → just the model
Message 2: "Add password hashing to the model" → one concern
Message 3: "Create the registration controller" → one component
Message 4: "Add input validation" → one enhancement
For tasks that span many messages, plan the conversation structure upfront — just like you'd plan the architecture of the code itself.
The "plan, then execute" structure:
Conversation Flow:
┌──────────────┐
│ Phase 1: │ Messages 1-3: Establish context, agree on approach
│ Planning │
├──────────────┤
│ Phase 2: │ Messages 4-10: Build component by component
│ Building │
├──────────────┤
│ Phase 3: │ Messages 11-13: Integration, testing, polish
│ Finishing │
└──────────────┘
Phase 1: Planning (3-4 messages)
Message 1: "I need to build [feature]. Here's the context: [details]"
Message 2: "Before we code, plan the approach: what files, what order,
what patterns?"
Message 3: "Good plan. One adjustment: [refinement]. Let's start."
Phase 2: Building (structured execution)
Execute the plan step by step:
Message 4: "Start with step 1 from the plan: [specific deliverable]"
Message 5: "Good. Step 2: [specific deliverable]"
...
Each message targets a specific, completable piece of work.
Phase 3: Finishing (integration and review)
Message 11: "Now let's make sure everything connects properly"
Message 12: "Review what we've built for any gaps or inconsistencies"
Message 13: "Write the tests"
Multi-conversation architecture:
For truly large features, split across multiple conversations:
Conversation 1: Planning + Data Layer
→ Outcome: database schema, migrations, repository functions
Conversation 2: Business Logic
→ Input: "We created [schema] in the previous session"
→ Outcome: service layer with business rules
Conversation 3: API Layer
→ Input: "We have [services] built. Now add the HTTP layer"
→ Outcome: controllers, routes, middleware
Conversation 4: Testing
→ Input: "Here's the feature we built across [describe]"
→ Outcome: integration and unit tests
The handoff message:
When starting a new conversation that continues previous work:
> Continuing from a previous session. Here's where we are:
>
> COMPLETED:
> - Database: tasks table with [columns], migration applied
> - Repository: TaskRepository with CRUD + findByAssignee
> - Service: TaskService with create, update, assign, complete
>
> NEXT:
> - Build the REST controller for tasks
> - Routes: GET/POST /tasks, GET/PUT/DELETE /tasks/:id, POST /tasks/:id/assign
>
> CONVENTIONS (from the previous work):
> - Using Zod for validation
> - Result<T, E> for error handling
> - Repository pattern (controller → service → repo)
The "checkpoint" technique:
Every 5-6 messages, ask the AI to summarise progress:
> Let's checkpoint. Summarise:
> 1. What we've built so far
> 2. What's remaining from our plan
> 3. Any decisions we made along the way
This catches drift, verifies understanding, and creates a save-point you can use if you need to start a new conversation.
Questions & Answers
Key Takeaways
- Context accumulates — every message builds on all previous ones, so quality early matters
- Know when to restart — confused context is worse than no context
- Name things and reference them — "like the users controller" beats repeating everything
- Fight drift actively — restate goals, park tangents, enforce scope
- Architect large tasks — plan phases, execute step by step, checkpoint regularly
- Handoff cleanly — when starting fresh, summarise decisions and progress explicitly
Next Steps: In Lesson 9 — Prompt Patterns & Templates, you'll learn reusable prompt patterns that work across any AI tool for common development tasks.