🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

本地模型服务 wertyBSd/dsh-local-llm

DeepSeek Harness
wertyBSd69 天前有提交已提供中文文档扫描:高危

下载并运行本地 GGUF 模型,为对话提供推理服务

28.4/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/18 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add wertyBSd/dsh-local-llm
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · desktop
装得上吗
实装验证未通过(dependency_conflict),装前请到仓库确认最近更新与 issue
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 69 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(dependency_conflict · 2026/9/26) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

安装时即执行脚本可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 98 处,展示前 92 条)
  • 发起网络请求
    dist/index.js:118
    const response = await fetch(healthUrl, { signal });
  • 读取本地文件
    dist/index.js:487
    if (!selectedPath || !fs.existsSync(selectedPath)) {
  • 发起网络请求
    dist/index.js:499
    const response = await fetch(`${runtimeUrl.replace(/ $/, '')}/v1/chat/completions`, {
  • 读取本地文件
    dist/index.js:525
    return fs.statSync(filePath).size;
  • 发起网络请求
    dist/client.js:1
    (()=>{"use strict";var e={139(e,r,o){var n=o(601),l=o.n(n),t=o(314),a=o.n(t)()(l());a.push([e.id,".dsh-local-llm-ui {\n color: #cdd6f4;\n}\n\n.dsh-lo
  • 读取本地文件
    scripts/copy-presets.js:9
    if (fs.existsSync(sourcePresets)) {
  • 读取本地文件
    scripts/copy-presets.js:10
    if (!fs.existsSync(targetPresets)) {
  • 写入本地文件
    scripts/copy-presets.js:11
    fs.mkdirSync(targetPresets, { recursive: true });
  • 读取本地文件
    scripts/copy-presets.js:15
    const presets = fs.readdirSync(sourcePresets);
  • 读取本地文件
    scripts/copy-presets.js:19
    if (fs.statSync(source).isDirectory()) {
  • 读取本地文件
    dist/downloader.js:11
    if (!fs.existsSync(downloadDir)) {
  • 写入本地文件
    dist/downloader.js:12
    fs.mkdirSync(downloadDir, { recursive: true });
  • 读取本地文件
    dist/downloader.js:22
    if (fs.existsSync(modelPath)) {
  • 写入本地文件
    dist/downloader.js:111
    const file = fs.createWriteStream(temporaryPath);
  • 删除本地文件
    dist/downloader.js:123
    fs.unlink(temporaryPath, () => { });
  • 写入本地文件
    dist/downloader.js:127
    fs.rename(temporaryPath, dest, (renameError) => {
  • 删除本地文件
    dist/downloader.js:129
    fs.unlink(temporaryPath, () => { });
  • 删除本地文件
    dist/downloader.js:138
    fs.unlink(temporaryPath, () => { });
  • 删除本地文件
    dist/downloader.js:143
    fs.unlink(temporaryPath, () => { });
  • 读取本地文件
    dist/downloader.js:156
    return fs.existsSync(modelPath);
  • 读取本地文件
    dist/downloader.js:162
    if (!fs.existsSync(this.downloadDir)) {
  • 读取本地文件
    dist/downloader.js:165
    return fs.readdirSync(this.downloadDir).filter(file => file.endsWith('.gguf'));
  • 读取本地文件
    dist/downloader.js:172
    if (!fs.existsSync(modelPath)) {
  • 删除本地文件
    dist/downloader.js:175
    fs.unlinkSync(modelPath);
  • 写入本地文件
    dist/server-manager.js:17
    fs.mkdirSync(this.serverDir, { recursive: true });
  • 删除本地文件
    dist/server-manager.js:41
    fs.rmSync(this.serverDir, { recursive: true, force: true });
  • 写入本地文件
    dist/server-manager.js:42
    fs.mkdirSync(this.serverDir, { recursive: true });
  • 删除本地文件
    dist/server-manager.js:52
    fs.rmSync(archivePath, { force: true });
  • 写入本地文件
    dist/server-manager.js:56
    fs.writeFileSync(path.join(this.serverDir, BUILD_METADATA_FILE), JSON.stringify({ build }, null, 2));
  • 读取本地文件
    dist/server-manager.js:74
    if (!fs.existsSync(modelPath))
  • 执行外部命令来自配置/变量
    dist/server-manager.js:82
    this.process = spawn(executable, [
  • 删除本地文件
    dist/server-manager.js:133
    fs.rmSync(this.serverDir, { recursive: true, force: true });
  • 写入本地文件
    dist/server-manager.js:134
    fs.mkdirSync(this.serverDir, { recursive: true });
  • 读取本地文件
    dist/server-manager.js:182
    for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
  • 读取本地文件
    dist/server-manager.js:195
    const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
  • 读取本地文件
    dist/server-manager.js:206
    return fs.existsSync(versionPath) ? fs.readFileSync(versionPath, 'utf8').trim() : undefined;
  • 执行外部命令来自配置/变量
    dist/server-manager.js:223
    const child = spawn(command, args, { stdio: 'ignore', windowsHide: true });
  • 发起网络请求
    dist/server-manager.js:240
    https.get(url, { headers: { 'User-Agent': 'dsh-local-llm' } }, response => {
  • 发起网络请求
    dist/server-manager.js:263
    https.get(url, { headers: { 'User-Agent': 'dsh-local-llm' } }, response => {
  • 写入本地文件
    dist/server-manager.js:276
    const file = fs.createWriteStream(temporary);
  • 写入本地文件
    dist/server-manager.js:286
    fs.rename(temporary, destination, renameError => renameError ? reject(renameError) : resolve());
  • 删除本地文件
    dist/server-manager.js:288
    file.on('error', error => { fs.rmSync(temporary, { force: true }); reject(error); });
  • 删除本地文件
    dist/server-manager.js:289
    response.on('error', error => { file.destroy(); fs.rmSync(temporary, { force: true }); reject(error); });
  • 发起网络请求
    dist/client-entry.js:109
    const response = await fetch('/api/local-llm/models');
  • 发起网络请求
    dist/client-entry.js:124
    const response = await fetch('/api/local-llm/server/status');
  • 发起网络请求
    dist/client-entry.js:153
    const response = await fetch('/api/local-llm/server/install', {
  • 发起网络请求
    dist/client-entry.js:180
    const response = await fetch(`/api/local-llm/server/${server?.running ? 'stop' : 'start'}`, {
  • 发起网络请求
    dist/client-entry.js:208
    const response = await fetch('/api/local-llm/server/uninstall', { method: 'POST' });
  • 发起网络请求
    dist/client-entry.js:239
    const response = await fetch('/api/local-llm/download', {
  • 发起网络请求
    src/client-entry.ts:141
    const response = await fetch('/api/local-llm/models')
  • 发起网络请求
    src/client-entry.ts:157
    const response = await fetch('/api/local-llm/server/status')
  • 发起网络请求
    src/client-entry.ts:184
    const response = await fetch('/api/local-llm/server/install', {
  • 发起网络请求
    src/client-entry.ts:208
    const response = await fetch(`/api/local-llm/server/${server?.running ? 'stop' : 'start'}`, {
  • 发起网络请求
    src/client-entry.ts:232
    const response = await fetch('/api/local-llm/server/uninstall', { method: 'POST' })
  • 发起网络请求
    src/client-entry.ts:258
    const response = await fetch('/api/local-llm/download', {
  • 读取本地文件
    src/downloader.ts:21
    if (!fs.existsSync(downloadDir)) {
  • 写入本地文件
    src/downloader.ts:22
    fs.mkdirSync(downloadDir, { recursive: true })
  • 读取本地文件
    src/downloader.ts:34
    if (fs.existsSync(modelPath)) {
  • 写入本地文件
    src/downloader.ts:139
    const file = fs.createWriteStream(temporaryPath)
  • 删除本地文件
    src/downloader.ts:154
    fs.unlink(temporaryPath, () => {})
  • 写入本地文件
    src/downloader.ts:158
    fs.rename(temporaryPath, dest, (renameError) => {
  • 删除本地文件
    src/downloader.ts:160
    fs.unlink(temporaryPath, () => {})
  • 删除本地文件
    src/downloader.ts:170
    fs.unlink(temporaryPath, () => {})
  • 删除本地文件
    src/downloader.ts:176
    fs.unlink(temporaryPath, () => {})
  • 读取本地文件
    src/downloader.ts:190
    return fs.existsSync(modelPath)
  • 读取本地文件
    src/downloader.ts:197
    if (!fs.existsSync(this.downloadDir)) {
  • 读取本地文件
    src/downloader.ts:200
    return fs.readdirSync(this.downloadDir).filter(file =>
  • 读取本地文件
    src/downloader.ts:210
    if (!fs.existsSync(modelPath)) {
  • 删除本地文件
    src/downloader.ts:213
    fs.unlinkSync(modelPath)
  • 发起网络请求
    src/index.ts:184
    const response = await fetch(healthUrl, { signal })
  • 读取本地文件
    src/index.ts:537
    if (!selectedPath || !fs.existsSync(selectedPath)) {
  • 发起网络请求
    src/index.ts:549
    const response = await fetch(`${runtimeUrl.replace(/ $/, '')}/v1/chat/completions`, {
  • 读取本地文件
    src/index.ts:578
    return fs.statSync(filePath).size
  • 写入本地文件
    src/server-manager.ts:53
    fs.mkdirSync(this.serverDir, { recursive: true })
  • 删除本地文件
    src/server-manager.ts:77
    fs.rmSync(this.serverDir, { recursive: true, force: true })
  • 写入本地文件
    src/server-manager.ts:78
    fs.mkdirSync(this.serverDir, { recursive: true })
  • 删除本地文件
    src/server-manager.ts:88
    fs.rmSync(archivePath, { force: true })
  • 写入本地文件
    src/server-manager.ts:92
    fs.writeFileSync(path.join(this.serverDir, BUILD_METADATA_FILE), JSON.stringify({ build }, null, 2))
  • 读取本地文件
    src/server-manager.ts:108
    if (!fs.existsSync(modelPath)) throw new Error('Model file not found')
  • 执行外部命令来自配置/变量
    src/server-manager.ts:116
    this.process = spawn(executable, [
  • 删除本地文件
    src/server-manager.ts:166
    fs.rmSync(this.serverDir, { recursive: true, force: true })
  • 写入本地文件
    src/server-manager.ts:167
    fs.mkdirSync(this.serverDir, { recursive: true })
  • 读取本地文件
    src/server-manager.ts:216
    for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
  • 读取本地文件
    src/server-manager.ts:228
    const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8')) as { build?: unknown }
  • 读取本地文件
    src/server-manager.ts:239
    return fs.existsSync(versionPath) ? fs.readFileSync(versionPath, 'utf8').trim() : undefined
  • 执行外部命令来自配置/变量
    src/server-manager.ts:257
    const child = spawn(command, args, { stdio: 'ignore', windowsHide: true })
  • 发起网络请求
    src/server-manager.ts:271
    https.get(url, { headers: { 'User-Agent': 'dsh-local-llm' } }, response => {
  • 发起网络请求
    src/server-manager.ts:294
    https.get(url, { headers: { 'User-Agent': 'dsh-local-llm' } }, response => {
  • 写入本地文件
    src/server-manager.ts:307
    const file = fs.createWriteStream(temporary)
  • 写入本地文件
    src/server-manager.ts:315
    fs.rename(temporary, destination, renameError => renameError ? reject(renameError) : resolve())
  • 删除本地文件
    src/server-manager.ts:317
    file.on('error', error => { fs.rmSync(temporary, { force: true }); reject(error) })
  • 删除本地文件
    src/server-manager.ts:318
    response.on('error', error => { file.destroy(); fs.rmSync(temporary, { force: true }); reject(error) })
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/schemastery@deepseek-ai/dsh-llm
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 下载本地GGUF模型
  • 运行本地模型
  • 提供对话推理服务

DeepSeek Harness 本地 LLM 集成插件

README

由 DeepSeek 最新模型翻译生成
dsh-local-llm 一个 DeepSeek Harness 插件,用于管理本地 GGUF 模型并通过 llama-server 提供服务——无需 Ollama。 dsh plugin --profile web add https://github.com/wertyBSd/dsh-local-llm llama-server 运行时从插件 UI 下载,并且仅在用户点击启动按钮时启动。在服务器就绪之前发出的请求会返回明确的错误。 功能 - 从 Hugging Face 或直接 URL 下载 GGUF 模型。 - 搜索内置模型目录。 - 通过粘贴直接的 .gguf URL 添加任意模型。 - 显示已下载的模型和文件大小。 - 通过 SSE 将下载进度流式传输到 UI。 - 删除已下载的模型。 - 防止通过模型文件名进行路径遍历。 - 遵循 HTTP 重定向并清理未完成的下载。 - 对同一模型的并发下载进行去重。 - 为所选模型自动选择合适的上下文大小。 - 在发送请求之前检测 TinyLlama 是否无法容纳 Harness 提示词。 - 在侧边栏页脚提供 on/off 服务器指示器。 要求 - Node.js 18 或更高版本。 - 带有 llm 和 webServer 服务的 DeepSeek Harness。 - 用于文本生成的本地推理运行时。
展开完整文档(README 剩余 1 节)
dsh-local-llm

一个 DeepSeek Harness 插件,用于管理本地 GGUF 模型并通过 llama-server 提供服务——无需 Ollama。

dsh plugin --profile web add https://github.com/wertyBSd/dsh-local-llm

llama-server 运行时从插件 UI 下载,并且仅在用户点击启动按钮时启动。在服务器就绪之前发出的请求会返回明确的错误。

功能

- 从 Hugging Face 或直接 URL 下载 GGUF 模型。
- 搜索内置模型目录。
- 通过粘贴直接的 .gguf URL 添加任意模型。
- 显示已下载的模型和文件大小。
- 通过 SSE 将下载进度流式传输到 UI。
- 删除已下载的模型。
- 防止通过模型文件名进行路径遍历。
- 遵循 HTTP 重定向并清理未完成的下载。
- 对同一模型的并发下载进行去重。
- 为所选模型自动选择合适的上下文大小。
- 在发送请求之前检测 TinyLlama 是否无法容纳 Harness 提示词。
- 在侧边栏页脚提供 on/off 服务器指示器。

要求

- Node.js 18 或更高版本。
- 带有 llm 和 webServer 服务的 DeepSeek Harness。
- 用于文本生成的本地推理运行时。

@deepseek-ai/cordis 包提供 Cordis 运行时。llm 和 webServer 服务必须由 Harness 或其插件提供。

安装与构建

npm install
npm run build

宿主插件入口点是 dist/index.js。侧边栏客户端包是 dist/client.js。

包清单公开了 dsh.bundle 和 dsh.client。重启 Harness 后,插件会被加载到客户端图中。

dist/ 已提交到仓库(未被 gitignore),并且必须与 src/ 保持同步。当使用 pnpm dsh plugin --profile web add 安装 Harness 时,pnpm 的供应链策略会阻止对 git 托管的包运行 build/prepare 脚本,因此该插件以预构建形式发布。在推送更改之前,请始终运行 npm run build 并提交 dist/。

对于本地 Windows 安装,请运行:

Set-Location C:\git\dsh-local-llm
npm install
npm run build

Set-Location C:\git\deepseek-harness
pnpm dsh plugin --profile web add C:\git\dsh-local-llm
pnpm dsh --profile web --dump-config | Select-String dsh-local-llm

验证输出应包含 name: dsh-local-llm。完全停止任何正在运行的 Harness 进程,然后再次启动它:

pnpm dsh web

刷新浏览器页面是不够的,因为客户端插件图是在 web 配置文件启动时构建的。

开发命令:

npm run dev # watch TypeScript compilation
npm run dev:ui # watch UI build

配置

配置示例:

{
"model": "mistral-7b-instruct-v0.3-Q4_K_M.gguf",
"modelPath": "",
"runtimeUrl": "http://127.0.0.1:8080",
"contextSize": 8192,
"autoContextSize": true,
"port": 8080,
"downloadDir": "./models"
}

参数:
- model - 内置模型名称或 .gguf 文件的直接 URL。
- modelPath - 现有模型文件的路径。如果省略,配置的模型将自动下载。
- runtimeUrl - 兼容 OpenAI 的本地运行时(如 llama-server)的 URL。
- contextSize - 传递给 llama-server 的最小上下文大小,以 token 为单位。默认值为 8192。
- autoContextSize - 自动选择取决于模型的上下文大小。默认启用。
- port - 插件配置值;Harness Web 服务器拥有其 HTTP 端口。
- downloadDir - 模型目录。默认为 ./models。

内置模型名称包括:

- mistral-7b-instruct-v0.3-Q4_K_M.gguf;
- llama-3-8b-instruct-q4_K_M.gguf;
- deepseek-coder-6.7b-instruct-q4_K_M.gguf;
- qwen-2.5-7b-instruct-q4_K_M.gguf。

本地服务器

服务器不会自动下载或启动。打开 Local models,点击 Download and install server,等待安装完成,选择一个已下载的模型,然后点击 Start。该插件从官方 ggml-org/llama.cpp 发布版下载 llama-server,并将其绑定到 127.0.0.1。

服务器参数:

- serverDir - 二进制文件和日志目录。默认为 ./llama-server。
- serverUrl - 可选的直接服务器归档 URL。如果为空,则从最新的 GitHub 发布版中选择兼容的归档。
- serverBuild - 选择运行时构建:auto 优先使用 CUDA,并回退到 CPU;cuda 要求 CUDA 归档;cpu 强制使用非 CUDA 归档。默认为 auto。

模型管理器包含一个服务器构建选择器。在切换构建之前停止服务器,选择 CUDA、CPU 或 Automatic,然后点击 Install selected build。所选模式会持久化在浏览器中,已安装模式会记录在 serverDir 内的 server-build.json 中,因此该选择在 Harness 重启后仍然保留。从一个已安装构建切换到另一个构建会替换 serverDir 中的运行时文件。
- serverPort - llama-server 端口。默认为 8080。
- contextSize - 以 token 为单位的最小上下文大小。Harness 系统指令和工具可能需要更大的值;插件绝不会以低于 8192 token 启动托管服务器。
- autoContextSize - 启用时,常规模型至少使用 16384 token;TinyLlama 受其模型限制 2048 token 的约束。

当选择不同的模型时,服务器会自动重启,因此新模型的上下文大小会生效。活动上下文大小会包含在服务器状态中。服务器日志写入 llama-server/llama-server.log。

更改上下文设置或更新插件后,请停止并启动一次托管服务器,以便应用新的 --ctx-size 值。TinyLlama 报告可用上下文为 2048,因为这是其模型限制。适配器会估算请求大小,并在发送前拒绝过大的 Harness 提示。

打开模型管理器 UI

该插件向 Harness 侧边栏添加了两个入口点:
- 在 New session 之后立即放置一个 Local models 按钮。这需要本地 Harness shell 槽位 sidebar.after-new-session,而该槽位并非在每个 Harness 构建中都存在。
- 在侧边栏页脚中放置一个开/关指示器(sidebar.footer.action),该指示器始终可用。点击指示器本身即可打开相同的设置对话框。

如果你的构建中未出现 New session 按钮变体,请改为点击页脚指示器——两者都会打开相同的 Local models 对话框,其中包含模型下载、服务器控制和语言选择。

本地化

模型管理器支持英语、俄语、中文、法语、西班牙语、意大利语、波兰语、德语、印地语和日语。默认使用英语。所选语言存储在浏览器中,并应用于模型窗口、错误、服务器控制和 local models 指示器。

API

- GET /api/local-llm/models - 列出已下载的模型。
- POST /api/local-llm/download,请求体为 { "model": "model-file.gguf" } - 下载模型。
- GET /api/local-llm/progress?model=... - 以 SSE 形式接收下载进度。
- POST /api/local-llm/delete,请求体为 { "model": "model-file.gguf" } - 删除模型。
- GET /api/local-llm/server/status - 获取服务器状态。
- POST /api/local-llm/server/install - 下载并解压服务器。
- POST /api/local-llm/server/start,请求体为 { "model": "model-file.gguf" } - 使用模型启动服务器。
- POST /api/local-llm/server/stop - 停止服务器。

Harness 集成

该插件在可配置的提供程序目录中注册 local-llm,并通过 registerAdapter(['local-llm'], ...) 激活它。重启 web profile 后,该提供程序将出现在 Harness 模型选择器中。

适配器向 ${runtimeUrl}/v1/chat/completions 发送流式请求。如果 runtimeUrl 为空,则使用插件在 http://127.0.0.1:8080 启动的服务器。Harness 工具会被转换为 OpenAI function-tool 格式,适配器在发送请求前会等待 /health。

可选的、紧跟在 New session 之后的侧边栏位置需要本地 DeepSeek Harness shell 槽位 sidebar.after-new-session。如果没有该本地 shell 补丁,该插件仍与标准页脚操作槽位兼容。

已知限制

- 内置目录使用固定的 Hugging Face URL。
- 下载的文件不会根据校验和进行验证。
- SSE 行为取决于 DeepSeek Harness web 服务器的实现。
- 在服务器安装、启动并准备就绪之前,文本生成不可用。

许可证

MIT
预览分享卡片长什么样 ↓wertyBSd/dsh-local-llm
分享 · DeepSeek Harness Hub
wertyBSd/dsh-local-llm

下载并运行本地 GGUF 模型,为对话提供推理服务

这是你的仓库?认领条目

回到顶部