[LangChain] 22. 回退机制
什么是回退机制?
可以理解为一种“保险机制”,就像:
- A 计划不行 → 执行 B 计划
- A 服务器挂了 → 走 B 节点
- A 模型限流 → 让本地模型顶上
主模型出错时,自动调用备用模型继续执行,用户无感知,体验不中断
如何实现回退
早期的时候,LangChain.js 没有提供相应的 API,所以需要通过 try/catch 来进行模拟:
async function safeInvoke(prompt) {
try {
const res = await openaiLLM.invoke(prompt);
console.log("OpenAI模型回复:", res.content);
} catch (err) {
console.warn("OpenAI模型出错,切换到备用模型:", err.message);
const fallbackRes = await llama3LLM.invoke(prompt);
console.log("Llama3模型回复:", fallbackRes.content);
}
}
不过这种模型不够优雅,而且有一定的局限性。
现在 LangChain.js 已经提供了对应的方法 withFallbacks,这是 Runnable 类型上的一个方法:给“主”Runnable 挂上备选 Runnable 列表。当主 Runnable 执行失败(抛错)时,会按顺序尝试后备,直到某个成功或全部失败为止。
-
在现有 Runnable 上调用
const chainWithFallback = primaryRunnable.withFallbacks([fallback1, fallback2]); -
直接实例化 RunnableWithFallbacks(工具类)
import { RunnableWithFallbacks } from "@langchain/core/runnables"; const r = new RunnableWithFallbacks({ runnable: primaryRunnable, // 主链 fallbacks: [fallback1, fallback2], // 备用链 });
课堂练习
使用 withFallbacks 实现回退
import { ChatOpenAI } from "@langchain/openai";
import { ChatOllama } from "@langchain/ollama";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnableLambda, RunnableSequence } from "@langchain/core/runnables";
import dotenv from "dotenv";
dotenv.config();
// 1. 创建 3 个链条
// 主模型
const primaryLLM = new ChatOpenAI({
model: "gpt-4o-mini",
temperature: 0,
// apiKey: process.env.API_KEY,
streaming: true,
});
// 备用模型
const secondaryLLM = new ChatOpenAI({
model: "gpt-3.5-turbo",
temperature: 0,
// apiKey: process.env.API_KEY,
streaming: true,
});
// 本地模型
const localLLM = new ChatOllama({
model: "llama3",
temperature: 0,
streaming: true,
});
// 提示词
const pt = ChatPromptTemplate.fromTemplate(
"请用中文、最多三句话回答:{question}"
);
// 解析器
const parser = new StringOutputParser();
// 一个中间件
// source 就是来源于哪个链:主链、备用链、本地链
function tagOutput(source) {
return new RunnableLambda({
func: async (text) => `[from=${source}] ${text}`,
});
}
// 组装链条
const primaryChain = RunnableSequence.from([
pt,
primaryLLM,
parser,
// tagOutput("主链"),
]);
const secondaryChain = RunnableSequence.from([
pt,
secondaryLLM,
parser,
// tagOutput("备用链"),
]);
const localChain = RunnableSequence.from([
pt,
localLLM,
parser,
// tagOutput("本地链"),
]);
// 根据上面的三条链,组装成一条可回退的链条
const canFallbackChain = primaryChain.withFallbacks([
secondaryChain,
localChain,
]);
const stream = await canFallbackChain.streamEvents(
{
question: "RAG的核心是什么?",
},
{
version: "v2",
}
);
for await (const chunk of stream) {
if (chunk.event === "on_chat_model_stream") {
process.stdout.write(chunk.data.chunk.content);
}
}
质量驱动的“软回退”
默认回退只在抛异常时触发。如果你想“结果不达标时也回退”,可以在主链末尾加一个“校验器”,不达标就主动抛错,让回退机制接管。
import { RunnableLambda } from "@langchain/core/runnables";
// 一个简单的输出质量校验器:含“抱歉/无法”就认为不达标
const rejectIfLowQuality = new RunnableLambda({
func: async (text: string) => {
const bad = /抱歉|无法|我不能/.test(text);
if (bad) {
throw new Error("LowQualityOutput"); // 主动抛错,触发回退
}
return text;
},
});
// 把校验器挂在主链末尾
const primaryChecked = primaryChain.pipe(rejectIfLowQuality);
// 回退链保持不变
const resilientQuality = primaryChecked.withFallbacks([secondaryChain, localChain]);
const answer = await resilientQuality.invoke({
question: "给我 3 条提升 RAG 召回质量的做法。",
});
-EOF-

浙公网安备 33010602011771号