在人工智能飞速发展的当下,大语言模型如 DeepSeek 正掀起新一轮的技术变革浪潮,为自然语言处理领域带来了诸多创新应用。随着数据隐私和安全意识的提升,以及对模型部署灵活性的追求,本地部署 DeepSeek 成为众多开发者和企业关注的焦点。
对于 C# 开发者而言,将 DeepSeek 模型本地部署并集成到 C# 项目中,不仅能充分发挥 C# 语言在 Windows 平台开发的优势,还能实现高度定制化的人工智能应用,无论是开发智能客服、文本生成工具,还是集成到企业内部系统,都能极大提升效率和用户体验。本文将带领大家一步步完成 DeepSeek 的本地部署,并详细介绍如何使用 C# 调用其 API,让你轻松开启属于自己的 AI 开发之旅 。
DeepSeek 模型有多个不同规模的版本,从参数较少的轻量级版本到参数众多的大规模版本,不同版本对硬件的要求差异较大。以下是一些常见规模模型的硬件参考配置:
DeepSeek-R1-1.5B:
DeepSeek-R1-8B:
DeepSeek-R1-32B:
在选择硬件时,要综合考虑自己的实际需求和预算。如果只是进行简单的测试和学习,较低配置的硬件即可;若是用于企业级应用或对性能要求较高的场景,则需要配备高性能的硬件。同时,还需注意硬件之间的兼容性,确保整个系统能够稳定运行 。
Ollama:
Page Assist 浏览器插件:
C# 开发环境:
curl -fsSL https://ollama.com/install.sh | sh
安装注意事项:
安装前务必确保系统磁盘空间充足,特别是 C 盘(对于 Windows 系统默认安装情况),因为 Ollama 及其下载的模型文件可能会占用较大空间。
在安装过程中,若遇到权限不足等问题,对于 Windows 系统,以管理员身份运行安装程序或命令;对于 Linux 系统,可使用 sudo 命令获取管理员权限。
安装完成后,如果 Ollama 没有自动启动,可手动打开命令提示符(Windows)、终端(macOS 或 Linux),输入 “ollama serve” 命令启动 Ollama 服务 。
打开命令提示符(Windows)、终端(macOS 或 Linux),确保 Ollama 服务已经启动(若未启动,输入 “ollama serve” 命令启动)。
访问 Ollama 的模型库页面https://ollama.ai/library ,在搜索框中输入 “deepseek” ,即可找到 DeepSeek 相关模型。
根据自己的硬件配置选择合适的 DeepSeek 模型版本:
选择好模型后,复制模型的下载命令(一般为 “ollama pull deepseek - r1: 版本号” ,例如 “ollama pull deepseek - r1:1.5b” )。
将复制的命令粘贴到命令提示符或终端中,按下回车键执行。此时,Ollama 会自动从远程仓库下载所选的 DeepSeek 模型,下载过程中会显示下载进度和速度等信息。由于模型文件较大,下载时间可能较长,请耐心等待。下载完成后,模型会自动安装到 Ollama 的默认模型存储路径(对于 Windows 系统,默认路径为 C:\Users\ 用户名.ollama\models ;对于 macOS 和 Linux 系统,默认路径为~/.ollama/models )。若想更改模型存储路径,可通过设置环境变量 “OLLAMA_MODELS” 来实现,具体方法为:在系统环境变量中新建一个变量,变量名为 “OLLAMA_MODELS” ,变量值为你希望的存储路径 。
ollama run deepseek - r1:版本号
将 “版本号” 替换为你实际下载的 DeepSeek 模型版本(如 “1.5b”“8b” 等)。按下回车键后,进入模型交互界面,此时输入一些简单的问题,如 “你好,今天天气怎么样?” ,如果模型能够正常回答你的问题,则说明 DeepSeek 模型部署成功。例如:
ollama run deepseek - r1:1.5b
> 你好,今天天气怎么样?
DeepSeek - R1 - 1.5B:很抱歉,我无法获取实时天气信息,但你可以通过天气预报类的应用或网站来了解具体的天气情况。
{
"models": [
{
"name": "deepseek - r1:1.5b",
"id": "xxxxxxxxxxxx",
"parameters": {
"dim": 2048,
"n_heads": 32,
"n_layers": 32,
"norm_eps": 1e - 06,
"vocab_size": 65024
},
"modelfile": "xxxxxxxxxxxx",
"format": "gguf",
"size": "1.37 GB",
"modified": "2024 - 07 - 15T10:30:00Z"
}
]
}
通过以上两种方式的验证,若都能得到预期的结果,就说明 DeepSeek 模型在本地已经成功部署,可以进行后续的开发和应用了 。
打开项目:在 Visual Studio 中,打开你要集成 DeepSeek API 的 C# 项目。如果是新建项目,在创建项目时选择合适的项目模板,如 “控制台应用程序”(用于简单的测试和学习)、“ASP.NET Core Web 应用程序”(用于开发 Web 服务来调用 API)等。
打开 NuGet 包管理器:在 Visual Studio 的菜单栏中,选择 “项目” -> “管理 NuGet 程序包” ,这将打开 NuGet 包管理器窗口。
搜索并安装 OllamaSharp:在 NuGet 包管理器窗口中,切换到 “浏览” 选项卡,在搜索框中输入 “OllamaSharp” ,然后在搜索结果中找到 “OllamaSharp” 包,点击 “安装” 按钮。此时,Visual Studio 会自动下载并安装 OllamaSharp 及其依赖项。在安装过程中,你可能会看到一些提示信息,如许可证接受提示等,按照提示操作即可。安装完成后,你可以在项目的 “依赖项” -> “NuGet” 中看到 “OllamaSharp” 包,表明安装成功 。
以下是一个使用 C# 调用 DeepSeek API 进行提问并获取回答的示例代码:
using Microsoft.AspNetCore.Mvc;
using OllamaSharp;
using System.Threading.Tasks;
namespace DeepSeekAPIDemo.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class DeepSeekController : ControllerBase
{
private readonly Uri _modelEndpoint = new Uri("http://localhost:11434");
private readonly string _modelName = "deepseek-r1:8b";//根据实际下载的模型版本修改
[HttpPost("ask")]
public async Task AskQuestion([FromBody] string question)
{
if (string.IsNullOrEmpty(question))
{
return BadRequest("请输入您的问题");
}
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
var response = responseBuilder.ToString();
return Ok(new { Response = response });
}
}
}
代码关键部分解释:
private readonly Uri _modelEndpoint = new Uri("http://localhost:11434");
private readonly string _modelName = "deepseek-r1:8b";
_modelEndpoint定义了 Ollama 服务的地址,默认是本地的 11434 端口;_modelName指定了要使用的 DeepSeek 模型版本,这里是 “deepseek - r1:8b” ,请根据实际下载的模型版本进行修改。
[HttpPost("ask")]
public async Task AskQuestion([FromBody] string question)
这是一个 HTTP POST 请求接口,名为 “ask”,接受一个字符串类型的问题作为请求体。
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
var response = responseBuilder.ToString();
return Ok(new { Response = response });
首先创建一个OllamaApiClient实例,用于与 Ollama 服务进行通信。然后使用GetStreamingResponseAsync方法以流式方式获取模型对问题的回答,将每次获取到的响应追加到responseBuilder中,最后将完整的响应返回给客户端 。
运行项目:在 Visual Studio 中,点击工具栏上的 “启动” 按钮(绿色三角形图标),或者按下 F5 键,启动项目。如果是 Web 项目,Visual Studio 会自动启动一个本地 Web 服务器,并打开浏览器访问项目的 URL(例如http://localhost:5000 ,具体端口号可能因项目配置而异)。
测试调用:使用工具(如 Postman)向http://localhost:5000/api/DeepSeek/ask(假设项目端口为 5000,控制器名为 DeepSeek)发送 POST 请求,在请求体中输入要提问的问题,例如 “介绍一下人工智能的发展历程” ,然后点击 “发送” 按钮。
分析结果:如果一切正常,你将在 Postman 的响应窗口中看到 DeepSeek 模型返回的回答。例如:
{
"Response": "人工智能的发展历程可以追溯到20世纪50年代。在1956年,达特茅斯会议正式确立了“人工智能”这一术语,标志着人工智能作为一个独立的研究领域诞生。早期的人工智能主要集中在符号推理和专家系统的研究……"
}
[ApiController]
[Route("api/ai")]
public class AIController : ControllerBase
{
private readonly Uri _modelEndpoint = new Uri("http://localhost:11434");
private readonly string _modelName = "deepseek-r1:8b";
[HttpPost("ask")]
public async Task AskQuestion([FromBody] string question)
{
if (string.IsNullOrEmpty(question))
{
return BadRequest("请输入您的问题");
}
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
var response = responseBuilder.ToString();
return Ok(new { Response = response });
}
}
这样,前端应用可以通过 HTTP POST 请求到/api/ai/ask端点,将用户的问题发送给后端,后端调用 DeepSeek 模型获取回答后返回给前端。
public class AIViewModel
{
public string Question { get; set; }
public string Answer { get; set; }
}
public class AIController : Controller
{
private readonly Uri _modelEndpoint = new Uri("http://localhost:11434");
private readonly string _modelName = "deepseek-r1:8b";
public IActionResult Index()
{
return View(new AIViewModel());
}
[HttpPost]
public async Task Index(AIViewModel model)
{
if (ModelState.IsValid)
{
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(model.Question))
{
responseBuilder.Append(update.ToString());
}
model.Answer = responseBuilder.ToString();
return View(model);
}
return View(model);
}
}
在视图中,使用 HTML 表单收集用户问题,并显示模型回答:
@model AIViewModel
@{
ViewBag.Title = "AI交互";
}
AI交互
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.Question, "请输入问题")
@Html.TextBoxFor(m => m.Question, new { @class = "form-control" })
if (!string.IsNullOrEmpty(Model.Answer))
{
回答:
@Model.Answer
}
}
private async void btnAsk_Click(object sender, EventArgs e)
{
string question = textBoxQuestion.Text;
if (string.IsNullOrEmpty(question))
{
MessageBox.Show("请输入问题");
return;
}
var _modelEndpoint = new Uri("http://localhost:11434");
var _modelName = "deepseek-r1:8b";
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
string response = responseBuilder.ToString();
textBoxAnswer.Text = response;
}
在代码背后文件中编写点击事件处理方法:
private async void btnAsk_Click(object sender, RoutedEventArgs e)
{
string question = txtQuestion.Text;
if (string.IsNullOrEmpty(question))
{
MessageBox.Show("请输入问题");
return;
}
var _modelEndpoint = new Uri("http://localhost:11434");
var _modelName = "deepseek-r1:8b";
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
string response = responseBuilder.ToString();
txtAnswer.Text = response;
}
在代码背后文件中编写点击事件处理方法:
private async void btnAsk_Click(object sender, EventArgs e)
{
string question = entryQuestion.Text;
if (string.IsNullOrEmpty(question))
{
await DisplayAlert("提示", "请输入问题", "确定");
return;
}
var _modelEndpoint = new Uri("http://localhost:11434");
var _modelName = "deepseek-r1:8b";
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
string response = responseBuilder.ToString();
labelAnswer.Text = response;
}
需要注意的是,在移动应用中调用本地 API 时,可能需要处理网络权限和跨域问题,确保应用能够正常访问本地的 Ollama 服务 。
private static MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
public async Task AskQuestion([FromBody] string question)
{
if (string.IsNullOrEmpty(question))
{
return BadRequest("请输入您的问题");
}
if (_cache.TryGetValue(question, out string cachedAnswer))
{
return Ok(new { Response = cachedAnswer });
}
var _modelEndpoint = new Uri("http://localhost:11434");
var _modelName = "deepseek-r1:8b";
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
string response = responseBuilder.ToString();
_cache.Set(question, response, TimeSpan.FromMinutes(30));//缓存30分钟
return Ok(new { Response = response });
}
private static Lazy _lazyConnection = new Lazy(() =>
{
return ConnectionMultiplexer.Connect("localhost:6379");
});
private static IDatabase _cache = _lazyConnection.Value.GetDatabase();
public async Task AskQuestion([FromBody] string question)
{
if (string.IsNullOrEmpty(question))
{
return BadRequest("请输入您的问题");
}
RedisValue cachedAnswer = _cache.StringGet(question);
if (!cachedAnswer.IsNullOrEmpty)
{
return Ok(new { Response = cachedAnswer });
}
var _modelEndpoint = new Uri("http://localhost:11434");
var _modelName = "deepseek-r1:8b";
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
string response = responseBuilder.ToString();
_cache.StringSet(question, response, TimeSpan.FromMinutes(30));//缓存30分钟
return Ok(new { Response = response });
}
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(question))
{
responseBuilder.Append(update.ToString());
}
var questions = new[] { "问题1", "问题2", "问题3" };
var tasks = new List>();
var chatClient = new OllamaApiClient(_modelEndpoint, _modelName);
foreach (var q in questions)
{
tasks.Add(Task.Run(async () =>
{
var responseBuilder = new System.Text.StringBuilder();
await foreach (var update in chatClient.GetStreamingResponseAsync(q))
{
responseBuilder.Append(update.ToString());
}
return responseBuilder.ToString();
}));
}
var results = await Task.WhenAll(tasks);
在部署和调用 DeepSeek 的过程中,可能会遇到各种各样的问题,以下是一些常见问题及对应的解决方案:
问题:模型下载速度过慢甚至无法下载。
问题:模型加载失败,提示 “error loading model: unable to allocate CUDA_Host buffer” 。
问题:在 ChatBox 中无法找到已下载的模型。
问题:API 调用报错,提示 “Error: Post “http://127.0.0.1:11434/api/show”: dial tcp 127.0.0.1:11434: connectex: No connection could be made because the target machine actively refused it” 。
问题:API 调用返回乱码或错误的响应内容。
问题:模型推理速度过慢,响应时间长。
问题:部署过程中出现 “CUDA 版本不兼容导致编译失败” 。
通过上述步骤,我们成功地在本地完成了 DeepSeek 模型的部署,并实现了使用 C# 语言调用其 API 的功能。从前期对硬件和软件的细致准备,到一步步完成 Ollama 的安装、DeepSeek 模型的下载与部署,再到搭建 C# 开发环境、安装依赖包并编写示例代码进行调用,每一个环节都为我们构建高效的私有 AI 服务奠定了坚实基础。
在这个过程中,我们深刻体会到了本地部署 DeepSeek 的显著优势。它不仅能够有效保障数据的隐私与安全,避免数据在云端传输和存储过程中可能面临的泄露风险,还赋予了我们更高的自主性和灵活性,使我们可以根据实际需求对模型进行定制化开发和优化。无论是将其集成到现有的 Web 应用、桌面应用还是移动应用中,DeepSeek 都展现出了强大的自然语言处理能力,为用户提供了智能化的交互体验,极大地拓展了应用的功能边界和价值。
展望未来,随着 C# 生态系统的不断发展壮大以及 DeepSeek 模型的持续优化升级,我们有理由期待在 C# 开发中应用 DeepSeek 会取得更加丰硕的成果。在实际项目中,我们可以进一步探索如何将 DeepSeek 与其他先进技术,如机器学习、计算机视觉等进行深度融合,打造出更加智能、多元化的应用场景。例如,结合图像识别技术,实现对图片内容的智能描述和分析;融合机器学习算法,进行个性化的用户行为预测和推荐。
同时,希望广大读者能够基于本文的基础,积极探索更多的应用可能性。可以尝试对现有示例代码进行优化和扩展,开发出更具创新性的功能。也可以将 DeepSeek 应用到不同的行业领域中,如医疗、金融、教育等,为解决实际业务问题提供新的思路和方法。相信在不断的实践和探索中,我们能够充分挖掘 DeepSeek 的潜力,为人工智能的发展贡献自己的力量,创造出更多具有价值和影响力的应用 。