You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Feat: Support tool calling in Generate component (#7572) ### What problem does this PR solve? Hello, our use case requires LLM agent to invoke some tools, so I made a simple implementation here. This PR does two things: 1. A simple plugin mechanism based on `pluginlib`: This mechanism lives in the `plugin` directory. It will only load plugins from `plugin/embedded_plugins` for now. A sample plugin `bad_calculator.py` is placed in `plugin/embedded_plugins/llm_tools`, it accepts two numbers `a` and `b`, then give a wrong result `a + b + 100`. In the future, it can load plugins from external location with little code change. Plugins are divided into different types. The only plugin type supported in this PR is `llm_tools`, which must implement the `LLMToolPlugin` class in the `plugin/llm_tool_plugin.py`. More plugin types can be added in the future. 2. A tool selector in the `Generate` component: Added a tool selector to select one or more tools for LLM: ![image](https://github.com/user-attachments/assets/74a21fdf-9333-4175-991b-43df6524c5dc) And with the `bad_calculator` tool, it results this with the `qwen-max` model: ![image](https://github.com/user-attachments/assets/93aff9c4-8550-414a-90a2-1a15a5249d94) ### Type of change - [ ] Bug Fix (non-breaking change which fixes an issue) - [x] New Feature (non-breaking change which adds functionality) - [ ] Documentation Update - [ ] Refactoring - [ ] Performance Improvement - [ ] Other (please describe): Co-authored-by: Yingfeng <yingfeng.zhang@gmail.com>
5 月之前
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # 插件
  2. 这个文件夹包含了RAGFlow的插件机制。
  3. RAGFlow将会从`embedded_plugins`子文件夹中递归加载所有的插件。
  4. ## 支持的插件类型
  5. 目前,唯一支持的插件类型是`llm_tools`。
  6. - `llm_tools`:用于供LLM进行调用的工具。
  7. ## 如何添加一个插件
  8. 添加一个LLM工具插件是很简单的:创建一个插件文件,向其中放一个继承自`LLMToolPlugin`的类,再实现它的`get_metadata`和`invoke`方法即可。
  9. - `get_metadata`方法:这个方法返回一个`LLMToolMetadata`对象,其中包含了对这个工具的描述。
  10. 这些描述信息将被提供给LLM进行调用,和RAGFlow的Web前端用作展示。
  11. - `invoke`方法:这个方法接受LLM生成的参数,并且返回一个`str`对象,其中包含了这个工具的执行结果。
  12. 这个工具的所有执行逻辑都应当放到这个方法里。
  13. 当你启动RAGFlow时,你会在日志中看见你的插件被加载了:
  14. ```
  15. 2025-05-15 19:29:08,959 INFO 34670 Recursively importing plugins from path `/some-path/ragflow/plugin/embedded_plugins`
  16. 2025-05-15 19:29:08,960 INFO 34670 Loaded llm_tools plugin BadCalculatorPlugin version 1.0.0
  17. ```
  18. 也可能会报错,这时就需要根据报错对你的插件进行修复。
  19. ### 示例
  20. 我们将会添加一个会给出错误答案的计算器工具,来演示添加插件的过程。
  21. 首先,在`embedded_plugins/llm_tools`文件夹下创建一个插件文件`bad_calculator.py`。
  22. 接下来,我们创建一个`BadCalculatorPlugin`类,继承基类`LLMToolPlugin`:
  23. ```python
  24. class BadCalculatorPlugin(LLMToolPlugin):
  25. _version_ = "1.0.0"
  26. ```
  27. `_version_`字段是必填的,用于指定这个插件的版本号。
  28. 我们的计算器拥有两个输入字段`a`和`b`,所以我们添加如下的`invoke`方法到`BadCalculatorPlugin`类中:
  29. ```python
  30. def invoke(self, a: int, b: int) -> str:
  31. return str(a + b + 100)
  32. ```
  33. `invoke`方法将会被LLM所调用。这个方法可以有许多参数,但它必须返回一个`str`。
  34. 最后,我们需要添加一个`get_metadata`方法,来告诉LLM怎样使用我们的`bad_calculator`工具:
  35. ```python
  36. @classmethod
  37. def get_metadata(cls) -> LLMToolMetadata:
  38. return {
  39. # 这个工具的名称,会提供给LLM
  40. "name": "bad_calculator",
  41. # 这个工具的展示名称,会提供给RAGFlow的Web前端
  42. "displayName": "$t:bad_calculator.name",
  43. # 这个工具的用法描述,会提供给LLM
  44. "description": "A tool to calculate the sum of two numbers (will give wrong answer)",
  45. # 这个工具的描述,会提供给RAGFlow的Web前端
  46. "displayDescription": "$t:bad_calculator.description",
  47. # 这个工具的参数
  48. "parameters": {
  49. # 第一个参数 - a
  50. "a": {
  51. # 参数类型,选项为:number, string, 或者LLM可以识别的任何类型
  52. "type": "number",
  53. # 这个参数的描述,会提供给LLM
  54. "description": "The first number",
  55. # 这个参数的描述,会提供给RAGFlow的Web前端
  56. "displayDescription": "$t:bad_calculator.params.a",
  57. # 这个参数是否是必填的
  58. "required": True
  59. },
  60. # 第二个参数 - b
  61. "b": {
  62. "type": "number",
  63. "description": "The second number",
  64. "displayDescription": "$t:bad_calculator.params.b",
  65. "required": True
  66. }
  67. }
  68. ```
  69. `get_metadata`方法是一个`classmethod`。它会把这个工具的描述提供给LLM。
  70. 以`display`开头的字段可以使用一种特殊写法`$t:xxx`,这种写法将使用RAGFlow的国际化机制,从`llmTools`这个分类中获取文字。如果你不使用这种写法,那么前端将会显示此处的原始内容。
  71. 现在,我们的工具已经做好了,你可以在`生成回答`组件中选择这个工具来尝试一下。