تصور کنید یک سیستم مالی، تنها به دلیل شباهت یک شرکت کلاهبردار به یک تأمینکننده معتبر، میلیونها تومان را به حسابی اشتباه واریز کند. در دنیای عاملهای هوش مصنوعی، این کابوس زمانی رخ میدهد که مدل سعی میکند با استفاده از «نزدیکترین همسایهها» (Nearest Neighbors) در حافظه، برای یک موجودیت ناشناس، اعتبار جعلی بسازد. این اتفاق زمانی میافتد که سیستم به جای بررسی تاریخچه واقعی، از روی شباهتهای ظاهری در دستهبندیها، شرایط یا مبالغ، اعتماد را استنتاج کند.
عامل مالی LedgerMind را به گونهای طراحی کردهاند که هنگام مواجهه با هر تأمینکننده جدید، عمداً همه چیز را فراموش کند. در یک تحلیل فنی، توسعهدهنده فاش کرد که بازگرداندن یک لیست حافظهٔ خالی، یک باگ نیست، بلکه یک ویژگی امنیتی حیاتی برای جلوگیری از کلاهبرداری است. در واقع، مهمترین خط کد در این عامل، همان بخشی است که دستور فراموش کردن میدهد تا از انتقال اعتبار یک شرکت معتبر به یک شرکت کلاهبردار (که دقیقاً هدف کلاهبرداریهای تغییر جزئیات بانکی است) جلوگیری شود.
بسیاری از توسعهدهندگان هوش مصنوعی تلاش میکنند کیفیت بازیابی (Retrieval) و حجم زمینه (Context) را افزایش دهند. اما در حسابهای پرداخت (AP)، این رویکرد خطرناک است. اعتماد در تراکنشهای مالی باید از طریق تاریخچه خاص یک تأمینکننده بهدست بیاید، نه اینکه از روی شباهت به دیگران استنتاج شود. اگر یک بانک پرداختی را برای تأمینکنندهای انجام دهد که هرگز ندیده است، یک جستوجوی معنایی استاندارد ممکن است خاطرات تأمینکنندگان مشابه را برگرداند. اگر هوش مصنوعی اینها را به عنوان دلیل اعتماد بپذیرد، یک تأمینکننده متقلب میتواند اعتبار یک شرکت مشابه و قانونی را به ارث ببرد. این چالش با خطرات دیگر در مدیریت دادههای عاملها همسو است؛ برای مثال، برخی نقصها در حذف دادههای تکراری میتواند منجر به ایجاد «موفقیتهای کاذب» در پردازش شود که مشابه توهمات اعتباری در سیستمهای مالی است.
یک عامل (Agent) — شبیه به کارمندی دیجیتال که میتواند تصمیم بگیرد و ابزارها را اجرا کند — در LedgerMind وظیفه دارد پرداختها را تأیید، علامتگذاری به عنوان استثنا (Exception)، متوقف کردن پرداخت یا ارجاع آن به انسان را مدیریت کند. این فرآیند از یک توالی سختگیرانه پیروی میکند:
صورتحساب $ \rightarrow $ سفارش خرید $ \rightarrow $ رسید کالا $ \rightarrow $ فراخوانی حافظه $ \rightarrow $ ارزیابی ریسک $ \rightarrow $ تصمیم $ \rightarrow $ ثبت در حافظه

