{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "cd80bc40-f10d-4ab3-826d-6cd0636d11e0", "metadata": {}, "outputs": [], "source": [ "from operator import itemgetter\n", "\n", "from langchain.chat_models import ChatOpenAI, ChatAnthropic\n", "from langchain.prompts import SystemMessagePromptTemplate, ChatPromptTemplate\n", "from langchain.schema.output_parser import StrOutputParser\n", "from langchain.runnables.openai_functions import OpenAIFunctionsRouter\n", "\n", "from permchain.connection_inmemory import InMemoryPubSubConnection\n", "from permchain.pubsub import PubSub\n", "from permchain.topic import Topic" ] }, { "cell_type": "markdown", "id": "54c553be-9ed1-452c-a4ab-828f34dbb3ce", "metadata": {}, "source": [ "## Content Fetcher" ] }, { "cell_type": "markdown", "id": "56a6788d-b67c-4331-af8d-7741a66f03af", "metadata": {}, "source": [ "First, we are going to define our content fetcher. This is responsible for taking a search query an getting relevant web pages." ] }, { "cell_type": "code", "execution_count": 2, "id": "a9c32e92-6f19-4cf1-8b87-1b756de0e263", "metadata": {}, "outputs": [], "source": [ "from langchain.utilities import GoogleSearchAPIWrapper\n", "from langchain.document_loaders import AsyncHtmlLoader\n", "from langchain.document_transformers import Html2TextTransformer" ] }, { "cell_type": "code", "execution_count": 3, "id": "89d4a96a-2f59-491f-81fd-4a5d755c0081", "metadata": {}, "outputs": [], "source": [ "from duckduckgo_search import DDGS\n", "\n", "ddgs = DDGS()" ] }, { "cell_type": "code", "execution_count": 4, "id": "dcdc3812-0cdc-4677-bf9d-f9d7d5cac7e2", "metadata": {}, "outputs": [], "source": [ "def retrieve_documents(query):\n", " query = query.strip().strip('\"')\n", " search_results = ddgs.text(query)\n", " urls_to_look = []\n", " for res in search_results:\n", " if res.get(\"href\", None):\n", " urls_to_look.append(res[\"href\"])\n", " if len(urls_to_look) >= 4:\n", " break\n", "\n", " # Relevant urls\n", " # Load, split, and add new urls to vectorstore\n", " if urls_to_look:\n", " loader = AsyncHtmlLoader(urls_to_look)\n", " html2text = Html2TextTransformer()\n", " docs = loader.load()\n", " docs = list(html2text.transform_documents(docs))\n", " else:\n", " docs = []\n", " return docs" ] }, { "cell_type": "code", "execution_count": 5, "id": "45bb7661-35db-4a67-a62e-9c791c9de359", "metadata": {}, "outputs": [], "source": [ "import nest_asyncio\n", "\n", "nest_asyncio.apply()" ] }, { "cell_type": "code", "execution_count": 6, "id": "d087d2b4-d1fa-4f63-81de-d3d4e1dc5b1b", "metadata": {}, "outputs": [], "source": [ "# docs = retrieve_documents(\"langchain\")" ] }, { "cell_type": "markdown", "id": "73e0b79f-f6bd-4f68-9433-645ee1eea81e", "metadata": {}, "source": [ "## Summarizer\n", "We will now come up with an actor to summarize the results given a query and some search results" ] }, { "cell_type": "code", "execution_count": 7, "id": "901e1f8d-c973-4998-a731-5dab0c147b8c", "metadata": {}, "outputs": [], "source": [ "prompt = ChatPromptTemplate.from_template(\n", " \"Answer the user's question given the search results\\n\\n{question}{search_results}\"\n", ")" ] }, { "cell_type": "code", "execution_count": 8, "id": "915bec33-d210-4471-b051-859ecba608be", "metadata": {}, "outputs": [], "source": [ "summarizer_chain = (\n", " prompt\n", " | ChatOpenAI(max_retries=0).with_fallbacks(\n", " [ChatOpenAI(model=\"gpt-3.5-turbo-16k\"), ChatAnthropic(model=\"claude-2\")]\n", " )\n", " | StrOutputParser()\n", ")" ] }, { "cell_type": "markdown", "id": "6bf403ec-39a4-4061-9401-06850ffe3761", "metadata": {}, "source": [ "## All together now!" ] }, { "cell_type": "code", "execution_count": 9, "id": "edc0def4-d184-4438-9099-e6604ba9ff28", "metadata": {}, "outputs": [], "source": [ "summarizer_inbox = Topic(\"summarizer\")" ] }, { "cell_type": "code", "execution_count": 10, "id": "23f89611-7b0f-4f01-b9a7-119124e3341d", "metadata": {}, "outputs": [], "source": [ "search_actor = (\n", " Topic.IN.subscribe()\n", " | {\n", " \"search_results\": retrieve_documents,\n", " \"question\": Topic.IN.current(),\n", " }\n", " | summarizer_inbox.publish()\n", ")" ] }, { "cell_type": "code", "execution_count": 11, "id": "2d4a6b51-bd93-47c2-a301-9593a47df7d4", "metadata": {}, "outputs": [], "source": [ "summ_actor = (\n", " summarizer_inbox.subscribe() | {\"answer\": summarizer_chain} | Topic.OUT.publish()\n", ")" ] }, { "cell_type": "code", "execution_count": 12, "id": "11d3b066-7f95-4ad9-82d0-ba64bbf3e3fa", "metadata": {}, "outputs": [], "source": [ "web_researcher = PubSub(\n", " processes=(search_actor, summ_actor),\n", " connection=InMemoryPubSubConnection(),\n", ").with_config(run_name=\"WebResearcher\")" ] }, { "cell_type": "code", "execution_count": 13, "id": "bc022d51-69f0-4da9-8025-70afdc3cc6a8", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Fetching pages: 100%|###################################################| 4/4 [00:01<00:00, 2.19it/s]\n" ] }, { "data": { "text/plain": [ "[{'answer': 'LangSmith is a platform built by LangChain to help developers build production-grade language model (LLM) applications. It enables developers to trace and evaluate their LLM applications and intelligent agents, ensuring reliability and maintainability in the production environment. LangSmith integrates seamlessly with LangChain and provides features such as tracing runs, testing, and evaluating prompts or answers generated by LLM applications. It aims to facilitate the development lifecycle, maintenance, and improvement of AI models. For more information, you can refer to the LangSmith documentation.'}]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "web_researcher.invoke(\"What is langsmith?\")" ] }, { "cell_type": "code", "execution_count": 14, "id": "000f4f24-15ba-476f-8a33-d023081b18d2", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Fetching pages: 0%| | 0/4 [00:00\n", "{question}\n", "\n", "\n", "In order to do that, you first came up with several sub questions and researched those. please find those below:\n", "\n", "\n", "{research}\n", "\n", "\n", "Now, write your final report answering the original question!\"\"\"\n", "prompt = ChatPromptTemplate.from_template(template)\n", "report_chain = prompt | ChatOpenAI() | StrOutputParser()" ] }, { "cell_type": "code", "execution_count": 19, "id": "d7715e0c-23c0-4985-97a7-bf5b151cf734", "metadata": {}, "outputs": [], "source": [ "research_inbox = Topic(\"research\")\n", "writer_inbox = Topic(\"writer_inbox\")" ] }, { "cell_type": "code", "execution_count": 20, "id": "f274027a-c9f0-4efa-b798-1921b9b376d9", "metadata": {}, "outputs": [], "source": [ "subquestion_actor = (\n", " # Listed in inputs\n", " Topic.IN.subscribe()\n", " | question_chain\n", " # The draft always goes to the editors inbox\n", " | research_inbox.publish()\n", ")\n", "research_actor = (\n", " research_inbox.subscribe()\n", " | {\n", " \"research\": web_researcher.map(),\n", " # \"research\": lambda x: [web_researcher.invoke({\"question\": i}) for i in x],\n", " \"question\": Topic.IN.current() | itemgetter(\"question\"),\n", " }\n", " | writer_inbox.publish()\n", ")\n", "write_actor = writer_inbox.subscribe() | report_chain | Topic.OUT.publish()" ] }, { "cell_type": "code", "execution_count": 21, "id": "789b636d-23ce-44fb-a8e3-fdfbfabe77ff", "metadata": {}, "outputs": [], "source": [ "longer_researcher = PubSub(\n", " processes=(subquestion_actor, research_actor, write_actor),\n", " connection=InMemoryPubSubConnection(),\n", ").with_config(run_name=\"LongResearcher\")" ] }, { "cell_type": "code", "execution_count": 22, "id": "8f713a31-5f60-4d90-9b95-3f42d8fbbddb", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Fetching pages: 0%| | 0/4 [00:00