首页
/ GPT Academic 插件开发指南:从函数式插件到类式插件的完整实践

GPT Academic 插件开发指南:从函数式插件到类式插件的完整实践

2026-09-05 17:55:46作者:钟日瑜

GPT Academic 的核心能力来源于其丰富的插件生态:从论文翻译到代码分析,从联网搜索到图片生成,每一个功能都以插件形式实现在 crazy_functions/ 目录下。本文基于仓库中的 插件开发文档 与真实源码,完整讲解两类插件(函数式与类式)的编写、注册、参数传递机制、文件上传与批量处理等实战技巧,并深入 toolbox.pycrazy_functions/crazy_utils.py 与插件模板类,帮助读者掌握从零开发一个可注册、可热更新、可交互的 GPT Academic 插件的完整能力。

插件系统概览

在开始编写代码之前,先了解 GPT Academic 插件系统的基本架构。

所有插件都位于 crazy_functions/ 目录下。当用户点击界面上的功能按钮或从下拉菜单选择插件时,系统会调用相应的插件函数或类来处理请求。插件可以访问用户的输入文本、对话历史、文件上传等信息,并通过大模型生成响应。

GPT Academic 支持两种插件形式:

类型 适用场景 特点
函数式插件 简单功能,无需用户额外输入 开发快速,代码简洁
类式插件 复杂功能,需要二级选项菜单 支持参数配置,交互更灵活

对于大多数场景,函数式插件已经足够。当需要在执行前让用户选择参数(如翻译语言、输出格式等)时,再考虑使用类式插件。这一区分在源码中也有直接体现:crazy_functional.pyget_crazy_functions() 函数集中导入并注册了所有插件,每个插件以字符串名为键,配置字典为值,"Function" 指向函数式入口,"Class"(可选)指向类式插件,例如"注释Python项目"同时注册了 HotReload(注释Python项目)SourceCodeComment_Wrap 两个入口。

开发环境与热重载机制

插件开发无需特殊的环境配置,只需确保已经成功运行了 GPT Academic。开发过程中建议开启热重载功能,修改插件代码后无需重启程序即可生效。

热重载能力来自 toolbox.py 中的 HotReload 装饰器。从源码实现看,它依赖配置项 PLUGIN_HOT_RELOAD

def HotReload(f):
    if get_conf("PLUGIN_HOT_RELOAD"):
        @wraps(f)
        def decorated(*args, **kwargs):
            fn_name = f.__name__
            f_hot_reload = getattr(importlib.reload(inspect.getmodule(f)), fn_name)
            yield from f_hot_reload(*args, **kwargs)
        return decorated
    else:
        return f

PLUGIN_HOT_RELOAD 开启时,装饰器在每次调用插件前通过 importlib.reload 重新加载插件所在模块,并用 getattr 取出同名的最新函数执行。这意味着保存插件文件后,下次调用该插件时会自动加载最新代码,极大提升开发效率;若该配置关闭,HotReload 会原样返回原函数,不影响插件正常运行。

函数式插件开发

从最简单的函数式插件开始,下面这个示例会查询"历史上的今天"发生的事件:

from toolbox import CatchException, update_ui
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
import datetime