سه گام اول، کنترلهای معمول حسابهای پرداخت هستند: یافتن سفارش خرید (PO)، یافتن رسید کالا و اجرای تطبیق سهجانبه (Three-way match). اما چهار گام نهایی جایی است که تصمیمات پیچیده رخ میدهد. این سیستم از Hindsight، یک سامانه حافظهٔ بازمتن برای عاملها، از طریق یک کلاینت TypeScript استفاده میکند. بکاند Express برای فراخوانی (Recall) و ثبت (Retain) با Hindsight ارتباط برقرار میکند. برای تضمین پایداری، عامل دو فراخوانی مجزا انجام میدهد: یک بار برای بازیابی قبل از تصمیم و یک بار برای ثبت پس از تعیین نتیجه. چون هر اجرا میتواند با یا بدون حافظه انجام شود، توسعهدهنده میتواند دقیقاً ببیند حافظه در هر صورتحساب چه تغییری در نتیجه ایجاد کرده است.
برای جلوگیری از «اعتماد توهمی» که پیشتر ذکر شد، تابع recallVendorMemory اگر در سوابق اصلی تأمینکننده (Vendor Master Record) هیچ پرداختی ثبت نشده باشد، از جستوجو در حافظه خودداری میکند. این یعنی تأمینکنندگان جدید بهصورت پیشفرض توسط کارکنان انسانی بخش مالی بررسی میشوند. در این حالت، تأمینکننده وارد مرحله ارزیابی میشود و سیستم با امتیاز اطمینان ۶۱٪، توصیه «بررسی انسانی» (HUMAN REVIEW) را صادر میکند.
این طراحی تضمین میکند که یک فراخوانی خالی به عنوان یک پاسخ معتبر تلقی شود. پاسخ حاوی مقدار منبع (Source Value) است تا در گزارشهای بازرسی و لاگهای سیستم، بتوان بین «نبود تاریخچه» و «شکست سیستم» (زمانی که Hindsight پاسخ نمیدهد) تمایز قائل شد.
حتی برای تأمینکنندگان شناختهشده، سیستم به خروجی خام حافظه اعتماد نمیکند. از آنجا که تمام تأمینکنندگان از یک بانک مشترک استفاده میکنند و حافظه شامل تصمیمات گذشته خود عامل است، دو ریسک ایجاد میشود: دریافت نتایج مربوط به تأمینکنندگان دیگر و ایجاد «شواهد دوری» (Circular Evidence)، جایی که فراخوانی برای صورتحساب امروز، تصمیمی را برمیگرداند که در اجرای قبلی برای همان صورتحساب گرفته شده است.

برای حل این مشکل، توسعهدهنده فیلترهای سختگیرانهای در سطح کد پیاده کرده است. سیستم تنها به کوئری تکیه نمیکند، بلکه نتایج را با منطق زیر فیلتر میکند:const rawMemories = (result.results || []).map(r => ({ text: r.text || r.content || '', type: r.type || 'memory' })).filter(m => m.text && m.text.toLowerCase().includes(vendorNameLower)).filter(m => !m.text.includes(invoice.invoiceNumber));
هر حافظه بازیابیشده باید سه آزمون را پاس کند:
۱. باید نام تأمینکننده را دقیقاً ذکر کند (با استفاده از هویت ثبت شده در Master Record و نه متن صورتحساب).
۲. نباید به شماره صورتحساب فعلی اشاره داشته باشد.
۳. تنها ۴ تکه (Snippet) از مرتبطترین یادداشتها حفظ شوند.
این تطبیق رشتهای ساده (String Matching) را به منطقهای پیچیده و مبهم ترجیح دادهاند چون قابل حسابرسی است. وقتی پرداختی متوقف میشود، حسابرس میتواند دقیقاً ۴ یادداشت را بخواند و دلیل تصمیم را بفهمد.
حافظه در اینجا معیاری برای تشخیص «غافلگیری» است. واضحترین مورد، تغییر شماره حساب بانکی است. برای مثال، سیستم ممکن است این حافظه را داشته باشد که شرکت Ravi Steel & Components تعداد ۱۴ پرداخت موفق به حسابی ختم شده به ۴۸۲۱ داشته و هیچ تغییری در ذینفع صورت نگرفته است.
اگر صورتحساب جدیدی با مبلغ ۹۵۸,۶۳۲ روپیه و جزئیات بانکی ختم شده به ۷۷۱۹ برسد، رفتار عامل بر اساس حافظه تغییر میکند:
- بدون حافظه: عامل تغییر حساب را میبیند و با اطمینان ۷۲٪ آن را به بررسی انسانی میفرستد.
- با حافظه: عامل متوجه انحراف از یک تاریخچه پایدار میشود. او از منطقی مانند
const firstBankChange = bankChanged && priorPayments >= 10;استفاده میکند.
چون ۱۴ پرداخت پاک به یک حساب و سپس تغییر ناگهانی آن یک سیگنال قوی است، عامل پرچم FIRST_BANK را فعال میکند، سطح اعتماد به تأمینکننده را از ۹۰ به ۳۰ میرساند و پرداخت را با اطمینان ۹۹٪ مسدود (PAYMENT BLOCKED) میکند. توصیه سیستم بهطور مشخص به کاربر میگوید که حساب جدید را از طریق اطلاعات تماسی که «قبلاً در پرونده موجود است» تأیید کند، نه از طریق تماسی که روی صورتحساب فعلی درج شده است؛ زیرا خود صورتحساب همان سندی است که مورد تردید است.

