Retrieval-Augmented Generation with LangChain

Nov 12 2024 · Python 3.12, LangChain 0.3.x, JupyterLab 4.2.4

Lesson 04: Advanced RAG Techniques

Enhancing a Basic RAG App Demo

Episode complete

Play next episode

Next

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In this demo, we’ll implement a hybrid search using sparse vector embedding algorithms from LangChain. Start a notebook and add the following code:

# Set up a User Agent for this session
import os
from langchain_openai import ChatOpenAI
from langchain_chroma import Chroma
from langchain_community.document_loaders import WikipediaLoader
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

os.environ['USER_AGENT'] = 'sports-buddy-advanced'

llm = ChatOpenAI(model="gpt-4o-mini")

loader = WikipediaLoader("2024_Summer_Olympics",)
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, 
  chunk_overlap=0)
splits = text_splitter.split_documents(docs)

database = Chroma.from_documents(documents=splits, 
  embedding=OpenAIEmbeddings())
retriever = database.as_retriever()
from langchain.retrievers import BM25Retriever, EnsembleRetriever

keyword_retriever = BM25Retriever.from_documents(splits)
keyword_retriever.k =  3

ensemble_retriever = EnsembleRetriever(retrievers=[retriever, 
  keyword_retriever], weights=[0.3, 0.7])
from langchain.chains import RetrievalQA

dense_chain = RetrievalQA.from_chain_type(
  llm=llm, chain_type="stuff", retriever=retriever
)

sparse_chain = RetrievalQA.from_chain_type(
  llm=llm, chain_type="stuff", retriever=ensemble_retriever
)
normal_response = normal_chain.invoke("What happened at the opening 
  ceremony of the 2024 Summer Olympics")
print(normal_response['result'])
  Athletes were paraded by boat along the Seine River in Paris.
sparse_response = sparse_chain.invoke("What happened at the 
  opening ceremony of the 2024 Summer Olympics")
print(hybrid_response['result'])
  Olympic history.

Citing in RAG

Citations add extra information to your responses, so you know where they came from. Open a new notebook to learn how to add citations to SportsBuddy. In the notebook, start with the following code:

from langchain_community.retrievers import WikipediaRetriever
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
import os

llm = ChatOpenAI(model="gpt-4o-mini")

system_prompt = (
  "You're a helpful AI assistant. Given a user question "
  "and some Wikipedia article snippets, answer the user "
  "question. If none of the articles answer the question, "
  "just say you don't know."
  "\n\nHere are the Wikipedia articles: "
  "{context}"
)

retriever = WikipediaRetriever(top_k_results=6, doc_content_chars_max=2000)
prompt = ChatPromptTemplate.from_messages(
  [
    ("system", system_prompt),
    ("human", "{input}"),
  ]
)
from typing import List

from langchain_core.documents import Document
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough


def format_docs(docs: List[Document]):
  return "\n\n".join(doc.page_content for doc in docs)


rag_chain = (
  RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))
  | prompt
  | llm
  | StrOutputParser()
)

retrieve_docs = (lambda x: x["input"]) | retriever

chain = RunnablePassthrough.assign(context=retrieve_docs).assign(
  answer=rag_chain
)
result = chain.invoke({"input": "How did the USA fair at the 2024 
  Summer Olympics"})
print(result.keys())
dict_keys(['input', 'context', 'answer'])
from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field


class CitedAnswer(BaseModel):
  """Answer the user question based only on the given sources, and cite 
    the sources used."""

  answer: str = Field(
    ...,
    description="The answer to the user question, which is based only on 
      the given sources.",
  )
  citations: List[int] = Field(
    ...,
    description="The integer IDs of the SPECIFIC sources which justify 
      the answer.",
  )
structured_llm = llm.with_structured_output(CitedAnswer)

query = """How did the USA fair at the 2024 Summer Olympics"""
result = structured_llm.invoke(query)

result
citations: List[str] = Field(
  ...,
  description="The string URLs of the SPECIFIC sources which justify 
    the answer.",
)
class Citation(BaseModel):
  source_id: int = Field(
    ...,
    description="The integer ID of a SPECIFIC source which 
      justifies the answer.",
  )
  quote: str = Field(
    ...,
    description="The VERBATIM quote from the specified source that 
      justifies the answer.",
  )


class QuotedAnswer(BaseModel):
  """Answer the user question based only on the given sources, and 
    cite the sources used."""

  answer: str = Field(
    ...,
    description="The answer to the user question, which is based 
      only on the given sources.",
  )
  citations: List[Citation] = Field(
    ..., description="Citations from the given sources that 
      justify the answer."
  )
rag_chain = (
  RunnablePassthrough.assign(context=(lambda x: 
    format_docs_with_id(x["context"])))
  | prompt
  | llm.with_structured_output(QuotedAnswer)
)

retrieve_docs = (lambda x: x["input"]) | retriever

chain = RunnablePassthrough.assign(context=retrieve_docs).assign(
  answer=rag_chain
)

chain.invoke({"input": "How did the USA fair at the 2024 Summer
  Olympics"})
See forum comments
Cinema mode Download course materials from Github
Previous: Enhancing a Basic RAG App Next: Conclusion