حفظ واسترجاع ذاكرة المحادثات من قاعدة بيانات (SQLite / Redis)


ماذا سنتعلم اليوم؟ سنتعلم كيفية حفظ واسترجاع ذاكرة المحادثات لتطبيقات الذكاء الاصطناعي باستخدام LangChain وقواعد البيانات SQLite و Redis، مما يضمن استمرارية السياق عبر الجلسات.

مقدمة: إدارة ذاكرة المحادثات

تعتبر ذاكرة المحادثات (Chat Memory) عنصراً حيوياً في بناء تطبيقات الذكاء الاصطناعي التفاعلية، خصوصاً تلك التي تعتمد على نماذج اللغة الكبيرة (LLMs). بدون ذاكرة، ستكون كل استجابة من النموذج مستقلة عن الاستجابات السابقة، مما يفقد المحادثة سياقها وتماسكها. في هذا الدرس، سنستكشف كيف يمكننا استخدام LangChain لتخزين واسترجاع ذاكرة المحادثات باستخدام قاعدتي بيانات شائعتين: SQLite للتخزين المحلي البسيط، و Redis للتخزين السريع والقابل للتوسع.
ملاحظة تقنية: LangChain توفر تجريداً رائعاً لإدارة ذاكرة المحادثات، حيث تسمح لك بتبديل آلية التخزين (مثل SQLite أو Redis) بسهولة دون الحاجة لتغيير منطق تطبيقك الأساسي. تعتمد على واجهات مشتركة مثل BaseChatMessageHistory.

الخطوة 1: تهيئة البيئة وتحديد قاعدة البيانات (SQLite)

سنبدأ بتهيئة بيئة العمل وتجهيز المكونات اللازمة. سنستخدم SQLite كخيارنا الأول لتخزين ذاكرة المحادثات، وهو مثالي للتطبيقات الصغيرة أو عند الحاجة لتخزين محلي بسيط. سنقوم بإنشاء جدول في قاعدة بيانات SQLite لتخزين سجلات المحادثة.
import os
from langchain_community.chat_message_histories import SQLChatMessageHistory
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
from langchain_community.llms import FakeListLLM # نستخدم هذا للتبسيط وتجنب الحاجة لمفتاح API

# --- 1. تهيئة LLM وهمي للاختبار ---
# قائمة بالردود المتوقعة من النموذج لتشغيل المثال بدون مفتاح API
responses = [
    "مرحباً بك! أنا مساعد ذكاء اصطناعي. كيف يمكنني مساعدتك اليوم؟",
    "بالتأكيد! يمكنني مساعدتك في مهام البرمجة. ما هي لغة البرمجة المفضلة لديك؟",
    "Python هي خيار ممتاز! ما هو أول مشروع برمجي تود البدء به؟",
    "فكرة رائعة! لإنشاء تطبيق ويب، ستحتاج إلى إطار عمل مثل Flask أو Django. هل أنت مستعد للبدء؟",
    "أهلاً بك مرة أخرى! لقد تذكرت محادثتنا السابقة. كيف يمكنني المساعدة في مشروع تطبيق الويب الخاص بك؟"
]
llm = FakeListLLM(responses=responses) # استخدام نموذج وهمي للدرس

# --- 2. إعداد SQLite لتخزين ذاكرة المحادثات ---
session_id = "user_123" # معرف فريد للجلسة، يستخدم لربط المحادثات بمستخدم معين
sqlite_db_path = "chat_history.db" # اسم ملف قاعدة بيانات SQLite
sqlite_connection_string = f"sqlite:///{sqlite_db_path}" # سلسلة الاتصال بقاعدة البيانات

# إنشاء كائن SQLChatMessageHistory الذي سيتعامل مع SQLite
# يقوم تلقائياً بإنشاء الجدول إذا لم يكن موجوداً
sqlite_message_history = SQLChatMessageHistory(
    session_id=session_id,
    connection_string=sqlite_connection_string
)

# إنشاء ذاكرة المحادثة باستخدام ConversationBufferMemory وتمرير سجل الرسائل
# هذه الذاكرة ستحتفظ بسجل الرسائل وتسمح للنموذج بالوصول إليه
sqlite_memory = ConversationBufferMemory(
    chat_memory=sqlite_message_history, # ربط الذاكرة بسجل SQLite
    return_messages=True # إرجاع الرسائل ككائنات Message بدلاً من سلاسل نصية
)

