diff --git a/lab-agent-vector-store.ipynb b/lab-agent-vector-store.ipynb index 263cef6..77d80d9 100644 --- a/lab-agent-vector-store.ipynb +++ b/lab-agent-vector-store.ipynb @@ -66,7 +66,7 @@ }, "outputs": [], "source": [ - "# !pip install \"langchain<0.3\" \"langchain-core<0.3\" \"langchain-community<0.3\" \"langchain-openai<0.2\"" + "!pip install \"langchain<0.3\" \"langchain-core<0.3\" \"langchain-community<0.3\" \"langchain-openai<0.2\"" ] }, { @@ -76,7 +76,7 @@ "metadata": {}, "outputs": [], "source": [ - "# !pip install python-dotenv==1.2.2 chromadb==1.5.9 beautifulsoup4==4.15.0" + "!pip install python-dotenv==1.2.2 chromadb==1.5.9 beautifulsoup4==4.15.0" ] }, { @@ -93,14 +93,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "2868cff1-a3ef-426f-b8d7-7fe89047a5b7", "metadata": { "tags": [] }, "outputs": [], "source": [ - "from langchain.chains import RetrievalQA\n", "from langchain_community.vectorstores import Chroma\n", "from langchain_openai import OpenAI, OpenAIEmbeddings\n", "from langchain_text_splitters import CharacterTextSplitter\n", @@ -109,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "aeff3a2d-b0cc-429f-a34c-4381d71f1a5f", "metadata": { "tags": [] @@ -118,14 +117,14 @@ "source": [ "import os\n", "from dotenv import load_dotenv, find_dotenv\n", - "_ = load_dotenv(find_dotenv())\n", + "_ = load_dotenv(find_dotenv(), override=True)\n", "\n", "OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "14331eec-fd46-42e0-b6e7-adaf21824ef7", "metadata": { "tags": [] @@ -137,7 +136,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "0b7b772b", "metadata": { "tags": [] @@ -166,14 +165,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "f2675861", "metadata": { "tags": [] }, "outputs": [], "source": [ - "loader = TextLoader(doc_path)\n", + "loader = TextLoader(doc_path, encoding=\"utf-8\")\n", "documents = loader.load()\n", "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\n", "texts = text_splitter.split_documents(documents)\n", @@ -197,21 +196,49 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "bc5403d4", "metadata": { "tags": [] }, - "outputs": [], - "source": [ - "state_of_union = RetrievalQA.from_chain_type(\n", - " llm=llm, chain_type=\"stuff\", retriever=docsearch.as_retriever()\n", - ")" + "outputs": [ + { + "data": { + "text/plain": [ + "'\\n\\nSystem: The current president of the United States is Joe Biden.'" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain_core.runnables import RunnablePassthrough\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "\n", + "retriever = docsearch.as_retriever()\n", + "\n", + "prompt = ChatPromptTemplate.from_messages([\n", + " (\"system\", \"Response using this context:\\n\\n{context}\"),\n", + " (\"human\", \"{input}\"),\n", + "])\n", + "format = lambda docs: \" \".join(doc.page_content for doc in docs)\n", + "\n", + "state_of_union = (\n", + " {\"context\": retriever | format, \"input\": RunnablePassthrough()}\n", + " | prompt\n", + " | llm\n", + " | StrOutputParser()\n", + ")\n", + "\n", + "state_of_union.invoke(\"Who is the president of the United States?\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "1431cded", "metadata": { "tags": [] @@ -223,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "id": "915d3ff3", "metadata": { "tags": [] @@ -235,19 +262,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "96a2edf8", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Created a chunk of size 2122, which is longer than the specified 1000\n", + "Created a chunk of size 3187, which is longer than the specified 1000\n", + "Created a chunk of size 1017, which is longer than the specified 1000\n", + "Created a chunk of size 2321, which is longer than the specified 1000\n" + ] + }, + { + "data": { + "text/plain": [ + "'\\n\\nRuff is a linter and formatter for the Ruff programming language. It helps developers catch errors and format their code for consistency.'" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "docs = loader.load()\n", "ruff_texts = text_splitter.split_documents(docs)\n", "ruff_db = Chroma.from_documents(ruff_texts, embeddings, collection_name=\"ruff\")\n", - "ruff = RetrievalQA.from_chain_type(\n", - " llm=llm, chain_type=\"stuff\", retriever=ruff_db.as_retriever()\n", - ")" + "\n", + "ruff_retriever = ruff_db.as_retriever()\n", + "\n", + "ruff = (\n", + " {\"context\": ruff_retriever | format, \"input\": RunnablePassthrough()}\n", + " | prompt\n", + " | llm\n", + " | StrOutputParser()\n", + ")\n", + "\n", + "ruff.invoke(\"Describe Ruff to me in two sentences.\")" ] }, { @@ -264,7 +320,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "id": "eb142786", "metadata": { "tags": [] @@ -272,8 +328,11 @@ "outputs": [], "source": [ "# Import things that are needed generically\n", - "from langchain.agents import AgentType, Tool, initialize_agent\n", - "from langchain_openai import OpenAI" + "#from langchain.agents import AgentType, Tool, initialize_agent\n", + "from langchain_openai import ChatOpenAI\n", + "from langchain.agents import create_agent\n", + "\n", + "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0, api_key=OPENAI_API_KEY)" ] }, { @@ -288,22 +347,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "id": "850bc4e9", "metadata": { "tags": [] }, "outputs": [], "source": [ + "from langchain_core.tools import Tool\n", + "\n", "tools = [\n", " Tool(\n", - " name=\"State of Union QA System\",\n", - " func=state_of_union.run,\n", + " name=\"state_of_union_qa_system\",\n", + " func=state_of_union.invoke,\n", " description=\"useful for when you need to answer questions about the most recent state of the union address. Input should be a fully formed question.\",\n", " ),\n", " Tool(\n", - " name=\"Ruff QA System\",\n", - " func=ruff.run,\n", + " name=\"ruff_qa_system\",\n", + " func=ruff.invoke,\n", " description=\"useful for when you need to answer questions about ruff (a python linter). Input should be a fully formed question.\",\n", " ),\n", "]" @@ -311,7 +372,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "id": "fc47f230", "metadata": { "tags": [] @@ -320,35 +381,91 @@ "source": [ "# Construct the agent. We will use the default agent type here.\n", "# See documentation for a full list of options.\n", - "agent = initialize_agent(\n", - " tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True\n", + "agent = create_agent(\n", + " model=llm,\n", + " tools=tools,\n", + " system_prompt=\"You are a helpful conversational assistant who can use tools when necessary.\",\n", ")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 45, "id": "10ca2db8", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "In the State of the Union address, Biden praised Ketanji Brown Jackson as one of the nation's top legal minds, emphasizing that she would continue the legacy of excellence left by retiring Justice Stephen Breyer. He highlighted her diverse background, noting her experience as a former top litigator and federal public defender, as well as her family background in public education and law enforcement. Biden also pointed out the broad support she received from both Democrats and Republicans.\n" + ] + } + ], "source": [ - "agent.invoke(\n", - " \"What did biden say about ketanji brown jackson in the state of the union address?\"\n", - ")" + "response = agent.invoke({ \"messages\": [(\"user\", \"What did biden say about ketanji brown jackson in the state of the union address?\")] })\n", + "print(response[\"messages\"][-1].content)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, + "id": "fa3e611e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "In the State of the Union address, Biden praised Ketanji Brown Jackson as one of the nation's top legal minds, emphasizing that she would continue the legacy of excellence left by retiring Justice Stephen Breyer. He highlighted her diverse background, noting her experience as a former top litigator and federal public defender, as well as her family background in public education and law enforcement. Biden also pointed out the broad support she received from both Democrats and Republicans." + ] + } + ], + "source": [ + "stream = agent.stream_events(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"What did biden say about ketanji brown jackson in the state of the union address?\"}]},\n", + " version=\"v3\",\n", + ")\n", + "\n", + "for message in stream.messages:\n", + " # Stream internal reasoning blocks\n", + " for token in message.reasoning:\n", + " print(f\"[thinking] {token}\", end=\"\", flush=True)\n", + "\n", + " # Stream final response tokens\n", + " for token in message.text:\n", + " print(token, end=\"\", flush=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, "id": "4e91b811", "metadata": { "tags": [] }, - "outputs": [], - "source": [ - "agent.invoke(\"Why use ruff over flake8?\")" + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Choosing Ruff over Flake8 for Python linting can be beneficial for several reasons:\n", + "\n", + "1. **Larger Rule Set**: Ruff provides a more extensive set of linting rules compared to Flake8, which can help catch a wider range of issues in your code.\n", + "\n", + "2. **Better Compatibility**: Ruff is designed to work well with other tools, such as type checkers, enhancing the overall development workflow.\n", + "\n", + "3. **Automatic Fixes**: Ruff has the capability to automatically fix its own lint violations, which can save time and effort during the development process.\n", + "\n", + "However, it's worth noting that Ruff does not support custom lint rules like Flake8 does, so if you need that flexibility, Flake8 might still be a better choice for your specific needs.\n" + ] + } + ], + "source": [ + "response = agent.invoke({ \"messages\": [(\"user\", \"Why use ruff over flake8?\")] })\n", + "print(response[\"messages\"][-1].content)" ] }, { @@ -382,14 +499,14 @@ "source": [ "tools = [\n", " Tool(\n", - " name=\"State of Union QA System\",\n", - " func=state_of_union.run,\n", + " name=\"state_of_union_qa_system\",\n", + " func=state_of_union.invoke,\n", " description=\"useful for when you need to answer questions about the most recent state of the union address. Input should be a fully formed question.\",\n", " return_direct=True,\n", " ),\n", " Tool(\n", - " name=\"Ruff QA System\",\n", - " func=ruff.run,\n", + " name=\"ruff_qa_system\",\n", + " func=ruff.invoke,\n", " description=\"useful for when you need to answer questions about ruff (a python linter). Input should be a fully formed question.\",\n", " return_direct=True,\n", " ),\n", @@ -398,42 +515,103 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "id": "8615707a", "metadata": { "tags": [] }, - "outputs": [], - "source": [ - "agent = initialize_agent(\n", - " tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True\n", - ")" + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "What did biden say about ketanji brown jackson?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " state_of_union_qa_system (call_dHobPmAhPb0kXtAr0qDfsygo)\n", + " Call ID: call_dHobPmAhPb0kXtAr0qDfsygo\n", + " Args:\n", + " __arg1: What did Biden say about Ketanji Brown Jackson in the most recent State of the Union address?\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: state_of_union_qa_system\n", + "\n", + "\n", + "\n", + "In the most recent State of the Union address, President Biden honored Justice Stephen Breyer and thanked him for his service. He also mentioned his recent nomination of Circuit Court of Appeals Judge Ketanji Brown Jackson to the United States Supreme Court, praising her as one of the nation's top legal minds who will continue Justice Breyer's legacy of excellence. He also mentioned her bipartisan support and her background as a former top litigator and federal public defender from a family of public school educators and police officers.\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "In the most recent State of the Union address, President Biden honored Justice Stephen Breyer and thanked him for his service. He also spoke about his nomination of Circuit Court of Appeals Judge Ketanji Brown Jackson to the United States Supreme Court, praising her as one of the nation's top legal minds who will continue Justice Breyer's legacy of excellence. Biden highlighted her bipartisan support and her background as a former top litigator and federal public defender, coming from a family of public school educators and police officers.\n" + ] + } + ], + "source": [ + "agent = create_agent(\n", + " model=llm,\n", + " tools=tools,\n", + " system_prompt=\"You are a helpful conversational assistant who can use tools when necessary.\"\n", + ")\n", + "\n", + "for step in agent.stream(\n", + " {\"messages\": [(\"user\", \"What did biden say about ketanji brown jackson?\")]},\n", + " stream_mode=\"values\",\n", + "):\n", + " step[\"messages\"][-1].pretty_print()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 53, "id": "36e718a9", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "In the State of the Union address, Biden praised Ketanji Brown Jackson as one of the nation's top legal minds, emphasizing that she would continue the legacy of excellence left by retiring Justice Stephen Breyer. He highlighted her diverse background, noting her experience as a former top litigator and federal public defender, as well as her family background in public education and law enforcement. Biden also pointed out the broad support she received from both Democrats and Republicans.\n" + ] + } + ], "source": [ - "agent.invoke(\n", - " \"What did biden say about ketanji brown jackson in the state of the union address?\"\n", - ")" + "response = agent.invoke(\n", + " {\"messages\": [(\"user\", \"What did biden say about ketanji brown jackson in the state of the union address?\")]}\n", + ")\n", + "print(response[\"messages\"][-1].content)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 52, "id": "edfd0a1a", "metadata": { "tags": [] }, - "outputs": [], - "source": [ - "agent.invoke(\"Why use ruff over flake8?\")" + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ruff is preferred over Flake8 for several reasons:\n", + "\n", + "1. **Larger Rule Set**: Ruff provides a more extensive set of linting rules compared to Flake8, which can help catch a wider range of issues in your code.\n", + "\n", + "2. **Better Compatibility**: Ruff is designed to work well with other tools, such as type checkers, enhancing the overall development workflow.\n", + "\n", + "3. **Automatic Fixes**: Ruff has the capability to automatically fix its own lint violations, which can save time and effort during the development process.\n", + "\n", + "However, it's worth noting that Ruff does not support custom lint rules like Flake8 does, so if you need that flexibility, Flake8 might still be a better choice for your specific needs.\n" + ] + } + ], + "source": [ + "response = agent.invoke(\n", + " {\"messages\": [(\"user\", \"Why use ruff over flake8?\")]}\n", + ")\n", + "print(response[\"messages\"][-1].content)" ] }, { @@ -450,7 +628,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "id": "d397a233", "metadata": { "tags": [] @@ -459,13 +637,13 @@ "source": [ "tools = [\n", " Tool(\n", - " name=\"State of Union QA System\",\n", - " func=state_of_union.run,\n", + " name=\"state_of_union_qa_system\",\n", + " func=state_of_union.invoke,\n", " description=\"useful for when you need to answer questions about the most recent state of the union address. Input should be a fully formed question, not referencing any obscure pronouns from the conversation before.\",\n", " ),\n", " Tool(\n", - " name=\"Ruff QA System\",\n", - " func=ruff.run,\n", + " name=\"ruff_qa_system\",\n", + " func=ruff.invoke,\n", " description=\"useful for when you need to answer questions about ruff (a python linter). Input should be a fully formed question, not referencing any obscure pronouns from the conversation before.\",\n", " ),\n", "]" @@ -473,7 +651,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 63, "id": "06157240", "metadata": { "tags": [] @@ -482,23 +660,34 @@ "source": [ "# Construct the agent. We will use the default agent type here.\n", "# See documentation for a full list of options.\n", - "agent = initialize_agent(\n", - " tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True\n", + "agent = create_agent(\n", + " model=llm,\n", + " tools=tools,\n", + " system_prompt=\"Break down complex questions into subquestions and consult the tools one by one before answering.\"\n", ")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 66, "id": "b492b520", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ruff uses **nbQA**, a tool for running linters and code formatters over Jupyter Notebooks. However, the president did not mention ruff or any tool related to running over Jupyter Notebooks in the state of the union address.\n" + ] + } + ], "source": [ - "agent.invoke(\n", - " \"What tool does ruff use to run over Jupyter Notebooks? Did the president mention that tool in the state of the union?\"\n", - ")" + "response = agent.invoke(\n", + " {\"messages\": [(\"user\", \"What tool does ruff use to run over Jupyter Notebooks? Did the president mention that tool in the state of the union?\")]}\n", + ")\n", + "print(response[\"messages\"][-1].content)" ] }, { @@ -541,9 +730,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (LangChain 0.2.x)", + "display_name": ".venv (3.13.9.final.0)", "language": "python", - "name": "langchain-v0.2.x" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -555,7 +744,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.13" + "version": "3.13.9" } }, "nbformat": 4,