بناء أداة تجيب على أسئلة المستخدمين من خلال تحليل بيانات ملف Excel/CSV مباشرة
بناء أداة تجيب على أسئلة المستخدمين من خلال تحليل بيانات ملف Excel/CSV مباشرة
هذا النوع من التطبيقات يُعد من أكثر أنماط الذكاء التوليدي فائدة داخل الشركات، لأنه يربط النموذج اللغوي الكبير LLM ببيانات تشغيلية حقيقية موجودة داخل ملفات جدولة مثل .xlsx و.csv. بدلاً من مطالبة المستخدم بقراءة الصفوف يدوياً أو كتابة تقارير مرهقة، يمكننا بناء طبقة وسيطة تستقبل السؤال، تحلل هيكل الملف، تستخرج الإحصاءات أو الصفوف المطابقة، ثم تمرر السياق النهائي إلى النموذج لإنتاج إجابة مفهومة ودقيقة.
فكرياً، هذا المشروع يقع بين نمطين: نمط التحليل الجدولي المباشر، ونمط RAG. لكنه يختلف عن استرجاع النصوص الحرة؛ فنحن هنا نتعامل مع بيانات مهيكلة ذات أعمدة وأنواع قيم وعلاقات ضمنية بين الحقول. لذلك فإن نجاح الأداة لا يعتمد فقط على جودة النموذج، بل على دقة تنظيف البيانات، وفهم أسماء الأعمدة، وبناء مسار معالجة واضح قبل إرسال أي سياق إلى API.
المعمارية الهندسية للأداة
أفضل تصميم عملي يبدأ بفصل النظام إلى طبقات صغيرة، بحيث تكون كل طبقة قابلة للاختبار والاستبدال:
- طبقة تحميل الملف باستخدام
pandas. - طبقة فحص البنية واكتشاف أنواع الأعمدة والقيم الناقصة.
- طبقة تفسير سؤال المستخدم وتحويله إلى نية تحليلية مثل: تجميع، تصفية، مقارنة، متوسط، أعلى قيمة.
- طبقة تنفيذ التحليل على
DataFrame. - طبقة توليد الإجابة النهائية بلغة طبيعية مع تضمين النتائج الرقمية الفعلية.
- طبقة حماية تمنع الهلوسة عبر إجبار النموذج على استخدام النتائج المحسوبة فقط.
هذا الفصل مهم جداً من منظور الاعتمادية. إذا تركت النموذج يقرأ الملف خاماً ويستنتج الأرقام بنفسه، فسترتفع احتمالات الخطأ. أما إذا جعلت العمليات الحسابية تنفذ برمجياً أولاً، ثم استخدمت LLM فقط لصياغة الإجابة وشرحها، فأنت تبني نظاماً أقرب إلى المنتجات المؤسسية.
تدفق البيانات من السؤال إلى الجواب
- يرفع المستخدم ملف
ExcelأوCSV. - يتم تحويله إلى
DataFrameموحد. - يُنشأ وصف ميتاداتا يتضمن أسماء الأعمدة والأنواع وعدد الصفوف.
- يُحلل سؤال المستخدم باستخدام قالب Prompt Engineering لتحديد العملية المطلوبة.
- تنفذ العملية حسابياً داخل بايثون.
- ترسل النتائج المنظمة إلى النموذج لصياغة رد نهائي واضح، ويمكن أيضاً إجبار المخرج على JSON إذا أردت واجهة أمامية أكثر صرامة.
الطبقة الأولى: قراءة الملفات وتوحيدها
الخطوة الأولى ليست “ذكاءً اصطناعياً” بقدر ما هي هندسة بيانات خفيفة. يجب أن تدعم الأداة الامتدادات الشائعة، وتتعامل مع أكثر من ترميز، وتزيل الفراغات من أسماء الأعمدة، لأن كثيراً من الأسئلة تفشل بسبب اختلاف بسيط مثل وجود مسافة زائدة داخل اسم عمود.
import pandas as pd
def load_tabular_file(file_path: str) -> pd.DataFrame:
if file_path.endswith(".csv"):
df = pd.read_csv(file_path)
elif file_path.endswith(".xlsx") or file_path.endswith(".xls"):
df = pd.read_excel(file_path)
else:
raise ValueError("Unsupported file type")
df.columns = [col.strip() for col in df.columns]
return df
def summarize_dataframe(df: pd.DataFrame) -> dict:
return {
"rows": len(df),
"columns": list(df.columns),
"dtypes": {col: str(dtype) for col, dtype in df.dtypes.items()},
"missing_values": df.isna().sum().to_dict()
}
إذا كنت قد أعددت بيئتك سابقاً وفق درس تثبيت مكتبات Python الأساسية للتعامل مع الذكاء الاصطناعي فستكون مكتبات مثل pandas وopenpyxl جاهزة للعمل مباشرة.
الطبقة الثانية: فهم السؤال بشكل قابل للتنفيذ
هنا تظهر أهمية النماذج اللغوية. المستخدم قد يكتب: “ما أعلى منطقة مبيعاً في الربع الأول؟” أو “كم متوسط الإيرادات للمنتجات الإلكترونية؟”. هذه الأسئلة يجب تحويلها إلى تمثيل تنفيذي يتضمن اسم العملية والعمود الهدف والمرشحات المطلوبة. هذه الفكرة قريبة من منطق Text-to-SQL، لكن بدلاً من قاعدة بيانات SQL نحن نستهدف DataFrame.
أنت محلل بيانات يعمل على ملف جدولي. بناءً على أسماء الأعمدة وسؤال المستخدم، أعد فقط كائناً يحدد:
نوع العملية، العمود المستهدف، أعمدة التصفية، القيم المطلوبة، وهل هناك تجميع أو ترتيب.
لا تخمّن أعمدة غير موجودة.
هذا النوع من القوالب يصبح أكثر استقراراً إذا أرفقنا معه ميتاداتا الأعمدة الفعلية بدلاً من إرسال عينات عشوائية من كامل الملف. كما أن التحكم في إعدادات الإبداع مثل Temperature مهم هنا؛ لأننا نريد سلوكاً حذراً لا إبداعياً.
مثال باستخدام LangChain
يمكنك استخدام LangChain لبناء سلسلة صغيرة تستقبل السؤال وميتا البيانات وتعيد بنية قابلة للتنفيذ:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "You convert user questions about tabular data into executable analysis instructions."),
("human", """
Dataset metadata:
{metadata}
User question:
{question}
Return a compact JSON object with:
operation, target_column, filters, group_by, sort_by, limit
""")
])
chain = prompt | llm
ربط هذه السلسلة بمفهوم السلاسل البرمجية موضح بوضوح في مقال إنشاء أول سلسلة (Chain) باستخدام LangChain.
الطبقة الثالثة: تنفيذ التحليل داخل بايثون
بعد الحصول على تعليمات منظمة، يجب تنفيذها محلياً. هذه النقطة هي حجر الأساس في تقليل الهلوسة. لا تجعل النموذج يحسب المتوسط أو يجمع القيم ذهنياً؛ بل نفذ ذلك عبر pandas، ثم مرر المخرجات الموثقة فقط.
def apply_filters(df, filters):
filtered_df = df.copy()
for item in filters:
column = item["column"]
value = item["value"]
filtered_df = filtered_df[filtered_df[column] == value]
return filtered_df
def execute_analysis(df, plan):
working_df = apply_filters(df, plan.get("filters", []))
if plan["operation"] == "average":
result = working_df[plan["target_column"]].mean()
return {"result": float(result)}
if plan["operation"] == "sum":
result = working_df[plan["target_column"]].sum()
return {"result": float(result)}
if plan["operation"] == "max_by_group":
grouped = working_df.groupby(plan["group_by"])[plan["target_column"]].sum()
top_item = grouped.sort_values(ascending=False).head(1)
return top_item.to_dict()
return {"error": "Unsupported operation"}
في المشاريع الأوسع، يمكنك تطوير طبقة تنفيذ تدعم عمليات أكثر مثل median وcount distinct وتحليل الاتجاهات الزمنية بعد تحويل الأعمدة التاريخية بشكل صحيح.
صياغة الإجابة النهائية للمستخدم
الآن يأتي دور النموذج التوليدي الحقيقي: شرح النتيجة بلغة إنسانية مفهومة، مع الالتزام الصارم بالأرقام المستخرجة. من الأفضل أن تزوده بسياق ضيق جداً: السؤال الأصلي + النتيجة الحسابية + تعليمات عدم اختراع أي قيمة غير موجودة.
أجب على المستخدم بالعربية الفصحى بشكل واضح ومهني. استخدم فقط النتائج الرقمية المرسلة لك. إذا كانت البيانات غير كافية أو الأعمدة غير موجودة، فاذكر ذلك صراحة ولا تخمّن.
إذا كان التطبيق موجهاً للواجهات التفاعلية، يمكنك دعم Streaming Responses حتى تظهر الإجابة تدريجياً مثل التطبيقات الحديثة.
متى نحتاج Embeddings أو RAG هنا؟
في الملفات الصغيرة والمتوسطة، التحليل المباشر يكفي غالباً. لكن إذا احتوى الملف على أعمدة وصفية طويلة، أو ملاحظات نصية، أو تفسيرات بشرية داخل الخلايا، فقد يصبح من المفيد دمج أساليب Embeddings وVector Databases لاسترجاع الصفوف أو التعليقات الأكثر صلة بالسؤال. هنا يتحول النظام إلى نسخة هجينة: جزء جدولي لحساب الأرقام، وجزء استرجاعي نصي لتفسير الملاحظات الحرة. وهذا امتداد طبيعي لفهم دمج المعلومات المسترجعة مع الـ LLM.
اعتبارات الأمان والجودة والإنتاج
- تحقق من أسماء الأعمدة قبل أي تنفيذ لتفادي فشل السلسلة.
- لا تسمح للنموذج بتنفيذ بايثون حر إذا كان التطبيق عاماً؛ استخدم طبقة أوامر محددة مسبقاً.
- سجّل الميتاداتا والخطة التحليلية والنتيجة النهائية لتسهيل التتبع.
- احسب حجم السياق والتكلفة إذا كنت ترسل عينات أو وصفاً كبيراً، ويمكن الاستفادة من مفاهيم إدارة الرموز والتكلفة.
- إذا كان الملف يحتوي على بيانات حساسة، ففكر في المعالجة المحلية أو تقليل البيانات المرسلة إلى المزود الخارجي.
الخلاصة الهندسية
بناء أداة للأسئلة والأجوبة فوق ملفات Excel/CSV ليس مجرد استدعاء LLM. إنه نظام هندسي مصغّر يبدأ من تنظيف البيانات، ثم تفسير السؤال، ثم تنفيذ العمليات حسابياً، ثم توليد إجابة موثوقة. كلما نقلت المسؤوليات العددية والمنطقية إلى طبقة برمجية صريحة، ازدادت دقة المنتج وقلت الهلوسة. وهذه بالضبط هي العقلية التي تميز تطبيقات الذكاء الاصطناعي الجاهزة للإنتاج عن النماذج التجريبية السريعة.
2 comments