From 7c64f82425e6db07b23c76e2bce13f0a8f37cb3a Mon Sep 17 00:00:00 2001 From: Lance Martin Date: Fri, 23 Feb 2024 16:37:35 -0800 Subject: [PATCH] Remove version used in video --- .../code_assistant/langgraph_code_gen.ipynb | 624 ------------------ 1 file changed, 624 deletions(-) delete mode 100644 examples/code_assistant/langgraph_code_gen.ipynb diff --git a/examples/code_assistant/langgraph_code_gen.ipynb b/examples/code_assistant/langgraph_code_gen.ipynb deleted file mode 100644 index 4d1b7875b..000000000 --- a/examples/code_assistant/langgraph_code_gen.ipynb +++ /dev/null @@ -1,624 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "54abe00a-0132-493a-bee0-5dcb3044c412", - "metadata": {}, - "outputs": [], - "source": [ - "! pip install langchain_community tiktoken langchain-openai langchainhub chromadb langchain langgraph faiss-cpu" - ] - }, - { - "cell_type": "markdown", - "id": "c02e806b-5169-4572-b007-3302df9801e0", - "metadata": {}, - "source": [ - "Optionally, use [LangSmith](https://docs.smith.langchain.com/) for tracing: \n", - "\n", - "```\n", - "export LANGCHAIN_TRACING_V2=true\n", - "export LANGCHAIN_ENDPOINT=https://api.smith.langchain.com\n", - "export LANGCHAIN_API_KEY=\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "15bb14a1-4640-461d-9385-401ce346da75", - "metadata": {}, - "source": [ - "## Docs" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "e471e650-97c2-4524-82c4-9bffaa8e6447", - "metadata": {}, - "outputs": [], - "source": [ - "from bs4 import BeautifulSoup as Soup\n", - "from langchain_community.document_loaders.recursive_url_loader import RecursiveUrlLoader\n", - "\n", - "# LCEL docs \n", - "url = \"https://python.langchain.com/docs/expression_language/\"\n", - "loader = RecursiveUrlLoader(\n", - " url=url, max_depth=20, extractor=lambda x: Soup(x, \"html.parser\").text\n", - ")\n", - "docs = loader.load()\n", - "\n", - "# Sort the list based on the URLs in 'metadata' -> 'source'\n", - "d_sorted = sorted(docs, key=lambda x: x.metadata[\"source\"])\n", - "d_reversed = list(reversed(d_sorted))\n", - "\n", - "# Concatenate the 'page_content' of each sorted dictionary\n", - "concatenated_content = \"\\n\\n\\n --- \\n\\n\\n\".join(\n", - " [doc.page_content for doc in d_reversed]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "5ccf1981-54b6-4667-b56e-a43dbfec35c7", - "metadata": {}, - "source": [ - "## Tool Use" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "133889df-277a-4641-93cb-5dafa942b47a", - "metadata": {}, - "outputs": [], - "source": [ - "from operator import itemgetter\n", - "from langchain_openai import ChatOpenAI\n", - "from langchain.prompts import PromptTemplate\n", - "from langchain_core.pydantic_v1 import BaseModel, Field\n", - "from langchain.output_parsers.openai_tools import PydanticToolsParser\n", - "from langchain_core.utils.function_calling import convert_to_openai_tool\n", - " \n", - "## Data model\n", - "class code(BaseModel):\n", - " \"\"\"Code output\"\"\"\n", - " prefix: str = Field(description=\"Description of the problem and approach\")\n", - " imports: str = Field(description=\"Code block import statements\")\n", - " code: str = Field(description=\"Code block not including import statements\")\n", - "\n", - "## LLM\n", - "model = ChatOpenAI(temperature=0, model=\"gpt-4-0125-preview\", streaming=True)\n", - "\n", - "# Tool\n", - "code_tool_oai = convert_to_openai_tool(code)\n", - "\n", - "# LLM with tool and enforce invocation\n", - "llm_with_tool = model.bind(\n", - " tools=[code_tool_oai],\n", - " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"code\"}},\n", - ")\n", - "\n", - "# Parser\n", - "parser_tool = PydanticToolsParser(tools=[code])\n", - "\n", - "## Prompt\n", - "template = \"\"\"You are a coding assistant with expertise in LCEL, LangChain expression language. \\n \n", - " Here is a full set of LCEL documentation: \n", - " \\n ------- \\n\n", - " {context} \n", - " \\n ------- \\n\n", - " Answer the user question based on the above provided documentation. \\n\n", - " Ensure any code you provide can be executed with all required imports and variables defined. \\n\n", - " Structure your answer with a description of the code solution. \\n\n", - " Then list the imports. And finally list the functioning code block. \\n\n", - " Here is the user question: \\n --- --- --- \\n {question}\"\"\"\n", - "\n", - "# Prompt \n", - "prompt = PromptTemplate(\n", - " template=template,\n", - " input_variables=[\"context\", \"question\"],\n", - ")\n", - "\n", - "# Chain\n", - "chain = (\n", - " {\n", - " # \"context\": lambda x: docs,\n", - " \"context\": lambda x: concatenated_content,\n", - " \"question\": itemgetter(\"question\"),\n", - " }\n", - " | prompt\n", - " | llm_with_tool \n", - " | parser_tool\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "450cfac7-8a2a-43ed-a431-b38fb4d0de66", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[code(prefix=\"To create a Retrieval-Augmented Generation (RAG) chain in LangChain Expression Language (LCEL), you need to follow a structured approach. This involves setting up a retriever to fetch relevant documents based on the user's query, and then using those documents to generate a response with a language model. Here's a step-by-step guide to creating a RAG chain in LCEL:\\n\\n\", imports='from operator import itemgetter\\nfrom langchain_community.vectorstores import FAISS\\nfrom langchain_core.output_parsers import StrOutputParser\\nfrom langchain_core.prompts import ChatPromptTemplate\\nfrom langchain_core.runnables import RunnablePassthrough\\nfrom langchain_openai import ChatOpenAI, OpenAIEmbeddings', code='# Initialize the vector store with sample texts and embeddings\\nvectorstore = FAISS.from_texts(\\n [\"harrison worked at kensho\"], embedding=OpenAIEmbeddings())\\n\\n# Create a retriever from the vector store\\nretriever = vectorstore.as_retriever()\\n\\n# Define the prompt template\\ntemplate = \"\"\"Answer the question based only on the following context:{context}Question: {question}\"\"\"\\nprompt = ChatPromptTemplate.from_template(template)\\n\\n# Initialize the model\\nmodel = ChatOpenAI()\\n\\n# Create the RAG chain\\nchain = (\\n {\"context\": retriever, \"question\": RunnablePassthrough()} | prompt | model | StrOutputParser()\\n)\\n\\n# Invoke the chain with a query\\nresponse = chain.invoke(\"where did harrison work?\")\\nprint(response)')]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chain.invoke({\"question\":\"How to create a RAG chain in LCEL?\"})" - ] - }, - { - "cell_type": "markdown", - "id": "32a6686d-48d9-4b4c-becf-0d496384eed9", - "metadata": {}, - "source": [ - "## State" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "95be35d1-b90c-4559-a6bf-2cd79e68ae4a", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Dict, TypedDict\n", - "\n", - "from langchain_core.messages import BaseMessage\n", - "\n", - "\n", - "class GraphState(TypedDict):\n", - " \"\"\"\n", - " Represents the state of our graph.\n", - "\n", - " Attributes:\n", - " keys: A dictionary where each key is a string.\n", - " \"\"\"\n", - "\n", - " keys: Dict[str, any]" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "396bee5b-9cc3-44d2-bc6a-955af0e0a847", - "metadata": {}, - "outputs": [], - "source": [ - "from operator import itemgetter\n", - "from bs4 import BeautifulSoup as Soup\n", - "from langchain_community.document_loaders.recursive_url_loader import RecursiveUrlLoader\n", - "from langchain_openai import ChatOpenAI\n", - "from langchain.prompts import PromptTemplate\n", - "from langchain_core.output_parsers import StrOutputParser\n", - "from langchain_core.runnables import RunnablePassthrough\n", - "from langchain_core.pydantic_v1 import BaseModel, Field\n", - "from langchain.output_parsers import PydanticOutputParser\n", - "from langchain.output_parsers.openai_tools import PydanticToolsParser\n", - "from langchain_core.utils.function_calling import convert_to_openai_tool\n", - "\n", - "def generate(state):\n", - " \"\"\"\n", - " Generate a code solution based on LCEL docs and the input question \n", - " with optional feedback from code execution tests \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", - " \n", - " ## State\n", - " state_dict = state[\"keys\"]\n", - " question = state_dict[\"question\"]\n", - " iter = state_dict[\"iterations\"]\n", - " \n", - " ## Data model\n", - " class code(BaseModel):\n", - " \"\"\"Code output\"\"\"\n", - " prefix: str = Field(description=\"Description of the problem and approach\")\n", - " imports: str = Field(description=\"Code block import statements\")\n", - " code: str = Field(description=\"Code block not including import statements\")\n", - " \n", - " ## LLM\n", - " model = ChatOpenAI(temperature=0, model=\"gpt-4-0125-preview\", streaming=True)\n", - " \n", - " # Tool\n", - " code_tool_oai = convert_to_openai_tool(code)\n", - " \n", - " # LLM with tool and enforce invocation\n", - " llm_with_tool = model.bind(\n", - " tools=[convert_to_openai_tool(code_tool_oai)],\n", - " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"code\"}},\n", - " )\n", - " \n", - " # Parser\n", - " parser_tool = PydanticToolsParser(tools=[code])\n", - " \n", - " ## Prompt\n", - " template = \"\"\"You are a coding assistant with expertise in LCEL, LangChain expression language. \\n \n", - " Here is a full set of LCEL documentation: \n", - " \\n ------- \\n\n", - " {context} \n", - " \\n ------- \\n\n", - " Answer the user question based on the above provided documentation. \\n\n", - " Ensure any code you provide can be executed with all required imports and variables defined. \\n\n", - " Structure your answer with a description of the code solution. \\n\n", - " Then list the imports. And finally list the functioning code block. \\n\n", - " Here is the user question: \\n --- --- --- \\n {question}\"\"\"\n", - "\n", - " ## Generation\n", - " if \"error\" in state_dict:\n", - " print(\"---RE-GENERATE SOLUTION w/ ERROR FEEDBACK---\")\n", - " \n", - " error = state_dict[\"error\"]\n", - " code_solution = state_dict[\"generation\"]\n", - " \n", - " # Udpate prompt \n", - " addendum = \"\"\" \\n --- --- --- \\n You previously tried to solve this problem. \\n Here is your solution: \n", - " \\n --- --- --- \\n {generation} \\n --- --- --- \\n Here is the resulting error from code \n", - " execution: \\n --- --- --- \\n {error} \\n --- --- --- \\n Please re-try to answer this. \n", - " Structure your answer with a description of the code solution. \\n Then list the imports. \n", - " And finally list the functioning code block. Structure your answer with a description of \n", - " the code solution. \\n Then list the imports. And finally list the functioning code block. \n", - " \\n Here is the user question: \\n --- --- --- \\n {question}\"\"\"\n", - " template = template + addendum\n", - "\n", - " # Prompt \n", - " prompt = PromptTemplate(\n", - " template=template,\n", - " input_variables=[\"context\", \"question\", \"generation\", \"error\"],\n", - " )\n", - " \n", - " # Chain\n", - " chain = (\n", - " {\n", - " \"context\": lambda x: concatenated_content,\n", - " \"question\": itemgetter(\"question\"),\n", - " \"generation\": itemgetter(\"generation\"),\n", - " \"error\": itemgetter(\"error\"),\n", - " }\n", - " | prompt\n", - " | llm_with_tool \n", - " | parser_tool\n", - " )\n", - "\n", - " code_solution = chain.invoke({\"question\":question,\n", - " \"generation\":str(code_solution[0]),\n", - " \"error\":error})\n", - " \n", - " else:\n", - " print(\"---GENERATE SOLUTION---\")\n", - " \n", - " # Prompt \n", - " prompt = PromptTemplate(\n", - " template=template,\n", - " input_variables=[\"context\", \"question\"],\n", - " )\n", - "\n", - " # Chain\n", - " chain = (\n", - " {\n", - " # \"context\": lambda x: docs,\n", - " \"context\": lambda x: concatenated_content,\n", - " \"question\": itemgetter(\"question\"),\n", - " }\n", - " | prompt\n", - " | llm_with_tool \n", - " | parser_tool\n", - " )\n", - "\n", - " code_solution = chain.invoke({\"question\":question})\n", - "\n", - " iter = iter+1 \n", - " return {\"keys\": {\"generation\": code_solution, \"question\": question, \"iterations\": iter}}\n", - "\n", - "def check_code_imports(state):\n", - " \"\"\"\n", - " Check imports\n", - "\n", - " Args:\n", - " state (dict): The current graph state\n", - "\n", - " Returns:\n", - " state (dict): New key added to state, error\n", - " \"\"\"\n", - " \n", - " ## State\n", - " print(\"---CHECKING CODE IMPORTS---\")\n", - " state_dict = state[\"keys\"]\n", - " question = state_dict[\"question\"]\n", - " code_solution = state_dict[\"generation\"]\n", - " imports = code_solution[0].imports\n", - " iter = state_dict[\"iterations\"]\n", - "\n", - " try: \n", - " # Attempt to execute the imports\n", - " exec(imports)\n", - " except Exception as e:\n", - " print(\"---CODE IMPORT CHECK: FAILED---\")\n", - " # Catch any error during execution (e.g., ImportError, SyntaxError)\n", - " error = f\"Execution error: {e}\"\n", - " if \"error\" in state_dict:\n", - " error_prev_runs = state_dict[\"error\"]\n", - " error = error_prev_runs + \"\\n --- Most recent run error --- \\n\" + error \n", - " else:\n", - " print(\"---CODE IMPORT CHECK: SUCCESS---\")\n", - " # No errors occurred\n", - " error = \"None\"\n", - "\n", - " return {\"keys\": {\"generation\": code_solution, \"question\": question, \"error\": error, \"iterations\":iter}}\n", - "\n", - "def check_code_execution(state):\n", - " \"\"\"\n", - " Check code block execution\n", - "\n", - " Args:\n", - " state (dict): The current graph state\n", - "\n", - " Returns:\n", - " state (dict): New key added to state, error\n", - " \"\"\"\n", - " \n", - " ## State\n", - " print(\"---CHECKING CODE EXECUTION---\")\n", - " state_dict = state[\"keys\"]\n", - " question = state_dict[\"question\"]\n", - " code_solution = state_dict[\"generation\"]\n", - " prefix = code_solution[0].prefix\n", - " imports = code_solution[0].imports\n", - " code = code_solution[0].code\n", - " code_block = imports +\"\\n\"+ code\n", - " iter = state_dict[\"iterations\"]\n", - "\n", - " try: \n", - " # Attempt to execute the code block\n", - " exec(code_block)\n", - " except Exception as e:\n", - " print(\"---CODE BLOCK CHECK: FAILED---\")\n", - " # Catch any error during execution (e.g., ImportError, SyntaxError)\n", - " error = f\"Execution error: {e}\"\n", - " if \"error\" in state_dict:\n", - " error_prev_runs = state_dict[\"error\"]\n", - " error = error_prev_runs + \"\\n --- Most recent run error --- \\n\" + error \n", - " else:\n", - " print(\"---CODE BLOCK CHECK: SUCCESS---\")\n", - " # No errors occurred\n", - " error = \"None\"\n", - "\n", - " return {\"keys\": {\"generation\": code_solution, \n", - " \"question\": question, \n", - " \"error\": error, \n", - " \"prefix\":prefix,\n", - " \"imports\":imports,\n", - " \"iterations\":iter,\n", - " \"code\":code}}\n", - "\n", - "### Edges\n", - "\n", - "def decide_to_check_code_exec(state):\n", - " \"\"\"\n", - " Determines whether to test code execution, or re-try answer generation.\n", - "\n", - " Args:\n", - " state (dict): The current graph state\n", - "\n", - " Returns:\n", - " str: Next node to call\n", - " \"\"\"\n", - "\n", - " print(\"---DECIDE TO TEST CODE EXECUTION---\")\n", - " state_dict = state[\"keys\"]\n", - " question = state_dict[\"question\"]\n", - " code_solution = state_dict[\"generation\"]\n", - " error = state_dict[\"error\"]\n", - "\n", - " if error == \"None\":\n", - " # All documents have been filtered check_relevance\n", - " # We will re-generate a new query\n", - " print(\"---DECISION: TEST CODE EXECUTION---\")\n", - " return \"check_code_execution\"\n", - " else:\n", - " # We have relevant documents, so generate answer\n", - " print(\"---DECISION: RE-TRY SOLUTION---\")\n", - " return \"generate\"\n", - "\n", - "def decide_to_finish(state):\n", - " \"\"\"\n", - " Determines whether to finish (re-try code 3 times.\n", - "\n", - " Args:\n", - " state (dict): The current graph state\n", - "\n", - " Returns:\n", - " str: Next node to call\n", - " \"\"\"\n", - "\n", - " print(\"---DECIDE TO TEST CODE EXECUTION---\")\n", - " state_dict = state[\"keys\"]\n", - " question = state_dict[\"question\"]\n", - " code_solution = state_dict[\"generation\"]\n", - " error = state_dict[\"error\"]\n", - " iter = state_dict[\"iterations\"]\n", - "\n", - " if error == \"None\" or iter == 3:\n", - " # All documents have been filtered check_relevance\n", - " # We will re-generate a new query\n", - " print(\"---DECISION: TEST CODE EXECUTION---\")\n", - " return \"end\"\n", - " else:\n", - " # We have relevant documents, so generate answer\n", - " print(\"---DECISION: RE-TRY SOLUTION---\")\n", - " return \"generate\"" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "1e19e44d-1628-41ea-8d45-51ea3ebd3c00", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import END, StateGraph\n", - "\n", - "workflow = StateGraph(GraphState)\n", - "\n", - "# Define the nodes\n", - "workflow.add_node(\"generate\", generate) # generation solution\n", - "workflow.add_node(\"check_code_imports\", check_code_imports) # check imports\n", - "workflow.add_node(\"check_code_execution\", check_code_execution) # check execution\n", - "\n", - "# Build graph\n", - "workflow.set_entry_point(\"generate\")\n", - "workflow.add_edge(\"generate\", \"check_code_imports\")\n", - "workflow.add_conditional_edges(\n", - " \"check_code_imports\",\n", - " decide_to_check_code_exec,\n", - " {\n", - " \"check_code_execution\": \"check_code_execution\",\n", - " \"generate\": \"generate\",\n", - " },\n", - ")\n", - "workflow.add_conditional_edges(\n", - " \"check_code_execution\",\n", - " decide_to_finish,\n", - " {\n", - " \"end\": END,\n", - " \"generate\": \"generate\",\n", - " },\n", - ")\n", - "\n", - "# Compile\n", - "app = workflow.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "8cf3924b-3121-4c52-8264-338ef2a82e14", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "---GENERATE SOLUTION---\n", - "---CHECKING CODE IMPORTS---\n", - "---CODE IMPORT CHECK: SUCCESS---\n", - "---DECIDE TO TEST CODE EXECUTION---\n", - "---DECISION: TEST CODE EXECUTION---\n", - "---CHECKING CODE EXECUTION---\n", - "---CODE BLOCK CHECK: FAILED---\n", - "---DECIDE TO TEST CODE EXECUTION---\n", - "---DECISION: RE-TRY SOLUTION---\n", - "---RE-GENERATE SOLUTION w/ ERROR FEEDBACK---\n", - "---CHECKING CODE IMPORTS---\n", - "---CODE IMPORT CHECK: SUCCESS---\n", - "---DECIDE TO TEST CODE EXECUTION---\n", - "---DECISION: TEST CODE EXECUTION---\n", - "---CHECKING CODE EXECUTION---\n", - "Why did the bear break up with his girlfriend?\n", - "Because he couldn't bear the relationship anymore!\n", - "---CODE BLOCK CHECK: SUCCESS---\n", - "---DECIDE TO TEST CODE EXECUTION---\n", - "---DECISION: TEST CODE EXECUTION---\n" - ] - } - ], - "source": [ - "question = \"I am passing text key 'foo' to my prompt and want to process it with a function, process_text(...), prior to the prompt. How can I do this using LCEL?\"\n", - "config = {\"recursion_limit\": 50}\n", - "answer = app.invoke({\"keys\":{\"question\":question, \"iterations\":0}},config=config)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "eb8999e8-fa58-45b9-9506-3eb7ce32f0a0", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"To process a text key 'foo' with a function before passing it to a prompt using LCEL, you can use a RunnableLambda. This allows you to define a custom function that processes the input text and then passes the modified text to the prompt. Here's how you can do it:\"" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "answer['keys']['generation'][0].prefix" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "486205af-0e59-4b74-94eb-518cfc55b01f", - "metadata": {}, - "outputs": [], - "source": [ - "exec(answer['keys']['generation'][0].imports)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "216c3c91-1954-4ee4-bc7c-e78a0ea655d5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Why did the bear break up with his girlfriend? \n", - "\n", - "Because he couldn't bear the relationship any longer!\n" - ] - } - ], - "source": [ - "exec(answer['keys']['generation'][0].code)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fc107f0-eecc-46f9-88d2-15c568537dfb", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.16" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -}