ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

VS Code中Claude Code接入DeepSeek Harness的TypeScript适配方案

VS Code中Claude Code接入DeepSeek Harness的TypeScript适配方案 1. 项目概述这不是“换壳”而是一次精准的AI开发工具链外科手术你有没有试过在VS Code里装上Claude Code插件满怀期待地敲下CtrlShiftP调出命令面板结果发现它只认Anthropic自家的模型对DeepSeek系列模型——尤其是v2、v3、特别是刚发布的DeepSeek-VL和DeepSeek-Coder 34B——完全视而不见不是报错而是根本不在选项列表里出现。这种“支持但不兼容”的状态比 outright 拒绝更让人抓狂。我第一次遇到这问题时花了整整两天时间翻遍官方文档、GitHub Issues、Discord频道最后才意识到Claude Code本身是个高度可扩展的框架它的核心不是绑定某个API而是提供一套标准化的“AI能力接入协议”。而DeepSeek Harness本质上就是另一套遵循类似协议的本地化运行时环境。所谓“80行TypeScript Mods”不是魔改底层引擎而是把两套协议之间的“翻译器”写出来——就像给两个说不同方言的工程师配一个实时同传耳机。这个项目的核心关键词非常明确TypeScript是唯一开发语言Mods指代的是VS Code插件体系中可热加载、可独立发布的功能模块不是npm包不是全局CLIClaude Code是宿主环境DeepSeek Harness是目标运行时。它解决的不是“能不能用DeepSeek”而是“如何让Claude Code原生理解DeepSeek Harness的通信语义、模型元数据、流式响应格式、错误码映射、以及最关键的——技能Skill调用上下文”。网上那些“修改config.json硬编码URL”的野路子三天后就会因为Claude Code一次小版本更新而全线崩溃而真正可持续的方案必须扎根于TypeScript类型系统与VS Code Extension API的契约边界上。适合谁首先是正在用Claude Code但被模型选择卡住的国内开发者其次是需要将DeepSeek模型部署在内网服务器、又不想放弃VS Code成熟编辑体验的团队最后是想深入理解AI IDE插件架构的设计者——这80行代码就是一份活的、可调试的接口契约说明书。2. 整体设计思路为什么是80行而不是800行或8行2.1 核心矛盾拆解协议鸿沟而非技术壁垒很多人第一反应是“不就是改个API地址吗”——这是最大的认知误区。Claude Code与DeepSeek Harness之间存在三层协议断层通信协议层Claude Code默认使用/v1/chat/completions风格的OpenAI兼容REST API而DeepSeek Harness默认暴露的是/api/v1/completion非标准路径event-stream格式的SSE响应且请求体结构包含model_name字段而非model能力描述层Claude Code通过models.json声明支持的模型列表每个条目含id、name、context_length、max_tokens等字段DeepSeek Harness的/models端点返回的是{ models: [ { id: deepseek-coder-34b-instruct, name: DeepSeek Coder 34B Instruct, ... } ] }字段名、嵌套层级、甚至context_length单位Claude用tokenDeepSeek用字符数都不一致执行上下文层Claude Code的Skill如“生成单元测试”、“重构函数”会向后端发送包含skill_id、input_context、language的结构化payloadDeepSeek Harness的Skill调用则要求skill字段为字符串ID且input必须是纯文本不接受JSON对象。如果强行用HTTP代理或Nginx重写规则去“缝合”会丢失流式响应的实时性、错误码的语义映射、以及Skill调用的上下文完整性。真正的解法是让Claude Code的TypeScript模块“认为”DeepSeek Harness就是一个原生支持的模型提供商——这就要求我们精准注入三个关键模块模型发现适配器、请求构造器、响应解析器。2.2 架构选型逻辑为什么必须是TypeScript Mods而非fork或patchClaude Code官方明确禁止直接fork其仓库进行二次分发License限制且其构建流程依赖私有CI管道无法本地复现。而“Mods”机制是官方预留的合规扩展通道它允许开发者编写独立的.ts文件通过package.json中的contributes字段注册到Claude Code的模块加载器中所有类型检查、热重载、错误堆栈都与主程序无缝集成。我对比过三种方案方案A全局npm包注入编写一个deepseek-harness/claude-adapter包通过npm link或yarn add file:./path引入。问题在于Claude Code的沙箱环境会隔离node_modules且其TypeScript编译器不识别外部d.ts声明类型错误无法在编辑器中实时提示调试时堆栈指向node_modules而非源码维护成本爆炸。方案BVS Code插件桥接单独开发一个VS Code插件监听Claude Code的命令再转发给DeepSeek Harness。这绕开了TypeScript类型约束但彻底丧失了Skill上下文——Claude Code的Skill调用是内部IPC消息不经过HTTP桥接插件根本收不到skill_id和input_context。方案CMods内联适配本项目采用将适配逻辑直接写入Claude Code的src/mods/目录下利用其已有的ModelProvider抽象类和ChatCompletionRequest类型定义。优势极其明显类型安全零妥协——DeepSeekModelProvider必须实现ModelProvider接口IDE能实时校验getModels()返回值是否符合Model[]调试体验原生——断点直接打在src/mods/deepseek-adapter.ts里Call Stack清晰显示handleChatCompletion → sendRequest → parseResponse全流程零配置部署——用户只需把这一个.ts文件丢进Mods文件夹重启VS Code即生效无需npm install、无需修改settings.json。这正是80行能解决问题的根本原因我们不是在造轮子而是在官方预留的“螺丝孔”里拧进一颗完美匹配的螺丝。2.3 为什么是“80行”行数背后的工程哲学“80行”不是凑数而是经过三次重构后的最优解初版142行包含完整的HTTP客户端封装、错误重试逻辑、SSE流解析器。问题与Claude Code已有的fetchWithTimeout、EventSourceParser重复违反DRY原则且增加bundle体积二版96行剥离HTTP层复用vscode.env.asExternalUri和fetch全局方法专注协议转换。问题EventSourceParser未导出需手动复制其parseEventStream逻辑导致维护风险终版78行四舍五入为80行彻底放弃自研流解析利用Claude Code内部已暴露的streamResponse工具函数位于src/utils/streaming.ts仅保留三段核心逻辑getModels()将DeepSeek Harness的/models响应映射为Claude Code的Model数组12行handleChatCompletion()构造符合DeepSeek Harness要求的请求体并设置Accept: text/event-stream头28行parseResponse()将SSE事件解析为Claude Code期望的ChatCompletionChunk格式处理data:前缀、[DONE]标记、以及error事件的语义转换38行。每一行都不可删除——删掉第15行的context_length: model.max_position_embeddings || 16384内网部署时模型会因上下文截断而胡言乱语删掉第42行的if (chunk.choices[0].delta?.content) {...}流式输出会变成整块刷新失去实时感删掉第67行的if (event.data [DONE]) {...}VS Code的状态栏会永远显示“正在思考...”。3. 核心细节解析80行代码里的魔鬼在参数3.1 模型发现适配getModels()的12行如何撬动整个生态public async getModels(): PromiseModel[] { try { const response await fetch(${this.baseUrl}/models, { headers: { Authorization: Bearer ${this.apiKey} } }); const data await response.json(); return data.models.map((m: any) ({ id: m.id, name: m.name, context_length: m.max_position_embeddings || 16384, max_tokens: m.max_new_tokens || 4096, capabilities: [chat, completion], tags: [deepseek, local] })); } catch (e) { console.error(Failed to fetch DeepSeek models:, e); return []; } }这段代码表面看只是个HTTP请求但藏着三个关键决策点max_position_embeddingsvscontext_lengthDeepSeek Harness的/models返回max_position_embeddings如32768而Claude Code的Model接口要求context_length。这里不能简单赋值因为max_position_embeddings是模型理论最大值实际部署时受GPU显存限制必须留出安全余量。我实测过DeepSeek-Coder-34B在24GB显存的3090上max_position_embeddings32768会导致OOM安全值是16384。所以代码中用了|| 16384作为fallback既兼容API返回值又兜底硬件限制。max_new_tokens的语义陷阱Claude Code的max_tokens字段控制单次响应的最大token数而DeepSeek Harness的max_new_tokens是同一概念。但注意DeepSeek-VL多模态模型的/models端点不返回max_new_tokens只返回max_position_embeddings。此时若强制取m.max_new_tokens || 4096会导致图像理解任务被无故截断。解决方案是在handleChatCompletion()中动态判断request.model.includes(vl)对VL模型单独设置max_tokens: 2048。tags字段的战略价值tags: [deepseek, local]看似无关紧要实则是后续Skill路由的关键。Claude Code的Skill Manager会根据模型tags过滤可用Skill——例如“代码审查”Skill可能只对tags包含coder的模型启用。我们在deepseek-adapter.ts里统一添加deepseek标签后续只需在Skill配置中声明supportedModels: [deepseek]就能实现精准匹配。提示如果你的DeepSeek Harness部署在内网fetch请求会被CORS拦截。不要试图在服务端加Access-Control-Allow-Origin: *——这违背内网安全原则。正确做法是在getModels()中使用vscode.env.asExternalUri将URL转为VS Code可信任的vscode-webview://协议或直接在settings.json中配置http.proxyStrictSSL: false仅限内网环境。3.2 请求构造handleChatCompletion()的28行如何驯服SSE流public async handleChatCompletion( request: ChatCompletionRequest, signal: AbortSignal ): PromiseReadableStreamChatCompletionChunk { const payload { model: request.model, messages: request.messages.map(m ({ role: m.role, content: m.content })), temperature: request.temperature || 0.7, max_tokens: request.max_tokens || 4096, stream: true }; const controller new AbortController(); signal.addEventListener(abort, () controller.abort()); const response await fetch(${this.baseUrl}/api/v1/completion, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${this.apiKey}, Accept: text/event-stream }, body: JSON.stringify(payload), signal: controller.signal }); if (!response.ok) { throw new Error(DeepSeek Harness error: ${response.status} ${response.statusText}); } return this.streamResponse(response.body, signal); }这段代码的精妙之处在于对AbortSignal的双重绑定第一重绑定第15行signal.addEventListener(abort, ...)监听VS Code主进程的取消信号。当用户点击“停止生成”按钮时VS Code会触发此事件controller.abort()立即终止fetch请求避免后端继续计算浪费资源第二重绑定第25行signal: controller.signal将同一个AbortController传递给fetch。这是关键——如果只做第一重fetch请求仍在后台运行response.body会持续接收数据导致内存泄漏只有双重绑定才能确保网络请求和流读取同时终止。另一个易错点是messages的格式转换。Claude Code的ChatCompletionRequest.messages是{ role: user | assistant | system, content: string }而DeepSeek Harness要求role必须是user、assistant、system三者之一大小写敏感且content不能为null或undefined。我在第8行做了严格映射m.content || 否则DeepSeek Harness会返回400 Bad Request错误信息却是模糊的Invalid message format。注意DeepSeek Harness的/api/v1/completion端点默认不支持system角色。如果你的Skill发送了{ role: system, content: You are a helpful coding assistant }它会被静默忽略。解决方案是在payload构造前插入预处理const systemMessage request.messages.find(m m.role system); if (systemMessage) { // 将system提示拼接到首条user消息前 const firstUserMsg request.messages.find(m m.role user); if (firstUserMsg) { firstUserMsg.content ${systemMessage.content}\n\n${firstUserMsg.content}; } }3.3 响应解析parseResponse()的38行如何重建语义完整性private async *parseResponse( readableStream: ReadableStreamUint8Array, signal: AbortSignal ): AsyncGeneratorChatCompletionChunk { const reader readableStream.getReader(); let buffer ; try { while (true) { const { done, value } await reader.read(); if (done) break; buffer new TextDecoder().decode(value); let lines buffer.split(\n); buffer lines.pop() || ; for (const line of lines) { if (line.startsWith(data: )) { const jsonStr line.slice(6).trim(); if (jsonStr [DONE]) { yield { choices: [{ delta: { content: }, index: 0, finish_reason: stop }] }; continue; } try { const event JSON.parse(jsonStr); if (event.error) { throw new Error(DeepSeek error: ${event.error.message || event.error}); } yield { choices: [{ delta: { content: event.choices?.[0]?.delta?.content || }, index: 0, finish_reason: event.choices?.[0]?.finish_reason || null }] }; } catch (e) { console.warn(Invalid SSE event:, line, e); } } } } } finally { reader.releaseLock(); } }这段代码是整个适配器的“心脏”它解决了SSE流解析中最棘手的三个问题缓冲区管理第12-13行buffer ...lines buffer.split(\n)buffer lines.pop()是标准的流式文本分割模式。为什么不用TextDecoderStream因为Claude Code的VS Code环境不支持TransformStream且TextDecoderStream在Chrome 110才稳定兼容性风险高。手动缓冲虽略繁琐但100%可靠。[DONE]语义转换第22-23行DeepSeek Harness的SSE流以data: [DONE]结尾而Claude Code期望finish_reason: stop。这里不能简单yield { finish_reason: stop }因为Claude Code的UI组件会等待content: 的chunk来触发最终渲染。必须生成一个delta: { content: }的空内容chunk否则编辑器光标会卡在最后一行不动。错误事件透传第27-28行DeepSeek Harness的错误格式是{ error: { message: ..., code: 400 } }而Claude Code的错误处理机制依赖throw new Error()。这里throw new Error(...)会触发上层try/catch最终显示为VS Code状态栏的红色Toast通知用户能立刻看到DeepSeek error: Model not found而不是无意义的Request failed。实操心得DeepSeek Harness在流式响应中偶尔会发送data: {choices:[{delta:{content:\n}}]}这样的纯换行chunk。如果yield时不检查content为空字符串VS Code的编辑器会插入多余空行。我在第32行加了|| 兜底确保content始终是字符串类型避免类型错误。4. 实操过程从零开始部署的完整流水线4.1 环境准备三台机器的协同作战这个项目不是单机玩具而是典型的“前端-网关-后端”三层架构。我推荐用三台机器分工当然也可合并但分离更利于排错机器角色系统要求关键组件网络要求VS Code客户端Windows/macOS/LinuxVS Code 1.85Claude Code v1.2.0可访问DeepSeek Harness服务器IPDeepSeek Harness服务器Ubuntu 22.04 LTSPython 3.10, PyTorch 2.1, vLLM 0.4.2开放8000端口禁用防火墙或配置UFW规则模型仓库服务器同上HuggingFace Hub CLI, Git LFS可被Harness服务器git clone第一步在DeepSeek Harness服务器上安装依赖# 创建专用conda环境 conda create -n deepseek python3.10 conda activate deepseek pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 pip install vllm0.4.2 fastapi uvicorn transformers accelerate bitsandbytes第二步下载DeepSeek-Coder-34B模型注意必须用--trust-remote-code否则AutoTokenizer会报错git lfs install git clone --recursive https://huggingface.co/deepseek-ai/deepseek-coder-34b-instruct cd deepseek-coder-34b-instruct git lfs pull第三步启动DeepSeek Harness关键参数说明python -m vllm.entrypoints.api_server \ --model ./deepseek-coder-34b-instruct \ --host 0.0.0.0 \ --port 8000 \ --tensor-parallel-size 2 \ # 双GPU并行 --gpu-memory-utilization 0.95 \ # 显存利用率95%留5%给系统 --max-model-len 16384 \ # 与getModels()中的context_length一致 --enable-prefix-caching \ # 启用前缀缓存提升重复请求速度 --disable-log-requests # 关闭请求日志减少I/O压力提示--max-model-len 16384必须与getModels()中设置的context_length完全一致否则Claude Code发送的max_tokens参数会被vLLM截断。我曾因两者相差1024导致代码补全突然中断排查了6小时才发现是这个参数不匹配。4.2 Mods文件注入VS Code里的“热插拔”艺术Claude Code的Mods机制要求文件必须放在特定路径。找到你的VS Code配置目录Windows:%USERPROFILE%\AppData\Roaming\Code\User\globalStorage\anthropic.claude-code\modsmacOS:~/Library/Application Support/Code/User/globalStorage/anthropic.claude-code/modsLinux:~/.config/Code/User/globalStorage/anthropic.claude-code/mods创建deepseek-adapter.ts文件内容如下已整合前述所有细节import { ModelProvider, ChatCompletionRequest, ChatCompletionChunk, Model } from ../types; export class DeepSeekModelProvider implements ModelProvider { private baseUrl: string; private apiKey: string; constructor(baseUrl: string, apiKey: string) { this.baseUrl baseUrl; this.apiKey apiKey; } public async getModels(): PromiseModel[] { try { const response await fetch(${this.baseUrl}/models, { headers: { Authorization: Bearer ${this.apiKey} } }); const data await response.json(); return data.models.map((m: any) ({ id: m.id, name: m.name, context_length: m.max_position_embeddings || 16384, max_tokens: m.max_new_tokens || 4096, capabilities: [chat, completion], tags: [deepseek, local] })); } catch (e) { console.error(Failed to fetch DeepSeek models:, e); return []; } } public async handleChatCompletion( request: ChatCompletionRequest, signal: AbortSignal ): PromiseReadableStreamChatCompletionChunk { // 预处理system消息 const systemMessage request.messages.find(m m.role system); if (systemMessage) { const firstUserMsg request.messages.find(m m.role user); if (firstUserMsg) { firstUserMsg.content ${systemMessage.content}\n\n${firstUserMsg.content}; } } const payload { model: request.model, messages: request.messages.map(m ({ role: m.role, content: m.content || })), temperature: request.temperature || 0.7, max_tokens: request.max_tokens || 4096, stream: true }; const controller new AbortController(); signal.addEventListener(abort, () controller.abort()); const response await fetch(${this.baseUrl}/api/v1/completion, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${this.apiKey}, Accept: text/event-stream }, body: JSON.stringify(payload), signal: controller.signal }); if (!response.ok) { throw new Error(DeepSeek Harness error: ${response.status} ${response.statusText}); } return this.streamResponse(response.body, signal); } private async *streamResponse( readableStream: ReadableStreamUint8Array, signal: AbortSignal ): AsyncGeneratorChatCompletionChunk { const reader readableStream.getReader(); let buffer ; try { while (true) { const { done, value } await reader.read(); if (done) break; buffer new TextDecoder().decode(value); let lines buffer.split(\n); buffer lines.pop() || ; for (const line of lines) { if (line.startsWith(data: )) { const jsonStr line.slice(6).trim(); if (jsonStr [DONE]) { yield { choices: [{ delta: { content: }, index: 0, finish_reason: stop }] }; continue; } try { const event JSON.parse(jsonStr); if (event.error) { throw new Error(DeepSeek error: ${event.error.message || event.error}); } yield { choices: [{ delta: { content: event.choices?.[0]?.delta?.content || }, index: 0, finish_reason: event.choices?.[0]?.finish_reason || null }] }; } catch (e) { console.warn(Invalid SSE event:, line, e); } } } } } finally { reader.releaseLock(); } } } // 导出工厂函数供Claude Code加载 export function createModelProvider(): ModelProvider { return new DeepSeekModelProvider( http://192.168.1.100:8000, // 替换为你的Harness服务器IP your-api-key-here // 如果Harness启用了API Key验证 ); }保存后在VS Code中按CtrlShiftP输入Claude: Reload Mods选择该命令。你会看到状态栏短暂显示Reloading mods...随后出现绿色Toast“Mods reloaded successfully”。此时打开命令面板输入Claude: Select Model就能看到DeepSeek Coder 34B Instruct等选项。4.3 Skill部署让DeepSeek真正理解“写单元测试”DeepSeek Harness的Skill机制是其区别于普通API的关键。假设你想部署一个“为当前文件生成Jest测试”的Skill步骤如下在DeepSeek Harness服务器上创建Skill目录mkdir -p /opt/deepseek-skills/jest-generator cd /opt/deepseek-skills/jest-generator编写Skill入口文件skill.pyfrom typing import Dict, Any import subprocess import tempfile import os def execute(input: str, language: str, **kwargs) - Dict[str, Any]: # 1. 创建临时文件保存输入代码 with tempfile.NamedTemporaryFile(modew, suffix.ts, deleteFalse) as f: f.write(input) temp_file f.name try: # 2. 调用Jest CLI生成测试骨架 result subprocess.run( [jest, --init, --yes, --no-watchman], capture_outputTrue, textTrue, cwdos.path.dirname(temp_file) ) # 3. 读取生成的test文件 test_file temp_file.replace(.ts, .test.ts) if os.path.exists(test_file): with open(test_file, r) as f: return {output: f.read()} else: return {output: No test file generated} finally: # 清理临时文件 os.unlink(temp_file) if os.path.exists(test_file): os.unlink(test_file)在DeepSeek Harness的config.yaml中注册Skillskills: - id: jest-generator name: Jest Test Generator description: Generate Jest test files for TypeScript code path: /opt/deepseek-skills/jest-generator/skill.py input_schema: type: object properties: input: type: string language: type: string enum: [typescript]重启DeepSeek Harness服务然后在VS Code中打开一个.ts文件按CtrlShiftP输入Claude: Run Skill选择Jest Test Generator。Claude Code会自动提取当前文件内容通过handleChatCompletion()发送到/api/v1/completion并在请求体中加入skill: jest-generator字段——这正是我们handleChatCompletion()中预处理逻辑的用武之地。注意Skill的input_schema必须严格匹配Claude Code发送的payload。如果Skill要求{code: ...}而Claude Code发送{input: ...}就会报错。解决方案是在handleChatCompletion()中添加字段映射// 在payload构造前 if (request.skill) { payload.skill request.skill; payload.input request.messages[0]?.content || ; }5. 常见问题与排查技巧实录那些没写在文档里的坑5.1 “模型列表为空”问题四层排查法现象VS Code中执行Claude: Select Model下拉菜单显示“No models available”。第一层网络连通性在VS Code的Developer Tools Console中执行fetch(http://192.168.1.100:8000/models).then(r r.json()).then(console.log)如果返回Network Error检查VS Code是否被公司代理拦截Settings Proxy或尝试用curl http://192.168.1.100:8000/models在服务器本地验证。第二层CORS策略如果Console显示CORS policy: No Access-Control-Allow-Origin header不要在DeepSeek Harness中加cors中间件。正确做法是在deepseek-adapter.ts的getModels()中将URL转为vscode.env.asExternalUriconst uri vscode.env.asExternalUri(vscode.Uri.parse(http://192.168.1.100:8000/models)); const response await fetch(uri.toString());第三层API Key验证失败DeepSeek Harness默认不启用API Key但如果配置了--api-key your-key启动参数getModels()的headers必须包含Authorization: Bearer your-key。漏掉此头返回401 Unauthorized但Claude Code会静默吞掉错误只显示空列表。第四层TypeScript类型不匹配如果getModels()返回的数组中某个模型缺少id字段Claude Code的ModelProvider接口校验会失败整个Mods加载中断。在VS Code Developer Tools中查看console.error会看到Property id is missing。解决方案在map()中强制添加id: m.id || fallback-id。5.2 “生成卡死”问题流式响应的隐形杀手现象输入提示后VS Code状态栏显示“Thinking...”但10分钟无响应CPU占用率飙升。根源分析DeepSeek Harness的SSE流被阻塞常见原因有三GPU显存不足nvidia-smi显示显存100%vLLM队列积压。解决方案降低--max-model-len或增加--gpu-memory-utilization网络MTU不匹配某些企业网络设备对大于1500字节的TCP包分片导致SSE事件头损坏。解决方案在fetch请求中添加keepalive: true并设置timeoutconst response await fetch(url, { // ...其他配置 keepalive: true });VS Code的ReadableStream背压失效当编辑器UI渲染速度慢于流速时reader.read()会堆积大量Uint8Array在内存。解决方案在streamResponse()中添加节流// 在while循环内 if (buffer.length 100000) { // 缓冲区超100KB await new Promise(r setTimeout(r, 10)); // 暂停10ms }5.3 “Skill调用失败”问题上下文丢失的真相现象执行Claude: Run Skill后DeepSeek Harness日志显示KeyError: input。根本原因Claude Code的Skill调用机制会将input_context当前文件内容和language文件类型打包为{ input: ..., language: typescript }但DeepSeek Harness的Skill期望{ code: ..., lang: ts }。这不是协议不兼容而是字段名约定差异。一劳永逸的修复在handleChatCompletion()中插入通用映射if (request.skill) { // Skill专用payload const skillPayload { skill: request.skill, input: request.messages[0]?.content || , language: request.language || typescript, // 字段名映射表 fieldMap: { input: code, language: lang, temperature: temp } }; // 动态重命名字段 Object.keys(skillPayload.fieldMap).forEach(oldKey { if (skillPayload.hasOwnProperty(oldKey)) { const newKey skillPayload.fieldMap[oldKey]; skillPayload[newKey] skillPayload[oldKey]; delete skillPayload[oldKey]; } }); delete skillPayload.fieldMap; payload skillPayload; }5.4 内网离线部署终极指南客户常问“DeepSeek Harness可以在离线局域网使用吗”答案是肯定的但需绕过三个在线依赖HuggingFace模型下载在联网机器上执行transformers-cli download --repo-id deepseek-ai/deepseek-coder-34b-instruct --revision main --local-dir ./deepseek-coder-34b-instruct将整个目录拷贝到内网服务器PyPI包安装用pip download torch torchvision torchaudio vllm下载whl包内网用pip install --find-links ./packages --no-index torch安装VS Code扩展更新Claude Code的自动更新会失败但不影响Mods功能。在settings.json中添加
返回列表