大多数今天添加 AI 功能的 .NET 团队最终都会编写相同的底层代码:HTTP 客户端、重试策略、API 密钥的机密管理,以及在某人的信用卡上按每个令牌计费的费用。Aspose.LLM 走了一条不同的路线。它是一个 NuGet 包,可在 您自己的进程内部 运行大型语言模型推理——无需调用服务、无需轮换密钥,也没有请求离开机器。
本文介绍了该库,解释了其 API 所基于的三个概念,并带您一步步实现一个可运行的聊天应用程序。如果您能够添加包引用,只需几十行代码即可发送提示。
为什么本地模型很重要
在进程内运行模型会改变您可以构建的内容。
- 数据保持不变。 提示永不离开主机,这在处理合同、医疗记录、源代码或任何受数据驻留政策约束的内容时尤为重要。
- 无每标记费用。 模型一旦存储在磁盘上,推理只消耗您已有的 CPU 或 GPU 资源,而不是按调用计费的 API。
- 运行时无网络依赖。 桌面工具、本地服务以及隔离环境都以相同方式工作。
- 单一部署产物。 模型配置随您的应用程序一起交付,而不是存在于单独账户的仪表板中。
权衡是诚实且值得提前说明的:您提供硬件。 本地运行的模型需要本地内存,首次运行时需要下载数千兆字节。
Aspose.LLM for .NET 的三个概念
表面积特意保持得很小。几乎所有使用 Aspose.LLM 的操作都涉及这三种类型。
| 概念 | 类型 | 角色 |
|---|---|---|
| License | Aspose.LLM.License | 激活库。请在使用任何其他 API 之前调用 SetLicense。 |
| Preset | e.g. Qwen25Preset | 将模型文件与生成参数(如采样器温度)捆绑在一起。 |
| API instance | AsposeLLMApi | 入口点。由预设创建,保存对话,并公开 SendMessageAsync。 |
预设是有趣的部分。与其让你手动设置模型路径、分词器设置和采样器值,不如使用预设将已知的良好组合打包起来。Qwen25Preset 是默认的起始点,你可以调整它的参数或稍后换成其他预设,而无需触及其余代码。
先决条件
在编写任何代码之前:
- 安装包 -
Install-Package Aspose.LLM - 放置许可证 - 将
Aspose.LLM.lic放在可执行文件运行时能够读取的位置。 - 检查内存预算 - Qwen25 预设至少需要 8 GB 的可用内存。
有关产品详细信息,请参阅 Aspose.LLM for .NET 产品页面。
您的第一次聊天
以下是实现真实对话的最简程序。请注意第二次和第三次调用:API 实例会自行跟踪上下文,因此模型仍然知道 Alice 是谁。
代码的作用
- 创建一个
License并指向您的许可证文件。 - 使用默认配置实例化一个
Qwen25Preset。 - 从该预设创建一个
AsposeLLMApi实例。 - 发送多个提示,所有提示共享同一个对话。
using Aspose.LLM;
using Aspose.LLM.Abstractions.Parameters.Presets;
var license = new Aspose.LLM.License();
license.SetLicense("Aspose.LLM.lic");
var preset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(preset);
string reply = await api.SendMessageAsync("What is 2 + 2?");
Console.WriteLine(reply);
// Output: 2 + 2 equals 4.
await api.SendMessageAsync("My name is Alice.");
string reply2 = await api.SendMessageAsync("What is my name?");
Console.WriteLine(reply2);
// Output: Your name is Alice.
AsposeLLMApi.Create(preset) 返回一个会话感知的客户端。每次调用 SendMessageAsync 都会将提示追加到正在进行的对话中,因此您无需自行管理任何状态即可获得多轮交互行为。using 声明很重要——实例拥有本机资源,需要进行释放。
Note: 这些示例遵循官方 Aspose 文档,尚未在沙箱中执行。请在您自己的环境中验证后再发布。
单个请求的行为调优
对话式答案受益于一定的随机性。算术则不需要。与其重新配置实例,不如构建第二个预设并将其传递给需要的那个调用。
代码的作用
- 创建默认预设并像往常一样创建 API 实例。
- 使用低采样温度构建
strictPreset。 - 通过
preset参数将其传递给SendMessageAsync。 - 将后续调用保留在原始默认设置上。
using Aspose.LLM.Abstractions.Parameters.Presets;
// Default preset used by the API instance
var defaultPreset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(defaultPreset);
// A more deterministic preset, for this question only
var strictPreset = new Qwen25Preset();
strictPreset.SamplerParameters.Temperature = 0.1f;
string reply = await api.SendMessageAsync(
"What is the square root of 144?",
preset: strictPreset);
Console.WriteLine(reply);
// Output: The square root of 144 is 12.
SamplerParameters.Temperature 控制采样器引入的随机程度。接近 0.1 的值会产生近乎确定性的输出;更高的值会产生更为多样的措辞。由于预设范围仅限于本次调用,覆盖不会泄漏到对话的其余部分。
取消和超时
生成长度并非完全可预测,且运行时间较长的请求会阻塞所有等待它的操作。SendMessageAsync 接受一个 CancellationToken,因此请提供一个。
代码的作用
- 创建一个具有 30 秒预算的
CancellationTokenSource。 - 将
cts.Token传递给SendMessageAsync。 - 捕获
OperationCanceledException并优雅地降级。
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
string reply = await api.SendMessageAsync(
"Write a 500-word essay about migration patterns of the Arctic tern.",
cancellationToken: cts.Token);
Console.WriteLine(reply);
}
catch (OperationCanceledException)
{
Console.WriteLine("Generation timed out.");
}
取消操作会保留会话状态,因此对话在下一次调用时会正常继续。在 ASP.NET Core 处理程序中,也应转发请求自身的 RequestAborted 令牌——没有理由为已经断开的客户端继续生成。
完整的控制台应用程序
把它们组合起来:一个 REPL,在整个进程生命周期内保持一个会话活跃,并且能够从每条消息的失败中恢复。
代码的作用
- 在启动时设置许可证和默认预设一次。
- 为整个程序创建一个
AsposeLLMApi实例。 - 循环读取用户输入,直到用户输入
quit。 - 发送每一行并打印回复。
- 对每条消息捕获异常,以免一次失败导致会话结束。
using Aspose.LLM;
using Aspose.LLM.Abstractions.Parameters.Presets;
internal class SimpleChatDemo
{
public static async Task Main()
{
var license = new Aspose.LLM.License();
license.SetLicense("Aspose.LLM.lic");
var preset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(preset);
Console.WriteLine("Ask me anything. Type 'quit' to exit.");
while (true)
{
Console.Write("> ");
string? line = Console.ReadLine();
if (line == null || line.Equals("quit", StringComparison.OrdinalIgnoreCase))
break;
try
{
string reply = await api.SendMessageAsync(line);
Console.WriteLine(reply);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
}
有两个设计要点值得在实际应用中采用。首先,实例只创建 一次 并重复使用——创建成本高,而且正如下一节所述,不允许并发实例。其次,try-catch 放在循环内部而不是外部,这样单个错误消息只会导致一次循环,而不是整个会话。
使用来自 Aspose 临时许可证页面 的临时许可证评估库。
您可能首先遇到的错误
| Error | Typical cause | Remedy |
|---|---|---|
Not licensed for this method | 许可证文件缺失或路径错误 | 确认 Aspose.LLM.lic 可以从工作目录读取,并且在任何其他 API 调用之前运行 SetLicense。 |
Only one AsposeLLMApi instance can be created at a time | 同时存在两个实例,通常来自每请求的工厂 | 将实例注册为单例,或在创建新实例之前释放之前的实例。 |
| First response takes minutes | 引擎正在下载本机二进制文件和模型权重 | 在干净的机器上预计需要 5-15 分钟。将在启动期间触发 Create,以免将成本转嫁给用户。 |
第二行在服务场景中值得强调。如果您将 Aspose.LLM 接入 DI 容器,请将 AsposeLLMApi 注册为单例,并对其访问进行序列化——作用域或瞬态注册将在两个请求重叠时失败。
其他资源
结论
Aspose.LLM 将 “在此 .NET 应用程序中添加 LLM” 简化为三种类型和一种方法。许可证激活库,预设定义模型及其生成方式,AsposeLLMApi 实例承载对话。从那里,SendMessageAsync 处理单个问题、多轮会话、每次调用的参数覆盖,以及可取消的长时间生成。
首先使用控制台示例,确认模型的行为符合您的功能需求,然后在基础扎实后继续进行多会话和持久化工作。
FAQs
1. 什么是 Aspose.LLM for .NET?
一个 NuGet 库,可在您自己的 .NET 进程中运行大型语言模型推理。您可以创建预设,创建 API 实例,并发送提示——无外部服务,无 API 密钥。
2. 使用它是否需要互联网连接?
仅在第一次运行时。首次 Create 调用会下载预设定义的本机引擎和模型文件,随后这些资产会被本地缓存。
3. 代码示例的先决条件是什么?
Aspose.LLM NuGet 包、有效的 Aspose.LLM.lic 文件,以及足够的可用 RAM 以满足您选择的预设——对于 Qwen25,建议至少 8 GB。
4. 如何更改模型在单个请求中的行为?
构建第二个预设,调整其参数(例如 SamplerParameters.Temperature),并通过 preset 参数将其传递给 SendMessageAsync。后续调用将恢复为实例的默认预设。
5. 如何停止运行时间过长的生成?
将 CancellationToken 传递给 SendMessageAsync 并捕获 OperationCanceledException。会话状态在取消后仍然保留,因此对话会正常继续。
6. 为什么第一次响应如此缓慢?
第一次 Create 调用会下载本机二进制文件和模型权重,这在全新机器上可能需要 5‑15 分钟。请在应用程序启动时预热实例,而不是在用户的首次请求时进行预热。
