创建自定义 Python 组件
创建您自己的自定义组件,以向 Langflow 添加您需要的任何功能,从 API 集成到数据处理。
在 Langflow 的基于节点的开发环境中,每个节点都是执行离散功能的“组件”。Langflow 中的自定义组件基于以下内容构建:
使用自定义组件快速入门将示例组件添加到 Langflow,然后使用随后的参考指南进行更高级的组件自定义。
自定义组件快速入门
通过创建 Python 文件,将其保存在正确的文件夹中,包含 __init__.py 文件,并将其加载到 Langflow 中来创建自定义 DataFrameProcessor 组件。
创建 Python 文件
-
为您的组件创建一个 Python 文件,例如
dataframe_processor.py。 -
将您的组件编写为
Component类的对象。创建一个继承自Component的新类并覆盖基类的方法。向后兼容性在 Langflow 1.7 中,
lfx导入路径取代了import from langflow.custom import Component,但原始输入仍然兼容并以相同方式工作。_10from typing import Any, Dict, Optional_10import pandas as pd_10from lfx.custom.custom_component.component import Component_10_10class DataFrameProcessor(Component)_10"""一个使用各种操作处理 pandas DataFrame 的组件。""" -
定义类属性以提供有关您的自定义组件的信息
_13from typing import Any, Dict, Optional_13import pandas as pd_13from lfx.custom.custom_component.component import Component_13_13class DataFrameProcessor(Component)_13"""一个使用各种操作处理 pandas DataFrame 的组件。"""_13_13display_name: str = "DataFrame 处理器"_13description: str = "使用各种操作(如过滤、排序和聚合)处理和转换 pandas DataFrame。"_13documentation: str = "https://docs.langflow.org.cn/components-dataframe-processor"_13icon: str = "DataframeIcon"_13priority: int = 100_13name: str = "dataframe_processor" -
通过指定组件的输入、输出以及处理它们的方法来定义组件的接口。方法名称必须与输出列表中的
method字段匹配,因为这是 Langflow 知道调用哪个方法来生成每个输出的方式。此示例创建了一个最小的自定义组件骨架。
_21from typing import Any, Dict, Optional_21import pandas as pd_21from lfx.custom.custom_component.component import Component_21_21class DataFrameProcessor(Component)_21"""一个使用各种操作处理 pandas DataFrame 的组件。"""_21_21display_name: str = "DataFrame 处理器"_21description: str = "使用各种操作(如过滤、排序和聚合)处理和转换 pandas DataFrame。"_21documentation: str = "https://docs.langflow.org.cn/components-dataframe-processor"_21icon: str = "DataframeIcon"_21priority: int = 100_21name: str = "dataframe_processor"_21_21# 输入和输出列表_21inputs = []_21outputs = []_21_21# 方法_21def some_output_method(self)_21return ...
保存自定义组件
将自定义组件保存在 Langflow 目录中,UI 将在此处发现并加载它。
默认情况下,Langflow 在 src/lfx/src/lfx/components 目录中查找自定义组件。
将组件保存在默认目录中时,组件必须以特定的目录结构组织才能在可视化编辑器中正确加载和显示。
组件必须放在类别文件夹中,而不是直接放在基本目录中。
类别文件夹名称决定了组件在 Langflow 中的显示位置。 核心组件菜单。例如,要将示例 DataFrameProcessor 组件添加到数据类别,请将其放在 data 子文件夹中。
_10src/lfx/src/lfx/components/_10└── data/ # 类别文件夹(决定菜单位置)_10├── __init__.py # 必需 - 使其成为 Python 包_10└── dataframe_processor.py # 您的自定义组件文件
如果您使用 LANGFLOW_COMPONENTS_PATH 环境变量在其他位置创建自定义组件,则组件必须以类似的目录结构组织才能在可视化编辑器中显示。
_10/your/custom/components/path/ # 由 LANGFLOW_COMPONENTS_PATH 设置的基本目录_10└── category_name/_10├── __init__.py_10└── custom_component.py
您可以拥有多个类别文件夹来将组件组织到不同的类别中,每个文件夹中可以有多个组件。
_10/app/custom_components/_10├── data/_10│ ├── __init__.py_10│ ├── custom_component.py_10│ └── dataframe_processor.py_10└── tools/_10├── __init__.py_10└── custom_tool.py
创建 __init__.py 文件
每个类别目录必须包含一个 __init__.py 文件,以便 Langflow 正确识别和加载组件。这是 Python 包的要求,可确保目录被视为模块。
要包含 DataFrameProcessor 组件,请在组件目录中创建一个名为 __init__.py 的文件,其内容如下。
_10from .dataframe_processor import DataFrameProcessor_10_10__all__ = ["DataFrameProcessor"]
延迟加载 DataFrameProcessor 组件
或者,您可以延迟加载组件,这有利于性能,但稍微复杂一些。
_32from __future__ import annotations_32_32from typing import TYPE_CHECKING, Any_32_32from lfx.components._importing import import_mod_32_32if TYPE_CHECKING_32from lfx.components.data.dataframe_processor import DataFrameProcessor_32_32_dynamic_imports = {_32"DataFrameProcessor": "dataframe_processor",_32}_32_32__all__ = [_32"DataFrameProcessor",_32]_32_32def __getattr__(attr_name: str) -> Any_32"""在属性访问时延迟导入数据组件。"""_32if attr_name not in _dynamic_imports_32msg = f"模块 '{__name__}' 没有属性 '{attr_name}'"_32raise AttributeError(msg)_32try_32result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)_32except (ModuleNotFoundError, ImportError, AttributeError) as e_32msg = f"无法从 '{__name__}' 导入 '{attr_name}':{e}"_32raise AttributeError(msg) from e_32globals()[attr_name] = result_32return result_32_32def __dir__() -> list[str]_32return list(__all__)
有关延迟加载的其他示例,请参阅 FAISS 组件。
加载您的组件
确保应用程序构建您的组件。
-
要重建后端和前端,请运行
make install_frontend && make build_frontend && make install_backend && uv run langflow run --port 7860。 -
刷新前端应用程序。您的新
DataFrameProcessor组件在可视化编辑器中数据类别下的 核心组件菜单中可用。
Docker 部署
在 Docker 中运行 Langflow 时,挂载您的自定义组件目录并在 docker run 命令中设置 LANGFLOW_COMPONENTS_PATH 环境变量以指向自定义组件目录。
_10docker run -d \_10--name langflow \_10-p 7860:7860 \_10-v ./custom_components:/app/custom_components \_10-e LANGFLOW_COMPONENTS_PATH=/app/custom_components \_10langflowai/langflow:latest
创建与保存自定义组件示例中相同的自定义组件目录结构。
_10/app/custom_components/ # LANGFLOW_COMPONENTS_PATH_10└── data/_10├── __init__.py_10└── dataframe_processor.py
组件如何执行
Langflow 的引擎管理
- 实例化:创建组件并初始化内部结构。
- 分配输入:将来自可视化编辑器或连接的值分配给组件字段。
- 验证和设置:可选钩子,例如
_pre_run_setup。 - 输出生成:
run()或build_results()触发输出方法。
您可以通过在自定义组件代码中覆盖这些可选钩子来自定义执行。
-
_pre_run_setup()- 在验证和设置期间使用。将此方法添加到您的组件类中,以在执行开始前初始化组件状态。_10class MyComponent(Component)_10# ... 您的输入、输出和其他属性 ..._10_10def _pre_run_setup(self)_10if not hasattr(self, "_initialized")_10self._initialized = True_10self.iteration = 0 -
覆盖
run或_run- 在输出生成期间使用。将此方法添加到您的组件类中以自定义主执行逻辑。_10class MyComponent(Component)_10_10async def_run(self)_10# 自定义执行逻辑在此处_10# 这将代替默认输出方法调用运行_10pass -
将数据存储在
self.ctx中。在您的任何组件方法中使用self.ctx在方法调用之间共享数据。_15class MyComponent(Component)_15_15def _pre_run_setup(self)_15# 在设置中初始化计数器_15self.ctx["processed_items"] = 0_15_15def process_data(self) -> Data_15# 在处理期间增加计数器_15self.ctx["processed_items"] += 1_15return Data(data={"item": f"processed {self.ctx['processed_items']}"})_15_15def get_summary(self) -> Data_15# 在不同方法中访问计数器_15total = self.ctx["processed_items"]_15return Data(data={"summary": f"Processed {total} items total"})
输入和输出
输入和输出是类级配置,它们定义了数据如何流经组件,它如何在可视化编辑器中显示,以及如何验证与其他组件的连接。
输入
输入在类级 inputs 列表中定义。当 Langflow 加载组件时,它使用此列表在可视化编辑器中渲染组件字段和端口。用户或其他组件提供值或连接以填充这些输入。
输入通常是 lfx.io 中某个类的实例(例如 StrInput、DataInput 或 MessageTextInput)。
例如,此组件有三个输入:一个文本字段 (StrInput)、一个布尔开关 (BoolInput) 和一个下拉选择 (DropdownInput)。
_10from lfx.io import StrInput, BoolInput, DropdownInput_10_10inputs = [_10StrInput(name="title", display_name="标题"),_10BoolInput(name="enabled", display_name="已启用", value=True),_10DropdownInput(name="mode", display_name="模式", options=["快速", "安全", "实验性"], value="安全")_10]
StrInput 创建一个用于输入文本的单行文本字段。name="title" 参数表示您可以使用 self.title 在组件方法中访问此值,而 display_name="标题" 在可视化编辑器中显示“标题”作为标签。
BoolInput 创建一个布尔开关,默认情况下使用 value=True 启用。用户可以打开或关闭它,您可以使用 self.enabled 访问当前状态。
DropdownInput 提供一个包含三个预定义选项(“快速”、“安全”和“实验性”)的选择菜单。value="安全" 将“安全”设置为默认选择,您可以使用 self.mode 访问用户的选择。
有关所有可用参数的列表,请参阅 Langflow 代码库中的 BaseInputMixin 定义。
有关所有可用输入类型的列表,请参阅 Langflow 代码库中的输入类型定义。
_10from lfx.io import StrInput, DataInput, MultilineInput, IntInput, BoolInput, DropdownInput, FileInput, CodeInput, ModelInput, HandleInput, Output
输出
输出在类级 outputs 列表中定义。当 Langflow 渲染组件时,每个输出都成为可视化编辑器中的连接点。当您将某些内容连接到输出时,Langflow 会自动调用相应的方法并将返回的对象传递给下一个组件。
输出通常是 lfx.io 中 Output 的实例。
例如,此组件有一个返回 DataFrame 的 output。
_16from lfx.io import Output_16from lfx.schema import DataFrame_16_16outputs = [_16Output(_16name="df_out",_16display_name="DataFrame 输出",_16method="build_df"_16 )_16]_16_16def build_df(self) -> DataFrame_16# 处理数据并返回 DataFrame_16df = DataFrame({"col1": [1, 2], "col2": [3, 4]})_16self.status = f"已使用 {len(df)} 行构建 DataFrame。"_16return df
Output 在可视化编辑器中创建了一个名为DataFrame 输出的连接点。name="df_out" 参数标识此输出,而 display_name="DataFrame 输出" 在 UI 中显示标签。method="build_df" 参数告诉 Langflow 当此输出连接到另一个组件时调用 build_df 方法。
build_df 方法处理数据并返回一个 DataFrame。-> DataFrame 类型注解有助于 Langflow 验证连接并在可视化编辑器中提供颜色编码。您还可以设置 self.status 以在 UI 中显示进度消息。
有关所有可用参数的完整列表,请参阅 Langflow 代码库中的 Output 类定义。常见参数包括
附加返回类型
Message:结构化聊天消息Data:具有.data和可选.text的灵活对象DataFrame:表格数据 (pandas DataFrame 子类)- 基本类型:
str、int、bool,不建议用于类型一致性
关联方法
每个输出都链接到一个方法,其中输出方法名称必须与方法名称匹配。该方法通常返回 Message、Data 或 DataFrame 等对象,并且可以使用 self. 访问输入。
例如,Output 定义了一个名为 file_contents 的连接点,当连接时将调用 read_file 方法。read_file 方法使用 self.filename 访问文件名输入,读取文件内容,设置状态消息,并将内容包装在 Data 对象中返回。
_12Output(_12name="file_contents",_12display_name="文件内容",_12method="read_file"_12)_12_12def read_file(self) -> Data_12path = self.filename_12with open(path, "r") as f_12content = f.read()_12self.status = f"已从 {path} 读取 {len(content)} 个字符"_12return Data(data={"content": content})
具有多个输出的组件
一个组件可以定义多个输出。每个输出可以有不同的对应方法。
例如:
_10outputs = [_10Output(display_name="已处理数据", name="processed_data", method="process_data"),_10Output(display_name="调试信息", name="debug_info", method="provide_debug_info"),_10]
默认情况下,Langflow 中生成多个输出的组件在可视化编辑器中只允许选择一个输出。组件将只有一个输出端口,用户可以在其中选择首选的输出类型。
此行为由 group_outputs 参数控制
-
group_outputs=False(默认):当组件有多个输出且group_outputs为false或未设置时,输出在可视化编辑器中分组,用户必须选择一个。当组件在流程中使用时只期望返回一种输出类型时,使用此选项。
-
group_outputs=True:所有输出在可视化编辑器中同时可用。组件为每个输出提供一个输出端口,用户可以将零个或多个输出连接到其他组件。当组件期望返回多个值并由下游组件或进程并行使用时,使用此选项。
- False 或未设置
- True (真)
在此示例中,可视化编辑器提供了一个输出端口,用户可以从中选择一个输出。由于 group_outputs=False 是默认行为,因此无需在组件中显式设置,如本例所示。
_12outputs = [_12Output(_12name="structured_output",_12display_name="结构化输出",_12method="build_structured_output",_12 ),_12Output(_12name="dataframe_output",_12display_name="DataFrame 输出",_12method="build_structured_dataframe",_12 ),_12]
在此示例中,所有输出在可视化编辑器中同时可用。
_14outputs = [_14Output(_14name="true_result",_14display_name="True",_14method="true_response",_14group_outputs=True,_14 ),_14Output(_14name="false_result",_14display_name="False",_14method="false_response",_14group_outputs=True,_14 ),_14]
工具模式
支持工具模式的组件可以作为独立组件使用(当不处于工具模式时)或作为具有工具输入的其他组件(如代理组件)的工具。
您可以通过设置 tool_mode=True 来允许自定义组件支持工具模式。
_10inputs = [_10MessageTextInput(_10name="message",_10display_name="消息",_10info="输入将由工具直接处理的消息",_10tool_mode=True,_10 ),_10]
类型化注解
在 Langflow 中,类型化注解允许 Langflow 在视觉上引导用户并保持流程一致性。始终使用 -> Data、-> Message 或 -> DataFrame 等返回类型注解您的输出方法,以启用正确的视觉编辑器颜色编码和验证。使用 Data、Message 或 DataFrame 包装器而不是返回普通结构,以获得更好的一致性。保持组件中的类型一致,以使流程可预测且更易于构建。
类型化注解提供颜色编码,其中 -> Data 或 -> Message 等输出获得不同的颜色,自动验证会阻止不兼容的连接,并提高了用户快速理解组件之间数据流的可读性。
常见返回类型
- 消息 (Message)
- 数据 (Data)
- 数据帧 (DataFrame)
- 基本类型
用于聊天式输出。连接到多个兼容 Message 的输入之一。
_10def produce_message(self) -> Message_10return Message(text="你好!来自类型化方法!", sender="系统")
用于结构化数据,如字典或部分文本。仅连接到 DataInput(接受 Data 的端口)。
_10def get_processed_data(self) -> Data_10processed = {"key1": "value1", "key2": 123}_10return Data(data=processed)
用于表格数据。仅连接到 DataFrameInput(接受 DataFrame 的端口)。
_10def build_df(self) -> DataFrame_10pdf = pd.DataFrame({"A": [1, 2], "B": [3, 4]})_10return DataFrame(pdf)
允许返回基本类型,但建议包装在 Data 或 Message 中,以在可视化编辑器中获得更好的一致性。
_10def compute_sum(self) -> int_10return sum(self.numbers)
启用动态字段
在 Langflow 中,动态字段允许输入根据用户交互而改变或出现。您可以通过设置 dynamic=True 使输入动态化。可选地,设置 real_time_refresh=True 会触发 update_build_config 方法,以实时调整输入的可见性或属性,从而创建一种上下文相关的可视化编辑器体验,仅根据用户的选择显示相关字段。
在此示例中,运算符字段使用 real_time_refresh=True 触发更新。regex_pattern 字段最初是隐藏的,并由 dynamic=True 控制。
_23from lfx.custom import Component_23from lfx.io import DropdownInput, StrInput_23_23class RegexRouter(Component)_23display_name = "正则表达式路由器"_23description = "演示正则表达式输入的动态字段。"_23_23inputs = [_23DropdownInput(_23name="operator",_23display_name="运算符",_23options=["等于", "包含", "正则表达式"],_23value="等于",_23real_time_refresh=True,_23 ),_23StrInput(_23name="regex_pattern",_23display_name="正则表达式模式",_23info="如果 operator='regex',则使用",_23dynamic=True,_23show=False,_23 ),_23 ]
根据用户选择显示或隐藏字段
当用户更改带有 real_time_refresh=True 的字段时,Langflow 会调用您的 update_build_config 方法。
此方法允许您根据用户选择的内容显示、隐藏或修改其他字段。
此示例仅当用户从运算符下拉列表中选择“正则表达式”时才显示 regex_pattern 字段。
_10def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict_10if field_name == "operator"_10if field_value == "regex"_10build_config["regex_pattern"]["show"] = True_10else_10build_config["regex_pattern"]["show"] = False_10return build_config
您可以在 update_build_config 中修改其他字段属性,而不仅仅是 show 和 hide。
-
required:动态使字段必填或可选_10if field_value == "regex"_10build_config["regex_pattern"]["required"] = True_10else_10build_config["regex_pattern"]["required"] = False -
advanced:将字段移动到“高级”部分_10if field_value == "实验性"_10build_config["regex_pattern"]["advanced"] = False # 在主部分显示_10else_10build_config["regex_pattern"]["advanced"] = True # 在高级部分隐藏 -
options:根据其他选择更改下拉选项_10if field_value == "regex"_10build_config["operator"]["options"] = ["正则表达式", "包含", "以...开头"]_10else_10build_config["operator"]["options"] = ["等于", "包含", "不等于"]
错误处理和日志记录
当验证失败时,您可以引发标准 Python 异常(例如 ValueError)或专门的异常(例如 ToolException)。Langflow 会自动捕获这些异常并在可视化编辑器中显示适当的错误消息,帮助用户快速识别出错的原因。
_10def compute_result(self) -> str_10if not self.user_input_10raise ValueError("未提供输入。")_10 # ...
或者,您可以返回包含 "error" 字段的 Data 对象,而不是突然停止流程。这种方法允许流程继续运行,并使下游组件能够优雅地检测和处理错误。
_10def run_model(self) -> Data_10try_10 # ..._10except Exception as e_10return Data(data={"error": str(e)})
Langflow 提供了几种工具来帮助您调试和管理组件执行。您可以使用 self.status 在可视化编辑器中直接显示有关执行结果的简短消息,从而使用户更容易进行故障排除。
_10def parse_data(self) -> Data_10# ..._10self.status = f"成功解析了 {len(rows)} 行。"_10return Data(data={"rows": rows})
当某些条件失败时,您可以使用 self.stop() 停止单个输出路径,而无需停止同一组件的其他输出。
如果用户输入为空,此示例将停止输出,从而防止组件处理无效数据。
_10def some_output(self) -> Data_10if not self.user_input or len(self.user_input.strip()) == 0_10self.stop("some_output")_10return Data(data={"error": "提供了空输入"})
您可以使用 self.log() 记录组件内部的关键执行详细信息。这些日志以结构化数据存储并显示在组件详细信息视图的“日志”或“事件”部分中,以后可以通过可视化编辑器中的日志按钮或导出的文件访问。
组件日志与 Langflow 的主应用程序日志系统不同。self.log() 创建组件特定的日志,这些日志显示在 UI 中,而 Langflow 的主日志系统使用 structlog 进行应用程序级日志记录,该日志记录输出到 langflow.log 文件。有关更多信息,请参阅日志。
当组件开始处理文件时,此示例会记录一条消息。
_10def process_file(self, file_path: str)_10self.log(f"正在处理文件 {file_path}")
向 Langflow 贡献自定义组件
要将您的自定义组件贡献给 Langflow 项目,请参阅贡献组件。