---
title: "Zero-shot entity extraction in C#"
url: https://recursiveai.org/onenlp/cookbook/extract-custom-entity-types/
description: "Extract custom entity types in C# with OneNLP open-type NER. Install the model package, pass runtime labels and tune thresholds against checked examples."
version: "1.0.0"
---

# Zero-shot entity extraction in C#

**OneNLP** is a free, open-source natural language processing library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneNlp) · [GitHub](https://github.com/recursive-ai-oss/onenlp-csharp) · [Docs](https://recursiveai.org/onenlp/docs/) · [Download example (.zip)](https://recursiveai.org/onenlp/cookbook/extract-custom-entity-types/extract-custom-entity-types.zip)

Pass entity type names at runtime to extract matching mentions. The model is in `RecursiveAI.OneNlp.Models.Multilingual` and works on English text.

```shell
dotnet add package RecursiveAI.OneNlp
dotnet add package RecursiveAI.OneNlp.Models.Multilingual
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneNlp;

var entities = Nlp.Entities(
    "Acme Corp. signed with Beta LLC.",
    "organization");
foreach (var entity in entities)
    Console.WriteLine(
        $"{entity.Label}: {entity}");
```

```text
organization: Acme Corp.
organization: Beta LLC
```

Without the model package, this overload throws `InvalidOperationException` naming `RecursiveAI.OneNlp.Models.Multilingual`; it never downloads a model.

Unzip [the example](https://recursiveai.org/onenlp/cookbook/extract-custom-entity-types/extract-custom-entity-types.zip), then `dotnet run`.

## Variations

**Lower the threshold for a less familiar type name.** Replace `Program.cs` with:

```csharp
using RecursiveAI.OneNlp;

var entities = Nlp.Entities(
    "Acme Corp. signed with Beta LLC.",
    ["contract party"], 0.1f);
foreach (var entity in entities)
    Console.WriteLine(
        $"{entity.Label}: {entity}");
```

```text
contract party: Acme Corp.
contract party: Beta LLC
```

## Related recipes

- [Match text token patterns in C#](https://recursiveai.org/onenlp/cookbook/match-token-patterns/)
- [Match phrases in text in C#](https://recursiveai.org/onenlp/cookbook/match-phrases/)
- [Rule-based entity recognition in C#](https://recursiveai.org/onenlp/cookbook/add-rule-based-entities/)

---

## The short answer

Install `RecursiveAI.OneNlp.Models.Multilingual` and call `Nlp.Entities(text, types)` with the entity type names you want. The example requests `organization`, not a fixed label inventory. The model weights are embedded in NuGet packages and registered by the model package; inference does not fetch them on demand.

The shipped open-type model is English-only. Accepting a runtime label does not guarantee useful extraction for that label. In particular, an unfamiliar business-specific term may score below the default threshold even when a familiar category name finds the same mention.

## Can you give me an example of zero-shot learning?

For this task, you give the recognizer an entity type name at inference time rather than retraining a fixed-label recognizer for that request. The snippet at the top asks for `organization` and extracts `Acme Corp.` and `Beta LLC`. The variation asks for `contract party` on the same input, with a lower threshold.

The [open-type documentation](https://recursiveai.org/onenlp/docs/open-ner/) uses “zero-shot” in a specific evaluation sense: no examples from the evaluated zero-shot dataset were used to train or select the model. It does not mean every requested label word was unseen in training. Calling the API with a custom label is not evidence that it has never encountered that concept.

Type names are part of the model input. The recognizer encodes each name and compares candidate text spans with it. The label in a returned entity is the type string you supplied. Choose clear names that express what should count as a mention, and keep that inventory stable while assessing extraction behavior.

The documented limits are one to 256 distinct type strings, each at most 200 characters. Candidate spans are at most 12 tokens. Output is flat: when predictions overlap, the more probable one wins. A request for both a broad and a narrow category therefore does not necessarily produce two labels for the same text span.

## How do I extract custom entity types in C#?

Use the overload with a type list and an explicit threshold when the default does not fit your data. The default is `0.5`; spans at or above it are retained before overlap selection. The variation lowers it to `0.1` for `contract party`. That is a working example on this sentence, not a recommended setting for contracts in general.

A lower threshold admits lower-scoring spans and can add unwanted matches. Check representative text manually before using a new type or threshold in a workflow. Include sentences with no matching entity, ambiguous names, longer mentions and multiple possible types. An empty result can mean the text has no qualifying mention, the label is poorly understood, or the threshold excluded the prediction.

The documentation reports weaker recall on its zero-shot evaluations and recommends the ordinary entity recognizer when types are fixed and labeled training data is available. This API should not be treated as a guarantee of complete extraction. If missing a party or product would change a decision, inspect those results rather than equating an empty list with proof of absence.

The library’s permissive license is separate from model-data terms. The [open-type model documentation](https://recursiveai.org/onenlp/docs/open-ner/#data-and-limits) identifies share-alike lineage in the shipped model’s training data; consult the package’s third-party notices when distributing model assets. The downloadable example contains code and package references, not a copy of those weights.
