جستجوی سند در .NET با حافظه هسته

من به تازگی کتابخانه حافظه هسته را برای نمایه سازی اسناد ، خراش وب ، جستجوی معنایی و پاسخ به سؤال مبتنی بر LLM کشف کردم. قابلیت ها ، انعطاف پذیری و سادگی این کتابخانه به قدری خارق العاده است که به سرعت لیست من از کتابخانه های مورد علاقه هوش مصنوعی را برای کار با جستجوی RAG ، جستجوی اسناد یا پاسخ به سؤال مبتنی بر هوش مصنوعی صعود می کند.
در این مقاله شما را از طریق حافظه هسته و چگونگی استفاده از نسخه C# این کتابخانه برای فهرست بندی سریع ، جستجو و گپ زدن با دانش ذخیره شده در اسناد یا صفحات وب استفاده می کنم.
حافظه هسته ، فهرست بندی اسناد انعطاف پذیر و کتابخانه جستجوی RAG
در هسته اصلی آن ، حافظه هسته همه چیز در مورد مصرف اطلاعات در منابع مختلف ، نمایه سازی آن ، ذخیره کردن آن در یک راه حل ذخیره سازی بردار و فراهم کردن وسیله ای برای جستجو و پاسخ به پاسخ به این دانش شاخص است.
ما در این مقاله یک برنامه کاربردی کامل را طی خواهیم کرد ، اما در اینجا یک اجرای ساده برای کمک به شما وجود دارد:
IKernelMemory memory = new KernelMemoryBuilder()
.WithOpenAI(openAiConfig)
.Build();
await memory.ImportDocumentAsync("TheGuide.pdf");
string question = "What is the answer to the question of life, the universe, and everything?"
MemoryAnswer answer = await memory.AskAsync(question);
string reply = answer.Result;
console.WriteLine(reply);
در این قطعه می بینیم که:
- حافظه هسته از API سازنده استاندارد استفاده می کند و به شما امکان می دهد منابع مختلفی را که مربوط به شما هستند اضافه کنید (در اینجا یک متن OpenAi و مدل تعبیه شده)
- حافظه هسته فراهم می کند
Import
روش هایی که به شما امکان می دهد اسناد ، متن و صفحات وب را فهرست بندی کرده و آنها را در فروشگاه وکتور فعلی خود ذخیره کنید - حافظه هسته یک روش مناسب برای پرسیدن سؤال به LLM و ارائه اطلاعات شما به عنوان منبع داده RAG ارائه می دهد
در این مثال کوتاه ، ما از فروشگاه وکتور حافظه فرار پیش فرض استفاده می کنیم که برای اهداف نمایش در حافظه هسته ساخته شده است ، اما می توانید به راحتی از یک ارائه دهنده ذخیره سازی بردار موجود مانند Qdrant ، Azure AI Search ، Postgres ، Redis یا موارد دیگر استفاده کنید.
به همین ترتیب ، حافظه هسته از طیف گسترده ای از LLM ها و سایر منابع داده مصرف از جمله مدل های Openai ، Anthropic ، Onnx و حتی مدل های Ollama در حال اجرا پشتیبانی می کند.
این نکته آخر من را به خصوص هیجان زده می کند زیرا اکنون می توانم از LLMS میزبان محلی و راه حل های ذخیره سازی بردار بر روی شبکه استفاده کنم تا اسناد جستجو و جستجوی اسناد را بدون نیاز به نگرانی در مورد داده های من یا هزینه های میزبانی ابر در هر بار استفاده کنم. این سناریوهای جدید استفاده را برای من برای آزمایش ، کارگاه های آموزشی در کنفرانس ها و سناریوهای تجاری باز می کند.
بیایید به یک برنامه حافظه هسته بزرگتر حفاری کنیم و ببینیم که چگونه جریان می یابد.
ایجاد یک نمونه حافظه هسته در C
از طریق بقیه این مقاله از ابتدا تا انتها یک برنامه کنسول C# کوچک را طی خواهیم کرد. اگر می خواهید آن را به صورت محلی کلون کنید و با آن آزمایش کنید ، این پروژه در GitHub موجود است ، اگرچه باید کلیدهای API خود را ارائه دهید.
در مرحله بعد ما از کد C# نسبتاً معمولی استفاده می کنیم Microsoft.Extensions.Configuration
مکانیسم تنظیم تنظیمات:
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddEnvironmentVariables()
.AddUserSecrets<Program>()
.AddCommandLine(args)
.Build();
DocSearchDemoSettings settings = config.Get<DocSearchDemoSettings>()!;
این اطلاعات را از یک پرونده محلی JSON ، آرگومان های خط فرمان ، اسرار کاربر و متغیرهای محیط می خواند و آنها را در یک شیء تنظیمات ذخیره می کند که به نظر می رسد:
public class DocSearchDemoSettings
{
public required string OpenAIEndpoint { get; init; }
public required string OpenAIKey { get; init; }
public required string TextModelName { get; init; }
public required string EmbeddingModelName { get; init; }
}
بیشتر این تنظیمات در appsettings.json
اگر قصد دارید با کلیدهای شخصی خود و مدیریت موارد در کنترل منبع کار کنید ، باید نقطه پایانی و کلید خود را در اسرار کاربر یا متغیرهای محیط ذخیره کنید.
{
"OpenAIEndpoint": "YourEndpoint",
"OpenAIKey": "YourApiKey",
"TextModelName": "gpt-4o-mini",
"EmbeddingModelName": "text-embedding-3-small"
}
با بارگذاری پیکربندی ما ، اکنون به ایجاد خود می پردازیم IKernelMemory
به عنوان مثال ، در جایی که ما باید اطلاعاتی را در مورد کدام مدل ، نقاط پایانی و کلیدها برای استفاده ارائه دهیم:
OpenAIConfig openAiConfig = new()
{
APIKey = settings.OpenAIKey,
Endpoint = settings.OpenAIEndpoint,
EmbeddingModel = settings.EmbeddingModelName,
TextModel = settings.TextModelName,
};
IKernelMemory memory = new KernelMemoryBuilder()
.WithOpenAI(openAiConfig)
.Build();
IAnsiConsole console = AnsiConsole.Console;
console.MarkupLine("[green]KernelMemory initialized.[/]");
این نمونه حافظه هسته ما را با استفاده از یک متن OpenAI و مدل تعبیه شده ایجاد و پیکربندی می کند. از مدل تکمیل متن برای مکالمات با داده های ما با استفاده از AskAsync
روش در حالی که از مدل تعبیه شده برای تولید یک بردار استفاده می شود که بخش های مختلفی از اسناد را نشان می دهد و همچنین در هنگام جستجو در نمونه حافظه ، پرس و جوهای جستجو را نشان می دهد.
به طور پیش فرض حافظه هسته از یک فروشگاه وکتور در حافظه فرار می کند که هر بار که برنامه اجرا می شود کاملاً دور ریخته و بازسازی می شود. این یک راه حل سطح تولید نیست ، اما برای تظاهرات سریع در مورد حجم کم داده ها خوب است. برای سناریوهای در مقیاس بزرگتر یا استفاده از تولید ، می توانید از یک راه حل اختصاصی ذخیره سازی بردار استفاده کرده و هنگام ساخت خود به حافظه هسته وصل کنید IKernelMemory
نمونه
همچنین توجه داشته باشید که استفاده از AnsiConsole
بشر این بخشی از Spectre.Console
، کتابخانه ای که من اغلب در کنار برنامه های کنسول .NET برای قابلیت های پیشرفته ورودی و خروجی استفاده می کنم. بعداً بیشتر از این خواهیم دید.
نمایه سازی اسناد و خراش وب با حافظه هسته
با استفاده از نمونه حافظه هسته ما یک فروشگاه وکتور خالی ، قبل از ادامه کار باید برخی از داده ها را مصرف کنیم.
حافظه هسته از وارد کردن داده ها در قالب های زیر پشتیبانی می کند:
- رشته های خام
- صفحات وب از طریق خراش وب
- اسناد با فرمت پشتیبانی شده (PDF ، تصاویر ، Word ، PowerPoint ، Excel ، Markdown ، Files Text و JSON)
API برای وارد کردن هر یک از این منابع نیز فوق العاده ساده است:
// Index documents and web content
console.MarkupLine("[yellow]Importing documents...[/]");
await memory.ImportTextAsync("KernelMemory allows you to import web pages, documents, and text");
await memory.ImportTextAsync("KernelMemory supports PDF, md, txt, docx, pptx, xlsx, and other formats", "Doc-Id");
await memory.ImportDocumentAsync("Facts.txt", "Repository-Facts");
await memory.ImportWebPageAsync("https://LeadingEDJE.com", "Leading-EDJE-Web-Page");
await memory.ImportWebPageAsync("https://microsoft.github.io/kernel-memory/",
"KernelMemory-Web-Page",
new TagCollection { "GitHub"});
console.MarkupLine("[green]Documents imported.[/]");
این کد یک جفت رشته خام ، یک پرونده FACTS.TXT را با مخزن و یک جفت صفحه وب فهرست می کند: وب سایت پیشرو Edje (کارفرمای من ، یک مشاوره خدمات فناوری اطلاعات در کلمبوس ، اوهایو) و مخزن GitHub برای حافظه هسته.
توجه داشته باشید که از آنجا که هر چیزی را فهرست می کنیم ، فقط می توانیم به آن منبع داده ای بدهیم ، یا می توانیم به آن منبع داده و یک شناسه سند بدهیم ، یا می توانیم برچسب یا ابرداده اضافی را نیز ارائه دهیم.
با استفاده از برچسب ها و ایندکس ها می توانید اسنادی را که متعلق به مجموعه های خاصی درج شده است ، حاشیه نویسی کنید. این به شما امکان می دهد بعداً هنگام جستجو یا پرسیدن سؤالاتی که از سناریوهای مهم مانند محدود کردن اطلاعات در دسترس کاربران مختلف بر اساس آن سازمان یا نقش امنیتی آنها پشتیبانی می کند ، بعداً به گروه های خاصی از اسناد فیلتر کنید.
بیشتر همه چیز در مورد حافظه هسته نیز قابل تنظیم است ، بنابراین می توانید نحوه رمزگشایی و پارتیشن اسناد را تغییر دهید و به عنوان مثال می توانید در ارائه دهنده ضایعات وب خود جایگزین کنید.
اینها Import
تماس ها بر اساس اندازه داده ها ، مدل تعبیه متن شما و انتخاب راه حل ذخیره سازی بردار ، چند ثانیه طول می کشد. پس از اتمام ، داده های شما برای جستجو در دسترس خواهد بود.
جستجوی اسناد با حافظه هسته و تعبیه متن
با استفاده از داده های خود ، اکنون می توانیم از حافظه هسته برای سؤالات خاص پرس و جو کنیم. این می تواند به یکی از دو روش انجام شود:
-
SearchAsync
که نتایج جستجوی خام را به صورت برنامه ای انجام می دهد -
AskAsync
که یک جستجو را انجام می دهد و سپس با توجه به نتایج جستجو ، به سؤال پرسیده شده پاسخ می دهد.
در حالی که نتایج جستجو پیچیده تر از نتایج سؤال است ، ما باید با بررسی جستجو شروع کنیم زیرا این به ما کمک می کند تا درک کنیم که حافظه هسته در زیر کاپوت چه کاری انجام می دهد.
کد برای انجام خود جستجو ساده و شهودی است:
string search = console.Ask<string>("What do you want to search for?");
console.MarkupLineInterpolated($"[yellow]Searching for '{search}'...[/]");
SearchResult results = await memory.SearchAsync(search);
در SearchResult
Object نتایج خود را در استنادهای مختلفی که اسناد مختلف جستجو شده را نشان می دهد ، سازماندهی می کند. در هر استناد ، مجموعه های مختلفی از پارتیشن ها وجود خواهد داشت که بخش های مختلفی از سند را نشان می دهد که برای بازیابی داده ها نمایه می شوند و ذخیره می شوند. این مهم است زیرا اسناد و صفحات وب می توانند بسیار طولانی باشند و شما می خواهید هنگام انجام جستجو فقط در بخش های مرتبط با یک سند مطابقت داشته باشید.
هر پارتیشن دارای نمره ارتباطی است که به عنوان یک درصد درصد اعشاری از 0 تا 1 ذخیره می شود.
با استفاده از Spectre.Console
، می توانید از این استناد و پارتیشن ها حلقه کنید و با استفاده از کد زیر یک جدول نمایش ایجاد کنید:
Table table = new Table()
.AddColumns("Document", "Partition", "Section", "Score", "Text");
foreach (var citation in results.Results)
{
foreach (var part in citation.Partitions)
{
string snippet = part.Text;
if (part.Text.Length > 100)
{
snippet = part.Text[..100] + "...";
}
table.AddRow(citation.DocumentId, part.PartitionNumber.ToString(), part.SectionNumber.ToString(), part.Relevance.ToString("P2"), snippet);
}
}
table.Expand();
console.Write(table);
console. WriteLine();
این یک جدول فرمت شده شبیه تصویر زیر تولید می کند:
همانطور که مشاهده می کنید ، هر مسابقه دارای یک سند ، پارتیشن ، بخش در آن پارتیشن ، نمره ارتباط و برخی متن های مرتبط است. برچسب های فردی و URL های منبع نیز در دسترس خواهند بود. توجه داشته باشید که چگونه نام های اسناد اجباری نیستند ، اما اگر خودتان شناسنامه ارائه ندهید ، حافظه هسته شناسه های تصادفی خود را تولید می کند.
می توانید استفاده کنید SearchAsync
برای شناسایی دستی ترین اسناد و قطعات اسناد از فروشگاه بردار خود. این می تواند برای ارائه قابلیت های جستجوی معنایی در سایت شما یا شناسایی متن برای تزریق به مطالب به عنوان نوعی از تولید بازیابی (RAG) مفید باشد. با این حال ، اگر با RAG کار می کنید ، این احتمال وجود دارد که بهتر از آن استفاده کنید AskAsync
در عوض ، همانطور که بعد خواهیم دید.
پاسخ به سوال با KernelMemory و LLM
اگر هدف نهایی شما این است که از پرس و جو مورد نظر برای کاربر پاسخ به کاربر ارائه دهید ، باید از حافظه هسته استفاده کنید AskAsync
روش
AskAsync
از مدل متن برای خلاصه کردن نتیجه یک جستجو استفاده می کند و آن رشته را به کاربر باز می گرداند.
کد این کار بسیار ساده است:
string question = console.Ask<string>("What do you want to ask?");
console.MarkupLineInterpolated($"[yellow]Asking '{question}'...[/]");
MemoryAnswer answer = await memory.AskAsync(question);
console.WriteLine(answer.Result);
این یک خروجی متن از LLM شما را همانطور که انتظار دارید فراهم می کند:
همانطور که ممکن است تصور کنید ، AskAsync
روش به طور قابل توجهی طولانی تر از SearchAsync
از آنجا که به طور موثری در حال انجام جستجو به عنوان جستجوی RAG و سپس استفاده از نتایج برای گپ زدن با LLM اساسی است.
اگر به اطلاعات مربوط به منابع ذکر شده نیاز دارید ، این موارد نیز در دسترس هستند MemoryAnswer
، که می تواند برای اهداف تشخیصی / ورود به سیستم مفید باشد یا به سادگی به کاربر اطلاع دهد که در پاسخ به سؤال خود چه چیزی استفاده شده است – یا پیوندهای اضافی برای بررسی آنها.
پسوندها و ادغام حافظه هسته
حافظه هسته یک کتابخانه بسیار قدرتمند و انعطاف پذیر با API ساده و رفتارهای خوب خارج از جعبه است. از نظر آن رفتارهای پیش فرض برای مواقعی که به کنترل اضافی نیاز دارید ، از نظر آن رفتارهای پیش فرض بالایی دارد.
به عنوان مثال ، شما می توانید مواردی را که از حافظه هسته استفاده می کند برای استخراج و خلاصه واقعیت استفاده کنید ، و کنترل بیشتری از رفتار آن به عنوان یک شریک گپ به شما می دهد.
علاوه بر این ، حافظه هسته دارای تعدادی مدل استقرار متفاوت است ، از فرآیند MemoryServerless
پیاده سازی هایی مانند مورد شرح داده شده در این مقاله برای ظروف پیش ساخته Docker ، به خدمات وب.
حافظه هسته همچنین با هسته معنایی حداقل تا حدی در ذهن ساخته شده است. در حالی که هسته معنایی قابلیت فروشگاه های وکتور داخلی خود را دارد ، استفاده از گزینه های حافظه هسته سخت تر است و گزینه های زیادی برای مصرف ندارند. در نتیجه ، می توانید حافظه هسته را به یک نمونه هسته معنایی وصل کنید و یک منبع داده RAG را برای راه حل ارکستراسیون هوش مصنوعی خود تهیه کنید. در واقع ، حتی یک بسته nuget از پیش ساخته Semantickernelplugin ساخته شده است که فقط برای این منظور ساخته شده است.
پایان
من کاملاً به کتابخانه حافظه هسته علاقه مندم و کاربردهای زیادی را برای این فناوری مشاهده می کنم از جمله:
- جستجوی ساده و پاسخ به سوال برای برنامه های وب
- نمایه کردن منابع دانش موجود مانند تلاقی یا طاق های ابسیدین
- ارائه گزینه ای مقرون به صرفه و مطمئن برای مصرف اسناد ، اطمینان از داده های اسناد هرگز شبکه را ترک نمی کند
اگر در مورد حافظه هسته کنجکاو هستید ، من شما را ترغیب می کنم که به مخزن GitHub حاوی کد این مقاله نگاهی بیندازید و خودتان چیزها را امتحان کنید.
من در یک فصل از کتاب فنی بعدی خود که در Q3 2025 منتشر می شود ، درباره حافظه هسته بیشتر می نویسم ، و من به دنبال تجدید نظر در راه حل استاد دیجیتال Dungeon Master برای استفاده از حافظه هسته / ادغام هسته معنایی هستم. من همچنین می توانم برخی از روشهای بسیار واقعی را ببینم که حافظه هسته می تواند به ارائه برخی از مشتریان پیشرو و آینده نگر Edje ارزش ، قابلیت ها و صرفه جویی در هزینه کمک کند ، بنابراین من هیجان زده ام که این فناوری را با جامعه فنی گسترده تر به اشتراک بگذارم.
زمان بسیار خوبی برای انجام AI و ML در .NET است و من انتخاب شده ام که حافظه هسته را به عنوان ابزاری در جعبه ابزار خود داشته باشم.