You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于LlamaIndex TS的LINE聊天机器人无法记忆上下文问题排查

问题解决:LINE Webhook部署后LlamaIndex OpenAIAgent丢失对话上下文

问题根源

你的猜测完全正确:

  • 每次LINE Webhook触发handleEvent时,都会重新读取文件、创建VectorStoreIndex和OpenAIAgent,导致Agent没有保留之前的对话历史。
  • Webhook服务是无状态的HTTP请求,每次用户消息都是独立请求,必须手动维护每个用户的对话上下文。

解决方案

需要做两个关键修改:

  1. 预加载资源:把文件读取、VectorStoreIndex和工具初始化移到全局作用域,服务启动时只执行一次,避免重复计算。
  2. 用户上下文隔离存储:用全局对象保存每个用户的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);

关键修改说明

  1. 预加载资源:

    • 新增preloadResources函数,在服务启动前读取文件、创建索引和工具,避免每次请求重复执行。
    • 只有服务启动时执行一次,大幅提升性能并确保资源复用。
  2. 用户上下文管理:

    • 新增userAgents全局对象,以用户ID为键存储每个用户的OpenAIAgent实例。
    • 每个用户第一次发消息时创建专属Agent,后续对话复用该Agent,自动保留对话历史。

生产环境注意事项

  • 内存存储(userAgents)在服务重启或扩容时会丢失上下文,生产环境建议改用Redis、MongoDB等持久化存储保存对话历史。
  • 可以设置对话上下文的过期时间,避免内存占用过高。

内容的提问来源于stack exchange,提问作者Porapat Pengjaingam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:57:21