داخل الجزء الأول من سلسلة هذه المجموعةلقد قمنا بتغطية أساسيات الجيل المُعزز-الريتريفال-الجيل - ما هو، كيف يعمل، والتكنولوجيا الكامنة (الاختلاسات، قواعد البيانات المتجهة، LLM الداخلية). الآن حان الوقت لوضع هذه المعرفة موضع التطبيق. هذه المقالة تظهر لكم كيفية بناء أنظمة RAG الحقيقية مع العمل C# رمز، حل التحديات المشتركة، واستخدام التقنيات المتقدمة من البحوث الحديثة.
إذا لم تقرأ الجزء 1: المجموعة شرحتأنصح بالبدء هناك لفهم المفاهيم الأساسية:
هذه المادة تفترض أنك تفهم تلك الأساسيات وتركز على في التنفيذ والاستخدام والأنماط في العالم الحقيقي.
لقد قمت ببناء العديد من الميزات ذات القدرة RAG على هذه المدونة. اسمحوا لي أن أعرض لكم أمثلة ملموسة.
كل تدوينة يمكن أن تظهر "النقاط ذات الصلة" باستخدام التشابه الدلالي.
كيف يعمل:
لماذا هو أفضل من العلامات:
كود نصّي:
public async Task<List<SearchResult>> GetRelatedPostsAsync(
string currentPostSlug,
string language,
int limit = 5)
{
// Get the current post's embedding
var currentPost = await _vectorStore.GetByIdAsync(currentPostSlug);
if (currentPost == null)
return new List<SearchResult>();
// Find similar posts
var similarPosts = await _vectorStore.SearchAsync(
currentPost.Embedding,
limit: limit + 1, // +1 because result includes the current post
filter: new Filter
{
Must =
{
new Condition
{
Field = "language",
Match = new Match { Keyword = language }
}
},
MustNot =
{
new Condition
{
Field = "slug",
Match = new Match { Keyword = currentPostSlug }
}
}
}
);
return similarPosts.Take(limit).ToList();
}
صندوق البحث على هذه المدونة يستخدم أسلوب RAG للبحث الدلالي (على الرغم من أنه بدون جزء الجيل - إنه مجرد إسترجاع).
تجربة المستخدم:
التنفيذ: سأغطي بناء هذا في مقال قادم عن قواعد بيانات المتجهات.
أَبْني a نظام RAG كامل لمُسَاعَدَتي أَكْتبُ مواقعَ مدوناتِ جديدةِ.
حالة استخدام: عندما أبدأ بالكتابة عن "توثيق التوثيق إلى ASP.net conre" النظام:
مشروع خط أنابيب كامل المسار الكامل:
public async Task<WritingAssistanceResponse> GetSuggestionsAsync(
string currentDraft,
string topic)
{
// 1. Embed the current draft
var draftEmbedding = await _embeddingService.GenerateEmbeddingAsync(
currentDraft
);
// 2. Retrieve related past content
var relatedPosts = await _vectorStore.SearchAsync(
draftEmbedding,
limit: 5
);
// 3. Build context for LLM
var prompt = BuildWritingAssistancePrompt(
currentDraft,
topic,
relatedPosts
);
// 4. Generate suggestions using local LLM
var suggestions = await _llmService.GenerateAsync(prompt);
// 5. Extract and format citations
var response = ExtractCitations(suggestions, relatedPosts);
return response;
}
هذا هو RAG في العمل - الاسترجاع (البحث الشمسي) + التعزيز (سياق الإغلاق) + الجيل (اقتراحات LLM).
هذه هي التحديات التي واجهتها وكيفية حلها.
المشكلة: كيف تقسم الوثائق؟ صغيرة جدا = فقدان السياق. كبيرة جدا = معلومات غير ذات صلة.
الحل: القطع المُهَلَّك استناداً إلى هيكل الوثيقة.
public class SmartChunker
{
public List<Chunk> ChunkDocument(string markdown, string sourceId)
{
var chunks = new List<Chunk>();
// Parse markdown into sections
var document = Markdown.Parse(markdown);
var sections = ExtractSections(document);
foreach (var section in sections)
{
var wordCount = CountWords(section.Content);
if (wordCount < MinChunkSize)
{
// Merge small sections
MergeWithPrevious(chunks, section);
}
else if (wordCount > MaxChunkSize)
{
// Split large sections
var subChunks = SplitSection(section);
chunks.AddRange(subChunks);
}
else
{
// Just right
chunks.Add(CreateChunk(section, sourceId));
}
}
return chunks;
}
}
الممارسات الفضلى:
المشكلة: وقد لا تلتقط النماذج التضمينية العامة نماذج دلالات خاصة بكل مجال على حدة.
الحلول:
الخيار 1: الخيارات 1: المزدجات المجزأة (المستأنفة)
# Using sentence-transformers in Python
from sentence_transformers import SentenceTransformer, InputExample, losses
model = SentenceTransformer('all-MiniLM-L6-v2')
# Create training examples from your domain
train_examples = [
InputExample(texts=['Docker Compose', 'container orchestration'], label=0.9),
InputExample(texts=['Entity Framework', 'ORM database'], label=0.9),
InputExample(texts=['Docker', 'apple fruit'], label=0.1)
]
# Fine-tune
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)
train_loss = losses.CosineSimilarityLoss(model)
model.fit(train_objectives=[(train_dataloader, train_loss)], epochs=1)
الخيار 2: المزجات (نماذج متعددة Combine)
public async Task<float[]> GenerateHybridEmbeddingAsync(string text)
{
var semantic = await _semanticModel.GenerateEmbeddingAsync(text);
var keyword = await _keywordModel.GenerateEmbeddingAsync(text);
// Concatenate or weighted average
return CombineEmbeddings(semantic, keyword);
}
الخيار 3: إضافة تجزئة
var results = await _vectorStore.SearchAsync(
queryEmbedding,
limit: 10,
filter: new Filter
{
Must =
{
new Condition { Field = "category", Match = new Match { Keyword = "ASP.NET" } },
new Condition { Field = "date", Range = new Range { Gte = "2024-01-01" } }
}
}
);
المشكلة: LLMs لها حدود رمزية. كيف يمكنك أن تناسب الاستعلام في النافذة؟
الحل: (ج) اختيار السياقات الدينامية وتلخيصها.
public string BuildContextAwarePrompt(
string query,
List<SearchResult> retrievedDocs,
int maxTokens = 4096)
{
var promptTemplate = GetPromptTemplate();
var queryTokens = CountTokens(query);
var templateTokens = CountTokens(promptTemplate);
// Reserve tokens for: prompt + query + response
var availableForContext = maxTokens - queryTokens - templateTokens - 500; // 500 for response
// Add context until we hit limit
var selectedContext = new List<SearchResult>();
var currentTokens = 0;
foreach (var doc in retrievedDocs.OrderByDescending(d => d.Score))
{
var docTokens = CountTokens(doc.Text);
if (currentTokens + docTokens <= availableForContext)
{
selectedContext.Add(doc);
currentTokens += docTokens;
}
else
{
// Try summarizing the doc if it's important
if (doc.Score > 0.85)
{
var summary = await SummarizeAsync(doc.Text, maxTokens: 200);
var summaryTokens = CountTokens(summary);
if (currentTokens + summaryTokens <= availableForContext)
{
selectedContext.Add(new SearchResult
{
Text = summary,
Title = doc.Title,
Score = doc.Score
});
currentTokens += summaryTokens;
}
}
}
}
return FormatPrompt(query, selectedContext);
}
المشكلة: وحتى مع السياق، فإن LLLS في بعض الأحيان تجاهله والهلوسة.
الحلول:
1 - هندسية السرعة:
var systemPrompt = @"
You are a technical assistant.
CRITICAL RULES:
1. ONLY use information from the provided CONTEXT sections
2. If the context doesn't contain the answer, say 'I don't have enough information in the provided context to answer that'
3. DO NOT use your training data to supplement answers
4. Always cite the source using [1], [2] notation
5. If you're unsure, say so
CONTEXT:
{context}
QUESTION: {query}
ANSWER (following all rules above):
";
2 - المصادقة على مرحلة ما بعد التوليد:
public async Task<bool> ValidateResponseAgainstContext(
string response,
List<SearchResult> context)
{
// Check if response contains claims not in context
var responseSentences = SplitIntoSentences(response);
foreach (var sentence in responseSentences)
{
var isSupported = await IsClaimSupportedByContext(sentence, context);
if (!isSupported)
{
_logger.LogWarning("Hallucination detected: {Sentence}", sentence);
return false;
}
}
return true;
}
3 - الصقل الإضافي:
public async Task<string> GenerateWithValidationAsync(
string query,
List<SearchResult> context,
int maxAttempts = 3)
{
for (int attempt = 0; attempt < maxAttempts; attempt++)
{
var response = await _llm.GenerateAsync(
BuildPrompt(query, context)
);
var isValid = await ValidateResponseAgainstContext(response, context);
if (isValid)
return response;
// Refine prompt for next attempt
query = $"{query}\n\nPrevious attempt hallucinated. Stick strictly to the context.";
}
return "I couldn't generate a reliable answer. Please rephrase your question.";
}
المشكلة: بينما تضيف مستندات جديدة، فإن قاعدة بيانات المتجه يجب أن تبقى الحالية.
الحل: خط أنبوب فهرس آلي.
public class BlogIndexingBackgroundService : BackgroundService
{
private readonly IVectorStoreService _vectorStore;
private readonly IMarkdownService _markdownService;
private readonly ILogger<BlogIndexingBackgroundService> _logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await IndexNewPostsAsync(stoppingToken);
// Check for updates every hour
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in indexing service");
}
}
}
private async Task IndexNewPostsAsync(CancellationToken ct)
{
var allPosts = await _markdownService.GetAllPostsAsync();
foreach (var post in allPosts)
{
var existingDoc = await _vectorStore.GetByIdAsync(post.Slug);
// Check if content changed
var currentHash = ComputeHash(post.Content);
if (existingDoc == null || existingDoc.ContentHash != currentHash)
{
_logger.LogInformation("Indexing updated post: {Title}", post.Title);
var chunks = _chunker.ChunkDocument(post.Content, post.Slug);
foreach (var chunk in chunks)
{
var embedding = await _embeddingService.GenerateEmbeddingAsync(chunk.Text);
await _vectorStore.UpsertAsync(
id: $"{post.Slug}_{chunk.Index}",
embedding: embedding,
metadata: new Dictionary<string, object>
{
["slug"] = post.Slug,
["title"] = post.Title,
["chunk_index"] = chunk.Index,
["content_hash"] = currentHash
},
ct: ct
);
}
}
}
}
}
دعونا نستكشف أحدث تقنيات RAG من البحوث الحديثة.
المشكلة: وغالباً ما تكون استفسارات المستعملين قصيرة وغير مكتملة التكوين، وشرائح الوثائق مفصلة ومكتوبة بشكل جيد، وهذا عدم التوافق يضر بالاسترجاع.
الحل: إعداد وثيقة افتراضية مثالية التي من شأنها أن تجيب على السؤال، غرس ذلك، ثم البحث.
public async Task<List<SearchResult>> HyDESearchAsync(string query)
{
// Generate hypothetical answer (even if hallucinated)
var hypotheticalAnswer = await _llm.GenerateAsync($@"
Write a detailed, technical paragraph that would perfectly answer this question:
Question: {query}
Paragraph:"
);
// Embed the hypothetical answer
var embedding = await _embeddingService.GenerateEmbeddingAsync(
hypotheticalAnswer
);
// Search using this embedding
return await _vectorStore.SearchAsync(embedding);
}
سبب عمله: وتستخدم الإجابة الافتراضية لغة وهيكلا مماثلين للوثائق الفعلية، مما يحسن الاسترجاع.
المشكلة: وغالباً ما تخلط استفسارات المستعملين بين البحث الدلالي وتنقيحات البيانات الفوقية.
مثال: "الوظائـف الثابتـة عـن Doker" = semanttte (""Doker") + مرشح (التاريخ > 2024-01-01)
الحل: استخدم LLLM لشرح الإستفسار إلى المرشّحات semantic + data.
public async Task<SearchQuery> ParseSelfQueryAsync(string naturalLanguageQuery)
{
var parsingPrompt = $@"
Parse this search query into:
1. Semantic search query (what the user is looking for)
2. Metadata filters (category, date range, etc.)
User Query: {naturalLanguageQuery}
Output JSON:
{{
""semantic_query"": ""the core concept"",
""filters"": {{
""category"": ""...",
""date_after"": ""..."",
""date_before"": ""...""
}}
}}
";
var jsonResponse = await _llm.GenerateAsync(parsingPrompt);
var parsed = JsonSerializer.Deserialize<SearchQuery>(jsonResponse);
return parsed;
}
// Use parsed query
var parsedQuery = await ParseSelfQueryAsync("Recent ASP.NET posts about authentication");
// semantic_query: "authentication"
// filters: { category: "ASP.NET", date_after: "2024-01-01" }
var results = await _vectorStore.SearchAsync(
embedding: await _embeddingService.GenerateEmbeddingAsync(parsedQuery.SemanticQuery),
filter: BuildFilter(parsedQuery.Filters)
);
المشكلة: وقد يغفل استفسار واحد عن الوثائق ذات الصلة بسبب الصياغة.
الحل: اوجد تغييرات متعددة للاستفسار، ابحث مع الكل، اجمع النتائج.
public async Task<List<SearchResult>> MultiQuerySearchAsync(string query)
{
// Generate query variations
var variations = await _llm.GenerateAsync($@"
Generate 3 different ways to phrase this search query:
Original: {query}
Variations (one per line):
");
var queries = variations.Split('\n', StringSplitOptions.RemoveEmptyEntries)
.Prepend(query) // Include original
.ToList();
// Search with all variations
var allResults = new List<SearchResult>();
foreach (var q in queries)
{
var embedding = await _embeddingService.GenerateEmbeddingAsync(q);
var results = await _vectorStore.SearchAsync(embedding, limit: 10);
allResults.AddRange(results);
}
// Deduplicate and merge scores
var merged = allResults
.GroupBy(r => r.Id)
.Select(g => new SearchResult
{
Id = g.Key,
Text = g.First().Text,
Title = g.First().Title,
Score = g.Max(r => r.Score) // Take best score
})
.OrderByDescending(r => r.Score)
.ToList();
return merged;
}
المشكلة: القطع المستردة تحتوي على معلومات غير ذات صلة ترسلها كلها كعربات نفايات
الحل: استخدم LLLM أصغر لضغط سياق الاسترجاع على الأجزاء ذات الصلة فقط.
public async Task<string> CompressContextAsync(
string query,
List<SearchResult> retrievedDocs)
{
var compressed = new List<string>();
foreach (var doc in retrievedDocs)
{
var compressionPrompt = $@"
Extract only the sentences from this document that are relevant to answering the question.
Question: {query}
Document:
{doc.Text}
Relevant excerpts (maintain original wording):
";
var relevantExcerpt = await _smallLLM.GenerateAsync(compressionPrompt);
if (!string.IsNullOrWhiteSpace(relevantExcerpt))
{
compressed.Add($"From '{doc.Title}':\n{relevantExcerpt}");
}
}
return string.Join("\n\n", compressed);
}
المشكلة: وتتطلب المسائل المعقدة معلومات من مصادر متعددة يلزم ربطها.
مثال: "ما هي قاعدة البيانات التي تستخدمها المدونات وكيف يتم تنفيذ البحث الدلالي؟"
الحل: الاسترجاع والتوليف.
public async Task<string> MultiHopRAGAsync(string complexQuery, int maxHops = 3)
{
var currentQuery = complexQuery;
var allContext = new List<SearchResult>();
for (int hop = 0; hop < maxHops; hop++)
{
// Retrieve for current query
var results = await SearchAsync(currentQuery, limit: 5);
allContext.AddRange(results);
// Check if we have enough information
var synthesisPrompt = $@"
Original question: {complexQuery}
Context so far:
{FormatContext(allContext)}
Can you answer the original question with this context?
If yes, provide the answer.
If no, what additional information do you need? (be specific)
";
var synthesis = await _llm.GenerateAsync(synthesisPrompt);
if (synthesis.Contains("yes", StringComparison.OrdinalIgnoreCase))
{
// We have enough information
return ExtractAnswer(synthesis);
}
// Extract what we need for next hop
currentQuery = ExtractNextQuery(synthesis);
}
// Final synthesis with all gathered context
return await GenerateFinalAnswerAsync(complexQuery, allContext);
}
المشكلة: كيف يمكنك بناء أنظمة الذكاء الاصطناعي التي تتذكر المحادثات من أشهر أو سنوات مضت؟ الدردشة التقليدية تفقد السياق بعد كل جلسة.
الحل: الجمع بين RAG مع التلخيص التدريجي لخلق ذاكرة مستمرة، قابلة للبحث.
هذا هو النهج المستخدم في الدالة DSSSSSSSS نظام متقدم أقوم ببناءه يستخدم ذاكرة سياقية قائمة على قاعدة RAG للحفاظ على تاريخ المحادثة المشترك إلى أجل غير مسمى.
السيناريو:
User (Today): "Remember George's specs?"
AI: "Yes, you discussed George's prescription requirements in our conversation
from 5 years ago (2019-03-15). He needed progressive lenses with..."
كيف يعمل:
flowchart TB
A[User Message] --> B[Store in RAG Memory]
B --> C[Extract Key Entities & Topics]
C --> D[Link to Past Conversations]
E[Periodic Summarization] --> F[Summarize Old Conversations]
F --> G[Store Summary with High-Level Tags]
G --> H[Keep Original for Retrieval]
I[Future Query: 'George's specs'] --> J[Semantic Search in RAG]
J --> K[Find: 2019 conversation]
K --> L[Retrieve Original Context]
L --> M[LLM generates response with 5-year-old context!]
style B stroke:#f9f,stroke-width:3px
style J stroke:#bbf,stroke-width:3px
نهج التنفيذ:
public class LongTermConversationalMemory
{
private readonly IVectorStoreService _vectorStore;
private readonly IEmbeddingService _embeddingService;
public async Task StoreConversationAsync(
string conversationId,
string userId,
List<ConversationTurn> turns,
DateTime timestamp)
{
// Extract key entities and topics
var entities = await ExtractEntitiesAsync(turns);
var topics = await ExtractTopicsAsync(turns);
// Create searchable representation
var conversationText = string.Join("\n", turns.Select(t =>
$"{t.Speaker}: {t.Message}"));
// Generate embedding
var embedding = await _embeddingService.GenerateEmbeddingAsync(
conversationText);
// Store in RAG with rich metadata
await _vectorStore.IndexDocumentAsync(
id: $"conv_{conversationId}",
embedding: embedding,
metadata: new Dictionary<string, object>
{
["user_id"] = userId,
["timestamp"] = timestamp.ToString("O"),
["entities"] = entities, // ["George", "specs", "prescription"]
["topics"] = topics, // ["healthcare", "eyewear"]
["full_text"] = conversationText,
["turn_count"] = turns.Count
}
);
}
public async Task<List<PastContext>> RetrieveRelevantPastAsync(
string currentQuery,
string userId,
int limit = 5)
{
// Embed the current query
var queryEmbedding = await _embeddingService.GenerateEmbeddingAsync(
currentQuery);
// Search past conversations
var results = await _vectorStore.SearchAsync(
queryEmbedding,
limit: limit,
filter: new Filter
{
Must =
{
new Condition { Field = "user_id", Match = new Match { Keyword = userId } }
}
}
);
return results.Select(r => new PastContext
{
ConversationId = r.Id,
Timestamp = DateTime.Parse(r.Metadata["timestamp"].ToString()),
Entities = (List<string>)r.Metadata["entities"],
FullText = r.Metadata["full_text"].ToString(),
Relevance = r.Score
}).ToList();
}
// Periodic summarization to keep memory manageable
public async Task SummarizeOldConversationsAsync(DateTime olderThan)
{
var oldConversations = await _vectorStore.FindByDateRangeAsync(
endDate: olderThan);
foreach (var conv in oldConversations)
{
// Generate summary using LLM
var summary = await _llm.GenerateAsync($@"
Summarize this conversation, preserving key facts and entities:
{conv.FullText}
Summary:");
// Update document with summary while keeping original
await _vectorStore.UpdateAsync(
id: conv.Id,
additionalMetadata: new Dictionary<string, object>
{
["summary"] = summary,
["summarized_at"] = DateTime.UtcNow.ToString("O")
}
);
}
}
}
لماذا هذا قوي:
مثال العالم الحقيقي من DISE:
يستخدم DISE هذا النهج لتذكر:
وهذا يخلق نظام الذكاء الاصطناعي الذي "يتعلم" حقاً من كل تفاعل ويبني ذاكرة مؤسسية، بدلاً من البدء من جديد في كل جلسة.
التحديات التي يلزم النظر فيها:
هذه التقنية تحول RAG من "ابحث في وثائقي" إلى "تذكر كل شيء ناقشناه من أي وقت مضى" -
(راج) ليس الجواب دائماً، إليك متى تتفاداه:
١ - مسائل المعارف العامة
2 - كتابة الكتابة الإبداعية
الاحتياجات من البيانات الآنية
4 - تعليل الموضوع
قواعد المعارف الصغيرة جدا
6 - عندما تتحكم في تدريب LLM
هل تريد بناء نظامك الخاص؟ هنا نهج الخطوة خطوة خطوة.
الهدف: الحصول على الاسترجاع الأساسي العمل مع لا LLLM.
// 1. Choose an embedding service (start with API for simplicity)
var openAI = new OpenAIClient(apiKey);
// 2. Embed a few test documents
var docs = new[]
{
"Docker is a containerization platform",
"Kubernetes orchestrates containers",
"Entity Framework is an ORM for .NET"
};
var embeddings = new List<float[]>();
foreach (var doc in docs)
{
var response = await openAI.GetEmbeddingsAsync(
new EmbeddingsOptions("text-embedding-3-small", new[] { doc })
);
embeddings.Add(response.Value.Data[0].Embedding.ToArray());
}
// 3. Implement basic search (in-memory for now)
var query = "container orchestration";
var queryEmbedding = await GetEmbeddingAsync(query);
var results = embeddings
.Select((emb, idx) => new
{
Text = docs[idx],
Score = CosineSimilarity(queryEmbedding, emb)
})
.OrderByDescending(r => r.Score)
.ToList();
// 4. Verify search works
foreach (var result in results)
{
Console.WriteLine($"{result.Score:F3}: {result.Text}");
}
// Expected: Kubernetes scores highest
الهدف: حدّد إلى حقيقي مستند مجموعات.
الخطوات المتخذة لتنفيذ ما يلي:
سأغطي هذا بالتفصيل في مقال قادم عن قواعد بيانات المتجهات.
الهدف: (أ) كامل خط أنابيب RAG.
// 1. Retrieve context
var context = await SearchAsync(query, limit: 3);
// 2. Build prompt
var prompt = $@"
Answer the question using this context:
{FormatContext(context)}
Question: {query}
Answer:";
// 3. Generate (start with API)
var response = await openAI.GetChatCompletionsAsync(new ChatCompletionsOptions
{
Messages =
{
new ChatMessage(ChatRole.System, "You are a helpful assistant."),
new ChatMessage(ChatRole.User, prompt)
},
Temperature = 0.7f,
MaxTokens = 500
});
return response.Value.Choices[0].Message.Content;
عندما تعمل الأساسيات، تنتقل إلى الاستدلال المحلي (سأغطي هذا في المقالات القادمة):
RAG (الجيل المسترجع - المدمج) هو تقنية قوية لجعل LLMs أكثر دقة وتحديثاً وموثوقية من خلال وضع ردودهم في وثائق فعلية. بدلاً من الاعتماد على بيانات التدريب الخاصة بالنموذج وحدها، أنظمة RAG:
الميزات الرئيسية للفريق الاستشاري:
وقت استخدام الرافعة:
الوقت الذي يتعين فيه تجنب الإسناد:
ويتطور هذا المجال بسرعة مع التقنيات المتقدمة مثل هايدي، والاسترجاع متعدد الماكيارات، والضغط السياقي، ولكن المفهوم الأساسي يظل بسيطا: إعطاء LLMs الوصول إلى المعلومات الصحيحة في الوقت المناسب.
بداية بسيطة، نتائج قياسية، وتكرار. RAG هي واحدة من أكثر الطرق العملية لبناء أنظمة الذكاء الفلكي الموثوقة اليوم.
الآن أنك الآن تفهم كل من الأساسيات (الجزء الأول) والتطبيقات العملية لRAG، في المقالات القادمة سأريكم كيفية بناء أنظمة كاملة وجاهزة للإنتاج RAG في C#:
ما يلي:
هذه المقالات سوف تأخذك من نظرية إلى ممارسة، مع قواعد العمل الكاملة، استراتيجيات الانتشار، والمثاليات في العالم الحقيقي على أساس تشغيل هذه الأنظمة في الإنتاج على هذه المدونة.
وابقوا متأهبين لأدلة التنفيذ العملية التي تحول معارف فريق البحث والتطوير هذه إلى نظم عاملة!
أولاً - معلومات أساسية:
الأدوات والأطر:
اقرأ المزيد:
بُنيّة مُباركة مُباركة مُباركة!
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.