逐步指南:向 ONLYOFFICE AI 智能体中添加自定义 AI 函数

2025年08月21日作者:Krystal

借助全新 AI 智能体,ONLYOFFICE 为当下快速发展的数字世界提供了前沿工具。作为开源项目,我们欢迎用户的创新。本文将展示如何向 AI 智能体添加自定义函数,使处理文档更快更便捷。

Step-by-step guide: adding custom AI functions to ONLYOFFICE AI agent

什么是 AI 函数?AI 函数有什么用途?

AI 函数是 AI 智能体功能的核心构建模块。它们本质上是对 AI 助手发出的指令,可以告诉 AI 助手:

  • 要向 AI 模型发送什么请求;
  • 要对您的文档执行哪些操作。

借助 AI 函数,您可以扩展并控制 AI 与文档内容的交互方式。

如何使用 AI 函数

  1. AI 插件中选择并添加模型。
  2. 按下 CTRL + B 打开 AI 智能体对话框
  3. 输入提示并按 Enter

示例:commentText 函数

commentText 函数可让您直接在文档中添加由 AI 生成的批注。工作流程如下:

  • 选中要添加批注的单词;
  • 打开 AI 智能体对话框(CTRL + B)
  • 输入指令,例如:“解释这段文字”;
  • 按下 Enter

Step-by-step guide: adding custom AI functions to ONLYOFFICE AI agent

AI 智能体将运行 commentText 函数,并在文档中插入相关批注:

Step-by-step guide: adding custom AI functions to ONLYOFFICE AI agent

为什么要为 AI 智能体添加自定义函数?

添加自定义 AI 函数可以扩展 AI 智能体能力,使其能精确满足个人需求。无论是处理文档、电子表格还是演示文稿,智能体的灵活性加上现代 AI 模型的强大功能,都能帮您把创意转化为现实,并整合进工作流中。

添加自定义 AI 函数的总体逻辑

添加自定义函数的过程包括两大阶段:

  • 函数注册——在智能体环境中注册 AI 函数及其元数据。
  • 函数执行——实现核心逻辑,包括向 AI 模型发送请求,以及利用我们的 Office API 处理文档内容。

下面将详细介绍这两个阶段。

函数注册

要添加新函数,我们需执行 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 文件中。

函数执行逻辑

注册函数后,我们要编写当 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 模型发送请求。
// 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 函数中统一使用了 StartActionEndAction 方法。

带完整注释的 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 能力,直至能完全满足个人需求。我们期待您的创意与想法。

如有任何疑问、建议或反馈,欢迎随时与我们联系。我们希望帮助您将愿景变为现实,祝愿您在探索 AI 功能的过程中一帆风顺。

创建免费的 ONLYOFFICE 账户

在线查看并协作编辑文本文档、电子表格、幻灯片、表单和 PDF 文件。