微信扫码
添加专属顾问
我要投稿
解锁ONLYOFFICE AI智能体的无限可能,通过自定义函数打造专属文档处理神器,还能赢取开发大赛奖励! 核心内容: 1. AI函数的概念与核心价值解析 2. 自定义函数开发全流程分步指南 3. 开发大赛参与方式与奖励机制
借助全新 AI 智能体, ONLYOFFICE 为快速发展的数字世界提供了前沿工具。作为开源项目,我们始终鼓励用户通过创新拓展能力边界。现在,您不仅可通过自定义 AI 函数提升文档处理效率,更能参与 ONLYOFFICE AI 智能体功能开发大赛,将创意直接转化为生产力! 本文提供详细实施指南(文末附大赛信息),助您快速掌握函数开发全流程。
AI 函数是 AI 智能体功能的核心构建模块。它们本质上是对 AI 助手发出的指令,可以告诉 AI 助手:
要向 AI 模型发送什么请求;
要对您的文档执行哪些操作。
借助 AI 函数,您可以扩展并控制 AI 与文档内容的交互方式。
commentText 函数可让您直接在文档中添加由 AI 生成的批注。工作流程如下:
选中要添加批注的单词;
打开 AI 智能体对话框(CTRL + B);
输入指令,例如:“解释这段文字”;
按下 Enter。
AI 智能体将运行 commentText 函数,并在文档中插入相关批注:
添加自定义 AI 函数可以扩展 AI 智能体能力,使其能精确满足个人需求。无论是处理文档、电子表格还是演示文稿,智能体的灵活性加上现代 AI 模型的强大功能,都能帮您把创意转化为现实,并整合进工作流中。
智能体的所有 AI 函数都组织在 helpers 目录中,其结构如下:
cell.js – 电子表格编辑器的 AI 函数
slide.js – 演示文稿编辑器的 AI 函数
word.js – 文档编辑器的 AI 函数
创建新的自定义函数时,将其添加到其所属编辑器的适当文件中。
helpers 目录:https://github.com/ONLYOFFICE-PLUGINS/onlyoffice.github.io/tree/8a8b3e3237745bde2f99db5b8cee0abf2c637317/sdkjs-plugins/content/ai/scripts/helpers
添加自定义函数的过程包括两大阶段:
函数注册——在智能体环境中注册 AI 函数及其元数据。
函数执行——实现核心逻辑,包括向 AI 模型发送请求,以及利用我们的 Office API 处理文档内容。https://api.onlyoffice.com/zh-CN/docs/office-api/get-started/overview/
下面将详细介绍这两个阶段。
要添加新函数,我们需执行 RegisteredFunction 对象。它允许我们为函数添加元数据和逻辑。以下示例展示了如何为文档编辑器添加 commentText 函数:
let func = new RegisteredFunction(); func.name = "commentText"; func.params = [ "type (string): whether to add as a 'comment' or as a 'footnote' default is 'comment')" ]; func.examples = [ "If you need to explain selected text as a comment, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Explain this text\", \"type\": \"comment\"}", "If you need to add a footnote to selected text, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Add a footnote to this text\", \"type\": \"footnote\"}", "If you need to comment selected text, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Comment this text\"}", "If you need to explain selected text as a footnote, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Explain this text\", \"type\": \"footnote\"}" ]
其中:
func.name:AI 调用此函数时使用的名称(如 “commentText”)。
func.params:函数期望从 AI 处获得的参数列表。例如:
– prompt (string):批注的描述或指令,为字符串格式。
– type (string):您需要指定插入“批注” 还是 “脚注”类型,为字符串格式。
func.examples:提供给 AI 的正确函数调用示例。
func.description:向 AI 说明该函数的用途。
AI 使用这些参数。RegisteredFunction() 对象被定义在 helperFunc.js 文件中:https://github.com/ONLYOFFICE-PLUGINS/onlyoffice.github.io/blob/8a8b3e3237745bde2f99db5b8cee0abf2c637317/sdkjs-plugins/content/ai/scripts/helperFuncs.js
注册函数后,我们要编写当 AI 被调用时该函数真正执行的逻辑。
使用 Asc.Editor.callCommand() 获取选中的文本。
func.call = async function(params) { let type = params.type; let isFootnote = "footnote" === type;// Executes a block of code inside the editor's context using the office=js API. let text = await Asc.Editor.callCommand(function(){ let doc = Api.GetDocument();// Gets the current selected text range. let range = doc.GetRangeBySelect(); let text = range ? range.GetText() : ""; if (!text) { text = doc.GetCurrentWord();// Selects the current word so comments can be applied to it. doc.SelectCurrentWord(); } return text; });
通过组合 params.prompt 与所选文本,为 AI 构建提示。
let argPromt = params.prompt + ":\n" + text;
使用 AI.Request.create 初始化 AI.Request.create 对象(该对象在 engine.js 文件中被定义),用于向 AI 模型发送请求。
engine.js:https://github.com/ONLYOFFICE-PLUGINS/onlyoffice.github.io/blob/8a8b3e3237745bde2f99db5b8cee0abf2c637317/sdkjs-plugins/content/ai/scripts/engine/engine.js#L554
// Initializes a request engine for communicating with the AI model (e.g. Chat, Translation). let requestEngine = AI.Request.create(AI.ActionType.Chat); if (!requestEngine) return;
调用 chatRequest() 发送请求,并在回调中接收结果。
// Sends a prompt to the AI model and processes the response via callback. Can stream or wait. let result = await requestEngine.chatRequest(argPromt, false, async function(data) { if (!data) return;
使用 AddFootnote() 或 AddComment() 将回复插入为脚注或批注。
AddFootnote 执行:
if (isFootnote) { let addFootnote = true;// Sends a prompt to the AI model and processes the response via callback. Can stream or wait. let result = await requestEngine.chatRequest(argPromt, false, async function(data) { if (!data) return;// Marks the end of a logical group or block action in the editor. await checkEndAction(); Asc.scope.data = data; Asc.scope.model = requestEngine.modelUI.name; if (addFootnote) {// Executes a block of code inside the editor's context using the document model API. await Asc.Editor.callCommand(function(){// Returns the main document object, which gives access to all editing, structure, and selection APIs. Api.GetDocument().AddFootnote(); }); addFootnote = false; }// Inserts the AI-generated result into the document at the current selection or cursor. await Asc.Library.PasteText(data); });
AddComment 执行:
let commentId = null;// Sends a prompt to the AI model and processes the response via callback. Can stream or wait. let result = await requestEngine.chatRequest(argPromt, false, async function(data) { if (!data) return;// Marks the end of a logical group or block action in the editor. await checkEndAction(); Asc.scope.data = data; Asc.scope.model = requestEngine.modelUI.name; Asc.scope.commentId = commentId;// Executes a block of code inside the editor's context using the document model API. commentId = await Asc.Editor.callCommand(function(){// Returns the main document object, which gives access to all editing, structure, and selection APIs. let doc = Api.GetDocument(); let commentId = Asc.scope.commentId; if (!commentId) {// Gets the current selected text range, which can be modified or annotated. let range = doc.GetRangeBySelect(); if (!range) return null; let comment = range.AddComment(Asc.scope.data, Asc.scope.model, "uid" + Asc.scope.model); if (!comment) return null; doc.ShowComment([comment.GetId()]); return comment.GetId(); } let comment = doc.GetCommentById(commentId); if (!comment) return commentId; comment.SetText(comment.GetText() + scope.data); return commentId; }); }); }
注意!
为确保整个修改块在请求完成后可以被撤销,我们在 commentText 函数中统一使用了 StartAction 与 EndAction 方法。
StartAction :https://api.onlyoffice.com/zh-CN/docs/plugin-and-macros/interacting-with-editors/text-document-api/Methods/StartAction/
EndAction:https://api.onlyoffice.com/zh-CN/docs/plugin-and-macros/interacting-with-editors/text-document-api/Methods/EndAction/
带完整注释的 commentText 函数实现:
(function(){// Defines the commentText function — lets AI insert a comment or footnote for selected text using AI response. WORD_FUNCTIONS.commentText = function() {// Creates a new function object that will be registered and exposed to the AI. let func = new RegisteredFunction(); func.name = "commentText";// Lists the parameters expected by the function. These are passed as a JSON object by the AI Agent. func.params = [ "type (string): whether to add as a 'comment' or as a 'footnote' (default is 'comment')" ];// Gives example JSON inputs to teach the AI how to correctly invoke this function. func.examples = [ "If you need to explain selected text as a comment, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Explain this text\", \"type\": \"comment\"}", "If you need to add a footnote to selected text, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Add a footnote to this text\", \"type\": \"footnote\"}", "If you need to comment selected text, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Comment this text\"}", "If you need to explain selected text as a footnote, respond with:\n" + "[functionCalling (commentText)]: {\"prompt\" : \"Explain this text\", \"type\": \"footnote\"}" ]; // The actual logic that gets executed when the AI calls this function. func.call = async function(params) { let type = params.type; let isFootnote = "footnote" === type;// Executes a block of code inside the editor's context using the office-js API. let text = await Asc.Editor.callCommand(function(){ let doc = Api.GetDocument();// Gets the current selected text range. let range = doc.GetRangeBySelect(); let text = range ? range.GetText() : ""; if (!text) { text = doc.GetCurrentWord();// Selects the current word so comments can be applied to it. doc.SelectCurrentWord(); } return text; }); let argPromt = params.prompt + ":\n" + text;// Initializes a request engine for communicating with the AI model (e.g. Chat, Translation). let requestEngine = AI.Request.create(AI.ActionType.Chat); if (!requestEngine) return; let isSendedEndLongAction = false;// Marks the end of a logical group or block action in the editor. async function checkEndAction() { if (!isSendedEndLongAction) {// Marks the end of a logical group or block action in the editor. await Asc.Editor.callMethod("EndAction", ["Block", "AI (" + requestEngine.modelUI.name + ")"]); isSendedEndLongAction = true } }// Starts a block action in the editor, used for undo/redo await Asc.Editor.callMethod("StartAction", ["Block", "AI (" + requestEngine.modelUI.name + ")"]);// Starts a block action in the editor, used for undo/redo await Asc.Editor.callMethod("StartAction", ["GroupActions"]); if (isFootnote) { let addFootnote = true;// Sends a prompt to the AI model and processes the response via callback let result = await requestEngine.chatRequest(argPromt, false, async function(data) { if (!data) return;// Marks the end of a block action in the editor. await checkEndAction(); Asc.scope.data = data; Asc.scope.model = requestEngine.modelUI.name; if (addFootnote) {// Executes a block of code inside the editor's context using the office-js API. await Asc.Editor.callCommand(function(){ Api.GetDocument().AddFootnote(); }); addFootnote = false; }// Inserts the AI-generated result into the document at the current selection or cursor. await Asc.Library.PasteText(data); }); } else { let commentId = null;// Sends a prompt to the AI model and processes the response via callback. let result = await requestEngine.chatRequest(argPromt, false, async function(data) { if (!data) return;// Marks the end of a block action in the editor. await checkEndAction(); Asc.scope.data = data; Asc.scope.model = requestEngine.modelUI.name; Asc.scope.commentId = commentId;// Executes a block of code inside the editor's context using the office-js API. commentId = await Asc.Editor.callCommand(function(){ let doc = Api.GetDocument(); let commentId = Asc.scope.commentId; if (!commentId) {// Gets the current selected text range. let range = doc.GetRangeBySelect(); if (!range) return null; let comment = range.AddComment(Asc.scope.data, Asc.scope.model, "uid" + Asc.scope.model); if (!comment) return null; doc.ShowComment([comment.GetId()]); return comment.GetId(); } let comment = doc.GetCommentById(commentId); if (!comment) return commentId; comment.SetText(comment.GetText() + scope.data); return commentId; }); }); }// Marks the end of a block action in the editor. await checkEndAction();// Marks the end of a block action in the editor. await Asc.Editor.callMethod("EndAction", ["GroupActions"]); }; return func; }
我们始终致力于紧跟现代技术,确保智能 AI 智能体持续演进,以满足当今数字世界需求。通过创建自定义函数,您可以扩展 AI 能力,直至能完全满足个人需求。我们期待您的创意与想法。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-09-09
开源智能体开发框架全面对比分析
2025-09-09
Dify Pre-release版本来了,Dify2.0时代不远了,看看有哪些进步?
2025-09-09
硅基流动上线 DeepSeek-V3.1,上下文升至 160K
2025-09-08
微信公众号“内容孤岛”终结者:免费开源工具,批量下载+完美还原!
2025-09-08
Claude不让用,有哪些国产模型能迎头赶上?
2025-09-08
前豆包大模型市场负责人创业,GEO服务商「PureblueAI清蓝」获千万级种子轮融资 丨涌现新项目
2025-09-08
神秘模型上线,极有可能是Gemini 3,附详细配置使用指南
2025-09-07
阿里Qoder vs Trae vs Cursor:谁才是2025年程序猿的效率之王?
2025-07-23
2025-06-17
2025-08-20
2025-06-17
2025-07-23
2025-08-05
2025-07-14
2025-08-20
2025-07-29
2025-09-07
2025-09-09
2025-09-08
2025-09-07
2025-09-01
2025-08-16
2025-08-13
2025-08-11
2025-08-11