print("تم تهيئة SQLite بنجاح.")
**شرح الكود:** * FakeListLLM: استخدمنا نموذج لغة وهمي (Mock LLM) لتشغيل المثال دون الحاجة إلى مفتاح API أو اتصال بالإنترنت. في تطبيق حقيقي، ستستبدل هذا بنموذج LLM حقيقي مثل ChatOpenAI أو HuggingFaceHub. * session_id: هذا المعرف بالغ الأهمية! إنه يحدد جلسة محادثة معينة. تسمح لك LangChain بتخزين محادثات متعددة، كل منها بمعرف جلسة فريد، في نفس قاعدة البيانات. * sqlite_connection_string: يحدد مسار ملف قاعدة بيانات SQLite. ستقوم LangChain بإنشاء هذا الملف والجدول اللازم لتخزين سجل الرسائل تلقائياً إذا لم يكن موجوداً. * SQLChatMessageHistory: هذا هو المكون الذي يتفاعل مباشرة مع قاعدة بيانات SQLite لتخزين واسترجاع الرسائل. * ConversationBufferMemory: هذا هو نوع من الذاكرة في LangChain يقوم بتخزين سجل كامل للرسائل. نحن نمرر له كائن SQLChatMessageHistory لربطه بقاعدة البيانات، مما يعني أن الذاكرة ستقوم بتحميل الرسائل السابقة من SQLite وحفظ الرسائل الجديدة فيه.

الخطوة 2: دمج ذاكرة المحادثة مع نموذج اللغة (LLM)

الآن بعد أن قمنا بتهيئة الذاكرة، حان الوقت لدمجها مع سلسلة محادثة (Conversation Chain) بحيث يمكن لنموذج اللغة (LLM) الاستفادة من السياق المخزن. سنقوم بإجراء بعض التفاعلات لاختبار ما إذا كانت الذاكرة تعمل بشكل صحيح.
# --- 3. دمج الذاكرة مع ConversationChain وإجراء محادثة ---

# إنشاء ConversationChain مع LLM والذاكرة التي تم إعدادها لـ SQLite
sqlite_conversation_chain = ConversationChain(
    llm=llm, # النموذج اللغوي المستخدم
    memory=sqlite_memory, # الذاكرة التي تم ربطها بـ SQLite
    verbose=True # لعرض تفاصيل عمل السلسلة (اختياري)
)

print("\n--- بدء المحادثة (SQLite) ---")

# التفاعل الأول: LLM يجب أن يرد بالتحية
response1 = sqlite_conversation_chain.predict(input="مرحباً، من أنت؟")
print(f"الإنسان: مرحباً، من أنت؟")
print(f"الذكاء الاصطناعي: {response1}")

# التفاعل الثاني: LLM يجب أن يتذكر السياق السابق
response2 = sqlite_conversation_chain.predict(input="أنا مهتم بالبرمجة، هل يمكنك المساعدة؟")
print(f"الإنسان: أنا مهتم بالبرمجة، هل يمكنك المساعدة؟")
print(f"الذكاء الاصطناعي: {response2}")

# التفاعل الثالث: LLM يجب أن يتذكر لغة البرمجة المفضلة
response3 = sqlite_conversation_chain.predict(input="لغتي المفضلة هي بايثون.")
print(f"الإنسان: لغتي المفضلة هي بايثون.")
print(f"الذكاء الاصطناعي: {response3}")

# التفاعل الرابع: LLM يجب أن يتذكر المشروع
response4 = sqlite_conversation_chain.predict(input="أريد بناء تطبيق ويب.")
print(f"الإنسان: أريد بناء تطبيق ويب.")
print(f"الذكاء الاصطناعي: {response4}")

# --- 4. اختبار استمرارية الذاكرة (SQLite) ---
print("\n--- اختبار استمرارية الذاكرة (SQLite) ---")

# لنفترض أن التطبيق أعيد تشغيله أو أن المستخدم عاد لاحقاً
# نقوم بإنشاء ذاكرة جديدة بنفس session_id
new_sqlite_message_history = SQLChatMessageHistory(
    session_id=session_id,
    connection_string=sqlite_connection_string
)
new_sqlite_memory = ConversationBufferMemory(
    chat_memory=new_sqlite_message_history,
    return_messages=True
)

