rootdriver 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rootdriver/__init__.py +32 -0
- rootdriver/agent.py +48 -0
- rootdriver/constants.py +2 -0
- rootdriver/conversation.py +72 -0
- rootdriver/engine.py +108 -0
- rootdriver/exception.py +1 -0
- rootdriver-0.1.0.dist-info/METADATA +102 -0
- rootdriver-0.1.0.dist-info/RECORD +10 -0
- rootdriver-0.1.0.dist-info/WHEEL +5 -0
- rootdriver-0.1.0.dist-info/top_level.txt +1 -0
rootdriver/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
__author__ = "zimvir"
|
|
3
|
+
__email__ = "zimvir@qq.com"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from .agent import Agent
|
|
10
|
+
from .engine import Engine
|
|
11
|
+
from .conversation import Conversation
|
|
12
|
+
from .llm import LLM
|
|
13
|
+
from .llm.base_adapter import BaseAdapter
|
|
14
|
+
from .llm.adapter import OpenAIAdapter
|
|
15
|
+
from .tool import tool, Tool
|
|
16
|
+
from .types.agent import AgentLLM
|
|
17
|
+
from .types import Message, ToolDefinition, ToolCall
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"Agent",
|
|
21
|
+
"Engine",
|
|
22
|
+
"Conversation",
|
|
23
|
+
"LLM",
|
|
24
|
+
"BaseAdapter",
|
|
25
|
+
"OpenAIAdapter",
|
|
26
|
+
"tool",
|
|
27
|
+
"Tool",
|
|
28
|
+
"AgentLLM",
|
|
29
|
+
"Message",
|
|
30
|
+
"ToolDefinition",
|
|
31
|
+
"ToolCall",
|
|
32
|
+
]
|
rootdriver/agent.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
from .engine import Engine
|
|
5
|
+
from .llm import LLM
|
|
6
|
+
from .conversation import Conversation
|
|
7
|
+
from .tool import Tool, BaseTool
|
|
8
|
+
from .types.agent import AgentLLM
|
|
9
|
+
from .types import ToolDefinition
|
|
10
|
+
from .utils import build_system_message, build_message, build_tool_message, build_user_message, build_assistant_message
|
|
11
|
+
|
|
12
|
+
class Agent:
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
agent_llm: AgentLLM,
|
|
17
|
+
*,
|
|
18
|
+
tools: list[BaseTool] | None = None,
|
|
19
|
+
system_prompt: str | None = None,
|
|
20
|
+
id: str | None = None,
|
|
21
|
+
# save_path: str | Path | None = None,
|
|
22
|
+
# max_retries: int = 3,
|
|
23
|
+
timeout: float | None = None,
|
|
24
|
+
):
|
|
25
|
+
self.conversation = Conversation(system_prompt)
|
|
26
|
+
self.tool = Tool(tools if tools else [])
|
|
27
|
+
self.id = id if id else uuid4().hex
|
|
28
|
+
# self.save_path = save_path
|
|
29
|
+
|
|
30
|
+
self.engine = Engine(
|
|
31
|
+
model=agent_llm.model,
|
|
32
|
+
llm=LLM(agent_llm.adapter),
|
|
33
|
+
conversation=self.conversation,
|
|
34
|
+
tool=self.tool,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def react(self, input_prompt:str) -> "str":
|
|
39
|
+
"""一次 react 循环"""
|
|
40
|
+
response = self.engine.run(build_user_message(input_prompt))
|
|
41
|
+
return response.content
|
|
42
|
+
|
|
43
|
+
def talk(self, input_prompt:str) -> "str":
|
|
44
|
+
"""一次 agent 调用"""
|
|
45
|
+
return self.engine.invoke(build_user_message(input_prompt)).content
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
rootdriver/constants.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from .types import Message
|
|
2
|
+
from .utils import get_iso_timestamp, build_system_message
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Conversation:
|
|
6
|
+
def __init__(self, system_prompt: str = None):
|
|
7
|
+
self.messages: list[Message] = []
|
|
8
|
+
self.system_prompt = system_prompt
|
|
9
|
+
if self.system_prompt:
|
|
10
|
+
self.append(build_system_message(system_prompt))
|
|
11
|
+
|
|
12
|
+
def append(self, message: Message) -> "Conversation":
|
|
13
|
+
self.messages.append(message)
|
|
14
|
+
return self
|
|
15
|
+
|
|
16
|
+
def append_many(self, messages: list[Message]) -> "Conversation":
|
|
17
|
+
self.messages.extend(messages)
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
# def append_user(self, content: str) -> "Conversation":
|
|
21
|
+
# self.messages.append(Message(role="user", content=content, created_at=get_iso_timestamp()))
|
|
22
|
+
# return self
|
|
23
|
+
#
|
|
24
|
+
# def append_assistant(self, content: str | None = None, tool_calls: list | None = None) -> "Conversation":
|
|
25
|
+
# msg = Message(role="assistant", content=content, created_at=get_iso_timestamp())
|
|
26
|
+
# if tool_calls:
|
|
27
|
+
# msg.tool_calls = tool_calls
|
|
28
|
+
# self.messages.append(msg)
|
|
29
|
+
# return self
|
|
30
|
+
#
|
|
31
|
+
# def append_tool(self, tool_call_id: str, content: str) -> "Conversation":
|
|
32
|
+
# self.messages.append(Message(
|
|
33
|
+
# role="tool",
|
|
34
|
+
# tool_call_id=tool_call_id,
|
|
35
|
+
# content=content,
|
|
36
|
+
# created_at=get_iso_timestamp()
|
|
37
|
+
# ))
|
|
38
|
+
# return self
|
|
39
|
+
|
|
40
|
+
def append_system(self, content: str) -> "Conversation":
|
|
41
|
+
self.messages.append(Message(role="system", content=content, created_at=get_iso_timestamp()))
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def delete(self, index: int=-1) -> "Conversation":
|
|
45
|
+
self.messages.pop(index)
|
|
46
|
+
return self
|
|
47
|
+
|
|
48
|
+
def get_messages(self) -> list[Message]:
|
|
49
|
+
'''返回 list[message<obj>]'''
|
|
50
|
+
return self.messages
|
|
51
|
+
|
|
52
|
+
def get_messages_in_list(self) -> list[dict]:
|
|
53
|
+
'''返回 字典加列表组成的message(可转成json用于网络、跨语言传输) 组成的列表'''
|
|
54
|
+
return [m.model_dump(exclude_none=True) for m in self.messages]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_dict_list(cls, messages: list[dict]) -> "Conversation":
|
|
59
|
+
conv = cls()
|
|
60
|
+
conv.messages = [Message.model_validate(m) for m in messages]
|
|
61
|
+
return conv
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def from_list(cls, messages: list[Message]) -> "Conversation":
|
|
65
|
+
conv = cls()
|
|
66
|
+
conv.messages = list(messages)
|
|
67
|
+
return conv
|
|
68
|
+
|
|
69
|
+
def clear(self) -> "Conversation":
|
|
70
|
+
self.messages = []
|
|
71
|
+
return self
|
|
72
|
+
|
rootdriver/engine.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from .llm import LLM
|
|
4
|
+
from .conversation import Conversation
|
|
5
|
+
from .tool import Tool
|
|
6
|
+
from .types import LLMRequest, Message
|
|
7
|
+
from .utils import get_iso_timestamp,build_tool_message, build_message
|
|
8
|
+
|
|
9
|
+
class Engine:
|
|
10
|
+
def __init__(self, model:str, llm:LLM, conversation:Conversation, tool:Tool, ):
|
|
11
|
+
self.llm = llm
|
|
12
|
+
self.conversation = conversation
|
|
13
|
+
self.tool = tool
|
|
14
|
+
self.model = model
|
|
15
|
+
|
|
16
|
+
def invoke(self, input_message:Message) -> Message:
|
|
17
|
+
self.conversation.append(input_message)
|
|
18
|
+
message = self.chat()
|
|
19
|
+
return message
|
|
20
|
+
|
|
21
|
+
def chat(self) -> Message:
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
1. 读会话消息
|
|
25
|
+
2. 大模型交流
|
|
26
|
+
3. 追加会话消息
|
|
27
|
+
4. 判断 是否调用工具
|
|
28
|
+
5. 是: tool 返回结果并追加,否: 追加并返回
|
|
29
|
+
"""
|
|
30
|
+
# 1. 读会话消息
|
|
31
|
+
message = self.conversation.get_messages()
|
|
32
|
+
|
|
33
|
+
# 2. llm交互
|
|
34
|
+
response = self.llm.invoke(self.messages_to_llm_request(message))
|
|
35
|
+
|
|
36
|
+
# 3. 追加会话消息
|
|
37
|
+
response_message = self.llm_response_to_message(response)
|
|
38
|
+
self.conversation.append(response_message)
|
|
39
|
+
|
|
40
|
+
return response_message
|
|
41
|
+
|
|
42
|
+
def deal_tool_or_output(self, response_message:Message) -> Message|None:
|
|
43
|
+
"""
|
|
44
|
+
1. 追加输入
|
|
45
|
+
2. 读会话消息
|
|
46
|
+
3. 大模型交流
|
|
47
|
+
4. 追加会话消息
|
|
48
|
+
5. 判断 是否调用工具
|
|
49
|
+
6. 是: tool 返回结果并追加,否: 追加并返回
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# 5. 判断 是否调用工具
|
|
57
|
+
if response_message.tool_calls:
|
|
58
|
+
# 6. 是: tool 返回结果追加
|
|
59
|
+
for tool_call in response_message.tool_calls:
|
|
60
|
+
tool_result = self.tool.invoke(tool_call)
|
|
61
|
+
self.conversation.append(build_tool_message(tool_result.tool_call_id, tool_result.content))
|
|
62
|
+
return None
|
|
63
|
+
else:
|
|
64
|
+
# 6. 否: 追加并返回
|
|
65
|
+
return response_message
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def run(self, input_message:Message) ->Message:
|
|
69
|
+
"""
|
|
70
|
+
1. 追加输入
|
|
71
|
+
2. 读会话消息
|
|
72
|
+
3. 大模型交流
|
|
73
|
+
4. 追加会话消息
|
|
74
|
+
5. 判断 是否调用工具
|
|
75
|
+
6. 是: tool 返回结果并追加,否: 追加并返回
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
self.conversation.append(input_message)
|
|
82
|
+
while True:
|
|
83
|
+
|
|
84
|
+
response_message = self.chat()
|
|
85
|
+
result = self.deal_tool_or_output(response_message)
|
|
86
|
+
if result is None:
|
|
87
|
+
continue
|
|
88
|
+
elif isinstance(result, Message):
|
|
89
|
+
return result
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def messages_to_llm_request(self,messages:list[Message]) -> LLMRequest:
|
|
99
|
+
return LLMRequest(
|
|
100
|
+
model=self.model,
|
|
101
|
+
messages=messages,
|
|
102
|
+
tools=self.tool.to_definitions(),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def llm_response_to_message(self, response) -> Message:
|
|
106
|
+
"""把 LLM 响应转成 Message 。"""
|
|
107
|
+
return response.message
|
|
108
|
+
|
rootdriver/exception.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rootdriver
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Rooted in Origin, Driving All Things
|
|
5
|
+
Author-email: zimvir <zimvir@qq.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: openai>=1.0.0
|
|
10
|
+
Requires-Dist: pydantic>=2.0.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
13
|
+
|
|
14
|
+
# RootDriver
|
|
15
|
+
|
|
16
|
+
根源出发, 驱动万物
|
|
17
|
+
|
|
18
|
+
一个轻量级的 Python AI Agent 开发框架。
|
|
19
|
+
|
|
20
|
+
## 特性
|
|
21
|
+
|
|
22
|
+
- **简洁易用**:装饰器方式定义工具,快速构建 Agent
|
|
23
|
+
- **模块化设计**:LLM 适配器、工具系统、会话管理解耦
|
|
24
|
+
- **工具调用**:支持 function calling,自动执行工具并返回结果
|
|
25
|
+
- **多适配器**:基于适配器模式,方便扩展其他 LLM Provider
|
|
26
|
+
|
|
27
|
+
## 安装
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install rootdriver
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 快速开始
|
|
34
|
+
|
|
35
|
+
### 定义工具
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from rootdriver import tool
|
|
39
|
+
|
|
40
|
+
@tool
|
|
41
|
+
def get_weather(city: str) -> str:
|
|
42
|
+
"""获取城市天气"""
|
|
43
|
+
return f"{city} 晴天"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 创建 Agent
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from rootdriver import Agent, AgentLLM, OpenAIAdapter
|
|
50
|
+
agent_llm=AgentLLM(
|
|
51
|
+
adapter=OpenAIAdapter(
|
|
52
|
+
api_key="YOUR_API_KEY",
|
|
53
|
+
base_url="BASE_URL"
|
|
54
|
+
),
|
|
55
|
+
model="gpt-4",
|
|
56
|
+
|
|
57
|
+
),
|
|
58
|
+
agent = Agent(
|
|
59
|
+
agent_llm=agent_llm,
|
|
60
|
+
tools=[get_weather],
|
|
61
|
+
system_prompt="你是一个有用的助手",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# 单次对话
|
|
65
|
+
response = agent.talk("北京天气怎么样?")
|
|
66
|
+
print(response)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 使用工具
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
# 完整对话循环(包含工具调用)
|
|
73
|
+
response = Agent.react("帮我查下上海天气")
|
|
74
|
+
print(response)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 核心组件
|
|
78
|
+
|
|
79
|
+
| 组件 | 说明 |
|
|
80
|
+
|------|------|
|
|
81
|
+
| `Agent` | 智能体入口,整合 LLM、工具、会话 |
|
|
82
|
+
| `Engine` | 核心引擎,处理对话循环和工具调用 |
|
|
83
|
+
| `Conversation` | 会话管理,维护消息历史 |
|
|
84
|
+
| `LLM` | LLM 调用封装 |
|
|
85
|
+
| `Tool` | 工具集合,管理所有可调用工具 |
|
|
86
|
+
|
|
87
|
+
## 项目结构
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
rootdriver/
|
|
91
|
+
├── agent.py # Agent 智能体
|
|
92
|
+
├── engine.py # 引擎核心
|
|
93
|
+
├── conversation.py # 对话管理
|
|
94
|
+
├── llm/ # LLM 适配器
|
|
95
|
+
├── tool/ # 工具系统
|
|
96
|
+
├── types/ # 类型定义
|
|
97
|
+
└── utils/ # 工具函数
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
rootdriver/__init__.py,sha256=E7fG0npdGMr935XTHf0ByQbphNxQTW-nfWx6L0bXXFg,622
|
|
2
|
+
rootdriver/agent.py,sha256=WDj0uc8Xt_KXwhOz3oyQwUSpmaIOrmAqEwHcyhGDiOQ,1454
|
|
3
|
+
rootdriver/constants.py,sha256=btldAAsVhgJwj9zmk0E0WP-q26ydyEYQNSUkrXVfgb0,55
|
|
4
|
+
rootdriver/conversation.py,sha256=_9lpx8K3ay32YI-vEf1ILfOaXgBPMCxRLmspYGbCEZE,2581
|
|
5
|
+
rootdriver/engine.py,sha256=D-6CjvykK8V0Ppo7b3EP2VLIeh3GrtKd9a5ipOABK90,3155
|
|
6
|
+
rootdriver/exception.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
7
|
+
rootdriver-0.1.0.dist-info/METADATA,sha256=YryuokUY6_huJ7r5tdhfccd7z8qtswijmSYwli96dow,2333
|
|
8
|
+
rootdriver-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
+
rootdriver-0.1.0.dist-info/top_level.txt,sha256=m8YK68IRM5Pzia9feIdOJkfBXPEjVzA_KUTawqeA1us,11
|
|
10
|
+
rootdriver-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rootdriver
|