Skip to content

Commit

Permalink
feat(search): add LLM reranker and reranker interface #46
Browse files Browse the repository at this point in the history
Implement a new LLM reranker class and a reranker interface in the search module. The LLM reranker uses a prompt to score the relevance of code snippets to a given query. The reranker interface defines the structure for reranking operations.
  • Loading branch information
phodal committed Aug 3, 2024
1 parent 1e1d556 commit 6a7b599
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.phodal.shirecore.search.rank

import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.phodal.shirecore.llm.LlmProvider
import com.phodal.shirecore.search.function.IndexEntry
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.flow.cancellable

fun RERANK_PROMPT(query: String, documentId: String, document: String): String {

Check notice on line 11 in core/src/main/kotlin/com/phodal/shirecore/search/rank/LlmReRanker.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Function naming convention

Function name `RERANK_PROMPT` should start with a lowercase letter
return """
You are an expert software developer responsible for helping detect whether the retrieved snippet of code is relevant to the query. For a given input, you need to output a single word: "Yes" or "No" indicating the retrieved snippet is relevant to the query.
Query: Where is the FastAPI server?
Snippet:
```/Users/andrew/Desktop/server/main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
fun read_root(): Map<String, String> {
return mapOf("Hello" to "World")
}
```
Relevant: Yes
Query: Where in the documentation does it talk about the UI?
Snippet:
```/Users/andrew/Projects/bubble_sort/src/lib.rs
fn bubble_sort<T: Ord>(arr: &mut [T]) {
for i in 0..arr.size {
for j in 1 until arr.size - i {
if (arr[j - 1] > arr[j]) {
arr.swap(j - 1, j)
}
}
}
}
```
Relevant: No
Query: $query
Snippet:
```$documentId
$document
```
Relevant:
""".trimIndent()
}


@Service(Service.Level.PROJECT)
class LLMReranker(val project: Project) : Reranker {

Check warning on line 53 in core/src/main/kotlin/com/phodal/shirecore/search/rank/LlmReRanker.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Class "LLMReranker" is never used
override val name = "llmReranker"

private suspend fun scoreChunk(chunk: IndexEntry, query: String): Double {
val prompt = RERANK_PROMPT(query, getBasename(chunk.file), chunk.chunk)

val stream = LlmProvider.provider(project)?.stream(prompt, "", false)!!
var completion: String = ""

Check warning on line 60 in core/src/main/kotlin/com/phodal/shirecore/search/rank/LlmReRanker.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Obvious explicit type

Explicitly given type is redundant here
runBlocking {
stream.cancellable().collect {
completion += it
}
}

if (completion.isBlank()) {
return 0.0
}

val answer = completion
.trim()
.lowercase()
.replace("\"", "")
.replace("'", "")

return when (answer) {
"yes" -> 1.0
"no" -> 0.0
else -> {
println("Unexpected response from single token reranker: \"$answer\". Expected \"yes\" or \"no\".")
0.0
}
}
}

private fun getBasename(file: VirtualFile?): String {
return file?.path?.substringAfterLast("/") ?: "unknown"
}

override suspend fun rerank(query: String, chunks: List<IndexEntry>): List<Double> {
return chunks.map { chunk -> scoreChunk(chunk, query) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.phodal.shirecore.search.rank

import cc.unitmesh.nlp.embedding.Embedding
import com.phodal.shirecore.search.function.IndexEntry

interface Reranker {
val name: String
suspend fun rerank(query: String, chunks: List<IndexEntry>): Embedding
}

0 comments on commit 6a7b599

Please sign in to comment.