mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-17 21:25:46 +02:00
728 KiB
728 KiB
In [1]:
%%capture --no-stderr
%pip install -U langchain_community langchain_openai langgraph wikipedia scikit-learn langchain_fireworks
# We use one or the other search engine below
%pip install -U duckduckgo tavily-pythonIn [2]:
# Uncomment if you want to draw the pretty graph diagrams.
# If you are on MacOS, you will need to run brew install graphviz before installing and update some environment flags
# ! brew install graphviz
# !CFLAGS="-I $(brew --prefix graphviz)/include" LDFLAGS="-L $(brew --prefix graphviz)/lib" pip install -U pygraphvizIn [86]:
import getpass
import os
def _set_env(var: str):
if os.environ.get(var):
return
os.environ[var] = getpass.getpass(var + ":")
# Set for tracing
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "STORM"
_set_env("LANGCHAIN_API_KEY")
_set_env("OPENAI_API_KEY")In [3]:
from langchain_openai import ChatOpenAI
fast_llm = ChatOpenAI(model="gpt-3.5-turbo")
# Uncomment for a Fireworks model
# fast_llm = ChatFireworks(model="accounts/fireworks/models/firefunction-v1", max_tokens=32_000)
long_context_llm = ChatOpenAI(model="gpt-4-turbo-preview")In [4]:
from typing import List, Optional
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
direct_gen_outline_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a Wikipedia writer. Write an outline for a Wikipedia page about a user-provided topic. Be comprehensive and specific.",
),
("user", "{topic}"),
]
)
class Subsection(BaseModel):
subsection_title: str = Field(..., title="Title of the subsection")
description: str = Field(..., title="Content of the subsection")
@property
def as_str(self) -> str:
return f"### {self.subsection_title}\n\n{self.description}".strip()
class Section(BaseModel):
section_title: str = Field(..., title="Title of the section")
description: str = Field(..., title="Content of the section")
subsections: Optional[List[Subsection]] = Field(
default=None,
title="Titles and descriptions for each subsection of the Wikipedia page.",
)
@property
def as_str(self) -> str:
subsections = "\n\n".join(
f"### {subsection.subsection_title}\n\n{subsection.description}"
for subsection in self.subsections or []
)
return f"## {self.section_title}\n\n{self.description}\n\n{subsections}".strip()
class Outline(BaseModel):
page_title: str = Field(..., title="Title of the Wikipedia page")
sections: List[Section] = Field(
default_factory=list,
title="Titles and descriptions for each section of the Wikipedia page.",
)
@property
def as_str(self) -> str:
sections = "\n\n".join(section.as_str for section in self.sections)
return f"# {self.page_title}\n\n{sections}".strip()
generate_outline_direct = direct_gen_outline_prompt | fast_llm.with_structured_output(
Outline
)/Users/wfh/code/lc/langchain/libs/core/langchain_core/_api/beta_decorator.py:86: LangChainBetaWarning: The function `with_structured_output` is in beta. It is actively being worked on, so the API may change. warn_beta(
In [5]:
example_topic = "Impact of million-plus token context window language models on RAG"
initial_outline = generate_outline_direct.invoke({"topic": example_topic})
print(initial_outline.as_str)# Impact of million-plus token context window language models on RAG ## Introduction Overview of million-plus token context window language models and RAG (Retrieval-Augmented Generation). ## Million-Plus Token Context Window Language Models Explanation of million-plus token context window language models, their architecture, training data, and applications. ## RAG (Retrieval-Augmented Generation) Overview of RAG, its architecture, how it combines retrieval and generation models, and its use in natural language processing tasks. ## Impact on RAG Discuss the impact of million-plus token context window language models on RAG, including improvements in performance, efficiency, and challenges faced.
In [6]:
gen_related_topics_prompt = ChatPromptTemplate.from_template(
"""I'm writing a Wikipedia page for a topic mentioned below. Please identify and recommend some Wikipedia pages on closely related subjects. I'm looking for examples that provide insights into interesting aspects commonly associated with this topic, or examples that help me understand the typical content and structure included in Wikipedia pages for similar topics.
Please list the as many subjects and urls as you can.
Topic of interest: {topic}
"""
)
class RelatedSubjects(BaseModel):
topics: List[str] = Field(
description="Comprehensive list of related subjects as background research.",
)
expand_chain = gen_related_topics_prompt | fast_llm.with_structured_output(
RelatedSubjects
)In [7]:
related_subjects = await expand_chain.ainvoke({"topic": example_topic})
related_subjectsOut [7]:
RelatedSubjects(topics=['Language models', 'Retriever-Reader-Generator (RAG) model', 'Natural language processing', 'Machine learning', 'Artificial intelligence', 'Text generation', 'Transformer architecture', 'Context window', 'Impact of language models'])
In [8]:
class Editor(BaseModel):
affiliation: str = Field(
description="Primary affiliation of the editor.",
)
name: str = Field(
description="Name of the editor.", pattern=r"^[a-zA-Z0-9_-]{1,64}$"
)
role: str = Field(
description="Role of the editor in the context of the topic.",
)
description: str = Field(
description="Description of the editor's focus, concerns, and motives.",
)
@property
def persona(self) -> str:
return f"Name: {self.name}\nRole: {self.role}\nAffiliation: {self.affiliation}\nDescription: {self.description}\n"
class Perspectives(BaseModel):
editors: List[Editor] = Field(
description="Comprehensive list of editors with their roles and affiliations.",
# Add a pydantic validation/restriction to be at most M editors
)
gen_perspectives_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""You need to select a diverse (and distinct) group of Wikipedia editors who will work together to create a comprehensive article on the topic. Each of them represents a different perspective, role, or affiliation related to this topic.\
You can use other Wikipedia pages of related topics for inspiration. For each editor, add a description of what they will focus on.
Wiki page outlines of related topics for inspiration:
{examples}""",
),
("user", "Topic of interest: {topic}"),
]
)
gen_perspectives_chain = gen_perspectives_prompt | ChatOpenAI(
model="gpt-3.5-turbo"
).with_structured_output(Perspectives)In [9]:
from langchain_community.retrievers import WikipediaRetriever
from langchain_core.runnables import RunnableLambda
from langchain_core.runnables import chain as as_runnable
wikipedia_retriever = WikipediaRetriever(load_all_available_meta=True, top_k_results=1)
def format_doc(doc, max_length=1000):
related = "- ".join(doc.metadata["categories"])
return f"### {doc.metadata['title']}\n\nSummary: {doc.page_content}\n\nRelated\n{related}"[
:max_length
]
def format_docs(docs):
return "\n\n".join(format_doc(doc) for doc in docs)
@as_runnable
async def survey_subjects(topic: str):
related_subjects = await expand_chain.ainvoke({"topic": topic})
retrieved_docs = await wikipedia_retriever.abatch(
related_subjects.topics, return_exceptions=True
)
all_docs = []
for docs in retrieved_docs:
if isinstance(docs, BaseException):
continue
all_docs.extend(docs)
formatted = format_docs(all_docs)
return await gen_perspectives_chain.ainvoke({"examples": formatted, "topic": topic})In [11]:
perspectives = await survey_subjects.ainvoke(example_topic)In [12]:
perspectives.dict()Out [12]:
{'editors': [{'affiliation': 'Academic Research',
'name': 'Dr. Linguist',
'role': 'Language Model Expert',
'description': 'Dr. Linguist will focus on explaining the technical aspects of million-plus token context window language models and their impact on RAG (Retrieval-Augmented Generation) systems.'},
{'affiliation': 'Industry',
'name': 'TechTrendz',
'role': 'AI Solutions Architect',
'description': 'TechTrendz will provide insights on the practical applications of million-plus token context window language models in RAG systems and discuss their benefits and challenges in real-world scenarios.'},
{'affiliation': 'Open Source Community',
'name': 'CodeGenius',
'role': 'Machine Learning Enthusiast',
'description': 'CodeGenius will explore the open-source tools and frameworks available for implementing million-plus token context window language models in RAG systems and share their experiences with the community.'},
{'affiliation': 'Tech Journalism',
'name': 'DataDive',
'role': 'AI Technology Journalist',
'description': 'DataDive will cover the latest developments and advancements in million-plus token context window language models and their implications for RAG systems, focusing on industry trends and use cases.'}]}In [13]:
from typing import Annotated
from langchain_core.messages import AnyMessage
from typing_extensions import TypedDict
from langgraph.graph import END, StateGraph, START
def add_messages(left, right):
if not isinstance(left, list):
left = [left]
if not isinstance(right, list):
right = [right]
return left + right
def update_references(references, new_references):
if not references:
references = {}
references.update(new_references)
return references
def update_editor(editor, new_editor):
# Can only set at the outset
if not editor:
return new_editor
return editor
class InterviewState(TypedDict):
messages: Annotated[List[AnyMessage], add_messages]
references: Annotated[Optional[dict], update_references]
editor: Annotated[Optional[Editor], update_editor]In [14]:
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
from langchain_core.prompts import MessagesPlaceholder
gen_qn_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""You are an experienced Wikipedia writer and want to edit a specific page. \
Besides your identity as a Wikipedia writer, you have a specific focus when researching the topic. \
Now, you are chatting with an expert to get information. Ask good questions to get more useful information.
When you have no more questions to ask, say "Thank you so much for your help!" to end the conversation.\
Please only ask one question at a time and don't ask what you have asked before.\
Your questions should be related to the topic you want to write.
Be comprehensive and curious, gaining as much unique insight from the expert as possible.\
Stay true to your specific perspective:
{persona}""",
),
MessagesPlaceholder(variable_name="messages", optional=True),
]
)
def tag_with_name(ai_message: AIMessage, name: str):
ai_message.name = name
return ai_message
def swap_roles(state: InterviewState, name: str):
converted = []
for message in state["messages"]:
if isinstance(message, AIMessage) and message.name != name:
message = HumanMessage(**message.dict(exclude={"type"}))
converted.append(message)
return {"messages": converted}
@as_runnable
async def generate_question(state: InterviewState):
editor = state["editor"]
gn_chain = (
RunnableLambda(swap_roles).bind(name=editor.name)
| gen_qn_prompt.partial(persona=editor.persona)
| fast_llm
| RunnableLambda(tag_with_name).bind(name=editor.name)
)
result = await gn_chain.ainvoke(state)
return {"messages": [result]}In [15]:
messages = [
HumanMessage(f"So you said you were writing an article on {example_topic}?")
]
question = await generate_question.ainvoke(
{
"editor": perspectives.editors[0],
"messages": messages,
}
)
question["messages"][0].contentOut [15]:
"Yes, that's correct. I'm focusing on the technical aspects of million-plus token context window language models and their impact on Retrieval-Augmented Generation (RAG) systems. Can you provide more information on how these large context window language models are trained and how they differ from traditional models in the context of RAG systems?"
In [16]:
class Queries(BaseModel):
queries: List[str] = Field(
description="Comprehensive list of search engine queries to answer the user's questions.",
)
gen_queries_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a helpful research assistant. Query the search engine to answer the user's questions.",
),
MessagesPlaceholder(variable_name="messages", optional=True),
]
)
gen_queries_chain = gen_queries_prompt | ChatOpenAI(
model="gpt-3.5-turbo"
).with_structured_output(Queries, include_raw=True)In [17]:
queries = await gen_queries_chain.ainvoke(
{"messages": [HumanMessage(content=question["messages"][0].content)]}
)
queries["parsed"].queriesOut [17]:
['Training process of million-plus token context window language models', 'Differences between large context window language models and traditional models in Retrieval-Augmented Generation systems']
In [43]:
class AnswerWithCitations(BaseModel):
answer: str = Field(
description="Comprehensive answer to the user's question with citations.",
)
cited_urls: List[str] = Field(
description="List of urls cited in the answer.",
)
@property
def as_str(self) -> str:
return f"{self.answer}\n\nCitations:\n\n" + "\n".join(
f"[{i+1}]: {url}" for i, url in enumerate(self.cited_urls)
)
gen_answer_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""You are an expert who can use information effectively. You are chatting with a Wikipedia writer who wants\
to write a Wikipedia page on the topic you know. You have gathered the related information and will now use the information to form a response.
Make your response as informative as possible and make sure every sentence is supported by the gathered information.
Each response must be backed up by a citation from a reliable source, formatted as a footnote, reproducing the URLS after your response.""",
),
MessagesPlaceholder(variable_name="messages", optional=True),
]
)
gen_answer_chain = gen_answer_prompt | fast_llm.with_structured_output(
AnswerWithCitations, include_raw=True
).with_config(run_name="GenerateAnswer")In [19]:
from langchain_community.utilities.duckduckgo_search import DuckDuckGoSearchAPIWrapper
from langchain_core.tools import tool
'''
# Tavily is typically a better search engine, but your free queries are limited
search_engine = TavilySearchResults(max_results=4)
@tool
async def search_engine(query: str):
"""Search engine to the internet."""
results = tavily_search.invoke(query)
return [{"content": r["content"], "url": r["url"]} for r in results]
'''
# DDG
search_engine = DuckDuckGoSearchAPIWrapper()
@tool
async def search_engine(query: str):
"""Search engine to the internet."""
results = DuckDuckGoSearchAPIWrapper()._ddgs_text(query)
return [{"content": r["body"], "url": r["href"]} for r in results]In [ ]:
import json
from langchain_core.runnables import RunnableConfig
async def gen_answer(
state: InterviewState,
config: Optional[RunnableConfig] = None,
name: str = "Subject_Matter_Expert",
max_str_len: int = 15000,
):
swapped_state = swap_roles(state, name) # Convert all other AI messages
queries = await gen_queries_chain.ainvoke(swapped_state)
query_results = await search_engine.abatch(
queries["parsed"].queries, config, return_exceptions=True
)
successful_results = [
res for res in query_results if not isinstance(res, Exception)
]
all_query_results = {
res["url"]: res["content"] for results in successful_results for res in results
}
# We could be more precise about handling max token length if we wanted to here
dumped = json.dumps(all_query_results)[:max_str_len]
ai_message: AIMessage = queries["raw"]
tool_call = queries["raw"].tool_calls[0]
tool_id = tool_call["id"]
tool_message = ToolMessage(tool_call_id=tool_id, content=dumped)
swapped_state["messages"].extend([ai_message, tool_message])
# Only update the shared state with the final answer to avoid
# polluting the dialogue history with intermediate messages
generated = await gen_answer_chain.ainvoke(swapped_state)
cited_urls = set(generated["parsed"].cited_urls)
# Save the retrieved information to a the shared state for future reference
cited_references = {k: v for k, v in all_query_results.items() if k in cited_urls}
formatted_message = AIMessage(name=name, content=generated["parsed"].as_str)
return {"messages": [formatted_message], "references": cited_references}In [21]:
example_answer = await gen_answer(
{"messages": [HumanMessage(content=question["messages"][0].content)]}
)
example_answer["messages"][-1].contentOut [21]:
'Large context window language models, such as the Llama2 70B model, can support context windows of more than 100k tokens without continual training through innovations like Dual Chunk Attention (DCA). These models have significantly longer context windows compared to traditional models, with capabilities like processing up to 1 million tokens at once, providing more consistent and relevant outputs. Training these models often involves starting with a smaller window size and gradually increasing it through fine-tuning on larger windows. In contrast, traditional models have much shorter context windows, limiting their ability to process extensive information in a prompt. Retrieval-Augmented Generation (RAG) systems, on the other hand, integrate large language models with external knowledge sources to enhance their performance, offering a pathway to combine the capabilities of models like ChatGPT/GPT-4 with custom data sources for more informed and contextually aware outputs.\n\nCitations:\n\n[1]: https://arxiv.org/abs/2402.17463\n[2]: https://blog.google/technology/ai/long-context-window-ai-models/\n[3]: https://medium.com/@ddxzzx/why-and-how-to-achieve-longer-context-windows-for-llms-5f76f8656ea9\n[4]: https://blog.google/technology/ai/google-gemini-next-generation-model-february-2024/\n[5]: https://huggingface.co/papers/2402.13753\n[6]: https://www.pinecone.io/blog/why-use-retrieval-instead-of-larger-context/\n[7]: https://medium.com/emalpha/innovations-in-retrieval-augmented-generation-8e6e70f95629\n[8]: https://inside-machinelearning.com/en/rag/'
In [45]:
max_num_turns = 5
def route_messages(state: InterviewState, name: str = "Subject_Matter_Expert"):
messages = state["messages"]
num_responses = len(
[m for m in messages if isinstance(m, AIMessage) and m.name == name]
)
if num_responses >= max_num_turns:
return END
last_question = messages[-2]
if last_question.content.endswith("Thank you so much for your help!"):
return END
return "ask_question"
builder = StateGraph(InterviewState)
builder.add_node("ask_question", generate_question)
builder.add_node("answer_question", gen_answer)
builder.add_conditional_edges("answer_question", route_messages)
builder.add_edge("ask_question", "answer_question")
builder.add_edge(START, "ask_question")
interview_graph = builder.compile().with_config(run_name="Conduct Interviews")In [46]:
from IPython.display import Image
# Feel free to comment out if you have
# not installed pygraphviz
Image(interview_graph.get_graph().draw_png())Out [46]:
In [23]:
final_step = None
initial_state = {
"editor": perspectives.editors[0],
"messages": [
AIMessage(
content=f"So you said you were writing an article on {example_topic}?",
name="Subject_Matter_Expert",
)
],
}
async for step in interview_graph.astream(initial_state):
name = next(iter(step))
print(name)
print("-- ", str(step[name]["messages"])[:300])
if END in step:
final_step = stepask_question -- [AIMessage(content="Yes, that's correct. I am focusing on the technical aspects of million-plus token context window language models and their impact on RAG systems. Can you provide more insight into how these large context window models affect the performance and capabilities of RAG systems?", name answer_question -- [AIMessage(content='The introduction of large context window language models, such as Gemini 1.5 with a 1 million token context window, has raised concerns in the AI community regarding its impact on Retrieval-Augmented Generation (RAG) systems. RAG systems represent a significant advancement over t ask_question -- [AIMessage(content='Thank you for the detailed explanation and resources. Could you elaborate on the specific challenges and opportunities that million-plus token context window language models present for RAG systems in terms of improving generation quality, addressing data biases, and the potentia answer_question -- [AIMessage(content='Million-plus token context window language models present both challenges and opportunities for RAG systems. Challenges include the increased computational cost and complexity associated with processing larger context windows, potential issues with retaining factual accuracy when ask_question -- [AIMessage(content='Thank you for the detailed information and references provided. It has been insightful to understand both the challenges and opportunities that million-plus token context window language models bring to RAG systems. I appreciate your assistance in shedding light on this complex t answer_question -- [AIMessage(content="You're welcome! If you have any more questions or need further assistance in the future, feel free to reach out. Good luck with your article on RAG systems and million-plus token context window language models!\n\nCitations:\n\n[1]: https://www.nerdwallet.com/article/finance/exam __end__ -- [AIMessage(content='So you said you were writing an article on Impact of million-plus token context window language models on RAG?', name='Subject Matter Expert'), AIMessage(content="Yes, that's correct. I am focusing on the technical aspects of million-plus token context window language models and
In [24]:
final_state = next(iter(final_step.values()))In [53]:
refine_outline_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""You are a Wikipedia writer. You have gathered information from experts and search engines. Now, you are refining the outline of the Wikipedia page. \
You need to make sure that the outline is comprehensive and specific. \
Topic you are writing about: {topic}
Old outline:
{old_outline}""",
),
(
"user",
"Refine the outline based on your conversations with subject-matter experts:\n\nConversations:\n\n{conversations}\n\nWrite the refined Wikipedia outline:",
),
]
)
# Using turbo preview since the context can get quite long
refine_outline_chain = refine_outline_prompt | long_context_llm.with_structured_output(
Outline
)In [26]:
refined_outline = refine_outline_chain.invoke(
{
"topic": example_topic,
"old_outline": initial_outline.as_str,
"conversations": "\n\n".join(
f"### {m.name}\n\n{m.content}" for m in final_state["messages"]
),
}
)In [27]:
print(refined_outline.as_str)# Impact of million-plus token context window language models on RAG ## Introduction Provides a brief overview of million-plus token context window language models and their relevance to Retrieval-Augmented Generation (RAG) systems, setting the stage for a deeper exploration of their impact. ## Background A foundational section to understand the core concepts involved. ### Million-Plus Token Context Window Language Models Explains what million-plus token context window language models are, including notable examples like Gemini 1.5, focusing on their architecture, training data, and the evolution of their applications. ### Retrieval-Augmented Generation (RAG) Describes the RAG framework, its unique approach of combining retrieval and generation models for enhanced natural language processing, and its significance in the AI landscape. ## Impact on RAG Systems Delves into the effects of million-plus token context window language models on RAG, highlighting both the challenges and opportunities presented. ### Performance and Efficiency Discusses how large context window models influence RAG performance, including aspects of latency, computational demands, and overall efficiency. ### Generation Quality and Diversity Explores the impact on generation quality, the potential for more accurate and diverse outputs, and how these models address data biases and factual accuracy. ### Technical Challenges Identifies specific technical hurdles such as prompt template design, context length limitations, and similarity searches in vector databases, and how they affect RAG systems. ### Opportunities and Advancements Outlines the new capabilities and improvements in agent interaction, information retrieval, and response relevance that these models bring to RAG systems. ## Future Directions Considers ongoing research and potential future developments in the integration of million-plus token context window language models with RAG systems, including speculation on emerging trends and technologies. ## Conclusion Summarizes the key points discussed in the article, reaffirming the significant impact of million-plus token context window language models on RAG systems.
In [28]:
from langchain_community.vectorstores import SKLearnVectorStore
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
reference_docs = [
Document(page_content=v, metadata={"source": k})
for k, v in final_state["references"].items()
]
# This really doesn't need to be a vectorstore for this size of data.
# It could just be a numpy matrix. Or you could store documents
# across requests if you want.
vectorstore = SKLearnVectorStore.from_documents(
reference_docs,
embedding=embeddings,
)
retriever = vectorstore.as_retriever(k=10)In [29]:
retriever.invoke("What's a long context LLM anyway?")Out [29]:
[Document(page_content='In Retrieval Augmented Generation (RAG), a longer context augments our model with more information. For LLMs that power agents, such as chatbots, longer context means more tools and capabilities. When summarizing, longer context means more comprehensive summaries. There exist plenty of use-cases for LLMs that are unlocked by longer context lengths.', metadata={'id': '20454848-23ac-4649-b083-81980532a77b', 'source': 'https://www.anyscale.com/blog/fine-tuning-llms-for-longer-context-and-better-rag-systems'}),
Document(page_content='By the way, the context limits differ among models: two Claude models offer a 100K token context window, which works out to about 75,000 words, which is much higher than most other LLMs. The ...', metadata={'id': '1ee2d2bb-8f8e-4a7e-b45e-608b0804fe4c', 'source': 'https://www.infoworld.com/article/3712227/what-is-rag-more-accurate-and-reliable-llms.html'}),
Document(page_content='Figure 1: LLM response accuracy goes down when context needed to answer correctly is found in the middle of the context window. The problem gets worse with larger context models. The problem gets ...', metadata={'id': 'a41d69e6-62eb-4abd-90ad-0892a2836cba', 'source': 'https://medium.com/@jm_51428/long-context-window-models-vs-rag-a73c35a763f2'}),
Document(page_content='To improve performance, we used retrieval-augmented generation (RAG) to prompt an LLM with accurate up-to-date information. As a result of using RAG, the writing quality of the LLM improves substantially, which has implications for the practical usability of LLMs in clinical trial-related writing.', metadata={'id': 'e1af6e30-8c2b-495b-b572-ac6a29067a94', 'source': 'https://arxiv.org/abs/2402.16406'})]In [30]:
class SubSection(BaseModel):
subsection_title: str = Field(..., title="Title of the subsection")
content: str = Field(
...,
title="Full content of the subsection. Include [#] citations to the cited sources where relevant.",
)
@property
def as_str(self) -> str:
return f"### {self.subsection_title}\n\n{self.content}".strip()
class WikiSection(BaseModel):
section_title: str = Field(..., title="Title of the section")
content: str = Field(..., title="Full content of the section")
subsections: Optional[List[Subsection]] = Field(
default=None,
title="Titles and descriptions for each subsection of the Wikipedia page.",
)
citations: List[str] = Field(default_factory=list)
@property
def as_str(self) -> str:
subsections = "\n\n".join(
subsection.as_str for subsection in self.subsections or []
)
citations = "\n".join([f" [{i}] {cit}" for i, cit in enumerate(self.citations)])
return (
f"## {self.section_title}\n\n{self.content}\n\n{subsections}".strip()
+ f"\n\n{citations}".strip()
)
section_writer_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are an expert Wikipedia writer. Complete your assigned WikiSection from the following outline:\n\n"
"{outline}\n\nCite your sources, using the following references:\n\n<Documents>\n{docs}\n<Documents>",
),
("user", "Write the full WikiSection for the {section} section."),
]
)
async def retrieve(inputs: dict):
docs = await retriever.ainvoke(inputs["topic"] + ": " + inputs["section"])
formatted = "\n".join(
[
f'<Document href="{doc.metadata["source"]}"/>\n{doc.page_content}\n</Document>'
for doc in docs
]
)
return {"docs": formatted, **inputs}
section_writer = (
retrieve
| section_writer_prompt
| long_context_llm.with_structured_output(WikiSection)
)In [31]:
section = await section_writer.ainvoke(
{
"outline": refined_outline.as_str,
"section": refined_outline.sections[1].section_title,
"topic": example_topic,
}
)
print(section.as_str)## Background To fully appreciate the impact of million-plus token context window language models on Retrieval-Augmented Generation (RAG) systems, it's essential to first understand the foundational concepts that underpin these technologies. This background section provides a comprehensive overview of both million-plus token context window language models and RAG, setting the stage for a deeper exploration of their integration and subsequent impacts on artificial intelligence and natural language processing. ### Million-Plus Token Context Window Language Models Million-plus token context window language models, such as Gemini 1.5, represent a significant leap forward in the field of language modeling. These models are designed to process and understand large swathes of text, sometimes exceeding a million tokens in a single pass. The ability to handle such vast amounts of information at once allows for a deeper understanding of context and nuance, which is crucial for generating coherent and relevant text outputs. The development of these models involves sophisticated architecture and extensive training data, pushing the boundaries of what's possible in natural language processing. Over time, the applications of these models have evolved, extending their utility beyond mere text generation to complex tasks like sentiment analysis, language translation, and more. ### Retrieval-Augmented Generation (RAG) The Retrieval-Augmented Generation framework represents a novel approach in the realm of artificial intelligence, blending the strengths of both retrieval and generation models to enhance natural language processing capabilities. At its core, RAG leverages a two-step process: initially, it uses a query to retrieve relevant documents or data from a knowledge base; this information is then utilized to inform and guide the generation of responses by a language model. This method addresses the limitations of fixed context windows by converting text to vector embeddings, facilitating a dynamic and flexible interaction with a vast array of information. RAG's unique approach has cemented its significance in the AI landscape, offering a pathway to more accurate, informative, and contextually relevant text generation.
In [32]:
from langchain_core.output_parsers import StrOutputParser
writer_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are an expert Wikipedia author. Write the complete wiki article on {topic} using the following section drafts:\n\n"
"{draft}\n\nStrictly follow Wikipedia format guidelines.",
),
(
"user",
'Write the complete Wiki article using markdown format. Organize citations using footnotes like "[1]",'
" avoiding duplicates in the footer. Include URLs in the footer.",
),
]
)
writer = writer_prompt | long_context_llm | StrOutputParser()In [33]:
for tok in writer.stream({"topic": example_topic, "draft": section.as_str}):
print(tok, end="")# Impact of Million-Plus Token Context Window Language Models on Retrieval-Augmented Generation (RAG)
The integration of million-plus token context window language models into Retrieval-Augmented Generation (RAG) systems marks a pivotal advancement in the field of artificial intelligence (AI) and natural language processing (NLP). This article delves into the background of both technologies, explores their convergence, and examines the profound effects of this integration on the capabilities and applications of AI-driven language models.
## Contents
1. [Background](#Background)
1. [Million-Plus Token Context Window Language Models](#Million-Plus-Token-Context-Window-Language-Models)
2. [Retrieval-Augmented Generation (RAG)](#Retrieval-Augmented-Generation-(RAG))
2. [Integration of Million-Plus Token Context Window Models and RAG](#Integration-of-Million-Plus-Token-Context-Window-Models-and-RAG)
3. [Impact on Natural Language Processing](#Impact-on-Natural-Language-Processing)
4. [Applications](#Applications)
5. [Challenges and Limitations](#Challenges-and-Limitations)
6. [Future Directions](#Future-Directions)
7. [Conclusion](#Conclusion)
8. [References](#References)
## Background
### Million-Plus Token Context Window Language Models
Million-plus token context window language models, exemplified by systems like Gemini 1.5, have revolutionized language modeling by their ability to process and interpret extensive texts, potentially exceeding a million tokens in a single analysis[1]. The capacity to manage such large volumes of data enables these models to grasp context and subtlety to a degree previously unattainable, enhancing their effectiveness in generating text that is coherent, relevant, and nuanced. The development of these models has been characterized by innovative architecture and the utilization of vast training datasets, pushing the envelope of natural language processing capabilities[2].
### Retrieval-Augmented Generation (RAG)
RAG systems represent an innovative paradigm in AI, merging the strengths of retrieval-based and generative models to improve the quality and relevance of text generation[3]. By initially retrieving related documents or data in response to a query, and subsequently using this information to guide the generation process, RAG overcomes the limitations inherent in fixed context windows. This methodology allows for dynamic access to a broad range of information, significantly enhancing the model's ability to generate accurate, informative, and contextually appropriate responses[4].
## Integration of Million-Plus Token Context Window Models and RAG
The integration of million-plus token context window models with RAG systems has been a natural progression in the quest for more sophisticated NLP solutions. By combining the extensive contextual understanding afforded by large context window models with the dynamic, information-rich capabilities of RAG, researchers and developers have been able to create AI systems that exhibit unprecedented levels of understanding, coherence, and relevance in text generation[5].
## Impact on Natural Language Processing
The fusion of these technologies has had a significant impact on the field of NLP, leading to advancements in several key areas:
- **Enhanced Understanding**: The combined system exhibits a deeper comprehension of both the immediate context and broader subject matter[6].
- **Improved Coherence**: Generated text is more coherent over longer passages, maintaining consistency and relevance[7].
- **Increased Relevance**: Outputs are more contextually relevant, drawing accurately from a wider range of sources[8].
## Applications
This technological convergence has broadened the applicability of NLP systems in numerous fields, including but not limited to:
- **Automated Content Creation**: Generating written content that is both informative and contextually appropriate for various platforms[9].
- **Customer Support**: Providing answers that are not only accurate but also tailored to the specific context of user inquiries[10].
- **Research Assistance**: Assisting in literature review and data analysis by retrieving and synthesizing relevant information from vast databases[11].
## Challenges and Limitations
Despite their advancements, the integration of these technologies faces several challenges:
- **Computational Resources**: The processing of million-plus tokens and the dynamic retrieval of relevant information require significant computational power[12].
- **Data Privacy and Security**: Ensuring the confidentiality and integrity of the data accessed by these systems poses ongoing concerns[13].
- **Bias and Fairness**: The potential for inheriting and amplifying biases from training data remains a critical issue to address[14].
## Future Directions
Future research is likely to focus on optimizing computational efficiency, enhancing the models' ability to understand and generate more diverse and nuanced text, and addressing ethical considerations associated with AI and NLP technologies[15].
## Conclusion
The integration of million-plus token context window language models with RAG systems represents a milestone in the evolution of natural language processing, offering enhanced capabilities that have significant implications across various applications. As these technologies continue to evolve, they promise to further transform the landscape of AI-driven language models.
## References
1. Gemini 1.5 Documentation. (n.d.).
2. The Evolution of Language Models. (2022).
3. Introduction to Retrieval-Augmented Generation. (2021).
4. Leveraging Large Context Windows for NLP. (2023).
5. Integrating Context Window Models with RAG. (2023).
6. Deep Learning in NLP. (2020).
7. Coherence in Text Generation. (2019).
8. Contextual Relevance in AI. (2021).
9. Applications of NLP in Content Creation. (2022).
10. AI in Customer Support. (2023).
11. NLP for Research Assistance. (2021).
12. Computational Challenges in NLP. (2022).
13. Data Privacy in AI Systems. (2020).
14. Addressing Bias in AI. (2021).
15. Future of NLP Technologies. (2023).In [55]:
class ResearchState(TypedDict):
topic: str
outline: Outline
editors: List[Editor]
interview_results: List[InterviewState]
# The final sections output
sections: List[WikiSection]
article: strIn [80]:
import asyncio
async def initialize_research(state: ResearchState):
topic = state["topic"]
coros = (
generate_outline_direct.ainvoke({"topic": topic}),
survey_subjects.ainvoke(topic),
)
results = await asyncio.gather(*coros)
return {
**state,
"outline": results[0],
"editors": results[1].editors,
}
async def conduct_interviews(state: ResearchState):
topic = state["topic"]
initial_states = [
{
"editor": editor,
"messages": [
AIMessage(
content=f"So you said you were writing an article on {topic}?",
name="Subject_Matter_Expert",
)
],
}
for editor in state["editors"]
]
# We call in to the sub-graph here to parallelize the interviews
interview_results = await interview_graph.abatch(initial_states)
return {
**state,
"interview_results": interview_results,
}
def format_conversation(interview_state):
messages = interview_state["messages"]
convo = "\n".join(f"{m.name}: {m.content}" for m in messages)
return f'Conversation with {interview_state["editor"].name}\n\n' + convo
async def refine_outline(state: ResearchState):
convos = "\n\n".join(
[
format_conversation(interview_state)
for interview_state in state["interview_results"]
]
)
updated_outline = await refine_outline_chain.ainvoke(
{
"topic": state["topic"],
"old_outline": state["outline"].as_str,
"conversations": convos,
}
)
return {**state, "outline": updated_outline}
async def index_references(state: ResearchState):
all_docs = []
for interview_state in state["interview_results"]:
reference_docs = [
Document(page_content=v, metadata={"source": k})
for k, v in interview_state["references"].items()
]
all_docs.extend(reference_docs)
await vectorstore.aadd_documents(all_docs)
return state
async def write_sections(state: ResearchState):
outline = state["outline"]
sections = await section_writer.abatch(
[
{
"outline": refined_outline.as_str,
"section": section.section_title,
"topic": state["topic"],
}
for section in outline.sections
]
)
return {
**state,
"sections": sections,
}
async def write_article(state: ResearchState):
topic = state["topic"]
sections = state["sections"]
draft = "\n\n".join([section.as_str for section in sections])
article = await writer.ainvoke({"topic": topic, "draft": draft})
return {
**state,
"article": article,
}In [73]:
from langgraph.checkpoint.memory import MemorySaver
builder_of_storm = StateGraph(ResearchState)
nodes = [
("init_research", initialize_research),
("conduct_interviews", conduct_interviews),
("refine_outline", refine_outline),
("index_references", index_references),
("write_sections", write_sections),
("write_article", write_article),
]
for i in range(len(nodes)):
name, node = nodes[i]
builder_of_storm.add_node(name, node)
if i > 0:
builder_of_storm.add_edge(nodes[i - 1][0], name)
builder_of_storm.add_edge(START, nodes[0][0])
builder_of_storm.add_edge(nodes[-1][0], END)
storm = builder_of_storm.compile(checkpointer=MemorySaver())In [74]:
Image(storm.get_graph().draw_png())Out [74]:
In [75]:
config = {"configurable": {"thread_id": "my-thread"}}
async for step in storm.astream(
{
"topic": "Groq, NVIDIA, Llamma.cpp and the future of LLM Inference",
},
config,
):
name = next(iter(step))
print(name)
print("-- ", str(step[name])[:300])init_research
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', sections=[Section(section_title='Introduction', description='Overview of Groq, NVIDIA, Llamma.cpp, and their significance in the field of La
conduct_interviews
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', sections=[Section(section_title='Introduction', description='Overview of Groq, NVIDIA, Llamma.cpp, and their significance in the field of La
refine_outline
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the Future of LLM Inference', sections=[Section(section_title='Introduction', description='An overview of the significance and roles of Groq, NVIDIA, and Llamma.cpp in th
index_references
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the Future of LLM Inference', sections=[Section(section_title='Introduction', description='An overview of the significance and roles of Groq, NVIDIA, and Llamma.cpp in th
write_sections
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the Future of LLM Inference', sections=[Section(section_title='Introduction', description='An overview of the significance and roles of Groq, NVIDIA, and Llamma.cpp in th
write_article
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the Future of LLM Inference', sections=[Section(section_title='Introduction', description='An overview of the significance and roles of Groq, NVIDIA, and Llamma.cpp in th
__end__
-- {'topic': 'Groq, NVIDIA, Llamma.cpp and the future of LLM Inference', 'outline': Outline(page_title='Groq, NVIDIA, Llamma.cpp and the Future of LLM Inference', sections=[Section(section_title='Introduction', description='An overview of the significance and roles of Groq, NVIDIA, and Llamma.cpp in th
In [82]:
checkpoint = storm.get_state(config)
article = checkpoint.values["article"]In [83]:
from IPython.display import Markdown
# We will down-header the sections to create less confusion in this notebook
Markdown(article.replace("\n#", "\n##"))Out [83]:
<IPython.core.display.Markdown object>
