# How the GPT Academic Plugin System Works and How to Add Custom Plugins

> Explore the GPT Academic plugin system. Learn how it centralizes UI elements and Python functions via ArgsGeneralWrapper and discover how to add your own custom tools by creating modules.

- Repository: [binary-husky/gpt_academic](https://github.com/binary-husky/gpt_academic)
- Tags: how-to-guide
- Published: 2026-03-02

---

**The GPT Academic plugin system uses a centralized registry in [`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py) to map UI elements to Python functions, which are executed through a standardized wrapper `ArgsGeneralWrapper` that normalizes arguments, handles cookies, and manages UI updates, allowing developers to add custom tools by creating modules in `crazy_functions/` and registering them with metadata.**

The GPT Academic project (binary-husky/gpt_academic) provides a flexible plugin architecture that enables users to extend its core functionality without modifying the main application code. Understanding how the GPT Academic plugin system handles registration, loading, and execution allows developers to integrate custom tools seamlessly into the Gradio-based interface.

## Architecture of the GPT Academic Plugin System

The plugin system consists of four coordinated components that handle discovery, loading, execution, and UI rendering.

### Plugin Registry: [`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py)

At the heart of the system lies the `function_plugins` dictionary, built by `crazy_functional.get_crazy_functions()`. This registry describes every function-plugin with metadata including group categorization, UI button configuration, color schemes, and entry points. When the application starts, this dictionary is returned to the UI layer in [`main.py`](https://github.com/binary-husky/gpt_academic/blob/main/main.py), which generates buttons and dropdowns based on the registry contents.

### Plugin Loader: [`connect_void_terminal.py`](https://github.com/binary-husky/gpt_academic/blob/main/connect_void_terminal.py)

The `shared_utils.connect_void_terminal.get_plugin_handle()` function transforms string identifiers like `"crazy_functions.Markdown_Translate->Markdown英译中"` into callable objects. It uses `importlib.import_module` combined with `getattr` to dynamically load the specified function or class from the `crazy_functions/` directory, enabling late-binding of plugin code.

### Execution Wrapper: `ArgsGeneralWrapper` in [`toolbox.py`](https://github.com/binary-husky/gpt_academic/blob/main/toolbox.py)

All plugins are executed through `toolbox.ArgsGeneralWrapper`, defined around lines 99-115 in [`toolbox.py`](https://github.com/binary-husky/gpt_academic/blob/main/toolbox.py). This decorator normalizes the call signature across all plugins, accepting parameters including `txt`, `llm_kwargs`, `plugin_kwargs`, `chatbot`, `history`, `system_prompt`, and `user_request`. The wrapper constructs a `ChatBotWithCookies` instance, injects cookies for session management, extracts advanced arguments from `plugin_advanced_arg`, handles error catching, and yields control to the actual plugin function.

### Front-End UI Integration

Two UI paths exist for plugin invocation. The legacy UI in [`main.py`](https://github.com/binary-husky/gpt_academic/blob/main/main.py) builds buttons that call plugins directly through `ArgsGeneralWrapper`. The advanced UI, defined in [`themes/gui_advanced_plugin_class.py`](https://github.com/binary-husky/gpt_academic/blob/main/themes/gui_advanced_plugin_class.py), presents a floating argument panel when `AdvancedArgs` is enabled. The `define_gui_advanced_plugin_class` function builds up to 8 textboxes and dropdowns, parses the JSON payload (see lines 38-42), and routes through `route_switchy_bt_with_arg` before hitting the same execution wrapper.

## How to Add a Custom Plugin to GPT Academic

Creating a new plugin requires implementing a standardized interface and registering it in the central dictionary.

### Step 1: Create a Plugin Module in `crazy_functions/`

Place a new Python file in the `crazy_functions/` directory, for example [`crazy_functions/my_plugin.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functions/my_plugin.py). The file must define a function or class that follows the execution wrapper's expected signature.

### Step 2: Implement the Required Function Signature

Your plugin must accept the exact arguments that `ArgsGeneralWrapper` passes. The standard signature is:

```python
def my_plugin(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
    # Implementation logic here

    yield from update_ui(chatbot, history)

```

The `txt` parameter contains the main input text, `llm_kwargs` holds model configuration, `plugin_kwargs` receives advanced arguments, and `chatbot` is the conversation state list. Always yield from `update_ui` to refresh the interface.

### Step 3: Register the Plugin in [`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py)

Import your function and add an entry to the `function_plugins` dictionary inside `get_crazy_functions()`:

```python
from crazy_functions.my_plugin import my_plugin
from toolbox import HotReload

function_plugins["我的演示插件"] = {
    "Group": "演示|实验",
    "Color": "primary",
    "AsButton": True,
    "Info": "演示如何快速集成自定义插件",
    "Function": HotReload(my_plugin),
}

```

The `HotReload` wrapper enables live editing by calling `importlib.reload` on each request, allowing you to modify code without restarting the Gradio server.

### Step 4: Configure Advanced Arguments (Optional)

For plugins requiring additional UI inputs, create a class with a static `execute` method and optional `get_arg_schema()`:

```python
class MyPluginWrap:
    @staticmethod
    def get_arg_schema():
        return {
            "main_input": {"type": "text", "label": "文件路径", "default": "./"},
            "temperature": {"type": "float", "label": "采样温度", "default": 0.7}
        }

    @staticmethod
    def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
        # Access arguments via plugin_kwargs.get("main_input")

        yield from update_ui(chatbot, history)

```

Register using `"Class": MyPluginWrap`, `"AdvancedArgs": True`, and optionally `"ArgsReminder": "提示信息"` to trigger the floating panel UI.

## Practical Code Examples

### Example 1: Simple Function Plugin

Create [`crazy_functions/hello_world.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functions/hello_world.py):

```python
def hello_world(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
    """Echo the input string with a friendly prefix."""
    reply = f"👋 你好！你刚才说的是：{txt}"
    chatbot.append([txt, reply])
    yield from update_ui(chatbot, history)

```

Register in [`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py):

```python
from crazy_functions.hello_world import hello_world
from toolbox import HotReload

function_plugins["问候插件"] = {
    "Group": "实验",
    "Color": "primary",
    "AsButton": True,
    "Info": "返回问候语并回显输入",
    "Function": HotReload(hello_world),
}

```

### Example 2: Advanced-Args Class Plugin

Create [`crazy_functions/word_counter.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functions/word_counter.py):

```python
class WordCounter:
    @staticmethod
    def get_arg_schema():
        return {
            "main_input": {"type": "text", "label": "要统计的文字", "default": ""},
            "ignore_case": {"type": "bool", "label": "忽略大小写", "default": True},
        }

    @staticmethod
    def execute(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request):
        text = plugin_kwargs.get("main_input", "")
        ignore = plugin_kwargs.get("ignore_case", True)
        words = text.lower().split() if ignore else text.split()
        count = len(words)
        reply = f"📝 共有 {count} 个词（{'忽略' if ignore else '区分'}大小写）。"
        chatbot.append([txt, reply])
        yield from update_ui(chatbot, history)

```

Register with advanced UI support:

```python
from crazy_functions.word_counter import WordCounter

function_plugins["词数统计"] = {
    "Group": "工具",
    "Color": "secondary",
    "AsButton": False,
    "Info": "统计文本中的词数，可选忽略大小写",
    "Class": WordCounter,
    "AdvancedArgs": True,
    "ArgsReminder": "请在右侧填写要统计的文本和是否忽略大小写",
}

```

### Example 3: Programmatic Plugin Testing

Test plugins outside the UI using the low-level loader:

```python
from toolbox import get_plugin_handle, get_plugin_default_kwargs

# Load the plugin by its canonical string

plugin = get_plugin_handle("crazy_functions.word_counter->execute")
default = get_plugin_default_kwargs()
default["plugin_kwargs"] = {"main_input": "Hello world!", "ignore_case": True}

# Run the generator

for cookies, chat, hist, msg in plugin(**default):
    print(msg)   # -> 📝 共有 2 个词（忽略大小写）。

```

## Key Files in the Plugin System

- **[`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py)**: Central registry that returns the `function_plugins` dict. Adding entries here makes the UI aware of the plugin.
- **[`toolbox.py`](https://github.com/binary-husky/gpt_academic/blob/main/toolbox.py)**: Provides `ArgsGeneralWrapper` (the execution wrapper), `HotReload` (live-code reload), and UI helpers like `update_ui`.
- **[`shared_utils/connect_void_terminal.py`](https://github.com/binary-husky/gpt_academic/blob/main/shared_utils/connect_void_terminal.py)**: Implements `get_plugin_handle` that turns `"module->function"` strings into callables using `importlib`.
- **[`main.py`](https://github.com/binary-husky/gpt_academic/blob/main/main.py)**: Builds the Gradio UI, registers button callbacks, and wires the plugin dictionary into the front-end.
- **[`themes/gui_advanced_plugin_class.py`](https://github.com/binary-husky/gpt_academic/blob/main/themes/gui_advanced_plugin_class.py)**: Implements the floating panel for plugins declaring `AdvancedArgs = True`, handling JSON-to-dict conversion.

## Summary

- The GPT Academic plugin system centers on a declarative registry (`function_plugins`) in [`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py) that describes available tools.
- `ArgsGeneralWrapper` in [`toolbox.py`](https://github.com/binary-husky/gpt_academic/blob/main/toolbox.py) provides a unified execution environment handling cookies, error management, and UI refresh cycles.
- Plugins must implement a standard seven-parameter signature: `(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request)`.
- The `HotReload` wrapper enables live development by reloading modules on each invocation without server restarts.
- Advanced plugins use a class-based approach with `get_arg_schema()` to generate dynamic UI panels for parameter input.

## Frequently Asked Questions

### What is the exact function signature required for GPT Academic plugins?

Plugins must accept seven positional arguments: `txt` (the input text), `llm_kwargs` (model configuration dictionary), `plugin_kwargs` (advanced arguments dictionary), `chatbot` (the conversation history list), `history` (raw history), `system_prompt` (system instructions), and `user_request` (the original request object). The function must yield control back to the UI using `yield from update_ui(chatbot, history)`.

### How does the `HotReload` wrapper enable live plugin development?

`HotReload`, defined in [`toolbox.py`](https://github.com/binary-husky/gpt_academic/blob/main/toolbox.py), wraps the plugin function and calls `importlib.reload` on the module before each execution. This reloads the source code from disk, allowing developers to modify plugin logic in `crazy_functions/` and see changes immediately in the Gradio interface without restarting the Python process.

### Can I add plugins without restarting the server?

Yes. Because the plugin registry uses `HotReload` wrappers and the UI dynamically loads plugins through `get_plugin_handle`, you can add new plugin files to `crazy_functions/`, register them in [`crazy_functional.py`](https://github.com/binary-husky/gpt_academic/blob/main/crazy_functional.py), and modify existing code while the server is running. The changes take effect on the next button click or dropdown selection.

### How are advanced arguments passed to plugins?

When a plugin declares `"AdvancedArgs": True`, the UI renders a floating panel defined in [`gui_advanced_plugin_class.py`](https://github.com/binary-husky/gpt_academic/blob/main/gui_advanced_plugin_class.py). User inputs are serialized to a JSON string, parsed into a dictionary (lines 38-42), and injected into the `plugin_kwargs` parameter of the plugin function. You can pre-define the schema using a static `get_arg_schema()` method in your plugin class to control label names, types, and defaults.