Wie man große CSV-Dateien mit lokalen LLMs analysiert
Serie: Lokale LLMs für Daten
Hier ist der Fehler, den jeder macht..... sie versuchen ihren CSV in einen LLM... LLMs sollten Abfragen erzeugen., konsumieren keine Daten.
Sie haben eine CSV-Datei von 500,MB und möchten fragen, was ', den durchschnittlichen Bestellwert nach Region, ?", Werkzeuge wie Copilot in Excel kann dies tun, aber was, wenn Ihre Daten zu sensitiv für Cloud-Services sind.
Dieser Artikel zeigt Ihnen, wie Sie vor Ort, ,... privat, in C, #....
Verwenden Sie DuckDB, um CSV-Dateien direkt abzufragen.Verwenden Sie ein lokales LLM, um die SQL zu generieren.Das LLM sieht nie Ihre Daten.
Für eine komplementäre Behandlung mit dem LLM-Interface ( und zeigt ein vollständiges Tool zur Umsetzung dieser Ideen.-, Profiling - Sicherer SQL-Modus.,, synthetisches Klonen und Drift-Detektion, siehe den Begleitartikel :. DatenSummarizer-:-Schnelles Profilieren lokaler Daten Statistik als Schnittstelle Diese beiden Artikel bilden eine kurze Reihe über praktische lokale LLM.
Der Kern der Erkenntnis
Die Verwendung eines LLM als Datenspeicher ist die falsche Abstraktion..-LLMs sind grundsätzlich nicht in der Lage, Millionen von Zeilen zu scannen, um ein durchschnittliches - zu berechnen, dass ' nicht das ist, was sie für . verwenden. Sogar ein Token-Kontextfenster passt vielleicht ...50,000-Zeilen...
Das richtige Muster LLM-Gründe: Die Datenbank berechnet die .
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
Beachten Sie, was geschieht.: Das LLM generiert eine SQL-Abfrage basierend auf Ihrer Frage und das Schema.MS K2 , DuckDB führt es gegen die tatsächlichen Daten aus.. , Die LLM berührt nie Ihre Daten , - , sie sieht nur Spaltennamen und Typen ,. , Dies ist der Grund, warum es schnell , , private , , , und präzise ,.
Für mehr über die Behandlung von Profilen wie das LLM-Interface und ein Beton CLI, das Profil implementiert.- first narration.MSC2 safe SQL- backed QMSC5 registry.- supported sessions and synthetic cloning. DatenSummarizer-:-Schnelles Profilieren lokaler Daten.
Warum laden Sie es nicht einfach in den Speicher?
Die offensichtlichen Ansätze alle teilen die gleichen fatalen Fehler
CsvHelper DatenrahmenLade die gesamte Datei in RAM-.. Ein CSV von 500.MB wird zu einem OOM-Absturz von ..
SQLite - PostgreSQLBenötigt einen langsamen Import-Schritt.(Minuten für große Dateien. ),Benötigt Upfront-Schema-Definitionen und Datenbankmanagement Overhead.
**PandasAI**Immer noch lädt alles ins Gedächtnis..... Plus...,... das Ausführen von LLM, -... generiertem beliebigen Code ist ein Sicherheits-Albtraum.-. SQL ist deklarativ und sandboxfähig.MSC5. Python ist nicht...
Warum DuckDB
EnteDB Es fragt CSV-Dateien ab direkt Kein Importschritt, kein Laden in den Speicher
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
Das Killer-Feature es behandelt Dateien als TabellenPunktieren Sie es auf eine CSV- oder JSON-Datei und fragen Sie sofort nach..e Kein KREATE-TABLETTE,e kein Masseneinsatz.
| Der Faktor | , CsvHelper, SQLite, DuckDB, | , |
|---|---|---|
| Speicher Lädt die gesamte Datei ein.Ladungen während des Imports. | ||
| Einrichtung Nicht-MSK-Einfuhr | ||
| 500-MB-Datei Minuten zum Importieren von Sofort- | ||
| Datei 5 OOM-Absturz - sehr langsam | ||
| Parkett Keine | Kein | Ja schnellere ) Nein |
DuckDB ist, was Daten-Ingenieure in Python für genau diesen Anwendungsfall verwenden Bindungen an das .-NET geben Ihnen volle ADO-.-NET Unterstützung Es fühlt sich an wie jede andere Datenbank, außer you.'.re Dateien abfragen
Der Stapel
| -Komponente - Warum dieser eine Teil? |
|---|
| EnteDB Fragen CSV direkt - kein Importschritt |
| EnteDB-.-NET Volle Unterstützung von ADO-.®NET – ,® fühlt sich einheimisch an |
| Ollama Keine API-Tasten keine Cloud |
| Bogus Realistische Testdaten in jeder Skala |
qwen2.5-coder:7b Beste SQL-Genauigkeit bei der Größe 7B |
Hinweis zur SicherheitDies ist sicherer als beliebiger Code, erfordert aber trotzdem eine Validierung. Abschnitt Sicherheit Für eine breitere Diskussion über das Verwandeln von Profilen in die LLM-Schnittstelle und einen CLI, der diese Muster implementiert, siehe das Begleitstück DatenSummarizer-:-Schnelles Profilieren lokaler Daten.
Projekt einrichten
Lassen Sie 's ein Beispielprojekt erstellen Installieren Sie die NuGet-Pakete
dotnet add package DuckDB.NET.Data.Full
dotnet add package OllamaSharp
dotnet add package Bogus
Ziehen Sie ein codierendes Modell, das sich auf SQL-: ausrichtet
ollama pull qwen2.5-coder:7b
Die Architektur
Hier sind die Stücke, wie sie zusammenpassen.
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
Die wichtigsten Erkenntnisse, die wir dem LLM geben Schema- und StichprobendatenDies hält Kontext klein und antwortet schnell
Warum das so wichtig istDer Validierungsschritt fängt Syntaxfehler vor der Ausführung an Die Wiederholungsschleife behandelt den gelegentlichen Fehler Diese Trennung macht das System sowohl sicher als auch akkurate, für eine detailliertere, ,.CLI--.centered Referenz .(.inklusive Profil ?- first narration and safe SQL execution limits - ) vgl. DatenSummarizer-:-Schnelles Profilieren lokaler Daten.
Schritt Testdaten mit Bogus generieren
Sie haben bereits CSV-Daten.? Überspringen zu Schritt Erstellen Sie den Schema-Kontext.
Bevor wir unseren LLM-Analysator CSV testen können, benötigen wir Daten zum Analysieren von . Für die Entwicklung und das Testen synthetischer Daten schlägt reale Daten:
- Skalierungsprüfung Generieren Sie die Zeilen 100, ,, MKS4 oder 10, um die Leistung in verschiedenen Größen zu überprüfen.
- Privatsphäre Keine Gefahr der Entlarvung von realen Kunden . . / Geschäftsdaten in Demos oder Screenshots
- Reproduzierbarkeit Same seam .= . gleiche Daten machen Bugs reproduzierbar
- Kantenfälle Kontrollieren Sie die Verteilung (...g.,. force liefert die spezifischen Datumsbereiche von ).
Was ist Bogus-??
Bogus Es erzeugt realistische ,- aussehende gefälschte Daten ,- names , , adressen , , , E-Mails , , , dates , , , Zahlen , mit korrekter Unterstützung für die Lokalisierung , und zwar . , statt manuellen Tests CSV-Dateien oder Verwendung von zufälligen Mülldaten ., , Bogus gibt Ihnen Daten, die sieht aus real-:
f.Name.FullName()"John Smith2, nicht "asdf1234")f.Internet.Email()"[email protected]"uGenau formatiert)f.Date.Between(start, end)Realistische Datumsverteilungf.Commerce.ProductName()"Handgefertigte Granit-Käse " ( - , aber wiedererkennbar
Dies spielt eine Rolle, weil realistische Daten Ihnen helfen Probleme zu erkennen, die seltsame Formatierung...... unvorhergesehene Aggregationen.......... Kantenfälle im Datums-Handling...... dass zufällige Strings...
Definieren Sie das Datenmodell
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; }
}
Den Faker einrichten
Bogus verwendet eine fließende API, um Generierungsregeln zu definieren.
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));
Lassen Sie die 's nach unten brechen was geschieht
f(-Faker, )-Fake Die Generator-Instanz mit Zugriff auf alle Datenmodulef.Random.Guid().ToString()[..8]Generieren Sie eine GUID, aber nehmen Sie nur erste Zeichen für eine lesbare Bestell-ID.f.Date.Between()Zufälliges Datum innerhalb eines realistischen Bereichsf.PickRandom(array)Wählen Sie zufällig aus vordefinierten Optionen aus.f.Random.Bool(0.3f)Die Wahrscheinlichkeit der wahren (30%' der Aufträge erhalten einen Rabatt.(f, s)Syntax Zugriff sowohl auf gefälschte und die teilweise gebaute Record-.ProductNameabhängig vonCategory
Das (f, s) pattern is performant -- , es bedeutet, dass die erzeugten Daten wesentlich realistischer für das Testen von Aggregationen wie z.B. ," , Umsatz nach Kategorie , ". , sind.
Generieren und Schreiben an 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 Zeilen erzeugt ca. 15MB von CSV genug zum Testen mit ,, aber Sie können leicht auf Millionen skalieren Die Generation ist schnell (~2. Sekunden für 100.K Reihen ), weil Bogus für Massengeneration optimiert ist
TippEinstellen
Randomizer.Seed = new Random(12345)vor der Generierung reproduzierbare Daten zu erhalten.. , die gleiche Samen , = , gleiche , " ,random ," , Rekorde jedes Mal, wenn es unschätzbar für das Debugging ist.
Schritt Erstellen Sie den Schema-Kontext
Bevor das LLM SQL®,® erzeugen kann, muss es die Datenstruktur verstehen.
Das Kontextmodell
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.
}
Dies erfasst alles, was die LLM benötigt.:-Säulennamen...,-Typen... und ein paar Beispielzeilen, um das Datenformat zu verstehen.
Extraktion des Schemas
DuckDB kann jeden CSV beschreiben, ohne ihn alle zu laden.
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;
}
Das DESCRIBE Befehl liest nur die Datei-Header plus ein paar Zeilen für den Typ Inference
Erhalten von Beispieldaten
Beispielreihen helfen dem LLM, Datenformate zu verstehen
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);
}
Drei Reihen sind in der Regel genug, es zeigt die LLM, welche Formate zu erwarten, ohne Tokens zu verschwenden.
Schritt SQL mit dem LLM generieren
Dies ist der harte Teil. Das Prompt-Engineering hier ist nicht ,-'verhandelbar , ohne strenge Regeln , ,' lokale LLMs werden kreative aber gebrochen SQL , .' Das Ziel ist Determinismus , nicht Kreativität
Bau der Prompt
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}");
}
Der Abschnitt Regeln ist entscheidend -- , es sagt dem LLM genau, wie man die Abfrage für DuckDB , . , Da explizit über Syntax , ( , LIMIT vs TOP ,, , String-Verkettung , ) , verhindert häufige Fehler .
Hinzufügen von Beispieldaten
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)}}}");
}
}
Fehlerwiederherstellung
Wenn ein früherer Versuch fehlgeschlagen ist, schließen Sie den Fehler ein.
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();
}
Dieser Retry-Mechanismus ist wichtig. lokale LLMs machen manchmal Syntaxfehler.
Anrufen der LLM
var request = new GenerateRequest { Model = _model, Prompt = prompt };
var response = await _ollama.GenerateAsync(request).StreamToEndAsync();
var sql = CleanSqlResponse(response?.Response ?? "");
Das StreamToEndAsync() wartet auf die komplette Antwort für ein besseres UX-, streamen Sie Token, wie sie ankommen
Reinigung der Reaktion
LLMs oft wickeln SQL in Markdown Code-Blöcke, obwohl nicht gesagt wird, um
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');
}
Schritt vor der Ausführung bestätigen
EnteDB-' EXPLAIN lässt uns SQL-Syntax überprüfen, ohne die Abfrage zu starten.
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;
}
}
Wenn die Validierung fehlschlägt, füttern wir den Fehler zurück an das LLM und versuchen es erneut bis zu einem Limit.
Schritt Ergebnisse ausführen und formatieren
Schließlich führen Sie die Abfrage aus und formatieren die Ausgabe.
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;
}
Das QueryResult class Im Beispielprojekt zeigt sich die Klasse (. ToString() Methode, die Formate als lesbare Tabelle ergibt
Konversationskontext hinzufügen
Für die interaktive Analyse: ,-Anwender wollen häufig folgende Fragen stellen:
"What's the total revenue?"
→ "Break that down by region"
→ "Show the top 5 regions"
Die zweite und dritte Frage ergibt nur Sinn mit Kontext aus dem ersten
Gesprächsgeschichte verfolgen
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"
}
Einschließlich Geschichte in 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();
}
}
Die Geschichte gibt dem LLM-Kontext, um Referenzen zu verstehen, wie z.B. ",, die Ergebnisse von ", oder ", brechen sie weiter nach unten
Welches Modell zu verwenden?
Für die SQL-Generation – ,-codierung – --fokussierte Modelle funktionieren am besten –.- Hier finden Sie die verfügbaren Optionen über Modellbibliothek von Ollama-':
| -Modell Größe | -Geschwindigkeit Qualität | -Verknüpfung | ||
|---|---|---|---|---|
qwen2.5-coder:7b Schnelles, schnelles und ausgezeichnetes |
Ollama | |||
deepseek-coder-v2:16b |
, das beste Mittel der | , Ollama | ||
codellama:7b , |
, , 4 , GB , | , schnell , | , gut , | , Ollama |
llama3.2:3b Sehr schnell, sehr schnell. Ollama |
Für die meisten Anwendungsfälle qwen2.5-coder:7b trifft den süßen Punkt, der auf bescheidener Hardware läuft.
Leistung
Reale Benchmarks der Welt
Testen auf einer Zeile CSV-Datei (14, MB, ), auf einem Standarddev-Gerät (, Ryzen, 5,, NVMe SSD,, MSC6, GB RAM,):,
Frage nach dem Typ der Zeit |------------|------| Einfaches Land ,| , 65 ,| GROUP BY MIT SUM |58-68ms »|« Komplexe Aggregation mit FILTER Multi---Table GROUP BY mit HAVING-MSC2, 71, |,
Sub--100-ms für analytische Abfragen auf den Zeilen 100-K ohne Importschritt .-Queren von Komplexitätsfragen mehr als Zeilenanzahl ;-Duck DBK5-Säulenmotor verarbeitet Aggregationen effizient unabhängig von der Dateigröße.-Segment
Große Dateien in Parkett konvertieren
Für Dateien über 1, GB, ,, Parkettformat ist schneller als :
using var cmd = connection.CreateCommand();
cmd.CommandText = $"COPY (SELECT * FROM '{csvPath}') TO '{parquetPath}' (FORMAT PARQUET)";
cmd.ExecuteNonQuery();
Die komprimierte Parkett-Datei ist auch viel kleiner.
Sicherheitsaspekte
Beim Ausführen von LLM---generierter 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 im --Memory-Modus bietet auch natürliche Isolation, die Ihre Produktionsdatenbanken beeinflussen kann.
Vollständiges Beispiel
Hier ist ', wie alles zusammenkommt
// 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?"));
Zusammenfassung
Das mentale Modell, um zu halten LLMs Grund ,; , Datenbanken berechnen , . ,
Don.'.t feed data to the LLM.MSC1. Feed it schema.,. let it generate SQL?,. execute that SQL any prospective engine.MS K4. Diese Trennung ist, warum der Ansatz im Maßstab funktioniert.
Die Implementierung
- EnteDB Abfragen von CSV direkt - keine Importe von ,
- Schema Proben dem LLM genügend Kontext zu geben, ohne Daten freizulegen
- Strenge Sofortregeln force deterministische SQL., nicht kreative Prosa
- Validierung über EXPLAIN Fangfehler vor der Ausführung
- Retry mit Fehler-Feedback behandelt den gelegentlichen Syntax-Slip
Das Ergebnis: Sub--100ms analytische Abfragen auf Millionen -row-Dateien, komplett offline , mit Daten, die nie Ihre Maschine verlassen
Das vollständige Beispielprojekt ist verfügbar unter: Meistlylucid-.-CsvLm „-" schließt ein CsvQueryService, ConversationalCsvAnalyserDatengenerierung auf Basis von , und Bogus--
Aufkommen
EnteDB
- DuckDB-Dokumentation Vollständiger Verweis
- DuckDB CSV importieren Besondere Merkmale von CSV--
- DuckDB SQL Referenz SQL-Syntaxunterschiede von anderen Datenbanken
- EnteDB-.-NET GitHub Bindungen
- EnteDB-.-NET NuGet Vollständiges Paket mit nativen Binärdateien
LLMs von Ollama
- Ollama Lokale LLM-Laufzeit
- Ollama Model Library Verfügbare Modelle
- OllamaSharp Client-Bibliothek
- OllamaSharp NuGet
Generierung von Testdaten
- Bogus GitHub Gefälschte Daten-Generator
- Bogus API-Referenz Verfügbare Datentypen
Alternativen genannt
- CsvHelper CSV Parsing-Bibliothek
- Microsoft-.-Datenanalyse DataFrame für .-NET
- PandasAI Integration von Python LLM-Pandas
Verwandte Artikel
- DatenSummarizer-:-Schnelles Profilieren lokaler Daten Artikel über CLI-- auf Basis von Datenprofilen