KevinHuSh
commited on
Commit
·
9279c42
1
Parent(s):
e0a940c
add README to graph (#1211)
Browse files### What problem does this PR solve?
### Type of change
- [x] Documentation Update
- graph/README.md +45 -0
- graph/README_zh.md +46 -0
- graph/canvas.py +3 -3
- graph/component/base.py +2 -2
- graph/component/categorize.py +2 -2
- graph/settings.py +2 -1
- graph/test/client.py +6 -5
- graph/test/dsl_examples/customer_service.json +1 -1
graph/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
English | [简体中文](./README_zh.md)
|
| 2 |
+
|
| 3 |
+
# *Graph*
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
## Introduction
|
| 7 |
+
|
| 8 |
+
*Graph* is a mathematical concept which is composed of nodes and edges.
|
| 9 |
+
It is used to compose a complex work flow or agent.
|
| 10 |
+
And this graph is beyond the DAG that we can use circles to describe our agent or work flow.
|
| 11 |
+
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.
|
| 12 |
+
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.
|
| 13 |
+
Otherwise, correct configurations in conf/service_conf.yaml is essential.
|
| 14 |
+
|
| 15 |
+
```bash
|
| 16 |
+
PYTHONPATH=path/to/ragflow python graph/test/client.py -h
|
| 17 |
+
usage: client.py [-h] -s DSL -t TENANT_ID -m
|
| 18 |
+
|
| 19 |
+
options:
|
| 20 |
+
-h, --help show this help message and exit
|
| 21 |
+
-s DSL, --dsl DSL input dsl
|
| 22 |
+
-t TENANT_ID, --tenant_id TENANT_ID
|
| 23 |
+
Tenant ID
|
| 24 |
+
-m, --stream Stream output
|
| 25 |
+
```
|
| 26 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 27 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/79179c5e-d4d6-464a-b6c4-5721cb329899" width="1000"/>
|
| 28 |
+
</div>
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
## How to gain a TENANT_ID in command line?
|
| 32 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 33 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/419d8588-87b1-4ab8-ac49-2d1f047a4b97" width="600"/>
|
| 34 |
+
</div>
|
| 35 |
+
💡 We plant to display it here in the near future.
|
| 36 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 37 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/c97915de-0091-46a5-afd9-e278946e5fe3" width="600"/>
|
| 38 |
+
</div>
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
## How to set 'kb_ids' for component 'Retrieval' in DSL?
|
| 42 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 43 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/0a731534-cac8-49fd-8a92-ca247eeef66d" width="600"/>
|
| 44 |
+
</div>
|
| 45 |
+
|
graph/README_zh.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[English](./README.md) | 简体中文
|
| 2 |
+
|
| 3 |
+
# *Graph*
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
## 简介
|
| 7 |
+
|
| 8 |
+
"Graph"是一个由节点和边组成的数学概念。
|
| 9 |
+
它被用来构建复杂的工作流或代理。
|
| 10 |
+
这个图超越了有向无环图(DAG),我们可以使用循环来描述我们的代理或工作流。
|
| 11 |
+
在这个文件夹下,我们提出了一个测试工具 ./test/client.py,
|
| 12 |
+
它可以测试像文件夹./test/dsl_examples下一样的DSL文件。
|
| 13 |
+
请在启动 RAGFlow 的同一文件夹中使用此客户端。如果它是通过 Docker 运行的,请在运行客户端之前进入容器。
|
| 14 |
+
否则,正确配置 conf/service_conf.yaml 文件是必不可少的。
|
| 15 |
+
|
| 16 |
+
```bash
|
| 17 |
+
PYTHONPATH=path/to/ragflow python graph/test/client.py -h
|
| 18 |
+
usage: client.py [-h] -s DSL -t TENANT_ID -m
|
| 19 |
+
|
| 20 |
+
options:
|
| 21 |
+
-h, --help show this help message and exit
|
| 22 |
+
-s DSL, --dsl DSL input dsl
|
| 23 |
+
-t TENANT_ID, --tenant_id TENANT_ID
|
| 24 |
+
Tenant ID
|
| 25 |
+
-m, --stream Stream output
|
| 26 |
+
```
|
| 27 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 28 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/05924730-c427-495b-8ee4-90b8b2250681" width="1000"/>
|
| 29 |
+
</div>
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
## 命令行中的TENANT_ID如何获得?
|
| 33 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 34 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/419d8588-87b1-4ab8-ac49-2d1f047a4b97" width="600"/>
|
| 35 |
+
</div>
|
| 36 |
+
💡 后面会展示在这里:
|
| 37 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 38 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/c97915de-0091-46a5-afd9-e278946e5fe3" width="600"/>
|
| 39 |
+
</div>
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
## DSL里面的Retrieval组件的kb_ids怎么填?
|
| 43 |
+
<div align="center" style="margin-top:20px;margin-bottom:20px;">
|
| 44 |
+
<img src="https://github.com/infiniflow/ragflow/assets/12318111/0a731534-cac8-49fd-8a92-ca247eeef66d" width="600"/>
|
| 45 |
+
</div>
|
| 46 |
+
|
graph/canvas.py
CHANGED
|
@@ -24,7 +24,7 @@ import pandas as pd
|
|
| 24 |
|
| 25 |
from graph.component import component_class
|
| 26 |
from graph.component.base import ComponentBase
|
| 27 |
-
from graph.settings import flow_logger
|
| 28 |
|
| 29 |
|
| 30 |
class Canvas(ABC):
|
|
@@ -170,14 +170,14 @@ class Canvas(ABC):
|
|
| 170 |
if cpn.component_name == "Answer":
|
| 171 |
self.answer.append(c)
|
| 172 |
else:
|
| 173 |
-
print("RUN: ", c)
|
| 174 |
ans = cpn.run(self.history, **kwargs)
|
| 175 |
self.path[-1].append(c)
|
| 176 |
ran += 1
|
| 177 |
|
| 178 |
prepare2run(self.components[self.path[-2][-1]]["downstream"])
|
| 179 |
while ran < len(self.path[-1]):
|
| 180 |
-
print(ran, self.path)
|
| 181 |
cpn_id = self.path[-1][ran]
|
| 182 |
cpn = self.get_component(cpn_id)
|
| 183 |
if not cpn["downstream"]: break
|
|
|
|
| 24 |
|
| 25 |
from graph.component import component_class
|
| 26 |
from graph.component.base import ComponentBase
|
| 27 |
+
from graph.settings import flow_logger, DEBUG
|
| 28 |
|
| 29 |
|
| 30 |
class Canvas(ABC):
|
|
|
|
| 170 |
if cpn.component_name == "Answer":
|
| 171 |
self.answer.append(c)
|
| 172 |
else:
|
| 173 |
+
if DEBUG: print("RUN: ", c)
|
| 174 |
ans = cpn.run(self.history, **kwargs)
|
| 175 |
self.path[-1].append(c)
|
| 176 |
ran += 1
|
| 177 |
|
| 178 |
prepare2run(self.components[self.path[-2][-1]]["downstream"])
|
| 179 |
while ran < len(self.path[-1]):
|
| 180 |
+
if DEBUG: print(ran, self.path)
|
| 181 |
cpn_id = self.path[-1][ran]
|
| 182 |
cpn = self.get_component(cpn_id)
|
| 183 |
if not cpn["downstream"]: break
|
graph/component/base.py
CHANGED
|
@@ -24,7 +24,7 @@ from typing import List, Dict
|
|
| 24 |
import pandas as pd
|
| 25 |
|
| 26 |
from graph import settings
|
| 27 |
-
from graph.settings import flow_logger
|
| 28 |
|
| 29 |
_FEEDED_DEPRECATED_PARAMS = "_feeded_deprecated_params"
|
| 30 |
_DEPRECATED_PARAMS = "_deprecated_params"
|
|
@@ -428,7 +428,7 @@ class ComponentBase(ABC):
|
|
| 428 |
reversed_cpnts.extend(self._canvas.path[-2])
|
| 429 |
reversed_cpnts.extend(self._canvas.path[-1])
|
| 430 |
|
| 431 |
-
print(self.component_name, reversed_cpnts[::-1])
|
| 432 |
for u in reversed_cpnts[::-1]:
|
| 433 |
if self.get_component_name(u) in ["switch"]: continue
|
| 434 |
if self.component_name.lower().find("switch") < 0 \
|
|
|
|
| 24 |
import pandas as pd
|
| 25 |
|
| 26 |
from graph import settings
|
| 27 |
+
from graph.settings import flow_logger, DEBUG
|
| 28 |
|
| 29 |
_FEEDED_DEPRECATED_PARAMS = "_feeded_deprecated_params"
|
| 30 |
_DEPRECATED_PARAMS = "_deprecated_params"
|
|
|
|
| 428 |
reversed_cpnts.extend(self._canvas.path[-2])
|
| 429 |
reversed_cpnts.extend(self._canvas.path[-1])
|
| 430 |
|
| 431 |
+
if DEBUG: print(self.component_name, reversed_cpnts[::-1])
|
| 432 |
for u in reversed_cpnts[::-1]:
|
| 433 |
if self.get_component_name(u) in ["switch"]: continue
|
| 434 |
if self.component_name.lower().find("switch") < 0 \
|
graph/component/categorize.py
CHANGED
|
@@ -20,6 +20,7 @@ import pandas as pd
|
|
| 20 |
from api.db import LLMType
|
| 21 |
from api.db.services.llm_service import LLMBundle
|
| 22 |
from graph.component import GenerateParam, Generate
|
|
|
|
| 23 |
|
| 24 |
|
| 25 |
class CategorizeParam(GenerateParam):
|
|
@@ -72,12 +73,11 @@ class Categorize(Generate, ABC):
|
|
| 72 |
|
| 73 |
def _run(self, history, **kwargs):
|
| 74 |
input = self.get_input()
|
| 75 |
-
print(input, "DDDDDDDDDDDDDDDDDDDDDDDDDDDDD")
|
| 76 |
input = "Question: " + ("; ".join(input["content"]) if "content" in input else "") + "Category: "
|
| 77 |
chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.CHAT, self._param.llm_id)
|
| 78 |
ans = chat_mdl.chat(self._param.get_prompt(), [{"role": "user", "content": input}],
|
| 79 |
self._param.gen_conf())
|
| 80 |
-
print(ans, ":::::::::::::::::::::::::::::::::")
|
| 81 |
for c in self._param.category_description.keys():
|
| 82 |
if ans.lower().find(c.lower()) >= 0:
|
| 83 |
return Categorize.be_output(self._param.category_description[c]["to"])
|
|
|
|
| 20 |
from api.db import LLMType
|
| 21 |
from api.db.services.llm_service import LLMBundle
|
| 22 |
from graph.component import GenerateParam, Generate
|
| 23 |
+
from graph.settings import DEBUG
|
| 24 |
|
| 25 |
|
| 26 |
class CategorizeParam(GenerateParam):
|
|
|
|
| 73 |
|
| 74 |
def _run(self, history, **kwargs):
|
| 75 |
input = self.get_input()
|
|
|
|
| 76 |
input = "Question: " + ("; ".join(input["content"]) if "content" in input else "") + "Category: "
|
| 77 |
chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.CHAT, self._param.llm_id)
|
| 78 |
ans = chat_mdl.chat(self._param.get_prompt(), [{"role": "user", "content": input}],
|
| 79 |
self._param.gen_conf())
|
| 80 |
+
if DEBUG: print(ans, ":::::::::::::::::::::::::::::::::", input)
|
| 81 |
for c in self._param.category_description.keys():
|
| 82 |
if ans.lower().find(c.lower()) >= 0:
|
| 83 |
return Categorize.be_output(self._param.category_description[c]["to"])
|
graph/settings.py
CHANGED
|
@@ -19,6 +19,7 @@ import os
|
|
| 19 |
from api.utils.file_utils import get_project_base_directory
|
| 20 |
from api.utils.log_utils import LoggerFactory, getLogger
|
| 21 |
|
|
|
|
| 22 |
LoggerFactory.set_directory(
|
| 23 |
os.path.join(
|
| 24 |
get_project_base_directory(),
|
|
@@ -30,4 +31,4 @@ LoggerFactory.LEVEL = 30
|
|
| 30 |
flow_logger = getLogger("flow")
|
| 31 |
database_logger = getLogger("database")
|
| 32 |
FLOAT_ZERO = 1e-8
|
| 33 |
-
PARAM_MAXDEPTH = 5
|
|
|
|
| 19 |
from api.utils.file_utils import get_project_base_directory
|
| 20 |
from api.utils.log_utils import LoggerFactory, getLogger
|
| 21 |
|
| 22 |
+
DEBUG = 0
|
| 23 |
LoggerFactory.set_directory(
|
| 24 |
os.path.join(
|
| 25 |
get_project_base_directory(),
|
|
|
|
| 31 |
flow_logger = getLogger("flow")
|
| 32 |
database_logger = getLogger("database")
|
| 33 |
FLOAT_ZERO = 1e-8
|
| 34 |
+
PARAM_MAXDEPTH = 5
|
graph/test/client.py
CHANGED
|
@@ -18,6 +18,7 @@ import os
|
|
| 18 |
from functools import partial
|
| 19 |
import readline
|
| 20 |
from graph.canvas import Canvas
|
|
|
|
| 21 |
|
| 22 |
if __name__ == '__main__':
|
| 23 |
parser = argparse.ArgumentParser()
|
|
@@ -28,21 +29,21 @@ if __name__ == '__main__':
|
|
| 28 |
)
|
| 29 |
parser.add_argument('-s', '--dsl', default=dsl_default_path, help="input dsl", action='store', required=True)
|
| 30 |
parser.add_argument('-t', '--tenant_id', default=False, help="Tenant ID", action='store', required=True)
|
| 31 |
-
parser.add_argument('-m', '--stream', default=False, help="Stream output", action='store_true', required=
|
| 32 |
args = parser.parse_args()
|
| 33 |
|
| 34 |
canvas = Canvas(open(args.dsl, "r").read(), args.tenant_id)
|
| 35 |
while True:
|
| 36 |
ans = canvas.run(stream=args.stream)
|
| 37 |
-
print("==================== Bot =====================\n> ")
|
| 38 |
if args.stream and isinstance(ans, partial):
|
| 39 |
cont = ""
|
| 40 |
for an in ans():
|
| 41 |
-
print(an["content"][len(cont):], end='')
|
| 42 |
cont = an["content"]
|
| 43 |
else:
|
| 44 |
print(ans["content"])
|
| 45 |
|
| 46 |
-
print(canvas.path)
|
| 47 |
-
question = input("==================== User =====================\n> ")
|
| 48 |
canvas.add_user_input(question)
|
|
|
|
| 18 |
from functools import partial
|
| 19 |
import readline
|
| 20 |
from graph.canvas import Canvas
|
| 21 |
+
from graph.settings import DEBUG
|
| 22 |
|
| 23 |
if __name__ == '__main__':
|
| 24 |
parser = argparse.ArgumentParser()
|
|
|
|
| 29 |
)
|
| 30 |
parser.add_argument('-s', '--dsl', default=dsl_default_path, help="input dsl", action='store', required=True)
|
| 31 |
parser.add_argument('-t', '--tenant_id', default=False, help="Tenant ID", action='store', required=True)
|
| 32 |
+
parser.add_argument('-m', '--stream', default=False, help="Stream output", action='store_true', required=False)
|
| 33 |
args = parser.parse_args()
|
| 34 |
|
| 35 |
canvas = Canvas(open(args.dsl, "r").read(), args.tenant_id)
|
| 36 |
while True:
|
| 37 |
ans = canvas.run(stream=args.stream)
|
| 38 |
+
print("==================== Bot =====================\n> ", end='')
|
| 39 |
if args.stream and isinstance(ans, partial):
|
| 40 |
cont = ""
|
| 41 |
for an in ans():
|
| 42 |
+
print(an["content"][len(cont):], end='', flush=True)
|
| 43 |
cont = an["content"]
|
| 44 |
else:
|
| 45 |
print(ans["content"])
|
| 46 |
|
| 47 |
+
if DEBUG: print(canvas.path)
|
| 48 |
+
question = input("\n==================== User =====================\n> ")
|
| 49 |
canvas.add_user_input(question)
|
graph/test/dsl_examples/customer_service.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
"obj":{
|
| 5 |
"component_name": "Begin",
|
| 6 |
"params": {
|
| 7 |
-
"prologue": "Hi
|
| 8 |
}
|
| 9 |
},
|
| 10 |
"downstream": ["answer:0"],
|
|
|
|
| 4 |
"obj":{
|
| 5 |
"component_name": "Begin",
|
| 6 |
"params": {
|
| 7 |
+
"prologue": "Hi! How can I help you?"
|
| 8 |
}
|
| 9 |
},
|
| 10 |
"downstream": ["answer:0"],
|