This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Comment analyser les grands fichiers CSV avec des LLM locaux en C#
Thursday, 18 December 2025
Série: LLMs locaux pour les données - Partie 1 de 2
C’est là l’erreur que tout le monde fait, c’est ici qu’ils tentent d’alimenter leur CSV dans un LLM. Les LLM devraient générer des demandes, ne consomment pas de données.
Vous ' avez un fichier CSV de 500MB et vous voulez demander MSC2 Quelle est la valeur moyenne d'ordonnance par région? Copilote dans Excel peut faire cela, mais que faire si vos données sont trop sensibles pour les services de nuage? Que faire si vous devez les construire vous-mêmeM SK2
Cet article vous montre comment - localement , privéementM SK2 dans C#.
Utiliser DuckDB pour interroger directement les fichiers CSV. Utiliser un LLM local pour générer l’ SQL. Le LLM ne voit jamais vos données M SK2 simplement le schéma . RésultatMSC4 sous-référenceMST5 ms de demandes sur un million MST6 fichiers en ligneM ST7 complètement hors connexionM st8
Pour un traitement complémentaire , plus CLI - axé sur l'utilisation de profils statistiques comme interface LLM ( et montre un outil complet pour la mise en œuvre de ces idées M- profilage m, mode SQL sécuritaire МSK5 clonage synthétique et détection des dérives P), voir l'article conjoint DataSummarizer: Profilage rapide des données locales - en particulier la section "La mise à niveau cléM SK2 Statistiques comme interface". Ces deux articles forment une courte série sur le LLM local pratique.
L'incertitude fondamentale
Utiliser un LLM comme entrepôt de données est une abstraction erronée. Les LLM sont fondamentalement incapables d’analyser des millions de lignes pour calculer une moyenne M SK1 que' n’est pas ce qu’ils 're pourMSC4 Même une fenêtre contextuelle de token 200K se prête peut-être à |50,000 rowsMST7 Votre ♫500MB CSV a des millionsMSL9
Le modèle correct: Motifs de LLM, Computes de base de données.
flowchart LR
A[User Question] --> B[LLM]
B --> C[SQL Query]
C --> D[DuckDB]
D --> E[Results]
style B stroke:#333,stroke-width:4px
style D stroke:#333,stroke-width:4px
Veuillez noter ce qui se passe' : le LLM génère une demande SQL fondée sur votre question et le schéma. DuckDB l'execute contre les données réellesM SK3 Le LLM ne touche jamais vos données MSC4 il ne voit que les noms de colonnes et les typesMST5 C'est la raison pour laquelle c'est rapideMSL6 MST7 privéM ST8 et exacteM st9
Pour en savoir plus sur le traitement des profils comme l'interface LLM (et un CLI concrète qui met en œuvre le profil-première présentationM SK2 SQL sécuritaire - Q-backedMST4AMSS5 registreMSST6 sessions backed et clonage synthétiqueMSM7 voir DataSummarizer: Profilage rapide des données locales.
Pourquoi ne pas simplement le charger dans la mémoire?
Les approches évidentes partagent tous le même défaut fatal.
CsvHelper / Cadres de données: Charger l'ensemble du fichier dans le RAM. Un 500MB CSV devient un MSC3GB d'objetsM SK4 Un file S5GBMSC6 OOM crashMST7
SQLite / PostgreSQL: Demande une étape d’importation lente (minutes pour les fichiers de grande taille
PandasAI: Il charge toujours tout dans la mémoire . Plus, exécuter LLMM SK3 le code arbitraire généré est un cauchemar de sécurité.
Pourquoi DuckDB
DuckDB est différent. Il demande des fichiers CSV Directement - aucune étape d'importation , aucun chargement dans la mémoire:
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();
using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT Region, SUM(Amount) FROM 'sales.csv' GROUP BY Region";
// Executes directly against the file - no import, no memory explosion
La caractéristique assassine: il traite les fichiers comme des tableaux. Envoyez-le à un CSVM SK1 Parquet , ou fichier JSON et demandez immédiatement. Pas de TABLEAU DE CRÉATION
| Facteur | CsvHelper | SQLite S | DuckDB M |
|---|---|---|---|
| Mémoire | Charge l'intégralité du fichier | Charge pendant l'importation | |
| Mise en place | Aucune | Système d’importation MSC2 Importations MSC3 Aucunes SMC4 | |
| 500MB fichier | ~2 RAM de GB MSC2 Minutes à importer SMC3 Instant SMC4 | ||
| 5GB fichier | OOM crash | Très lente | fonctionne bien S |
| Parquet | Non | Non |
DuckDB est ce que les ingénieurs de données utilisent dans Python pour exactement cette utilisation. .Bindings NET vous donner le plein ADO.Support NET - il se sent comme toute autre base de données , à l’exception de vousM SK3des fichiers de demandes de renseignements
The Stack
| Component | Pourquoi c'est-ce qui est le cas ? |
|---|---|
| DuckDB | Demandes de renseignements CSV directementM SK1 pas d'importation |
| DuckDB.NET | ADO complet.Support NETM SK2 se sent natif |
| Ollama | Inférence locale , pas de clés API |
| Bogus | Données d'essai réalistes à n'importe quelle échelle |
qwen2.5-coder:7b |
La meilleure précision SQL à la taille de 7B |
Note sur la sécurité: Nous ' exécutons LLM- SQL généréM SK3 Il s’agit d’un code plus sûr que le codage arbitraire Section de la sécurité pour les garanties. Pour une discussion plus large sur la transformation des profils dans l’interface LLM et un CLI qui applique ces modèles ,, voir le document complémentaire DataSummarizer: Profilage rapide des données locales.
Établissement du projet
Let's créer un projet d'échantillonnage . Installer les paquets NuGet:
dotnet add package DuckDB.NET.Data.Full
dotnet add package OllamaSharp
dotnet add package Bogus
Faire appel à un modèle de codage axé sur - qui soit bon dans SQL
ollama pull qwen2.5-coder:7b
L'architecture
Voici' comment les pièces s’intègrent ensemble:
flowchart TB
subgraph Input
Q[User Question]
CSV[CSV File]
end
subgraph Processing
Schema[Extract Schema]
Sample[Get Sample Rows]
Context[Build LLM Context]
LLM[Generate SQL]
Validate[Validate SQL]
Execute[Execute Query]
end
subgraph Output
Results[Query Results]
end
CSV --> Schema
CSV --> Sample
Schema --> Context
Sample --> Context
Q --> Context
Context --> LLM
LLM --> Validate
Validate -->|Error| LLM
Validate -->|OK| Execute
CSV --> Execute
Execute --> Results
style LLM stroke:#333,stroke-width:4px
style Execute stroke:#333,stroke-width:4px
L’influence clé que nous avons apportée à la LLM, c’est le :. schéma et données d'échantillonnage, non les données réellesM SK1 Cela maintient le contexte petit et les réponses rapides .
Pourquoi cela est important?: Le LLM génère l'intention (SQLM SK2 DuckDB l'execute. La étape de validation saisit les erreurs de syntaxe avant l'exécutionMSC4 La boucle d'essai remédie aux erreurs occasionnellesMNK5 Cette séparation est ce qui rend le système à la fois sûr et précisMRK6 Pour un aperçu plus détailléMMK7 CLI-\Reférence centrée |(\y compris le profil\MNK10\premier exposé et limites de sécurité d'exécution SQL\MGK11\ voir DataSummarizer: Profilage rapide des données locales.
Étape 1: Gérer des données d'essai avec Bogus
Vous avez déjà des données CSV? Passer à Étape 2: Construire le contexte du schéma.
Avant que nous puissions tester notre LLM-analyseur CSV à moteur, nous avons besoin de données pour analyserM SK2 Pour le développement et la mise à l’essai , les données synthétiques battent les données réellesMSC4
- Évaluation à l'échelle - Générer des rangées 100KM SK2 | | 3 | 4 | ou | 5 | pour vérifier la performance à différentes tailles
- Protection des renseignements personnels - Il n'y a pas de risque d'exposer des données commerciales sur les clients réels / dans des démonstrations ou des screenshots
- Reproductibilité - Le même graine = les mêmes donnéesM SK2 rendant les bogues reproduisables
- Cases à bord - Contrôle de la distribution eM SK2g., force
Qu'est-ce que Bogus?
Bogus est un port .NET du faker populaireM SK1js library . Il produit des données réalistes-apparentement fausses |- noms=, adressesMSSK6 courriels+, dates*, numéros - avec le soutien local approprié | . Au lieu d'utiliser la main à l'essai de fichiers CSV ou en utilisant les données de déchets aléatoires | aperçus Réel:
f.Name.FullName()→ "John SmithM SK2 ≥(nonf.Internet.Email()→ "johnMSC2smith@gmailM SK4comMST5 |f.Date.Between(start, end)→ Répartition réaliste des datesf.Commerce.ProductName()→
Cela est important parce que les données réalistes vous aident à repérer des problèmes - formats étranges , agrégations inattendues M SK2 cas de bord dans la manipulation des dates
Définir le modèle de données
internal class SaleRecord
{
public string OrderId { get; set; } = "";
public DateTime OrderDate { get; set; }
public string CustomerId { get; set; } = "";
public string CustomerName { get; set; } = "";
public string Region { get; set; } = "";
public string Category { get; set; } = "";
public string ProductName { get; set; } = "";
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Discount { get; set; }
public bool IsReturned { get; set; }
}
Configurer le Faker
Bogus utilise une API fluide pour définir les règles de génération:
var categories = new[] { "Electronics", "Clothing", "Home & Garden", "Sports", "Books" };
var regions = new[] { "North", "South", "East", "West", "Central" };
var faker = new Faker<SaleRecord>()
.RuleFor(s => s.OrderId, f => f.Random.Guid().ToString()[..8].ToUpper())
.RuleFor(s => s.OrderDate, f => f.Date.Between(
new DateTime(2022, 1, 1),
new DateTime(2024, 12, 31)))
.RuleFor(s => s.CustomerId, f => $"CUST-{f.Random.Number(10000, 99999)}")
.RuleFor(s => s.CustomerName, f => f.Name.FullName())
.RuleFor(s => s.Region, f => f.PickRandom(regions))
.RuleFor(s => s.Category, f => f.PickRandom(categories))
.RuleFor(s => s.ProductName, (f, s) => GenerateProductName(f, s.Category))
.RuleFor(s => s.Quantity, f => f.Random.Number(1, 20))
.RuleFor(s => s.UnitPrice, f => f.Random.Decimal(9.99m, 299.99m))
.RuleFor(s => s.Discount, f => f.Random.Bool(0.3f) ? f.Random.Decimal(0.05m, 0.25m) : 0m)
.RuleFor(s => s.IsReturned, f => f.Random.Bool(0.05f));
Qu’on détermine ce qui se passe.
f(FakerM SK1 - Instance génératrice avec accès à tous les modules de données NomM SK2 Date, Aléatoiref.Random.Guid().ToString()[..8]- Gérer un GUID mais ne prendre que les premières chars 8 pour une ID d'ordre lisiblef.Date.Between()- Date aléatoire dans une plage réaliste (non année 9999)f.PickRandom(array)- Choisissez au hasard parmi les options définies précédemment.f.Random.Bool(0.3f)- 30% chance d’obtenir un rabais sur les commandes(f, s)syntaxe - Accès à la fois faker ET partiellement -enregistrement bâti. Ce qui permetProductNamede dépendreCategory
L'article 5 de la Loi sur l'immigration et le statut des réfugiés (f, s) Cette cohérence rend les données générées beaucoup plus réalistes pour tester des agrégats comme :
Générer et écrire en CSV
var records = faker.Generate(100_000); // Adjust for your testing needs
await using var writer = new StreamWriter(csvPath, false, Encoding.UTF8);
await writer.WriteLineAsync("OrderId,OrderDate,CustomerId,CustomerName,Region,Category,...");
foreach (var record in records)
{
var total = record.Quantity * record.UnitPrice * (1 - record.Discount);
await writer.WriteLineAsync($"{record.OrderId},{record.OrderDate:yyyy-MM-dd},...");
}
100K rows génére environ 15MB de CSV
Conseils: Set
Randomizer.Seed = new Random(12345)avant de produire des données reproductibles. Same seed = same " randomM SK3 records every timeMSC4 which is invaluable for debuggingMNK5
Étape 2: Construire le contexte du schéma
Avant que le LLM puisse générer SQL, il faut comprendre la structure des données.
Le modèle de contexte
public class DataContext
{
public string CsvPath { get; set; } = "";
public List<ColumnInfo> Columns { get; set; } = new();
public List<Dictionary<string, string>> SampleRows { get; set; } = new();
public long RowCount { get; set; }
}
public class ColumnInfo
{
public string Name { get; set; } = "";
public string Type { get; set; } = ""; // VARCHAR, DOUBLE, TIMESTAMP, etc.
}
Cela permet de saisir tout ce dont le LLM a besoin: noms de colonnes , typesM SK2 et quelques rangées d’échantillon pour comprendre le format des données.
Extraction du schéma
DuckDB peut décrire n'importe quel CSV sans le charger tout:
private DataContext BuildContext(DuckDBConnection connection, string csvPath)
{
var context = new DataContext { CsvPath = csvPath };
// Get schema - DuckDB infers types from the CSV
using var cmd = connection.CreateCommand();
cmd.CommandText = $"DESCRIBE SELECT * FROM '{csvPath}'";
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
context.Columns.Add(new ColumnInfo
{
Name = reader.GetString(0), // Column name
Type = reader.GetString(1) // Inferred type
});
}
return context;
}
L'article 5 de la Loi sur l'immigration et le statut des réfugiés DESCRIBE la commande ne lit que le titre du fichier plus quelques lignes pour l'inférence de type - it' s instantanée même sur des fichiers énormes .
Obtenir des données d'échantillonnage
Les lignes d'échantillonnage aident le LLM à comprendre les formats de données (datesM SK1IDs , etc.):
using var cmd = connection.CreateCommand();
cmd.CommandText = $"SELECT * FROM '{csvPath}' LIMIT 3";
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
var row = new Dictionary<string, string>();
for (int i = 0; i < reader.FieldCount; i++)
{
var value = reader.IsDBNull(i) ? "NULL" : reader.GetValue(i)?.ToString() ?? "";
row[reader.GetName(i)] = value;
}
context.SampleRows.Add(row);
}
Trois rangées sont habituellement suffisantes - il montre au LLM les formats à attendre sans perdre des tokens.
Étape 3: Gérer SQL avec le LLM
C'est la partie difficile. L’ingénierie rapide ici n’est pas - négociable - sans règles strictesM SK2 les LLM locaux produisent des SQL créatifs mais déformés. l’objectif est le determinismeMST4 non la créativitéMSS5
Établissement de la promesse
private string BuildPrompt(DataContext context, string question, string? previousError)
{
var sb = new StringBuilder();
sb.AppendLine("You are a SQL expert. Generate a DuckDB SQL query to answer the user's question.");
sb.AppendLine();
sb.AppendLine("IMPORTANT RULES:");
sb.AppendLine("1. The table is accessed directly from the CSV file path");
sb.AppendLine("2. Use single quotes around the file path in FROM clause");
sb.AppendLine("3. DuckDB syntax - use LIMIT not TOP, use || for string concat");
sb.AppendLine("4. Return ONLY the SQL query, no explanation, no markdown");
sb.AppendLine();
sb.AppendLine($"CSV File: '{context.CsvPath}'");
sb.AppendLine($"Row Count: {context.RowCount:N0}");
sb.AppendLine();
// Schema
sb.AppendLine("Schema:");
foreach (var col in context.Columns)
{
sb.AppendLine($" - {col.Name}: {col.Type}");
}
La section des règles est cruciale - elle indique au LLM exactement comment formater la demande pour DuckDB. Être explicite quant à la syntaxe (LIMIT vs TOPMSC3 concatenation de chaînesM SK4 empêche les erreurs courantes
Ajouter des données d'échantillonnage
if (context.SampleRows.Count > 0)
{
sb.AppendLine();
sb.AppendLine("Sample data (first 3 rows):");
foreach (var row in context.SampleRows)
{
var values = row.Select(kv => $"{kv.Key}='{kv.Value}'");
sb.AppendLine($" {{{string.Join(", ", values)}}}");
}
}
Récupération d'une erreur
Si une tentative antérieure a échoué, inclure l'erreur
if (previousError != null)
{
sb.AppendLine();
sb.AppendLine("YOUR PREVIOUS QUERY HAD AN ERROR:");
sb.AppendLine(previousError);
sb.AppendLine("Please fix the query based on this error.");
}
sb.AppendLine();
sb.AppendLine($"Question: {question}");
sb.AppendLine();
sb.AppendLine("SQL Query (no markdown, no explanation):");
return sb.ToString();
}
Ce mécanisme de réessai est important - les LLM locaux font parfois des erreurs de syntaxe , et en leur donnant l’erreur, ils le corrigent habituellement lors du deuxième essai.
En appelant le LLM
var request = new GenerateRequest { Model = _model, Prompt = prompt };
var response = await _ollama.GenerateAsync(request).StreamToEndAsync();
var sql = CleanSqlResponse(response?.Response ?? "");
L'article 5 de la Loi sur l'immigration et le statut des réfugiés StreamToEndAsync() waits for the complete response. For a better UX, you could stream tokens as they arrive
Nettoyage de la réponse
Les LLM enveloppent souvent SQL dans des blocs de code de marquage en dépit d’être informés de ne pas le faire:
private string CleanSqlResponse(string response)
{
var sql = response.Trim();
// Remove markdown code blocks if present
if (sql.StartsWith("```"))
{
var lines = sql.Split('\n').ToList();
lines.RemoveAt(0); // Remove opening ```sql
if (lines.Count > 0 && lines[^1].Trim().StartsWith("```"))
{
lines.RemoveAt(lines.Count - 1); // Remove closing ```
}
sql = string.Join('\n', lines);
}
return sql.Trim('`', ' ', '\n', '\r');
}
Étape 4: Valider avant l'exécution
DuckDB's EXPLAIN nous permet de vérifier la syntaxe SQL sans faire passer la demande:
private string? ValidateSql(DuckDBConnection connection, string sql)
{
try
{
using var cmd = connection.CreateCommand();
cmd.CommandText = $"EXPLAIN {sql}";
cmd.ExecuteNonQuery();
return null; // Valid
}
catch (Exception ex)
{
return ex.Message;
}
}
Si la validation n'est pas effectuée, nous retournons l'erreur au LLM et tenons à nouveau ( jusqu'à un seuil
Étape 5: Exécuter et formater les résultats
Finalement, effectuer la recherche et formater le résultat:
private QueryResult ExecuteQuery(DuckDBConnection connection, string sql)
{
var result = new QueryResult { Sql = sql };
try
{
using var cmd = connection.CreateCommand();
cmd.CommandText = sql;
using var reader = cmd.ExecuteReader();
// Capture column names
for (int i = 0; i < reader.FieldCount; i++)
{
result.Columns.Add(reader.GetName(i));
}
// Capture rows
while (reader.Read())
{
var row = new List<object?>();
for (int i = 0; i < reader.FieldCount; i++)
{
row.Add(reader.IsDBNull(i) ? null : reader.GetValue(i));
}
result.Rows.Add(row);
}
result.Success = true;
}
catch (Exception ex)
{
result.Success = false;
result.Error = ex.Message;
}
return result;
}
L'article 5 de la Loi sur l'immigration et le statut des réfugiés QueryResult class ( montré en entier dans le projet d’échantillonnage ToString() méthode qui forme les résultats comme une table lisible.
Ajouter le contexte de la conversation
Pour l’analyse interactive, les utilisateurs souhaitent souvent poser des questions à la suite
"What's the total revenue?"
→ "Break that down by region"
→ "Show the top 5 regions"
Les deuxième et troisième questions n’ont de sens que dans le contexte du premier questionnaire.
Suivi de l'historique des conversations
public class ConversationTurn
{
public string Question { get; set; } = "";
public string Sql { get; set; } = "";
public bool Success { get; set; }
public int RowCount { get; set; }
public string Summary { get; set; } = ""; // "Single value: 1234567.89"
}
Incluant l'historique dans les prompts
if (_history.Count > 0)
{
sb.AppendLine();
sb.AppendLine("CONVERSATION HISTORY (for context):");
foreach (var turn in _history.TakeLast(5)) // Last 5 turns
{
sb.AppendLine($"Q: {turn.Question}");
sb.AppendLine($"SQL: {turn.Sql}");
if (turn.Success)
{
sb.AppendLine($"Result: {turn.Summary}");
}
sb.AppendLine();
}
}
L’historique permet au contexte de l’ALM de comprendre des références comme : "qu’M SK1 "ceux résultats", ou "la débrouiller plus loin
Quel modèle utiliser?
Pour la génération de SQL, codage-les modèles ciblés fonctionnent le mieux . Voici les options disponibles par Ollama's modèle de bibliothèque:
| Modèle MSC1 Taille MSC2 Accès rapide SMC3 Qualité MMC4 Lien RMC5 | ||
|---|---|---|
qwen2.5-coder:7b |
MSC1GB MSC2 rapide | Excellent SMC4 Ollama |
deepseek-coder-v2:16b |
9GB MSC2 Moyenne MSC3 Meilleure SMC4 Ollama | |
codellama:7b |
MSC1GB MSC2 Fast SMC3 Bon SMC4 Ollama | |
llama3.2:3b |
MSC1GB MSC2 Très rapide SMC3 Acceptable SMC4 Ollama |
Pour la plupart des cas d'utilisation, qwen2.5-coder:7b , fonctionne sur un matériel modeste (8GBM SK4 RAM).
Rendement
Real-Marches de référence mondiales
Essai sur une row CSV de 100K (14MB) sur un ordinateur standard dev | (Ryzen |5, | NVMe SSD |
| Type de demande | Temps |
|---|---|
| Compte simple | 65ms S |
| GROUPE PAR avec SUM | 58-68ms M |
| Aggregation complexe avec FILTER | 63ms |
| Multi-table GROUPE PAR avec HAVING | 71ms S |
Sub-100ms pour les demandes analytiques sur M SK1K rows - sans aucune étape d'importation. La complexité des demandes est plus importante que le nombre de lignesMSC4 DuckDBMNK5le moteur à colonnes permet de gérer efficacement l'agrégation indépendamment de la taille du fichier
Convertir de grands fichiers en parquet
Pour les fichiers au-dessus de 1GB, Format du parquet est 10-100x plus rapideM SK1
using var cmd = connection.CreateCommand();
cmd.CommandText = $"COPY (SELECT * FROM '{csvPath}') TO '{parquetPath}' (FORMAT PARQUET)";
cmd.ExecuteNonQuery();
Le fichier de parquet comprimé est également beaucoup plus petit.
Considérations en matière de sécurité
En exécutant LLM-générer SQL:
private bool IsSafeQuery(string sql)
{
var dangerous = new[] { "DROP", "DELETE", "TRUNCATE", "UPDATE", "INSERT", "ALTER", "CREATE" };
var upperSql = sql.ToUpperInvariant();
return !dangerous.Any(d => upperSql.Contains(d));
}
DuckDB's dans le mode de mémoire- offre également une isolation naturelle.
Exemple complète
Voici comment cela allègue-t-il ?
// Generate test data
await GenerateSalesCsvAsync("sales.csv", 100_000);
// Simple query
using var service = new CsvQueryService("qwen2.5-coder:7b", verbose: true);
var result = await service.QueryAsync("sales.csv", "What are total sales by region?");
Console.WriteLine(result);
// Conversational analysis
using var analyser = new ConversationalCsvAnalyser("sales.csv", "qwen2.5-coder:7b");
Console.WriteLine(await analyser.AskAsync("What's the total revenue?"));
Console.WriteLine(await analyser.AskAsync("Break that down by category"));
Console.WriteLine(await analyser.AskAsync("Which category has the most returns?"));
Résumé
Le modèle mental à maintenir: LLMs raison; calcul des bases de données.
Donn't feed data to the LLMM SK1 Feed it schema, let it generate SQL , execute that SQL against a proper query engineMSC4 Cette séparation est la raison pour laquelle l’approche fonctionne à grande échelle
La mise en œuvre:
- DuckDB demandes CSV directement - pas d'importation, flux de disque
- Échantillons du schéma + donner au LLM suffisamment de contexte sans exposer les données
- Règles strictes de prompt force deterministic SQL, non prose créative
- Validation via EXPLAIN saisit les erreurs avant l'exécution
- Essayer de nouveau avec un retour d'information sur les erreurs gère le feuillet de syntaxe occasionnel
Résultat: sous--100ms de demandes analytiques sur un million de fichiers de rangéeM SK2 files en ligne, complètement hors ligne , avec des données qui n'abandonnent jamais votre machineMSC5
L'échantillon complet du projet est disponible à : Mostlylucid.CsvLlm - inclut CsvQueryService, ConversationalCsvAnalyser, et Bogus-génération de données fondée sur la .
Ressources
DuckDB
- Documentation DuckDB - Référence complète
- Importation du CSV DuckDB - CSVM SK1caractéristiques spécifiques
- Référence SQL DuckDB - Différences de syntaxe SQL par rapport à d'autres bases de données
- DuckDB.NET GitHub - CM SK1 fixations
- DuckDB.NET NuGet - Paquet complet avec des binaires natifs
Ollama & LLMs
- Ollama - Durée de fonctionnement local du LLM
- Bibliothèque Ollama Model - Modèles disponibles
- OllamaSharp - C# bibliothèque client
- OllamaSharp NuGet
Production de données d'essai
- Bogus GitHub - Générateur de données fausses
- Bogus API Référence - Types de données disponibles
Solutions envisagées
- CsvHelper - Bibliothèque de partage CSV
- Microsoft.DataM SK1Analyse - Cadre de données pour .NET
- PandasAI - Python LLM + integration des pandas
Articles connexes
- DataSummarizer: Profilage rapide des données locales - Article complémentaire couvrant le profilage des données basé sur l’ILC