SmoothLingua
A .NET library for building conversational agents powered by intent recognition, story-based dialogue management, and rule-based responses.
SmoothLingua is designed for teams that want a lightweight, code-first alternative to heavy conversational AI frameworks — you define your agent entirely in C# and run it anywhere .NET runs, with no external services required.
Installation
Install SmoothLingua via the .NET CLI:
dotnet add package SmoothLingua
Or via the NuGet Package Manager Console:
Install-Package SmoothLingua
Quick Start
Define a domain, train it, load the agent, and start handling messages:
using SmoothLingua;
using SmoothLingua.Abstractions;
using SmoothLingua.Abstractions.Stories;
// 1. Define and train the domain in memory
MemoryStream memoryStream = new();
Trainer trainer = new();
await trainer.Train(new Domain(
[
new("Greeting", ["Hello", "Hi"]),
new("Good", ["I am fine", "I am good, thank you"]),
new("Bad", ["I am feeling bad", "I am not good"]),
new("Bye", ["Good bye", "Bye"]),
new("IAmFrom", ["I am from USA", "I am from Bulgaria", "I am from Germany"])
],
[
new("Good",
[
new IntentStep("Greeting"),
new ResponseStep("Hello! How are you?"),
new IntentStep("Good"),
new ResponseStep("Glad to hear that! Where are you from?"),
new IntentStep("IAmFrom"),
new ResponseStep("It is nice in {country}!")
]),
new("Bad",
[
new IntentStep("Greeting"),
new ResponseStep("Hello! How are you?"),
new IntentStep("Bad"),
new ResponseStep("I am sorry to hear that.")
])
],
[new("Bye", "Bye", "Bye")],
[new Slot("country", "IAmFrom", "country", "")],
[new Entity("country", new HashSet<string> { "Bulgaria", "USA", "Germany" })]
), memoryStream, default);
// 2. Load the trained agent and start a conversation
var agent = await AgentLoader.Load(new MemoryStream(memoryStream.GetBuffer()));
var conversationId = Guid.NewGuid().ToString();
var r = agent.Handle(conversationId, "bye");
// r.IntentName == "Bye", r.Messages == ["Bye"]
r = agent.Handle(conversationId, "hello");
// r.IntentName == "Greeting", r.Messages == ["Hello! How are you?"]
r = agent.Handle(conversationId, "I am fine");
// r.IntentName == "Good", r.Messages == ["Glad to hear that! Where are you from?"]
r = agent.Handle(conversationId, "I am from Bulgaria");
// r.IntentName == "IAmFrom", r.Messages == ["It is nice in Bulgaria!"]
Load a model from file
Train once and persist to disk — no retraining needed on subsequent starts:
// Train and save
await trainer.Train(domain, "model.zip", default);
// Load on every restart
var agent = await AgentLoader.Load("model.zip");
Concepts
Intent
A named category of user utterances. You supply example phrases and the ML trainer learns to recognise
them. An Intent named Greeting with examples ["Hello", "Hi"] will
match any similar greeting at runtime.
Story
A multi-turn conversation flow defined as an ordered list of IntentStep and
ResponseStep entries. Stories model sequences: "after the user greets, reply; if they say
they're fine, reply differently than if they say they're sad."
Rule
An always-active, single-turn shortcut. A rule fires whenever its intent is predicted, regardless of
conversation context. Use rules for commands like Bye that should always produce the same
response.
Domain
The bundle that groups all intents, stories, rules, slots, and entities into one trainable unit. Pass a
Domain to Trainer.Train, which serialises it (together with the trained ML
model) into a zip archive you can store anywhere.
Agent
The runtime object that handles user input. Obtain one via AgentLoader.Load. It predicts
the intent, advances the conversation state, and returns a Response containing the matched
intent name and the bot's reply messages.
Behavioural insights
Find out where the agent is unsure — without retaining personal data.
SmoothLingua ships with an opt-in IAnalyticsRecorder that captures anonymous per-turn signals (predicted intent, confidence, fallback flag) and aggregates them on demand. Conversation identifiers and message text never leave the recorder.
using SmoothLingua.Analytics;
var recorder = new InMemoryAnalyticsRecorder();
var agent = await AgentLoader.Load("model.zip", analyticsRecorder: recorder);
agent.Handle("conv-1", "hi");
agent.Handle("conv-1", "what's the weather on Jupiter?");
var snapshot = recorder.GetSnapshot();
// snapshot.TotalMessages, snapshot.FallbackRate, snapshot.AverageConfidence, snapshot.Intents
Reading the signals
- High fallback rate — many user messages land below the confidence threshold. Either lower the threshold or add more examples to the intents users are reaching for.
- Popular intent with low average confidence — the model picks it, but only barely. Add more (and more varied) examples so the score firms up.
- Short average conversation length combined with a high fallback rate — usually points at a missing intent.
The SmoothLingua.Server host registers an InMemoryAnalyticsRecorder automatically and exposes the snapshot at GET /insights. The interactive demo at chat.smooth-lingua.com renders the same data live.
When SmoothLingua, when not
Good fit
- .NET applications that need embedded conversational logic with no external services
- Prototypes and internal tools where you want full control over training data and model lifecycle
- Chatbots with a finite, well-defined intent set (up to ~50 intents)
- Offline or air-gapped environments
Not a good fit
- Large-scale open-domain conversation — use a hosted LLM instead
- Use cases that require deep semantic understanding beyond the ML.NET SDCA classifier
- Teams that need a visual or no-code dialogue editor
Changelog
See what's new added, changed, fixed, improved or updated in the latest versions.
Version 2.2.0 (10 June, 2026)
- Added
IAnalyticsRecorderabstraction in the core package — captures anonymous per-turn signals (intent, confidence, fallback flag) and aggregates them on demand.InMemoryAnalyticsRecorderships as the default;NullAnalyticsRecorderstays in place when analytics are not requested. - Added
GET /insightsonSmoothLingua.Server— returns aggregated counts (fallback rate, average confidence, per-intent stats) without exposing conversation IDs or message text. - Added
POST /playground/predict— trains a tiny in-memory classifier from visitor-supplied intents and predicts an intent for a piece of text. Cached per intent set; intent and example counts are hard-capped. - Added CORS support on
SmoothLingua.ServerviaSmoothLingua:Cors:AllowedOrigins; the chat subdomain and the docs site are allowed by default. - Added Interactive demo at chat.smooth-lingua.com — chat with the pre-trained agent, a Playground tab for your own intents, and an Insights tab that shows the live aggregates.
- Updated
AgentLoader.Loadand theAgentconstructor accept an optionalIAnalyticsRecorder— fully backward compatible.
Version 2.1.0 (9 June, 2026)
- Added
IConversationStoreabstraction in the core package — no ASP.NET dependency. ExposesGet,Save, andReset; works identically in a console app, a desktop tool, or a web service. - Added
InMemoryConversationStore— default implementation, existing behaviour preserved exactly. - Added
FileConversationStore— durable implementation that serialises each conversation as a JSON file. State survives process restarts with no external dependencies. - Added
SmoothLingua.Server— minimal ASP.NET Core Web API:POST /conversations/{id}/messages,POST /conversations/{id}/reset,GET /health, and anAddSmoothLinguaDI extension. - Added Dockerfile for
SmoothLingua.Server— multi-stage build,/app/datavolume for model and store. - Updated
AgentLoader.LoadandConversationManageraccept an optionalIConversationStore— fully backward compatible.
Version 2.0.0 (8 June, 2026)
- Added Confidence score on every prediction (softmax-normalised, range 0–1)
- Added Fallback intent when confidence falls below a configurable threshold (default 0.4)
- Added Lookup-based entity extraction — matched values returned in
Response.ExtractedEntities - Added
Domain.ConfidenceThresholdandDomain.FallbackIntentNameconfiguration fields - Breaking
Responsegains a requiredConfidencefield — see migration notes in the GitHub release - Breaking
IPredictor.Predictnow returns(string IntentName, float Confidence)
Version 1.2.0 (2026)
- Added Rewritten README with Concepts, Quick Start, and When/Not guidance
- Added XML documentation on all public types — improves IntelliSense for consumers
- Added File-based model loading example in QuickStart
- Added Automated website deploy workflow
- Updated Website content aligned with library documentation
Version 1.1.0 (6 June, 2026)
- Added Automated release pipeline — push a
v*tag to build, test, pack, and publish to NuGet automatically - Added GitHub Releases auto-generated on each tag push
- Added CHANGELOG.md and CONTRIBUTING.md
- Added GitHub issue and pull request templates
- Added Code coverage via Coverlet
- Updated CI split into build-and-test and release workflows
Version 1.0.6 (1 January, 2024)
Initial public release — intent recognition, story management, rule-based responses, Trainer, Agent, AgentLoader, NuGet package.