# التحقق من أن الذاكرة الجديدة تحتوي على الرسائل السابقة
print("الرسائل المحملة من SQLite:")
for msg in new_sqlite_memory.chat_memory.messages:
    print(f"  {msg.type.capitalize()}: {msg.content}")

# إنشاء سلسلة محادثة جديدة باستخدام الذاكرة المحملة
restored_sqlite_conversation_chain = ConversationChain(
    llm=llm,
    memory=new_sqlite_memory,
    verbose=True
)

# التفاعل الخامس: LLM يجب أن يتذكر المحادثة السابقة بالكامل
response5 = restored_sqlite_conversation_chain.predict(input="ما هي الخطوة التالية في مشروع تطبيق الويب الخاص بي؟")
print(f"الإنسان: ما هي الخطوة التالية في مشروع تطبيق الويب الخاص بي؟")
print(f"الذكاء الاصطناعي: {response5}")
**شرح الكود:** * ConversationChain: هذا هو المكون الأساسي في LangChain الذي يربط بين LLM والذاكرة (Memory). عند استدعاء predict، يقوم ConversationChain بتمرير سجل المحادثة الحالي إلى LLM، ثم يحفظ استجابة LLM والرسالة الجديدة في الذاكرة. * predict(input=...): هذه هي الطريقة التي ترسل بها مدخلات المستخدم إلى سلسلة المحادثة. * **اختبار استمرارية الذاكرة**: الجزء الأخير يوضح كيفية محاكاة إعادة تشغيل التطبيق. نقوم بإنشاء كائن SQLChatMessageHistory و ConversationBufferMemory جديدين بنفس session_id. نظراً لأن session_id يطابق المعرف المستخدم في المحادثة السابقة، ستقوم الذاكرة بتحميل جميع الرسائل المخزنة في chat_history.db تلقائياً، مما يضمن استمرارية السياق.

الخطوة 3: تبديل قاعدة البيانات إلى Redis (اختياري/متقدم)

Redis هي قاعدة بيانات In-memory سريعة للغاية وتستخدم عادة للتخزين المؤقت (Caching) أو كمتجر لقيم المفاتيح (Key-Value Store). إنها خيار ممتاز لتخزين ذاكرة المحادثات في تطبيقات الويب ذات الحجم الكبير التي تتطلب سرعة استجابة عالية وقابلية للتوسع. لاستخدام Redis، ستحتاج إلى تثبيت خادم Redis وتشغيل مكتبة redis في Python.
from langchain_community.chat_message_histories import RedisChatMessageHistory
import redis

# --- 5. إعداد Redis لتخزين ذاكرة المحادثات (يتطلب تشغيل خادم Redis) ---

