akm-cli
Version:
akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur
38 lines (37 loc) • 1.8 kB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
/**
* Reciprocal rank fusion (Cormack, Clarke and Büttcher, SIGIR 2009) of the
* lexical and vector candidate lists — the whole of search ranking.
*
* Fusing ranks rather than scores needs no calibration between BM25 and cosine
* similarity, so it holds for every embedding model. On the retrieval suite,
* BM25 fused with document vectors this way scored nDCG@10 0.568 against 0.349
* for the additive boost stack it replaced
* (`akm/eval/retrieval/reports/baseline-2026-09-27.md`).
*/
import { compareCodePoints } from "../../core/common.js";
/** The RRF constant: a candidate at rank r in a channel adds 1 / (RRF_K + r). */
export const RRF_K = 60;
/**
* Fuse ranked channels with equal weights. Candidates are ordered by fused
* score, then by `itemRef`, so equal scores always come back in the same order.
*/
export function reciprocalRankFusion(channels) {
const fused = new Map();
channels.forEach((channel, channelIndex) => {
channel.forEach((candidate, position) => {
let entry = fused.get(candidate.id);
if (entry === undefined) {
entry = { id: candidate.id, itemRef: candidate.itemRef, score: 0, ranks: channels.map(() => undefined) };
fused.set(candidate.id, entry);
}
if (entry.ranks[channelIndex] !== undefined)
return;
entry.ranks[channelIndex] = position + 1;
entry.score += 1 / (RRF_K + position + 1);
});
});
return [...fused.values()].sort((a, b) => b.score - a.score || compareCodePoints(a.itemRef, b.itemRef));
}