如何在Node.js的LangChain RetrievalQAChain中添加系统消息
解决LangChain RetrievalQA系统消息不生效问题
要让回答和问题语言保持一致,你需要自定义RetrievalQA的提示模板,将系统规则融入到LLM的输入逻辑中,而不是简单拼接问题或传入额外参数。以下是具体修改方案:
核心问题
你使用的RetrievalQAChain默认提示模板不支持直接传入系统消息,之前的方法(拼接问题、chain.call额外参数)无法让LLM识别到这条规则,导致部分场景下翻译失效。
修改步骤
1. 切换为ChatOpenAI模型
Chat模型原生支持系统消息的格式规范,比基础OpenAI模型更适合处理这类对话规则:
const { ChatOpenAI } = require("langchain/chat_models/openai"); // 替换原来的 new OpenAI({}) const model = new ChatOpenAI({});
2. 构建包含系统消息的自定义提示模板
使用ChatPromptTemplate创建包含系统消息、上下文、用户问题的完整prompt结构:
const { ChatPromptTemplate } = require("langchain/prompts"); const systemMessage = "Answer in the same language as the question"; const prompt = ChatPromptTemplate.fromMessages([ ["system", systemMessage], ["human", "使用以下上下文回答问题:\n{context}\n\n问题:{question}"] ]);
3. 配置RetrievalQAChain使用自定义prompt
通过RetrievalQAChain.fromLLM的第三个参数传入自定义prompt,并指定返回格式:
const chain = RetrievalQAChain.fromLLM(model, vectorStoreRetriever, { prompt: prompt, returnSourceDocuments: false, // 根据需求设置是否返回源文档 });
4. 调用chain时传入正确参数
现在调用chain时,需要传入question参数(替换原来的query):
response = await chain.call({ question: question, });
完整修改后的代码
const fs = require('fs'); const fsPromises = fs.promises; const { ChatOpenAI } = require("langchain/chat_models/openai"); const { RecursiveCharacterTextSplitter } = require("langchain/text_splitter"); const { HNSWLib } = require("langchain/vectorstores/hnswlib"); const { OpenAIEmbeddings } = require("langchain/embeddings/openai"); const { RetrievalQAChain } = require("langchain/chains"); const { ChatPromptTemplate } = require("langchain/prompts"); app.post('/faq', async (req, res) => { const question = req.body.question; let answers = {}; try { const data = await fsPromises.readFile("answers.json", "utf8"); answers = JSON.parse(data); } catch (error) { console.log('answers.json does not exist') } let response; if (answers[question]) { response = answers[question]; } else { const model = new ChatOpenAI({}); const text = fs.readFileSync("test.txt", "utf8"); const textSplitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000 }); const docs = await textSplitter.createDocuments([text]); const vectorStore = await HNSWLib.fromDocuments(docs, new OpenAIEmbeddings()); const vectorStoreRetriever = vectorStore.asRetriever(); // 构建包含系统消息的自定义prompt const systemMessage = "Answer in the same language as the question"; const prompt = ChatPromptTemplate.fromMessages([ ["system", systemMessage], ["human", "使用以下上下文回答问题:\n{context}\n\n问题:{question}"] ]); // 配置RetrievalQAChain使用自定义prompt const chain = RetrievalQAChain.fromLLM(model, vectorStoreRetriever, { prompt: prompt, returnSourceDocuments: false, }); response = await chain.call({ question: question, }); console.log(response); answers[question] = response; try { await fsPromises.writeFile("answers.json", JSON.stringify(answers, null, 2), "utf8"); } catch (error) { console.log('Error writing json file.') } } res.status(200).json(response); });
额外说明
- 如果你坚持使用基础
OpenAI模型而非ChatOpenAI,可以直接将系统消息拼接进prompt模板的前缀部分,比如:const { PromptTemplate } = require("langchain/prompts"); const prompt = new PromptTemplate({ template: "Answer in the same language as the question\n使用以下上下文回答问题:\n{context}\n\n问题:{question}", inputVariables: ["context", "question"], }); - 确保你的API密钥配置正确,
ChatOpenAI和OpenAI的初始化参数一致,只需替换类名即可。
内容的提问来源于stack exchange,提问作者Geister
相关产品推荐
相关产品推荐

