archgraph-argo 0.20.2 → 0.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -240,12 +240,12 @@ async function executeWpP2Retrieval({
|
|
|
240
240
|
const lexicalTopK = hybridTopK();
|
|
241
241
|
const fusionK = rrfK();
|
|
242
242
|
const fusionWeights = hybridWeights();
|
|
243
|
-
const rerank = isRerankEnabled();
|
|
243
|
+
const rerank = isRerankEnabled() && request.rerank !== false;
|
|
244
244
|
const rerankOptions = rerankConfig();
|
|
245
245
|
const rerankProvider = rerank ? resolveRerankProvider(configurationEvidence.configuration) : null;
|
|
246
246
|
// Rerank needs a larger candidate pool than the final top-K.
|
|
247
247
|
const pool = rerank ? Math.max(topK, rerankOptions.poolSize) : topK;
|
|
248
|
-
const
|
|
248
|
+
const channelSeeds = [];
|
|
249
249
|
for (const channel of CHANNELS) {
|
|
250
250
|
const vectorSeeds = await exhaustChannel({
|
|
251
251
|
channel,
|
|
@@ -266,17 +266,27 @@ async function executeWpP2Retrieval({
|
|
|
266
266
|
});
|
|
267
267
|
seeds = fuseChannelSeeds({ vectorSeeds, lexicalSeeds, k: fusionK, limit: Math.max(pool, lexicalTopK), weights: fusionWeights });
|
|
268
268
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
269
|
+
channelSeeds.push({ channel, seeds });
|
|
270
|
+
}
|
|
271
|
+
if (rerank) {
|
|
272
|
+
// Rerank every channel CONCURRENTLY: the LLM calls dominate latency and are
|
|
273
|
+
// independent, so parallelizing turns the cost from sum(channels) into
|
|
274
|
+
// ~one call. fail-open: a null/empty order keeps the original ordering.
|
|
275
|
+
const rerankedSeeds = await Promise.all(channelSeeds.map(({ seeds }) => (
|
|
276
|
+
seeds.length > 1
|
|
277
|
+
? rerankCandidates({
|
|
278
|
+
query: request.intent,
|
|
279
|
+
candidates: seeds,
|
|
280
|
+
provider: rerankProvider,
|
|
281
|
+
transport: composition.transport,
|
|
282
|
+
maxReturn: rerankOptions.maxReturn,
|
|
283
|
+
}).then(ordered => applyRerankOrder(seeds, ordered, topK))
|
|
284
|
+
: seeds
|
|
285
|
+
)));
|
|
286
|
+
channelSeeds.forEach((entry, index) => { entry.seeds = rerankedSeeds[index]; });
|
|
287
|
+
}
|
|
288
|
+
const seedsByType = {};
|
|
289
|
+
for (const { channel, seeds } of channelSeeds) {
|
|
280
290
|
seedsByType[channel.key] = seeds;
|
|
281
291
|
}
|
|
282
292
|
return completeSemanticResult({
|
|
@@ -6,9 +6,18 @@
|
|
|
6
6
|
// the caller keeps the original ordering. Pure helpers are exported for tests.
|
|
7
7
|
|
|
8
8
|
const DEFAULT_RERANK_MODEL = 'qwen-turbo';
|
|
9
|
+
// Candidate pool size. The pool is the recall CEILING: a target the seed stage
|
|
10
|
+
// ranks outside the pool can never be recovered by rerank, so it must NOT be
|
|
11
|
+
// shrunk for speed. Keep the original 20. With DeepSeek thinking disabled a
|
|
12
|
+
// single rerank call is ~flat across candidate counts (8-40 all ~1s), so a
|
|
13
|
+
// larger pool costs ~nothing -- never trade recall for latency here.
|
|
9
14
|
const DEFAULT_RERANK_POOL = 20;
|
|
10
15
|
const DEFAULT_RERANK_RETURN = 8;
|
|
11
|
-
|
|
16
|
+
// Per-call timeout. Channel reranks run concurrently, so the end-to-end rerank
|
|
17
|
+
// cost is ~one timeout, not N. 3.5s keeps the whole semantic query under ~5s
|
|
18
|
+
// while still letting typical calls (1-4s) complete; slower calls fail open to
|
|
19
|
+
// the pre-rerank (fused) order. Overridable via ARGO_SEMANTIC_RERANK_TIMEOUT_MS.
|
|
20
|
+
const DEFAULT_RERANK_TIMEOUT_MS = 3500;
|
|
12
21
|
|
|
13
22
|
function rerankTimeoutMs(env = process.env) {
|
|
14
23
|
const value = Number(env && env.ARGO_SEMANTIC_RERANK_TIMEOUT_MS);
|
|
@@ -110,6 +119,11 @@ async function rerankCandidates({ query, candidates, provider, transport, maxRet
|
|
|
110
119
|
model,
|
|
111
120
|
temperature: 0,
|
|
112
121
|
response_format: { type: 'json_object' },
|
|
122
|
+
// DeepSeek's default is a "thinking" model: for a listwise ranking it spends
|
|
123
|
+
// 5k-10k reasoning tokens per call (measured 6-12s, highly variable) with no
|
|
124
|
+
// accuracy gain. Disable thinking for a fast, deterministic rerank
|
|
125
|
+
// (deepseek-flash: ~6s -> ~0.7s, reasoning tokens -> 0).
|
|
126
|
+
...(provider.provider === 'deepseek' ? { thinking: { type: 'disabled' } } : {}),
|
|
113
127
|
messages: [
|
|
114
128
|
{ role: 'system', content: 'You rank architecture elements by relevance to a query. Return ONLY JSON {"order":[ids best-first]} using only the candidate ids.' },
|
|
115
129
|
{ role: 'user', content: `Query: ${query}\n\nCandidates (id\\ttext):\n${list.map(candidate => `${candidate.id}\t${candidateText(candidate)}`).join('\n')}\n\nReturn up to ${Math.min(maxReturn || DEFAULT_RERANK_RETURN, list.length)} ids best-first.` },
|
|
@@ -2801,7 +2801,7 @@ async function buildSemanticDedupAdvisory(context, mutations, dependencies) {
|
|
|
2801
2801
|
const intent = [element.type, element.name, element.description]
|
|
2802
2802
|
.filter(part => typeof part === 'string' && part.trim() !== '')
|
|
2803
2803
|
.join(' ');
|
|
2804
|
-
const retrieved = await journey.query({ purpose: 'general', intent, topK: SEMANTIC_DEDUP_TOP_K });
|
|
2804
|
+
const retrieved = await journey.query({ purpose: 'general', intent, topK: SEMANTIC_DEDUP_TOP_K, rerank: false });
|
|
2805
2805
|
const source = retrieved && (retrieved.result || retrieved.document) || retrieved;
|
|
2806
2806
|
const subset = buildCanonicalSemanticDocumentSubset(source, context.document);
|
|
2807
2807
|
const elements = subset && subset.status === 'passed' && subset.document
|
package/package.json
CHANGED