基于LlamaIndex TS的LINE聊天机器人无法记忆上下文问题排查
问题解决:LINE Webhook部署后LlamaIndex OpenAIAgent丢失对话上下文
问题根源
你的猜测完全正确:
- 每次LINE Webhook触发
handleEvent时,都会重新读取文件、创建VectorStoreIndex和OpenAIAgent,导致Agent没有保留之前的对话历史。 - Webhook服务是无状态的HTTP请求,每次用户消息都是独立请求,必须手动维护每个用户的对话上下文。
解决方案
需要做两个关键修改:
- 预加载资源:把文件读取、
VectorStoreIndex和工具初始化移到全局作用域,服务启动时只执行一次,避免重复计算。 - 用户上下文隔离存储:用全局对象保存每个用户的
OpenAIAgent实例(因为Agent内部维护对话历史),确保不同用户的对话互不干扰。
修正后的完整代码
const line = require('@line/bot-sdk'); const express = require('express'); const dotenv = require('dotenv'); const { OpenAI } = require("llamaindex"); const fs = require("fs").promises; const { Document, VectorStoreIndex, QueryEngineTool, OpenAIAgent } = require("llamaindex"); dotenv.config(); const lineConfig = { channelAccessToken: process.env.ACESS_TOKEN, channelSecret: process.env.SECRET_TOKEN }; const client = new line.Client(lineConfig); const app = express(); // 全局变量:预加载的索引和工具 let vectorIndex = null; let queryEngineTool = null; // 全局对象:存储每个用户的Agent实例(key: userId, value: OpenAIAgent) const userAgents = {}; // 服务启动时预加载资源,只执行一次 async function preloadResources() { const path = "data/car.json"; const essay = await fs.readFile(path, "utf-8"); const document = new Document({ text: essay, id_: path }); vectorIndex = await VectorStoreIndex.fromDocuments([document]); queryEngineTool = new QueryEngineTool({ queryEngine: vectorIndex.asQueryEngine(), metadata: { name: "vector_index", description: "Useful when you want to answer questions about information about cars assembled in Thailand.", }, }); console.log("Resources preloaded successfully"); } app.post('/webhook', line.middleware(lineConfig), async(req, res) => { try { const events = req.body.events; console.log('events >>>>', events); if (events && events.length > 0) { await Promise.all(events.map(async(event) => { await handleEvent(event); })); } res.status(200).send('OK'); } catch (error) { console.error('Error processing events:', error); res.status(500).end(); } }); const handleEvent = async(event) => { if (event.type !== 'message' || event.message.type !== 'text') { return null; } const userQuery = event.message.text; const userId = event.source.userId; // 为当前用户初始化Agent(如果不存在) if (!userAgents[userId]) { userAgents[userId] = new OpenAIAgent({ tools: [queryEngineTool], verbose: true }); } try { // 使用用户专属的Agent进行对话,自动维护上下文 const response = await userAgents[userId].chat({ message: userQuery }); await client.pushMessage(userId, { type: 'text', text: response.message.content }); } catch (error) { console.error("Error handling query:", error); return client.pushMessage(userId, { type: 'text', text: 'Sorry, there was an error processing your request.' }); } }; // 先预加载资源,再启动服务 preloadResources().then(() => { app.listen(4000, () => { console.log('listening on 4000'); }); }).catch(console.error);
关键修改说明
预加载资源:
- 新增
preloadResources函数,在服务启动前读取文件、创建索引和工具,避免每次请求重复执行。 - 只有服务启动时执行一次,大幅提升性能并确保资源复用。
- 新增
用户上下文管理:
- 新增
userAgents全局对象,以用户ID为键存储每个用户的OpenAIAgent实例。 - 每个用户第一次发消息时创建专属Agent,后续对话复用该Agent,自动保留对话历史。
- 新增
生产环境注意事项
- 内存存储(
userAgents)在服务重启或扩容时会丢失上下文,生产环境建议改用Redis、MongoDB等持久化存储保存对话历史。 - 可以设置对话上下文的过期时间,避免内存占用过高。
内容的提问来源于stack exchange,提问作者Porapat Pengjaingam
相关产品推荐
相关产品推荐

