{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# LightMem Example with travel data\n", "\n", "Tutorial author: xubuqiang" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 0. Prepare the runtime environment" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/disk/disk_20T/xubuqiang/lightmem\n", "env: ALL_PROXY=\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", "To disable this warning, you can either:\n", "\t- Avoid using `tokenizers` before the fork if possible\n", "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n", "Obtaining file:///disk/disk_20T/xubuqiang/lightmem\n", " Installing build dependencies ... \u001b[?25ldone\n", "\u001b[?25h Checking if build backend supports build_editable ... \u001b[?25ldone\n", "\u001b[?25h Getting requirements to build editable ... \u001b[?25ldone\n", "\u001b[?25h Preparing editable metadata (pyproject.toml) ... \u001b[?25ldone\n", "\u001b[?25hRequirement already satisfied: torch==2.8.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.8.0)\n", "Requirement already satisfied: transformers==4.57.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (4.57.0)\n", "Requirement already satisfied: sentence-transformers==5.1.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (5.1.1)\n", "Requirement already satisfied: accelerate==1.10.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.10.1)\n", "Requirement already satisfied: openai==2.3.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.3.0)\n", "Requirement already satisfied: tiktoken==0.12.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.12.0)\n", "Requirement already satisfied: llmlingua==0.2.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.2.2)\n", "Requirement already satisfied: qdrant-client==1.15.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.15.1)\n", "Requirement already satisfied: pydantic==2.11.10 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.11.10)\n", "Requirement already satisfied: pydantic_core==2.33.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.33.2)\n", "Requirement already satisfied: numpy==2.2.6 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.2.6)\n", "Requirement already satisfied: scipy==1.15.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.15.3)\n", "Requirement already satisfied: scikit-learn==1.7.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.7.2)\n", "Requirement already satisfied: nltk==3.9.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.9.2)\n", "Requirement already satisfied: tokenizers==0.22.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.22.1)\n", "Requirement already satisfied: huggingface-hub==0.35.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.35.3)\n", "Requirement already satisfied: safetensors==0.6.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.6.2)\n", "Requirement already satisfied: tqdm==4.67.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (4.67.1)\n", "Requirement already satisfied: PyYAML==6.0.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (6.0.3)\n", "Requirement already satisfied: requests==2.32.5 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.32.5)\n", "Requirement already satisfied: filelock==3.20.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.20.0)\n", "Requirement already satisfied: regex==2025.9.18 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2025.9.18)\n", "Requirement already satisfied: packaging==25.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (25.0)\n", "Requirement already satisfied: httpx==0.28.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.28.1)\n", "Requirement already satisfied: httpcore==1.0.9 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.0.9)\n", "Requirement already satisfied: h11==0.16.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.16.0)\n", "Requirement already satisfied: h2==4.3.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (4.3.0)\n", "Requirement already satisfied: anyio==4.11.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (4.11.0)\n", "Requirement already satisfied: certifi==2025.10.5 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2025.10.5)\n", "Requirement already satisfied: charset-normalizer==3.4.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.4.3)\n", "Requirement already satisfied: idna==3.10 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.10)\n", "Requirement already satisfied: click==8.3.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (8.3.0)\n", "Requirement already satisfied: joblib==1.5.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.5.2)\n", "Requirement already satisfied: Jinja2==3.1.6 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.1.6)\n", "Requirement already satisfied: MarkupSafe==3.0.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.0.3)\n", "Requirement already satisfied: pillow==11.3.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (11.3.0)\n", "Requirement already satisfied: protobuf==6.32.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (6.32.1)\n", "Requirement already satisfied: psutil==7.1.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (7.1.0)\n", "Requirement already satisfied: fsspec==2025.9.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2025.9.0)\n", "Requirement already satisfied: grpcio==1.75.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.75.1)\n", "Requirement already satisfied: portalocker==3.2.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.2.0)\n", "Requirement already satisfied: annotated-types==0.7.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.7.0)\n", "Requirement already satisfied: typing_extensions==4.15.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (4.15.0)\n", "Requirement already satisfied: typing-inspection==0.4.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.4.2)\n", "Requirement already satisfied: networkx==3.4.2 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.4.2)\n", "Requirement already satisfied: sympy==1.14.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.14.0)\n", "Requirement already satisfied: mpmath==1.3.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.3.0)\n", "Requirement already satisfied: distro==1.9.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.9.0)\n", "Requirement already satisfied: hf-xet==1.1.10 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.1.10)\n", "Requirement already satisfied: hpack==4.1.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (4.1.0)\n", "Requirement already satisfied: hyperframe==6.1.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (6.1.0)\n", "Requirement already satisfied: jiter==0.11.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (0.11.0)\n", "Requirement already satisfied: sniffio==1.3.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (1.3.1)\n", "Requirement already satisfied: threadpoolctl==3.6.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (3.6.0)\n", "Requirement already satisfied: urllib3==2.5.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from lightmem==0.1.0) (2.5.0)\n", "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.8.93 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.8.93)\n", "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.8.90 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.8.90)\n", "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.8.90 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.8.90)\n", "Requirement already satisfied: nvidia-cudnn-cu12==9.10.2.21 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (9.10.2.21)\n", "Requirement already satisfied: nvidia-cublas-cu12==12.8.4.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.8.4.1)\n", "Requirement already satisfied: nvidia-cufft-cu12==11.3.3.83 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (11.3.3.83)\n", "Requirement already satisfied: nvidia-curand-cu12==10.3.9.90 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (10.3.9.90)\n", "Requirement already satisfied: nvidia-cusolver-cu12==11.7.3.90 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (11.7.3.90)\n", "Requirement already satisfied: nvidia-cusparse-cu12==12.5.8.93 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.5.8.93)\n", "Requirement already satisfied: nvidia-cusparselt-cu12==0.7.1 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (0.7.1)\n", "Requirement already satisfied: nvidia-nccl-cu12==2.27.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (2.27.3)\n", "Requirement already satisfied: nvidia-nvtx-cu12==12.8.90 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.8.90)\n", "Requirement already satisfied: nvidia-nvjitlink-cu12==12.8.93 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (12.8.93)\n", "Requirement already satisfied: nvidia-cufile-cu12==1.13.1.3 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (1.13.1.3)\n", "Requirement already satisfied: triton==3.4.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from torch==2.8.0->lightmem==0.1.0) (3.4.0)\n", "Requirement already satisfied: setuptools>=40.8.0 in /disk/disk_20T/xubuqiang/anaconda3/envs/LightMem/lib/python3.11/site-packages (from triton==3.4.0->torch==2.8.0->lightmem==0.1.0) (80.9.0)\n", "Building wheels for collected packages: lightmem\n", " Building editable for lightmem (pyproject.toml) ... \u001b[?25ldone\n", "\u001b[?25h Created wheel for lightmem: filename=lightmem-0.1.0-0.editable-py3-none-any.whl size=11716 sha256=7af01086068eb7a894b4bc406b2f9a2f0257090ea4f3ebd62fc2753ca3dbe9bc\n", " Stored in directory: /tmp/pip-ephem-wheel-cache-85oq2t07/wheels/6e/78/3e/ad25a8ed5245b53409d8ea7f1a62638ba248b738ed4cf419a3\n", "Successfully built lightmem\n", "Installing collected packages: lightmem\n", " Attempting uninstall: lightmem\n", " Found existing installation: lightmem 0.1.0\n", " Uninstalling lightmem-0.1.0:\n", " Successfully uninstalled lightmem-0.1.0\n", "Successfully installed lightmem-0.1.0\n", "/disk/disk_20T/xubuqiang/lightmem/tutorial-notebooks\n" ] } ], "source": [ "# Set your LightMemory project path\n", "LIGHTMEM_PROJECT_PATH = '/disk/disk_20T/xubuqiang/lightmem'\n", "\n", "# Install in editable mode\n", "%cd {LIGHTMEM_PROJECT_PATH}\n", "%env ALL_PROXY=\n", "!pip install -e .\n", "%cd tutorial-notebooks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Import Dependencies" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [], "source": [ "import os\n", "import json\n", "import datetime\n", "from lightmem.memory.lightmem import LightMemory\n", "from typing import List, Dict, Any\n", "import pandas as pd\n", "from tqdm import tqdm" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# logging setup\n", "LOGS_ROOT = \"./logs\"\n", "RUN_TIMESTAMP = datetime.datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n", "RUN_LOG_DIR = os.path.join(LOGS_ROOT, RUN_TIMESTAMP)\n", "os.makedirs(RUN_LOG_DIR, exist_ok=True)\n", "\n", "# API\n", "API_KEY = ''\n", "API_BASE_URL = ''\n", "LLM_MODEL = 'gpt-4o-mini'\n", "\n", "LLMLINGUA_MODEL_PATH = '/disk/disk_20T/fangjizhan/models/llmlingua-2-bert-base-multilingual-cased-meetingbank'\n", "EMBEDDING_MODEL_PATH = '/disk/disk_20T/fangjizhan/models/all-MiniLM-L6-v2'\n", "DATA_FILE_PATH = '/travel_single.json'\n", "\n", "print(f\"RUN_LOG_DIR: {RUN_LOG_DIR}\")\n", "print(f\"DATA_FILE_PATH: {DATA_FILE_PATH}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. LightMemory Initial config" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2025-12-07 23:40:23 - LightMemory - INFO - Initializing LightMemory with provided configuration\n", "2025-12-07 23:40:23 - LightMemory - INFO - Token statistics tracking initialized\n", "2025-12-07 23:40:23 - LightMemory - INFO - Initializing pre-compressor\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Initial LightMem...\n", "pre_compressor:llmlingua-2\n", "pre_compressor:llmlingua_config={'model_name': '/disk/disk_20T/fangjizhan/models/llmlingua-2-bert-base-multilingual-cased-meetingbank', 'device_map': 'cuda', 'use_llmlingua2': True} llmlingua2_config={'max_batch_size': 50, 'max_force_token': 100} compress_config={'instruction': '', 'rate': 0.8, 'target_token': -1}\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2025-12-07 23:40:23 - LightMemory - INFO - Initializing topic segmenter\n", "2025-12-07 23:40:23 - LightMemory - INFO - Initializing memory manager\n", "2025-12-07 23:40:23 - LightMemory - INFO - Initializing text embedder\n", "2025-12-07 23:40:23 - sentence_transformers.SentenceTransformer - INFO - Load pretrained SentenceTransformer: /disk/disk_20T/fangjizhan/models/all-MiniLM-L6-v2\n", "2025-12-07 23:40:24 - LightMemory - INFO - Initializing embedding retriever\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "DEBUG: resolved to encoding o200k_base\n", "ShortMemBufferManager initialized with max_tokens=512\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2025-12-07 23:40:24 - LightMemory - INFO - LightMemory initialization completed successfully\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "LightMem initialized!\n" ] } ], "source": [ "config_dict = {\n", " \"pre_compress\": True,\n", " \"pre_compressor\": {\n", " \"model_name\": \"llmlingua-2\",\n", " \"configs\": {\n", " \"llmlingua_config\": {\n", " \"model_name\": LLMLINGUA_MODEL_PATH,\n", " \"device_map\": \"cuda\",\n", " \"use_llmlingua2\": True,\n", " },\n", " }\n", " },\n", " \"topic_segment\": True,\n", " \"precomp_topic_shared\": True,\n", " \"topic_segmenter\": {\n", " \"model_name\": \"llmlingua-2\",\n", " },\n", " \"messages_use\": \"hybrid\",\n", " \"metadata_generate\": True,\n", " \"text_summary\": True,\n", " \"memory_manager\": {\n", " \"model_name\": 'openai',\n", " \"configs\": {\n", " \"model\": LLM_MODEL,\n", " \"api_key\": API_KEY,\n", " \"max_tokens\": 16000,\n", " \"openai_base_url\": API_BASE_URL\n", " }\n", " },\n", " \"extract_threshold\": 0.1,\n", " \"index_strategy\": \"embedding\",\n", " \"text_embedder\": {\n", " \"model_name\": \"huggingface\",\n", " \"configs\": {\n", " \"model\": EMBEDDING_MODEL_PATH,\n", " \"embedding_dims\": 384,\n", " \"model_kwargs\": {\"device\": \"cuda\"},\n", " },\n", " },\n", " \"retrieve_strategy\": \"embedding\",\n", " \"embedding_retriever\": {\n", " \"model_name\": \"qdrant\",\n", " \"configs\": {\n", " \"collection_name\": \"travel_demo\",\n", " \"embedding_model_dims\": 384,\n", " \"path\": \"./travel_demo_db\", \n", " }\n", " },\n", " \"update\": \"offline\",\n", " \"logging\": {\n", " \"level\": \"DEBUG\",\n", " \"file_enabled\": True,\n", " \"log_dir\": RUN_LOG_DIR,\n", " }\n", "}\n", "\n", "print(\"Initial LightMem...\")\n", "lightmem = LightMemory.from_config(config_dict)\n", "print(\"LightMem initialized!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Load dataset\n" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dataset statistics:\n", "- Number of questions: 3\n", "- Number of historical sessions: 3\n", "- Session ID list: ['session_0', 'session_1', 'session_2']\n", "\n", "Question preview:\n", " [q_travel_01] I'm reviewing my expenses from the solo trip to Tampa I took back in March 2022. Can you remind me w...\n", " [q_travel_02] I'm going back to our previous conversation about the 2-day Tampa trip from Washington. Can you remi...\n", " [q_travel_03] For the family trip we took over the July 4th weekend, I recall we had to be very careful about food...\n" ] } ], "source": [ "with open(DATA_FILE_PATH, 'r', encoding='utf-8') as f:\n", " data = json.load(f)\n", "\n", "if isinstance(data, list):\n", " data_item = data[0]\n", "else:\n", " data_item = data\n", "\n", "question_ids = data_item.get('question_id', [])\n", "question_types = data_item.get('question_type', [])\n", "questions = data_item.get('question', [])\n", "question_dates = data_item.get('question_date', [])\n", "answers = data_item.get('answer', [])\n", "answer_session_ids = data_item.get('answer_session_ids', [])\n", "haystack_session_ids = data_item.get('haystack_session_ids', [])\n", "haystack_dates = data_item.get('haystack_dates', [])\n", "haystack_sessions = data_item.get('haystack_sessions', [])\n", "\n", "print(f\"Dataset statistics:\")\n", "print(f\"- Number of questions: {len(questions)}\")\n", "print(f\"- Number of historical sessions: {len(haystack_sessions)}\")\n", "print(f\"- Session ID list: {haystack_session_ids}\")\n", "print(f\"\\nQuestion preview:\")\n", "for i, (qid, q) in enumerate(zip(question_ids[:3], questions[:3])):\n", " print(f\" [{qid}] {q[:100]}...\" if len(q) > 100 else f\" [{qid}] {q}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. ADD memory into LightMem\n" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [], "source": [ "METADATA_GENERATE_PROMPT = \"\"\"\n", "You are a Travel Planning Conversation Analyzer.\n", "Your task is to extract **all travel-related facts and preferences** from a conversation.\n", "\n", "Input format:\n", "--- Topic X ---\n", "[timestamp, weekday] source_id.SpeakerName: message\n", "...\n", "\n", "Critical Instructions:\n", "1. **Process messages strictly in ascending source_id order** (one by one)\n", "\n", "2. **Extract ALL travel information** including:\n", " - Travel plans: dates, destinations, budget, duration\n", " - Personal preferences: dietary restrictions, activity preferences, accommodation needs\n", " - Bookings: flights (with flight numbers), hotels (with addresses), restaurants, attractions\n", " - Specific details: prices, addresses, ratings, operating hours\n", " - Transportation: modes, routes, costs\n", " - Itinerary details: daily plans, timing, locations\n", "\n", "3. **Preserve ALL Specific Details - DO NOT generalize**:\n", " Flight information:\n", " - ✓ \"User booked Flight F3694191 departing Washington at 09:30, arriving Tampa at 12:01 on March 25, 2022 for $173.\"\n", " - ✗ \"User booked a flight\"\n", " \n", " Accommodation:\n", " - ✓ \"User booked 'Spacious 1+bedroom apt NYC' at 100 N Ashley Dr, Tampa for 2 nights (March 25-27) at $547/night, total $1,094.\"\n", " - ✗ \"User booked an apartment\"\n", " \n", " Preferences:\n", " - ✓ \"User is vegetarian with a per-meal budget of $30-$60.\"\n", " - ✗ \"User has dietary restrictions\"\n", " \n", " Restaurants:\n", " - ✓ \"Assistant recommended The Zaffran at 35 W Gasparilla Plaza, vegetarian-friendly with veggie wraps, $35, 3.3 rating, 5-minute walk from apartment.\"\n", " - ✗ \"Assistant recommended a restaurant\"\n", "\n", "4. **Time Handling**:\n", " - Always include specific dates: \"March 25, 2022\" not \"the trip\"\n", " - Include times when mentioned: \"09:30\" not \"morning\"\n", " - Reference the message timestamp for context\n", "\n", "5. **For multi-day itineraries**:\n", " - Extract each day's plan separately\n", " - Include all activities, timings, locations, costs\n", " - Preserve the sequence of events\n", "\n", "6. Output format:\n", "Please return your response in JSON format.\n", " {\n", " \"data\": [\n", " {\n", " \"source_id\": \"\",\n", " \"fact\": \"\"\n", " }\n", " ]\n", " }\n", "\n", "Example:\n", "--- Topic 1 ---\n", "[2022-03-20T13:21:00.000, Sun] 0.User: I need help planning a 3-day trip to Paris from NYC, March 10-12, budget $2000. I'm vegetarian.\n", "[2022-03-20T13:21:00.500, Sun] 0.Assistant: For your Paris trip, I recommend Flight AF123 (departs 18:00, arrives 08:00 next day, $450). Hotel Le Marais at 15 Rue des Archives ($180/night).\n", "\n", "{\"data\": [\n", " {\"source_id\": \"0\", \"fact\": \"User is planning a 3-day trip from NYC to Paris from March 10-12, 2022 with a budget of $2,000.\"},\n", " {\"source_id\": \"0\", \"fact\": \"User is vegetarian.\"},\n", " {\"source_id\": \"0\", \"fact\": \"Assistant recommended Flight AF123 departing NYC at 18:00, arriving Paris at 08:00 the next day for $450.\"},\n", " {\"source_id\": \"0\", \"fact\": \"Assistant recommended Hotel Le Marais located at 15 Rue des Archives, Paris for $180 per night.\"}\n", "]}\n", "\n", "Reminder:\n", "- Preserve ALL specific details: flight numbers, addresses, prices, ratings, times\n", "- DO NOT summarize or generalize\n", "- Extract information for EVERY day in multi-day itineraries\n", "- Include both user preferences and assistant recommendations\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [], "source": [ "def convert_timestamp(timestamp: str) -> str:\n", " \"\"\"\n", " Convert timestamp from '2025/12/02 (Tue) 17:06' to '2025-12-02 17:06:00'\n", " \n", " Args:\n", " timestamp: Original timestamp string\n", " \n", " Returns:\n", " Converted timestamp string in format '%Y-%m-%d %H:%M:%S'\n", " \"\"\"\n", " from datetime import datetime\n", " \n", " # Remove day of week (e.g., \"(Tue)\")\n", " timestamp_clean = timestamp.split('(')[0].strip() + ' ' + timestamp.split(')')[1].strip()\n", " # Now it's like: '2025/12/02 17:06'\n", " \n", " # Parse the timestamp\n", " dt = datetime.strptime(timestamp_clean, '%Y/%m/%d %H:%M')\n", " \n", " # Convert to target format\n", " return dt.strftime('%Y-%m-%d %H:%M:%S')\n", "\n", "def add_sessions_to_memory(lightmem: LightMemory, \n", " sessions: List[List[Dict]], \n", " session_ids: List[str],\n", " dates: List[str]) -> None:\n", " \"\"\"\n", " Add historical sessions to the LightMemory system.\n", " Sessions are added turn by turn (each turn contains a user message and an assistant message).\n", " \n", " Args:\n", " lightmem: LightMemory instance\n", " sessions: List of sessions, each session contains multiple conversation turns\n", " session_ids: List of session IDs\n", " dates: List of session timestamps (will be converted to standard format)\n", " \"\"\"\n", " print(\"Starting to add historical sessions to memory repository...\")\n", " \n", " # Convert all timestamps to standard format\n", " print(\"Converting timestamps to standard format...\")\n", " converted_dates = [convert_timestamp(date) for date in dates]\n", " \n", " # Calculate total number of turns for progress bar\n", " total_turns = 0\n", " for session in sessions:\n", " # Ensure first message is from user\n", " session_copy = session.copy()\n", " while session_copy and session_copy[0][\"role\"] != \"user\":\n", " session_copy.pop(0)\n", " num_turns = len(session_copy) // 2\n", " total_turns += num_turns\n", " \n", " progress_bar = tqdm(total=total_turns, desc=\"Adding turns\")\n", " \n", " for session_idx, (session, session_id, date) in enumerate(zip(sessions, session_ids, converted_dates)):\n", " # Ensure the first message is from user\n", " while session and session[0][\"role\"] != \"user\":\n", " session.pop(0)\n", " \n", " num_turns = len(session) // 2\n", " \n", " for turn_idx in range(num_turns):\n", " # Extract one turn (user + assistant messages)\n", " turn_messages = session[turn_idx*2 : turn_idx*2 + 2]\n", " \n", " # Validate turn structure\n", " if len(turn_messages) < 2 or turn_messages[0][\"role\"] != \"user\" or turn_messages[1][\"role\"] != \"assistant\":\n", " continue\n", " \n", " # Add timestamp and speaker information to each message\n", " for msg in turn_messages:\n", " msg[\"time_stamp\"] = date\n", " # Add default speaker information if not present\n", " if \"speaker_name\" not in msg:\n", " msg[\"speaker_name\"] = \"User\" if msg[\"role\"] == \"user\" else \"Assistant\"\n", " if \"speaker_id\" not in msg:\n", " msg[\"speaker_id\"] = \"speaker_a\" if msg[\"role\"] == \"user\" else \"speaker_b\"\n", " \n", " # Only force_segment and force_extract on the last turn of the last session\n", " is_last_turn = (session_idx == len(sessions) - 1 and turn_idx == num_turns - 1)\n", " \n", " # Add turn to memory system\n", " try:\n", " lightmem.add_memory(\n", " messages=turn_messages,\n", " METADATA_GENERATE_PROMPT=METADATA_GENERATE_PROMPT,\n", " force_segment=is_last_turn,\n", " force_extract=is_last_turn,\n", " )\n", " progress_bar.update(1)\n", " except Exception as e:\n", " print(f\"\\nWarning: Failed to add turn {turn_idx} from session {session_id}: {str(e)}\")\n", " continue\n", " \n", " progress_bar.close()\n", " print(\"\\nAll historical sessions have been added!\")\n", " " ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Starting to add historical sessions to memory repository...\n", "Converting timestamps to standard format...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "Adding turns: 0%| | 0/27 [00:00 512). Running this sequence through the model will result in indexing errors\n", "2025-12-07 23:42:07 - LightMemory - INFO - [add_memory_20251207_234207_344308] Restored visual contexts after compression\n", "2025-12-07 23:42:07 - LightMemory - INFO - [add_memory_20251207_234207_344308] Target compression rate: 0.8\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "aad9cd8846c84bff91c0c8b06162aaaa", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Batches: 0%| | 0/1 [00:00 pd.DataFrame:\n", " \"\"\"\n", " Perform memory retrieval, generate answers using LLM, and evaluate correctness.\n", " \n", " Args:\n", " lightmem: LightMemory instance\n", " questions: List of questions\n", " question_ids: List of question IDs\n", " question_types: List of question types\n", " question_dates: List of question dates\n", " answers: List of expected answers\n", " top_k: Number of memory entries to retrieve\n", " \n", " Returns:\n", " DataFrame containing retrieval and evaluation results\n", " \"\"\"\n", " results = []\n", " \n", " print(f\"Starting memory retrieval and answer generation for {len(questions)} questions...\\n\")\n", " \n", " # Initialize LLM for answer generation (using the same config as LightMemory)\n", " from openai import OpenAI\n", " \n", " llm_client = OpenAI(\n", " api_key=API_KEY,\n", " base_url=API_BASE_URL\n", " )\n", " \n", " # LLM for judging (can be the same)\n", " llm_judge = llm_client\n", " \n", " for idx, (qid, question, qtype, qdate, expected_answer) in enumerate(\n", " zip(question_ids, questions, question_types, question_dates, answers), 1\n", " ):\n", " print(f\"\\n{'='*80}\")\n", " print(f\"Question {idx}/{len(questions)} [ID: {qid}]\")\n", " print(f\"{'='*80}\")\n", " print(f\"Question: {question}\")\n", " print(f\"Question Date: {qdate}\")\n", " print(f\"Question Type: {qtype}\")\n", " print(f\"Expected Answer: {expected_answer}\")\n", " \n", " try:\n", " # Step 1: Retrieve relevant memories\n", " result_string = lightmem.retrieve(question, limit=top_k)\n", " related_memories = [m.strip() for m in result_string.split('\\n') if m.strip()]\n", " \n", " print(f\"\\nRetrieved {len(related_memories)} relevant memories\")\n", " print(\"-\" * 80)\n", " \n", " # Display first few memories\n", " for mem_idx, memory in enumerate(related_memories, 1):\n", " print(f\"Memory {mem_idx}: {memory}\")\n", " \n", " # Step 2: Generate answer using LLM\n", " print(\"\\nGenerating answer...\")\n", " messages = [\n", " {\"role\": \"system\", \"content\": \"You can ONLY answer based on the provided memories.\"},\n", " {\n", " \"role\": \"user\",\n", " \"content\": f\"Question: {question}\\n\\nPlease answer the question based on the following memories:\\n{result_string}\"\n", " }\n", " ]\n", " \n", " response = llm_client.chat.completions.create(\n", " model=LLM_MODEL,\n", " messages=messages,\n", " max_tokens=1024,\n", " temperature=0.0\n", " )\n", " \n", " generated_answer = response.choices[0].message.content\n", " print(f\"\\nGenerated Answer: {generated_answer}\")\n", " \n", " # Step 3: Evaluate answer correctness\n", " print(\"\\nEvaluating answer...\")\n", " \n", " # Build evaluation prompt\n", "\n", " eval_prompt = f\"\"\"You are an expert evaluator. Compare the generated answer with the expected answer.\n", " Question: {question}\n", " Expected Answer: {expected_answer}\n", " Generated Answer: {generated_answer}\n", "\n", " Determine if the generated answer is correct compared to the expected answer.\n", " Answer only \"True\" or \"False\".\"\"\"\n", " \n", " eval_messages = [{\"role\": \"user\", \"content\": eval_prompt}]\n", " \n", " eval_response = llm_judge.chat.completions.create(\n", " model=LLM_MODEL,\n", " messages=eval_messages,\n", " max_tokens=10,\n", " temperature=0.0\n", " )\n", " \n", " eval_result = eval_response.choices[0].message.content.strip()\n", " correct = 1 if \"true\" in eval_result.lower() else 0\n", " \n", " print(f\"Evaluation Result: {eval_result} ({'✓ Correct' if correct else '✗ Incorrect'})\")\n", " \n", " # Record results\n", " results.append({\n", " 'question_id': qid,\n", " 'question_type': qtype,\n", " 'question': question,\n", " 'question_date': qdate,\n", " 'expected_answer': expected_answer,\n", " 'retrieved_count': len(related_memories),\n", " 'retrieved_memories': related_memories,\n", " 'generated_answer': generated_answer,\n", " 'eval_result': eval_result,\n", " 'correct': correct\n", " })\n", " \n", " except Exception as e:\n", " print(f\"\\nError: Processing failed - {str(e)}\")\n", " import traceback\n", " traceback.print_exc()\n", " \n", " results.append({\n", " 'question_id': qid,\n", " 'question_type': qtype,\n", " 'question': question,\n", " 'question_date': qdate,\n", " 'expected_answer': expected_answer,\n", " 'retrieved_count': 0,\n", " 'retrieved_memories': [],\n", " 'generated_answer': '',\n", " 'eval_result': '',\n", " 'correct': 0,\n", " 'error': str(e)\n", " })\n", " \n", " print(f\"\\n{'='*80}\")\n", " print(\"Retrieval and answer generation completed!\")\n", " print(f\"{'='*80}\\n\")\n", " \n", " df = pd.DataFrame(results)\n", " \n", " # Print summary statistics\n", " if len(df) > 0 and 'correct' in df.columns:\n", " accuracy = df['correct'].mean() * 100\n", " print(f\"Overall Accuracy: {accuracy:.2f}% ({df['correct'].sum()}/{len(df)})\")\n", " \n", " return df\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2025-12-07 23:44:21 - LightMemory - INFO - ========== START retrieve_20251207_234421_637955 ==========\n", "2025-12-07 23:44:21 - LightMemory - INFO - [retrieve_20251207_234421_637955] Query: I'm reviewing my expenses from the solo trip to Tampa I took back in March 2022. Can you remind me which specific apartment I booked near the Riverwalk and what was the nightly rate?\n", "2025-12-07 23:44:21 - LightMemory - INFO - [retrieve_20251207_234421_637955] Parameters: limit=20, filters=None\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Starting memory retrieval and answer generation for 3 questions...\n", "\n", "\n", "================================================================================\n", "Question 1/3 [ID: q_travel_01]\n", "================================================================================\n", "Question: I'm reviewing my expenses from the solo trip to Tampa I took back in March 2022. Can you remind me which specific apartment I booked near the Riverwalk and what was the nightly rate?\n", "Question Date: 2022/06/01 (Thu) 14:30\n", "Question Type: single-session-assistant\n", "Expected Answer: You booked the 'Spacious 1+ bedroom apt' at 100 N Ashley Dr. The rate was $547 per night.\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "dcd97e7ef44046a3a3b5c1c3e068a2b3", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Batches: 0%| | 0/1 [00:00