开头先交代一个真实背景:我手上长期维护着几套文档自动化工具,其中一套就是把豆包API接进Word,覆盖Microsoft Office的Word和WPS文字,全部用VBA写成,没有任何额外插件。这周有个做行政的朋友问我要方案,我干脆把完整实现整理成这篇博文,从申请API Key到写宏、绑定按钮、排坑,一次性讲透。如果你每天要写材料、改通知、翻邮件,又不想在浏览器和Word之间来回切,这篇就是为你准备的。
1. 为什么要在Word里接豆包API:方案选型与原理
1.1 这脚本解决的问题,以及解决不了的问题
先说能解决什么。最典型的使用方式:在Word里选中一段写得不顺的文字,按一下快捷键,豆包API把润色后的版本返回给你,要么直接替换原文,要么追加到文末;选中的英文段落,一键翻译成中文;月底写工作总结时,把零散的工作要点丢进去,AI帮你整理成三段式的完整汇报。整个过程不离开Word窗口,格式不乱、上下文不丢,比“复制到网页、等结果、再粘贴回来”至少省一半时间。
这个方案解决不了的事情也要说清楚。它不适合做长篇生成,比如一次让AI写八千字的行业报告,VBA往HTTP请求里塞那么长的字符串,既慢又容易碰长度限制;它也不适合做实时对话,毕竟每点一次按钮就要等一次网络往返。本质上这只是一个“选中文本—请求AI—写回结果”的文档增强工具,定位是写作辅助,不是聊天机器人。
1.2 为什么选豆包API:选型背后的具体考量
选豆包API,不是因为它比其他大模型强,而是综合条件最适合Word自动化这个场景。
第一是调用方便。豆包API提供的是标准的chat/completions接口,请求和返回都是JSON格式,VBA用HTTP对象就能直接对接,不需要任何SDK。对VBA这种老环境来说,接口越标准越省事,越花哨越容易踩兼容性的坑。
第二是中文写作质量够用。Word场景里处理的大部分内容都是中文公文、邮件、总结、翻译,豆包的中文语料和风格控制能力在同类模型里属于第一梯队,润色、改写、翻译这些任务实测下来效果让人满意。
第三是配额申请简单。注册开放平台后,按指引开通服务、创建API Key、选一个模型ID就能调用,新人也有一定的免费额度,适合先跑通流程再决定要不要升级。至于模型ID选哪个,可以从官方文档里找最新的对话模型名称,比如doubao-pro系列和lite系列,文本稍长、要求质量高就选大模型,日常短文本用小模型,成本和速度更划算。
1.3 为什么用VBA而非插件:兼容性与门槛
群里总有人问,为啥不用COM加载项、Office JS宏或者独立软件?我的答案很简单:VBA是Microsoft Office和WPS文字两边现存的最大公约数。
Office这边自带VBA编辑器,F11就能打开,保存为.docm文件即可;WPS文字虽然在个人版里默认不带VBA,但官方提供一个VBA插件,装上之后,宏的语法、对象模型、开发体验都跟Office高度一致。也就是说,同一份VBA代码,两边都能跑,这比任何第三方插件跨两个平台都好使。
从门槛角度看,做一个Office插件要学打包、清单文件、代码签名,办公用户基本劝退;独立软件又涉及安装部署、权限、杀毒拦截。VBA的入门门槛反而是最低的:你只需要把代码粘进编辑器,运行一次,再把宏绑到按钮上就结束了。对于“给自己用”的办公自动化场景,VBA就是性价比最高的选择。
1.4 一句话讲清VBA调用AI的完整链路
我用最简单的方式描述整个运行过程:你选中Word里的一段文字,宏把这段文本读取出来,转义成JSON能接受的格式,拼进HTTP请求体里,通过ServerXMLHTTP对象POST到豆包API的接口,等接口返回一段JSON,宏再从中抠出“AI生成的文本”,最后把这个文本插入到Word文档中。
说得更具体一点,链路里每一步都有对应的VBA操作:选区用Selection.Text读取;JSON组装靠字符串拼接;网络请求用CreateObject("MSXML2.ServerXMLHTTP.6.0");解析返回值则是在JSON里定位content字段。整条链路里没有隐藏的黑魔法,每一步都可以独立调试,这也是我推荐用VBA入门AI接入的原因——你看到的就是正在发生的。
2. 接入前的准备:申请API Key与配置VBA环境
2.1 在豆包开放平台拿到API Key
打开豆包的开放平台或火山方舟控制台,登录后先完成个人实名认证,一般几分钟就能通过。接着开通大模型服务,在“API Key管理”里创建一个新的Key,这个Key是后续请求的身份凭证,格式上是一串较长的字母数字组合。
这里有一个重要的习惯:创建Key时,平台通常只完整显示一次,务必复制保存到一个安全的地方,比如密码管理器或专门的配置文件里。千万不要把Key贴在共享文档里发给同事,也不要在群里截图,Key一旦泄露,别人就能用你的配额刷接口,产生不必要的费用。我一般把这个Key放在一个单独的txt文件里,开发时读取,不进代码库,也不写死到模板。
2.2 必须先看懂的请求返回结构
豆包API的接口格式是OpenAI兼容的chat/completions格式,这一点非常关键,因为它决定了下面的VBA代码怎么写。请求体是一个JSON对象,通常包含model、messages、temperature、max_tokens四个字段。model填模型ID;messages是一个数组,里面至少有一条system消息(设定角色)和一条user消息(放你给AI的内容);temperature控制随机性,写作场景一般0.5到0.8;max_tokens控制最长回复长度。
返回体也是一个JSON对象,核心内容在choices数组里,第一个元素的message对象下面有一个content字段,字段值就是AI回复的正文。理解了这两个结构,VBA代码就能精准地“发什么”和“取什么”。我建议第一次测试时,先用浏览器工具或命令行工具手动发一个请求,把返回的JSON看一遍,再写VBA,能省去很多调试时间。
2.3 Word与WPS两个环境分别怎么开VBA
Microsoft Office的Word开VBA很简单:文件→选项→自定义功能区,在右侧主选项卡里勾选“开发工具”,确认之后顶部菜单栏就会出现“开发工具”标签,点进去就能看到“Visual Basic”和“宏”入口。F11是打开VBA编辑器的快捷键,这里我用了十年,闭着眼都能摸到。
WPS文字略有区别。WPS个人版默认没有VBA功能,需要先到WPS官网或开放平台下载并安装VBA插件,安装后重启WPS文字,开发工具标签就会出现。如果装的WPS版本较新同时是教育版等特殊版本,VBA支持情况略有差异,但流程一致:开发工具→宏。另外,在WPS里运行宏之前,到“工具→选项→安全性”里把宏安全性调整为中或低,文件保存时选择“启用宏的文档”格式,也就是.docm后缀,否则宏会静默丢失。
提示:公司电脑如果有宏安全策略,优先使用“受信任位置”,把包含宏的文档放到指定受信任文件夹,这样既不影响安全,也不会有“无法运行宏”的弹窗。
2.4 HTTP对象选型:为什么是ServerXMLHTTP.6.0
VBA里发HTTP请求有两个常用对象:MSXML2.XMLHTTP和MSXML2.ServerXMLHTTP.6.0。很多老教程用XMLHTTP,但我强烈建议用ServerXMLHTTP.6.0。原因是XMLHTTP基于Windows的WinINet组件,容易受系统代理和缓存配置影响,在部分Office环境下行为不稳定;ServerXMLHTTP则是为服务器端通信设计的组件,对HTTPS证书的校验更严格,在Word这类宿主环境里表现更可靠。
还有一个实际好处是版本。6.0版在Windows 7及以上系统基本都自带,不需要额外注册组件,CreateObject直接就new出来了。如果哪天遇到公司电脑注册表异常导致6.0不可用,可以临时退回XMLHTTP测试,但正式方案里我始终用ServerXMLHTTP.6.0。同步请求模式下,VBA会等在HTTP响应结束才继续执行,代码逻辑最简单,不用处理回调函数,这也是它适合VBA的原因。
3. 可直接抄的VBA代码:请求、解析与写回
3.1 主控宏:从选中文本到插入结果
主控宏是这个工具的总入口,作用一共四步:检查用户是否选中了文字,调用AI,拿到结果,写回Word。核心代码如下:
Sub AskDoubao() Dim sSelection As String Dim sResult As String sSelection = Trim(Selection.Text) If Len(sSelection) < 2 Then MsgBox "请先选中需要处理的文字内容。", vbExclamation, "豆包助手" Exit Sub End If sResult = CallDoubaoEx("polish", sSelection) If sResult <> "" Then ' 这里是输出方式的选择,三选一 Selection.Text = sResult ' 1. 直接替换选中内容 ' Selection.InsertAfter vbCrLf & sResult ' 2. 追加到选中内容后面 ' 新建文档输出:Documents.Add:再到新文档里插入 End If End Sub这里我故意把输出方式放在注释里说明。实际使用中,“润色”我习惯用直接替换,因为目标是让原文变得更好;“翻译”我常用追加方式,保留原文做对照;如果是“生成新内容”,那就新建文档。你拿到代码后第一件事就是把注释按你的习惯改一行。
主控宏里的If判断很重要,因为Selection.Text在没有任何选中文本时可能只有一个段落标记,直接发给API会浪费一次请求。我加了一个2字符的最小长度判断,实测能避免不少误触。
3.2 发送请求:把账号信息和JSON组装处理好
核心的请求函数需要处理三件事:组装JSON请求体、设置HTTP头、发送并接收响应。代码如下:
Function CallDoubaoEx(ByVal sType As String, ByVal sText As String) As String Const sUrl As String = "https://ark.cn-beijing.volces.com/api/v3/chat/completions" Const sApiKey As String = "你的APIKey" Const sModel As String = "doubao-pro-32k" Dim sMessages As String Dim sBody As String Dim objHTTP As Object Dim sResp As String sMessages = CreateMessages(sType, sText) sBody = "{" & _ """model"": """ & sModel & """," & _ """messages"": " & sMessages & "," & _ """temperature"": 0.7," & _ """max_tokens"": 2048" & _ "}" Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0") objHTTP.setTimeouts 10000, 10000, 20000, 60000 objHTTP.Open "POST", sUrl, False objHTTP.setRequestHeader "Content-Type", "application/json; charset=utf-8" objHTTP.setRequestHeader "Accept", "application/json" objHTTP.setRequestHeader "Authorization", "Bearer " & sApiKey objHTTP.send sBody If objHTTP.Status = 200 Then sResp = objHTTP.responseText CallDoubaoEx = ParseContent(sResp) Else MsgBox "请求失败:" & objHTTP.Status & vbCrLf & objHTTP.responseText, vbCritical CallDoubaoEx = "" End If End FunctionsetTimeouts那行建议保留:第一个参数是连接超时,第二个是发送超时,第三个是接收超时,第四个是整体超时,单位都是毫秒。我习惯给整体超时留到60秒,因为长文本生成确实可能超过20秒,太短的话会误报失败。
Authorization头的格式是固定的“Bearer”加空格加Key,这是整套鉴权机制中最容易写错的地方。我见过好几个同事把Bearer漏掉,返回401还百思不得其解,这行代码一定要原样保留。
3.3 解析回复:两种方式,小白选A老手选B
解析返回JSON有两种方案。方案A是字符串定位,代码量最少,适合大多数日常场景;方案B是引入JSON解析库,处理特殊字符更稳妥。
先看方案A。豆包接口返回的JSON里,content字段位于"content":"之后、下一个","之前,定位逻辑非常直接:
Function ParseContent(ByVal sResp As String) As String Dim sKey As String Dim iPos As Long Dim sRaw As String sKey = """content"":""" iPos = InStr(sResp, sKey) If iPos <= 0 Then ParseContent = "" Exit Function End If sRaw = Mid$(sResp, iPos + Len(sKey)) sRaw = Left$(sRaw, InStr(sRaw, """,""") - 1) sRaw = Replace(sRaw, "\\n", vbCrLf) sRaw = Replace(sRaw, "\\\""", """") sRaw = Replace(sRaw, "\\", "") ParseContent = sRaw End Function这个方案的局限在于:如果AI回复的内容里恰好包含了类似","的字符组合,截断位置就会算错。简单润色、翻译场景基本碰不上,但如果你让AI生成包含JSON示例的代码,就可能翻车。所以我强烈建议把JsonConverter导入VBA工程,这是社区流传很广的一个VBA JSON解析库,把.bas文件导入编辑器后,解析代码变成:
Dim objJson As Object Set objJson = Json.Decode(sResp) ParseContent = Json.GetProperty(objJson, "choices[0].message.content")这个方案能正确处理转义字符和不规则结构,代价是代码依赖外部模块。我的个人做法是:自己用的工具直接上JsonConverter,分享给同事的简化版用字符串定位。
3.4 Prompt设计:AI好不好用,一半靠这里
很多人的VBA写出来了,但AI给出的结果很空,问题几乎都出在Prompt上。豆包这类模型吃“角色设定”和“任务指令”,你需要把这两个层次分开写。
Function CreateMessages(ByVal sType As String, ByVal sText As String) As String Dim sSystem As String Dim sUser As String Select Case LCase(sType) Case "polish" sSystem = "你是资深中文写作编辑,擅长润色文字,让表达更通顺、精炼、专业。" sUser = "请润色下面这段文字,保持原意,直接输出润色后的结果,不要附加解释。" & vbCrLf & sText Case "translate" sSystem = "你是专业翻译,中英互译准确地道,符合目标语言表达习惯。" sUser = "请将下面内容翻译成英文,直接输出译文:" & vbCrLf & sText Case "summary" sSystem = "你是高效的信息提炼助手,能把长文本压缩成要点。" sUser = "请用三句话总结下面内容,直接输出总结:" & vbCrLf & sText Case "email" sSystem = "你是商务写作专家,语气得体、结构清晰。" sUser = "请根据下面要点起草一封商务邮件,直接输出邮件正文:" & vbCrLf & sText Case Else sSystem = "你是文档写作助手。" sUser = sText End Select CreateMessages = "[{""role"":""system"",""content"":""" & EscapeJson(sSystem) & """}," & _ "{""role"":""user"",""content"":""" & EscapeJson(sUser) & """}]" End FunctionPrompt里最关键的一句是“直接输出结果,不要附加解释”。不加这句,模型经常给你来一段“好的,下面是我润色后的版本:”之类的废话,还要手动清理。几个模式的system prompt区别明显:润色强调保持原意,翻译强调地道,总结强调要点数量,邮件强调语气。你可以照这个模板自定义更多场景,比如“会议纪要”“宣传文案”“公文格式”,把常用的Prompt固定成参数最省心。
3.5 编码与转义:中文乱码从哪来
VBA向HTTP请求体里塞中文,最常遇到的问题就是乱码或者JSON解析失败。根因在于JSON字符串里的特殊字符必须转义,以及HTTP响应用UTF-8编码。
所以必须写一个EscapeJson函数,把中文原文里的反斜杠、双引号、换行、制表符转成JSON合法形式:
Function EscapeJson(ByVal sText As String) As String sText = Replace(sText, "\", "\\") sText = Replace(sText, """", "\""") sText = Replace(sText, vbCrLf, "\n") sText = Replace(sText, vbLf, "\n") sText = Replace(sText, vbTab, "\t") EscapeJson = sText End Function这个函数要在两个位置配合使用:组装messages时,对Prompt文本调用;如果AI返回content里带换行符,解析时再把\\n还原成vbCrLf。很多人问“为什么返回的文字都堆在一行里”,就是少了最后一步Replace。
中文乱码本身在responseText场景下不太常见,因为ServerXMLHTTP会自动按UTF-8解码响应内容。如果你用了XMLHTTP且出现乱码,优先检查响应头里的charset声明,或者干脆换成ServerXMLHTTP再看结果。
4. 把脚本变成“Word里的AI按钮”
4.1 Word快速访问工具栏绑定宏
代码写好之后,真正的日常使用不应该每次打开宏对话框去运行。我建议把主控宏绑到Word左上角的快速访问工具栏,方式很简单:文件→选项→快速访问工具栏,在“从下列位置选择命令”下拉框里选择“宏”,找到AskDoubao,点添加,再点确定,工具栏上就会出现一个带分行符图标的按钮。
这个图标默认不怎么直观,你可以右键按钮选择自定义外观,给它换成绿色圆形或铅笔图标,目的只有一个:让你能一眼找到。绑定按钮还有一个额外好处——不占用功能区空间,也不会在打印时出现。
4.2 WPS文字里添加宏按钮的差异
WPS文字的设置路径和Office略有不同:开发工具→宏,选中AskDoubao后点击“选项”或“自定义”,把宏指定到快捷键或快速访问工具栏。WPS的快速访问工具栏同样支持添加宏按钮,只是菜单名称在不同版本叫法略有差异,有的版本叫“选项”,有的版本叫“自定义快速访问工具栏”。
实测下来,WPS对宏按钮的稳定性整体不错,但有个情况要注意:如果WPS文字升级版本,快速访问工具栏里的自定义宏按钮偶尔会丢失,重新添加一次就行。相比之下,Word的按钮保存得更持久,这是一个细微差别,提前知道能省一次翻找菜单的时间。
4.3 一次加四个按钮:润色、翻译、总结、起草邮件
主控宏只负责一个功能,体验上不够完整。我更推荐的方案是定义一组宏,每个宏只是换一个参数:
Sub AiPolish() RunDoubaoAction "polish" End Sub Sub AiTranslate() RunDoubaoAction "translate" End Sub Sub AiSummary() RunDoubaoAction "summary" End Sub Sub AiMail() RunDoubaoAction "email" End Sub Private Sub RunDoubaoAction(ByVal sType As String) Dim sSelection As String Dim sResult As String sSelection = Trim(Selection.Text) If Len(sSelection) < 2 Then MsgBox "请先选中文字。", vbExclamation, "豆包助手" Exit Sub End If sResult = CallDoubaoEx(sType, sSelection) If sResult <> "" Then Selection.Text = sResult End If End Sub把四个宏分别添加到快速访问工具栏,你的Word就变成一个带“润色、翻译、总结、邮件”四个按钮的AI写作工具。每个按钮只做一件事,逻辑清晰,也不用担心忘记切换模式。你还能给每个按钮分配不同的图标和快捷键,常年使用的话,肌肉记忆比鼠标点击快得多。
4.4 进阶用法:整篇文档自动分段处理
单个选中已经满足大部分需求,但如果你拿到一份几十页的材料,要逐段润色,手动一段段选太折磨人。这时候可以把逻辑升级成遍历段落。核心思路是用Word的Paragraph对象遍历Selection覆盖范围内的每一段,跳过太短的段落,逐段调用API并写回:
Dim para As Paragraph For Each para In Selection.Paragraphs Dim txt As String txt = Trim(para.Range.Text) If Len(txt) > 20 Then Dim res As String res = CallDoubaoEx("polish", txt) If res <> "" Then para.Range.Text = res End If Application.Wait (Now + TimeValue("0:00:02")) End If Next para这个写法能用,但速度不快,因为每段一次网络请求。我更推荐的做法是先把整篇内容合并成几个大块,每块控制在1000字以内,分3到5次请求完成,最后手动检查链接处。这么做的原因是API调用有频率限制和单次长度限制,一次塞整个文档容易超时或触发限流,分段分批反而更稳。
5. 踩坑实录:常见问题与排查速查表
5.1 高频报错对照表,先收藏
我把自己和周围朋友用过一段后的高频问题整理成一张表,你可以直接对照排查:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 提示“运行时错误91”或结果为空 | 网络请求失败,或解析函数没找到content字段 | 检查网络连接;用MsgBox输出完整响应文本,看返回是否正常 |
| 返回HTTP 401 | API Key错误,或忘记Bearer前缀 | 核对Key;确认请求头格式是“Bearer 你的Key” |
| 返回HTTP 429 | 触发频率限制 | 在循环调用里加Application.Wait延时 |
| 返回内容全是英文或乱码 | 编码问题或模型输出异常 | 检查Content-Type是否带charset=utf-8;换模型ID重试 |
| 返回内容堆在一行 | 换行符没还原 | 在解析函数里把\n正确Replace成vbCrLf |
| Word里宏按钮是灰的 | 文档不是宏格式 | 另存为.docm,确认文件在受信任位置 |
| WPS里找不到宏入口 | 没有安装VBA插件 | 到WPS官方下载安装VBA插件,重启软件 |
这张表不完整,但覆盖了我遇到过的九成情况。如果你看到报错但不在这张表里,下一步永远是MsgBox打印响应原文,真相全在返回JSON里。
5.2 密钥安全:最容易忽略的坑
API Key泄露是这类工具最常见的翻车点。因为VBA代码明文保存在宏里,只要别人拿到你的.docm文件,打开宏编辑器就能看到Const sApiKey那一行,然后你的Key就变成了别人的提款机。
我现在的做法是把Key从代码里分离出来:运行时用InputBox让用户输入Key,存入模块级变量,不写进文档;也可以把Key存到电脑的某个文本文件中,宏启动时读取,如果找不到就提示设置。还有一个方案是把Key放到文档的自定义文档属性里,界面不可见,但代码可以读取。无论哪种方式,原则只有一条:Key不属于代码,只属于运行它的那台机器。
5.3 超时与限流:请求卡住怎么办
VBA同步请求有个让人焦虑的问题:点击按钮后,Word界面会卡住几秒甚至几十秒,看起来像死机。这是正常现象,因为VBA在等HTTP返回。解决方法是给setTimeouts设一个合理值,同时做好提示——在调用前弹一个“正在请求AI,请稍候”的临时窗体,或者直接接受等待。
遇到429限流时,不要天真地以为过一会儿自动好。连续请求几十次后,平台会对高频调用做频率限制,这时候最简单有效的方案是加延时。批量处理脚本里每段请求后睡2秒,虽然慢,但基本不会触发限流。
5.4 Office与WPS兼容性差异
同一段VBA代码在Office和WPS里跑,绝大多数情况结果一致,但有几个差异值得注意。首先是环境依赖:Office自带VBA,WPS需要VBA插件,两边都要在开发工具标签下运行宏,没有哪个版本天然免这一步。其次是对象行为:Selection、Paragraph等基础对象两边通用,但部分窗口类属性和事件在WPS里支持不完整,比如自定义窗体的某些细节外观会不同。
最稳妥的排查方式是在两套环境里都跑一遍同样的测试用例。我的经验是先确保代码在Office里正常,再到WPS里验证一遍输出结果,两边差距通常集中在按钮绑定和快捷键上,代码本身改动很少。
5.5 这套思路还能扩展到哪里
最后的扩展价值其实比Word本身更大。同一套CallDoubaoEx和EscapeJson函数,可以直接移植到Excel VBA里,批量处理单元格内容;Outlook的VBA也能用,实现发邮件前自动润色正文;PowerPoint里做备注生成也同样可行。核心差异只在于宿主对象怎么取文本,连接API和解析结果的那部分代码完全复用。
我也在考虑把这段代码改造成一个独立的个人工具库,把API Key统一管理、Prompt统一配置,免得每个Office组件里都存一份。这个方向值得继续做,但那是下一个项目的事了。
我个人用得最多的场景还是润色和翻译。刚开始接入时,我真觉得VBA太老,担心这些网络操作它搞不定,实际跑通后发现,恰恰是VBA这种朴素环境,能把API调用、文本处理、文档写入都规规矩矩地串起来。最后提醒一句:带宏的文件请务必另存为.docm,我见过太多人辛辛苦苦写完宏,存成.docx后宏全部丢失,又从头再来一遍。这个小习惯,比任何调试技巧都省心。