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

A folder of documents

The rest of this course built one agent. This part builds the thing people actually ask for: something that answers questions about a set of documents, and admits it when the answer is not in them.

You have every LangGraph idea you need already. What is missing is the piece that finds the right page, and that is ordinary Python. Start there, with no graph at all.

The documents

Four help pages for a note taking app. Small enough to read, varied enough that finding the right one is a real question.

python
DOCS = {
    "getting-started.md": "Install the app from the store, then sign in with your email address. Your notes sync automatically once you are signed in.",
    "passwords.md": "To reset your password, open Settings and choose Reset password. A link is sent to your email, and it expires after one hour.",
    "billing.md": "Plans are billed monthly. To cancel, open Settings, choose Billing, then Cancel plan. You keep access until the end of the month.",
    "offline.md": "Notes written offline are saved on your device. They sync the next time you open the app with a connection.",
}

In a real project these come off disk, and the loop that reads them is four lines. The dictionary is here so the lesson stays about finding, not about file handling.

python
import pathlib

DOCS = {p.name: p.read_text() for p in pathlib.Path("docs").glob("*.md")}

Turning text into words worth matching

To compare a question with a page, reduce both to a set of words. Throwing away the most common English words stops every page matching on the and to.

python
COMMON = {"the", "a", "an", "to", "how", "do", "i", "my", "is", "it",
          "of", "and", "in", "for", "you", "on", "can", "what", "about"}

def words(text):
    return {w.strip(".,?").lower() for w in text.split()} - COMMON

Finding the best page

Score every page by how many words it shares with the question, take the highest, and refuse to guess when nothing overlaps at all.

python
def search(question):
    asked = words(question)
    scored = [(len(asked & words(body)), name) for name, body in DOCS.items()]
    best_score, best_name = max(scored)
    if best_score == 0:
        return None, ""
    return best_name, DOCS[best_name]

That last check is the important line. A search that always returns something will hand the model a page about billing when you asked about the weather, and the model will dutifully answer from it. Returning nothing is what makes lesson 34 possible.

Try it

Example
questions = [
    "How do I reset my password?",
    "Can I cancel my plan?",
    "What happens to notes written offline?",
    "Who won the cricket?",
]

for question in questions:
    name, _ = search(question)
    print(f"{question:42} -> {name or 'nothing found'}")

Three found, one refused, and the fourth is the one that matters. The question is perfectly reasonable and the answer is genuinely not in these documents.

It matches words. It does not understand that cancel my subscription and end my plan mean the same thing, and a real system uses embeddings, which turn text into numbers so that similar meanings sit near each other.

Embeddings need a model, and a model needs a key, so the swap is shown rather than run. Everything around it stays exactly as it is.

python
from langchain_core.vectorstores import InMemoryVectorStore
from langchain.embeddings import init_embeddings

store = InMemoryVectorStore.from_texts(
    texts=list(DOCS.values()),
    embedding=init_embeddings("openai:text-embedding-3-small"),
    metadatas=[{"source": name} for name in DOCS],
)

def search(question):
    hit = store.similarity_search(question, k=1)[0]
    return hit.metadata["source"], hit.page_content
Same trick as the model
The pattern of a course like this is that the crude version teaches the shape and the real version is a swap. You did the same with the model in lesson 14, and the graph you are about to build does not care which search it is given.
Try it yourself
  • Add a fifth document and ask a question that should find it.
  • Take the COMMON words away and see which pages start matching everything.
  • Return the top two pages instead of one, and print both names.

You understood something today that you didn't yesterday.