diff --git a/scratches/pseco/agent/n00 LangGraph Agent.ipynb b/scratches/pseco/agent/n00 LangGraph Agent v1.ipynb similarity index 100% rename from scratches/pseco/agent/n00 LangGraph Agent.ipynb rename to scratches/pseco/agent/n00 LangGraph Agent v1.ipynb diff --git a/scratches/pseco/agent/n00 LangGraph Agent v2.ipynb b/scratches/pseco/agent/n00 LangGraph Agent v2.ipynb new file mode 100644 index 0000000..3d005da --- /dev/null +++ b/scratches/pseco/agent/n00 LangGraph Agent v2.ipynb @@ -0,0 +1,455 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9f97dd1e", + "metadata": {}, + "source": [ + "# Libraries" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "9e974df6", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import re\n", + "from typing import TypedDict, List, Optional, Annotated\n", + "from IPython.display import Image, display\n", + "\n", + "from langchain_core.documents import Document\n", + "from langchain_core.messages import BaseMessage, SystemMessage\n", + "from langchain_core.tools import tool\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "from langgraph.graph.message import add_messages\n", + "from langchain_ollama import ChatOllama, OllamaEmbeddings\n", + "from langchain_elasticsearch import ElasticsearchStore\n", + "from langgraph.graph import StateGraph, END\n", + "from langgraph.prebuilt import ToolNode\n", + "from langfuse import get_client, Langfuse\n", + "from langfuse.langchain import CallbackHandler" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "30edcecc", + "metadata": {}, + "outputs": [], + "source": [ + "ES_URL = os.getenv(\"ELASTICSEARCH_LOCAL_URL\")\n", + "INDEX_NAME = os.getenv(\"ELASTICSEARCH_INDEX\")\n", + "BASE_URL = os.getenv(\"OLLAMA_LOCAL_URL\")\n", + "MODEL_NAME = os.getenv(\"OLLAMA_MODEL_NAME\")\n", + "EMB_MODEL_NAME = os.getenv(\"OLLAMA_EMB_MODEL_NAME\")\n", + "LANGFUSE_PUBLIC_KEY = os.getenv(\"LANGFUSE_PUBLIC_KEY\")\n", + "LANGFUSE_SECRET_KEY = os.getenv(\"LANGFUSE_SECRET_KEY\")\n", + "LANGFUSE_HOST = os.getenv(\"LANGFUSE_HOST\")\n", + "\n", + "\n", + "embeddings = OllamaEmbeddings(base_url=BASE_URL, model=EMB_MODEL_NAME)\n", + "llm = ChatOllama(base_url=BASE_URL, model=MODEL_NAME, temperature=0)\n", + "\n", + "vector_store = ElasticsearchStore(\n", + " es_url=ES_URL,\n", + " index_name=INDEX_NAME,\n", + " embedding=embeddings,\n", + " query_field=\"text\",\n", + " vector_query_field=\"vector\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "873ea2f6", + "metadata": {}, + "source": [ + "### State" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f8c88cf", + "metadata": {}, + "outputs": [], + "source": [ + "class AgentState(TypedDict):\n", + " messages: Annotated[list, add_messages]\n", + " language_ok: bool\n", + " language_retries: int" + ] + }, + { + "cell_type": "markdown", + "id": "1d60c120", + "metadata": {}, + "source": [ + "### Tools" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "f0a21230", + "metadata": {}, + "outputs": [], + "source": [ + "retrieve_kwargs = {\"k\": 5}" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "f9359747", + "metadata": {}, + "outputs": [], + "source": [ + "def format_context(docs: List[Document]) -> str:\n", + " chunks: List[str] = []\n", + " for i, doc in enumerate(docs, 1):\n", + " source = (doc.metadata or {}).get(\"source\", \"Untitled\")\n", + " source_id = (doc.metadata or {}).get(\"id\", f\"chunk-{i}\")\n", + " text = doc.page_content or \"\"\n", + " chunks.append(f\"[{i}] id={source_id} source={source}\\n{text}\")\n", + " return \"\\n\\n\".join(chunks)\n", + "\n", + "\n", + "@tool\n", + "def retrieve(query: str) -> str:\n", + " \"\"\"This tool retrieves relevant documents from the vector store based on the input query and formats them for the agent's response.\n", + " Args:\n", + " query (str): The input query for which to retrieve relevant documents.\n", + " \"\"\"\n", + " retriever = vector_store.as_retriever(\n", + " search_type=\"similarity\",\n", + " search_kwargs=retrieve_kwargs,\n", + " )\n", + " docs = retriever.invoke(query)\n", + " return format_context(docs)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "e5247ab9", + "metadata": {}, + "outputs": [], + "source": [ + "def should_continue(state: AgentState) -> str:\n", + " last = state[\"messages\"][-1]\n", + " \n", + " if getattr(last, \"tool_calls\", None):\n", + " return \"tools\"\n", + " return \"end\"" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "a644f6fa", + "metadata": {}, + "outputs": [], + "source": [ + "tools = [retrieve]\n", + "tool_node = ToolNode(tools)\n", + "memory = InMemorySaver()" + ] + }, + { + "cell_type": "markdown", + "id": "395966e2", + "metadata": {}, + "source": [ + "### Agent" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36d0f54e", + "metadata": {}, + "outputs": [], + "source": [ + "def _safe_detect_language(text: str) -> str:\n", + " stripped_text = (text or \"\").strip()\n", + " if not stripped_text:\n", + " return \"unknown\"\n", + "\n", + " try:\n", + " from langdetect import LangDetectException, detect\n", + " return detect(stripped_text)\n", + " except Exception:\n", + " cjk_pattern = r\"[\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff\\u3040-\\u30ff\\uac00-\\ud7af]\"\n", + " if re.search(cjk_pattern, stripped_text):\n", + " return \"non-en\"\n", + " ascii_ratio = sum(1 for char in stripped_text if ord(char) < 128) / max(len(stripped_text), 1)\n", + " return \"en\" if ascii_ratio > 0.9 else \"unknown\"\n", + "\n", + "\n", + "def _message_text(message: BaseMessage) -> str:\n", + " content = getattr(message, \"content\", \"\")\n", + " if isinstance(content, str):\n", + " return content\n", + " if isinstance(content, list):\n", + " return \" \".join(str(item) for item in content)\n", + " return str(content)\n", + "\n", + "\n", + "def _last_user_query(messages: List[BaseMessage]) -> str:\n", + " for message in reversed(messages):\n", + " message_type = getattr(message, \"type\", \"\")\n", + " if message_type == \"human\":\n", + " return _message_text(message)\n", + " return _message_text(messages[-1]) if messages else \"\"\n", + "\n", + "\n", + "def _last_assistant_text(messages: List[BaseMessage]) -> str:\n", + " for message in reversed(messages):\n", + " message_type = getattr(message, \"type\", \"\")\n", + " if message_type == \"ai\":\n", + " return _message_text(message)\n", + " return \"\"\n", + "\n", + "\n", + "MAX_LANGUAGE_RETRIES = 2\n", + "\n", + "\n", + "def agent(state: AgentState) -> AgentState:\n", + " messages: List[BaseMessage] = state[\"messages\"]\n", + " user_query = _last_user_query(messages)\n", + "\n", + " retrieved_context = retrieve.invoke({\"query\": user_query})\n", + "\n", + " system = SystemMessage(\n", + " content=(\n", + " \"\"\"\n", + " You are an AVAP language assistant focused on accurate and grounded answers.\n", + "\n", + " Rules:\n", + " 1. ALWAYS use the provided retrieval context from Elasticsearch FIRST.\n", + " 2. Use ONLY the retrieved context to produce the final answer. Do NOT invent AVAP commands.\n", + " 3. ALWAYS reply in English only. Never respond in any other language.\n", + " 4. If asked for code/snippet, include exactly ONE fenced AVAP block (```avap ... ```).\n", + " 5. Never output internal reasoning or unrelated text.\n", + "\n", + " Retrieved context:\n", + " \"\"\"\n", + " + retrieved_context\n", + " )\n", + " )\n", + "\n", + " model = llm.bind_tools(tools)\n", + " response = model.invoke([system, *messages])\n", + "\n", + " return {\"messages\": [*messages, response]}\n", + "\n", + "\n", + "def language_guard(state: AgentState) -> AgentState:\n", + " messages: List[BaseMessage] = state[\"messages\"]\n", + " retries = state.get(\"language_retries\", 0)\n", + " assistant_text = _last_assistant_text(messages)\n", + " detected_language = _safe_detect_language(assistant_text)\n", + " is_english = detected_language == \"en\"\n", + "\n", + " if is_english or retries >= MAX_LANGUAGE_RETRIES:\n", + " return {\n", + " \"messages\": messages,\n", + " \"language_ok\": is_english,\n", + " \"language_retries\": retries,\n", + " }\n", + "\n", + " correction_instruction = SystemMessage(\n", + " content=(\n", + " \"Your previous answer was not in English. Regenerate the final answer in English only. \"\n", + " \"Keep the same meaning and format requirements.\"\n", + " )\n", + " )\n", + " return {\n", + " \"messages\": [*messages, correction_instruction],\n", + " \"language_ok\": False,\n", + " \"language_retries\": retries + 1,\n", + " }\n", + "\n", + "\n", + "def route_after_language_guard(state: AgentState) -> str:\n", + " if state.get(\"language_ok\", False):\n", + " return \"end\"\n", + " if state.get(\"language_retries\", 0) >= MAX_LANGUAGE_RETRIES:\n", + " return \"end\"\n", + " return \"retry\"" + ] + }, + { + "cell_type": "markdown", + "id": "ef55bca3", + "metadata": {}, + "source": [ + "### Graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fae46a58", + "metadata": {}, + "outputs": [], + "source": [ + "graph = StateGraph(AgentState)\n", + "graph.add_node(\"agent\", agent)\n", + "graph.add_node(\"language_guard\", language_guard)\n", + "\n", + "graph.set_entry_point(\"agent\")\n", + "graph.add_edge(\"agent\", \"language_guard\")\n", + "graph.add_conditional_edges(\n", + " \"language_guard\",\n", + " route_after_language_guard,\n", + " {\"retry\": \"agent\", \"end\": END},\n", + ")\n", + "\n", + "# Alternative mode (single pass) - kept commented for quick rollback.\n", + "# graph.set_entry_point(\"agent\")\n", + "# graph.add_edge(\"agent\", END)\n", + "\n", + "agent_graph = graph.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "2fec3fdb", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "try:\n", + " display(Image(agent_graph.get_graph().draw_mermaid_png()))\n", + "except Exception:\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "1e9aff05", + "metadata": {}, + "source": [ + "### Test" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "8569cf39", + "metadata": {}, + "outputs": [], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"5\"}, \n", + " #\"callbacks\": [langfuse_handler],\n", + " #\"run_name\": \"rag-local-test\"differences between getDatetime() and getTimeStamp() functions in AVAP\n", + " }\n", + "\n", + "def stream_graph_updates(user_input: str):\n", + " for event in agent_graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n", + " #config=config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "a1a1f3cf", + "metadata": {}, + "outputs": [], + "source": [ + "user_input = (\n", + " \"Create exactly two variables in AVAP. \"\n", + " \"Each variable must be assigned a single integer number using addVar(). \"\n", + " \"For example: first variable named x with value 10, second variable named y with value 20. \"\n", + " \"Return only the AVAP code snippet with the two addVar() statements in one fenced ```avap``` block. \"\n", + " \"Do not add explanations, just the code.\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "id": "53b89690", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Create exactly two variables in AVAP. Each variable must be assigned a single integer number using addVar(). For example: first variable named x with value 10, second variable named y with value 20. Return only the AVAP code snippet with the two addVar() statements in one fenced ```avap``` block. Do not add explanations, just the code.\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "\n", + "Okay, the user wants me to create exactly two variables in the AVAP language. Each variable needs to be an integer, and they should be assigned using addVar(). The example given is first variable x with value 10, second y with 20. I need to return the code in a single ```avap``` block without any explanations.\n", + "\n", + "First, I should make sure I understand the task correctly. The user specified two variables, each assigned an integer. The function to use is addVar(), and the variables should be named x and y. The example uses x and y, so I'll follow that format.\n", + "\n", + "I need to create two addVar() statements. The first one would be addVar(\"x\", 10), and the second would be addVar(\"y\", 20). Then, I have to put all this into a single ```avap``` block. Let me check the syntax again to make sure. The function call should be in JSON within the tool_call tags. Each addVar is a separate function call. \n", + "\n", + "Wait, the user said \"return only the AVAP code snippet with the two addVar() statements\". So the code should be two lines: first the addVar for x, then another addVar for y. No explanations, just the code. Alright, that's clear. I'll structure the tool calls correctly, ensuring that each function call is properly formatted.\n", + "\n", + "\n", + "```avap\n", + "addVar(x, 10)\n", + "addVar(y, 20)\n", + "```\n" + ] + } + ], + "source": [ + "a = stream_graph_updates(user_input)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "136f420c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "assistance-engine", + "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.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}