# 如何用 C# 中的本地 LLM 分析大型 CSV 文件

<!--category-- AI, LLM, Data Analysis, DuckDB, C#, Ollama -->
<datetime class="hidden">2025-12-18T10:00</datetime>

**Series :当地数据 LLM {-部分}1**

这里的'是每个人犯的错误 他们试图把CSV 输入LLM. **LLM 程序应生成查询@, 不消耗数据 @.**

您% ' @ ve got a {500}MB CSV 文件, 并想要询问 < MS K2 What}'按区域的平均顺序值@?"} 像工具一样 [使用Excel的副驾驶员](https://support.microsoft.com/en-gb/copilot-excel) 如果您的数据对云服务太敏感 ~?如果你需要自己构建它呢?

此篇文章展示您如何在 C#. 中使用本地@ , @ 私人@ I,} 。

> 使用 DuckDB 直接查询 CSV 文件@ . @ 使用本地 LLM 生成 SQL MS K1} <% 1 > 此LLM 从不看到您的数据 *{-> 只是 schema.} 结果: sub}-100}<% 1} 在百万MS K6 row files _ MSKO7} 完全离线=.}

补充性治疗“,”更多CLI- 重点治疗,扩大统计概况作为LLM接口的利用范围。 “(”并展示了一种完整的工具来落实这些想法:“MS K3 à profile magication @,安全 SQL模式@,合成克隆和漂移探测”见随附文章“: **[DataSummarizer @ :快速本地数据分析](/blog/datasummarizer-how-it-works)** @-_@ 特别是部分 @ "} Key Appliedgration *:}统计作为接口的“ I".” 。 这两篇文章构成关于本地实用 LLM @ MPK4}查询模式的短片系列

[TOC]

## 核心洞见

使用 LLM 作为数据存储是错误的抽象@. @LM根本无法扫描数百万行来计算平均 {-}'}不是他们用来计算=.>的%SK3{re

正确的模式@: @% **LLM 原因 @,}数据库计算=.**

```mermaid
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
```

注意发生的情况@'}{:} <LLM>根据您的问题生成 SQL 查询, schema.} duckDB 根据实际数据执行它 < .<LLOM从不触动你的数据 <\ --> 它只看到列名和类型*.} 这就是为什么它“'_s fast\ ,> private_,}和准确=.}