# تأكد من تشغيل خادم Redis على 'localhost:6379' أو عدّل الإعدادات
# يمكنك تثبيت Redis محلياً أو استخدام Docker
try:
    redis_client = redis.Redis(host='localhost', port=6379, db=0) # إنشاء عميل Redis
    redis_client.ping() # اختبار الاتصال بخادم Redis
    print("تم الاتصال بخادم Redis بنجاح.")

    # إنشاء كائن RedisChatMessageHistory
    redis_message_history = RedisChatMessageHistory(
        session_id=session_id, # استخدام نفس معرف الجلسة لاختبار التبديل
        redis_client=redis_client # تمرير كائن عميل Redis
    )

    # إنشاء ذاكرة المحادثة باستخدام ConversationBufferMemory وربطها بـ Redis
    redis_memory = ConversationBufferMemory(
        chat_memory=redis_message_history,
        return_messages=True
    )

    # --- 6. دمج الذاكرة مع ConversationChain وإجراء محادثة (Redis) ---
    redis_conversation_chain = ConversationChain(
        llm=llm, # استخدام نفس النموذج اللغوي الوهمي
        memory=redis_memory,
        verbose=True
    )

    print("\n--- بدء المحادثة (Redis) ---")

    # يمكننا الآن التفاعل مع النموذج باستخدام ذاكرة Redis
    # الرسائل السابقة من SQLite لن تكون موجودة هنا إلا إذا قمنا بنقلها يدوياً
    # لأن كل آلية تخزين تعمل بشكل مستقل. سنبدأ محادثة جديدة في Redis.

    response_r1 = redis_conversation_chain.predict(input="أهلاً بك، ما هو رأيك في قواعد البيانات NoSQL؟")
    print(f"الإنسان: أهلاً بك، ما هو رأيك في قواعد البيانات NoSQL؟")
    print(f"الذكاء الاصطناعي: {response_r1}")

    response_r2 = redis_conversation_chain.predict(input="هل توصي باستخدام MongoDB لمشروع كبير؟")
    print(f"الإنسان: هل توصي باستخدام MongoDB لمشروع كبير؟")
    print(f"الذكاء الاصطناعي: {response_r2}")

    # --- 7. اختبار استمرارية الذاكرة (Redis) ---
    print("\n--- اختبار استمرارية الذاكرة (Redis) ---")

    # لنفترض أن التطبيق أعيد تشغيله
    new_redis_message_history = RedisChatMessageHistory(
        session_id=session_id,
        redis_client=redis_client
    )
    new_redis_memory = ConversationBufferMemory(
        chat_memory=new_redis_message_history,
        return_messages=True
    )

    print("الرسائل المحملة من Redis:")
    for msg in new_redis_memory.chat_memory.messages:
        print(f"  {msg.type.capitalize()}: {msg.content}")

    restored_redis_conversation_chain = ConversationChain(
        llm=llm,
        memory=new_redis_memory,
        verbose=True
    )
    response_r3 = restored_redis_conversation_chain.predict(input="ما هي البدائل الأخرى لـ MongoDB؟")
    print(f"الإنسان: ما هي البدائل الأخرى لـ MongoDB؟")
    print(f"الذكاء الاصطناعي: {response_r3}")

except redis.exceptions.ConnectionError as e:
    print(f"\nخطأ: لم يتمكن الاتصال بخادم Redis. يرجى التأكد من تشغيله. التفاصيل: {e}")
    print("تخطي جزء Redis من الدرس.")
except Exception as e:
    print(f"حدث خطأ غير متوقع في جزء Redis: {e}")
    print("تخطي جزء Redis من الدرس.")
**شرح الكود:** * redis.Redis: يقوم بإنشاء كائن عميل للاتصال بخادم Redis. يجب أن يكون خادم Redis قيد التشغيل على العنوان والمنفذ المحدد (الافتراضي هو localhost:6379). * RedisChatMessageHistory: هذا المكون يتفاعل مع Redis لتخزين واسترجاع الرسائل. يتميز بالسرعة العالية نظراً لطبيعة Redis في التخزين في الذاكرة. * **اختبار الاتصال**: تم إضافة كتلة try-except للتعامل مع حالة عدم تشغيل خادم Redis، مما يسمح بتشغيل باقي الدرس حتى لو لم يكن Redis متاحاً. * **استمرارية الذاكرة (Redis)**: تعمل بنفس مبدأ SQLite. باستخدام نفس session_id وكائن RedisChatMessageHistory جديد، سيتم تحميل المحادثة السابقة من Redis تلقائياً.

الكود النهائي الكامل

هذا هو السكربت الكامل الذي يجمع جميع الخطوات المذكورة أعلاه. يمكنك نسخه ولصقه وتشغيله مباشرة بعد تثبيت المكتبات المطلوبة (langchain-community, langchain-openai, redis) وتأكيد تشغيل خادم Redis إذا كنت ترغب في اختبار جزء Redis.
import os
from langchain_community.chat_message_histories import SQLChatMessageHistory
from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
from langchain_community.llms import FakeListLLM # نستخدم هذا للتبسيط وتجنب الحاجة لمفتاح API

import sqlite3
import redis