@CatchException
def 历史上的今天(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
    """
    插件入口函数

    参数说明:
        txt           - 用户在输入框中输入的文本
        llm_kwargs    - 大模型参数(温度、top_p 等)
        plugin_kwargs - 插件参数(来自二级菜单,函数式插件通常为空)
        chatbot       - 对话显示组件,用于更新界面
        history       - 对话历史记录
        system_prompt - 系统提示词
        user_request  - 用户请求信息(包含 IP 等)
    """
    # 清空历史,避免上下文过长
    history = []

    # 获取当前日期
    today = datetime.date.today()

    # 在界面上显示处理状态
    chatbot.append(("正在查询历史上的今天...", "请稍候..."))
    yield from update_ui(chatbot=chatbot, history=history)

    # 构造提问
    query = f"请列举历史上 {today.month}{today.day} 日发生的 3 个重要事件,简要说明每个事件的背景和影响。"

    # 调用大模型并流式输出
    response = yield from request_gpt_model_in_new_thread_with_ui_alive(
        inputs=query,
        inputs_show_user=query,
        llm_kwargs=llm_kwargs,
        chatbot=chatbot,
        history=history,
        sys_prompt="你是一位历史学专家,擅长介绍历史事件。"
    )

    # 更新对话历史
    history.extend([query, response])
    yield from update_ui(chatbot=chatbot, history=history)

这个示例虽然简单,但包含了插件开发的所有核心要素,逐一解析如下:

装饰器 @CatchException 是一个错误处理包装器,确保插件运行时的异常不会导致整个程序崩溃。从 toolbox.py 的源码实现看,它会区分 FriendlyException 与一般 Exception 两类异常:前者渲染友好的错误 HTML,后者将精简后的 traceback 以 [Local Message] 插件调用出错 的形式追加到对话界面,并通过 update_ui 刷新界面。在开发阶段,它会把错误信息显示在对话界面中,方便调试。

函数签名定义了插件接收的参数。这七个参数是所有插件的标准接口,可以按需要使用其中的部分或全部。

yield from update_ui() 是更新界面的关键。由于插件函数是一个生成器,使用 yield from 可以实时将处理进度反馈给用户,而不是等待所有处理完成后才显示结果。

request_gpt_model_in_new_thread_with_ui_alive() 是调用大模型的核心函数,定义于 crazy_functions/crazy_utils.py。从源码实现看,它内部使用 ThreadPoolExecutor 在独立线程中发起请求,同时以约 0.2 秒的间隔向 chatbot 回写部分结果以保持界面响应;它还内置了看门狗机制(watch_dog_patience)检测程序终止,并可在 token 溢出时通过 input_clipping 自动截断重试。函数返回的 response 是模型的完整回复文本。其关键参数包括:

参数 含义
inputs 真正发送给模型的输入文本
inputs_show_user 展示给用户的输入,可借此在报告中隐藏啰嗦的真实输入
llm_kwargs 大模型参数(模型名、温度、top_p 等)
chatbot 界面对话窗口句柄,用于数据流可视化
history 对话历史列表
sys_prompt 系统提示词
refresh_interval UI 刷新间隔(默认 0.2,建议低于 1,不可高于 3)
handle_token_exceed 是否自动处理 token 溢出(默认开启,溢出时暴力截断)
retry_times_at_unknown_error 未知错误时的重试次数(默认 2)

注册插件

插件编写完成后,需要在 crazy_functional.pyfunction_plugins 字典中注册才能在界面上使用。以仓库中已注册的插件为例:

function_plugins = {
    # ... 其他插件 ...

    "历史上的今天": {
        "Group": "对话",           # 所属分组,用于插件分类
        "Color": "secondary",      # 按钮颜色:primary/secondary/stop
        "AsButton": False,         # True 显示为按钮,False 放入下拉菜单
        "Info": "查询历史上今天发生的重要事件",  # 插件说明
        "Function": HotReload(历史上的今天),    # 关联函数,HotReload 启用热重载
    },

    # ... 其他插件 ...
}

注册时需要指定的属性含义如下:

  • Group 决定插件在界面上的分类位置。可选值包括"对话"、"编程"、"学术"、"智能体",也可以用 | 分隔同时归属多个分组,如 crazy_functional.py 中"虚空终端"注册的 "Group": "对话|编程|学术|智能体"
  • Color 控制按钮颜色,可选 primary/secondary/stop
  • AsButton 控制插件的显示形式。设为 True 时,插件以按钮形式显示在主界面;设为 False 时,插件出现在下拉菜单中。常用功能建议设为按钮,以便快速访问。
  • Info 是插件说明文本,展示在菜单中。
  • Function 必须用 HotReload() 包装,这样修改插件代码后无需重启程序。

保存文件后,刷新浏览器页面,新插件就会出现在界面上。

类式插件开发

当插件需要用户在执行前配置参数时,类式插件是更好的选择。它允许定义一个二级选项菜单,用户可以在其中输入文本、选择下拉选项等。

类式插件的基类是 crazy_functions/plugin_template/plugin_class_template.py 中的 GptAcademicPluginTemplate,参数描述模型 ArgProperty 也由该模块提供。下面是一个支持自定义天数的"历史上的今天"类式插件:

from crazy_functions.plugin_template.plugin_class_template import GptAcademicPluginTemplate, ArgProperty
from toolbox import update_ui
from crazy_functions.crazy_utils import request_gpt_model_in_new_thread_with_ui_alive
import datetime

class HistoryToday_Wrap(GptAcademicPluginTemplate):
    """
    类式插件必须继承 GptAcademicPluginTemplate
    """

    def __init__(self):
        """
        初始化函数。注意:execute 方法可能在不同线程中运行,
        避免在此存储会被多线程访问的状态。
        """
        pass

    def define_arg_selection_menu(self):
        """
        定义二级选项菜单

        返回一个字典,每个键值对对应一个参数。
        支持的参数类型:
          - type="string": 文本输入框
          - type="dropdown": 下拉选择菜单
        """
        gui_definition = {
            "main_input": ArgProperty(
                title="查询日期",
                description="留空则查询今天,或输入指定日期如 3-15",
                default_value="",
                type="string"
            ).model_dump_json(),

            "event_count": ArgProperty(
                title="事件数量",
                description="选择要列举的历史事件数量",
                options=["3个事件", "5个事件", "10个事件"],
                default_value="3个事件",
                type="dropdown"
            ).model_dump_json(),

            "advanced_arg": ArgProperty(
                title="额外要求",
                description="如有特殊要求可在此输入,如:只列举中国历史事件",
                default_value="",
                type="string"
            ).model_dump_json(),
        }
        return gui_definition

    def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
        """
        执行插件主逻辑

        用户在二级菜单中的选择会通过 plugin_kwargs 字典传入。
        字典的键与 define_arg_selection_menu 中定义的参数名对应。
        """
        # 从 plugin_kwargs 获取用户选择
        main_input = plugin_kwargs.get("main_input", "")
        event_count = plugin_kwargs.get("event_count", "3个事件")
        advanced_arg = plugin_kwargs.get("advanced_arg", "")

        # 解析日期
        if main_input:
            try:
                month, day = map(int, main_input.split("-"))
            except Exception:
                month, day = datetime.date.today().month, datetime.date.today().day
        else:
            month, day = datetime.date.today().month, datetime.date.today().day

        # 解析事件数量
        count = int(event_count.replace("个事件", ""))

        # 构造提问
        query = f"请列举历史上 {month}{day} 日发生的 {count} 个重要事件。"
        if advanced_arg:
            query += f" 额外要求:{advanced_arg}"

        # 清空历史并显示状态
        history = []
        chatbot.append((f"查询 {month}{day}日 的历史事件", "正在查询..."))
        yield from update_ui(chatbot=chatbot, history=history)

        # 调用大模型
        response = yield from request_gpt_model_in_new_thread_with_ui_alive(
            inputs=query,
            inputs_show_user=query,
            llm_kwargs=llm_kwargs,
            chatbot=chatbot,
            history=history,
            sys_prompt="你是一位历史学专家。"
        )

        history.extend([query, response])
        yield from update_ui(chatbot=chatbot, history=history)

类式插件的核心在于 define_arg_selection_menu() 方法。它返回的字典定义了二级菜单的结构,每个参数都由 ArgProperty 对象描述。ArgProperty 是一个 Pydantic 模型,包含五个字段:

字段 含义 约束
title 参数标题 字符串
description 参数说明 字符串
default_value 默认值 字符串
type 控件类型 目前支持 string(文本输入框)与 dropdown(下拉选择)
options 下拉选项列表 仅当 type="dropdown" 时使用

每个 ArgProperty 通过 model_dump_json() 序列化为 JSON 字符串后放入返回字典。从模板类源码看,前端菜单由 get_js_code_for_generating_menu 方法生成:它把 define_arg_selection_menu() 的返回值序列化为 JSON 并做 base64 编码传给前端渲染,同时会执行硬约束校验——参数数量最多 8 个,超出会抛出 ValueError

有两个特殊的参数名需要注意:

  • main_input 会与界面主输入框自动同步,用户在输入框中的内容会预填到这个参数;
  • advanced_arg 会与界面的高级参数输入区自动同步。

除此之外,可以自由定义其他参数名,如示例中的 event_count

另外,execute 方法可能在不同线程中运行(模板类注释明确提醒"不应在插件实例中存储可能被多线程访问的状态"),开发时不要把可变状态放在实例属性上。

注册类式插件

注册类式插件时,需要同时指定 FunctionClass

"历史上的今天(高级版)": {
    "Group": "对话",
    "Color": "stop",
    "AsButton": False,
    "Info": "可自定义日期和事件数量的历史查询插件",
    "Function": HotReload(历史上的今天),  # 兼容虚空终端调用
    "Class": HistoryToday_Wrap,           # 类式插件的类名
},

当插件同时注册了 FunctionClass 时,界面按钮会触发类式插件(显示二级菜单),而虚空终端等自然语言调用场景会使用函数式入口。这一点在 crazy_functional.py 中也有官方注释佐证,例如"Arxiv论文翻译"同时注册了 Function: HotReload(Latex翻译中文并重新编译PDF)(注释说明"当注册 Class 后,Function 旧接口仅会在'虚空终端'中起作用")和 Class: Arxiv_Localize。仓库中 Conversation_To_File_WrapDocument_Conversation_WrapImageGen_WrapNetworkGPT_Wrap 等都是可以参考的类式插件实现。

实用开发技巧

处理文件上传

许多插件需要处理用户上传的文件。用户上传的文件路径会通过 txt 参数传入,可以使用以下模式解析:

import os, glob

@CatchException
def 处理上传文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
    # txt 可能是单个文件路径,也可能是目录路径
    if os.path.isfile(txt):
        file_list = [txt]
    elif os.path.isdir(txt):
        # 获取目录下所有 PDF 文件
        file_list = glob.glob(os.path.join(txt, "*.pdf"))
    else:
        chatbot.append(("错误", "请先上传文件或输入有效路径"))
        yield from update_ui(chatbot=chatbot, history=history)
        return

    for file_path in file_list:
        # 处理每个文件...
        pass

多线程批量处理

当需要处理大量文件或执行耗时操作时,可以使用 crazy_functions/crazy_utils.py 中的多线程请求函数 request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency 提升效率:

from crazy_functions.crazy_utils import request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency

def 批量处理(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
    # 准备多个任务
    inputs_array = ["任务1", "任务2", "任务3"]
    inputs_show_user_array = inputs_array.copy()

    # 并行执行
    results = yield from request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
        inputs_array=inputs_array,
        inputs_show_user_array=inputs_show_user_array,
        llm_kwargs=llm_kwargs,
        chatbot=chatbot,
        history_array=[[] for _ in inputs_array],
        sys_prompt_array=["" for _ in inputs_array],
    )

    # results 是所有任务结果的列表

从源码实现看,该函数以 _array 结尾的参数都是列表,列表长度为子任务数量,执行时会把列表拆解、放到每个子线程中分别执行,并实时在 UI 上反馈远程数据流。它还提供 max_workers 参数控制线程池大小(默认读取配置项 DEFAULT_WORKER_NUM,用于避免高频请求模型导致限流错误)、scroller_max_len 控制数据流滚动显示长度、show_user_at_complete 控制结束时是否把完整输入-输出结果展示在聊天框。如果某个子任务出错,results 中对应项会携带 traceback 报错信息,方便调试和定位问题。

生成下载文件

插件可以生成文件供用户下载。使用 toolbox.py 中的 on_report_generated() 函数将文件注册到下载区:

from toolbox import on_report_generated

def 生成报告(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
    # ... 生成报告内容 ...

    # 保存文件
    report_path = "path/to/report.pdf"
    with open(report_path, "wb") as f:
        f.write(report_content)

    # 注册到下载区
    cookies = user_request.get("cookies", {})
    cookies, report_files, chatbot = on_report_generated(
        cookies=cookies,
        files=[report_path],
        chatbot=chatbot
    )

    yield from update_ui(chatbot=chatbot, history=history)

on_report_generated(cookies, files, chatbot) 接收 cookies 字典、文件路径列表和 chatbot 句柄,将生成的文件登记到会话的下载区并刷新界面,用户即可在界面上下载。

调试与测试

开发过程中,可以使用以下方法进行调试:

查看日志输出:在插件代码中使用 logger 输出调试信息:

from loguru import logger

logger.info(f"处理文件: {file_path}")
logger.warning("参数可能不正确")
logger.error("发生错误")

日志会输出到终端,帮助追踪插件的执行流程。

使用虚空终端测试:虚空终端支持通过自然语言调用插件,是快速测试插件功能的好方法。只需在虚空终端中描述想执行的任务,系统会自动匹配并调用相应插件。这也是为什么类式插件建议同时注册 Function 入口——自然语言调用走的正是函数式入口。

渐进式开发:建议先实现最基本的功能,验证可行后再逐步添加复杂特性。利用热重载特性,可以在不重启程序的情况下快速迭代。

小结

GPT Academic 的插件体系可以归纳为三条主线:

  1. 函数式插件:标准七参数生成器函数 + @CatchException + HotReload 注册,适合无需额外参数的快速功能;
  2. 类式插件:继承 GptAcademicPluginTemplate,通过 define_arg_selection_menu() 声明二级菜单(最多 8 个 ArgProperty 参数,支持 string/dropdown 两类控件,main_inputadvanced_arg 为特殊同步参数),适合需要用户配置参数的复杂交互;
  3. 核心工具链update_ui 负责界面刷新,request_gpt_model_in_new_thread_with_ui_alive 负责单请求流式输出,多线程版函数负责批量并行任务,on_report_generated 负责产出文件下载。

掌握以上内容后,可以进一步阅读 crazy_functions/ 目录下的现有插件源码(如 PDF_Translate_Wrap.pyInternet_GPT_Wrap.pyMermaid_Figure_Gen.py)学习更多实现技巧,也可以探索 自定义按钮 功能创建更轻量的快捷功能,或查阅 主题定制 为插件界面增添个性。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384