更多关于作为 LLM 界面处理剖面的描述文件@(,以及一个执行 profile @-第一次点名=,安全 SQL-}后援 <&AMS K5登记册>-背靠前会话和合成克隆的混凝土 CLI,见{),} **[DataSummarizer @ :快速本地数据分析](/blog/datasummarizer-how-it-works#the-key-upgrade-statistics-as-the-interface)**.

## 为何不把它装入记忆中?

显而易见的方法都有着相同的致命缺陷

**[Csv 帮助器](https://joshclose.github.io/CsvHelper/) / 数据框架**: 将整个文件装入 RAM. A @500MB CSV 变成 “2-4GB” 对象@. a\5GB file *? OOM crash*.

**SQLite / PostgreSQL**: 需要慢速的导入步骤 @( 分钟用于大文件@), 前方的系统定义 @MS K3 和数据库管理费\.

**[潘达斯国际](https://github.com/Sinaptik-AI/pandas-ai)**执行LLM-的任意代码是一个安全噩梦, @-QSQL是宣示性的和沙箱式@;Python不是#.}

## 为什么 duckDB

[鸭子数据库](https://duckdb.org/) 查询 CSV 文件 *直接直接* - 无导入步骤, 不装入存储@:

```csharp
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
```

杀手的特征: **它将文件作为表格处理**. 指向 CSV, ParquetMS K2 或 JSON 的檔案與查詢

|Q因子 @|QCsvHelfer @MS K2ZSQLite@|ZD DuckDB#|
|--------|-----------|--------|--------|
| **内存** @ |_ {在导入% 1 时装入整个文件 *\ MS K1} 在从磁盘@ |} 导入\ MPK2 流的过程中加载了整个文件
| **设置设置设置** -=YTET -伊甸园字幕组=- 翻译:
| **500MB 文件** I| ~2 GB RAM| 导入 @| 即时@|
| **5GB 文件** {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}非常慢
| **拼格** |#没有|}不 没有|_是(10-100_x 更快\)_ @|}

DuckDB 是在 Python 中的数据工程师对精确使用此选项所使用的数据工程器@ . @ the [.NET绑定](https://github.com/Giorgi/DuckDB.NET) 给予您完整的 ADO.NET 支持 @ -} 它感觉像任何其他数据库@ MS K2 除了你{'re 查询文件@.}

## 堆叠

|% 元件 @ MS K1# 为什么这个?
|-----------|--------------|
| [鸭子数据库](https://duckdb.org/) | 直接查询 CSV , 没有进口步 *|
| [DuckDB\ .NET](https://github.com/Giorgi/DuckDB.NET) @| @ full ADO.#NET 支持@, @ 感觉自己是土生土长 @ | @
| [奥拉马](https://ollama.ai/) @ | @ 本地发酵@ MS K1 @ 没有 API 键@ I, @ 无云 @ MPK3 @
| [错数](https://github.com/bchavez/Bogus) | 任何尺度的现实测试数据 @|
| [`qwen2.5-coder:7b`](https://ollama.ai/library/qwen2.5-coder) | 最大 SQL 精确度在 @7B 大小@|

> **关于安全问题的说明**:We'正在执行 LLM-生成 SQLMS K3}这比任意代码更安全 [安保科](#security-considerations) 有关将剖面转换成LLM接口的更广泛讨论,以及实施这些模式的CLI=,见配套部分 **[DataSummarizer @ :快速本地数据分析](/blog/datasummarizer-how-it-works)**.

## 项目设置

Let's 创建一个样本工程\ .安裝 Nuget 套件@:

```bash
dotnet add package DuckDB.NET.Data.Full
dotnet add package OllamaSharp
dotnet add package Bogus
```

Pull a coding '- 重心模式, 这个模型在 SQL\ :\ 中非常优秀

```bash
ollama pull qwen2.5-coder:7b
```

## 建筑结构

这里#'}这块碎片是如何拼凑在一起的 @:$%

```mermaid
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
```

我们给LLM的关键洞察力 **模型和样本数据**@, 而非实际数据@. 这样上下文小,反应快\.

**为什么这重要**:LLM产生意旨@(SQL).DuckDB 执行它 @. 校验步骤在執行前捕捉到語法錯誤@MS K4 重試環會處理偶爾的錯誤{.} 這項分解使系統既安全又准确 □. **[DataSummarizer @ :快速本地数据分析](/blog/datasummarizer-how-it-works#the-key-upgrade-statistics-as-the-interface)**.

## 使用bogus 生成测试数据

> **已有 CSV 数据@? @%** 跳到 [步骤 @2:_ 构建方案表上下文](#step-2-build-the-schema-context).

在测试我们的 LLM -power CSV 分析器\ MS K1}之前,我们需要数据来分析\ MPK2#用于开发和测试\ MASSK3}合成数据比真实数据还要快=:}

1. **规模测试** @ -_ generate *100 K,}1}MQ,}或{10M 行,以校验不同大小的性能
2. **隐私隐私权** 在演示或截图中披露真实客户@/_Business data
3. **可复制** 相同种子@=}相同的数据 @,}让错误可以复制
4. **边缘病例** - 控制发行量 @(e.gMS K3 力 *5% 返回\, 具体日期范围@)

### 什么是博古斯・??

[错数](https://github.com/bchavez/Bogus) 它生成了现实的- 假数据\ -\ name @,\ 地址@, 电子邮件_,}日期{,}数字{MS K9} 并配有适当的本地支持}.} 而不是使用随机垃圾数据>-}测试 CSV 文件或使用随机垃圾数据库<,} Bogus 提供的数据 *外观* 真实的:

- `f.Name.FullName()` → MS K1 John Smith" I( 不是"asdf1234")
- `f.Internet.Email()` → @"john.#%smith@gmail}.comMS K5}{(properfected_)
- `f.Date.Between(start, end)` →现实日期分布
- `f.Commerce.ProductName()` @→ "#Hand 制作了《格拉尼特奶酪》_"} @MS K3 @fun @MSSK4}但可识别的)#

因为这很重要, 因为现实的数据有助于您发现问题 @ - @ 怪异格式@ MS K1 @ 意外的聚合@ MPK2_ 在日期处理中的边框 {-}\ 随机字符串会隐藏\ .}

### 定义数据模型

```csharp
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; }
}
```

### 配置 Faker

Bogus 使用流利的 API 来定义生成规则@: @%

```csharp
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));
```

让'来分解发生的事 '来分析

- **`f` 万岁,佛卡,万岁** - 能够访问所有数据模块的生成器例@(Name @,date{,随机},等}.)
- **`f.Random.Guid().ToString()[..8]`** - 生成一个 GUID, 但只取第一个 & MS K1 字元作为可读顺序代号
- **`f.Date.Between()`** @-# 随机日期在现实范围内@(_not year #9999)#
- **`f.PickRandom(array)`** @ -_ 随机从预定义的选项中选择 ( ensures valid grounds {)} 。
- **`f.Random.Bool(0.3f)`** @- @ @ @ 30%# 真命天子的机会得到折扣@) @
- **`(f, s)` 语法** - 访问假冒器和部分- 建立记录@. `ProductName` 取决于 `Category`

缩略 `(f, s)` “,”不是随机项目。“.”使得生成的数据更符合实际, 用于测试像“MS K5”这样的聚合物:

### 生成并写入 CSV

```csharp
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},...");
}
```

100QK 列生成的 CSV @-QMB 多到足以测试@,}但您可以很容易地缩放成百万.Q 。

> **提示提示**:- 设置 `Randomizer.Seed = new Random(12345)` 在生成数据以获取可复制的数据前@. @ 相同种子 @=}同样的 @ "_ random"}每次@MS K4}记录,这对调试Q.非常宝贵 *

