@devilsdev/rag-core 3.3.0 → 3.4.0
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.
package/dist/index.cjs
CHANGED
|
@@ -1296,7 +1296,7 @@ var require_package = __commonJS({
|
|
|
1296
1296
|
"package.json"(exports2, module2) {
|
|
1297
1297
|
module2.exports = {
|
|
1298
1298
|
name: "@devilsdev/rag-pipeline-utils",
|
|
1299
|
-
version: "3.
|
|
1299
|
+
version: "3.4.0",
|
|
1300
1300
|
description: "Composable retrieval-augmented generation (RAG) for Node.js: grounded citations, evaluation, guardrails, hybrid retrieval and a CLI.",
|
|
1301
1301
|
main: "dist/index.cjs",
|
|
1302
1302
|
type: "commonjs",
|
|
@@ -1550,10 +1550,10 @@ var require_package = __commonJS({
|
|
|
1550
1550
|
"why-is-node-running": "^3.2.2"
|
|
1551
1551
|
},
|
|
1552
1552
|
dependencies: {
|
|
1553
|
-
"@devilsdev/rag-connectors": "3.
|
|
1554
|
-
"@devilsdev/rag-core": "3.
|
|
1555
|
-
"@devilsdev/rag-eval": "3.
|
|
1556
|
-
"@devilsdev/rag-guardrails": "3.
|
|
1553
|
+
"@devilsdev/rag-connectors": "3.4.0",
|
|
1554
|
+
"@devilsdev/rag-core": "3.4.0",
|
|
1555
|
+
"@devilsdev/rag-eval": "3.4.0",
|
|
1556
|
+
"@devilsdev/rag-guardrails": "3.4.0",
|
|
1557
1557
|
ajv: "^8.17.1",
|
|
1558
1558
|
axios: "^1.21.0",
|
|
1559
1559
|
chokidar: "^4.0.3",
|
|
@@ -35,6 +35,10 @@ export type GroundingMiddlewareOptions = {
|
|
|
35
35
|
* - Run checkAnswer on the answer
|
|
36
36
|
*/
|
|
37
37
|
check?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* - An LLM with `generate()` (this library's LLM contract, e.g. `createAiSdkAdapter({ ai, languageModel }).llm`) that rules on the sentences the lexical check failed for lack of word overlap; see checkAnswer. Give it the base model, not the wrapped one, or each judge call is grounded again
|
|
40
|
+
*/
|
|
41
|
+
judge?: any;
|
|
38
42
|
/**
|
|
39
43
|
* - Return the passages as source parts
|
|
40
44
|
*/
|
|
@@ -96,6 +100,10 @@ export type GroundingReport = {
|
|
|
96
100
|
* - Per-sentence citations
|
|
97
101
|
*/
|
|
98
102
|
citations?: Array<any>;
|
|
103
|
+
/**
|
|
104
|
+
* - With the `judge` option: the verdicts, the number of calls, the token usage when known, and `error` when the judge failed (its sentences then stay unsupported)
|
|
105
|
+
*/
|
|
106
|
+
judge?: any;
|
|
99
107
|
/**
|
|
100
108
|
* - What each enabled guard found
|
|
101
109
|
*/
|
|
@@ -135,6 +143,7 @@ export function groundingMiddleware(options?: GroundingMiddlewareOptions): any;
|
|
|
135
143
|
* @property {Function} [countTokens] - Token counter for maxContextTokens
|
|
136
144
|
* @property {string} [systemPrompt] - Replaces the default RAG system prompt
|
|
137
145
|
* @property {boolean} [check=true] - Run checkAnswer on the answer
|
|
146
|
+
* @property {Object} [judge] - An LLM with `generate()` (this library's LLM contract, e.g. `createAiSdkAdapter({ ai, languageModel }).llm`) that rules on the sentences the lexical check failed for lack of word overlap; see checkAnswer. Give it the base model, not the wrapped one, or each judge call is grounded again
|
|
138
147
|
* @property {boolean} [sources=true] - Return the passages as source parts
|
|
139
148
|
* @property {Object|boolean} [preRetrieval] - PreRetrievalGuard options (true for defaults): injection detection on the query
|
|
140
149
|
* @property {Object|boolean} [retrieval] - RetrievalGuard options (true for defaults): ACL, minimum score, injection in documents
|
|
@@ -152,6 +161,7 @@ export function groundingMiddleware(options?: GroundingMiddlewareOptions): any;
|
|
|
152
161
|
* @property {number} [groundedness] - Share of supported sentences, 0..1
|
|
153
162
|
* @property {string[]} [unsupported] - Sentences no passage supports
|
|
154
163
|
* @property {Array<Object>} [citations] - Per-sentence citations
|
|
164
|
+
* @property {Object} [judge] - With the `judge` option: the verdicts, the number of calls, the token usage when known, and `error` when the judge failed (its sentences then stay unsupported)
|
|
155
165
|
* @property {Object} guardrails - What each enabled guard found
|
|
156
166
|
*/
|
|
157
167
|
export class GroundingBlockedError extends Error {
|
|
@@ -37,6 +37,74 @@ export type AnswerCheck = {
|
|
|
37
37
|
content: string;
|
|
38
38
|
metadata: any;
|
|
39
39
|
}>;
|
|
40
|
+
/**
|
|
41
|
+
* - Only when the `judge` option is given
|
|
42
|
+
*/
|
|
43
|
+
judge?: JudgeReport;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Any LLM for the `judge` option: this library's LLM plugin contract.
|
|
47
|
+
* `generate` may return the text, or an object with `text` or `content`
|
|
48
|
+
* (and optionally `usage`).
|
|
49
|
+
*/
|
|
50
|
+
export type JudgeLLM = {
|
|
51
|
+
generate: (prompt: string, context: Array<any>, options?: any) => (string | {
|
|
52
|
+
text?: string;
|
|
53
|
+
content?: string;
|
|
54
|
+
usage?: any;
|
|
55
|
+
} | Promise<string | {
|
|
56
|
+
text?: string;
|
|
57
|
+
content?: string;
|
|
58
|
+
usage?: any;
|
|
59
|
+
}>);
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The verdict on one sentence when a judge is used.
|
|
63
|
+
*/
|
|
64
|
+
export type JudgeVerdict = {
|
|
65
|
+
sentence: string;
|
|
66
|
+
/**
|
|
67
|
+
* - The combined verdict
|
|
68
|
+
*/
|
|
69
|
+
verdict: "supported" | "unsupported";
|
|
70
|
+
/**
|
|
71
|
+
* - Id of the supporting source, when supported
|
|
72
|
+
*/
|
|
73
|
+
sourceId: string | null;
|
|
74
|
+
/**
|
|
75
|
+
* - Why, in words (the judge's reason when it decided)
|
|
76
|
+
*/
|
|
77
|
+
reason: string;
|
|
78
|
+
/**
|
|
79
|
+
* - What the lexical check found. Only `low_overlap` sentences go to the judge
|
|
80
|
+
*/
|
|
81
|
+
lexicalReason: "supported" | "low_overlap" | "number_mismatch" | "polarity_mismatch" | "no_sources";
|
|
82
|
+
decidedBy: "lexical" | "judge";
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* What the judge did.
|
|
86
|
+
*/
|
|
87
|
+
export type JudgeReport = {
|
|
88
|
+
/**
|
|
89
|
+
* - One per sentence, in order
|
|
90
|
+
*/
|
|
91
|
+
verdicts: JudgeVerdict[];
|
|
92
|
+
/**
|
|
93
|
+
* - Calls made to `judge.generate` (0 or 1)
|
|
94
|
+
*/
|
|
95
|
+
calls: number;
|
|
96
|
+
/**
|
|
97
|
+
* - Token usage summed over the calls, when the LLM result carries `usage`
|
|
98
|
+
*/
|
|
99
|
+
usage?: {
|
|
100
|
+
inputTokens: number;
|
|
101
|
+
outputTokens: number;
|
|
102
|
+
totalTokens: number;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* - Why the judge's reply could not be parsed
|
|
106
|
+
*/
|
|
107
|
+
error?: string;
|
|
40
108
|
};
|
|
41
109
|
/**
|
|
42
110
|
* @typedef {Object} AnswerCheck
|
|
@@ -51,6 +119,37 @@ export type AnswerCheck = {
|
|
|
51
119
|
* referenceAnswer is given); only when `evaluate` is not false
|
|
52
120
|
* @property {Array<{id: string, content: string, metadata: Object}>} sources
|
|
53
121
|
* - The sources as they were checked
|
|
122
|
+
* @property {JudgeReport} [judge] - Only when the `judge` option is given
|
|
123
|
+
*/
|
|
124
|
+
/**
|
|
125
|
+
* Any LLM for the `judge` option: this library's LLM plugin contract.
|
|
126
|
+
* `generate` may return the text, or an object with `text` or `content`
|
|
127
|
+
* (and optionally `usage`).
|
|
128
|
+
*
|
|
129
|
+
* @typedef {Object} JudgeLLM
|
|
130
|
+
* @property {(prompt: string, context: Array<any>, options?: Object) => (string|{text?: string, content?: string, usage?: Object}|Promise<string|{text?: string, content?: string, usage?: Object}>)} generate
|
|
131
|
+
*/
|
|
132
|
+
/**
|
|
133
|
+
* The verdict on one sentence when a judge is used.
|
|
134
|
+
*
|
|
135
|
+
* @typedef {Object} JudgeVerdict
|
|
136
|
+
* @property {string} sentence
|
|
137
|
+
* @property {'supported'|'unsupported'} verdict - The combined verdict
|
|
138
|
+
* @property {string|null} sourceId - Id of the supporting source, when supported
|
|
139
|
+
* @property {string} reason - Why, in words (the judge's reason when it decided)
|
|
140
|
+
* @property {'supported'|'low_overlap'|'number_mismatch'|'polarity_mismatch'|'no_sources'} lexicalReason
|
|
141
|
+
* - What the lexical check found. Only `low_overlap` sentences go to the judge
|
|
142
|
+
* @property {'lexical'|'judge'} decidedBy
|
|
143
|
+
*/
|
|
144
|
+
/**
|
|
145
|
+
* What the judge did.
|
|
146
|
+
*
|
|
147
|
+
* @typedef {Object} JudgeReport
|
|
148
|
+
* @property {JudgeVerdict[]} verdicts - One per sentence, in order
|
|
149
|
+
* @property {number} calls - Calls made to `judge.generate` (0 or 1)
|
|
150
|
+
* @property {{inputTokens: number, outputTokens: number, totalTokens: number}} [usage]
|
|
151
|
+
* - Token usage summed over the calls, when the LLM result carries `usage`
|
|
152
|
+
* @property {string} [error] - Why the judge's reply could not be parsed
|
|
54
153
|
*/
|
|
55
154
|
/**
|
|
56
155
|
* Check an answer against the sources it was generated from.
|
|
@@ -74,15 +173,24 @@ export type AnswerCheck = {
|
|
|
74
173
|
* @param {Object} [params.embedder] - With a referenceAnswer, adds
|
|
75
174
|
* `evaluation.scores.semanticSimilarity` (computeSemanticSimilarity)
|
|
76
175
|
* @param {boolean} [params.evaluate=true] - Also compute evaluation scores
|
|
176
|
+
* @param {JudgeLLM} [params.judge] - Opt-in LLM judge for sentences the
|
|
177
|
+
* lexical check failed for lack of word overlap (correct paraphrases).
|
|
178
|
+
* It never overturns a sentence that failed the number or negation check,
|
|
179
|
+
* and a "supported" verdict must name a source whose numbers and negation
|
|
180
|
+
* match the sentence. Unparseable output keeps a sentence unsupported.
|
|
181
|
+
* With a judge, `grounded`, `groundedness` and `unsupported` combine both
|
|
182
|
+
* checks and `judge` reports the verdicts; `citations` and `evaluation`
|
|
183
|
+
* stay lexical. Errors thrown by `judge.generate` are not caught.
|
|
77
184
|
* @returns {Promise<AnswerCheck>}
|
|
78
185
|
*/
|
|
79
|
-
export function checkAnswer({ answer, sources, question, referenceAnswer, embedder, evaluate, }?: {
|
|
186
|
+
export function checkAnswer({ answer, sources, question, referenceAnswer, embedder, evaluate, judge, }?: {
|
|
80
187
|
answer: string;
|
|
81
188
|
sources: Array<string | any>;
|
|
82
189
|
question?: string;
|
|
83
190
|
referenceAnswer?: string;
|
|
84
191
|
embedder?: any;
|
|
85
192
|
evaluate?: boolean;
|
|
193
|
+
judge?: JudgeLLM;
|
|
86
194
|
}): Promise<AnswerCheck>;
|
|
87
195
|
/**
|
|
88
196
|
* Normalize sources to `{ id, content, metadata }`.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export namespace REASONS {
|
|
2
|
+
let supported: string;
|
|
3
|
+
let lowOverlap: string;
|
|
4
|
+
let numberMismatch: string;
|
|
5
|
+
let polarityMismatch: string;
|
|
6
|
+
let noSources: string;
|
|
7
|
+
}
|
|
8
|
+
/** Instructions at the top of every judge prompt. */
|
|
9
|
+
export const JUDGE_INSTRUCTIONS: string;
|
|
10
|
+
/**
|
|
11
|
+
* Build the judge prompt for the given claims.
|
|
12
|
+
*
|
|
13
|
+
* @param {string[]} claims - Sentences to rule on
|
|
14
|
+
* @param {Array<{id: string, content: string}>} docs
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
export function buildJudgePrompt(claims: string[], docs: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
content: string;
|
|
20
|
+
}>): string;
|
|
21
|
+
/**
|
|
22
|
+
* Parse the judge's reply into one verdict per claim. Tolerates a code fence
|
|
23
|
+
* around the JSON; anything else that is not the expected array leaves every
|
|
24
|
+
* claim without a verdict.
|
|
25
|
+
*
|
|
26
|
+
* @param {*} raw - What llm.generate() returned
|
|
27
|
+
* @param {number} claimCount
|
|
28
|
+
* @returns {{ verdicts: Array<{verdict: string, source: string|null, reason: string}|null>, error: string|null }}
|
|
29
|
+
* verdicts[i] is null when claim i+1 got no well-formed verdict
|
|
30
|
+
*/
|
|
31
|
+
export function parseJudgeVerdicts(raw: any, claimCount: number): {
|
|
32
|
+
verdicts: Array<{
|
|
33
|
+
verdict: string;
|
|
34
|
+
source: string | null;
|
|
35
|
+
reason: string;
|
|
36
|
+
} | null>;
|
|
37
|
+
error: string | null;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The lexical reason for every sentence, in order.
|
|
41
|
+
*
|
|
42
|
+
* @param {Array<{text: string, classification: string}>} sentences - From
|
|
43
|
+
* CitationTracker's hallucination report
|
|
44
|
+
* @param {Array<{content: string}>} docs
|
|
45
|
+
* @returns {string[]}
|
|
46
|
+
*/
|
|
47
|
+
export function lexicalReasons(sentences: Array<{
|
|
48
|
+
text: string;
|
|
49
|
+
classification: string;
|
|
50
|
+
}>, docs: Array<{
|
|
51
|
+
content: string;
|
|
52
|
+
}>): string[];
|
|
53
|
+
/**
|
|
54
|
+
* Run the judge on the sentences that failed for lack of overlap and
|
|
55
|
+
* combine its verdicts with the lexical result.
|
|
56
|
+
*
|
|
57
|
+
* Overturn rule: a judge "supported" counts only when the sentence failed
|
|
58
|
+
* for lack of overlap, the verdict is well formed, it names a source that
|
|
59
|
+
* exists, and that source passes the numeric and polarity checks against
|
|
60
|
+
* the sentence. Everything else keeps the lexical verdict.
|
|
61
|
+
*
|
|
62
|
+
* @param {Object} params
|
|
63
|
+
* @param {{generate: Function}} params.judge
|
|
64
|
+
* @param {Array<{text: string, classification: string, bestSource: Object|null}>} params.sentences
|
|
65
|
+
* @param {Array<{id: string, content: string}>} params.docs
|
|
66
|
+
* @returns {Promise<{verdicts: Array<Object>, calls: number, usage?: Object, error?: string}>}
|
|
67
|
+
*/
|
|
68
|
+
export function runJudge({ judge, sentences, docs }: {
|
|
69
|
+
judge: {
|
|
70
|
+
generate: Function;
|
|
71
|
+
};
|
|
72
|
+
sentences: Array<{
|
|
73
|
+
text: string;
|
|
74
|
+
classification: string;
|
|
75
|
+
bestSource: any | null;
|
|
76
|
+
}>;
|
|
77
|
+
docs: Array<{
|
|
78
|
+
id: string;
|
|
79
|
+
content: string;
|
|
80
|
+
}>;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
verdicts: Array<any>;
|
|
83
|
+
calls: number;
|
|
84
|
+
usage?: any;
|
|
85
|
+
error?: string;
|
|
86
|
+
}>;
|