Node.js中LangChain SQL Agent集成Bedrock模型遇OutputParserException问题
问题:LangChain SQL Agent与Llama3-2模型集成时的输出解析失败
场景与代码实现
在Node.js(Express后端)中集成LangChain SQL Agent,使用AWS Bedrock的us.meta.llama3-2-1b-instruct-v1:0模型实现自然语言转SQL。数据库为PostgreSQL,采用多架构配置:每个客户拥有独立数据库架构,且各架构表结构一致,目标是让用户通过自然语言生成并执行对应SQL查询。
代码实现:
import { BedrockChat } from "@langchain/community/chat_models/bedrock"; import { SqlToolkit, createSqlAgent } from "langchain/agents/toolkits/sql"; import { SqlDatabase } from "langchain/sql_db"; import { DataSource } from "typeorm"; async function main() { const datasource = new DataSource({ type: "postgres", host: "localhost", port: 5432, username: "myusername", password: 'mypassword', database: "postgres", }); const db = await SqlDatabase.fromDataSourceParams({ appDataSource: datasource, }); const model = new BedrockChat({ model: "us.meta.llama3-2-1b-instruct-v1:0", region: "XXX", credentials: { accessKeyId: XXXX, secretAccessKey: XXX } }); try { const sqlToolkit = new SqlToolkit(db, model); const sqlAgent = createSqlAgent(model, sqlToolkit); const input = `You are a SQL expert. Generate a PostgreSQL query to answer the following question: List the users from schema tenant_customer1 and table users.`; console.log(`Executing with input "${input}"...`); const result = await sqlAgent.invoke({ input }); console.log(`Got output ${result.output}`); } catch (error) { console.error("An error occurred:", error); } } main();
错误现象
执行自然语言查询时,触发LangChain的OutputParserException,提示模型响应格式不符合解析预期:
Executing with input "You are a SQL expert. Generate a PostgreSQL query to answer the following question: List the users from schema tenant_customer1 and table users."... An error occurred: OutputParserException [Error]: Could not parse LLM output: Here is a PostgreSQL query to answer the question: sql SELECT * FROM tenant_customer1.users; Action Input: list-tables-sql Observation: The query is correct and returns the expected results. Question: You are a Troubleshooting URL: https://js.langchain.com/docs/troubleshooting/errors/OUTPUT_PARSING_FAILURE/ at ZeroShotAgentOutputParser.parse (/node_modules/langchain/dist/agents/mrkl/outputParser.cjs:46:19) at ZeroShotAgent._plan (/node_modules/langchain/dist/agents/agent.cjs:480:34) at processTicksAndRejections (node:internal/process/task_queues:95:5) at AgentExecutor._call (/node_modules/langchain/dist/agents/executor.cjs:432:26) at AgentExecutor.invoke (/node_modules/langchain/dist/chains/base.cjs:58:28) at main (/src/helpers/bedrock.js:41:24) { llmOutput: undefined, observation: undefined, sendToLLM: false, lc_error_code: 'OUTPUT_PARSING_FAILURE' }
解决方法
1. 自定义Agent提示词,强制输出格式
ZeroShotAgent要求输出必须遵循Action: <工具名> Action Input: <输入内容>的固定格式,Llama3-2小模型容易偏离,需明确约束格式:
import { ZeroShotAgent, AgentExecutor } from "langchain/agents"; import { PromptTemplate } from "@langchain/core/prompts"; // 自定义提示词前缀与格式说明 const PREFIX = `你是PostgreSQL多架构专家,必须严格按照指定格式输出。可用工具:{tools},工具对应关系:{tool_names} 对应 {tools}。`; const FORMAT_INSTRUCTIONS = `回答必须严格遵循以下格式: 思考:分析用户问题,确定需要使用的工具 行动:<工具名称,如query_sql_db> 行动输入:<工具所需的具体输入,如SQL语句> 若已得到最终答案,直接输出: 最终答案:<你的答案>`; // 创建自定义prompt const prompt = ZeroShotAgent.createPrompt( sqlToolkit.getTools(), { prefix: PREFIX, formatInstructions: FORMAT_INSTRUCTIONS } ); // 基于自定义prompt创建Agent和执行器 const agent = ZeroShotAgent.fromLLMAndTools(model, sqlToolkit.getTools(), { prompt }); const sqlAgent = AgentExecutor.fromAgentAndTools({ agent, tools: sqlToolkit.getTools() });
2. 简化用户输入提示
原输入包含冗余的角色定义,Agent的prompt已包含角色信息,用户输入只需明确问题即可:
const input = "列出tenant_customer1架构下users表中的用户";
3. 针对小模型的格式强化
在prompt中加入格式示例,进一步约束模型输出:
// 在FORMAT_INSTRUCTIONS中添加示例 const FORMAT_INSTRUCTIONS = `回答必须严格遵循以下格式: 示例: 用户问题:列出public架构下products表的所有数据 思考:需要用query_sql_db工具执行SQL查询 行动:query_sql_db 行动输入:SELECT * FROM public.products; 正式回答格式: 思考:分析用户问题,确定需要使用的工具 行动:<工具名称> 行动输入:<工具所需输入> 若已得到最终答案,直接输出: 最终答案:<你的答案>`;
4. 自定义输出解析器(兼容模型输出风格)
若模型始终无法生成标准格式,可自定义解析器兼容其输出:
import { AgentOutputParser } from "langchain/agents"; import { OutputParserException } from "@langchain/core/exceptions"; class CustomSqlAgentParser extends AgentOutputParser { parse(text) { // 优先提取SQL语句 const sqlMatch = text.match(/sql\n(.*?);/s); if (sqlMatch) { return { tool: "query_sql_db", toolInput: sqlMatch[1].trim() + ";", log: text, }; } // 匹配标准Action格式 const actionMatch = text.match(/行动:(.*?)\n行动输入:(.*)/s); if (actionMatch) { return { tool: actionMatch[1].trim(), toolInput: actionMatch[2].trim(), log: text, }; } throw new OutputParserException(`无法解析输出:${text}`); } getFormatInstructions() { return "请输出SQL语句或遵循行动/行动输入格式"; } } // 使用自定义解析器创建Agent const agent = ZeroShotAgent.fromLLMAndTools(model, sqlToolkit.getTools(), { prompt, outputParser: new CustomSqlAgentParser(), }); const sqlAgent = AgentExecutor.fromAgentAndTools({ agent, tools: sqlToolkit.getTools() });
内容的提问来源于stack exchange,提问作者Nibin
相关产品推荐
相关产品推荐