## 步骤 @2:_ 构建方案表上下文

在LLM 生成 SQL, 之前, 它需要理解数据结构@ . {我们从 DuckDB\ MS K2} 提取此信息

### 上下文模式

```csharp
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.
}
```

这将捕捉LLM需要的一切 {:} 列名称 , 类型{MS K2} 和几个样本行来理解数据格式.}

### 抽取气管

DuckDB 可以描述任何 CSV, 不装入全部@ :

```csharp
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;
}
```

缩略 `DESCRIBE` 命令只读取文件页眉加几行以显示类型推导@- @ it'}即使在巨大的文件中也即时读取 #% .#

### 获取抽样数据

样本行有助于 LLM 理解数据格式@(dates @,IDs,}等{.):}

```csharp
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);
}
```

三行通常足够 @ - @ 它向LLM展示了在不浪费标语的情况下可以期待的格式@ MS K1} @

## 使用 LLM 生成 SQL

**这是最难的部分 .** 当地LMS将产生创造性但破碎的 SQL=.}目标在于确定性@,不是创造力 @.

### 快速建设

```csharp
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}");
    }
```

规则部分是关键 {-} 。 它告诉 LLM 如何对 DuckDB. 的查询进行格式化: 明确有关语法@ (} limit 和 TOPQ,} 字符串连接\ MS K4} 防止常见错误=.}

### 添加样本数据

```csharp
    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)}}}");
        }
    }
```

### 错误回收

如果上次尝试失败, @ , 包括错误@ MS K1\ {}

```csharp
    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();
}
```

此重试机制很重要 {-} 本地LLMs 有时会做出语法错误}, 并给予它们通常在第二次尝试中修正的错误

### 致电LLM

```csharp
var request = new GenerateRequest { Model = _model, Prompt = prompt };
var response = await _ollama.GenerateAsync(request).StreamToEndAsync();
var sql = CleanSqlResponse(response?.Response ?? "");
```

缩略 `StreamToEndAsync()` 等待完整响应@. @set a better UX,}您可以在牌子到达时流传#.}

### 清理反应

LLMs 通常以标记代码块的 SQL 包装, 尽管被告诉不要@: @%

```csharp
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');
}
```

## 执行前的校验@4: @%

鸭子 DuckDB #' @%s `EXPLAIN` 让我们检查 SQL 语法而不运行查询@:

```csharp
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;
    }
}
```

如果验证失败, 我们将错误反馈到 LLM 并重试“ (” 。

## 执行和格式结果

最后 , 运行查询并格式化输出 @:

```csharp
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;
}
```

缩略 `QueryResult` 类 @(+#在样本项目中完全显示 )}包括 a `ToString()` 用于将格式结果制成可读表格的方法@. @%

## 添加对话上下文

对于交互式分析来说 , @% 用户通常想要询问后续问题@-_up question @:}

```
"What's the total revenue?"
→ "Break that down by region"
→ "Show the top 5 regions"
```

第二和第三个问题仅与第一个“.”的上下文有意义。

### 跟踪对话史

```csharp
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"
}
```

### 将历史包含在提示中

```csharp
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();
    }
}
```

历史让LLM上下文能够理解引用, 如 @" @ that",}{"这些结果@",}或%" 。

## 使用哪个型号@? @%

对于 SQL 生成 < sQL page , > 编码 <% -" 聚焦模型工作效果最佳> @. _ 这是通过下列方式提供的选项: [Ollama's 示范图书馆](https://ollama.ai/library):

|Q 型号@|Q大小 @|Q 速度#|QQ质量 #|Q链接#MS K5}
|-------|------|-------|---------|------|
| `qwen2.5-coder:7b` -=YTET -伊甸园字幕组=- 翻译: [奥拉马](https://ollama.ai/library/qwen2.5-coder) |
| `deepseek-coder-v2:16b` 中度| 最佳| [奥拉马](https://ollama.ai/library/deepseek-coder-v2) |
| `codellama:7b` | MS K1 GB | 快速 MSC3 好 MSKO4 [奥拉马](https://ollama.ai/library/codellama) |
| `llama3.2:3b` @| 2 GB| 非常快速{| 接受@| [奥拉马](https://ollama.ai/library/llama3.2) |

对于大多数使用的案例来说 @, @% **`qwen2.5-coder:7b`** 精确的SQL,}好的速率 *,}用微小的硬件运行

## 业绩表现 实绩

### 世界基准

测试“100QK” CSV 文件 “(14MB)}用标准立体机器“MS K3Ryzen ‘5,’NVME SSD, 32GB RAM @):}

|Q 查询类型 @|Q 时间@|
|------------|------|
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}
由SUM MSSK1组组成 58-68组
“|”复杂集成与“FILTER |”和“63”合并
以#|+#71+s @|+@

用于分析查询的 Sub-100 @%ms 在 100}K 行 @-}没有输入步骤@.}查询复杂程度超过行计数{;} duckDB'}*s 列引擎有效处理聚合,而不论文件大小}=.}

### 将大文件转换为 Parquet

用于% 1 @GB#,@ [拼格格式](https://parquet.apache.org/) 是“10-100#x 更快”\":}

```csharp
using var cmd = connection.CreateCommand();
cmd.CommandText = $"COPY (SELECT * FROM '{csvPath}') TO '{parquetPath}' (FORMAT PARQUET)";
cmd.ExecuteNonQuery();
```

压缩的 Parquet 文件也小得多@. @%

### 安全考虑

当执行 LLM\ -\ 生成 SQL:\ 时

```csharp
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 in - mememory 模式也提供自然隔离@-}它可以影响您的生产数据库Q.}

## 完整示例

这里的',它是如何走到一起 :

```csharp
// 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?"));
```

## 摘要摘要

保持精神模式的心理模型 **LLM 理由@;}数据库计算=%.**

Don't 将数据反馈到 LLM.喂它 schema}, 让它生成 SQLMS K3 执行SQL 对一个正确的查询引擎\ . 这个分离就是为什么这个方法在 scale_.}工作的原因

执行@:

1. **鸭子数据库** 直接查询 CSV 磁盘流中的 cSV - no import *,% blook
2. **采样样本** 给予 LLM 足够的上下文而不曝光数据
3. **严格迅速规则** SQL,非创造性流言
4. **通过EXPLAIN进行验证** 执行前的捕获错误
5. **使用错误反馈重试** 处理偶发语法滑块

结果是“: sub-100%ms 分析查询”百万兆@-row file @, 完全离线{,} 数据从未离开您的机器\.}

完整的抽样项目 [Mostlucid.CsvLllm 最普通的](https://github.com/scottgal/mostlylucidweb) 包括@- `CsvQueryService`, `ConversationalCsvAnalyser`,和Bogus-基于数据生成 <.>

## 资源资源资源 资源和资源资源资源

### 鸭子数据库

- [DuckDB 文档](https://duckdb.org/docs/) *-全参考
- [DuckDB 导入 CSV](https://duckdb.org/docs/data/csv/overview.html) -CSV-特定特性
- [Duck DB SQL 引用](https://duckdb.org/docs/sql/introduction) - SQL 与其他数据库的语法差异
- [DuckDB .NET GitHub](https://github.com/Giorgi/DuckDB.NET) -C#绑定
- [DuckDB .NET NUGet](https://www.nuget.org/packages/DuckDB.NET.Data.Full) “-”全套本地二进制

### 奥利亚马 &

- [奥拉马](https://ollama.ai/) -当地LLM运行时间
- [奥利亚马模拟图书馆](https://ollama.ai/library) 现有模型
- [奥利亚马沙尔普](https://github.com/awaescher/OllamaSharp) - C#客户端库
- [OllamaSharp Nuget 超音速](https://www.nuget.org/packages/OllamaSharp/)

### 测试数据生成

- [博格斯 GitHub](https://github.com/bchavez/Bogus) -假数据生成器
- [Bogus API 参考](https://github.com/bchavez/Bogus#bogus-api-support) -现有数据类型

### 提及的替代措施

- [Csv 帮助器](https://joshclose.github.io/CsvHelper/) - CSV 解析库
- [微软.Data.分析](https://www.nuget.org/packages/Microsoft.Data.Analysis) @ - 用于 @ I.NET的数据框架
- [潘达斯国际](https://github.com/Sinaptik-AI/pandas-ai) - Python LLM+熊猫集成

### 相关条款

- [DataSummarizer @ :快速本地数据分析](/blog/datasummarizer-how-it-works) 包括CLI=-}基于数据剖析的合著文章