101 lines
3.6 KiB
JavaScript
101 lines
3.6 KiB
JavaScript
|
import { BaseOutputParser, OutputParserException, } from "@langchain/core/output_parsers";
|
||
|
import { LLMChain } from "../chains/llm_chain.js";
|
||
|
import { NAIVE_FIX_PROMPT } from "./prompts.js";
|
||
|
function isLLMChain(x) {
|
||
|
return (x.prompt !== undefined && x.llm !== undefined);
|
||
|
}
|
||
|
/**
|
||
|
* Class that extends the BaseOutputParser to handle situations where the
|
||
|
* initial parsing attempt fails. It contains a retryChain for retrying
|
||
|
* the parsing process in case of a failure.
|
||
|
*/
|
||
|
export class OutputFixingParser extends BaseOutputParser {
|
||
|
static lc_name() {
|
||
|
return "OutputFixingParser";
|
||
|
}
|
||
|
/**
|
||
|
* Static method to create a new instance of OutputFixingParser using a
|
||
|
* given language model, parser, and optional fields.
|
||
|
* @param llm The language model to be used.
|
||
|
* @param parser The parser to be used.
|
||
|
* @param fields Optional fields which may contain a prompt.
|
||
|
* @returns A new instance of OutputFixingParser.
|
||
|
*/
|
||
|
static fromLLM(llm, parser, fields) {
|
||
|
const prompt = fields?.prompt ?? NAIVE_FIX_PROMPT;
|
||
|
const chain = new LLMChain({ llm, prompt });
|
||
|
return new OutputFixingParser({ parser, retryChain: chain });
|
||
|
}
|
||
|
constructor({ parser, retryChain, }) {
|
||
|
super(...arguments);
|
||
|
Object.defineProperty(this, "lc_namespace", {
|
||
|
enumerable: true,
|
||
|
configurable: true,
|
||
|
writable: true,
|
||
|
value: ["langchain", "output_parsers", "fix"]
|
||
|
});
|
||
|
Object.defineProperty(this, "lc_serializable", {
|
||
|
enumerable: true,
|
||
|
configurable: true,
|
||
|
writable: true,
|
||
|
value: true
|
||
|
});
|
||
|
Object.defineProperty(this, "parser", {
|
||
|
enumerable: true,
|
||
|
configurable: true,
|
||
|
writable: true,
|
||
|
value: void 0
|
||
|
});
|
||
|
Object.defineProperty(this, "retryChain", {
|
||
|
enumerable: true,
|
||
|
configurable: true,
|
||
|
writable: true,
|
||
|
value: void 0
|
||
|
});
|
||
|
this.parser = parser;
|
||
|
this.retryChain = retryChain;
|
||
|
}
|
||
|
/**
|
||
|
* Method to parse the completion using the parser. If the initial parsing
|
||
|
* fails, it uses the retryChain to attempt to fix the output and retry
|
||
|
* the parsing process.
|
||
|
* @param completion The completion to be parsed.
|
||
|
* @param callbacks Optional callbacks to be used during parsing.
|
||
|
* @returns The parsed output.
|
||
|
*/
|
||
|
async parse(completion, callbacks) {
|
||
|
try {
|
||
|
return await this.parser.parse(completion, callbacks);
|
||
|
}
|
||
|
catch (e) {
|
||
|
// eslint-disable-next-line no-instanceof/no-instanceof
|
||
|
if (e instanceof OutputParserException) {
|
||
|
const retryInput = {
|
||
|
instructions: this.parser.getFormatInstructions(),
|
||
|
completion,
|
||
|
error: e,
|
||
|
};
|
||
|
if (isLLMChain(this.retryChain)) {
|
||
|
const result = await this.retryChain.call(retryInput, callbacks);
|
||
|
const newCompletion = result[this.retryChain.outputKey];
|
||
|
return this.parser.parse(newCompletion, callbacks);
|
||
|
}
|
||
|
else {
|
||
|
const result = await this.retryChain.invoke(retryInput, {
|
||
|
callbacks,
|
||
|
});
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Method to get the format instructions for the parser.
|
||
|
* @returns The format instructions for the parser.
|
||
|
*/
|
||
|
getFormatInstructions() {
|
||
|
return this.parser.getFormatInstructions();
|
||
|
}
|
||
|
}
|