How can I append an object from an external blender file using a relative path with Python?
There is a pretty nice example using BlendDataLibraries and a relative path in the API: https://docs.blender.org/api/current/bpy.types.BlendDataLibraries.html

Example script to append all objects named Cube... from a blend file called link_library.blend in the same folder as the script:

import bpy
import os

# "//" prefix is a Blender specific identifier for the current blend file
#filepath = "//link_library.blend"
#abs_filepath = bpy.path.abspath(filepath) # returns the absolute path

# os.path.abspath(__file__) returns path to the script
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "link_library.blend")

# link all objects starting with 'Cube'
with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
    data_to.objects = [name for name in data_from.objects if name.startswith("Cube")]

# link object to scene collection
for obj in data_to.objects:
    if obj is not None:
       bpy.context.collection.objects.link(obj)


Assuming the folder structure is like:

my_folder/
├── my_script.py
├── link_library.blend/
    ├── Objects
        ├── Cube


Further reading:


How do I get the full path of the current file's directory?
How to Link/Append a data-block using the Python API?
How to get the directory of open blend file? (from Python)




Can be wrapped into an operator easily. I suggest declare at least two StringProperties, one to hold the name of the blend and another one for the actual object name, which basically allows to pass arguments when calling the operator or when adding the operator to any layout:

class MY_OT_custom_append(bpy.types.Operator):
    ...
    blend = StringProperty(name="Library Blend File")
    object_name = StringProperty(name="Object Name")
    ...

 # On a panel
 class MY_PT_custom_panel(Panel):
    ...
    row = layout.row()
    props = row.operator(MY_OT_custom_append.bl_idname)
    props.blend = "link_library.blend"
    props.object_name = "Cube"
    ...

...
# Test call
bpy.ops.scene.custom_append(blend="link_library.blend", object_name="Cube")


Read: How to pass multiple operator properties via UI layout?



custom_append.py

Panel and operator example to append given/known objects from another blend file next to the Add-on (see the folder structure above): 



bl_info = {
    "name": "Custom Append Add-on",
    "description": "",
    "author": "",
    "version": (0, 1),
    "blender": (2, 80, 0),
    "location": "3D View &gt; Tools",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "",
    "tracker_url": "",
    "category": "Development"
}


import bpy
import os

from bpy.props import StringProperty
from bpy.types import Panel, Operator

# ------------------------------------------------------------------------
#    Append Operator
# ------------------------------------------------------------------------

class MY_OT_custom_append(bpy.types.Operator):
    bl_idname = "scene.custom_append"
    bl_label = "Custom Append Operator"
    bl_options = {'REGISTER'}

    blend = StringProperty(name="Library Blend File")
    object_name = StringProperty(name="Object Name")

    def execute(self, context):   

        # os.path.abspath(__file__) returns path to the addon
        filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), self.blend)

        # -&gt; Test whether the file exist
        if not os.path.isfile(filepath):
            self.report({'WARNING'},"{} does not exist".format(self.blend))
            return {'CANCELLED'}

        # link all objects starting with 'Cube'
        with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
            data_to.objects = [name for name in data_from.objects if name == self.object_name]

        # -&gt; Test whether the obejct exist
        if not data_to.objects:
            self.report({'WARNING'},"{} not found in {}".format(self.object_name, self.blend))
            return {'CANCELLED'}

        # link object to scene collection
        for obj in data_to.objects:
            if obj is not None:
                # Append to active collection
                active_coll = context.view_layer.active_layer_collection
                active_coll.collection.objects.link(obj)
                # Append to main collection
                # context.collection.objects.link(obj)

        return {'FINISHED'}


# ------------------------------------------------------------------------
#    Panel in Object Mode
# ------------------------------------------------------------------------

class MY_PT_custom_panel(Panel):
    bl_idname = "OBJECT_PT_my_panel"
    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"

    def draw(self, context):
        layout = self.layout

        file_name = "link_library.blend"
        object_name_01 = "Cube"
        object_name_02 = "Sphere"

        row = layout.row()
        props = row.operator(MY_OT_custom_append.bl_idname, text="Append {}".format(object_name_01))
        props.blend = file_name
        props.object_name = object_name_01

        row = layout.row()
        props = row.operator(MY_OT_custom_append.bl_idname, text="Append {}".format(object_name_02))
        props.blend = file_name
        props.object_name = object_name_02

        layout.separator()

# ------------------------------------------------------------------------
#    Registration
# ------------------------------------------------------------------------

classes = (
    MY_OT_custom_append,
    MY_PT_custom_panel
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)

if __name__ == "__main__":
    register()


Further reading: How to create a custom UI?