mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 17:16:16 +08:00
feat(server): faster reranking based on confidence (#12957)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Improved document reranking with a more streamlined and accurate
scoring system.
* Enhanced support for binary ("yes"/"no") document relevance judgments.
* **Improvements**
* Simplified user prompts and output formats for reranking tasks, making
results easier to interpret.
* Increased reliability and consistency in document ranking results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -17,7 +17,6 @@ import {
|
||||
import {
|
||||
EMBEDDING_DIMENSIONS,
|
||||
EmbeddingClient,
|
||||
getReRankSchema,
|
||||
type ReRankResult,
|
||||
} from './types';
|
||||
|
||||
@@ -81,9 +80,9 @@ class ProductionEmbeddingClient extends EmbeddingClient {
|
||||
}
|
||||
|
||||
private getTargetId<T extends ChunkSimilarity>(embedding: T) {
|
||||
return 'docId' in embedding
|
||||
return 'docId' in embedding && typeof embedding.docId === 'string'
|
||||
? embedding.docId
|
||||
: 'fileId' in embedding
|
||||
: 'fileId' in embedding && typeof embedding.fileId === 'string'
|
||||
? embedding.fileId
|
||||
: '';
|
||||
}
|
||||
@@ -102,24 +101,19 @@ class ProductionEmbeddingClient extends EmbeddingClient {
|
||||
throw new CopilotPromptNotFound({ name: RERANK_PROMPT });
|
||||
}
|
||||
const provider = await this.getProvider({ modelId: prompt.model });
|
||||
const schema = getReRankSchema(embeddings.length);
|
||||
|
||||
const ranks = await provider.structure(
|
||||
const ranks = await provider.rerank(
|
||||
{ modelId: prompt.model },
|
||||
prompt.finish({
|
||||
query,
|
||||
results: embeddings.map(e => ({
|
||||
targetId: this.getTargetId(e),
|
||||
chunk: e.chunk,
|
||||
content: e.content,
|
||||
})),
|
||||
schema,
|
||||
}),
|
||||
{ maxRetries: 3, signal }
|
||||
embeddings.map(e => prompt.finish({ query, doc: e.content })),
|
||||
{ signal }
|
||||
);
|
||||
|
||||
try {
|
||||
return schema.parse(JSON.parse(ranks)).ranks;
|
||||
return ranks.map((score, i) => ({
|
||||
chunk: embeddings[i].content,
|
||||
targetId: this.getTargetId(embeddings[i]),
|
||||
score,
|
||||
}));
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to parse rerank results', error);
|
||||
// silent error, will fallback to default sorting in parent method
|
||||
@@ -176,9 +170,9 @@ class ProductionEmbeddingClient extends EmbeddingClient {
|
||||
|
||||
const highConfidenceChunks = ranks
|
||||
.flat()
|
||||
.toSorted((a, b) => b.scores.score - a.scores.score)
|
||||
.filter(r => r.scores.score > 5)
|
||||
.map(r => chunks[`${r.scores.targetId}:${r.scores.chunk}`])
|
||||
.toSorted((a, b) => b.score - a.score)
|
||||
.filter(r => r.score > 5)
|
||||
.map(r => chunks[`${r.targetId}:${r.chunk}`])
|
||||
.filter(Boolean);
|
||||
|
||||
this.logger.verbose(
|
||||
|
||||
@@ -177,11 +177,6 @@ export abstract class EmbeddingClient {
|
||||
|
||||
const ReRankItemSchema = z.object({
|
||||
scores: z.object({
|
||||
reason: z
|
||||
.string()
|
||||
.describe(
|
||||
'Think step by step, describe in 20 words the reason for giving this score.'
|
||||
),
|
||||
chunk: z.string().describe('The chunk index of the search result.'),
|
||||
targetId: z.string().describe('The id of the target.'),
|
||||
score: z
|
||||
@@ -194,11 +189,4 @@ const ReRankItemSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const getReRankSchema = (size: number) =>
|
||||
z.object({
|
||||
ranks: ReRankItemSchema.array().describe(
|
||||
`A array of scores. Make sure to score all ${size} results.`
|
||||
),
|
||||
});
|
||||
|
||||
export type ReRankResult = z.infer<ReturnType<typeof getReRankSchema>>['ranks'];
|
||||
export type ReRankResult = z.infer<typeof ReRankItemSchema>['scores'][];
|
||||
|
||||
Reference in New Issue
Block a user