Skip to content

Commit 53c909e

Browse files
committed
Made improvements in the prompt of the /rcc-devdocs command and improved neo4j queries for the same
1 parent 409bb80 commit 53c909e

File tree

6 files changed

+146
-4
lines changed

6 files changed

+146
-4
lines changed

ai-assistant/src/commands/AskDocsCommand.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
SlashCommandContext,
99
} from "@rocket.chat/apps-engine/definition/slashcommands";
1010

11+
import { PromptFactory } from "../core/prompt.factory";
12+
import { Query } from "../core/query";
1113
import { Neo4j } from "../core/services/db/neo4j";
1214
import { MiniLML6 } from "../core/services/embeddings/minilml6";
1315
import { Llama3_70B } from "../core/services/llm/llama3_70B";
@@ -19,12 +21,48 @@ export class AskDocsCommand implements ISlashCommand {
1921
public i18nDescription = "";
2022
public providesPreview = false;
2123

24+
/**
25+
* Processes the user's query and returns the answer.
26+
*
27+
* @param {IHttp} http - The HTTP object used for making requests.
28+
* @param {string} query - The user's query.
29+
* @returns {Promise<string | null>} A promise that resolves to the response to be given to the user or `null` if no answer or no reference is found.
30+
*/
2231
private async process(http: IHttp, query: string): Promise<string | null> {
2332
const db = new Neo4j(http);
2433
const llm = new Llama3_70B(http);
2534
const embeddingModel = new MiniLML6(http);
2635

27-
return "UNDER DEVELOPMENT";
36+
/**
37+
* ---------------------------------------------------------------------------------------------
38+
* STEP 1:
39+
* Query the database to find the nodes names of which are similar to what user has requested
40+
* ---------------------------------------------------------------------------------------------
41+
*/
42+
const results = await Query.getDocsNodesFromQuery(
43+
db,
44+
embeddingModel,
45+
query
46+
);
47+
if (!results.length) return null;
48+
49+
/**
50+
* ---------------------------------------------------------------------------------------------
51+
* STEP 2:
52+
* Generate the answer and diagram for the user's query given the nodes data
53+
* ---------------------------------------------------------------------------------------------
54+
*/
55+
const uniqueSources = [...new Set<string>(results.map((x) => x.url))];
56+
const answer = await llm.ask(
57+
PromptFactory.makeAskDocsPrompt(
58+
results.map((x) => x.content).join("\n\n"),
59+
uniqueSources,
60+
query
61+
)
62+
);
63+
if (!answer) return null;
64+
65+
return answer;
2866
}
2967

3068
public async executor(

ai-assistant/src/commands/WhyUsedCommand.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ export class WhyUsedCommand implements ISlashCommand {
4646
* ---------------------------------------------------------------------------------------------
4747
*/
4848
const keywords = await Query.getDBKeywordsFromQuery(llm, query);
49-
console.log(keywords);
5049
if (!keywords.length) return null;
5150

5251
/**

ai-assistant/src/core/prompt.factory.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,42 @@ export namespace PromptFactory {
6161
return prompt;
6262
}
6363

64+
export function makeAskDocsPrompt(
65+
content: string,
66+
sourceURLs: string[],
67+
query: string
68+
): Prompt {
69+
const prompt = new Prompt();
70+
prompt.pushSystem(`
71+
You are an expert in understanding the documentation of Rocket.Chat and answering questions of user when given a proper context.
72+
73+
Here're the sources of the content:
74+
${sourceURLs.map((url) => `- ${url}`).join("\n")}
75+
76+
Here're the rules:
77+
1. Even if user asks for any kind of diagram or visualization, you must ignore that.
78+
2. If the user asks for an explanation of the content, you must provide the answer based on the content.
79+
3. You must provide the answer in text GitHub Markdown format only.
80+
4. In case of any request for diagrams or visualizations, tell user to use the "/rcc-diagram" command.
81+
5. If you are unable to answer the question, you must tell the user that you are unable to answer the question.
82+
6. Always and always mentions the sources of the content in the end. You must provide all these URLs.
83+
`);
84+
prompt.pushUser(`
85+
Hey I have been the reading the following documentation content and I am not able to understand it quite well. I'll provide you the content in between the tags <CONTENT_START> and <CONTENT_END> and the query between <QUERY_START> and <QUERY_END>. Can you please help me understand it better?
86+
87+
<QUERY_START>
88+
${query}
89+
<QUERY_END>
90+
91+
Here's the content:
92+
<CONTENT_START>
93+
${content}
94+
<CONTENT_END>
95+
`);
96+
97+
return prompt;
98+
}
99+
64100
export function makeDiagramPrompt(codebase: string, query: string): Prompt {
65101
const prompt = new Prompt();
66102

ai-assistant/src/core/query.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { PromptFactory } from "./prompt.factory";
22
import { IDB } from "./services/db/db.types";
33
import { DBNode } from "./services/db/dbNode";
4+
import { DevDocDBNode } from "./services/db/devDocDBNode";
45
import { IEmbeddingModel } from "./services/embeddings/embeddings.types";
56
import { ILLMModel } from "./services/llm/llm.types";
67

@@ -82,6 +83,75 @@ export namespace Query {
8283
return results;
8384
}
8485

86+
/**
87+
* Retrieves an array of DevDocDBNodes from the specified vector query.
88+
*
89+
* @param {IDB} db - The IDB instance used for the query.
90+
* @param {string} indexName - The name of the index to query.
91+
* @param {number[]} vector - The vector used for the query.
92+
* @param {number} threshold - The minimum score threshold for the query results.
93+
* @returns {Promise<DevDocDBNode[]>} - A promise that resolves to an array of DevDocDBNodes that match the query criteria.
94+
*/
95+
export async function getDevDocDBNodesFromVectorQuery(
96+
db: IDB,
97+
indexName: string,
98+
vector: number[],
99+
threshold: number
100+
): Promise<DevDocDBNode[]> {
101+
const result = await db.run(
102+
`
103+
CALL db.index.vector.queryNodes("${indexName}", 2, $vector)
104+
YIELD node, score
105+
WHERE score >= ${threshold}
106+
WITH node, score
107+
OPTIONAL MATCH (node)-[r]->(relatedNode)
108+
RETURN node, COLLECT(relatedNode) AS relatedNodes, score
109+
ORDER BY score DESC
110+
`,
111+
{ vector }
112+
);
113+
if (!result.length) return [];
114+
115+
const nodes: DevDocDBNode[] = [];
116+
const processRecord = (record: any) => {
117+
const data = record as DevDocDBNode;
118+
data.contentEmbeddings = [];
119+
nodes.push(data);
120+
};
121+
// node
122+
processRecord(result[0]);
123+
// relatedNodes
124+
for (const record of (result as any)[1]) processRecord(record);
125+
126+
return nodes;
127+
}
128+
129+
/**
130+
* Retrieves an array of DevDocDBNodes from the provided query.
131+
*
132+
* @param {IDB} db - The IDB instance used for querying the database.
133+
* @param {IEmbeddingModel} embeddingModel - The embedding model used for generating query vectors.
134+
* @param {string} query - The query string used for searching the database.
135+
* @returns {Promise<DevDocDBNode[]>} - A promise that resolves to an array of DevDocDBNodes matching the query.
136+
*/
137+
export async function getDocsNodesFromQuery(
138+
db: IDB,
139+
embeddingModel: IEmbeddingModel,
140+
query: string
141+
): Promise<DevDocDBNode[]> {
142+
const queryVector = await embeddingModel.generate(query);
143+
if (!queryVector) return [];
144+
145+
const results: DevDocDBNode[] = await getDevDocDBNodesFromVectorQuery(
146+
db,
147+
"contentEmbeddings",
148+
queryVector,
149+
0.7
150+
);
151+
152+
return results;
153+
}
154+
85155
/**
86156
* Retrieves database keywords from a given query using a language model.
87157
*

ai-assistant/src/core/services/db/neo4j.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ export class Neo4j implements IDB {
200200
}
201201

202202
if (response.errors.length) {
203-
console.log(response.errors);
204203
throw new Error(
205204
response.errors.map((x) => JSON.stringify(x)).join("\n\n")
206205
);

ai-assistant/src/endpoints/purgeDB.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class PurgeDBEndpoint extends ApiEndpoint {
5858
// Create indices for content embeddings
5959
[
6060
"CREATE VECTOR INDEX `contentEmbeddings` IF NOT EXISTS",
61-
"FOR (n: Node) ON (n.contentEmbeddings)",
61+
"FOR (n: DevDocDBNode) ON (n.contentEmbeddings)",
6262
"OPTIONS {indexConfig: {",
6363
" `vector.dimensions`: 384,",
6464
" `vector.similarity_function`: 'COSINE'",

0 commit comments

Comments
 (0)