File size: 9,016 Bytes
24ff9b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Make sure ollama serve is running(docker or terminal)\n",
    "from operator import itemgetter\n",
    "from langchain.prompts import PromptTemplate\n",
    "from shared import getModel, getEmbeddingsModel, getQdrantClient\n",
    "\n",
    "def answer(query):\n",
    "    # Create a qdrant connection\n",
    "    qClient = getQdrantClient()\n",
    "\n",
    "    # Setup the text embedder\n",
    "    embeddingsModel = getEmbeddingsModel()\n",
    "\n",
    "    # Setup the model\n",
    "    model = getModel()\n",
    "\n",
    "    # Retrieval Pipeline\n",
    "    # Retrieve the chunks with the most similar embeddings from Qdrant\n",
    "    def retriever(text, collection):\n",
    "        results = qClient.search(\n",
    "            collection_name=collection,\n",
    "            query_vector = embeddingsModel.embed_query(text),\n",
    "            limit=10\n",
    "        )\n",
    "        return results\n",
    "\n",
    "    # Query expansion(I only generate one additional prompt for simplicity)\n",
    "    template = \"\"\"\n",
    "    Rewrite the prompt. The new prompt must offer a different perspective.\n",
    "    Do not change the meaning. Output only the rewritten prompt with no introduction.\n",
    "        Prompt: {prompt}\n",
    "    \"\"\"\n",
    "    prompt = PromptTemplate.from_template(template)\n",
    "    chain = {\"prompt\": itemgetter(\"prompt\")} | prompt | model\n",
    "    queryExpansion = chain.invoke({\"prompt\": query})\n",
    "    print(\"Query expansion: \", queryExpansion)\n",
    "\n",
    "    # Self-querying(The metadata I will be generating determines whether to look through the Qdrant collection containing github code)\n",
    "    template = \"\"\"\n",
    "    You are an AI assistant. You must determine if the prompt requires code as the answer.\n",
    "    Output a 1 if it is or a 0 if it is not and nothing else.\n",
    "        Prompt: {prompt}\n",
    "    \"\"\"\n",
    "    prompt = PromptTemplate.from_template(template)\n",
    "    chain = {\"prompt\": itemgetter(\"prompt\")} | prompt | model\n",
    "    codingQuestion = chain.invoke({\"prompt\": query})\n",
    "    print(\"Coding question?: \", codingQuestion)\n",
    "\n",
    "    # Filtered vector search for each of the N queries after expansion\n",
    "    relatedCollection = 'Document'\n",
    "    if (codingQuestion == '1'):\n",
    "        relatedCollection = 'Github'\n",
    "    results1 = retriever(query, relatedCollection)\n",
    "    results2 = retriever(queryExpansion, relatedCollection)\n",
    "    print(\"Related collection: \", relatedCollection)\n",
    "    \n",
    "\n",
    "    # Collecting results\n",
    "    results = results1+results2\n",
    "\n",
    "    # Reranking(Instead of using a CrossEncoder, I will manually compare embeddings)\n",
    "    ids = [result.id for result in results]\n",
    "    scores = [result.score for result in results]\n",
    "    topIds = []\n",
    "    topIndexes = []\n",
    "    for x in range(3):\n",
    "        maxScore = 0\n",
    "        maxIndex = 0\n",
    "        for i in range(len(ids)):\n",
    "            if ids[i] not in topIds and scores[i] > maxScore:\n",
    "                maxScore = scores[i]\n",
    "                maxIndex = i\n",
    "        topIds.append(ids[maxIndex])\n",
    "        topIndexes.append(maxIndex)\n",
    "    texts = [result.payload['text'] for result in results]\n",
    "    links = [result.payload['link'] for result in results]\n",
    "    topTexts = ''\n",
    "    for index in topIndexes:\n",
    "        print(\"Top texts: \", texts[index])\n",
    "        print(\"Link: \", links[index])\n",
    "        topTexts += texts[index]\n",
    "\n",
    "    # Building prompt\n",
    "    if(codingQuestion == '1'):\n",
    "        template = \"\"\"\n",
    "        Write code for the following question given the related coding document below.\n",
    "\n",
    "        Document: {document}\n",
    "        Question: {question}\n",
    "        \"\"\"\n",
    "        prompt = PromptTemplate.from_template(template)\n",
    "    else:\n",
    "        template = \"\"\"\n",
    "        You are an AI agent that has retreived a document from the web.\n",
    "        If the document is useful for answering the question use it.\n",
    "        If the document is not useful, answer normally.\n",
    "        Do not mention the document.\n",
    "\n",
    "        Document: {document}\n",
    "        Question: {question}\n",
    "        \"\"\"\n",
    "        prompt = PromptTemplate.from_template(template)\n",
    "\n",
    "    # Obtaining answer\n",
    "    chain = {\"document\": itemgetter(\"document\"), \"question\": itemgetter(\"question\")} | prompt | model\n",
    "    print(\"RAG answer: \", chain.invoke({\"document\": topTexts, \"question\": query}))\n",
    "    print(\"\\n----------------------------------------------\\n\")\n",
    "    baseline = model.invoke(query)\n",
    "    print(\"Baseline answer: \", baseline[:500])\n",
    "    print(\"\\n----------------------------------------------\\n\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Query expansion:  What percentage of global companies have adopted or are utilizing Nav2?\n",
      "Coding question?:  0\n",
      "Related collection:  Document\n",
      "Top texts:  types of tasks like object following, complete coverage navigation, and more. Nav2 is a production-grade and high-quality navigation framework trusted by 100+ companies worldwide. It provides perception, planning, control, localization, visualization, and much more to build highly reliable autonomous systems. This will compute an environmental model from sensor and semantic data, dynamically path plan, compute velocities for motors, avoid obstacles, and structure higher-level robot behaviors.\n",
      "Link:  https://docs.nav2.org/\n",
      "Top texts:  not specifically address here. BehaviorTree.CPP upgraded to version 4.5+ Since we migrated from version 3.8 to 4.5, users must upgrade their XML and source code accordingly. You can refer to [this page](https://www.behaviortree.dev/docs/migration) for more details, but the main changes are: XML must be changed. This [python script can help](https://github.com/BehaviorTree/BehaviorTree.CPP/blob/master/convert_v3_to_v4.py). The syntax of SubTrees has changed; the one of SubTreePlus was adopted,\n",
      "Link:  https://docs.nav2.org/migration/Iron.html\n",
      "Top texts:  September 19, 2015 MoveIt! Upcoming Events - RoboBusiness 2015 Come meet MoveIt! developers and users at RoboBusiness 2015 in San Jose... September 17, 2015 Report on First MoveIt! Community Meeting Watch video of the First MoveIt! Community Meeting in case you missed it. Thank you for coming to the MoveIt! Community Meeting and thanks to the present... July 02, 2015 MoveIt! goes underwater! MoveIt! on an underwater Girona500 AUV robot and 4-DOF arm for autonomous underwater manipulation...\n",
      "Link:  https://moveit.ai/blog/\n",
      "RAG answer:  Nav2 is trusted by 100+ companies worldwide.\n",
      "\n",
      "----------------------------------------------\n",
      "\n",
      "Baseline answer:  I don't have any information about a company called \"Nav2.\" It's possible that it's a small or private company, or it may not be well-known. Can you provide more context or clarify which Nav2 you are referring to?\n",
      "\n",
      "Alternatively, I can suggest some well-known companies that use Nav (a navigation and mapping platform) for their trust services. For example:\n",
      "\n",
      "* Uber uses Nav for its ride-hailing service\n",
      "* Lyft also uses Nav for its service\n",
      "* Pizza Hut uses Nav to help customers navigate to location\n",
      "\n",
      "----------------------------------------------\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#queries = [\"How can I develop the navigation stack of an agent with egomotion?\", \"What is ROS?\", \"How many companies is Nav2 trusted by worldwide?\", \"How would I build a ROS 2 Navigation Framework and System?\", \"Write me code to move a robot using Moveit\"]\n",
    "queries = [\"How many companies is Nav2 trusted by worldwide?\"]\n",
    "for query in queries:\n",
    "    answer(query)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}