使用NestJS接入DeepSeek开放API及本地模型:从零到一的实践指南

概要

本文将简单介绍如何使用NestJS框架接入DeepSeek开放API,帮助开发者快速实现API集成。文章将从NestJS项目初始化开始,逐步讲解如何申请开放apikey、调用SDK、实现普通接口请求以及SSE方式实现,另外扩展如何调用本地的Ollama模型。通过本文,读者将掌握如何利用NestJS接入deepseek的开放API。本文只是分享一下我的思路,只提供一个MVP代码示例,更多功能自行摸索尝试,有机会后续也会继续分享。如有错误之处,欢迎各位大佬评论区或私信讨论~

效果预览

一. 准备工作

首先,我们先在本地搭建一个nestjs项目

bash 复制代码
npm i -g @nestjs/cli
nest new [project name]

详细过程不再展开

第二步:我们去deepseek开放平台注册账号,并申请apikey,一定要保存好,他这里只展示这一次,忘记了就需要重新创建了

这里需要实名认证,并充值,deepseek的开放接口定价还是挺便宜的

模型&价格细节

以上都完成申请完成后可以在这里管理你的apikey

恭喜,到这里你已经完成了全部的前置准备工作


二、代码编写

创建deepseek模块,可以随意起名

bash 复制代码
nest g res deepseek

// 安装`openai`模块
pnpm add openai

目录结构如下

编写接口,我们实现两种方式:

ts 复制代码
// deepseek.controller.ts
import { Body, Controller, HttpCode, Post, Query, Sse } from '@nestjs/common';
import { DeepseekService } from './deepseek.service';

@Controller('deepseek')
export class DeepseekController {
  constructor(private readonly deepseekService: DeepseekService) {}

  @Post()
  @HttpCode(200)
  // 定义一个名为 getHello 的方法,该方法接收一个名为 msg 的字符串参数
  getHello(@Body('msg') msg: string) {
    // 调用 deepseekService 的 generate 方法,并将 msg 作为参数传递给它
    // generate 方法会根据传入的 msg 生成一些内容,并将其作为返回值返回
    return this.deepseekService.generate(msg);
  }

  @Sse()
  // 定义一个名为 sse 的方法,该方法接收一个查询参数 msg,并返回一个结果
  sse(@Query('msg') msg: string) {
    // 调用 deepseekService 服务的 sse 方法,并将查询参数 msg 作为参数传递
    // 然后将 deepseekService.sse 方法的返回值作为当前方法的返回值
    return this.deepseekService.sse(msg);
  }
}
ts 复制代码
// deepseek.service.ts
import { Injectable } from '@nestjs/common';

import OpenAI from 'openai';
import { from, map } from 'rxjs';

const openai = new OpenAI({
  baseURL: 'https://api.deepseek.com',
  apiKey: 'sk-xxxxxxxxx',
});

@Injectable()
export class DeepseekService {
  // 定义一个异步函数 generate,接收一个字符串参数 msg,默认值为 '你是谁?'
  async generate(msg: string = '你是谁?') {
    // 调用 openai 的 chat.completions.create 方法,生成聊天回复
    // 传入的参数是一个对象,包含 messages、model 和 stream 三个属性
    // messages 是一个数组,包含一个对象,表示用户的提问,role 为 'user',content 为传入的 msg 参数
    // model 指定使用的模型为 'deepseek-chat'
    // stream 设置为 false,表示不使用流式响应
    const completions = await openai.chat.completions.create({
      messages: [{ role: 'user', content: msg }],
      model: 'deepseek-chat',
      stream: false,
    });
    // 打印生成的回复对象
    console.log('completions', completions);

    return completions.choices[0].message?.content;
  }

  // 定义一个异步函数 sse,接收一个字符串参数 msg,默认值为 '你是谁?'
  async sse(msg: string = '你是谁?') {
    // 使用 openai 的 chat.completions.create 方法创建一个聊天完成请求
    // 请求参数包括消息数组(包含用户角色和内容),使用的模型,以及是否开启流式响应
    const response = await openai.chat.completions.create({
      messages: [{ role: 'user', content: msg }], // 消息数组,包含一个用户角色和内容
      model: 'deepseek-chat', // 使用的模型名称
      stream: true, // 开启流式响应
    });

    // 初始化一个空字符串数组 res,用于存储每一部分的响应内容
    const res: string[] = [];
    // 返回一个 Observable 对象,通过 from 操作符将 response 转换为可观察对象
    // 然后使用 pipe 操作符进行一系列操作
    return from(response).pipe(
      // 使用 map 操作符对每一部分响应进行处理
      map((part) => {
        // 将当前部分的 delta 内容(如果存在)添加到 res 数组中,否则添加空字符串
        res.push(part.choices[0].delta?.content || '');
        // 将 res 数组中的所有内容连接成一个字符串并返回
        return res.join('');
      }),
    );
  }
}