# --- 1. تهيئة LLM وهمي للاختبار ---
responses = [
    "مرحباً بك! أنا مساعد ذكاء اصطناعي. كيف يمكنني مساعدتك اليوم؟",
    "بالتأكيد! يمكنني مساعدتك في مهام البرمجة. ما هي لغة البرمجة المفضلة لديك؟",
    "Python هي خيار ممتاز! ما هو أول مشروع برمجي تود البدء به؟",
    "فكرة رائعة! لإنشاء تطبيق ويب، ستحتاج إلى إطار عمل مثل Flask أو Django. هل أنت مستعد للبدء؟",
    "أهلاً بك مرة أخرى! لقد تذكرت محادثتنا السابقة. كيف يمكنني المساعدة في مشروع تطبيق الويب الخاص بك؟",
    "قواعد البيانات NoSQL ممتازة للمرونة وقابلية التوسع الأفقي، خاصة مع البيانات غير المهيكلة أو شبه المهيكلة.",
    "MongoDB خيار شائع، لكن لمشروع كبير، قد تحتاج إلى تقييم متطلبات الاتساق والتعامل مع المعاملات. قد تكون قواعد بيانات أخرى مثل Cassandra أو Couchbase مناسبة أكثر لبعض السيناريوهات.",
    "بالتأكيد، هناك Apache Cassandra للبيانات الموزعة على نطاق واسع، وCouchbase التي تجمع بين ميزات NoSQL وذاكرة التخزين المؤقت، وDynamoDB من AWS كخدمة مدارة. يعتمد الاختيار على متطلبات مشروعك المحددة."
]
llm = FakeListLLM(responses=responses)

# معرف فريد للجلسة (يمكن أن يكون معرف المستخدم أو معرف الجلسة في تطبيق الويب)
session_id = "user_123"

# --- 2. إعداد SQLite لتخزين ذاكرة المحادثات ---
sqlite_db_path = "chat_history.db"
sqlite_connection_string = f"sqlite:///{sqlite_db_path}"

sqlite_message_history = SQLChatMessageHistory(
    session_id=session_id,
    connection_string=sqlite_connection_string
)
sqlite_memory = ConversationBufferMemory(
    chat_memory=sqlite_message_history,
    return_messages=True
)

print("تم تهيئة SQLite بنجاح.")

# --- 3. دمج الذاكرة مع ConversationChain وإجراء محادثة (SQLite) ---
sqlite_conversation_chain = ConversationChain(
    llm=llm,
    memory=sqlite_memory,
    verbose=True
)

print("\n--- بدء المحادثة (SQLite) ---")

response1 = sqlite_conversation_chain.predict(input="مرحباً، من أنت؟")
print(f"الإنسان: مرحباً، من أنت؟")
print(f"الذكاء الاصطناعي: {response1}")

response2 = sqlite_conversation_chain.predict(input="أنا مهتم بالبرمجة، هل يمكنك المساعدة؟")
print(f"الإنسان: أنا مهتم بالبرمجة، هل يمكنك المساعدة؟")
print(f"الذكاء الاصطناعي: {response2}")

response3 = sqlite_conversation_chain.predict(input="لغتي المفضلة هي بايثون.")
print(f"الإنسان: لغتي المفضلة هي بايثون.")
print(f"الذكاء الاصطناعي: {response3}")

response4 = sqlite_conversation_chain.predict(input="أريد بناء تطبيق ويب.")
print(f"الإنسان: أريد بناء تطبيق ويب.")
print(f"الذكاء الاصطناعي: {response4}")

# --- 4. اختبار استمرارية الذاكرة (SQLite) ---
print("\n--- اختبار استمرارية الذاكرة (SQLite) ---")

# إنشاء ذاكرة جديدة بنفس session_id لتحميل المحادثة السابقة
new_sqlite_message_history = SQLChatMessageHistory(
    session_id=session_id,
    connection_string=sqlite_connection_string
)
new_sqlite_memory = ConversationBufferMemory(
    chat_memory=new_sqlite_message_history,
    return_messages=True
)

print("الرسائل المحملة من SQLite:")
for msg in new_sqlite_memory.chat_memory.messages:
    print(f"  {msg.type.capitalize()}: {msg.content}")

restored_sqlite_conversation_chain = ConversationChain(
    llm=llm,
    memory=new_sqlite_memory,
    verbose=True
)
response5 = restored_sqlite_conversation_chain.predict(input="ما هي الخطوة التالية في مشروع تطبيق الويب الخاص بي؟")
print(f"الإنسان: ما هي الخطوة التالية في مشروع تطبيق الويب الخاص بي؟")
print(f"الذكاء الاصطناعي: {response5}")

