
简介面向需要将DeepSeek等大模型能力落地到办公场景的开发者这份PDF完整呈现了在WPS中深度集成DeepSeek API、打造智能办公插件的全过程覆盖从入门到实战的关键环节。资源共1个文件为PDF格式压缩包大小约2.16MB文档共33页内容按“开发实录”组织依次展开WPS插件环境搭建、API密钥获取、需求分析、插件架构设计、DeepSeek API集成、文本生成/语言翻译/格式调整/信息检索等功能模块开发以及插件注册、菜单工具栏整合、测试优化和部署发布。通过清晰目录与步骤化叙述读者可了解API请求参数构造、HTTP调用、错误处理与重试机制、WPS文档内容读写和事件监听等实现细节并可直接借鉴该架构完成同类智能办公插件的设计与编码。目前已有107人学习下载适合具备一定编程基础、希望掌握WPS二次开发和AI能力集成的开发者作为系统参考。1. 用 DeepSeekAPI 给 WPS 装上一个“会干活”的 AI 助手标题在讲什么写周报时把一段流水账复制到手边某个对话框里让它变成通顺的汇报文字打开表格让 AI 按表头生成一列公式对着 PPT 页念一段需求让它直接产出演讲词。这些场景听起来是“智能办公”该有的样子可真落地时多数人卡在同一个地方DeepSeekAPI 在代码里能跑通一回到 WPS 就不知道怎么把接口、文档对象和选区粘起来。要聊的正是这条实测过的路径在 WPS 的 JS 宏环境里用 DeepSeekAPI 搭一个能读写选区内容的智能办公插件。它不需要编译不依赖外部服务器适合想把 AI 能力真正塞进日常文档流程里的一线从业者。2. 选型与最小可跑通为什么走 WPS JS 宏以及第一个能用的请求很多人拿到“用 DeepSeekAPI 做 WPS 插件”这个题目第一反应是去搜“WPS 插件开发”。搜索到一半就发现路由太多有 VBA、COM 加载项、JS 宏、加载项Add-in还有用 Python 写独立进程的野路子。本文直接把结论亮出来个人与中小团队做深度集成优先走 WPS JS 宏需要给整个部门交付统一体验时再把同一套逻辑包装成 WPS 加载项。下面讲清楚为什么是这条路以及第一个最小脚本怎么落地。2.1 有四条集成路线为什么唯独 JS 宏最适合把 WPS 接上 DeepSeekAPI本质上只干两件事拿到当前文档的选区内容再把这个内容 POST 到接口拿到返回后写回文档。难点不在 HTTP 请求而在“怎么在 WPS 进程内合法地碰文档”。常见做法是以下四条路线各自的代价完全不同。VBA 最老牌网上“wps vba”的教程一抓一把很多老插件说支持 WPS其实走的是兼容层。它的问题是环境配置依赖“启用 VBA 组件”分发时要担心目标机器有没有装对应组件而且 VBA 的 HTTP 请求要引用 MSXML2.XMLHTTP在 WPS 里偶尔会因为组件版本差异翻车。做原型很快做交付很痛苦。COM 加载项是 Windows 平台上的正规军用 C# 或 C 写 DLL注册到注册表里WPS 启动时加载。功能上限最高但你要先解决开发环境、注册表权限、签名、目标机器信任策略这一串问题对个人开发者来说成本偏高不适合“先跑起来”的阶段。Python 独立进程是很多熟手喜欢偷懒的方案用 pywin32 或通过 WPS 的 COM 接口控制文档AI 调用放在 Python 里。本质上你的 WPS 插件是一个外部控制程序用户得先启动一个后台服务部署时还要解决 Python 环境的依赖。团队内部自用可以给外部交付会被运维骂。真正省事的是 WPS 自己带的那套 JS 宏对应热词里一堆人在搜的“wps js宏”。WPS 的桌面版内置了 JavaScript 运行时开发工具菜单里可以直接打开 JS 宏编辑器新建脚本、选中函数、运行全程不编译。JS 宏内部能访问 Application.ActiveDocument 这类文档对象也能发 XMLHttpRequest 请求。对“用 DeepSeekAPI 做智能办公插件”这个目标来说它几乎是零门槛。集成方式语言HTTP 请求分发难度适合场景VBAVB需 MSXML2 组件中依赖 VBA 组件老宏兼容、临时脚本JS 宏JavaScriptXMLHttpRequest 可用低WPS 自带个人提效、团队小范围共享COM 加载项C#/C随便高注册表签名商业级插件、深度 UI 集成Python 独立进程Pythonrequests高要部署服务数据管线、复杂业务逻辑JS 宏不是没有缺点它对 UI 的支持比较弱画不出漂亮的侧边栏。但在“读选区、调 API、写回文档”这条主链路上它提供的阻力是最小的。先把这条链路跑通再谈加载项的事。2.2 DeepSeekAPI 接入 WPS 的核心参数接口、模型与三个必调参数DeepSeekAPI 用的是 OpenAI 兼容的接口格式所以请求体长得很眼熟不需要额外引 SDK。在 WPS 的 JS 宏里发请求地址是 https://api.deepseek.com/chat/completions模型名用“deepseek-chat”。办公场景下真正要调的参数并不多新手不要被接口文档里的二十多个字段吓到只调下面这几个就够。temperature 控制随机性0 到 2 之间。作改写和润色时我一般用 0.3 到 0.5靠近 0 则保守输出稳定作头脑风暴时放到 0.8 以上让模型多给几个方向。总结类任务建议 0.2 到 0.3防止模型自己加戏。max_tokens 控制返回的最大长度。很多人的误区是给到 4000 不嫌多实际办公场景里一段改写 500 token 足够一份纪要摘要 800 也够。给的太大会让等待时间变长而且额度消耗翻倍。做插件时还应该在代码里判断这个值防止某次手滑选中整本书导致请求体爆炸。stream 参数在宏环境里尽量关掉。流式输出在浏览器里很好用但在 WPS 宏里处理流式响应要反复解析缓冲区状态栏刷新也跟不上经常搞得像死机。发出去直接等完整 JSON 返回体验反而稳。还有 top_p新版接口里建议直接忽略。文档里说它和 temperature 互斥调优真实工作中你两三个参数都调不过来不会去碰它。保留默认值即可。2.3 最小验证脚本在 WPS JS 宏里发送一次 DeepSeekAPI 请求打开一个 WPS 文字文档进入“开发工具 - JS 宏”新建一个脚本把下面这段整体粘进去在宏列表里选择 callDeepSeek 运行。function callDeepSeek() { var url https://api.deepseek.com/chat/completions; var apiKey sk-在这里换成你的Key; var body { model: deepseek-chat, messages: [ { role: system, content: 你是WPS里的智能助手回答要简短。 }, { role: user, content: 用一句话介绍WPS JS宏。 } ], temperature: 0.7, max_tokens: 500 }; var xhr new XMLHttpRequest(); xhr.open(POST, url, false); xhr.setRequestHeader(Content-Type, application/json); xhr.setRequestHeader(Authorization, Bearer apiKey); xhr.send(JSON.stringify(body)); if (xhr.status 200) { var resp JSON.parse(xhr.responseText); var content resp.choices[0].message.content; MsgBox(DeepSeek返回 content); } else { MsgBox(接口状态 xhr.status xhr.responseText); } }这段代码做了三件事拼接标准 OpenAI 兼容请求体、用 XMLHttpRequest 同步发送、把返回内容弹出来。同步模式是刻意为之的WPS 宏环境的生命周期不像浏览器那样有稳定的异步事件循环异步回调里操作文档对象容易踩到对象已释放的坑。xhr.status 判断很重要常见值是 401Key无效、429限流或余额不足、400body 参数格式有问题。看到非 200 时先把 responseText 弹出来绝大多数问题一眼能看出来。注意运行位置。当前文档如果是 WPS 表格Application.ActiveDocument 不存在这段代码跑起来会报空对象错误。验证时请打开“WPS 文字”类型的文档环境。3. 做第一个智能功能改写选中文本并写回文档最小脚本只是把一句话发给模型离“插件”还差得远。真正的智能办公插件至少要能回答选中了什么、做了什么、结果写回哪里。本章以“改写选中文本”这个最常见的需求为例把它做成一条闭环。3.1 读取 WPS 里的选中内容Range.Text 够用但跨段落会截断在 JS 宏里读选中内容表面上一行代码取当前文档的 Selection 对象再取它的 Range.Text。实际使用中跨段落选中一段五号字文本Range.Text 有时只拿回第一段后面全丢。这跟 WPS 底层对 Range 的实现有关宏拿到的不一定是可视化选区而是逻辑选区的一部分。我一般会顺手做一个保险函数用 Paragraphs 集合遍历拼接保证跨段落内容不丢function readSelectionText() { var doc Application.ActiveDocument; if (doc null) { MsgBox(请先打开一个WPS文字文档); return ; } var sel doc.Selection; var range sel.Range; var text range.Text; // 跨段落时粗暴取值容易截断改用段落集合补齐 if (text.indexOf(\r) -1 || text.length 2) { var parts []; for (var i 1; i sel.Paragraphs.Count; i) { parts.push(sel.Paragraphs.Item(i).Range.Text); } text parts.join(\n); } return text; }这个函数判定逻辑很直白如果 Range.Text 里已经能看到回车符说明至少包含两个段落那就用段落集合重新拼一遍。拼出来的文本把段落标记统一换成 \n后续发给模型时干净很多。注意 WPS JS 宏里的对象模型和 VBA 有一个共同的脾气集合的下标从 1 开始不是从 0 开始写循环时别按浏览器习惯写成 Item(0)否则会报下标越界。还有一个容易忽略的问题文档里如果混入大量高亮、批注、书签Selection.Text 读出来也会夹带特殊标记。对纯文案场景影响不大但如果读到奇怪字符先检查文档里有没有域代码和批注引用。3.2 把 DeepSeek 的返回内容写回文档先格式化再替换把模型返回的内容塞回选区新手最常见的翻车操作是直接 range.Text newText。这在简单场景能跑但会吞掉选区原有的字体、字号和段落格式而且一旦 newText 里有换行符或制表符WPS 会按自己的规则重新断段。正确的姿势是先构造好要写入的字符串再替换同时做好可撤销处理。推荐用下面的写回函数function writeBackText(newText) { var doc Application.ActiveDocument; if (doc null || newText.length 1) return; var sel doc.Selection; var range sel.Range; // 清理模型输出里可能的 Markdown 痕迹 newText newText.replace(/#{1,6}\s*/g, ); newText newText.replace(/\*\*(.*?)\*\*/g, $1); newText newText.replace(/\n{3,}/g, \n\n); range.Text newText; range.Font.Bold false; }为什么先做清理再写回DeepSeekAPI 在默认 prompt 下喜欢给结果加标题、加粗、列表符号。直接写回文档用户会看到一整片 # 和 * 号观感极差。上面这段正则把常见 Markdown 标题和加粗标记剥掉再压缩多余空行输出就已经接近干净的办公文本了。写回之后还有一个细节range.Font.Bold false 是为了防止模型输出的某个片段带 ** 被清洗后残留加粗属性。你把它去掉也能用但实际操作中遇到过选区原有文字是加粗、写回后整体变粗的问题这一行能兜底。如果你想保留用户选区的原始格式不做整体替换可以这样先在选区末尾插入新文本再反向删除旧文本。顺序不能反反了会把新内容一起删掉。3.3 prompt 怎么拼系统角色与“格式约束”决定办公效果同样的接口、同样的参数prompt 措辞不同WPS 里看到的结果完全不同。办公插件里最大的坑不是模型不懂而是模型把结果写得太“AI”。我常用的系统角色模板是这样的var systemPrompt 你是嵌入在WPS文字里的写作助手。 用户会给出一段选中的文字请改写它。 要求1. 保持原意2. 去掉口语和重复3. 长度尽量与原段一致4. 只输出改写后的正文不要加任何解释、标题、列表符号。;最后一条“只输出改写后的正文”是关键。很多模型没加这条时会输出“好的以下是改写后的内容”然后把正文包在一段客套话里。写回文档时这些客套话全会被写进去用户看到的第一反应就是“插件不行”。user 消息部分直接传选中的原文不要自作主张加“请帮我改进一下这段文字”这句可以留在 system 里。有的场景希望模型保留原文中的关键数字和专有名词这种约束也要写进 system否则模型会擅自做同义替换。比如“英伟达”被改成“NVIDIA”、“成本占比 37%”被改成“接近四成”专业文档里这是不可接受的。prompt 写法效果“帮我把这段话改一下”输出充满寒暄格式随机“保持原意用办公书面语改写保留所有数字只输出正文”输出干净可直接写入文档给深度集成做 prompt 时建议把 system 和 user 拆成两个变量将来要支持“总结”“扩写”等多种功能时只需要切换 system 文本读选区和写回逻辑完全复用。4. 深度集成避坑WPS JS 宏调 DeepSeekAPI 的 5 个翻车现场这一章是血泪经验的总和。WPS JS 宏看着像浏览器实际上是一个能力受限的宿主环境。你在这边发的每个请求、写的每行文档操作都可能踩到环境特有的坑。4.1 同步请求后界面假死超时与重试是玄学现象宏运行后WPS 整个窗口卡住鼠标转圈几分钟没反应只能从任务管理器强杀进程。原因XMLHttpRequest 同步模式会阻塞 UI 线程网络延迟越高卡得越久。如果 DeepSeekAPI 返回慢或你的网络对 api.deepseek.com 握手有延迟WPS 就表现成“死机”。很多人以为是宏写错了其实只是请求没回来。解决给 xhr 加超时控制并在超时后做友好提示。xhr.timeout 30000; xhr.ontimeout function () { MsgBox(请求超时请确认网络状态后重试); };30 秒是办公场景的折中值。改稿任务通常 10 秒内返回摘要长文档可能接近 20 秒。设置 30 秒能覆盖绝大多数情况又不至于让用户等太久。再加一层保险同步请求前先把要处理的文本长度打印到状态栏text.length 超过 6000 字时主动提示可能超时。4.2 fetch 不可用或不稳定退回 XMLHttpRequest现象网上很多教程用 fetch 写请求粘到 WPS JS 宏里直接报“fetch is not defined”或者明明定义了跑到一半回调不执行。原因WPS 的 JS 宏宿主版本不一。新内核预览版支持标准 fetch稳定版内置的运行时可能只暴露 XMLHttpRequest。团队办公电脑里的 WPS 大多不追求最新版fetch 可用性纯看运气。解决统一用 XMLHttpRequest别赌环境。它的兼容性在 WPS JS 宏里是最稳的。有些版本对同步模式有限制会抛“同步 XHR 不可用”的警告此时把 xhr.open 里的第三个参数改成 true再用 onreadystatechange 接收结果但记得把文档操作挪进回调里做否则对象会提前释放。这是一条我已经踩实的经验能同步就同步不能同步就老老实实在回调里处理千万别用 setTimeout 轮询 response。4.3 返回的 Markdown 在 WPS 里显示成乱码现象模型输出正常接口调用正常MsgBox 里看字符串也没毛病但写入文档后到处都是 # 号、星号和横线像一封失真的邮件。原因DeepSeekAPI 默认返回的是 Markdown 格式文本WPS 不会帮你渲染它只会原样把字符写入文档。你在代码编辑器里看得很舒服的排版落到 WPS 里就是噪音。解决写回前做一次 Markdown 轻清洗也就是前面 3.2 那套正则。注意这套清洗只是“够用”不是完整解析器。真遇到模型返回表格或代码块清洗就不够了这时应该在 prompt 层拦住明确要求“禁止输出 Markdown 表格、代码块、标题符号”。与其事后解析不如事前约束prompt 能解决的问题不要让代码去扛。4.4 写回时遇到 WPS 报错 75保护区域和多窗口的锅现象替换选区文本时宏弹出“wps报错75”或“下标越界”代码明明在读取时还好好的。原因报错 75 在 WPS/VBA 体系里通常跟路径访问有关但 JS 宏里遇到它九成是文档区域受保护或当前焦点不在文档正文而在页眉、批注框。另一个隐蔽触发点是用户开了多个文档窗口Selection 对象拿到的是旧窗口的引用。解决写回前检查当前文档是否可编辑。if (doc.ProtectedForForms || doc.ReadOnly) { MsgBox(当前文档受保护无法写回); return; }同时建议在宏开头固定活动文档而不是反复让用户保证焦点正确。多窗口场景用 Documents.Item(1) 这类显式引用并不靠谱用户开的窗口顺序经常变。最稳的办法是取 Application.ActiveDocument在宏启动时立刻获取不要跨多个操作窗口后再取。4.5 API Key 硬编码在宏文件里现象脚本写完能跑过几天同事要了一份宏文件你把这段代码发过去了。对方打开代码一眼就看到 sk- 开头的明文 Key于是它出现在聊天记录里、共享文档里甚至被搜索引擎索引。原因JS 宏脚本本质是明文 JavaScript写在代码里的 Key 没有任何保护。解决把 Key 单独放到一个本地配置文件里脚本运行时读取。var fso new ActiveXObject(Scripting.FileSystemObject); var keyFile D:/wps-key/deepseek.key; var apiKey ; if (fso.FileExists(keyFile)) { var tf fso.OpenTextFile(keyFile, 1, false, -1); apiKey tf.ReadLine(); tf.Close(); }如果你们单位的宏环境禁止创建 ActiveXObject备选方案是让 key 通过接口读取或每次启动时手工输入一次存到全局变量。无论如何别把明文 Key 写在一个会被转发的 .js 文件里。这个坑翻车率极高而且翻的是数据安全的车。5. 从宏脚本升级到正式插件加载项结构与团队分发前面的内容能让你在本机用得很爽但“深度集成”意味着不止一个人用、不止一个环境跑。JS 宏脚本的价值在个人自动化一旦要交给同事、覆盖部门级场景就需要把它从“宏列表里的一个函数”变成真正的插件形态。5.1 为什么“能用”的宏不等于“可交付”的插件宏脚本交付最大的痛点是入口太生硬用户要自己打开开发工具、进 JS 宏界面、找到函数再运行。对非技术同事来说这一步已经劝退一半人。另一个痛点是更新你改了一个 prompt要把新的 .js 文件挨个发给所有人还得保证对方复制到正确目录。加载项WPS Add-in正是解决这两个痛点而存在的形态。它可以带自己的界面入口常驻在右边栏或工具栏里脚本以包的形式分发更新时替换整个包即可。把第 3 章的 callDeepSeek 函数逻辑平移到加载项工程里本质没有变变的只是外层包装。如果你只需要在十人以内的小团队内网用不一定要走完整的签名发布流程用加载项开发模式挂载未打包目录就能跑。5.2 最简加载项的文件结构manifest 与入口脚本WPS 加载项本质是一个按规则打包的目录里面至少包含一个描述插件信息的 manifest 文件和一个入口脚本。以目前常见的结构为例目录大致长这样文件作用manifest.xml插件名、版本、入口文件路径等元数据index.js真正的逻辑代码调用 DeepSeekAPI 和处理文档config.json模型参数、API 地址、Key 读取路径icon.png可选功能区或侧边栏图标manifest.xml 的骨架写法如下字段名不同版本略有差异以开发文档当前示例为准但结构思想一致?xml version1.0 encodingUTF-8? manifest plugin nameDeepSeek Office Assistant/name version1.0.0/version idcom.example.deepseek-assistant/id typewps/type runtimejs/runtime mainindex.js/main description基于DeepSeekAPI的WPS智能办公插件/description /plugin /manifest这个文件的核心是 main 字段它告诉 WPS 启动后去加载哪个 JavaScript 文件。index.js 的职责很纯粹把第 3 章里 readSelectionText、writeBackText、callDeepSeek 三件事收拢成一个入口函数。加载项的 UI 部分各版本接口名不统一我不在这里贴易变的 SDK 代码拿到开发文档里当前版本的 hello 示例把“改写选中内容”函数接到按钮点击事件上即可。底层的三件套逻辑是通用的可以直接搬。5.3 安装、验证与分发三种落地方式加载项建好后第一步永远是本地验证。WPS 里打开开发者模式用“从文件夹加载”方式挂载整个目录然后新建文档测试。注意挂载后要完全关闭 WPS 再重开部分版本不会热加载 manifest 变更不重启就看不到入口。验证通过后按场景选分发路径。个人自己用直接把加载项目录挂到 WPS 的固定加载路径下小团队共享把整个目录打成压缩包放到共享盘同事下载后同样走“从文件夹加载”需要正式覆盖整个部门时再把目录按官方规范打成插件包交给 IT 做统一推送。这里要留个醒不要直接压缩成 zip 改名加载项包对内部文件布局有特定要求格式不对会直接加载失败。如果暂时不想学加载项包的构建还有一个过渡方案把写好的宏模板带宏的 WPS 文档放到共享盘让同事用“文件 - 打开 - 模板”的方式进来运行。这个方案不优雅但胜在能立刻让队友用上 AI 能力等流程跑顺再升级成加载项。6. 再往前走一步验证输出质量与参数产品化插件跑通只代表请求通路没问题不代表输出质量稳定。办公场景最怕模型每次都给你不同的措辞昨天给同事的改写结果是一种风格今天又是另一种。所以插件上线前建议先做一组回归验证。准备 5 到 10 个固定样本一段官方文件措辞、一段口语记录、一段带数字的技术描述、一段含表格碎片的长文本。写一个批处理宏把每个样本分别发给 DeepSeekAPI记录返回文本。重点看三条长度漂移是否超过 20%关键数字和专有名词有没有被改写输出里有没有混入解释性话语。这几条不满意就先调 temperature 和 system prompt参数打架时优先改 prompt 而不是改 temperature。场景扩展也顺着这条通路走。做表格公式生成时把选中区域的第一行表头拼进 user 消息让模型返回 Excel 公式遇到“html格式转换wps表格”这类高频需求不要让模型返回 HTML改成返回 TSV 格式的纯文本再在宏里按 \t 切分写入单元格比解析 HTML 标签可靠得多。批量摘要则要注意限流DeepSeekAPI 对并发有限制循环调用时每轮加一秒间隔避免中途撞上 429。到这个阶段插件已经不再是一个脚本而是一套从“读取文档”到“约束模型行为”再到“写回与验证”的完整链路。我会把 temperature、max_tokens、接口地址、模型名都挪进 config.json换模型或调参数时不必改代码业务同事也能接管这个文件。这是我从“写死参数的脚本”到“可维护工具”之间的那个坎跨过去之后后续加功能的速度快很多。前阵子帮同事做一个批量归档功能我图省事把 Key 写死在宏里结果共享出去的瞬间就后悔了。现在我的习惯是任何对接外部 API 的 WPS 脚本第一行就去读配置文件宁可多写十行代码不让密钥出现在能被旁人看见的地方。希望这些踩过的坑能让你少走一段弯路也希望这套从宏到加载项的路径能帮你的文档工作流真正省下时间。本文还有配套的精品资源点击获取