Skip to content

Commit d5afa6e

Browse files
yhjun1026fangyinclcx01800250lcxadmlAralhi
authored
Native data AI application framework based on AWEL+AGENT (#1152)
Co-authored-by: Fangyin Cheng <staneyffer@gmail.com> Co-authored-by: lcx01800250 <lcx01800250@alibaba-inc.com> Co-authored-by: licunxing <864255598@qq.com> Co-authored-by: Aralhi <xiaoping0501@gmail.com> Co-authored-by: xuyuan23 <643854343@qq.com> Co-authored-by: aries_ckt <916701291@qq.com> Co-authored-by: hzh97 <2976151305@qq.com>
1 parent dbb9ac8 commit d5afa6e

File tree

328 files changed

+22613
-3289
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

328 files changed

+22613
-3289
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ repos:
44
hooks:
55
- id: python-fmt
66
name: Python Format
7-
entry: make fmt
7+
entry: make fmt-check
88
language: system
99
exclude: '^dbgpt/app/static/|^web/'
1010
types: [python]

assets/schema/dbgpt.sql

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,81 @@ CREATE TABLE `gpts_plans` (
262262
UNIQUE KEY `uk_sub_task` (`conv_id`,`sub_task_num`)
263263
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COMMENT="gpt plan";
264264

265+
-- dbgpt.dbgpt_serve_flow definition
266+
CREATE TABLE `dbgpt_serve_flow` (
267+
`id` int NOT NULL AUTO_INCREMENT COMMENT 'Auto increment id',
268+
`uid` varchar(128) NOT NULL COMMENT 'Unique id',
269+
`dag_id` varchar(128) DEFAULT NULL COMMENT 'DAG id',
270+
`name` varchar(128) DEFAULT NULL COMMENT 'Flow name',
271+
`flow_data` text COMMENT 'Flow data, JSON format',
272+
`user_name` varchar(128) DEFAULT NULL COMMENT 'User name',
273+
`sys_code` varchar(128) DEFAULT NULL COMMENT 'System code',
274+
`gmt_created` datetime DEFAULT NULL COMMENT 'Record creation time',
275+
`gmt_modified` datetime DEFAULT NULL COMMENT 'Record update time',
276+
`flow_category` varchar(64) DEFAULT NULL COMMENT 'Flow category',
277+
`description` varchar(512) DEFAULT NULL COMMENT 'Flow description',
278+
`state` varchar(32) DEFAULT NULL COMMENT 'Flow state',
279+
`source` varchar(64) DEFAULT NULL COMMENT 'Flow source',
280+
`source_url` varchar(512) DEFAULT NULL COMMENT 'Flow source url',
281+
`version` varchar(32) DEFAULT NULL COMMENT 'Flow version',
282+
`label` varchar(128) DEFAULT NULL COMMENT 'Flow label',
283+
`editable` int DEFAULT NULL COMMENT 'Editable, 0: editable, 1: not editable',
284+
PRIMARY KEY (`id`),
285+
UNIQUE KEY `uk_uid` (`uid`),
286+
KEY `ix_dbgpt_serve_flow_sys_code` (`sys_code`),
287+
KEY `ix_dbgpt_serve_flow_uid` (`uid`),
288+
KEY `ix_dbgpt_serve_flow_dag_id` (`dag_id`),
289+
KEY `ix_dbgpt_serve_flow_user_name` (`user_name`),
290+
KEY `ix_dbgpt_serve_flow_name` (`name`)
291+
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
292+
293+
-- dbgpt.gpts_app definition
294+
CREATE TABLE `gpts_app` (
295+
`id` int NOT NULL AUTO_INCREMENT COMMENT 'autoincrement id',
296+
`app_code` varchar(255) NOT NULL COMMENT 'Current AI assistant code',
297+
`app_name` varchar(255) NOT NULL COMMENT 'Current AI assistant name',
298+
`app_describe` varchar(2255) NOT NULL COMMENT 'Current AI assistant describe',
299+
`language` varchar(100) NOT NULL COMMENT 'gpts language',
300+
`team_mode` varchar(255) NOT NULL COMMENT 'Team work mode',
301+
`team_context` text COMMENT 'The execution logic and team member content that teams with different working modes rely on',
302+
`user_code` varchar(255) DEFAULT NULL COMMENT 'user code',
303+
`sys_code` varchar(255) DEFAULT NULL COMMENT 'system app code',
304+
`created_at` datetime DEFAULT NULL COMMENT 'create time',
305+
`updated_at` datetime DEFAULT NULL COMMENT 'last update time',
306+
`icon` varchar(1024) DEFAULT NULL COMMENT 'app icon, url',
307+
PRIMARY KEY (`id`),
308+
UNIQUE KEY `uk_gpts_app` (`app_name`)
309+
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
310+
311+
CREATE TABLE `gpts_app_collection` (
312+
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'autoincrement id',
313+
`app_code` varchar(255) NOT NULL COMMENT 'Current AI assistant code',
314+
`user_code` int(11) NOT NULL COMMENT 'user code',
315+
`sys_code` varchar(255) NOT NULL COMMENT 'system app code',
316+
`created_at` datetime DEFAULT NULL COMMENT 'create time',
317+
`updated_at` datetime DEFAULT NULL COMMENT 'last update time',
318+
PRIMARY KEY (`id`),
319+
KEY `idx_app_code` (`app_code`),
320+
KEY `idx_user_code` (`user_code`)
321+
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT="gpt collections";
322+
323+
-- dbgpt.gpts_app_detail definition
324+
CREATE TABLE `gpts_app_detail` (
325+
`id` int NOT NULL AUTO_INCREMENT COMMENT 'autoincrement id',
326+
`app_code` varchar(255) NOT NULL COMMENT 'Current AI assistant code',
327+
`app_name` varchar(255) NOT NULL COMMENT 'Current AI assistant name',
328+
`agent_name` varchar(255) NOT NULL COMMENT ' Agent name',
329+
`node_id` varchar(255) NOT NULL COMMENT 'Current AI assistant Agent Node id',
330+
`resources` text COMMENT 'Agent bind resource',
331+
`prompt_template` text COMMENT 'Agent bind template',
332+
`llm_strategy` varchar(25) DEFAULT NULL COMMENT 'Agent use llm strategy',
333+
`llm_strategy_value` text COMMENT 'Agent use llm strategy value',
334+
`created_at` datetime DEFAULT NULL COMMENT 'create time',
335+
`updated_at` datetime DEFAULT NULL COMMENT 'last update time',
336+
PRIMARY KEY (`id`),
337+
UNIQUE KEY `uk_gpts_app_agent_node` (`app_name`,`agent_name`,`node_id`)
338+
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
339+
265340
CREATE
266341
DATABASE IF NOT EXISTS EXAMPLE_1;
267342
use EXAMPLE_1;

dbgpt/agent/actions/action.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import json
2+
from abc import ABC
3+
from typing import (
4+
Any,
5+
Dict,
6+
Generic,
7+
List,
8+
Optional,
9+
Tuple,
10+
Type,
11+
TypeVar,
12+
Union,
13+
get_args,
14+
get_origin,
15+
)
16+
17+
from pydantic import BaseModel
18+
19+
from dbgpt.agent.resource.resource_api import AgentResource, ResourceType
20+
from dbgpt.agent.resource.resource_loader import ResourceLoader
21+
from dbgpt.util.json_utils import find_json_objects
22+
23+
T = TypeVar("T", None, BaseModel, List[BaseModel])
24+
25+
26+
class ActionOutput(BaseModel):
27+
content: str
28+
is_exe_success: bool = True
29+
view: str = None
30+
resource_type: Optional[str] = None
31+
resource_value: Optional[Any] = None
32+
33+
@staticmethod
34+
def from_dict(param: Optional[Dict]):
35+
if not param:
36+
return None
37+
return ActionOutput.parse_obj(param)
38+
39+
40+
class Action(ABC, Generic[T]):
41+
def __init__(self):
42+
self.resource_loader: ResourceLoader = None
43+
44+
def init_resource_loader(self, resource_loader: ResourceLoader):
45+
self.resource_loader = resource_loader
46+
47+
@property
48+
def resource_need(self) -> Optional[ResourceType]:
49+
return None
50+
51+
@property
52+
def render_protocal(self):
53+
raise NotImplementedError("The run method should be implemented in a subclass.")
54+
55+
def render_prompt(self):
56+
if self.render_protocal is None:
57+
return None
58+
else:
59+
return self.render_protocal.render_prompt()
60+
61+
def _create_example(
62+
self,
63+
model_type: Union[Type[BaseModel], Type[List[BaseModel]]],
64+
) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
65+
if model_type is None:
66+
return None
67+
origin = get_origin(model_type)
68+
args = get_args(model_type)
69+
if origin is None:
70+
example = {}
71+
for field_name, field in model_type.__fields__.items():
72+
field_info = field.field_info
73+
if field_info.description:
74+
example[field_name] = field_info.description
75+
elif field_info.default:
76+
example[field_name] = field_info.default
77+
else:
78+
example[field_name] = ""
79+
return example
80+
elif origin is list or origin is List:
81+
element_type = args[0]
82+
if issubclass(element_type, BaseModel):
83+
return [self._create_example(element_type)]
84+
else:
85+
raise TypeError("List elements must be BaseModel subclasses")
86+
else:
87+
raise ValueError(
88+
f"Model type {model_type} is not an instance of BaseModel."
89+
)
90+
91+
@property
92+
def out_model_type(self) -> T:
93+
return None
94+
95+
@property
96+
def ai_out_schema(self) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
97+
if self.out_model_type is None:
98+
return None
99+
100+
return f"""Please response in the following json format:
101+
{json.dumps(self._create_example(self.out_model_type), indent=2, ensure_ascii=False)}
102+
Make sure the response is correct json and can be parsed by Python json.loads.
103+
"""
104+
105+
def _ai_mesage_2_json(self, ai_message: str) -> json:
106+
json_objects = find_json_objects(ai_message)
107+
json_count = len(json_objects)
108+
if json_count != 1:
109+
raise ValueError("Unable to obtain valid output.")
110+
return json_objects[0]
111+
112+
def _input_convert(self, ai_message: str, cls: Type[T]) -> Union[T, List[T]]:
113+
json_result = self._ai_mesage_2_json(ai_message)
114+
if get_origin(cls) == list:
115+
inner_type = get_args(cls)[0]
116+
return [inner_type.parse_obj(item) for item in json_result]
117+
else:
118+
return cls.parse_obj(json_result)
119+
120+
async def a_run(
121+
self,
122+
ai_message: str,
123+
resource: Optional[AgentResource] = None,
124+
rely_action_out: Optional[ActionOutput] = None,
125+
need_vis_render: bool = True,
126+
**kwargs,
127+
) -> ActionOutput:
128+
raise NotImplementedError("The run method should be implemented in a subclass.")
File renamed without changes.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import json
2+
import logging
3+
from typing import Any, Dict, List, Optional, Union
4+
5+
from pydantic import BaseModel, Field
6+
7+
from dbgpt.agent.actions.action import Action, ActionOutput, T
8+
from dbgpt.agent.common.schema import Status
9+
from dbgpt.agent.plugin.generator import PluginPromptGenerator
10+
from dbgpt.agent.resource.resource_api import AgentResource, ResourceType
11+
from dbgpt.agent.resource.resource_plugin_api import ResourcePluginClient
12+
from dbgpt.vis.tags.vis_plugin import Vis, VisPlugin
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
class BlankAction(Action):
18+
def __init__(self, **kwargs):
19+
super().__init__(**kwargs)
20+
21+
@property
22+
def resource_need(self) -> Optional[ResourceType]:
23+
return None
24+
25+
@property
26+
def render_protocal(self) -> Optional[Vis]:
27+
return None
28+
29+
@property
30+
def ai_out_schema(self) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
31+
return None
32+
33+
async def a_run(
34+
self,
35+
ai_message: str,
36+
resource: Optional[AgentResource] = None,
37+
rely_action_out: Optional[ActionOutput] = None,
38+
need_vis_render: bool = True,
39+
) -> ActionOutput:
40+
return ActionOutput(is_exe_success=True, content=ai_message, view=ai_message)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import json
2+
import logging
3+
from typing import Optional
4+
5+
from pydantic import BaseModel, Field
6+
7+
from dbgpt.agent.actions.action import ActionOutput, T
8+
from dbgpt.agent.resource.resource_api import AgentResource, ResourceType
9+
from dbgpt.agent.resource.resource_db_api import ResourceDbClient
10+
from dbgpt.vis.tags.vis_chart import Vis, VisChart
11+
12+
from .action import Action
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
class SqlInput(BaseModel):
18+
display_type: str = Field(
19+
...,
20+
description="The chart rendering method selected for SQL. If you don’t know what to output, just output 'response_table' uniformly.",
21+
)
22+
sql: str = Field(
23+
..., description="Executable sql generated for the current target/problem"
24+
)
25+
thought: str = Field(..., description="Summary of thoughts to the user")
26+
27+
28+
class ChartAction(Action[SqlInput]):
29+
def __init__(self):
30+
self._render_protocal = VisChart()
31+
32+
@property
33+
def resource_need(self) -> Optional[ResourceType]:
34+
return ResourceType.DB
35+
36+
@property
37+
def render_protocal(self) -> Optional[Vis]:
38+
return self._render_protocal
39+
40+
@property
41+
def out_model_type(self):
42+
return SqlInput
43+
44+
async def a_run(
45+
self,
46+
ai_message: str,
47+
resource: Optional[AgentResource] = None,
48+
rely_action_out: Optional[ActionOutput] = None,
49+
need_vis_render: bool = True,
50+
) -> ActionOutput:
51+
try:
52+
param: SqlInput = self._input_convert(ai_message, SqlInput)
53+
except Exception as e:
54+
logger.exception(f"str(e)! \n {ai_message}")
55+
return ActionOutput(
56+
is_exe_success=False,
57+
content="The requested correctly structured answer could not be found.",
58+
)
59+
try:
60+
resource_db_client: ResourceDbClient = (
61+
self.resource_loader.get_resesource_api(self.resource_need)
62+
)
63+
if not resource_db_client:
64+
raise ValueError(
65+
"There is no implementation class bound to database resource execution!"
66+
)
67+
data_df = await resource_db_client.a_query_to_df(resource.value, param.sql)
68+
view = await self.render_protocal.disply(
69+
chart=json.loads(param.json()), data_df=data_df
70+
)
71+
return ActionOutput(
72+
is_exe_success=True,
73+
content=param.json(),
74+
view=view,
75+
resource_type=self.resource_need.value,
76+
resource_value=resource.value,
77+
)
78+
except Exception as e:
79+
logger.exception("Check your answers, the sql run failed!")
80+
return ActionOutput(
81+
is_exe_success=False,
82+
content=f"Check your answers, the sql run failed!Reason:{str(e)}",
83+
)

0 commit comments

Comments
 (0)