# --- 5. إعداد Redis لتخزين ذاكرة المحادثات (يتطلب تشغيل خادم Redis) ---
try:
    redis_client = redis.Redis(host='localhost', port=6379, db=0)
    redis_client.ping()
    print("\nتم الاتصال بخادم Redis بنجاح.")

    redis_message_history = RedisChatMessageHistory(
        session_id=session_id,
        redis_client=redis_client
    )
    redis_memory = ConversationBufferMemory(
        chat_memory=redis_message_history,
        return_messages=True
    )

    # --- 6. دمج الذاكرة مع ConversationChain وإجراء محادثة (Redis) ---
    redis_conversation_chain = ConversationChain(
        llm=llm,
        memory=redis_memory,
        verbose=True
    )

    print("\n--- بدء المحادثة (Redis) ---")

    response_r1 = redis_conversation_chain.predict(input="أهلاً بك، ما هو رأيك في قواعد البيانات NoSQL؟")
    print(f"الإنسان: أهلاً بك، ما هو رأيك في قواعد البيانات NoSQL؟")
    print(f"الذكاء الاصطناعي: {response_r1}")

    response_r2 = redis_conversation_chain.predict(input="هل توصي باستخدام MongoDB لمشروع كبير؟")
    print(f"الإنسان: هل توصي باستخدام MongoDB لمشروع كبير؟")
    print(f"الذكاء الاصطناعي: {response_r2}")

    # --- 7. اختبار استمرارية الذاكرة (Redis) ---
    print("\n--- اختبار استمرارية الذاكرة (Redis) ---")

    new_redis_message_history = RedisChatMessageHistory(
        session_id=session_id,
        redis_client=redis_client
    )
    new_redis_memory = ConversationBufferMemory(
        chat_memory=new_redis_message_history,
        return_messages=True
    )

    print("الرسائل المحملة من Redis:")
    for msg in new_redis_memory.chat_memory.messages:
        print(f"  {msg.type.capitalize()}: {msg.content}")

    restored_redis_conversation_chain = ConversationChain(
        llm=llm,
        memory=new_redis_memory,
        verbose=True
    )
    response_r3 = restored_redis_conversation_chain.predict(input="ما هي البدائل الأخرى لـ MongoDB؟")
    print(f"الإنسان: ما هي البدائل الأخرى لـ MongoDB؟")
    print(f"الذكاء الاصطناعي: {response_r3}")

except redis.exceptions.ConnectionError as e:
    print(f"\nخطأ: لم يتمكن الاتصال بخادم Redis. يرجى التأكد من تشغيله. التفاصيل: {e}")
    print("تخطي جزء Redis من الدرس.")
except Exception as e:
    print(f"\nحدث خطأ غير متوقع في جزء Redis: {e}")
    print("تخطي جزء Redis من الدرس.")

النتيجة المتوقعة

عند تشغيل السكربت، ستلاحظ ما يلي في وحدة التحكم (Console): 1. رسائل تأكيد تهيئة SQLite. 2. سلسلة من المحادثات باستخدام ذاكرة SQLite، حيث يقوم النموذج الوهمي بالردود المتوقعة التي تظهر فهماً للسياق السابق. سترى أيضاً مخرجات verbose=True التي توضح كيف يتم تمرير سجل المحادثة إلى النموذج. 3. قسم يوضح كيفية تحميل الذاكرة من SQLite بعد "إعادة التشغيل"، مع طباعة الرسائل السابقة التي تم استرجاعها من ملف chat_history.db. 4. المحادثة تستمر مع الذاكرة المستعادة، مما يثبت أن السياق تم حفظه واسترجاعه بنجاح. 5. إذا كان خادم Redis قيد التشغيل، سترى رسالة تأكيد الاتصال به. 6. سلسلة جديدة من المحادثات باستخدام ذاكرة Redis، حيث يبدأ النموذج محادثة جديدة (لأنها ذاكرة منفصلة عن SQLite) ويحافظ على سياقها ضمن Redis. 7. قسم يوضح كيفية تحميل الذاكرة من Redis بعد "إعادة التشغيل"، مع طباعة الرسائل السابقة التي تم استرجاعها من Redis. 8. المحادثة تستمر مع ذاكرة Redis المستعادة. سيتم إنشاء ملف chat_history.db في نفس مجلد السكربت، والذي يمكنك فحصه باستخدام أي أداة لمتصفح SQLite لرؤية الرسائل المخزنة.