### What problem does this PR solve? ### Type of change - [x] Documentation Updatetags/v0.8.0
| English | [简体中文](./README_zh.md) | |||||
| # *Graph* | |||||
| ## Introduction | |||||
| *Graph* is a mathematical concept which is composed of nodes and edges. | |||||
| It is used to compose a complex work flow or agent. | |||||
| And this graph is beyond the DAG that we can use circles to describe our agent or work flow. | |||||
| Under this folder, we propose a test tool ./test/client.py which can test the DSLs such as json files in folder ./test/dsl_examples. | |||||
| Please use this client at the same folder you start RAGFlow. If it's ran by docker, please go into the container before running the client. | |||||
| Otherwise, correct configurations in conf/service_conf.yaml is essential. | |||||
| ```bash | |||||
| PYTHONPATH=path/to/ragflow python graph/test/client.py -h | |||||
| usage: client.py [-h] -s DSL -t TENANT_ID -m | |||||
| options: | |||||
| -h, --help show this help message and exit | |||||
| -s DSL, --dsl DSL input dsl | |||||
| -t TENANT_ID, --tenant_id TENANT_ID | |||||
| Tenant ID | |||||
| -m, --stream Stream output | |||||
| ``` | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/79179c5e-d4d6-464a-b6c4-5721cb329899" width="1000"/> | |||||
| </div> | |||||
| ## How to gain a TENANT_ID in command line? | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/419d8588-87b1-4ab8-ac49-2d1f047a4b97" width="600"/> | |||||
| </div> | |||||
| 💡 We plant to display it here in the near future. | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/c97915de-0091-46a5-afd9-e278946e5fe3" width="600"/> | |||||
| </div> | |||||
| ## How to set 'kb_ids' for component 'Retrieval' in DSL? | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/0a731534-cac8-49fd-8a92-ca247eeef66d" width="600"/> | |||||
| </div> | |||||
| [English](./README.md) | 简体中文 | |||||
| # *Graph* | |||||
| ## 简介 | |||||
| "Graph"是一个由节点和边组成的数学概念。 | |||||
| 它被用来构建复杂的工作流或代理。 | |||||
| 这个图超越了有向无环图(DAG),我们可以使用循环来描述我们的代理或工作流。 | |||||
| 在这个文件夹下,我们提出了一个测试工具 ./test/client.py, | |||||
| 它可以测试像文件夹./test/dsl_examples下一样的DSL文件。 | |||||
| 请在启动 RAGFlow 的同一文件夹中使用此客户端。如果它是通过 Docker 运行的,请在运行客户端之前进入容器。 | |||||
| 否则,正确配置 conf/service_conf.yaml 文件是必不可少的。 | |||||
| ```bash | |||||
| PYTHONPATH=path/to/ragflow python graph/test/client.py -h | |||||
| usage: client.py [-h] -s DSL -t TENANT_ID -m | |||||
| options: | |||||
| -h, --help show this help message and exit | |||||
| -s DSL, --dsl DSL input dsl | |||||
| -t TENANT_ID, --tenant_id TENANT_ID | |||||
| Tenant ID | |||||
| -m, --stream Stream output | |||||
| ``` | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/05924730-c427-495b-8ee4-90b8b2250681" width="1000"/> | |||||
| </div> | |||||
| ## 命令行中的TENANT_ID如何获得? | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/419d8588-87b1-4ab8-ac49-2d1f047a4b97" width="600"/> | |||||
| </div> | |||||
| 💡 后面会展示在这里: | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/c97915de-0091-46a5-afd9-e278946e5fe3" width="600"/> | |||||
| </div> | |||||
| ## DSL里面的Retrieval组件的kb_ids怎么填? | |||||
| <div align="center" style="margin-top:20px;margin-bottom:20px;"> | |||||
| <img src="https://github.com/infiniflow/ragflow/assets/12318111/0a731534-cac8-49fd-8a92-ca247eeef66d" width="600"/> | |||||
| </div> | |||||
| from graph.component import component_class | from graph.component import component_class | ||||
| from graph.component.base import ComponentBase | from graph.component.base import ComponentBase | ||||
| from graph.settings import flow_logger | |||||
| from graph.settings import flow_logger, DEBUG | |||||
| class Canvas(ABC): | class Canvas(ABC): | ||||
| if cpn.component_name == "Answer": | if cpn.component_name == "Answer": | ||||
| self.answer.append(c) | self.answer.append(c) | ||||
| else: | else: | ||||
| print("RUN: ", c) | |||||
| if DEBUG: print("RUN: ", c) | |||||
| ans = cpn.run(self.history, **kwargs) | ans = cpn.run(self.history, **kwargs) | ||||
| self.path[-1].append(c) | self.path[-1].append(c) | ||||
| ran += 1 | ran += 1 | ||||
| prepare2run(self.components[self.path[-2][-1]]["downstream"]) | prepare2run(self.components[self.path[-2][-1]]["downstream"]) | ||||
| while ran < len(self.path[-1]): | while ran < len(self.path[-1]): | ||||
| print(ran, self.path) | |||||
| if DEBUG: print(ran, self.path) | |||||
| cpn_id = self.path[-1][ran] | cpn_id = self.path[-1][ran] | ||||
| cpn = self.get_component(cpn_id) | cpn = self.get_component(cpn_id) | ||||
| if not cpn["downstream"]: break | if not cpn["downstream"]: break |
| import pandas as pd | import pandas as pd | ||||
| from graph import settings | from graph import settings | ||||
| from graph.settings import flow_logger | |||||
| from graph.settings import flow_logger, DEBUG | |||||
| _FEEDED_DEPRECATED_PARAMS = "_feeded_deprecated_params" | _FEEDED_DEPRECATED_PARAMS = "_feeded_deprecated_params" | ||||
| _DEPRECATED_PARAMS = "_deprecated_params" | _DEPRECATED_PARAMS = "_deprecated_params" | ||||
| reversed_cpnts.extend(self._canvas.path[-2]) | reversed_cpnts.extend(self._canvas.path[-2]) | ||||
| reversed_cpnts.extend(self._canvas.path[-1]) | reversed_cpnts.extend(self._canvas.path[-1]) | ||||
| print(self.component_name, reversed_cpnts[::-1]) | |||||
| if DEBUG: print(self.component_name, reversed_cpnts[::-1]) | |||||
| for u in reversed_cpnts[::-1]: | for u in reversed_cpnts[::-1]: | ||||
| if self.get_component_name(u) in ["switch"]: continue | if self.get_component_name(u) in ["switch"]: continue | ||||
| if self.component_name.lower().find("switch") < 0 \ | if self.component_name.lower().find("switch") < 0 \ |
| from api.db import LLMType | from api.db import LLMType | ||||
| from api.db.services.llm_service import LLMBundle | from api.db.services.llm_service import LLMBundle | ||||
| from graph.component import GenerateParam, Generate | from graph.component import GenerateParam, Generate | ||||
| from graph.settings import DEBUG | |||||
| class CategorizeParam(GenerateParam): | class CategorizeParam(GenerateParam): | ||||
| def _run(self, history, **kwargs): | def _run(self, history, **kwargs): | ||||
| input = self.get_input() | input = self.get_input() | ||||
| print(input, "DDDDDDDDDDDDDDDDDDDDDDDDDDDDD") | |||||
| input = "Question: " + ("; ".join(input["content"]) if "content" in input else "") + "Category: " | input = "Question: " + ("; ".join(input["content"]) if "content" in input else "") + "Category: " | ||||
| chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.CHAT, self._param.llm_id) | chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.CHAT, self._param.llm_id) | ||||
| ans = chat_mdl.chat(self._param.get_prompt(), [{"role": "user", "content": input}], | ans = chat_mdl.chat(self._param.get_prompt(), [{"role": "user", "content": input}], | ||||
| self._param.gen_conf()) | self._param.gen_conf()) | ||||
| print(ans, ":::::::::::::::::::::::::::::::::") | |||||
| if DEBUG: print(ans, ":::::::::::::::::::::::::::::::::", input) | |||||
| for c in self._param.category_description.keys(): | for c in self._param.category_description.keys(): | ||||
| if ans.lower().find(c.lower()) >= 0: | if ans.lower().find(c.lower()) >= 0: | ||||
| return Categorize.be_output(self._param.category_description[c]["to"]) | return Categorize.be_output(self._param.category_description[c]["to"]) |
| from api.utils.file_utils import get_project_base_directory | from api.utils.file_utils import get_project_base_directory | ||||
| from api.utils.log_utils import LoggerFactory, getLogger | from api.utils.log_utils import LoggerFactory, getLogger | ||||
| DEBUG = 0 | |||||
| LoggerFactory.set_directory( | LoggerFactory.set_directory( | ||||
| os.path.join( | os.path.join( | ||||
| get_project_base_directory(), | get_project_base_directory(), | ||||
| flow_logger = getLogger("flow") | flow_logger = getLogger("flow") | ||||
| database_logger = getLogger("database") | database_logger = getLogger("database") | ||||
| FLOAT_ZERO = 1e-8 | FLOAT_ZERO = 1e-8 | ||||
| PARAM_MAXDEPTH = 5 | |||||
| PARAM_MAXDEPTH = 5 |
| from functools import partial | from functools import partial | ||||
| import readline | import readline | ||||
| from graph.canvas import Canvas | from graph.canvas import Canvas | ||||
| from graph.settings import DEBUG | |||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||
| parser = argparse.ArgumentParser() | parser = argparse.ArgumentParser() | ||||
| ) | ) | ||||
| parser.add_argument('-s', '--dsl', default=dsl_default_path, help="input dsl", action='store', required=True) | parser.add_argument('-s', '--dsl', default=dsl_default_path, help="input dsl", action='store', required=True) | ||||
| parser.add_argument('-t', '--tenant_id', default=False, help="Tenant ID", action='store', required=True) | parser.add_argument('-t', '--tenant_id', default=False, help="Tenant ID", action='store', required=True) | ||||
| parser.add_argument('-m', '--stream', default=False, help="Stream output", action='store_true', required=True) | |||||
| parser.add_argument('-m', '--stream', default=False, help="Stream output", action='store_true', required=False) | |||||
| args = parser.parse_args() | args = parser.parse_args() | ||||
| canvas = Canvas(open(args.dsl, "r").read(), args.tenant_id) | canvas = Canvas(open(args.dsl, "r").read(), args.tenant_id) | ||||
| while True: | while True: | ||||
| ans = canvas.run(stream=args.stream) | ans = canvas.run(stream=args.stream) | ||||
| print("==================== Bot =====================\n> ") | |||||
| print("==================== Bot =====================\n> ", end='') | |||||
| if args.stream and isinstance(ans, partial): | if args.stream and isinstance(ans, partial): | ||||
| cont = "" | cont = "" | ||||
| for an in ans(): | for an in ans(): | ||||
| print(an["content"][len(cont):], end='') | |||||
| print(an["content"][len(cont):], end='', flush=True) | |||||
| cont = an["content"] | cont = an["content"] | ||||
| else: | else: | ||||
| print(ans["content"]) | print(ans["content"]) | ||||
| print(canvas.path) | |||||
| question = input("==================== User =====================\n> ") | |||||
| if DEBUG: print(canvas.path) | |||||
| question = input("\n==================== User =====================\n> ") | |||||
| canvas.add_user_input(question) | canvas.add_user_input(question) |
| "obj":{ | "obj":{ | ||||
| "component_name": "Begin", | "component_name": "Begin", | ||||
| "params": { | "params": { | ||||
| "prologue": "Hi there!" | |||||
| "prologue": "Hi! How can I help you?" | |||||
| } | } | ||||
| }, | }, | ||||
| "downstream": ["answer:0"], | "downstream": ["answer:0"], |