برای جلوگیری از شلوغ شدن حافظه با تاییدات روتین، LedgerMind تنها «یادگیریهای معنادار» را ثبت میکند. اگر عامل هر تصمیمی را ثبت میکرد، تاییدات عادی باعث میشد خاطرات با سیگنال بالا (High-signal) به حاشیه بروند.
ثبت در حافظه تنها در صورتی رخ میدهد که وضعیت تصمیم یکی از موارد زیر باشد:
- مسدود شدن پرداخت (PAYMENT BLOCKED)
- استثنا (EXCEPTION)
- بررسی انسانی (HUMAN REVIEW)
تاییدات بدون نقص ثبت نمیشوند. سیستم همچنین یک بررسی برای جلوگیری از ثبت تکراری (Idempotence) به کار میبرد: const alreadyRetained = store.audit.some(a => a.action === 'AGENT_MEMORY_RETAINED' && a.invoiceId === invoice.id);. این کار مانع از ایجاد حافظههای تکراری در صورتی میشود که کاربر چندین بار دکمه «اجرا» را بزند، اتفاقی که در غیر این صورت باعث سوگیری در فراخوانیهای آینده میشد.
این معماری تمرکز را از «عامل چقدر میتواند به یاد بیاورد» به «عامل اجازه دارد چه چیزی را به یاد بیاورد» تغییر میدهد. توسعهدهنده چندین درس کلیدی را برجسته میکند:
- فراخوانی خالی را به عنوان یک نتیجه درجه اول در نظر بگیرید: مواردی را که نیاز به «هیچ» دارند، قبل از کوئری اعمال کنید، نه بعد از آن.
- فیلتر را در کد پیاده کنید، نه فقط در پرامپت: پرامپت کمک میکند، اما بررسیهای سطح کد رفتار را قابل اطمینان میکنند.
- مجموعه شواهد را محدود کنید: چهار حافظه برای توجیه یک تصمیم کافی است و برای حسابرس به اندازه کافی کوچک است.
- در نوشتن گزینشی عمل کنید: رویدادهایی را ذخیره کنید که باعث تغییر تصمیم شدهاند تا کیفیت بازیابی آینده حفظ شود.
یک نقطه ضعف باقیمانده، استفاده از Regex برای استخراج تعداد پرداختها از متون بازیابی شده است. توسعهدهنده اشاره میکند که برای بررسیهای آستانهای (Threshold)، باید از متادیتای ساختاریافته در زمان ثبت استفاده کرد، زیرا متن برای استدلال (Reasoning) عالی است اما اعداد برای قوانین (Rules) مناسبترند.
برای کسانی که عاملهایی برای تصمیمات حساس میسازند، توسعهدهنده پیشنهاد میکند مخزن گیتهاب Hindsight را بررسی کنند یا پژوهشهای Vectorize درباره تفاوت حافظه عامل در مقابل RAG (در آدرس https://vectorize.io/articles/agent-memory-vs-rag) را مطالعه نمایند. در محیطهای مالی پرریسک، صادقانهترین پاسخ اغلب «هیچ» است.
گام بعدی شما
- اگر در حال ساخت عاملهای مالی هستید، به جای تکیه بر پرامپت، فیلترهای سختگیرانه در سطح کد (Code-level filters) را برای اعتبارسنجی دادهها پیاده کنید.
- برای سیستمهای حساس، «خروجی خالی» از حافظه را به عنوان یک پاسخ معتبر و امن تعریف کنید، نه یک خطا.
- مخزن گیتهاب Hindsight را برای پیادهسازی حافظه در عاملهای خود بررسی کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو