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
Wednesday, 21 January 2026
Так, як я будую прозораРАГ Я читаю в соціальних медіа, де люди питають одне й те саме. МСК1 МСК2 Як ви отримуєте характеристики від сканованого тексту? МСК3 помилка категорії завжди. ' просто користуйтесь LLM '... яка працює, але дуже дорого. глибоко в просторі OCR Я подумав, що я напишу 'напрочуд дружній для początkujących ' підхід до NON
У вас є зображення з текстом. Ви хочете виокремити цей текстM SK1 тоді знаходити корисний структуру всередині нього ( назви , компаніїMska4 місцяMска5 без виклику LLMM Ska6 відправлення даних до хмариMSKA7 або платити за один токенМska8
Ця стаття показує найпростіше трубка: Тесеракт для видобутку тексту, тоді БЕРТ NER (via ONNXM SK1 для розпізнавання об 'єктів . Все локальне МSK3 Все детерміністичне M SK4 Все в C #.
Детерміністично тут означає фіксовані версії, фіксоване значення мовиM SK1 і відсутність адаптивного навчання в часі запуску
NuGet скоро прийде - IM SK1m упакуємо це в простий
mostlylucid.ocrnerбібліотека. На даний момент
flowchart LR
subgraph OCR["Part 1: OCR"]
IMG[Image]
TESS[Tesseract]
TXT[Raw Text]
end
subgraph NER["Part 2: NER"]
TOK[Tokenize]
BERT[BERT NER<br/>ONNX]
ENT[Entities]
end
IMG --> TESS
TESS --> TXT
TXT --> TOK
TOK --> BERT
BERT --> ENT
style TESS stroke:#f60,stroke-width:3px
style BERT stroke:#f60,stroke-width:3px
style ENT stroke:#090,stroke-width:3px
Два кроки, два моделі , обидва локально працюютьM SK2 Дозвольте' збудувати кожну частинуMSC4
Тесеракт це стандартний відкритий -ソース OCR двигун . Ми МSK2 використаємо Теsseract.NET, упаковка CM SK1
dotnet add package Tesseract
Вам також потрібні треновані файли даних. завантажити eng.traineddata від тести і помістити його в tessdata папка.
using Tesseract;
public static string ExtractText(string imagePath)
{
using var engine = new TesseractEngine("./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
return page.GetText();
}
Це - МСК0, це - МSK1 ExtractText("invoice.png") і ви отримуєте струну.
Важливо:
TesseractEngineце дорого створити. В реальному програмуванніМSK1 створити його один раз і відновити
Теsseract працює добре для чистий, високийM SK1 контрастний текст в стандартних шрифтах. Він бореться з
inter-\nnational) може потребувати обробки післяM SK1 перед NERДля систем виробництва, які мають справу з дивними речами, см. Трійна труба МСК0Tier-, що додає Флоренції -2 ONNX як середній рівень і ескалацію Vision LLM для жорстких корпусів
Для цього уроку ми припускаємо, що ви маєте чисті зображення або текст з іншого джерела.
У практиці, ви зазвичай хочете нормалізувати OCR вихідні коди ( trim whitespace, collapse repeated newlinesM SK3 fix obvious hyphenationMska4 before passing it to NERM Ska5
Перед тим, як зануритися у код, треба зрозуміти, що ми насправді робимо. Якщо ви - програміст, який ніколи не торкався ML,
Визначання наименованих об 'єктів (NERM SK1 є розв 'язаною проблемою. Дослідники навчили нейронні мережі, які можуть читати текст і виділяти цікаві біти
Модель не розуміє тексту NER - це виділення властивостей, не обґрунтуванняM SK1 Імовірність співпадіння шаблону на стероидах
NX ( Open Neural Network Exchange ) це стандартний формат для моделей ML МSK2 Подумайте про це як про заморожена деференція DLL для нейронних мереж: фіксовані вага вM SK1 витяжники назовні, без тренувальної логіки МSK3 без випадковості :
flowchart LR
subgraph Training["Training (Python)"]
PT[PyTorch Model]
TF[TensorFlow Model]
end
subgraph Export["Export Once"]
ONNX[model.onnx]
end
subgraph Runtime["Run Anywhere"]
CS[C# App]
CPP[C++ App]
JS[JavaScript App]
end
PT --> ONNX
TF --> ONNX
ONNX --> CS
ONNX --> CPP
ONNX --> JS
style ONNX stroke:#f60,stroke-width:4px
style CS stroke:#090,stroke-width:3px
Найголовніша думка: хтось інший зробив важку роботу (викладання моделі в PythonіM SK1 Ви просто виконуєте висновки у C#.
Ви можете надіслати текст на GPT-4 і запитати: M SK1знайомте людей та компанії в цьому текстіMSC2 Це працює! АлеMST4
| Погляньмо на це. МSK1 Швидкість. | |||||
|---|---|---|---|---|---|
| NER МSK0 ~50ms МSK2 ♫ ♫ $0 ♫ | |||||
| Місцевий LLM API МSK0 4-30s МSK2 | $0 \ | МSK4 Малі моделі можуть бути склоподібними | |||
| LLM API МSK0 1-5s МSK2 | $20-50 \ | МSK4 | Дані надсилаються назовні | Варіабель M |
ЛЛМ чудові для складного обґрунтування. Для видобутку шаблонів в масштабіM SK1 спеціальною моделью є 40x швидше і вільніше.
Ось що ми будуємо
flowchart LR
subgraph Input
TEXT[Raw Text]
end
subgraph Tokenization["Step 1: Tokenization"]
TOK[Split into tokens]
IDS[Convert to IDs]
end
subgraph Model["Step 2: ONNX Inference"]
BERT[BERT Model]
LOGITS[Logits Output]
end
subgraph Output["Step 3: Decode"]
LABELS[BIO Labels]
ENT[Entities]
end
TEXT --> TOK
TOK --> IDS
IDS --> BERT
BERT --> LOGITS
LOGITS --> LABELS
LABELS --> ENT
style BERT stroke:#f60,stroke-width:4px
style ENT stroke:#090,stroke-width:3px
Кожен крок простий.
Вам потрібні три файли з HuggingFace. завантажити їх ręczно до папки M SK1e .g., ./models/ner/):
| Файлі МSK1 Размер МSK2 यूआरएल |
|---|
model.onnx МSK0 ~430MB МSK2 Загрузити |
vocab.txt МSK0 ~230KB МSK2 Загрузити |
config.json МSK0 ~1KB МSK2 Загрузити |
Модель bert-baseM SK1NER exported to ONNX format by захист.
Ваша папка має виглядати як:
models/
ner/
model.onnx (the neural network)
vocab.txt (word → ID mapping)
config.json (label definitions)
Створити нову консольну програму і додати пакети NuGet:
dotnet new console -n NerDemo
cd NerDemo
dotnet add package Microsoft.ML.OnnxRuntime
dotnet add package Microsoft.ML.Tokenizers
Це – МСК0, це – МSK1, два пакети, МSK2
Перед тим, як модель зможе обробляти текст, ми повинні конвертувати його в цифриM SK1 Це називається символізація.
flowchart TD
subgraph Input
TEXT["John works at Microsoft"]
end
subgraph Tokenize["Tokenization"]
T1["[CLS]"]
T2["John"]
T3["works"]
T4["at"]
T5["Microsoft"]
T6["[SEP]"]
end
subgraph IDs["Token IDs"]
I1["101"]
I2["1287"]
I3["2573"]
I4["1120"]
I5["7513"]
I6["102"]
end
TEXT --> T1 & T2 & T3 & T4 & T5 & T6
T1 --> I1
T2 --> I2
T3 --> I3
T4 --> I4
T5 --> I5
T6 --> I6
style T1 stroke:#c00,stroke-width:3px
style T6 stroke:#c00,stroke-width:3px
style I2 stroke:#090,stroke-width:3px
style I5 stroke:#090,stroke-width:3px
Ключевые моменти:
[CLS] і [SEP] є особливими символами, які позначають межі реченняvocab.txtusing Microsoft.ML.Tokenizers;
// Load the vocabulary file
var vocabPath = "./models/ner/vocab.txt";
var options = new BertOptions
{
LowerCaseBeforeTokenization = false, // BERT-NER is case-sensitive!
UnknownToken = "[UNK]",
ClassificationToken = "[CLS]",
SeparatorToken = "[SEP]",
PaddingToken = "[PAD]"
};
using var stream = File.OpenRead(vocabPath);
var tokenizer = BertTokenizer.Create(stream, options);
Чому? LowerCaseBeforeTokenization = false? Ця модель була навчена на корпусному тексті . МSK2Джон МSK3 і СМСК4Джун ММСК5 мають різні значення СМСК6 один МПСК7 скоріш за все ім 'я
Важливо: Токенізер повинна точно співпадуть з моделлю. Використовуючи інший vocabM SK1 опцію обробки , або індивідуальні значки символів тиші погіршують результати
vocab.txtщо судна з моделью.
var text = "John Smith works at Microsoft in London.";
// Tokenize (splits into subwords)
var encoded = tokenizer.EncodeToTokens(text, out _);
// Get special token IDs
var clsId = 101; // [CLS] token
var sepId = 102; // [SEP] token
// Build the full sequence: [CLS] + tokens + [SEP]
var tokenIds = new List<int> { clsId };
tokenIds.AddRange(encoded.Select(t => t.Id));
tokenIds.Add(sepId);
// Also keep the text tokens for later
var tokens = new List<string> { "[CLS]" };
tokens.AddRange(encoded.Select(t => t.Value));
tokens.Add("[SEP]");
Після цього ми маємо
tokenIds: [101, 1287, 3455, 2573, 1120, 7513, 1999, 2414, 119, 102]tokens: ["[CLS]", "John", "Smith", "works", "at", "Microsoft", "in", "London", ".", "[SEP]"]Тепер ми додаємо ці цифри до моделі ONNX. Модель повертає "логітиM SK2raw результати для кожного можливого ярлика на кожному місціMSC3
flowchart LR
subgraph Inputs
IDS["Token IDs<br/>[101, 1287, 3455, ...]"]
MASK["Attention Mask<br/>[1, 1, 1, ...]"]
end
subgraph Model
ONNX["BERT NER<br/>model.onnx"]
end
subgraph Outputs
LOG["Logits<br/>[batch, seq_len, 9]"]
end
IDS --> ONNX
MASK --> ONNX
ONNX --> LOG
style ONNX stroke:#f60,stroke-width:4px
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
// Configure for best performance
var sessionOptions = new SessionOptions
{
GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL,
IntraOpNumThreads = Math.Min(4, Environment.ProcessorCount)
};
// Load the model (takes ~2 seconds first time)
var session = new InferenceSession("./models/ner/model.onnx", sessionOptions);
Важливо: Створити токенізер і сеанс висновків один раз.
InferenceSessionдуже дорого створити.
Модель очікує:
long[]// Pad to a fixed length (BERT requires fixed shapes; powers of 2 are cache-friendly)
int sequenceLength = 64; // or 128, 256, 512
var inputIds = new long[sequenceLength];
var attentionMask = new long[sequenceLength];
for (int i = 0; i < sequenceLength; i++)
{
if (i < tokenIds.Count)
{
inputIds[i] = tokenIds[i];
attentionMask[i] = 1;
}
else
{
inputIds[i] = 0; // PAD token
attentionMask[i] = 0;
}
}
// Create tensors (shape: [batch_size=1, sequence_length])
var inputIdsTensor = new DenseTensor<long>(inputIds, [1, sequenceLength]);
var attentionMaskTensor = new DenseTensor<long>(attentionMask, [1, sequenceLength]);
// Build inputs
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor("input_ids", inputIdsTensor),
NamedOnnxValue.CreateFromTensor("attention_mask", attentionMaskTensor)
};
// Run the model
using var results = session.Run(inputs);
// Get output logits
var output = results.First(r => r.Name == "logits");
var logits = output.AsTensor<float>();
Виход logits має форму [1, sequence_length, 9]-9 можливі ярлики для кожного місця символуM SK1
Модель виводить сирові очки. Нам потрібноM SK1
Модель використовує BIO нотація:
flowchart LR
subgraph Tokens
T1["John"]
T2["Smith"]
T3["works"]
T4["at"]
T5["Microsoft"]
end
subgraph Labels
L1["B-PER"]
L2["I-PER"]
L3["O"]
L4["O"]
L5["B-ORG"]
end
T1 --> L1
T2 --> L2
T3 --> L3
T4 --> L4
T5 --> L5
style L1 stroke:#090,stroke-width:3px
style L2 stroke:#090,stroke-width:3px
style L5 stroke:#00f,stroke-width:3px
Це дозволяє моделлю працювати з багатьма-іменними об 'єктами, такими як M SK1Джон Сміт " або МSK3Великобританія МSK4
// These are the 9 labels the model was trained on (CoNLL-2003 dataset)
string[] labels =
{
"O", // 0: Outside any entity
"B-PER", // 1: Beginning of Person
"I-PER", // 2: Inside Person
"B-ORG", // 3: Beginning of Organization
"I-ORG", // 4: Inside Organization
"B-LOC", // 5: Beginning of Location
"I-LOC", // 6: Inside Location
"B-MISC", // 7: Beginning of Miscellaneous
"I-MISC" // 8: Inside Miscellaneous
};
Примітка: Це специфічна модель, яка використовує стандартну 9-схему CoNLL зображень
config.json(id2labelполе). Якщо ви поміняєте моделіM SK1 читайте ярлики з конфігурації, а не за допомогою кодування
Для кожного символу ми вибираємо ярлик з найвищим logit балом:
var predictions = new List<(string Token, string Label, float Confidence)>();
int numLabels = 9;
for (int i = 0; i < tokens.Count; i++)
{
// Skip special tokens
if (tokens[i] is "[CLS]" or "[SEP]" or "[PAD]")
continue;
// Find highest scoring label
float maxScore = float.MinValue;
int maxIndex = 0;
for (int j = 0; j < numLabels; j++)
{
float score = logits[0, i, j];
if (score > maxScore)
{
maxScore = score;
maxIndex = j;
}
}
// Convert logit to probability (softmax)
float confidence = Softmax(logits, i, numLabels, maxIndex);
predictions.Add((tokens[i], labels[maxIndex], confidence));
}
І Softmax функція перетворює чисті партитури на ймовірність (0-1):
static float Softmax(Tensor<float> logits, int position, int numLabels, int targetIndex)
{
// Find max for numerical stability
float maxLogit = float.MinValue;
for (int j = 0; j < numLabels; j++)
maxLogit = Math.Max(maxLogit, logits[0, position, j]);
// Compute softmax
float sumExp = 0f;
for (int j = 0; j < numLabels; j++)
sumExp += MathF.Exp(logits[0, position, j] - maxLogit);
return MathF.Exp(logits[0, position, targetIndex] - maxLogit) / sumExp;
}
Довідка про довіру: Оцінки Softmax родичі, не калібровані вірогідності . Вони МSK2 є корисними для рейтингу та порогового значення M SK3 але їх не лікують
0.92як "92% правильнийM SK1 Використовуйте їх для того, щоб відфільтрувати низькі - прогнози впевненості МSK3 не як базову правду
Тепер ми маємо прогнози на% 1,% 2,% 3,% 4,% 5. Нам потрібно об 'єднати їх в один ціль.
Перші, допоміжні дозволяти поєднати WordPiece. Ці ручки ## слова-заголовки та відмітки правильно:
static void AppendWordPiece(StringBuilder sb, string token)
{
if (string.IsNullOrEmpty(token)) return;
// WordPiece continuation: "##soft" → append without space
if (token.StartsWith("##", StringComparison.Ordinal))
{
sb.Append(token.AsSpan(2));
return;
}
// No leading space if first token or if punctuation
if (sb.Length > 0 && !IsPunctuationToken(token))
sb.Append(' ');
sb.Append(token);
}
static bool IsPunctuationToken(string token) =>
token.Length == 1 && char.IsPunctuation(token[0]);
static string MergeWordPieces(IEnumerable<string> tokens)
{
var sb = new StringBuilder();
foreach (var t in tokens)
AppendWordPiece(sb, t);
return sb.ToString();
}
Тепер виділення об 'єкту. Довіра об' єкту мінімальний рівень довіру через весь діапазон, так що один слабкий символ не приховується середнім показником
public sealed class Entity
{
public required string Text { get; init; }
public required string Type { get; init; } // PER, ORG, LOC, MISC
public required float Confidence { get; init; }
}
static List<Entity> ExtractEntities(
IReadOnlyList<(string Token, string Label, float Confidence)> predictions)
{
var entities = new List<Entity>();
string? currentType = null;
var currentTokens = new List<string>();
float currentConfidence = 1.0f;
void Flush()
{
if (currentType == null || currentTokens.Count == 0) return;
entities.Add(new Entity
{
Type = currentType,
Text = MergeWordPieces(currentTokens),
Confidence = currentConfidence
});
currentType = null;
currentTokens.Clear();
currentConfidence = 1.0f;
}
foreach (var (token, label, conf) in predictions)
{
// Continue current entity if model says I-<same type>
if (currentType != null && label == $"I-{currentType}")
{
currentTokens.Add(token); // keep ## form, merge handles it
currentConfidence = Math.Min(currentConfidence, conf);
continue;
}
// New entity begins
if (label.StartsWith("B-", StringComparison.Ordinal))
{
Flush();
currentType = label[2..];
currentTokens.Add(token);
currentConfidence = conf;
continue;
}
// Anything else (O, or I- without matching current type) ends the entity
Flush();
}
Flush();
return entities;
}
Примітка: WordPiece повністю обробляється MergeWordPieces-не потрібно спеціального управління потоком
Тут' є мінімальним прикладом, який ви можете скопіювати і запустити
using System.Text;
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using Microsoft.ML.Tokenizers;
// === Configuration ===
var modelPath = "./models/ner/model.onnx";
var vocabPath = "./models/ner/vocab.txt";
// === Load tokenizer ===
var bertOptions = new BertOptions
{
LowerCaseBeforeTokenization = false,
UnknownToken = "[UNK]",
ClassificationToken = "[CLS]",
SeparatorToken = "[SEP]"
};
using var vocabStream = File.OpenRead(vocabPath);
var tokenizer = BertTokenizer.Create(vocabStream, bertOptions);
// === Load model ===
var sessionOptions = new SessionOptions
{
GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL
};
using var session = new InferenceSession(modelPath, sessionOptions);
// === Process text ===
var text = "John Smith, CEO of Microsoft, announced the acquisition in London yesterday.";
// Tokenize
var encoded = tokenizer.EncodeToTokens(text, out _);
// Build sequence with special tokens
var tokens = new List<string> { "[CLS]" };
tokens.AddRange(encoded.Select(t => t.Value));
tokens.Add("[SEP]");
var rawIds = new List<int> { 101 }; // [CLS]
rawIds.AddRange(encoded.Select(t => t.Id));
rawIds.Add(102); // [SEP]
// Pad to fixed length
int seqLen = 64;
var inputIds = new long[seqLen];
var attentionMask = new long[seqLen];
for (int i = 0; i < seqLen; i++)
{
inputIds[i] = i < rawIds.Count ? rawIds[i] : 0;
attentionMask[i] = i < rawIds.Count ? 1 : 0;
}
// === Run inference ===
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor("input_ids",
new DenseTensor<long>(inputIds, [1, seqLen])),
NamedOnnxValue.CreateFromTensor("attention_mask",
new DenseTensor<long>(attentionMask, [1, seqLen]))
};
using var results = session.Run(inputs);
var logits = results.First().AsTensor<float>();
// === Decode predictions ===
string[] labels = ["O", "B-PER", "I-PER", "B-ORG", "I-ORG", "B-LOC", "I-LOC", "B-MISC", "I-MISC"];
// WordPiece merge helper
static string MergeWordPieces(List<string> tokens)
{
var sb = new StringBuilder();
foreach (var t in tokens)
{
if (t.StartsWith("##", StringComparison.Ordinal))
sb.Append(t.AsSpan(2));
else if (sb.Length > 0 && t.Length > 0 && !char.IsPunctuation(t[0]))
sb.Append(' ').Append(t);
else
sb.Append(t);
}
return sb.ToString();
}
Console.WriteLine($"Input: {text}\n");
Console.WriteLine("Entities found:");
string? currentType = null;
var currentTokens = new List<string>();
for (int i = 1; i < tokens.Count - 1; i++) // Skip [CLS] and [SEP]
{
var token = tokens[i];
// Find best label
int bestIdx = 0;
float bestScore = float.MinValue;
for (int j = 0; j < 9; j++)
{
if (logits[0, i, j] > bestScore)
{
bestScore = logits[0, i, j];
bestIdx = j;
}
}
var label = labels[bestIdx];
// Continue current entity if model says I-<same type>
if (currentType != null && label == $"I-{currentType}")
{
currentTokens.Add(token);
continue;
}
// New entity begins
if (label.StartsWith("B-"))
{
if (currentType != null)
Console.WriteLine($" [{currentType}] {MergeWordPieces(currentTokens)}");
currentType = label[2..];
currentTokens = [token];
continue;
}
// Anything else ends the current entity
if (currentType != null)
Console.WriteLine($" [{currentType}] {MergeWordPieces(currentTokens)}");
currentType = null;
currentTokens.Clear();
}
// Output last entity
if (currentType != null)
Console.WriteLine($" [{currentType}] {MergeWordPieces(currentTokens)}");
Виход:
Input: John Smith, CEO of Microsoft, announced the acquisition in London yesterday.
Entities found:
[PER] John Smith
[ORG] Microsoft
[LOC] London
БЕРТ використовує Токенізація WordPiece,, що розділяє невідомі слова на підслова ## попереднє слово означає "продовжування попереднього словаM SK1
flowchart LR
subgraph Original
W1["Elasticsearch"]
end
subgraph Tokenized
T1["Elastic"]
T2["##search"]
end
subgraph Merged
M1["Elasticsearch"]
end
W1 --> T1 & T2
T1 --> M1
T2 --> M1
style T2 stroke:#c00,stroke-width:3px
І MergeWordPieces допомічник керує цим: ## टोकони прикріплені без простору,, що виробляє "Elasticsearch" замість "Elastic search".
Якщо ви маєте багато текстів, обробляйте їх в партіяхM SK1
// Instead of: 1 text × 1 inference = 50ms
// Do: 16 texts × 1 inference = 100ms (6ms per text)
int batchSize = 16;
var batchInputIds = new long[batchSize, seqLen];
// ... fill batch ...
var tensor = new DenseTensor<long>(batchInputIds, [batchSize, seqLen]);
' не завжди прикріплятись до МSK1 Використовуйте найменший контейнер, який вписується в :
int[] buckets = [32, 64, 128, 256, 512];
int targetLength = buckets.FirstOrDefault(b => b >= tokenIds.Count);
if (targetLength == 0) targetLength = 512;
На практиці, ONNX NER досить швидко працює встромлений під час поглинання, не просто як пакетна роботаM SK1 Ви можете витягати сутності, коли приходять документи, а не переміщувати їх в чергах на пізніше.
Для високої пропускної спроможності, використовуйте DirectML (WindowsM SK2 або CUDA:
dotnet add package Microsoft.ML.OnnxRuntime.DirectML # Windows GPU
# or
dotnet add package Microsoft.ML.OnnxRuntime.Gpu # NVIDIA CUDA
var options = new SessionOptions();
options.AppendExecutionProvider_DML(); // Use GPU
| Використовуйте ONNX NER | |
|---|---|
| високий об 'єм МSK1 шл. доків МSK2 | один мSK4 аналіз ззовні M |
| Стандартні об 'єкти МSK1 люди МSK2 організації , місця | |
| конфіденциальністьM SK1чутливі дані | Коли вам потрібні пояснения МSK3 |
| Детерміністичні труби МSK1 Дослідковий аналіз МSK2 | |
| Видобуток властивостей МSK1 інтерпретація МSK2 синтез |
Обидві методи працюють. Вони розв 'язують різні проблеми. NER виділяє структуру ; LLM - причину значущості МSK2
Ця модель-детерміністичне видобуток з замороженими моделями,, потім опціональна синтеза- набагато краще, ніж втиснути чистий текст у LLM і сподіватися, що він буде вестись так
NER - це не те, що ви робите.
Те ж саме стосується і інших завдань по видобутку властивостей.
Де це підходить?: Це OCR + NER труба є одним з будівельних блоків МSK2 Для повної картини МSK3 як виокремлені об 'єкти входять у графову конструкцію Reduced RAG і Документація LucidRAG. Втіли, які ви тут витягуєте, стають вузлими ; документи стають крапочками МSK2 LLM бачить тільки те, що йому потрібно
Кітапники & Моделі:
Подібні статті:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.