下载并运行本地 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预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
wertyBSd/dsh-local-llm
下载并运行本地 GGUF 模型,为对话提供推理服务
相关插件 · 桌面端
Codex 任务面板chuspeeism/dashi-taskboard
现代化可灵活嵌入的任务面板,支持 Codex、DeepSeek Harness
★ 3,409已汉化DSH
71.7
多智能体自进化开发平台Prism-Shadow/penguin-harness
统一、稳定的 Agent 自进化框架全自动优化:任意模型 · 任意算法 · 任意 Benchmark
★ 3,111已汉化DSH
71.1
桌面宠物PC2005-cloud/dsh-pet
DSH 桌面宠物:一行命令装好即用的透明动画小桌宠,支持多开、大小位置随心配置;还内置 DIY 素材链,能用 AI…
★ 5,341已汉化DSH
71
多端 Agent 工作台GCWing/OpenBitFun
OpenBitFun 是一个高度可定制的开源 Agent 工作台,让任务按你的方式持续推进。
★ 3,449已汉化DSH
70.8
DSH Desktopanywhere-labs/dsh-desktop
为 DeepSeek Harness DSH 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。
★ 34,710已汉化DSH
70.7
桌面宠物伴侣OpenPetsHQ/openpets
桌面伴侣平台,带宠物、插件,还能选配本地智能体集成。
★ 1,353已汉化DSH
70.2
这是你的仓库?认领条目