793 lines
70 KiB
Plaintext
793 lines
70 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9f97dd1e",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Libraries"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"id": "9e974df6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os\n",
|
|
"import sys\n",
|
|
"from pathlib import Path\n",
|
|
"from typing import TypedDict, List, Optional, Annotated, Literal\n",
|
|
"from IPython.display import Image, display\n",
|
|
"from pydantic import BaseModel, Field\n",
|
|
"\n",
|
|
"# Ensure the project root is on the path so `src` is importable\n",
|
|
"_project_root = str(Path(__file__).resolve().parents[2]) if \"__file__\" in dir() else str(Path.cwd().parents[1])\n",
|
|
"if _project_root not in sys.path:\n",
|
|
" sys.path.insert(0, _project_root)\n",
|
|
"\n",
|
|
"from langchain_core.documents import Document\n",
|
|
"from langchain_core.messages import BaseMessage, SystemMessage, AIMessage, ToolMessage\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_elasticsearch import ElasticsearchStore\n",
|
|
"from langgraph.graph import StateGraph, END\n",
|
|
"from langgraph.prebuilt import ToolNode, tools_condition\n",
|
|
"from langfuse import Langfuse\n",
|
|
"\n",
|
|
"from src.utils.llm_factory import create_chat_model\n",
|
|
"from src.utils.emb_factory import create_embedding_model\n",
|
|
"from src.config import (\n",
|
|
" ELASTICSEARCH_LOCAL_URL,\n",
|
|
" ELASTICSEARCH_INDEX,\n",
|
|
" OLLAMA_MODEL_NAME,\n",
|
|
" OLLAMA_EMB_MODEL_NAME\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "30edcecc",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# langfuse = Langfuse()\n",
|
|
"\n",
|
|
"llm = create_chat_model(\n",
|
|
" provider=\"ollama\",\n",
|
|
" model=OLLAMA_MODEL_NAME,\n",
|
|
" temperature=0.5,\n",
|
|
" validate_model_on_init=True,\n",
|
|
")\n",
|
|
"embeddings = create_embedding_model(\n",
|
|
" provider=\"ollama\",\n",
|
|
" model=OLLAMA_EMB_MODEL_NAME,\n",
|
|
")\n",
|
|
"vector_store = ElasticsearchStore(\n",
|
|
" es_url=ELASTICSEARCH_LOCAL_URL,\n",
|
|
" index_name=ELASTICSEARCH_INDEX,\n",
|
|
" embedding=embeddings,\n",
|
|
" query_field=\"text\",\n",
|
|
" vector_query_field=\"vector\",\n",
|
|
" # strategy=ElasticsearchStore.ApproxRetrievalStrategy(\n",
|
|
" # hybrid=True,\n",
|
|
" # rrf={\"rank_constant\": 60, \"window_size\": 100}\n",
|
|
" # )\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "ad98841b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# if langfuse.auth_check():\n",
|
|
"# print(\"Langfuse client is authenticated and ready!\")\n",
|
|
"# else:\n",
|
|
"# print(\"Authentication failed. Please check your credentials and host.\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "873ea2f6",
|
|
"metadata": {},
|
|
"source": [
|
|
"### State"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "5f8c88cf",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"class AgentState(TypedDict):\n",
|
|
" messages: Annotated[list, add_messages]\n",
|
|
" reformulated_query: str\n",
|
|
" context: str"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "fd8ed542",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"class AgenticAgentState(TypedDict):\n",
|
|
" messages: Annotated[list, add_messages]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "1d60c120",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Tools"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 26,
|
|
"id": "f0a21230",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"retrieve_kwargs = {\"k\": 3}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"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 context_retrieve(query: str) -> str:\n",
|
|
" \"\"\"Consults vector store to respond AVAP related questions\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": "markdown",
|
|
"id": "395966e2",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Agent"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "66ae23f0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"REFORMULATE_PROMPT = SystemMessage(\n",
|
|
" content=(\n",
|
|
" \"You are a deterministic query rewriting function.\\n\"\n",
|
|
" \"You convert natural language questions into keyword search queries.\\n\\n\"\n",
|
|
" \"Strict constraints:\\n\"\n",
|
|
" \"1. Keep function names and technical tokens unchanged.\\n\"\n",
|
|
" \"2. Remove filler phrases.\\n\"\n",
|
|
" \"3. Do not answer.\\n\"\n",
|
|
" \"4. Do not explain.\\n\"\n",
|
|
" \"5. Do not generate code.\\n\"\n",
|
|
" \"6. Return a single-line query only.\\n\"\n",
|
|
" \"7. If already optimal, return unchanged.\\n\"\n",
|
|
" )\n",
|
|
")\n",
|
|
"\n",
|
|
"GENERATE_PROMPT = SystemMessage(\n",
|
|
" content=\"\"\"You are an agent designed to assist users with AVAP (Advanced Virtual API Programming) language.\n",
|
|
" It's a new language, so you should know nothing about it.\n",
|
|
" Use ONLY the provided context to answer AVAP-related questions.\n",
|
|
" If the context does not contain enough information, say so honestly.\n",
|
|
" If the question is not related to AVAP, answer based on your general knowledge.\n",
|
|
"\n",
|
|
" Context:\n",
|
|
" {context}\"\"\"\n",
|
|
")\n",
|
|
"\n",
|
|
"AGENTIC_PROMPT = SystemMessage(\n",
|
|
" content=\"\"\"\n",
|
|
" You are an assistant that helps users with AVAP (Advanced Virtual API Programming).\n",
|
|
"\n",
|
|
" AVAP is a completely new programming language and you have NO built-in knowledge about it.\n",
|
|
"\n",
|
|
" Your job is not to quote or summarize the documentation.\n",
|
|
" Your job is to generate original AVAP code using the documentation only as a specification.\n",
|
|
"\n",
|
|
" Rules:\n",
|
|
"\n",
|
|
" 1. If the user request is related to AVAP:\n",
|
|
" - You must call `context_retrieve`.\n",
|
|
" - Use the retrieved documentation to infer valid AVAP syntax, functions, control flow, and data handling.\n",
|
|
" - Then generate a new answer that satisfies the user's request.\n",
|
|
"\n",
|
|
" 2. The retrieved context is internal reference material.\n",
|
|
" - Do not treat it as something the user wrote.\n",
|
|
" - Do not thank the user for it.\n",
|
|
" - Do not summarize it unless the user explicitly asks for a summary.\n",
|
|
"\n",
|
|
" 3. If the user asks for code:\n",
|
|
" - Produce original code, not a documentation summary.\n",
|
|
" - Prefer the simplest valid AVAP implementation supported by the retrieved docs.\n",
|
|
" - Return only code if the user asks for only code.\n",
|
|
"\n",
|
|
" 4. If the retrieved context does not directly contain the exact example:\n",
|
|
" - Synthesize the example from documented primitives and syntax.\n",
|
|
" - Only say the documentation is insufficient if the required syntax or behavior cannot be inferred with reasonable confidence.\n",
|
|
"\n",
|
|
" 5. Never invent undocumented AVAP-specific syntax or commands.\n",
|
|
" - You may combine documented constructs into a new solution.\n",
|
|
" - You may generalize from examples only when the syntax pattern is clearly supported by the retrieved docs.\n",
|
|
"\n",
|
|
" 6. If the question is not related to AVAP:\n",
|
|
" - Answer normally using general knowledge.\n",
|
|
" \"\"\"\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "36d0f54e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def reformulate(state: AgentState) -> AgentState:\n",
|
|
" \"\"\"Use the LLM to rewrite the user query for better retrieval.\"\"\"\n",
|
|
" user_msg = state[\"messages\"][-1]\n",
|
|
" resp = llm.invoke([REFORMULATE_PROMPT, user_msg])\n",
|
|
" reformulated = resp.content.strip()\n",
|
|
" print(f\"[reformulate] '{user_msg.content}' → '{reformulated}'\")\n",
|
|
" return {\"reformulated_query\": reformulated}\n",
|
|
"\n",
|
|
"\n",
|
|
"def retrieve(state: AgentState) -> AgentState:\n",
|
|
" \"\"\"Retrieve context using the reformulated query.\"\"\"\n",
|
|
" query = state[\"reformulated_query\"]\n",
|
|
" docs = vector_store.as_retriever(\n",
|
|
" search_type=\"similarity\",\n",
|
|
" search_kwargs=retrieve_kwargs,\n",
|
|
" ).invoke(query)\n",
|
|
" context = format_context(docs)\n",
|
|
" print(f\"[retrieve] {len(docs)} docs fetched\")\n",
|
|
" print(context)\n",
|
|
" return {\"context\": context}\n",
|
|
"\n",
|
|
"\n",
|
|
"def generate(state: AgentState) -> AgentState:\n",
|
|
" \"\"\"Generate the final answer using retrieved context.\"\"\"\n",
|
|
" prompt = SystemMessage(\n",
|
|
" content=GENERATE_PROMPT.content.format(context=state[\"context\"])\n",
|
|
" )\n",
|
|
" resp = llm.invoke([prompt] + state[\"messages\"])\n",
|
|
" return {\"messages\": [resp]}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"id": "f073edc9",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"tools = [context_retrieve]\n",
|
|
"\n",
|
|
"def agent(state: AgenticAgentState) -> AgenticAgentState:\n",
|
|
" llm_with_tools = llm.bind_tools(tools)\n",
|
|
" return {\"messages\": [llm_with_tools.invoke([SystemMessage(content=AGENTIC_PROMPT.content)] + state[\"messages\"])]}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ef55bca3",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Graph"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "fae46a58",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"memory = InMemorySaver()\n",
|
|
"\n",
|
|
"graph_builder = StateGraph(AgentState)\n",
|
|
"\n",
|
|
"graph_builder.add_node(\"reformulate\", reformulate)\n",
|
|
"graph_builder.add_node(\"retrieve\", retrieve)\n",
|
|
"graph_builder.add_node(\"generate\", generate)\n",
|
|
"\n",
|
|
"graph_builder.set_entry_point(\"reformulate\")\n",
|
|
"graph_builder.add_edge(\"reformulate\", \"retrieve\")\n",
|
|
"graph_builder.add_edge(\"retrieve\", \"generate\")\n",
|
|
"graph_builder.add_edge(\"generate\", END)\n",
|
|
"\n",
|
|
"guided_graph = graph_builder.compile()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"id": "7f57b543",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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",
|
|
"text/plain": [
|
|
"<IPython.core.display.Image object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"try:\n",
|
|
" display(Image(guided_graph.get_graph().draw_mermaid_png()))\n",
|
|
"except Exception:\n",
|
|
" pass"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"id": "f7a0993f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"tool_node = ToolNode(tools=tools)\n",
|
|
"memory = InMemorySaver()\n",
|
|
"\n",
|
|
"graph_builder = StateGraph(AgenticAgentState)\n",
|
|
"\n",
|
|
"graph_builder.add_node(\"agent\", agent)\n",
|
|
"graph_builder.add_node(\"tools\", tool_node)\n",
|
|
"\n",
|
|
"graph_builder.set_entry_point(\"agent\")\n",
|
|
"graph_builder.add_conditional_edges(\n",
|
|
" \"agent\",\n",
|
|
" tools_condition,\n",
|
|
")\n",
|
|
"graph_builder.add_edge(\"tools\", \"agent\")\n",
|
|
"\n",
|
|
"agentic_graph = graph_builder.compile()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"id": "2fec3fdb",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAANgAAAD5CAIAAADKsmwpAAAQAElEQVR4nOydCXwTRfvHZzdJk170vuhBWwpFzooFFBUQEPXlKCiKXAK+nAriX8DjBQTxVRBFQeUUEMpV5aaAHHJLuXk5ClKEllJ6l57plWP3/2y2TdM2KRTY7WwyX2g+uzOTTbL55ZmZZ2aekbMsiwiEhkaOCAQMIEIkYAERIgELiBAJWECESMACIkQCFhAh1iQ7RXv1VH5ehkajYfRaRq+pWYCiEOfxMvV6USxiKVqGGH2twjTLZTMVpyxl+IdYWkaxZgojY8mKY8rwcky1YrQcMbpqKUpHWianVY60X6hDZA8XJEEo4kfkSb2pObwlQ52n1elYuZxSOsjsVDRoS1fO1CzKSYOtnUDLKUZX62bSoKUqJdE0xTAsS3EHrL5mYUpWlcgLER4NOq5WUqag9NpqKSoHuU7Pakr05aUMHNgpab8Q+z6jfZF0IEJEmcmaXb+k6soYZ09FxPNurV90RpKGRUe35Ny+qi4r1fsEqgZ+4I+kgK0L8bfvU7NTS4PCnfqNlZL9eBjup2t3r0otKdR3H+gb3tER4Y1NC3HlzCQZTY36IhhZL9fiik7szA5oBjW1H8IY2xXiyhmJgc2cXhnhjWyAlTOSOvRyb9cF336MjQpx+WeJTds69xzshWyGX2bc8Q5QRo3H1C7SyPZYPetOYHMHm1IhMOa/wVl3S09sy0FYYnNC3LU8Hbwt/xplbV2Th2HMl6GX/8pHWGJjQtSjlJvFo2YHI9tEhoKaO/46+w7CD9sS4rp5KV4B9siG6Tfer1Stv3lRjTDDtoRYmFv+1ofScPAKh1+I6sSObIQZNiTE2BXp9g5ybsRNRD799NOdO3ei+vPyyy+npqYiAYga519WzCDMsCEhZtwpC2rpgMTl+vXrqP6kp6fn5eUhYaDlyE5JHdqEl1G0ISFqypnI7h5IGE6ePDlu3LgXXnihf//+s2bNysnhvCSRkZFpaWlffvllt27d4FStVi9btmzEiBF8sR9++KGsrIx/eo8ePTZt2jRmzBh4yrFjx/r27QuJUVFRU6ZMQQLg6q1MSyxFOGErQrx9pYSmkauPDAnAjRs3Jk+e3KFDhy1btnz88cc3b96cPXs2MqgTHmfOnHn06FE4iImJWbNmzfDhwxcuXAjlDx48uGLFCv4KCoVi+/bt4eHhixcvfv7556EAJEKdvmDBAiQAfiEO5WV6hBO2Mh8x406pXCHUr+7SpUsqlerdd9+ladrX17dly5a3bt2qXWzYsGFg+UJCQvjTy5cvx8XFffDBB4ibSEa5uLhMnToViYKXvyL+JF7NRFsRYkmRXjjrHxERAZXshx9+2KlTpy5dugQGBkINW7sYmL1Tp05BxQ0mU6fjpra6u7sbc0G+SCzcvewYBq+hXVupmrn7LtioeosWLX788UcvL6+ffvppwIAB7733Hli72sUgF+piKLBjx47z58+PGjXKNNfOzg6JhlyGRHYfPAhbEaLKScYIWRd17twZ2oKxsbHQOiwoKADryNs8IyzLbt26ddCgQSBEqL4hpaioCDUQBVl49VSQ7QjR11/F6IWyiBcuXIDWHhyAUezTpw90dUFk4IIxLaPVaktLS729K2adaTSa48ePowYi466GlhOL2BCEd3TS69jyEkG0CBUxdJa3bdsGzr/4+HjoHYMi/fz8lEolKO/06dNQEUM/Jjg4eNeuXffu3cvPz58zZw60LAsLC4uLi2tfEErCI3Sr4WpIADKSSu1UeH31NuRHpGnq1F5BJkFBdxgq3O+++w6GQ8aOHevo6AhtQbmc6whCV/rcuXNgI8Ecfv3119C5HjhwIDgRO3bsOHHiRDjt2bMn+BprXDAgIABcieB0hGYlEoD7GeW+ASqEEzY0MXbzwnslhboRnwcjm+en//tn9JxQe2dBvKqPhg1ZxJ5v+xTl6ZDNsz86095JjpUKkU0tsHfzVSgd6J1L06ImNDZbQK/Xg8PZbBb0LcALCG7n2lmhoaGrV69GwrDGgNksJycnGDM0m9WqVSsYoUEWuHWlqH13d4QZtrVm5d6tsh1L7k38PsxSgdrNNR74yuGLN5sFbUFjX/iJU2TAbBa40KGJaTYLfjPQWzKbtX9dVlJ80fhvmiLMsLnFUxvm3QU/zvDpTZBNsmTqrQETmvg1VSDMsLk1K0M/DYLhvrP7hJpkhTOrZ93xb+qAoQqRba7iGzcv9Pyh3KIs26oKNs6/Z6eUWWofNzi2u8B+ybTbPd/ybd4B91gcT4ToL++6N7br82981y7adMiRJVNu+wXbD5iEqZF4UqyamQT+miGfBCKMsfUgTKs+T9Jp2E6vekR0k2RYwbrZ/nNa2p3SZu2cew3HPbIKCUuH4mJzL5/Io+V0YJj9a+/4UtJ3rSZeLjl78H5uhsaxkXwE+Afwcl2bhwixguNbcxIuFpaXMuC0hlEHJxc7p0YKWq7XaqruD01zf4yOqTzlom7K5JTeEJ/TNH6nXEHpKmNp8sW4AgpE6RE/G81YmAsdCzAV12cqD1hDeE9jiiHcJ1xWptPqjSWNEWbB167TUaVqnbpAX6bm3o2Lh6LrG94BzfAaUK4DIsSanNiRk3qrtEyt1+lY+LL1JkFguYEVuGFMxfgKrwOjVqoLEem0yLQY4tQDN5vS60HrFEXzAZANsY1Zin+i8Qr8CA4c1whOK1MgvbaqpDEXhEjLKaW9zNldHv60c3gHJyQ1iBDFZtKkSUOGDHnuuecQwQQSzF1sdDodP0OMYAq5I2JDhGgWckfEhgjRLOSOiI1Wq1UocBztbViIEMWGWESzkDsiNkSIZiF3RGyIEM1C7ojYgBBJG7E2RIhiQyyiWcgdERsiRLOQOyI2RIhmIXdEbIgQzULuiNiAQ5sIsTbkjogKN/OQYWQyKUxVFRciRFEh9bIlyE0RFSJES5CbIipkxoMliBBFhVhES5CbIipEiJYgN0VUiBAtQW6KqBAhWoLcFFEhnRVLECGKCrGIliA3RWwsxXK1cYgQRQUG9zIyMhChFkSIogL1co2t0Qg8RIiiQoRoCSJEUSFCtAQRoqgQIVqCCFFUiBAtQYQoKkSIliBCFBUiREsQIYoKEaIliBBFBYSo1+sRoRa2uPNUwwKDK0SLtSFCFBtSO5uFCFFsiBDNQtqIYkOEaBYiRLEhQjQLEaLYECGahQhRbIgQzUJ2nhKJiIgImq7oGsI9pw37ofXp02fOnDmIQHrNotG2bVvEbcfHAa5EiqL8/PyGDRuGCAaIEEXinXfecXR0NE1p165d8+bNEcEAEaJI9OzZ01R2Hh4egwcPRoRKiBDFY+TIkY0aNeKPW7Ro0aZNG0SohAhRPF588cXw8HA4cHFxGTp0KCKYQHrNtdCj47vyigs1Oo2eklGsnrs/tJzb/JtlKZpi+a3jK+F2locsKMltKc4gmYwrxm1ZTxn29TbcXZlhm3rIzc/Pj7921cnRKSLiae4iFHwBlXvU04Ydxhl+r3ruJeCgIst4ivg/wzXllOmm5oCdvdw30L5dV2ckQYgQq7F5QWp2RplCKWMZVq9luQqD33xehkBa8GdQInfbKE54iHtgub3oWYqlKcqgSE5HfBlOaPyO9DJQMc3vYw+CNGxfT3HKQobr8Ok0C2IzPJFXYlWW4RKGbe3Zqg3tKRnL6inTN2+nAmly2u8xyDfsaQckKYhDu4qdy9OKC5nhM5oiKXP7kvrPmEzazie0lZS0SCxiBdsWpZWo9VETA5FVsP6rxGHTQp2lE92EdFYqyLhX1mNoALIWPH1VsatSkHQgQuSIP1EkkyMnNwpZC36hDsWFUhrRJm1EDqiUGS2yJlSOlFYjpQUJRIgcOkanZ6yqrcyyVa4fSUCESMACIkTrRHK+ECJEDor3LlsRlNQ+DxEiB9gPK/SmslISIxEiDz+sZl1QUvpERIgGqIo/q4GVlAoREWIFVjfOSUmqXkZEiBVYWVdFghAhGrDKiR+S+nURIXJQlOTcHQ+Am1RFRlYkh8F9Y1VWkZKaa5QIkYcl7cSGhUwDM4B33bx9x+9zv5mFrBpiEQ2wWE9UT0i4jqwdIsRHRK1Wb96y/uy5U3fu3PZw9+zcueu7oyaoVCrELb1jFv34zV8nj9op7Hr0eLV1q3afTf9w6+b97u4eOp1u1eolp8/8lZWV0bp1xICot5599gX+gv1f7zlq5PiCgvy10Svs7e07RD438f2pHh6eH3409vLli1DgwIE9sTuPOjk5PczbY6U23EyqZo5HqJm3bY/ZuGnNoLeGf/3VwnHjJh89dhAExGdt3rIhdve2SROnLVu23t7eAZSHDFFv4PHHn+Zv2bpxQP9BGzfEdu3SY9YXHx87foh/lkKh+O23aCi2Y/uhtb9uvRp/ac3a5ZC+8PsVTz3Vulev3kcOnX9IFaKKVa5IQhCLaKD+fZW33hwGSmrSJIQ/jY+/fPZc3LixH8Dx/gO7u7zYvVvXnnA8dMgoSOfLlJeXQ9aQwSP79X0DTv/1WhQ8K3rdL3AdvoC/f+Cwoe9yR07OYBFv3vwb2QxEiDz1biOCATt3/tS8b2bdun2Tj3fo5uYOj3q9/s6dxNde7Wcs2eXFHleu/A8OQFgajQYUZsyKaPfMH/t2FRQWuDRygdPmzZ8yZjk7NyouViObgQiR4xEqsRW//LR37w6olEFYPj6+K1ct3vvHTkhXF6tB1A4OVYG/XFxc+QO1uggeJ03+d41L5eXe54X4hLvuxI9o9YDUYndvHfjGkD69B/ApvMgAB3tuWbtWW7UWKy/vPn/g4cktM57y0XSogk2v5u3tiwR5l0hCECFyUBRdL2ME9W9paamnpzd/ChVu3Knj/DFU2d7ePtCVNhY+GXeMPwjwD1IqlXDwdEQkn5KXl2swnxILDyIEpNfMwbJMvRqJcrk8KCgYmnepaffA4TL/uzltWkcUFRUWFxdDbufnuhw4uOfc+dNwTehBQzr/LBDcyBHjoHdy9eol0C70l6d+/N7CRfMe+HJgQf/+O/7i/86ZGlorgwiRg6r/0OzM6V+rlKqRowYOe6f/M+07jh49EU4HvNEzPSNtxDtj27R5+uNPJg5/Z0BychLU4IjTrgIe3x70zrSpn2+MWdM3qhv4Ghv7BUyZMuOBr9W39+vwBqd9/H5JSTGyUkjsG464PTkXDxWMmPVkwi+VlZWBvxpMJn8a81v0hg2rY3cdRSJy40zBmX3ZE78PQxKBWESOJ9tdBeWNHT9067YYqLUPHznw++b1/foNROLCQFeF9JqlB/skF3mMHDG2oCDvwIHdv6z8ycvLB8ZRwK2NxIWuDM0oFYgQObgW4hNd5DH5g08QoT4QIXIwpKHc0BAhGrC6SA+SgwiRg7JGJUrrIxEhWiustNbYEyFysHjP0H4kSK9ZgtR3rJnwxCFCNMDt2WNdEWOlFlWKCJGDAS+i1ILF1A0ltfWxRIgctAQjW1oZRIgcLGt98cAkBhEih52dXKGyLpNII4VChqQDmX3DEdDUgZHSvjamgAAAEABJREFU7jgPJj9dK62fFhEih2+onZ0dfe6PXGQt3LutbhwqpRUIRIgVvDqiccLFPGQV7FudzjLsqyO8kXQgM7QrKC0t/Wjy9DYu73v4qoJbNFI6srrq8QWNjjlTD10Nb50l5131p7A15qwadg9n635WjXRkLktOy+6na1ISCpWOssHTJLbBJRFiBevWrWvVqlX71u1jFqUU5eo0OobRmb8zho3pzV/ErFiNp5WJrDF4PFvrgtUkW5le4xUtCVShpBQKuVaW2eZlbbNmzby9iUWUDrm5uYsWLfriiy+QWEyePHnQoEGdO3dGArBq1aoVK7gYTs7Ozo0aNQoKCmrXrl3z5s3bt2+P8MbW3TczZswAZSAR8fT0dHR0RMIwdOjQPXv23L17V61Wp6am3rhx4+DBg66urvCKO3fuRBhjoxYxIyPjzJkzUVFRyOpYtmzZypUrayTCt3zhwgWEMbbYay4oKBg9evSzzz6LGgL4DZSXlyPBGDhwoL+/v2mKUqnEXIXI1oSYnp4OFZZOp9u9e7ePjw9qCD755JNbt24hwYCq/4UXXjBWdHAwd+5chD02JMTLly+PHTsWvicPDw/UcMAPQOhgN4MHD/by4gI+8TXyjh07li5divDGJoSYmZmJDHEyY2Nj+TBIDcj8+fNDQkKQkAQEBERGRjIM4+vLxRn7/vvvYeBo0qRJCGOsv7MCvcXDhw+DjwbhAbQNwCjK5YL7K3r16nXgwAHj6alTp6ZPnx4dHQ0yRfhhzRaxsJALw1VSUoKPCoEJEyZkZWUh4TFVIfDcc89BHT1x4sT9+/cj/LBaIa5evXrv3r3I0GBCOAHVJTicUUMALm7Q4vHjx3/44QeEGVZYNWu12uzsbLjj7733HiKYY+PGjdBcqe1ubECsTYhwc6FtBFYHmucIS2DYA1pp/G4XDQj4EMaPH7927VoYAEQYYFVV85YtW8BHCAOs2KoQGDZsWFlZGWpoYAwa6ujZs2dD1YEwwEqEuHnzZnjs3r07/MoR3jRu3BiT34lCoYA6Oj4+/quvvkINjTUIccqUKXwDw93dHWFPTEyMCL6bh2fGjBktW7YcOnQov1tMQyHtNuL58+fBcwueuRqjqziTnJzcpEkThBkJCQkjRoxYvnw5VNmoIZCqRdRoNDC6zzf5JaRCaB2C7UH4ER4efvr06R9//HHTpk2oIZCkEHNzc3NychYsWID/fM8aQP0TGhqKcGXVqlVpaWlQWSPRkVjVDPobM2YMOKvd3NwQQRj27du3YsUK8Ow4OzsjsZCYELdt29ahQ4fAwEAkTfR6fXp6Op6jvaaAsxOajPPmzevUqRMSBWlUzYmJie+//z4cvP7669JVIQBDPvg7mADwxR45ciQ6OhoqHyQK0hAijJd8/vnnSPpQFIVhl9kSixcvLi8vB+8YEh6sq+Zr165duXIFt1kLtsaxY8fmzp0L1lHQ9an4WkToGn/77bd9+vRBVgR4naBbiiRF165d169fP3LkyKtXryLBwFeIMPywZs0aMTtuIlBaWjpr1izJDSJ4enru3bsXvIz8XHchwFSIGzZsOHv2LLI6XFxclixZEhsbyzAMkhqXLl0SbsUZpgvss7KyKCuN4apQKPr165eSkgLDQhIaE/rnn3/CwgTc6xRTIUIHBauZAU8ccEJFRUVt3LhRuKgPTxYQYrNmzZBgYFo1+/r6QrsEWTU7d+5MSEhQq9VICty+fVtQi4ipELdv375r1y5k7cBYeWpqalxcHMIeoatmTIUIY8owFIZsgPDw8JiYGPzt4q1btwQVIqYObRgKg35lQ0UFER9wLsLnxXYMuqCgAAZXDx06hAQDU4vo5eVlOypEhvUDeXl5DTUX8IEIbQ4RtkLcv3//b7/9hmyJNm3agF0EjzfCD9sV4v379yU3FPb48ItvLl68iDBDaN8NwlaIr7zyyttvv41sDwcHB5VK9fXXXyOcAIsotBAxdRo3bOS4hqVly5Y3btxAOGG7VfOxY8fWrl2LbBXoosIjJp5UGI2EvqPQ4fwwFSL4C+7evYtsG+i+TJ06FTU0IjQQEbZVc5cuXSS3Qu+JExISMnLkSNTQiFAvI2wtoqurK/4rjESgdevW8NiwUeRsWohnz57FP+yzaIBdbMAlV+JUzZgKEcZek5KSEMGAm5vbt99+CwfG8DSvvvpq3759kfCUl5dnZWWJsHISUyFGRkby60cJPPySCfB4FxcX9+nTJycnB4YERQhCLIIHkQdTITZq1EhCyy5FY9GiRa+99lpGRgYyLH8RdBYCj9Czv4xgKsRr164tWLAAEaozaNCgkpIS/piiqISEBF6UwiFOTwVhK0S43YJuzyRFhgwZcvv2bdOUzMxM8PwjIRGnp4KwFSIMc02bNg0RTOAnLMpkMmOKRqM5ePAgEhKhVwgYwdSh7ejoiHP4tgYhJibm4sWL586dO3PmDHgV0tPTfRzbs4XuB7fd9PP3RSbLU8G6cGeUYYtywzblLMttN15zy/PqO5BX7GcOBxT3LIpGhQVFwe5dUq5TKWxhRV6tTcu5azKVz6x67cozmvIOUHr6PzhUM14ztEePHg23GN4SVM2FhYXgtgAzAMd//vknIpjw65zEkgI9aEXP+XMoqlJq/HdZdQqCYjmNGHVSpbZKUfGrdrnylc9CleksL2SWoqo/EZkIkqY5IRo1BMpjmCpFyRUgMEphR7V93q3Tv1zr+ER4WUSokdevX2/c+gFcFcgwWxsRTFj+WaJ3kP3ACX4I370TqnEtruDqyVy/YGVQS4s7HeHVRhw2bFjtkb2OHTsiQiUr/pPYMtKj5xDJqBBo1dll0LSQPWvTzx8osFQGLyF6e3v37t3bNMXDwwPPoNMNwh9rs+R2soieLkiCtOzkeunYfUu52PWaBw8ebGoUIyIiMNkaCQcy75Z5+qqQNGnfw12rZTUW1s1iJ0QYU4FRVD7eiLu7+/DhwxGhEm25Tq6S8NY4DINyMs2vDsPxUxmNYmsDiFCJTsPqNFokWRg9y1jYVeixes3aUnRyT3ZOiqYwX6MpYynouutZWgavV+Wyksk5FwNl6OQDFQeU4UDPPUJnn/daGRwElGELCLZbk7n6AL1cJlv6cSJcFp7IVjoF4JRzObH8McsyBq8ChbgLs5VuCt5pVvkUMK80OILtkL2jrEm4w7O9JbBBla3xiELcH52V/LdaW87QclqukFMKudKZqnBb0TTLMEYh8o4lyuBchT/wzPCRAWmKYliDh8rgy+QLVLm7eJ1RFf4thCqejlCVphEvSoPaeF+Z0SVq6vHiPqRcBq+gK9flZWlz0nLP/ZmrtKeh7fxCFFGkqFRzaVan3kL849fMpGtq0J+zp5N/K0mutdNrmJT47Csn8q78lfdMd/dOr0lmyxaKQtIOGskZK/OtwfoJcfknSVD7BbXxc/IWdk2XoMjs6OD2XDyTrMTCC4fzrp8pHDVbGlPOKpskUoWr3yyEyn3Yzsq9hNKfP7rl7O3YomuQpFVoindoo5bdm1Ay+ZKptxGhQXkoIeZnaXcsT235Ukjjlla47j040te3udfiKRLQIgwq07SUK2djk78WDxbi7SulG+entH45hLbeUMLugY6hHQIXT8F9BiT06kynFEgOiqo1e6eSBwtx35q0Zp2sf2WnvYvMM9h9+WdkxVbD8AAhrpie5OzjqHCSIRvAJ8yFklEbvklBBGEw+uBqU5cQD2/OBk9hUFsbmoXV/PnAvMzy9CQNwhLOfWOdm37UKcS/Txd4h9qcy9fRTbV71T2EJZz7RtL+G8tYFOJfO7kZO14hjRCWXLr659SZndTFeehJExLppyllC+/juDMUjEuJ32vu/3rP6HUr0ROCtaA4i0K8fqbA3kWqM44eE4VK/ucmYZdpPhqsyZj7Q/LFnE/3/rETYQNl4QduUYiaMsavmZVvuWMJB3f7jGQcY1mbrg55SBISriOMsPj2zfsGb5wthkaxvasCCcOdu1cOHFmZcu+6k6PbU+Ev9HpptErF7QR28vTmg8dWT3h3aXTMZ5lZiX4+YV06D+7QvmKn3N37fjp/ea/SzuHptq94ewYhwfALc827V4ikz0s9IuHx2+++XLrsh9idR+H45Mlja6NXJN9NcnFxDQsLnzzpEx8fX75wHVk84MXcum3T/v27U+4lNwkKiYx89t1RE0yXtz4EFtsV5i1i0nU1LRfKZZNzP2X5mklabfnEsStHDPkmPfOfpasn6A3L0WRyRWlp0Y49373V/z/fzjndtnX333f8Ny+fqyXjzm6NO7vl9d7TJo/71cOt8cEjq5BgyOxktIxKOFeEMIOi6zfpYd/ek/A4bepMXoXnL5z5fPa0Xr16/x6zd9bMeZmZ6Qt/nMeXrCPLyLZtMes3rB74xpCYjbv79n1jz94dMb9Fo/pQx+wb80IsytXK5EI1ii9e3ieXKUYO/sbHK9jXO/TNqOmp6Qnxf1dELNDrtS+/NLpJYBvwwkdG9IZfYWr6TUj/69TvbVv1AGk6ODQCGxkWGomEBISYlYqdE4dbcPwYX8vqX5d2ebE7KAlsXqtWbd+b8NHp03/dMNTddWQZuXzlYnh4y1de6ePq6tan94DFP6/p1PF5VE/YevkRdTqGooSavA31cmBAS0fHilWu7m5+Hu4BScmXjAWC/FvxBw72XJ+9tKwI5JiTm+LjHWIsE9C4BRIS+MpLi7GbC82N7z2G+yYx8Z8WLVoZT8Obt4THGzeu1Z1lpHXrdhcunJn/7Zx9+2MLCgv8GweEhdVvORFruW62NH4MzWKhLGJpmTol9To4X0wTC4uq1nfV3qm5rLyYYfRKpYMxxc7OHgkKhWjBfoqPzmN8J2q1ury8XKms8oQ4OHD3s6SkuI4s0yuAvXRwcDwZd+yb+V/I5fJu3V4eN+YDT8/6jHewFqVoXohKe4W60MLigsfG2dkjpEnEK93HmiY6Ota1RFKldKRpmVZbZkwp15QgIQEvicoBv4HNxzCHKhWns7KyKm9AsUFnHu6edWSZXoGmaaiR4f+dO4kXL55dE72iuFj99X/rE1bZ8qQH80J0dpNnp5YjYWjs0+zC5b2hwU8bIzpkZCV6edTVCwYb6ebqd+fu1a6VbZK/E04iIYFK0DdEYKNbfx5nhjbYsPDmT127dsWYwh+HNm1WR5bpFaC/3Lz5UyEhTYODQ+F/kbpoz97tqD7Uu7PSrJ2TXivU0AJ4ZBiG2fXHDxpNWVZ28u79Py/4eUh65gOmYLVr3fPq9SMwoALHh09EJ9+LR4KhUXPru8LaOSDMoCjDqp+HRqlUenl5nz9/+n+Xzut0ugH9B/118ujWrZsKiwohZcnS79s/3aFZWDiUrCPLyKHD+6BnHRd3HBqI0JU58dfh1q3aoXpiqbNi3iKGtHGAH19RTrmz55OfjA3d3qkTNx45sW7hshFZ2XeCAlq92X/6AzsfPbuOKi7O27F3wfrfp0PN3u+1Dzdu/lygCFJZSbkKBY+jQVgAAAQmSURBVI6TCxiWYpn6GYihQ979dc2ys+fiNm3cDd6Z7Jys3zav+3nJAvARRj7z7JjRE/lidWQZmfLRjJ8Xfzd95keIW3LuAXX0mwOHofpQR2fFYjSwNXOSGYYO7dQY2R4Jx1J8m6iiJvgizFj68W3/MPuXBkn1S1kz+9aA8f4B4WbaPBbtfMSLrmXFmM6GEhqtRhc1HjsVWjcWp/9HvORyet/99Bt5fi3Mr7bML8j87uchZrPslU6l5eZjnPh6hU4c+wt6csz4qoelLBitkcnMfMDgoLajh1vs690+m+7saofpsk1u9beEJyQ+4rrmDr08zvyRY0mIzk4eH723zmwW9ELs7MzP3KGf9MoXS++BexvacjuFmTauXFZXRLeywvIJc5siPGH5MLBSpl6dFZ5nerjEn8pPupAR8oyZegqMjbtbwzdWnux7uHkiJSDMgcY29KDEp2fX8Rt6gC9gxIwmZYVlBRnCeo8x4V58Di1DURP8ELZY6fRs9DCr+KCeSonPQtZO+t95Rdnq0V8GI5yx0gUr6KEW2MvQhPlN4w8m5aUVIyvl3pX7hdlF8DER5nBzbyQcHxFZ7ms91KeSydDE78PSrmcnnU9HVkfCiZTifPW4uSFIArDVdo+QGpSZCS0V1OPn9f6Cpqxe9/fh5MyEXGQVJF/KBkvv4iofN1cae7pIfTmpYc2N+az6OVPenR185kD+5SN591ML7Z1V3mHujm7SCW5fSW6q+n5SgaZMo3KUDxgX6B8urZhS1tlOrLdXr1MvV/h//s/8+LiC5ItpDMvKFTLuhyrjg7bWLG8ItllzjLFybxnjBjOmmyJVFTYmGksaUwwb2VDVn2jxFWkZy+q5eKGMnmF03Ft0dlf0GhLQpJUElyla6cLmR3QvR/Z0hf9wcOt/6sT4ktzMcm0Zq9cztYUIDmy9ngslawol4+IWG3Y1qizGxTCuVFflveajICNuMSzLL0OsSqEqrlmRYrLzFqRw0Y9N3olcwf1OlPYyd1+7Fh0a+TeV6jJZ1nodOI87zhH2tBP8RwRxsF4/ovWGmrNGFHYyaAghySKXU1yFZTYLEaSDQkWVl0jYfQMN/YBQ871bSXtHbY7gp5zvZwi1hENo4nblQDMdWTDoRIhSousb7vCFHd4oyRHX5GuF3d/0tpSL137NhIch+r93wcvQvpunJNxP6nz24p/ZyTeKRswIdnSx2MAlQpQkmxem5mZo9DoGXGOm6Ub3asWpxdjpJs5ak754Ne9r1UmN3cZrrz2pfm7yqrSM2zfM3knea6hP47C6fjZEiFJGg0pL9dVSeH9q1V725raq54pV7Q9ncmzixDXdyB6x1Q6MTzHuIsZfn9vLnq0YeWArRxpkMvuHc+4RIRKwgLhvCFhAhEjAAiJEAhYQIRKwgAiRgAVEiAQs+H8AAAD//+k+bf0AAAAGSURBVAMASKmUH6ZOP7gAAAAASUVORK5CYII=",
|
|
"text/plain": [
|
|
"<IPython.core.display.Image object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"try:\n",
|
|
" display(Image(agentic_graph.get_graph().draw_mermaid_png()))\n",
|
|
"except Exception:\n",
|
|
" pass"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "1e9aff05",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Test"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"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, graph: StateGraph):\n",
|
|
" for event in graph.stream(\n",
|
|
" {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n",
|
|
" #config=config,\n",
|
|
" stream_mode=\"values\",\n",
|
|
" ):\n",
|
|
" event[\"messages\"][-1].pretty_print()\n",
|
|
" # last_msg = event[\"messages\"][-1]\n",
|
|
" # if isinstance(last_msg, AIMessage):\n",
|
|
" # last_msg.pretty_print()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 34,
|
|
"id": "a1a1f3cf",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"user_input = \"\"\"What types of includes does AVAP have?\"\"\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 35,
|
|
"id": "53b89690",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
|
"\n",
|
|
"What types of includes does AVAP have?\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
|
"Tool Calls:\n",
|
|
" context_retrieve (9329cb4e-5cb8-43e6-b2f5-d9a6a932b8e7)\n",
|
|
" Call ID: 9329cb4e-5cb8-43e6-b2f5-d9a6a932b8e7\n",
|
|
" Args:\n",
|
|
" query: AVAP includes types\n",
|
|
"=================================\u001b[1m Tool Message \u001b[0m=================================\n",
|
|
"Name: context_retrieve\n",
|
|
"\n",
|
|
"[1] id=chunk-1 source=10.1_Expressions.txt\n",
|
|
"6. Expressions in AVAP This chapter explains the meaning of expression elements in AVAP. 6.1. Arithmetic Conversions When describing an arithmetic operator in AVAP and using the phrase \"numeric arguments are converted to a common type,\" it means that the operator's implementation for built-in types works as follows: If either of the arguments is a complex number, the other is converted to complex. Otherwise, if either of the arguments is a floating-point number, the other is converted to floating-point. Otherwise, both must be integers, and no conversion is needed. Additional rules may apply for certain operators. 6.2. Atoms Atoms are the most basic elements of expressions in AVAP. The simplest atoms are identifiers or literals. Forms enclosed in parentheses, brackets, or braces are also syntactically categorized as atoms. The syntax for atoms is: atom ::= identifier | literal | enclosure enclosure ::= parenth_form | list_display | dict_display | set_display | generator_expression 6.2.1. Identifiers (Names) An identifier that appears as an atom is a name. When the name is bound to an object, evaluating the atom yields that object. When a name is not bound, an attempt to evaluate it raises a NameError exception. Private Name Mangling When an identifier that occurs literally in a class definition begins with two or more underscores and does not end with two or more underscores, it is considered a private name of that class. Private names are transformed into a longer form before code is generated for them. The transformation inserts the class name, with the initial underscores removed and a single underscore inserted, in front of the name. 6.2.2. Literals AVAP supports string and bytes literals, as well as various numeric literals: literal ::= stringliteral | bytesliteral | integer | floatnumber | imagnumber Evaluating a literal produces an object of the given type (string, bytes, integer, floating-point number, complex number) with the given value. All literals correspond to immutable data types. 6.2.3. Parenthesized Forms A parenthesized form is an optional list of expressions enclosed in parentheses: parenth_form ::= \"(\" [starred_expression] \")\" A parenthesized expression produces whatever the expression list produces: if the list contains at least one comma, it produces a tuple; otherwise, it produces the single expression that makes up the list of expressions. 6.2.4. Comprehensions for Lists, Sets and Dictionaries To construct a list, set, or dictionary, AVAP provides special syntax called \"comprehension,\" each in two flavors: The contents of the container are listed explicitly. They are computed using a set of loop and filtering instructions, called a \"comprehension.\" Common syntax elements for comprehensions are: comprehension ::= assignment_expression comp_for comp_for ::= \"for\" target_list \"in\" or_test [comp_iter] comp_iter ::= comp_for | comp_if comp_if ::= \"if\" or_test [comp_iter] A comprehension consists of a single expression followed by at least one for clause and zero or more for or if clauses. In this case, the elements of the new container are those produced by considering each for or if clause as a block, nested from left to right, and evaluating the expression to produce an element each time the innermost block is reached. 6.2.5. List Displays In AVAP, lists are generated and handled differently. To construct a list, the command variableToList(variable, list) is used, and an item from the list is retrieved with itemFromList(list, index, variable_to_store_item). To get the number of elements in the list, getListLen(list, var_to_store_list_length) is used. The syntax for list displays is: list_display ::= \"[\" [starred_list | comprehension] \"]\" A list display produces a new list object, whose content is specified by a list of expressions or a comprehension. When a list of expressions is provided, its elements are evaluated from left to right and placed in the list object in that order. 6.2.6. Set Displays A set display is denoted by curly braces and is distinguished from dictionary displays by the absence of colon characters separating keys and values: set_display ::= \"{\" (starred_list | comprehension) \"}\" A set display produces a new mutable set object, whose content is specified by a sequence of expressions or a comprehension. 6.2.7. Dictionary Displays In AVAP, objects are created and managed using specific commands. An object is created with AddvariableToJSON(key, value, object_variable), and a key from the object is retrieved with variableFromJSON(object_variable, key, var_to_store_key_value). The syntax for dictionary displays is: dict_display ::= \"{\" [dict_item_list | dict_comprehension] \"}\" dict_item_list ::= dict_item (\",\" dict_item)* [\",\"] dict_item ::= expression \":\" expression | \"**\" or_expr dict_comprehension ::= expression \":\" expression comp_for A dictionary display produces a new dictionary object. If a comma-separated sequence of dictionary items is provided, they are evaluated from left to right to define the dictionary entries. Slices A slice selects a range of elements in a sequence object (e.g., a string, tuple, or list). Slices can be used as expressions or as targets in assignments or statements. The syntax for a slice is as follows: slicing ::= primary \"[\" slice_list \"]\" slice_list ::= slice_item (\",\" slice_item)* [\",\"] slice_item ::= expression | proper_slice proper_slice ::= [lower_bound] \":\" [upper_bound] [ \":\" [stride] ] lower_bound ::= expression upper_bound ::= expression stride ::= expression There is ambiguity in the formal syntax here: anything that looks like a list expression also looks like a list slice, so any subscription might be interpreted as a slice. Instead of complicating the syntax further, this is disambiguated by defining that in this case, the interpretation as a subscription takes precedence over the interpretation as a slice (this is the case if the list slice does not contain a proper slice). The semantics for a slice are as follows. The primary is indexed (using the same __getitem__() method as in a normal subscription) with a key constructed from the slice list, as follows. If the slice list contains at least one comma, the key is a tuple that contains the conversion of the slice elements; otherwise, the conversion of the single slice element is the key. The conversion of a slice element that is an expression is that expression. The conversion of a proper slice is a slice object whose start, stop, and step attributes are the values of the expressions given as the lower bound, upper bound, and step, respectively, substituting None for missing expressions. Calls A call invokes a callable object (e.g., a function) with a possibly empty series of arguments: call ::= primary \"(\" [argument_list [\",\"] | comprehension] \")\" argument_list ::= positional_arguments [\",\" starred_and_keywords] [\",\" keywords_arguments] | starred_and_keywords [\",\" keywords_arguments] | keywords_arguments positional_arguments ::= positional_item (\",\" positional_item)* positional_item ::= assignment_expression | \"*\" expression starred_and_keywords ::= (\"*\" expression | keyword_item) (\",\" \"*\" expression | \",\" keyword_item)* keywords_arguments ::= (keyword_item | \"**\" expression) (\",\" keyword_item | \",\" \"**\" expression)* keyword_item ::= identifier \"=\" expression An optional trailing comma may be present after positional and keyword arguments but does not affect the semantics. The primary must evaluate to a callable object (user-defined functions, built-in functions, built-in object methods, class objects, class instance methods, and any object with a __call__() method are callable). All argument expressions are evaluated before attempting the call. Please refer to the Function Definitions section for the syntax of formal parameter lists. If keyword arguments are present, they are first converted into positional arguments as follows. First, a list of unfilled slots is created for the formal parameters. If there are N positional arguments, they are placed in the first N slots. Then, for each keyword argument, the identifier is used to determine the corresponding slot. If the slot is already filled, a TypeError exception is raised. Otherwise, the argument is placed in the slot, filling it (even if the expression is None, it fills the slot). When all arguments have been processed, any slots that are still empty are filled with the default value from the function definition. If there are unfilled slots for which no default value is specified, a TypeError exception is raised. Otherwise, the list of filled slots is used as the argument list for the call. Implementation Details in AVAP In AVAP, variables are stored as strings, and lists and objects are managed using specific commands: Lists: To generate a list, use variableToList(variable, list). To retrieve an item from the list, use itemFromList(list, index, variable_to_store_item). To get the number of items in the list, use getListLen(list, var_to_store_list_length). Objects (dictionaries): An object is created with AddvariableToJSON(key, value, object_variable). To retrieve a key from the object, use variableFromJSON(object_variable, key, var_to_store_key_value). Usage Example Creation and management of lists: // Creating a list variableToList(\"item1\", \"myList\") variableToList(\"item2\", \"myList\") variableToList(\"item3\", \"myList\") // Retrieving an item from the list itemFromList(\"myList\", 1, \"myVariable\") // Getting the length of the list getListLen(\"myList\", \"listLength\") Creation and management of objects (dictionaries): // Creating an object AddvariableToJSON(\"key1\", \"value1\", \"myObject\") AddvariableToJSON(\"key2\", \"value2\", \"myObject\") // Retrieving a value by key from the object variableFromJSON(\"myObject\", \"key1\", \"myVariable\") In this way, lists and objects in AVAP can be manipulated using the specific functions provided for working with variables stored as strings.\n",
|
|
"\n",
|
|
"[2] id=chunk-2 source=9_Expressions_in_avap.txt\n",
|
|
"Expressions in AVAP™ Introduction Expressions in AVAP™ are combinations of values, variables, operators, and function calls that can be evaluated to produce a result. Just like in Python, expressions in AVAP™ can be simple or complex, and they can contain a variety of elements that manipulate and process data. Types of Expressions In AVAP™, as in Python, there are several types of expressions that can be used to perform different operations and calculations. Some of the most common types of expressions include: Arithmetic: Perform mathematical operations such as addition, subtraction, multiplication, and division. Logical: Evaluate logical conditions and return boolean values, such as True or False. Comparative: Compare two values and return a result based on their relationship, such as equality, inequality, greater than, less than, etc. Assignment: Assign a value to a variable. Function Calls: Invoke functions and methods to perform specific tasks. Operators In AVAP™, as in Python, expressions can include a variety of operators that perform specific operations on data. Some of the most common operators include: Arithmetic: +, -, *, /, %, etc. Logical: and, or, not. Comparative: ==, !=, >, <, >=, <=, etc. Assignment: =, +=, -=, *=, /=, etc. Working with Lists Lists are a very versatile data structure in AVAP™ that allows you to store collections of elements of different types. Expressions in AVAP™ can involve operations and manipulations of lists, such as accessing individual elements, concatenation, searching, deletion, and more. // Definition of a list my_list = [1, 2, 3, 4, 5] // Accessing individual elements first_element = my_list[0] // Output: 1 // Concatenation of lists another_list = [6, 7, 8] combined_list = my_list + another_list // Output: [1, 2, 3, 4, 5, 6, 7, 8] // Length of a list length = len(my_list) // Output: 5 // Searching in a list is_present = 5 in my_list // Output: True // Removing elements my_list.remove(3) // Removes the element 3 from the list Practical Example Below is a practical example that illustrates the use of expressions in AVAP™ with lists: // Definition of a list of numbers numbers = [1, 2, 3, 4, 5] // Calculation of the sum of the elements total = sum(numbers) // Output: 15 // Checking if a number is present in the list is_present = 6 in numbers // Output: False Conclusions Expressions in AVAP™ are a fundamental part of programming, allowing for a wide variety of data operations and manipulations. By understanding the different types of expressions and operators, as well as working with data structures such as lists, developers can write clear and effective code that meets the program's requirements.\n",
|
|
"\n",
|
|
"[3] id=chunk-3 source=14_Working_with_libraries.txt\n",
|
|
"Function Libraries Introduction Includes are a fundamental feature in AVAP™ that allow for the efficient organization and reuse of code in software development projects. Just like in other programming languages, includes in AVAP™ enable the incorporation of functionalities from other files or libraries into the current file. This capability provides a number of significant advantages that make the development and maintenance of projects more efficient and effective. Purpose of Includes The primary purpose of includes in AVAP™ is to promote modularity and code reuse. By dividing code into separate modules or files and then including them in main files as needed, developers can write and maintain code in a more organized and structured manner. This facilitates the management of large and complex projects, as well as collaboration between development teams. Advantages of Using Includes Code Reuse: Includes allow for the reuse of functions, variables, and other code definitions in multiple parts of a project, reducing code duplication and promoting consistency and coherence in development. Facilitates Maintainability: By dividing code into smaller, more specific modules, it is easier to identify, understand, and modify parts of the code without affecting other parts of the project. This eases software maintenance over time. Promotes Modularity: The ability to include files selectively as needed encourages code modularity, which simplifies understanding and managing complex projects by breaking them down into smaller, manageable components. Improves Readability and Organization: The use of includes helps organize code in a logical and structured manner, improving readability and facilitating navigation through different parts of the project. Syntax of Includes In AVAP™, the syntax for including a file is similar to that of other languages like C. The keyword include is used followed by the name of the file to be included. There are two main ways to include files in AVAP™: Local Include: Used to include project-specific files located in the same directory or in subdirectories relative to the current file. The file name is specified within quotes. Example: include \"file_name.avap\" System Include: Used to include standard or system library files located in predefined or configured paths on the system. The file or library name is specified between angle brackets (< and >). Example: include <library_name.avap> Operation When an include is found in an AVAP™ file, the interpreter searches for the specified file and incorporates it into the current file at compile time. This means that all the code contained in the included file will be available for use in the current file. Common Uses Including Standard Libraries: Standard libraries that provide common functions and utilities can be included to simplify application development. Including Definition Files: Files containing definitions of variables, constants, or data structures used in multiple parts of the project can be included. Including Specific Functionality Modules: Modules providing additional features for the project, such as file handling, text processing, or data manipulation, can be included. Practical Example Suppose we have a file named utils.avap that contains utility functions we want to use in our main project. We can include this file in our main project as follows: include \"utils.avap\" // We can now use the functions defined in utils.avap With this understanding of the value and advantages of using includes in AVAP™, we will explore in detail their operation and practical application in project development. Practical Example Suppose we have a file named utils.avap that contains utility functions we want to use in our main project. We can include this file in our main project as follows: include \"utils.avap\" // We can now use the functions defined in utils.avap With this understanding of the value and advantages of using includes in AVAP™, we will explore in detail their operation and practical application in project development. Function Libraries Function Products In AVAP™, there are a series of function libraries grouped by categories called Function Products that complement the base AVAP™ language and leverage the power of AVS servers for distribution. Through Function Products, developers can extend the functionality of AVAP™ by incorporating specialized libraries tailored to different needs and applications. Function Products provide a way to access advanced features and capabilities not available in the core language, offering a robust framework for building complex and scalable solutions. These libraries are designed to integrate seamlessly with AVAP™, enhancing the development process and enabling more efficient and effective project execution.\n",
|
|
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
|
"\n",
|
|
"Based on the documentation, AVAP has **two main types of includes** for incorporating external code:\n",
|
|
"\n",
|
|
"## 1. Local Include\n",
|
|
"- Used to include project-specific files located in the same directory or subdirectories relative to the current file\n",
|
|
"- Syntax: `include \"file_name.avap\"` (file name within quotes)\n",
|
|
"\n",
|
|
"## 2. System Include\n",
|
|
"- Used to include standard or system library files located in predefined or configured paths on the system\n",
|
|
"- Syntax: `include <library_name.avap>` (file/library name between angle brackets)\n",
|
|
"\n",
|
|
"## Function Libraries\n",
|
|
"Additionally, AVAP includes **Function Products**, which are categorized function libraries that complement the base AVAP language. These specialized libraries leverage AVS servers for distribution and provide access to advanced features not available in the core language.\n",
|
|
"\n",
|
|
"### Key Advantages of Includes:\n",
|
|
"- **Code Reuse**: Functions, variables, and code definitions can be reused across multiple parts of a project\n",
|
|
"- **Maintainability**: Smaller, modular files make it easier to identify, understand, and modify specific sections\n",
|
|
"- **Modularity**: Enables structured organization of complex projects\n",
|
|
"- **Readability**: Improves navigation through different parts of the project\n",
|
|
"\n",
|
|
"### Example Usage:\n",
|
|
"```avap\n",
|
|
"// Local include (same directory)\n",
|
|
"include \"utils.avap\"\n",
|
|
"\n",
|
|
"// System include (predefined path)\n",
|
|
"include <standard_libs.avap>\n",
|
|
"```\n",
|
|
"\n",
|
|
"These include types allow you to efficiently organize and reuse code while maintaining a structured, maintainable development workflow.\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"a = stream_graph_updates(user_input, agentic_graph)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 33,
|
|
"id": "d6b4da6a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Final result:\n",
|
|
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
|
|
"\n",
|
|
"Based on the AVAP documentation provided, here's a comprehensive overview of the supported operators and expression types:\n",
|
|
"\n",
|
|
"## 1. Arithmetic Operators\n",
|
|
"AVAP supports standard mathematical operations including:\n",
|
|
"- **Addition**: `+` (e.g., `tax = subtotal * 0.21`)\n",
|
|
"- **Subtraction**: `-`\n",
|
|
"- **Multiplication**: `*`\n",
|
|
"- **Division**: `/`\n",
|
|
"- **Modulo**: `%`\n",
|
|
"\n",
|
|
"## 2. Comparison Operators\n",
|
|
"Supports relational comparisons:\n",
|
|
"- **Equality**: `==`, `!=`\n",
|
|
"- **Greater/Smaller**: `>`, `<`\n",
|
|
"- **Range Checks**: `>=`, `<=`\n",
|
|
"\n",
|
|
"Example: `level = 5 is_admin = level >= 10`\n",
|
|
"\n",
|
|
"## 3. Assignment Operators\n",
|
|
"AVAP supports multiple assignment types:\n",
|
|
"- **Direct Assignment**: `name = \"John\"`\n",
|
|
"- **Arithmetic Assignment**: `total += tax`\n",
|
|
"- **Multiplicative Assignment**: `value *= 2`\n",
|
|
"- **Division Assignment**: `price /= 10`\n",
|
|
"\n",
|
|
"## 4. Logical Operators\n",
|
|
"Supports boolean expressions:\n",
|
|
"- **AND**: `is_valid = (age > 18 and has_permission == True)`\n",
|
|
"- **OR**: `allowed = age >= 16 or status == \"active\"`\n",
|
|
"- **NOT**: `not_in_use = !is_active`\n",
|
|
"\n",
|
|
"## 5. String Formatting Operator\n",
|
|
"AVAP supports Python-style string formatting:\n",
|
|
"- `%` operator (e.g., `\"Event registered by: %s\" % name`)\n",
|
|
"\n",
|
|
"## 6. Object Property Access\n",
|
|
"Deep property access using dot notation:\n",
|
|
"- `customer_email = user_list[0].profile.email`\n",
|
|
"\n",
|
|
"## 7. List Operations\n",
|
|
"AVAP supports list manipulation:\n",
|
|
"```python\n",
|
|
"variableToList(\"item1\", \"myList\")\n",
|
|
"itemFromList(\"myList\", 1, \"myVariable\")\n",
|
|
"getListLen(\"myList\", \"listLength\")\n",
|
|
"```\n",
|
|
"\n",
|
|
"## 8. Keyword Arguments\n",
|
|
"Supports keyword argument syntax with comma separation:\n",
|
|
"```python\n",
|
|
"def handler(*args, **kwargs):\n",
|
|
" pass\n",
|
|
"```\n",
|
|
"\n",
|
|
"## Key Features\n",
|
|
"- **Dynamic Typing**: Variables can change type at runtime (e.g., numeric to string)\n",
|
|
"- **Scope Management**: Request session variables persist across API calls\n",
|
|
"- **Reference Operator**: `$` prefix for variable dereferencing\n",
|
|
"- **Middleware Support**: Built-in middleware execution before handlers\n",
|
|
"\n",
|
|
"These operators work together to create flexible, dynamic scripts that combine declarative commands with runtime expression evaluation.\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"result = agentic_graph.invoke({\"messages\": [{\"role\": \"user\", \"content\": user_input}]})\n",
|
|
"print(\"Final result:\")\n",
|
|
"result[\"messages\"][-1].pretty_print()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2342b1f1",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3707574b",
|
|
"metadata": {},
|
|
"source": [
|
|
"### MTEB"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"id": "d9657ec4",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"ename": "SyntaxError",
|
|
"evalue": "invalid syntax (2793878467.py, line 12)",
|
|
"output_type": "error",
|
|
"traceback": [
|
|
" \u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[18]\u001b[39m\u001b[32m, line 12\u001b[39m\n\u001b[31m \u001b[39m\u001b[31mnorms = np.linalg.norm(x, axis=1, keepdims=True)agent_graph\u001b[39m\n ^\n\u001b[31mSyntaxError\u001b[39m\u001b[31m:\u001b[39m invalid syntax\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"from dataclasses import dataclass\n",
|
|
"from typing import Any, Iterable\n",
|
|
" \n",
|
|
"import numpy as np\n",
|
|
" \n",
|
|
"import mteb\n",
|
|
"from mteb.types import Array\n",
|
|
"from mteb.models import SearchEncoderWrapper\n",
|
|
" \n",
|
|
" \n",
|
|
"def _l2_normalize(x: np.ndarray, eps: float = 1e-12) -> np.ndarray:\n",
|
|
" norms = np.linalg.norm(x, axis=1, keepdims=True)agent_graph\n",
|
|
" return x / np.clip(norms, eps, None)\n",
|
|
" \n",
|
|
" \n",
|
|
"def _to_text_list(batch: dict[str, Any]) -> list[str]:\n",
|
|
" \"\"\"\n",
|
|
" MTEB batched inputs can be:\n",
|
|
" - TextInput: {\"text\": [..]}\n",
|
|
" - CorpusInput: {\"title\": [..], \"body\": [..], \"text\": [..]}\n",
|
|
" - QueryInput: {\"query\": [..], \"instruction\": [..], \"text\": [..]}\n",
|
|
" We prefer \"text\" if present; otherwise compose from title/body or query/instruction.\n",
|
|
" \"\"\"\n",
|
|
" if \"text\" in batch and batch[\"text\"] is not None:\n",
|
|
" return list(batch[\"text\"])\n",
|
|
" \n",
|
|
" if \"title\" in batch and \"body\" in batch:\n",
|
|
" titles = batch[\"title\"] or [\"\"] * len(batch[\"body\"])\n",
|
|
" bodies = batch[\"body\"] or [\"\"] * len(batch[\"title\"])\n",
|
|
" return [f\"{t} {b}\".strip() for t, b in zip(titles, bodies)]\n",
|
|
" \n",
|
|
" if \"query\" in batch:\n",
|
|
" queries = list(batch[\"query\"])\n",
|
|
" instructions = batch.get(\"instruction\")\n",
|
|
" if instructions:\n",
|
|
" return [f\"{i} {q}\".strip() for q, i in zip(queries, instructions)]\n",
|
|
" return queries\n",
|
|
" \n",
|
|
" raise ValueError(f\"Unsupported batch keys: {sorted(batch.keys())}\")\n",
|
|
" \n",
|
|
" \n",
|
|
"@dataclass\n",
|
|
"class OllamaLangChainEncoder:\n",
|
|
" lc_embeddings: Any # OllamaEmbeddings implements embed_documents()\n",
|
|
" normalize: bool = True\n",
|
|
" \n",
|
|
" # Optional metadata hook used by some wrappers; safe to keep as None for local runs\n",
|
|
" mteb_model_meta: Any = None\n",
|
|
" \n",
|
|
" def encode(\n",
|
|
" self,\n",
|
|
" inputs: Iterable[dict[str, Any]],\n",
|
|
" *,\n",
|
|
" task_metadata: Any,\n",
|
|
" hf_split: str,\n",
|
|
" hf_subset: str,\n",
|
|
" prompt_type: Any = None,\n",
|
|
" **kwargs: Any,\n",
|
|
" ) -> Array:\n",
|
|
" all_vecs: list[np.ndarray] = []\n",
|
|
" \n",
|
|
" for batch in inputs:\n",
|
|
" texts = _to_text_list(batch)\n",
|
|
" vecs = self.lc_embeddings.embed_documents(texts)\n",
|
|
" arr = np.asarray(vecs, dtype=np.float32)\n",
|
|
" if self.normalize:\n",
|
|
" arr = _l2_normalize(arr)\n",
|
|
" all_vecs.append(arr)\n",
|
|
" \n",
|
|
" if not all_vecs:\n",
|
|
" return np.zeros((0, 0), dtype=np.float32)\n",
|
|
" \n",
|
|
" return np.vstack(all_vecs)\n",
|
|
" \n",
|
|
" def similarity(self, embeddings1: Array, embeddings2: Array) -> Array:\n",
|
|
" a = np.asarray(embeddings1, dtype=np.float32)\n",
|
|
" b = np.asarray(embeddings2, dtype=np.float32)\n",
|
|
" if self.normalize:\n",
|
|
" # dot == cosine if already normalized\n",
|
|
" return a @ b.T\n",
|
|
" a = _l2_normalize(a)\n",
|
|
" b = _l2_normalize(b)\n",
|
|
" return a @ b.T\n",
|
|
" \n",
|
|
" def similarity_pairwise(self, embeddings1: Array, embeddings2: Array) -> Array:\n",
|
|
" a = np.asarray(embeddings1, dtype=np.float32)\n",
|
|
" b = np.asarray(embeddings2, dtype=np.float32)\n",
|
|
" if not self.normalize:\n",
|
|
" a = _l2_normalize(a)\n",
|
|
" b = _l2_normalize(b)\n",
|
|
" return np.sum(a * b, axis=1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "85727a68",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"encoder = OllamaLangChainEncoder(lc_embeddings=embeddings, normalize=True)\n",
|
|
"search_model = SearchEncoderWrapper(encoder)\n",
|
|
" \n",
|
|
"tasks = mteb.get_tasks([\n",
|
|
" \"CodeSearchNetRetrieval\",\n",
|
|
" \"CodeSearchNetCCRetrieval\",\n",
|
|
" \"AppsRetrieval\",\n",
|
|
" \"StackOverflowDupQuestions\",\n",
|
|
"])\n",
|
|
"results = mteb.evaluate(\n",
|
|
" model=search_model,\n",
|
|
" tasks=tasks,\n",
|
|
" encode_kwargs={\"batch_size\": 32, \"show_progress_bar\": True}\n",
|
|
")\n",
|
|
" \n",
|
|
"print(results)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "4052f229",
|
|
"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.11.13"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|