调用方式:

  1. 使用post请求调用:调用nestjs服务,我的是启动在3333端口,并且全局添加了/api前缀
  1. 使用SSE,这个需要特别说明一下,直接使用get请求localhost:3333/api/deepseek?msg=你是谁?地址,但是这样子直接发起请求是不行的,还需要设置一下请求头Content-Typetext/event-stream,这时候就可以了,效果就是文章开头的效果预览

至此,我们使用nestjs调用deepseek开放API的功能就已经实现了


三、调用本地的Ollama本地大语言模型

其实这种方式只适合自己本地玩玩,本机部署的大模型想让公网能够访问,需要配置内网穿透,具体这里不再展开,感兴趣的自行了解

下面说说如何调用本地的大模型,直接上代码

bash 复制代码
// 安装SDK
pnpm add ollama

至于如何本地部署本地大模型,不再赘述,最近很多文章都有讲

ts 复制代码
// ollama.service.ts
import { Injectable } from '@nestjs/common';
import { Message, Ollama } from 'ollama';
import { from, map } from 'rxjs';

const ollama = new Ollama({ host: 'http://127.0.0.1:11434' });

@Injectable()
export class OllamaService {
  // 定义一个异步函数chat,用于与聊天模型进行对话
  async chat(prompt: string = 'who are you?') {
    // 初始化消息数组,默认用户输入为'who are you?'
    const messages: Message[] = [{ role: 'user', content: prompt }];

    // 调用ollama的chat方法,传入模型名称、消息数组和流模式
    const response = await ollama.chat({
      model: 'deepseek-r1:1.5b', // 指定使用的模型名称
      messages, // 传入的消息数组
      stream: true, // 启用流模式,以便实时获取响应
    });

    // 初始化一个空数组,用于存储每部分的消息内容
    const res: string[] = [];

    // 返回一个Observable对象,通过from操作符将response转换为Observable
    return from(response).pipe(
      // 使用map操作符处理每一部分的数据
      map((part) => {
        res.push(part.message.content); // 将每部分的消息内容添加到res数组中
        return res.join(''); // 将res数组中的所有消息内容连接成一个字符串并返回
      }),
    );
  }
}
ts 复制代码
// ollama.controller.ts
import { Controller, Query, Sse } from '@nestjs/common';
import { OllamaService } from './ollama.service';

@Controller('ollama')
export class OllamaController {
  constructor(private readonly ollamaService: OllamaService) {}
  @Sse('chat')
  // 定义一个名为chat的方法,该方法接收一个Query参数
  chat(@Query() query: Record<string, any>) {
    // 在控制台打印出'ollama controller'和传入的query参数
    console.log('ollama controller', query);
    // 调用this.ollamaService的chat方法,传入query.msg的值,如果query.msg不存在则传入undefined
    return this.ollamaService.chat(query.msg || undefined);
  }
}

效果预览

四. 总结

  • 本文主要介绍了如何在本地通过nestjs启动一个服务,并使用openaiSDK调用deepseek开放API,以及使用ollamaSDK调用本地大语言模型
  • 本文没有深入介绍nestjs相关的其他细节内容,也未扩展讲本地部署大模型的步骤,更多细节及更多完整功能的实现欢迎大家讨论

NOTE:文中的代码注释均由VsCode CodeGeeX插件生成,这个时代,谁还自己写注释 /dog 🐶

相关推荐
机器之心9 小时前
27、42、73,DeepSeek这些大模型竟都喜欢这些数!为什么?
人工智能·deepseek
三花AI11 小时前
Midjourney V1视频模型每月10美元起
deepseek
海拥12 小时前
从零搭建AI Agent:DeepSeek-V3商用+Dify部署全流程实战
deepseek
—Qeyser1 天前
让 Deepseek 写电器电费计算器(html版本)
前端·javascript·css·html·deepseek
Jeesoul2 天前
【springboot集成各类大模型】支持讯飞星火、通义千问、ChatGPT、和DeepSeek等
人工智能·spring boot·开源·大模型·讯飞星火·千问·deepseek
量子位2 天前
性能比肩 DeepSeek-R1,MiniMax 仅花 380 万训出推理大模型性价比新王|开源
deepseek
顾林海2 天前
DeepSeek 技术原理详解
深度学习·llm·deepseek
机器之心3 天前
刚刚,LMArena最新模型榜单出炉!DeepSeek-R1网页编程能力赶超了Claude Opus 4
人工智能·deepseek
陈佬昔没带相机4 天前
基于 open-webui 搭建企业级知识库
人工智能·ollama·deepseek
Jet45054 天前
玩转ChatGPT:DeepSeek实战(核酸蛋白序列核对)
人工智能·chatgpt·kimi·deepseek