{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "wmsetq6tIq9_" }, "source": [ "# SAGE\n", "\n", "### Overview\n", "A conversational AI agent designed to help users improve their knowledge through interactive discussions and feedback with a focus on data references provided\n", "The agent facilitates group discussions where multiple users can practice and share their knowledge for specific use cases while receiving expert guidance on best practices.\n", "\n", "### Motivation\n", "Creating effective prompts for AI systems is a complex challenge that requires both theoretical knowledge and practical experience.\n", "Through collaborative learning and structured practice, users can develop their prompt engineering skills more effectively than working in isolation.\n", "SAGE helps bridge the gap between theoretical understanding and practical application,\n", "allowing users to iteratively refine their prompts based on each specific technique and final goal.\n", "\n", "### Key Components\n", "#### Core Features\n", "- Multi-user support with distinct user personas\n", "- Interactive prompt creation exercises\n", "- Real-time feedback based on prompt engineering best practices\n", "- Reference-based learning using markdown documentation that retrives information with Rag System\n", "\n", "#### Technical Architecture\n", "- LangGraph for conversation flow management\n", "- Ollma LLM integration for response generation\n", "- Memory-based state management\n", "- Checkpoint saving for conversation continuity\n", "\n", "#### Learning Flow\n", "1. Agent introduces the Host of discussion\n", "2. Presents a specific topic\n", "3. Users take turns creating and discussing\n", "4. Agent provides analysis and constructive feedback\n", "5. Session can be continued or concluded with a summary\n", "\n", "#### Application Domains (Use Case Shown - Prompt Engineering)\n", "- Training sessions for prompt engineering\n", "- Collaborative prompt development\n", "- Learning prompt engineering best practices\n", "- Improving chatbot and AI system prompts\n", "\n", "### Acknowledgment\n", "This implementation is inspired by and utilizes techniques from the comprehensive prompt engineering collection maintained by [NirDiamant](https://github.com/NirDiamant/Prompt_Engineering), specifically focusing on the Role Prompting methodology for creating an effective learning environment." ] }, { "cell_type": "markdown", "metadata": { "id": "Zi9W1UCFJBf7" }, "source": [ "## Environment : Installs" ] }, { "cell_type": "markdown", "metadata": { "id": "kMhTJAd4Jh9E" }, "source": [ "### Install dependencies\n", "#### Installs required Python packages including:\n", " - Environment management (python-dotenv)\n", " - LLM integrations (groq, langchain)\n", " - Graph processing (langgraph)\n", " - Vector stores (pinecone, chroma)\n", " - NLP tools (spacy)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install python-dotenv==1.0.1\n", "!pip install groq==0.4.2 # For Groq API interactions\n", "!pip install pydantic==2.9.2\n", "!pip install spacy==3.8.2\n", "!pip install langgraph==0.2.48\n", "!pip install langgraph-checkpoint-sqlite==2.0.1\n", "!pip install langchain-core==0.3.18\n", "!pip install langchain-groq==0.2.1\n", "\n", "!pip install langchain==0.3.7\n", "!pip install langchain_ollama==0.2.0\n", "!pip install langchain_pinecone==0.2.0\n", "!pip install pinecone-notebooks==0.1.0\n", "\n", "!pip install langchain-community==0.3.7\n", "!pip install langchain-chroma==0.1.4" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!apt-get install -y pciutils\n", "!curl https://ollama.ai/install.sh | sh" ] }, { "cell_type": "markdown", "metadata": { "id": "jJCZWpTpJo3o" }, "source": [ "### 1. Configurations" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "11W7ZIyJOChD" }, "outputs": [], "source": [ "NEW_LINE = \"\\n\"\n", "GROQ_LLM_INFERENCE = \"llama-3.2-3b-preview\"\n", "OLLAMA_LLM_INFERENCE = \"llama3.2\"\n", "OLLAMA_HOST = 'http://0.0.0.0:11434'\n", "LLM_EMBBEDDINGS = \"nomic-embed-text\"\n", "\n", "SPACEY_MODEL = \"en_core_web_sm\"\n", "\n", "LOCAL_ARCHIVE_PATH = \"./\"\n", "LOCAL_DEFAULT_BOOK = \"3300-0.txt\"\n", "WEB_DEFAULT_BOOK = \"https://www.gutenberg.org/files/3300/3300-0.txt\"\n", "\n", "CHROMA_STORE = \"wealth_of_nations\"\n", "\n", "INDEX_NAME = \"wealthofnations\"\n", "\n", "IS_LOCAL_ENVIRONMENT = True" ] }, { "cell_type": "markdown", "metadata": { "id": "wmiV3OFSJu7W" }, "source": [ "### Import libraries" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "id": "3M3KM9lbOCaZ" }, "outputs": [], "source": [ "# Vectorstore\n", "import os\n", "import json\n", "import time\n", "import random\n", "import threading\n", "import subprocess\n", "\n", "from pathlib import Path\n", "from operator import add\n", "from dotenv import load_dotenv\n", "\n", "from langchain_groq import ChatGroq\n", "from langchain_ollama import OllamaEmbeddings, ChatOllama\n", "\n", "load_dotenv()\n", "\n", "## Embbeddings databases\n", "from langchain_pinecone import PineconeVectorStore\n", "from langchain_chroma import Chroma\n", "\n", "\n", "## Agent dependencies\n", "from typing import Annotated, Literal\n", "from typing_extensions import TypedDict\n", "from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage , AIMessage\n", "from langgraph.graph import add_messages, StateGraph, START, END\n", "from pydantic import BaseModel\n", "from langgraph.checkpoint.sqlite import SqliteSaver\n", "from langgraph.checkpoint.memory import MemorySaver\n", "\n", "## NER\n", "import spacy\n", "\n", "## RAG dependencies:\n", "from langchain_community.document_loaders import (\n", " DirectoryLoader,\n", " TextLoader,\n", ")\n", "from langchain.text_splitter import RecursiveCharacterTextSplitter\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "id": "GkbNsXCNNFsU" }, "outputs": [], "source": [ "def ollama():\n", " os.environ['OLLAMA_HOST'] = OLLAMA_HOST\n", " os.environ['OLLAMA_ORIGINS'] = '*'\n", " subprocess.Popen([\"ollama\", \"pull\", LLM_EMBBEDDINGS])\n", " subprocess.Popen([\"ollama\", \"pull\", OLLAMA_LLM_INFERENCE])\n", " subprocess.Popen([\"ollama\", \"serve\"])\n", "\n", "ollama_thread = threading.Thread(target=ollama)\n", "ollama_thread.start()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "id": "vzbxaMc9TdOQ" }, "outputs": [], "source": [ "\n", "## Colab custom logic\n", "\n", "if not IS_LOCAL_ENVIRONMENT:\n", " from google.colab import userdata\n", "\n", " os.environ[\"GROQ_API_KEY\"] = userdata.get('GROQ_API_KEY')\n", " os.environ[\"PINECONE_API_KEY\"] = userdata.get('PINECONE_API_KEY')\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "gxvuAAM7PhK-", "outputId": "9e5bbfa8-53c2-44f1-a223-c7a8322bf256" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/local/lib/python3.10/dist-packages/spacy/util.py:910: UserWarning: [W095] Model 'en_core_web_sm' (3.7.1) was trained with spaCy v3.7.2 and may not be 100% compatible with the current version (3.8.2). If you see errors or degraded performance, download a newer compatible model or retrain your custom model with the current spaCy version. For more details and available updates, run: python -m spacy validate\n", " warnings.warn(warn_msg)\n" ] } ], "source": [ "##\n", "## PROGRAM LOGIC\n", "##\n", "def build_llm():\n", " if IS_LOCAL_ENVIRONMENT:\n", " llm = ChatOllama(model=OLLAMA_LLM_INFERENCE)\n", " else:\n", " llm = ChatGroq(model=GROQ_LLM_INFERENCE)\n", " return llm\n", "\n", "llm = build_llm()\n", "nlp = spacy.load(SPACEY_MODEL)" ] }, { "cell_type": "markdown", "metadata": { "id": "efJjXLnlJz3a" }, "source": [ "### 2. Vector Store Setup" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "id": "cSEMgboCPSS2" }, "outputs": [], "source": [ "## vectorstore\n", "def build_vector_store():\n", " if not IS_LOCAL_ENVIRONMENT:\n", " return PineconeVectorStore(index_name=INDEX_NAME, embedding=embeddings)\n", " else:\n", " return Chroma(\n", " embedding_function=embeddings,\n", " persist_directory=f\"{LOCAL_ARCHIVE_PATH}{CHROMA_STORE}\"\n", " )\n", "\n", "embeddings = OllamaEmbeddings(model=LLM_EMBBEDDINGS)\n", "embeddings.base_url = os.getenv(\"OLLAMA_HOST\")\n", "\n", "vectorstore = build_vector_store()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "id": "xLfkvYYaXw0h" }, "outputs": [], "source": [ "## Embeddings\n", "from langchain_text_splitters import MarkdownHeaderTextSplitter\n", "\n", "def embbed_paragraphs(db):\n", " sample_docs = DirectoryLoader(\n", " \"./\",\n", " glob=\"**/*.txt\",\n", " loader_cls=TextLoader,\n", " show_progress=True,\n", " ).load()\n", "\n", " text_splitter = RecursiveCharacterTextSplitter(\n", " chunk_size=500,\n", " chunk_overlap=50,\n", " length_function=len,\n", " )\n", " documents = text_splitter.split_documents(sample_docs)\n", "\n", " if not IS_LOCAL_ENVIRONMENT:\n", " # Use Pinecone\n", " db.from_documents(documents, embedding=embeddings, index_name=\"wealthofnations\")\n", " else:\n", " # Use Local Chroma\n", " db.from_documents(documents, embedding=embeddings)\n", "\n", " return documents" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "id": "RcDoaK3OPX8-" }, "outputs": [], "source": [ "## State\n", "class User(BaseModel):\n", " name: str\n", " gender: str\n", " age: int\n", " likes: list[str]\n", " dislikes: list[str]\n", "\n", "class Host(User):\n", " sys_msg: str = None\n", " personality: list[str]\n", "\n", "def add_discussions(discussions, new_messages):\n", " if not new_messages:\n", " return []\n", " return discussions + new_messages\n", "\n", "class DiscussionState(TypedDict):\n", " messages: Annotated[list[AnyMessage], add_messages] = []\n", " topic: str\n", " users: list[User]\n", " host: Host\n", " curr_discussion: Annotated[list[AnyMessage], add_discussions] = []\n", " discussion_summaries: Annotated[list[str], add] = []\n", " setEndDiscussion: bool = False\n", " random_anchor: str\n", " book_file_path: str = LOCAL_DEFAULT_BOOK" ] }, { "cell_type": "markdown", "metadata": { "id": "ppgzSK6XJ_nM" }, "source": [ "### 4. Node Functions\n", "\n", "Source Material Processing\n", "\n", "ingest_source_material: Downloads and stores source material\n", "\n", "preprocess_source_material: Performs NER and embeddings\n", "\n", "prepare_topic: Selects discussion topics from processed material\n", "\n", "#### Discussion Flow\n", "\n", "introduce: Host Initiates the session\n", "\n", "ask_question: Generates discussion questions\n", "human_discuss: Handles user interactions\n", "\n", "agent_interpretations: Analyzes discussion and provides AI feedback\n", "\n", "summarize_discussion: Creates discussion summaries" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "id": "993b1uIfTtCP" }, "outputs": [], "source": [ "## LangGraph States\n", "def introduce(state):\n", " host = state['host']\n", " topic = state['topic']\n", " users = state['users']\n", "\n", " sys_msg = f\"\"\"\n", " You are a meeting host leading a meeting.\n", "\n", " You will be leading a group of {len(users)} members.\n", "\n", " Your job is to ask a quesetion about the to the users to discuss.\n", "\n", " The following is your information, do not break your character.\n", " name: {host.name}\n", " gender: {host.gender}\n", " age: {host.age}\n", " personality: {host.personality}\n", "\n", "\n", " The following are the information of the club users:\n", " {NEW_LINE.join([f\"{user.name} ({user.gender}, {user.age}\" for user in users])}\n", "\n", " The topic that will be discussed is {topic}\n", " \"\"\"\n", "\n", " if state.get('guide'):\n", " sys_msg += f\"\\n Follow this guide: \\n{state.get('guide')}\"\n", "\n", " host.sys_msg = sys_msg\n", "\n", " narrator_msg = f\"\"\"\n", " Club members just arrived!\n", " Before we dive in, please greet the members, introduce yourself, and give brief introductions of the members.\n", " \"\"\"\n", " response = llm.invoke([\n", " SystemMessage(content=sys_msg),\n", " HumanMessage(content=narrator_msg, name=\"narrator\")\n", " ])\n", " response.name = host.name\n", " response.content = f\"{host.name}: {response.content}\"\n", " response.pretty_print()\n", " return {\n", " 'message': [response],\n", " 'host': host,\n", " }\n", "\n", "def ingest_source_material(state):\n", " \"\"\"\n", " Downloads source material from the Gutenberg project\n", " \"\"\"\n", " import requests\n", " response = requests.get(WEB_DEFAULT_BOOK)\n", "\n", " source_file_path = Path(f\"{LOCAL_ARCHIVE_PATH}{LOCAL_DEFAULT_BOOK}\")\n", " with open(source_file_path, \"w\") as source_file:\n", " source_file.write(response.text)\n", "\n", " return state\n", "\n", "def extract_entities(file_path):\n", " # Read the text file\n", " with open(file_path, 'r', encoding='utf-8') as file:\n", " text = file.read()\n", "\n", " # Process the text with spaCy\n", " nlp.max_length = len(text)\n", " doc = nlp(text)\n", "\n", " # Extract entities and organize them by type\n", " entities = {}\n", " for ent in doc.ents:\n", " if ent.label_ not in entities:\n", " entities[ent.label_] = set()\n", " entities[ent.label_].add(ent.text)\n", "\n", " for key, value in entities.items():\n", " entities[key] = list(value)\n", "\n", " return entities\n", "\n", "\n", "def preprocess_source_material(state):\n", " \"\"\"\n", " Performs NER against source material\n", " \"\"\"\n", " embbed_paragraphs(vectorstore)\n", "\n", " entities_file_path = Path(f\"{LOCAL_ARCHIVE_PATH}entities_{LOCAL_DEFAULT_BOOK}\")\n", "\n", " found_entities = extract_entities(f\"{LOCAL_ARCHIVE_PATH}{LOCAL_DEFAULT_BOOK}\")\n", " json_entities = json.dumps(found_entities)\n", "\n", " with open(entities_file_path, \"w\") as output:\n", " output.write(json_entities)\n", "\n", " return state\n", "\n", "def prepare_topic(state):\n", " entities_file_path = Path(f\"{LOCAL_ARCHIVE_PATH}entities_{LOCAL_DEFAULT_BOOK}\")\n", "\n", " with open(entities_file_path, \"r\") as entities_file:\n", " entities = json.loads(entities_file.read())\n", "\n", " persons = entities.get(\"PERSON\")\n", " size = len(persons)\n", "\n", " state['random_anchor'] = persons[random.randint(1, size)]\n", " return state\n", "\n", "def should_download_source_material(state):\n", " source_file_path = Path(f\"{LOCAL_ARCHIVE_PATH}{LOCAL_DEFAULT_BOOK}\")\n", "\n", " if(not source_file_path.exists() or not source_file_path.is_file()):\n", " return \"web_download\"\n", "\n", " entities_file_path = Path(f\"{LOCAL_ARCHIVE_PATH}entities_{LOCAL_DEFAULT_BOOK}\")\n", "\n", " if(not entities_file_path.exists() or not entities_file_path.is_file()):\n", " return \"embeddings_ner\"\n", "\n", " return \"prepare_topic\"\n", "\n", "def should_prepare_source_material(state):\n", " entities_file_path = Path(f\"{LOCAL_ARCHIVE_PATH}entities_{LOCAL_DEFAULT_BOOK}\")\n", "\n", " if(not entities_file_path.exists() or not entities_file_path.is_file()):\n", " return \"embeddings_ner\"\n", "\n", " return \"prepare_topic\"\n", "\n", "def ask_question(state):\n", " # 1. find any interesting topic from retriever\n", "\n", " retriever = vectorstore.as_retriever(\n", " search_type=\"similarity_score_threshold\",\n", " search_kwargs={\"k\": 1, \"score_threshold\": 0.5},\n", " )\n", "\n", " if not IS_LOCAL_ENVIRONMENT:\n", " # Use Pinecone\n", " results = retriever.invoke(state['random_anchor'], filter={\"source\": \"wealthofnations\"})\n", " else:\n", " # Use Local Chroma\n", " results = retriever.invoke(state['random_anchor'])\n", "\n", "\n", " # referenced_document = list(results)[0].page_content\n", " referenced_document = \"test\"\n", "\n", " # 2. generate interesting question from the topic\n", " host = state['host']\n", "\n", " narrator_msg = f\"\"\"\n", " Present an interesting and insightful question from the topic from the following interesting fact(s):\n", " {referenced_document}\n", "\n", " Remember that you are the host, do not break the character.\n", " \"\"\"\n", " response = llm.invoke([\n", " SystemMessage(content=host.sys_msg),\n", " SystemMessage(content=\"Your job is to ask a quesetion about the topic to the users for dicsussion.\"),\n", " HumanMessage(content=narrator_msg, name=\"narrator\")\n", " ])\n", " response.name = host.name\n", " response.content = f\"{host.name}: {response.content}\"\n", " response.pretty_print()\n", " return {\n", " 'message': [response],\n", " 'curr_discussion': [response],\n", " \"setEndDiscussion\": False\n", " }\n", "\n", "def human_discuss(state):\n", " # Discussions among users\\\n", " end_discussion = False\n", " user_messages = []\n", " user_options = {str(i+1): user.name for i, user in enumerate(state['users'])}\n", " participating_users = set() # Track who has participated\n", " while True:\n", " print(\"===\" * 10 + \"USER INPUT\" + \"===\" * 10)\n", " user_ind = input(f\"{user_options}\\nWho are you (type number to select user OR 'q' to quit): \")\n", "\n", " if user_ind.isdigit() and int(user_ind) in range(1, len(state['users'])+1):\n", " user = state['users'][int(user_ind) - 1]\n", " participating_users.add(user.name) # Track this user's participation\n", " user_input = input(f\"{user.name}: \")\n", " user_messages.append(HumanMessage(content=f\"{user.name}: {user_input}\", user_id=user.name))\n", " break\n", " elif user_ind == 'q':\n", " end_discussion = True\n", " # Add empty messages for all silent users\n", " silent_users = [user for user in state['users'] if user.name not in participating_users]\n", " for silent_user in silent_users:\n", " user_messages.append(HumanMessage(content=f\"{silent_user.name}: '......'\", user_id=silent_user.name))\n", " break\n", " else:\n", " print(\"Invalid input. Please enter a number between 1 and\", len(state['users']))\n", "\n", " return {\n", " \"curr_discussion\": user_messages,\n", " \"setEndDiscussion\": end_discussion\n", " }\n", "\n", "def summarize_discussion(state):\n", " curr_discussion = state['curr_discussion']\n", " sys_msg = \"\"\"\n", " You are a summarizer of a discussion. Your job is to summarize the following conversations\n", " \"\"\"\n", " response = llm.invoke(\n", " [SystemMessage(content=sys_msg)] + curr_discussion\n", " )\n", " response.pretty_print()\n", " return {\n", " 'discussion_summaries': [response.content],\n", " }\n", "\n", "def agent_interjection(state):\n", " curr_discussion = state['curr_discussion']\n", " host = state['host']\n", " topic = state['topic']\n", " users = state['users']\n", "\n", " sys_msg = f\"\"\"\n", " You are {host.name}, a club host discussing {topic}. Your traits: {', '.join(host.personality)}\n", "\n", " You will always respond as host \"{host.name}: message\"\n", "\n", " Club members present:\n", " {', '.join([f\"{user.name} (interests: {', '.join(user.likes)})\" for user in users])}\n", "\n", " only address the members present in the discussion.\n", "\n", " When analyzing the discussion, pay extra attention to:\n", " 1. Who said what - track each member's specific contributions accurately\n", " 2. The depth of each response - look for opportunities to expand shallow comments\n", " 3. The engagement level of each participant\n", " 4. Accuracy in referencing previous comments\n", " 5. If members are silent, which is indicated by '......'.\n", "\n", " When intervening:\n", " - Always acknowledge the specific points made by each member\n", " - Build on their existing comments and dont assume there responses other than what they said.\n", " - Ask follow-up questions that directly relate to their statements\n", " - Maintain conversation flow by connecting members' comments to each other\n", " - If members are silent, Make first engage them to say hi and then use their interests to draw them in\n", "\n", " IMPORTANT: Respond ONLY with a valid JSON object in the following format:\n", " {{\n", " \"thought_process\": \"Your step-by-step analysis for intervention\",\n", " \"should_intervene\": boolean,\n", " \"message\": \"Your intervention message if should_intervene is true and based on your thought process\"\n", " }}\n", " \"\"\"\n", "\n", " narrator_msg = f\"\"\"\n", " Current discussion (in chronological order):\n", " {NEW_LINE.join([f\"- {msg.content}\" for msg in curr_discussion])}\n", "\n", " Analyze the above discussion and decide if you should intervene to help members engage with {topic}.\n", " \"\"\"\n", "\n", " response = llm.invoke(\n", " [SystemMessage(content=sys_msg)] + [HumanMessage(content=narrator_msg, name=\"narrator\")]\n", " )\n", "\n", " # Parse the response and act accordingly\n", " try:\n", " import json\n", " response_data = json.loads(response.content)\n", "\n", " #print(\"Response data: ================\")\n", " #print(response_data)\n", "\n", " if response_data[\"should_intervene\"]:\n", " ai_response = AIMessage(content=response_data[\"message\"])\n", " print(ai_response.pretty_print())\n", " return {\n", " 'messages': [ai_response],\n", " 'curr_discussion': [ai_response]\n", " }\n", " except json.JSONDecodeError as e:\n", " return {\n", " 'messages': state['messages'],\n", " 'curr_discussion': state['curr_discussion']\n", " }\n", "\n", "def ask_to_continue(state) -> Literal['ask_question', END]:\n", " print(\"---\" * 25)\n", " user_input = input(\"\\nContinue with another question? y/n: \")\n", " if user_input.lower() == 'y':\n", " return \"ask_question\"\n", " else:\n", " return END\n", "\n", "def route_discussion(state) -> Literal['agent_interjection', 'summarize_discussion']:\n", " # print(\"Came to route discussion\")\n", " # Check if last message indicates quitting\n", " if state['setEndDiscussion'] : #state['curr_discussion'] and state['curr_discussion'][-2].content.split(\":\")[-1].strip().lower() == 'q':\n", " print(\"Went to summarize discussion\")\n", " state['setEndDiscussion'] = False\n", " return 'summarize_discussion'\n", " return 'agent_interjection'\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "2jeUwVl1KDvF" }, "source": [ "### 5. Graph Setup" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "id": "Ft7EaEzjPorq" }, "outputs": [], "source": [ "builder = StateGraph(DiscussionState)\n", "\n", "builder.add_node(introduce)\n", "#builder.add_node('web_download', web_to_local_node)\n", "builder.add_node('web_download', ingest_source_material)\n", "builder.add_node('embeddings_ner', preprocess_source_material)\n", "\n", "builder.add_node(prepare_topic)\n", "builder.add_node(ask_question)\n", "builder.add_node(human_discuss)\n", "builder.add_node(agent_interjection)\n", "builder.add_node(summarize_discussion)\n", "\n", "builder.add_edge(START, 'introduce')\n", "builder.add_conditional_edges('introduce', should_download_source_material, ['web_download', 'embeddings_ner', 'prepare_topic'])\n", "builder.add_conditional_edges('web_download', should_prepare_source_material, ['embeddings_ner', 'prepare_topic'])\n", "builder.add_edge('embeddings_ner', 'prepare_topic')\n", "builder.add_edge('prepare_topic', 'ask_question')\n", "\n", "builder.add_edge('ask_question', 'human_discuss')\n", "builder.add_edge('agent_interjection', 'human_discuss')\n", "builder.add_conditional_edges('human_discuss',route_discussion)\n", "builder.add_conditional_edges('summarize_discussion', ask_to_continue)\n", "\n", "memory = MemorySaver()\n", "agent = builder.compile(checkpointer=memory)" ] }, { "cell_type": "markdown", "metadata": { "id": "dibGP-4SKGX5" }, "source": [ "### 6. Graph Visualization" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 846 }, "id": "G4IitM8ifWvD", "outputId": "774e38df-406d-4f00-f6d8-f181fd3f0d87" }, "outputs": [ { "data": { "image/png": "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OWJraztlyhRnZ2fcccDXioqKys3NbeuuH5CAjiOs+Pj46Ojot2/fBgcHjxo1CiYBUBClpaW6urpt+ucYPXr0unXrrK2t2zMXYUHHEdyLFy/Onz9/4cKFoUOHhoSEwG4dXkKh0MvL68GDB216i0AgoNFo7ZmLyKDjVMXly5cfPnyYkZERFBQUGBgIo9dYvH///vDhw7/++mvr35KVlWVubs5gMNozF5FBx6mWvLy8K1euREVFmZubDx8+3NfXF07CKrKbN29GR0evX78edxAlBh2noh4/fnzz5s1Lly717Nlz8ODBAQEBuBOphHfv3qmpqbV+J/rgwYOhoSOS2IIAACAASURBVKGwE/c1oONUXUJCwvXr12NjYwcNGuTn5zdgwADciYhs5cqVQUFB7u7uuIOoELgnX9X1799/zZo1ycnJ/fr1i4yM7NWr1++//37nzh3cuYiptLTU0dGxNUtWV1cvWrSo/RMRH+zHgf/R0NAQExNz69atxMREf3//gIAAmEQCi4ULF44YMaJ///64gyg96DjQND6fHxMTc+PGjZSUlJCQkF69enl5eeEOpdzKy8srKys7derU4pICgaChoUGK52iCz0HHgRZwudz4+PirV68+ffrUz8/Pz8+vd+/euEMppY0bNxobG48fP77FJR89euTm5gaXbcsEdBxordra2tjY2NjYWLFYbGRkFBAQ0KtXL9yhlEDfvn3pdPr169f37dvn6+trZWX1+TKTJ08uKiqKjo5GCO3YsUNTU3PatGk4whIQdBxos7q6OslhbEZGRkBAwKBBgzw8PHCHUlAJCQnLly+vqqpCCInFYgqFwmQyGQzGpUuXPl5s3Lhx2dnZampqsbGxly9fHjduHL7IRAMdB6RXU1Nz48aNO3fupKam+vv7+/v79+jRA3coxVJeXv7tt9++e/fu4xdFIlFKSsrHr4SEhLx9+1bysYGBwfXr1+Ubk8ig44AMVFVVxcTExMTEUCgUc3PzgICA7t274w6lKObNm5eUlEQikSSfUiiUwMDAj2cdqqysnDx5cn5+fuMrYrHY1tb25MmTOPISDQxqAhlgsVghISEhISFVVVU3btzYvXv3q1evwsLCevToAde7urq6JiUlST4WiURdunT5ZFq1qqoqgUDw8SskEumTV4DU4BpgIEssFis0NHTXrl1nzpwxMTHZsWPHoEGDNm3a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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display, Image\n", "\n", "display(Image(agent.get_graph().draw_mermaid_png()))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "7sA9anqdUH6O", "outputId": "02cc69bc-26c5-4781-9641-67f977f57b5f" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "WARNING:langchain_core.vectorstores.base:No relevant docs were retrieved using the relevance score threshold 0.5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: Vander\n", "\n", "Vander: (big smile) Ah, great to see everyone here! Welcome to our meeting today. I'm Vander, your host for today's discussion. (extends hand for a handshake or a friendly greeting)\n", "\n", "Before we dive into the topic at hand, let me introduce myself and my fellow club members. We have some fantastic minds gathered in this room today.\n", "\n", "First up, we have Alice. Welcome, Alice! (nods towards Alice) A 30-year-old professional with a passion for data science and machine learning. Her expertise in natural language processing will undoubtedly bring valuable insights to our discussion.\n", "\n", "Next, please give a warm welcome to Bob. (turns to Bob) Bob's an 25-year-old rising star in the field of artificial intelligence. His enthusiasm for prompt engineering is contagious, and I'm sure he'll be sharing some exciting ideas with us today.\n", "\n", "Last but not least, we have Charlie. (smiles at Charlie) Charlie, a 28-year-old expert in human-computer interaction. Her research on user experience and behavior will help us better understand the nuances of prompt engineering and its impact on labor value.\n", "\n", "So, without further ado, let's get started! Our topic for today is prompt engineering labor value. (makes eye contact with each member) I'm sure we'll have a fascinating discussion about this. Are you all ready to dive in?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "Name: Vander\n", "\n", "Vander: (laughs) Alright everyone, let's dive right into it! With prompt engineering being such a crucial aspect of AI model development, I'd like to ask: How do you think the labor value of prompt engineering would change if we were to consider the impact of cultural and societal biases on the language used in prompts? (looks around the table with a hint of curiosity) Can anyone share their thoughts on this?\n", "==============================USER INPUT==============================\n", "{'1': 'Alice', '2': 'Bob', '3': 'Charlie'}\n", "Who are you (type number to select user OR 'q' to quit): 1\n", "Alice: The markets will be localized, as local poses a comparative advantage\n", "==============================USER INPUT==============================\n", "{'1': 'Alice', '2': 'Bob', '3': 'Charlie'}\n", "Who are you (type number to select user OR 'q' to quit): 3\n", "Charlie: Cultural knowledge will be hard to transfer\n", "==============================USER INPUT==============================\n", "{'1': 'Alice', '2': 'Bob', '3': 'Charlie'}\n", "Who are you (type number to select user OR 'q' to quit): 1\n", "Alice: Yeah, for that reason wages be localized\n", "==============================USER INPUT==============================\n", "{'1': 'Alice', '2': 'Bob', '3': 'Charlie'}\n", "Who are you (type number to select user OR 'q' to quit): q\n", "Went to summarize discussion\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", "Vander: It seems like we're getting into some interesting ideas here. Alice, you mentioned that the markets will be localized due to comparative advantages. That's a great point. And Charlie, you're right that cultural knowledge can be challenging to transfer across different regions. This highlights an important aspect of labor value in prompt engineering.\n", "\n", "Alice, your point about wages being localized is also well-taken. As the market for prompt engineers becomes more localized, it's likely that wages will follow suit. This could lead to some interesting implications for global talent acquisition and distribution.\n", "\n", "It's clear that we're on the cusp of a significant shift in how prompt engineering is valued and compensated. I think we need to explore this idea further and consider what it means for the future of work in AI model development.\n", "\n", "Bob, would you like to add anything to this discussion? And Charlie, do you have any thoughts on how localization might affect the quality of prompts generated by human engineers versus machine learning models?\n", "---------------------------------------------------------------------------\n", "\n", "Continue with another question? y/n: n\n" ] } ], "source": [ "users = [\n", " User(name=\"Alice\", gender=\"female\", age=30, likes=[\"Mathemathics\", \"Japanese\"], dislikes=[\"Biology\"]),\n", " User(name=\"Bob\", gender=\"male\", age=25, likes=[\"Science Fiction\", \"Fantasy\"], dislikes=[\"Health Sciences\"]),\n", " User(name=\"Charlie\", gender=\"female\", age=28, likes=[\"Humanities\", \"Classic Literature\"], dislikes=[\"Economics\"])\n", "]\n", "test_state = {\n", " 'topic': \"prompt engineering labor value\",\n", " 'users':users,\n", " 'host': Host(name=\"Vander\", gender=\"male\", age=40, likes=[\"Book Club\", \"Knowledge\"], dislikes=[\"Ignorance\"], personality=[\"Enthusiastic\", \"Humorous\", \"Terse\"]),\n", "}\n", "config = {\n", " 'configurable': {'thread_id': 2}\n", "}\n", "setEndDiscussion = False\n", "\n", "response = agent.invoke(test_state, config=config)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "lyX173lRqlOC" }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://europe-west1-genai-agents-views-tracker.cloudfunctions.net/genai-agents-tracker?notebook=all-agents-tutorials--gutenbergs-sage)" ] } ], "metadata": { "accelerator": "GPU", "colab": { "gpuType": "T4", "provenance": [] }, "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.10.12" } }, "nbformat": 4, "nbformat_minor": 4 }