LangGraphLangGraph 1.2 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
37 small wins to finish your pathNext lesson

Answering from what you found

Two nodes. One finds the page, the other answers from it. That is the whole shape of a documentation assistant, and you built both kinds of node earlier in this course.

Find, then answer
START. A question arrives in the state.Step 1 of 4

The state

Four keys: what was asked, what was found, which file it came from, and what to say.

python
from typing_extensions import TypedDict

class State(TypedDict):
    question: str
    found: str
    source: str
    answer: str

The finding node

It is the search function from the last lesson, wrapped so it reads from the state and writes back to it. Assume DOCS, words and search are in the file already.

python
def retrieve(state):
    name, body = search(state["question"])
    return {"source": name or "", "found": body}

The answering node

This is the only genuinely new idea in the lesson. You do not send the model the question on its own. You send it the page as well, and tell it to answer out of that.

python
from pretend_model import PretendModel
from langchain_core.messages import HumanMessage

model = PretendModel()

def answer(state):
    prompt = f"Context: {state['found']}\n\nQuestion: {state['question']}"
    return {"answer": model.invoke([HumanMessage(prompt)]).content}

Handing over the passage along with the question is the entire idea behind retrieval. The model is not being asked what it knows. It is being asked to read something and answer from it, which is why it can answer about a product it has never heard of.

Wire the two together

python
from langgraph.graph import StateGraph, START

builder = StateGraph(State)
builder.add_node("retrieve", retrieve)
builder.add_node("answer", answer)
builder.add_edge(START, "retrieve")
builder.add_edge("retrieve", "answer")
graph = builder.compile()

Two nodes and one edge between them. That is lesson 4, with a search in the first node and a model in the second.

Example
result = graph.invoke({"question": "How do I reset my password?", "found": "", "source": "", "answer": ""})

print(result["answer"])

The answer came out of the page, not out of the model's memory. Our stand-in quotes the passage back rather than rewriting it, and a real model would put it in its own words. What matters is where the words came from, and that does not change with the model.

Now ask it something it cannot know

Example
missed = graph.invoke({"question": "Who won the cricket?", "found": "", "source": "", "answer": ""})

print(repr(missed["answer"]))

There is the bug. The search correctly found nothing, the answering node cheerfully handed the model an empty page, and out came an answer that says nothing at all while sounding like it should.

A real model does something worse here. Given an empty passage and a confident instruction, it falls back on whatever it happens to believe and states it as though it came from your documentation. That is the failure people mean when they talk about a model making things up.

This is not the model's fault
The graph is doing exactly what you told it. Nothing checks whether anything was found, so nothing can behave differently when it was not. The next lesson is one conditional edge.
Try it yourself
  • Print result["found"] and confirm the answer came from that page.
  • Ask about billing and watch a different file get used.
  • Print the prompt before sending it, and read exactly what the model is given.

Slow is fine. Stopping is the only problem.