|
|
|
@@ -1,5 +1,13 @@
|
|
|
|
|
{
|
|
|
|
|
"cells": [
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
"id": "403aeb6e",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"source": [
|
|
|
|
|
"This directory is retained purely for archival purposes and is no longer updated. Please see the newly [consolidated LangChain documentation](https://docs.langchain.com/oss/python/langgraph/overview) for the most current information and resources."
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"attachments": {
|
|
|
|
|
"15cba0ab-a549-4909-8373-fb761e384eff.png": {
|
|
|
|
@@ -54,7 +62,11 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"import os\n\nos.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\nos.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\"\nos.environ[\"LANGCHAIN_API_KEY\"] = \"<your-api-key>\""
|
|
|
|
|
"import os\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
|
|
|
|
|
"os.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\"\n",
|
|
|
|
|
"os.environ[\"LANGCHAIN_API_KEY\"] = \"<your-api-key>\""
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -64,7 +76,9 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"import os\n\nos.environ[\"LANGCHAIN_PROJECT\"] = \"pinecone-devconnect\""
|
|
|
|
|
"import os\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"os.environ[\"LANGCHAIN_PROJECT\"] = \"pinecone-devconnect\""
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -84,7 +98,18 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"from langchain_openai import OpenAIEmbeddings\nfrom langchain_pinecone import PineconeVectorStore\n\n# use pinecone movies database\n\n# Add to vectorDB\nvectorstore = PineconeVectorStore(\n embedding=OpenAIEmbeddings(),\n index_name=\"sample-movies\",\n text_key=\"summary\",\n)\nretriever = vectorstore.as_retriever()"
|
|
|
|
|
"from langchain_openai import OpenAIEmbeddings\n",
|
|
|
|
|
"from langchain_pinecone import PineconeVectorStore\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# use pinecone movies database\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Add to vectorDB\n",
|
|
|
|
|
"vectorstore = PineconeVectorStore(\n",
|
|
|
|
|
" embedding=OpenAIEmbeddings(),\n",
|
|
|
|
|
" index_name=\"sample-movies\",\n",
|
|
|
|
|
" text_key=\"summary\",\n",
|
|
|
|
|
")\n",
|
|
|
|
|
"retriever = vectorstore.as_retriever()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -113,7 +138,11 @@
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
|
|
|
|
"docs = retriever.invoke(\"James Cameron\")\nfor doc in docs:\n print(\"# \" + doc.metadata[\"title\"])\n print(doc.page_content)\n print()"
|
|
|
|
|
"docs = retriever.invoke(\"James Cameron\")\n",
|
|
|
|
|
"for doc in docs:\n",
|
|
|
|
|
" print(\"# \" + doc.metadata[\"title\"])\n",
|
|
|
|
|
" print(doc.page_content)\n",
|
|
|
|
|
" print()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -173,7 +202,12 @@
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
|
|
|
|
"# Test the retrieval grader\nquestion = \"movies starring jason momoa\"\ndocs = retriever.invoke(question)\ndoc_txt = docs[0].page_content\nprint(doc_txt)\nprint(retrieval_grader.invoke({\"question\": question, \"document\": doc_txt}))"
|
|
|
|
|
"# Test the retrieval grader\n",
|
|
|
|
|
"question = \"movies starring jason momoa\"\n",
|
|
|
|
|
"docs = retriever.invoke(question)\n",
|
|
|
|
|
"doc_txt = docs[0].page_content\n",
|
|
|
|
|
"print(doc_txt)\n",
|
|
|
|
|
"print(retrieval_grader.invoke({\"question\": question, \"document\": doc_txt}))"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -201,7 +235,23 @@
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
|
|
|
|
"### Generate\n\nfrom langchain import hub\nfrom langchain_core.output_parsers import StrOutputParser\n\n# Prompt\nprompt = hub.pull(\"rlm/rag-prompt\")\n\n# LLM\nllm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\n# Chain\nrag_chain = prompt | llm | StrOutputParser()\n\n# Run\ngeneration = rag_chain.invoke({\"context\": docs, \"question\": question})\nprint(generation)"
|
|
|
|
|
"### Generate\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"from langchain import hub\n",
|
|
|
|
|
"from langchain_core.output_parsers import StrOutputParser\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Prompt\n",
|
|
|
|
|
"prompt = hub.pull(\"rlm/rag-prompt\")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# LLM\n",
|
|
|
|
|
"llm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Chain\n",
|
|
|
|
|
"rag_chain = prompt | llm | StrOutputParser()\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Run\n",
|
|
|
|
|
"generation = rag_chain.invoke({\"context\": docs, \"question\": question})\n",
|
|
|
|
|
"print(generation)"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -329,7 +379,17 @@
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
|
|
|
|
"### Question Re-writer\n\n# LLM\nllm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n\n# Prompt\nre_write_prompt = hub.pull(\"efriis/self-rag-question-rewriter\")\n\nquestion_rewriter = re_write_prompt | llm | StrOutputParser()\nprint(question)\nquestion_rewriter.invoke({\"question\": question})"
|
|
|
|
|
"### Question Re-writer\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# LLM\n",
|
|
|
|
|
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Prompt\n",
|
|
|
|
|
"re_write_prompt = hub.pull(\"efriis/self-rag-question-rewriter\")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"question_rewriter = re_write_prompt | llm | StrOutputParser()\n",
|
|
|
|
|
"print(question)\n",
|
|
|
|
|
"question_rewriter.invoke({\"question\": question})"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -351,7 +411,24 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"from typing import List\n\nfrom typing_extensions import TypedDict\n\n\nclass GraphState(TypedDict):\n \"\"\"\n Represents the state of our graph.\n\n Attributes:\n question: question\n generation: LLM generation\n documents: list of documents\n \"\"\"\n\n question: str\n generation: str\n documents: List[str]"
|
|
|
|
|
"from typing import List\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"from typing_extensions import TypedDict\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"class GraphState(TypedDict):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Represents the state of our graph.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Attributes:\n",
|
|
|
|
|
" question: question\n",
|
|
|
|
|
" generation: LLM generation\n",
|
|
|
|
|
" documents: list of documents\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" question: str\n",
|
|
|
|
|
" generation: str\n",
|
|
|
|
|
" documents: List[str]"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -361,7 +438,95 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"### Nodes\n\n\ndef retrieve(state):\n \"\"\"\n Retrieve documents\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): New key added to state, documents, that contains retrieved documents\n \"\"\"\n print(\"---RETRIEVE---\")\n question = state[\"question\"]\n\n # Retrieval\n documents = retriever.invoke(question)\n return {\"documents\": documents, \"question\": question}\n\n\ndef generate(state):\n \"\"\"\n Generate answer\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): New key added to state, generation, that contains LLM generation\n \"\"\"\n print(\"---GENERATE---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # RAG generation\n generation = rag_chain.invoke({\"context\": documents, \"question\": question})\n return {\"documents\": documents, \"question\": question, \"generation\": generation}\n\n\ndef grade_documents(state):\n \"\"\"\n Determines whether the retrieved documents are relevant to the question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): Updates documents key with only filtered relevant documents\n \"\"\"\n\n print(\"---CHECK DOCUMENT RELEVANCE TO QUESTION---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # Score each doc\n filtered_docs = []\n for d in documents:\n score = retrieval_grader.invoke(\n {\"question\": question, \"document\": d.page_content}\n )\n grade = score.binary_score\n if grade == \"yes\":\n print(\"---GRADE: DOCUMENT RELEVANT---\")\n filtered_docs.append(d)\n else:\n print(\"---GRADE: DOCUMENT NOT RELEVANT---\")\n continue\n return {\"documents\": filtered_docs, \"question\": question}\n\n\ndef transform_query(state):\n \"\"\"\n Transform the query to produce a better question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): Updates question key with a re-phrased question\n \"\"\"\n\n print(\"---TRANSFORM QUERY---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # Re-write question\n better_question = question_rewriter.invoke({\"question\": question})\n return {\"documents\": documents, \"question\": better_question}"
|
|
|
|
|
"### Nodes\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def retrieve(state):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Retrieve documents\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Args:\n",
|
|
|
|
|
" state (dict): The current graph state\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Returns:\n",
|
|
|
|
|
" state (dict): New key added to state, documents, that contains retrieved documents\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" print(\"---RETRIEVE---\")\n",
|
|
|
|
|
" question = state[\"question\"]\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" # Retrieval\n",
|
|
|
|
|
" documents = retriever.invoke(question)\n",
|
|
|
|
|
" return {\"documents\": documents, \"question\": question}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def generate(state):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Generate answer\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Args:\n",
|
|
|
|
|
" state (dict): The current graph state\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Returns:\n",
|
|
|
|
|
" state (dict): New key added to state, generation, that contains LLM generation\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" print(\"---GENERATE---\")\n",
|
|
|
|
|
" question = state[\"question\"]\n",
|
|
|
|
|
" documents = state[\"documents\"]\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" # RAG generation\n",
|
|
|
|
|
" generation = rag_chain.invoke({\"context\": documents, \"question\": question})\n",
|
|
|
|
|
" return {\"documents\": documents, \"question\": question, \"generation\": generation}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def grade_documents(state):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Determines whether the retrieved documents are relevant to the question.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Args:\n",
|
|
|
|
|
" state (dict): The current graph state\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Returns:\n",
|
|
|
|
|
" state (dict): Updates documents key with only filtered relevant documents\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" print(\"---CHECK DOCUMENT RELEVANCE TO QUESTION---\")\n",
|
|
|
|
|
" question = state[\"question\"]\n",
|
|
|
|
|
" documents = state[\"documents\"]\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" # Score each doc\n",
|
|
|
|
|
" filtered_docs = []\n",
|
|
|
|
|
" for d in documents:\n",
|
|
|
|
|
" score = retrieval_grader.invoke(\n",
|
|
|
|
|
" {\"question\": question, \"document\": d.page_content}\n",
|
|
|
|
|
" )\n",
|
|
|
|
|
" grade = score.binary_score\n",
|
|
|
|
|
" if grade == \"yes\":\n",
|
|
|
|
|
" print(\"---GRADE: DOCUMENT RELEVANT---\")\n",
|
|
|
|
|
" filtered_docs.append(d)\n",
|
|
|
|
|
" else:\n",
|
|
|
|
|
" print(\"---GRADE: DOCUMENT NOT RELEVANT---\")\n",
|
|
|
|
|
" continue\n",
|
|
|
|
|
" return {\"documents\": filtered_docs, \"question\": question}\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def transform_query(state):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Transform the query to produce a better question.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Args:\n",
|
|
|
|
|
" state (dict): The current graph state\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Returns:\n",
|
|
|
|
|
" state (dict): Updates question key with a re-phrased question\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" print(\"---TRANSFORM QUERY---\")\n",
|
|
|
|
|
" question = state[\"question\"]\n",
|
|
|
|
|
" documents = state[\"documents\"]\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" # Re-write question\n",
|
|
|
|
|
" better_question = question_rewriter.invoke({\"question\": question})\n",
|
|
|
|
|
" return {\"documents\": documents, \"question\": better_question}"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -371,7 +536,74 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"### Edges\n\n\ndef decide_to_generate(state):\n \"\"\"\n Determines whether to generate an answer, or re-generate a question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n str: Binary decision for next node to call\n \"\"\"\n\n print(\"---ASSESS GRADED DOCUMENTS---\")\n state[\"question\"]\n filtered_documents = state[\"documents\"]\n\n if not filtered_documents:\n # All documents have been filtered check_relevance\n # We will re-generate a new query\n print(\n \"---DECISION: ALL DOCUMENTS ARE NOT RELEVANT TO QUESTION, TRANSFORM QUERY---\"\n )\n return \"transform_query\"\n else:\n # We have relevant documents, so generate answer\n print(\"---DECISION: GENERATE---\")\n return \"generate\"\n\n\ndef grade_generation_v_documents_and_question(state):\n \"\"\"\n Determines whether the generation is grounded in the document and answers question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n str: Decision for next node to call\n \"\"\"\n\n print(\"---CHECK HALLUCINATIONS---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n generation = state[\"generation\"]\n\n score = hallucination_grader.invoke(\n {\"documents\": documents, \"generation\": generation}\n )\n grade = score.binary_score\n\n # Check hallucination\n if grade == \"yes\":\n print(\"---DECISION: GENERATION IS GROUNDED IN DOCUMENTS---\")\n # Check question-answering\n print(\"---GRADE GENERATION vs QUESTION---\")\n score = answer_grader.invoke({\"question\": question, \"generation\": generation})\n grade = score.binary_score\n if grade == \"yes\":\n print(\"---DECISION: GENERATION ADDRESSES QUESTION---\")\n return \"useful\"\n else:\n print(\"---DECISION: GENERATION DOES NOT ADDRESS QUESTION---\")\n return \"not useful\"\n else:\n pprint(\"---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, RE-TRY---\")\n return \"not supported\""
|
|
|
|
|
"### Edges\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def decide_to_generate(state):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Determines whether to generate an answer, or re-generate a question.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Args:\n",
|
|
|
|
|
" state (dict): The current graph state\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Returns:\n",
|
|
|
|
|
" str: Binary decision for next node to call\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" print(\"---ASSESS GRADED DOCUMENTS---\")\n",
|
|
|
|
|
" state[\"question\"]\n",
|
|
|
|
|
" filtered_documents = state[\"documents\"]\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" if not filtered_documents:\n",
|
|
|
|
|
" # All documents have been filtered check_relevance\n",
|
|
|
|
|
" # We will re-generate a new query\n",
|
|
|
|
|
" print(\n",
|
|
|
|
|
" \"---DECISION: ALL DOCUMENTS ARE NOT RELEVANT TO QUESTION, TRANSFORM QUERY---\"\n",
|
|
|
|
|
" )\n",
|
|
|
|
|
" return \"transform_query\"\n",
|
|
|
|
|
" else:\n",
|
|
|
|
|
" # We have relevant documents, so generate answer\n",
|
|
|
|
|
" print(\"---DECISION: GENERATE---\")\n",
|
|
|
|
|
" return \"generate\"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"def grade_generation_v_documents_and_question(state):\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
" Determines whether the generation is grounded in the document and answers question.\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Args:\n",
|
|
|
|
|
" state (dict): The current graph state\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" Returns:\n",
|
|
|
|
|
" str: Decision for next node to call\n",
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" print(\"---CHECK HALLUCINATIONS---\")\n",
|
|
|
|
|
" question = state[\"question\"]\n",
|
|
|
|
|
" documents = state[\"documents\"]\n",
|
|
|
|
|
" generation = state[\"generation\"]\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" score = hallucination_grader.invoke(\n",
|
|
|
|
|
" {\"documents\": documents, \"generation\": generation}\n",
|
|
|
|
|
" )\n",
|
|
|
|
|
" grade = score.binary_score\n",
|
|
|
|
|
"\n",
|
|
|
|
|
" # Check hallucination\n",
|
|
|
|
|
" if grade == \"yes\":\n",
|
|
|
|
|
" print(\"---DECISION: GENERATION IS GROUNDED IN DOCUMENTS---\")\n",
|
|
|
|
|
" # Check question-answering\n",
|
|
|
|
|
" print(\"---GRADE GENERATION vs QUESTION---\")\n",
|
|
|
|
|
" score = answer_grader.invoke({\"question\": question, \"generation\": generation})\n",
|
|
|
|
|
" grade = score.binary_score\n",
|
|
|
|
|
" if grade == \"yes\":\n",
|
|
|
|
|
" print(\"---DECISION: GENERATION ADDRESSES QUESTION---\")\n",
|
|
|
|
|
" return \"useful\"\n",
|
|
|
|
|
" else:\n",
|
|
|
|
|
" print(\"---DECISION: GENERATION DOES NOT ADDRESS QUESTION---\")\n",
|
|
|
|
|
" return \"not useful\"\n",
|
|
|
|
|
" else:\n",
|
|
|
|
|
" pprint(\"---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, RE-TRY---\")\n",
|
|
|
|
|
" return \"not supported\""
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -390,7 +622,42 @@
|
|
|
|
|
"id": "0e09ca9f-e36d-4ef4-a0d5-79fdbada9fe0",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": ["from langgraph.graph import END, StateGraph, START\n\nworkflow = StateGraph(GraphState)\n\n# Define the nodes\nworkflow.add_node(\"retrieve\", retrieve) # retrieve\nworkflow.add_node(\"grade_documents\", grade_documents) # grade documents\nworkflow.add_node(\"generate\", generate) # generate\nworkflow.add_node(\"transform_query\", transform_query) # transform_query\n\n# Build graph\nworkflow.add_edge(START, \"retrieve\")\nworkflow.add_edge(\"retrieve\", \"grade_documents\")\nworkflow.add_conditional_edges(\n \"grade_documents\",\n decide_to_generate,\n {\n \"transform_query\": \"transform_query\",\n \"generate\": \"generate\",\n },\n)\nworkflow.add_edge(\"transform_query\", \"retrieve\")\nworkflow.add_conditional_edges(\n \"generate\",\n grade_generation_v_documents_and_question,\n {\n \"not supported\": \"generate\",\n \"useful\": END,\n \"not useful\": \"transform_query\",\n },\n)\n\n# Compile\napp = workflow.compile()"]
|
|
|
|
|
"source": [
|
|
|
|
|
"from langgraph.graph import END, StateGraph, START\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"workflow = StateGraph(GraphState)\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Define the nodes\n",
|
|
|
|
|
"workflow.add_node(\"retrieve\", retrieve) # retrieve\n",
|
|
|
|
|
"workflow.add_node(\"grade_documents\", grade_documents) # grade documents\n",
|
|
|
|
|
"workflow.add_node(\"generate\", generate) # generate\n",
|
|
|
|
|
"workflow.add_node(\"transform_query\", transform_query) # transform_query\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Build graph\n",
|
|
|
|
|
"workflow.add_edge(START, \"retrieve\")\n",
|
|
|
|
|
"workflow.add_edge(\"retrieve\", \"grade_documents\")\n",
|
|
|
|
|
"workflow.add_conditional_edges(\n",
|
|
|
|
|
" \"grade_documents\",\n",
|
|
|
|
|
" decide_to_generate,\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" \"transform_query\": \"transform_query\",\n",
|
|
|
|
|
" \"generate\": \"generate\",\n",
|
|
|
|
|
" },\n",
|
|
|
|
|
")\n",
|
|
|
|
|
"workflow.add_edge(\"transform_query\", \"retrieve\")\n",
|
|
|
|
|
"workflow.add_conditional_edges(\n",
|
|
|
|
|
" \"generate\",\n",
|
|
|
|
|
" grade_generation_v_documents_and_question,\n",
|
|
|
|
|
" {\n",
|
|
|
|
|
" \"not supported\": \"generate\",\n",
|
|
|
|
|
" \"useful\": END,\n",
|
|
|
|
|
" \"not useful\": \"transform_query\",\n",
|
|
|
|
|
" },\n",
|
|
|
|
|
")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Compile\n",
|
|
|
|
|
"app = workflow.compile()"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"cell_type": "code",
|
|
|
|
@@ -426,7 +693,18 @@
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"source": [
|
|
|
|
|
"from pprint import pprint\n\n# Run\ninputs = {\"question\": \"Movies that star Daniel Craig\"}\nfor output in app.stream(inputs):\n for key, value in output.items():\n # Node\n pprint(f\"Node '{key}':\")\n pprint(\"\\n---\\n\")\n\n# Final generation\npprint(value[\"generation\"])"
|
|
|
|
|
"from pprint import pprint\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Run\n",
|
|
|
|
|
"inputs = {\"question\": \"Movies that star Daniel Craig\"}\n",
|
|
|
|
|
"for output in app.stream(inputs):\n",
|
|
|
|
|
" for key, value in output.items():\n",
|
|
|
|
|
" # Node\n",
|
|
|
|
|
" pprint(f\"Node '{key}':\")\n",
|
|
|
|
|
" pprint(\"\\n---\\n\")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Final generation\n",
|
|
|
|
|
"pprint(value[\"generation\"])"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -436,7 +714,15 @@
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
"inputs = {\"question\": \"Which movies are about aliens?\"}\nfor output in app.stream(inputs):\n for key, value in output.items():\n # Node\n pprint(f\"Node '{key}':\")\n pprint(\"\\n---\\n\")\n\n# Final generation\npprint(value[\"generation\"])"
|
|
|
|
|
"inputs = {\"question\": \"Which movies are about aliens?\"}\n",
|
|
|
|
|
"for output in app.stream(inputs):\n",
|
|
|
|
|
" for key, value in output.items():\n",
|
|
|
|
|
" # Node\n",
|
|
|
|
|
" pprint(f\"Node '{key}':\")\n",
|
|
|
|
|
" pprint(\"\\n---\\n\")\n",
|
|
|
|
|
"\n",
|
|
|
|
|
"# Final generation\n",
|
|
|
|
|
"pprint(value[\"generation\"])"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@@ -445,9 +731,7 @@
|
|
|
|
|
"id": "42369ab8-322d-434a-b5dd-2266e4cb2903",
|
|
|
|
|
"metadata": {},
|
|
|
|
|
"outputs": [],
|
|
|
|
|
"source": [
|
|
|
|
|
""
|
|
|
|
|
]
|
|
|
|
|
"source": []
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"metadata": {
|
|
|
|
|