diff --git a/examples/code_assistant/lcel-teacher-langgraph.ipynb b/examples/code_assistant/langgraph_code_assistant.ipynb similarity index 99% rename from examples/code_assistant/lcel-teacher-langgraph.ipynb rename to examples/code_assistant/langgraph_code_assistant.ipynb index bda21f2d8..d9ee03375 100644 --- a/examples/code_assistant/lcel-teacher-langgraph.ipynb +++ b/examples/code_assistant/langgraph_code_assistant.ipynb @@ -37,7 +37,7 @@ "\n", "--- \n", "\n", - "## LangGraph for code generation\n", + "## LangGraph self-corrective code assistant\n", "\n", "We wanted to test these the general idea of iterative code generation in LangGraph, making a few simplifications relative to the AlphaCodium work:\n", "\n", @@ -112,7 +112,7 @@ "source": [ "## State \n", "\n", - "Our state is simple a dict that will contain doc (above), as well as other values (any errors, our question) relevant to code generation." + "Our state is a dict that will contain keys (errors, question, code generation) relevant to code generation." ] }, { @@ -150,20 +150,16 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 5, "id": "b70e8301-63ae-4f7e-ad8f-c9a052fe3566", "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", @@ -199,7 +195,7 @@ " \n", " # LLM with tool and enforce invocation\n", " llm_with_tool = model.bind(\n", - " tools=[convert_to_openai_tool(code_tool_oai)],\n", + " tools=[code_tool_oai],\n", " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"code\"}},\n", " )\n", " \n", @@ -425,7 +421,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "f66b4e00-4731-42c8-bc38-72dd0ff7c92c", "metadata": {}, "outputs": [], @@ -472,7 +468,10 @@ "\n", "[Here](https://smith.langchain.com/public/ea1f6ca5-de52-4d36-bd7b-fde3faa74a70/d) is a public dataset of LCEL questions. \n", " \n", - "Let's create a LangSmith evaluator [here](https://docs.smith.langchain.com/evaluation/faq/custom-evaluators) to test each." + "Let's create a custom LangSmith evaluator [here](https://docs.smith.langchain.com/evaluation/faq/custom-evaluators) to test them with:\n", + "\n", + "* Base case: context stuffing chain without LangGraph\n", + "* Our self-corrective coding assistant" ] }, { @@ -480,7 +479,9 @@ "id": "86411645-98f8-4d19-889f-c78f3c026380", "metadata": {}, "source": [ - "### Base Case RAG" + "### Base Case\n", + "\n", + "Here is context stuffing without LangGraph." ] }, { @@ -531,7 +532,7 @@ "def parse_answer_to_dict(x):\n", " return x[0].dict()\n", "\n", - "chain_base_rag = (\n", + "chain_base_case = (\n", " {\n", " \"context\": lambda x: concatenated_content,\n", " \"question\": RunnablePassthrough(),\n", @@ -550,7 +551,7 @@ "metadata": {}, "outputs": [], "source": [ - "answer = chain_base_rag.invoke(\"How can I write a RAG chain?\")" + "answer = chain_base_case.invoke(\"How can I write a RAG chain?\")" ] }, { @@ -621,7 +622,7 @@ "project_name = \"context-stuffing-no-langgraph\"\n", "client.run_on_dataset(\n", " dataset_name=\"lcel-teacher-eval\",\n", - " llm_or_chain_factory= lambda: (lambda x: x[\"question\"]) | chain_base_rag,\n", + " llm_or_chain_factory= lambda: (lambda x: x[\"question\"]) | chain_base_case,\n", " evaluation=evaluation_config,\n", " project_name=f\"{run_id}-{project_name}\",\n", ")" @@ -675,7 +676,6 @@ "\n", "config = {\"recursion_limit\": 50}\n", "def model(input):\n", - " # return app.invoke({\"keys\":{**input, \"docs\": concatenated_content, \"iterations\":0}},config=config)\n", " return app.invoke({\"keys\":{**input, \"iterations\":0}},config=config)\n", "\n", "run_id = uuid.uuid4().hex[:4]\n", diff --git a/examples/code_assistant/langgraph_code_gen.ipynb b/examples/code_assistant/langgraph_code_gen.ipynb new file mode 100644 index 000000000..4d1b7875b --- /dev/null +++ b/examples/code_assistant/langgraph_code_gen.ipynb @@ -0,0 +1,624 @@ +{ + "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 +} diff --git a/examples/rag/langgraph_crag.ipynb b/examples/rag/langgraph_crag.ipynb index a9f583384..921fc1152 100644 --- a/examples/rag/langgraph_crag.ipynb +++ b/examples/rag/langgraph_crag.ipynb @@ -72,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "id": "3a566a30-cf0e-4330-ad4d-9bf994bdfa86", "metadata": {}, "outputs": [], @@ -121,7 +121,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "id": "94b3945f-ef0f-458d-a443-f763903550b0", "metadata": {}, "outputs": [], @@ -172,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 3, "id": "efd639c5-82e2-45e6-a94a-6a4039646ef5", "metadata": {}, "outputs": [], @@ -279,7 +279,7 @@ "\n", " # LLM with tool and enforce invocation\n", " llm_with_tool = model.bind(\n", - " tools=[convert_to_openai_tool(grade_tool_oai)],\n", + " tools=[grade_tool_oai],\n", " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"grade\"}},\n", " )\n", "\n", @@ -428,7 +428,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 4, "id": "dedae17a-98c6-474d-90a7-9234b7c8cea0", "metadata": {}, "outputs": [], @@ -467,7 +467,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 5, "id": "f5b7c2fe-1fc7-4b76-bf93-ba701a40aa6b", "metadata": {}, "outputs": [ @@ -492,13 +492,10 @@ "'\\n---\\n'\n", "\"Node '__end__':\"\n", "'\\n---\\n'\n", - "('There are several types of memory in human brains, including sensory memory, '\n", - " 'which retains impressions of sensory information for a few seconds after the '\n", - " 'original stimuli have ended. Short-term memory is utilized for in-context '\n", - " 'learning, while long-term memory allows the agent to retain and recall '\n", - " 'information over extended periods by leveraging an external vector store and '\n", - " 'fast retrieval. Additionally, agents can use tool use to call external APIs '\n", - " 'for extra information that is missing from the model weights.')\n" + "('Short-term memory stores information needed for complex cognitive tasks and '\n", + " 'lasts for 20-30 seconds. Long-term memory can store information for a long '\n", + " 'time and has explicit and implicit subtypes. Sensory memory retains sensory '\n", + " 'impressions briefly after stimuli end.')\n" ] } ], diff --git a/examples/rag/langgraph_self_rag.ipynb b/examples/rag/langgraph_self_rag.ipynb index 6d154243b..661eb3979 100644 --- a/examples/rag/langgraph_self_rag.ipynb +++ b/examples/rag/langgraph_self_rag.ipynb @@ -88,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 7, "id": "565a6d44-2c9f-4fff-b1ec-eea05df9350d", "metadata": {}, "outputs": [], @@ -183,7 +183,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "add509d8-6682-4127-8d95-13dd37d79702", "metadata": {}, "outputs": [], @@ -223,7 +223,7 @@ " return {\"keys\": {\"documents\": documents, \"question\": question}}\n", "\n", "\n", - "def generate(state):a\n", + "def generate(state):\n", " \"\"\"\n", " Generate answer\n", "\n", @@ -288,7 +288,7 @@ "\n", " # LLM with tool and enforce invocation\n", " llm_with_tool = model.bind(\n", - " tools=[convert_to_openai_tool(grade_tool_oai)],\n", + " tools=[grade_tool_oai],\n", " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"grade\"}},\n", " )\n", "\n", @@ -444,7 +444,7 @@ "\n", " # LLM with tool and enforce invocation\n", " llm_with_tool = model.bind(\n", - " tools=[convert_to_openai_tool(grade_tool_oai)],\n", + " tools=[grade_tool_oai],\n", " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"grade\"}},\n", " )\n", "\n", @@ -508,7 +508,7 @@ "\n", " # LLM with tool and enforce invocation\n", " llm_with_tool = model.bind(\n", - " tools=[convert_to_openai_tool(grade_tool_oai)],\n", + " tools=[grade_tool_oai],\n", " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"grade\"}},\n", " )\n", "\n", @@ -553,7 +553,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "id": "0e09ca9f-e36d-4ef4-a0d5-79fdbada9fe0", "metadata": {}, "outputs": [], @@ -606,7 +606,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "id": "fb69dbb9-91ee-4868-8c3c-93af3cd885be", "metadata": {}, "outputs": [ @@ -638,12 +638,12 @@ "---DECISION: USEFUL---\n", "\"Node '__end__':\"\n", "'\\n---\\n'\n", - "('Short-term memory is the stage of memory that stores information that we are '\n", - " 'currently aware of and needed to carry out complex cognitive tasks. It has a '\n", - " 'limited capacity and lasts for a short duration. Long-term memory, on the '\n", - " 'other hand, can store information for a long time and has unlimited storage '\n", - " 'capacity. It includes explicit/declarative memory for facts and events, and '\n", - " 'implicit/procedural memory for unconscious skills and routines.')\n" + "('Short-term memory stores information needed for immediate cognitive tasks '\n", + " 'and lasts for about 20-30 seconds. Long-term memory can retain information '\n", + " 'for extended periods, with subtypes including explicit (facts and events) '\n", + " 'and implicit (skills and routines) memory. Sensory memory retains sensory '\n", + " 'impressions briefly after stimuli end, while long-term memory stores '\n", + " 'information for a long time.')\n" ] } ], @@ -664,7 +664,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "id": "4138bc51-8c84-4b8a-8d24-f7f470721f6f", "metadata": {}, "outputs": [ @@ -696,13 +696,12 @@ "---DECISION: USEFUL---\n", "\"Node '__end__':\"\n", "'\\n---\\n'\n", - "('Chain of thought prompting involves guiding the behavior of autoregressive '\n", - " 'language models by providing prompts or demonstrations that contain '\n", - " 'high-quality reasoning chains. This can be done through methods such as '\n", - " 'self-asking, interleaving retrieval with chain-of-thought reasoning, and '\n", - " 'complexity-based prompting for multi-step reasoning. These techniques aim to '\n", - " \"improve the model's ability to generate coherent and logical responses \"\n", - " 'without updating its weights.')\n" + "('Chain of thought prompting works by providing a series of prompts or '\n", + " 'demonstrations to guide the model through a reasoning process. This method '\n", + " 'involves iteratively constructing thought processes by asking follow-up '\n", + " 'questions or exploring multiple reasoning possibilities at each step. '\n", + " 'External search queries and relevant content from sources like Wikipedia can '\n", + " \"be integrated into the context to enhance the model's understanding.\")\n" ] } ],