thinkai-framework 0.2.2__tar.gz → 0.3.0__tar.gz
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.
- {thinkai_framework-0.2.2/thinkai_framework.egg-info → thinkai_framework-0.3.0}/PKG-INFO +43 -19
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/README.md +42 -18
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/pyproject.toml +1 -1
- thinkai_framework-0.3.0/tests/test_function_calling_skill.py +363 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/tests/test_thinkai.py +1 -1
- thinkai_framework-0.3.0/thinkai/__init__.py +40 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/agent/__init__.py +2 -0
- thinkai_framework-0.3.0/thinkai/agent/function_calling.py +162 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/base.py +25 -4
- thinkai_framework-0.3.0/thinkai/skill/__init__.py +258 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0/thinkai_framework.egg-info}/PKG-INFO +43 -19
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai_framework.egg-info/SOURCES.txt +3 -0
- thinkai_framework-0.2.2/thinkai/__init__.py +0 -24
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/.env.example +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/LICENSE +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/MANIFEST.in +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/config.example.yaml +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/examples/agent_example.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/examples/basic_usage.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/examples/fastapi_demo.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/examples/rag_example.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/setup.cfg +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/agent/base.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/agent/react.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/agent/tool.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/core/__init__.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/core/client.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/core/config.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/core/models.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/exceptions.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/middleware/__init__.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/middleware/base.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/middleware/logging_middleware.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/middleware/retry_middleware.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/prompt/template.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/__init__.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/claude.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/deepseek.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/gemini.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/ollama.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/openai.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/openai_compatible.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/qwen.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/registry.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/providers/shortcuts.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/rag/__init__.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/rag/chroma_store.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/rag/document_loader.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/rag/pipeline.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/rag/text_splitter.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/rag/vector_store.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/session/__init__.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/session/context.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/session/manager.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/session/memory.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/session/storage.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai/streaming.py +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai_framework.egg-info/dependency_links.txt +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai_framework.egg-info/entry_points.txt +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai_framework.egg-info/requires.txt +0 -0
- {thinkai_framework-0.2.2 → thinkai_framework-0.3.0}/thinkai_framework.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: thinkai-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Enterprise-grade AI framework for seamless LLM integration
|
|
5
5
|
Author-email: ThinkAi Team <thinkai@example.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -60,6 +60,15 @@ Dynamic: license-file
|
|
|
60
60
|
|
|
61
61
|
基于Python异步的企业级AI大模型集成框架 - **开箱即用,简单易用,功能全面**
|
|
62
62
|
|
|
63
|
+
[](https://gitee.com/hongxinge/think-ai)
|
|
64
|
+
[](https://github.com/hongxinge/ThinkAi)
|
|
65
|
+
[](https://pypi.org/project/thinkai-framework/)
|
|
66
|
+
[](LICENSE)
|
|
67
|
+
|
|
68
|
+
- 🏠 Gitee: https://gitee.com/hongxinge/think-ai
|
|
69
|
+
- 🌐 GitHub: https://github.com/hongxinge/ThinkAi
|
|
70
|
+
- 📦 PyPI: https://pypi.org/project/thinkai-framework/
|
|
71
|
+
|
|
63
72
|
## 特性
|
|
64
73
|
|
|
65
74
|
- **轻量零依赖** - 核心框架不依赖任何Web框架,完全脱离FastAPI
|
|
@@ -70,7 +79,8 @@ Dynamic: license-file
|
|
|
70
79
|
- **流式响应** - 支持SSE流式输出
|
|
71
80
|
- **会话管理** - 内置多轮对话上下文管理
|
|
72
81
|
- **RAG支持** - 3行代码实现检索增强生成
|
|
73
|
-
- **Agent系统** - 内置ReAct Agent
|
|
82
|
+
- **Agent系统** - 内置ReAct Agent和Function Calling Agent
|
|
83
|
+
- **Skill系统** - 可复用AI能力包(搜索/代码/数学/文件操作)
|
|
74
84
|
- **中间件管道** - 日志、重试、缓存、限流
|
|
75
85
|
- **企业级性能** - 异步架构,连接池,自动重试
|
|
76
86
|
|
|
@@ -181,33 +191,41 @@ answer = await rag.query("ThinkAi框架支持哪些AI模型?")
|
|
|
181
191
|
print(answer)
|
|
182
192
|
```
|
|
183
193
|
|
|
184
|
-
### 7. Agent(
|
|
194
|
+
### 7. Function Calling Agent(函数调用智能体)
|
|
185
195
|
|
|
186
196
|
```python
|
|
187
197
|
from thinkai import ThinkAI
|
|
188
|
-
from thinkai.agent import
|
|
198
|
+
from thinkai.agent import FunctionCallingAgent
|
|
199
|
+
from thinkai.skill import MathSkill, CodeSkill
|
|
189
200
|
|
|
190
|
-
|
|
191
|
-
@Tool(name="calculator", description="计算数学表达式")
|
|
192
|
-
def calculator(expression: str) -> str:
|
|
193
|
-
return str(eval(expression))
|
|
201
|
+
ai = ThinkAI(provider="openai", api_key="your-key")
|
|
194
202
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
203
|
+
agent = FunctionCallingAgent(
|
|
204
|
+
name="math-coder",
|
|
205
|
+
tools=[MathSkill().get_tools(), CodeSkill().get_tools()],
|
|
206
|
+
ai_client=ai,
|
|
207
|
+
verbose=True,
|
|
208
|
+
)
|
|
199
209
|
|
|
200
|
-
|
|
210
|
+
result = await agent.run("计算123*456,然后用Python写一个斐波那契数列函数")
|
|
211
|
+
print(result)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 8. Skill(技能组合)
|
|
201
215
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
216
|
+
```python
|
|
217
|
+
from thinkai import ThinkAI
|
|
218
|
+
from thinkai.skill import skill_manager, MathSkill, WebSearchSkill
|
|
219
|
+
|
|
220
|
+
ai = ThinkAI(provider="openai", api_key="your-key")
|
|
221
|
+
|
|
222
|
+
agent = skill_manager.create_agent(
|
|
205
223
|
ai_client=ai,
|
|
206
|
-
|
|
224
|
+
skill_names=["math", "code"],
|
|
225
|
+
system_prompt="You are a helpful assistant with math and coding skills.",
|
|
207
226
|
)
|
|
208
227
|
|
|
209
|
-
|
|
210
|
-
result = await agent.run("计算25*48,然后搜索Python的相关信息")
|
|
228
|
+
result = await agent.run("计算2的10次方")
|
|
211
229
|
print(result)
|
|
212
230
|
```
|
|
213
231
|
|
|
@@ -294,6 +312,12 @@ thinkai/
|
|
|
294
312
|
│ ├── middleware/ # 中间件
|
|
295
313
|
│ ├── rag/ # RAG模块
|
|
296
314
|
│ ├── agent/ # Agent模块
|
|
315
|
+
│ │ ├── base.py # Agent基类
|
|
316
|
+
│ │ ├── react.py # ReAct Agent
|
|
317
|
+
│ │ ├── function_calling.py # Function Calling Agent
|
|
318
|
+
│ │ └── tool.py # Tool定义
|
|
319
|
+
│ ├── skill/ # Skill系统
|
|
320
|
+
│ │ ├── __init__.py # Skill基类和内置Skill
|
|
297
321
|
│ ├── streaming.py # 流式处理
|
|
298
322
|
│ └── exceptions.py # 异常定义
|
|
299
323
|
├── examples/ # 示例代码
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
基于Python异步的企业级AI大模型集成框架 - **开箱即用,简单易用,功能全面**
|
|
4
4
|
|
|
5
|
+
[](https://gitee.com/hongxinge/think-ai)
|
|
6
|
+
[](https://github.com/hongxinge/ThinkAi)
|
|
7
|
+
[](https://pypi.org/project/thinkai-framework/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
- 🏠 Gitee: https://gitee.com/hongxinge/think-ai
|
|
11
|
+
- 🌐 GitHub: https://github.com/hongxinge/ThinkAi
|
|
12
|
+
- 📦 PyPI: https://pypi.org/project/thinkai-framework/
|
|
13
|
+
|
|
5
14
|
## 特性
|
|
6
15
|
|
|
7
16
|
- **轻量零依赖** - 核心框架不依赖任何Web框架,完全脱离FastAPI
|
|
@@ -12,7 +21,8 @@
|
|
|
12
21
|
- **流式响应** - 支持SSE流式输出
|
|
13
22
|
- **会话管理** - 内置多轮对话上下文管理
|
|
14
23
|
- **RAG支持** - 3行代码实现检索增强生成
|
|
15
|
-
- **Agent系统** - 内置ReAct Agent
|
|
24
|
+
- **Agent系统** - 内置ReAct Agent和Function Calling Agent
|
|
25
|
+
- **Skill系统** - 可复用AI能力包(搜索/代码/数学/文件操作)
|
|
16
26
|
- **中间件管道** - 日志、重试、缓存、限流
|
|
17
27
|
- **企业级性能** - 异步架构,连接池,自动重试
|
|
18
28
|
|
|
@@ -123,33 +133,41 @@ answer = await rag.query("ThinkAi框架支持哪些AI模型?")
|
|
|
123
133
|
print(answer)
|
|
124
134
|
```
|
|
125
135
|
|
|
126
|
-
### 7. Agent(
|
|
136
|
+
### 7. Function Calling Agent(函数调用智能体)
|
|
127
137
|
|
|
128
138
|
```python
|
|
129
139
|
from thinkai import ThinkAI
|
|
130
|
-
from thinkai.agent import
|
|
140
|
+
from thinkai.agent import FunctionCallingAgent
|
|
141
|
+
from thinkai.skill import MathSkill, CodeSkill
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
@Tool(name="calculator", description="计算数学表达式")
|
|
134
|
-
def calculator(expression: str) -> str:
|
|
135
|
-
return str(eval(expression))
|
|
143
|
+
ai = ThinkAI(provider="openai", api_key="your-key")
|
|
136
144
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
agent = FunctionCallingAgent(
|
|
146
|
+
name="math-coder",
|
|
147
|
+
tools=[MathSkill().get_tools(), CodeSkill().get_tools()],
|
|
148
|
+
ai_client=ai,
|
|
149
|
+
verbose=True,
|
|
150
|
+
)
|
|
141
151
|
|
|
142
|
-
|
|
152
|
+
result = await agent.run("计算123*456,然后用Python写一个斐波那契数列函数")
|
|
153
|
+
print(result)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 8. Skill(技能组合)
|
|
143
157
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
```python
|
|
159
|
+
from thinkai import ThinkAI
|
|
160
|
+
from thinkai.skill import skill_manager, MathSkill, WebSearchSkill
|
|
161
|
+
|
|
162
|
+
ai = ThinkAI(provider="openai", api_key="your-key")
|
|
163
|
+
|
|
164
|
+
agent = skill_manager.create_agent(
|
|
147
165
|
ai_client=ai,
|
|
148
|
-
|
|
166
|
+
skill_names=["math", "code"],
|
|
167
|
+
system_prompt="You are a helpful assistant with math and coding skills.",
|
|
149
168
|
)
|
|
150
169
|
|
|
151
|
-
|
|
152
|
-
result = await agent.run("计算25*48,然后搜索Python的相关信息")
|
|
170
|
+
result = await agent.run("计算2的10次方")
|
|
153
171
|
print(result)
|
|
154
172
|
```
|
|
155
173
|
|
|
@@ -236,6 +254,12 @@ thinkai/
|
|
|
236
254
|
│ ├── middleware/ # 中间件
|
|
237
255
|
│ ├── rag/ # RAG模块
|
|
238
256
|
│ ├── agent/ # Agent模块
|
|
257
|
+
│ │ ├── base.py # Agent基类
|
|
258
|
+
│ │ ├── react.py # ReAct Agent
|
|
259
|
+
│ │ ├── function_calling.py # Function Calling Agent
|
|
260
|
+
│ │ └── tool.py # Tool定义
|
|
261
|
+
│ ├── skill/ # Skill系统
|
|
262
|
+
│ │ ├── __init__.py # Skill基类和内置Skill
|
|
239
263
|
│ ├── streaming.py # 流式处理
|
|
240
264
|
│ └── exceptions.py # 异常定义
|
|
241
265
|
├── examples/ # 示例代码
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"""Function Calling 和 Skill 系统测试"""
|
|
2
|
+
import pytest
|
|
3
|
+
import asyncio
|
|
4
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestFunctionCallingAgent:
|
|
8
|
+
"""Function Calling Agent 测试"""
|
|
9
|
+
|
|
10
|
+
def test_import(self):
|
|
11
|
+
"""测试导入"""
|
|
12
|
+
from thinkai.agent import FunctionCallingAgent
|
|
13
|
+
assert FunctionCallingAgent is not None
|
|
14
|
+
|
|
15
|
+
def test_import_from_thinkai(self):
|
|
16
|
+
"""测试从 thinkai 导入"""
|
|
17
|
+
from thinkai import FunctionCallingAgent
|
|
18
|
+
assert FunctionCallingAgent is not None
|
|
19
|
+
|
|
20
|
+
def test_create_agent(self):
|
|
21
|
+
"""测试创建 Agent"""
|
|
22
|
+
from thinkai.agent import FunctionCallingAgent
|
|
23
|
+
from thinkai.skill import MathSkill
|
|
24
|
+
|
|
25
|
+
agent = FunctionCallingAgent(
|
|
26
|
+
name="test-agent",
|
|
27
|
+
tools=MathSkill().get_tools(),
|
|
28
|
+
verbose=False,
|
|
29
|
+
)
|
|
30
|
+
assert agent.name == "test-agent"
|
|
31
|
+
assert len(agent.tools) == 1
|
|
32
|
+
assert agent.tools[0].name == "calculate"
|
|
33
|
+
|
|
34
|
+
def test_agent_has_ai_client(self):
|
|
35
|
+
"""测试 Agent 带有 ai_client"""
|
|
36
|
+
from thinkai.agent import FunctionCallingAgent
|
|
37
|
+
from thinkai.skill import MathSkill
|
|
38
|
+
from thinkai import ThinkAI
|
|
39
|
+
|
|
40
|
+
ai = ThinkAI(provider="ollama", model="llama3")
|
|
41
|
+
agent = FunctionCallingAgent(
|
|
42
|
+
ai_client=ai,
|
|
43
|
+
tools=MathSkill().get_tools(),
|
|
44
|
+
)
|
|
45
|
+
assert agent.ai_client is ai
|
|
46
|
+
|
|
47
|
+
def test_build_tools_spec(self):
|
|
48
|
+
"""测试构建工具规范"""
|
|
49
|
+
from thinkai.agent import FunctionCallingAgent
|
|
50
|
+
from thinkai.skill import MathSkill
|
|
51
|
+
|
|
52
|
+
agent = FunctionCallingAgent(tools=MathSkill().get_tools())
|
|
53
|
+
tools_spec = agent._build_tools_spec()
|
|
54
|
+
|
|
55
|
+
assert len(tools_spec) == 1
|
|
56
|
+
assert tools_spec[0]["type"] == "function"
|
|
57
|
+
assert tools_spec[0]["function"]["name"] == "calculate"
|
|
58
|
+
assert "description" in tools_spec[0]["function"]
|
|
59
|
+
assert "parameters" in tools_spec[0]["function"]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TestSkillSystem:
|
|
63
|
+
"""Skill 系统测试"""
|
|
64
|
+
|
|
65
|
+
def test_import_skills(self):
|
|
66
|
+
"""测试导入 Skills"""
|
|
67
|
+
from thinkai.skill import Skill, SkillManager
|
|
68
|
+
from thinkai.skill import WebSearchSkill, CodeSkill, MathSkill, FileSkill
|
|
69
|
+
|
|
70
|
+
assert Skill is not None
|
|
71
|
+
assert SkillManager is not None
|
|
72
|
+
assert WebSearchSkill is not None
|
|
73
|
+
assert CodeSkill is not None
|
|
74
|
+
assert MathSkill is not None
|
|
75
|
+
assert FileSkill is not None
|
|
76
|
+
|
|
77
|
+
def test_import_from_thinkai(self):
|
|
78
|
+
"""测试从 thinkai 导入"""
|
|
79
|
+
from thinkai import Skill, SkillManager, skill_manager
|
|
80
|
+
from thinkai import WebSearchSkill, CodeSkill, MathSkill, FileSkill
|
|
81
|
+
|
|
82
|
+
assert Skill is not None
|
|
83
|
+
assert SkillManager is not None
|
|
84
|
+
assert skill_manager is not None
|
|
85
|
+
|
|
86
|
+
def test_web_search_skill(self):
|
|
87
|
+
"""测试 WebSearchSkill"""
|
|
88
|
+
from thinkai.skill import WebSearchSkill
|
|
89
|
+
|
|
90
|
+
skill = WebSearchSkill()
|
|
91
|
+
assert skill.name == "web_search"
|
|
92
|
+
tools = skill.get_tools()
|
|
93
|
+
assert len(tools) == 1
|
|
94
|
+
assert tools[0].name == "web_search"
|
|
95
|
+
|
|
96
|
+
def test_code_skill(self):
|
|
97
|
+
"""测试 CodeSkill"""
|
|
98
|
+
from thinkai.skill import CodeSkill
|
|
99
|
+
|
|
100
|
+
skill = CodeSkill()
|
|
101
|
+
assert skill.name == "code"
|
|
102
|
+
tools = skill.get_tools()
|
|
103
|
+
assert len(tools) == 1
|
|
104
|
+
assert tools[0].name == "execute_python"
|
|
105
|
+
|
|
106
|
+
def test_code_skill_execute(self):
|
|
107
|
+
"""测试 CodeSkill 执行代码"""
|
|
108
|
+
from thinkai.skill import CodeSkill
|
|
109
|
+
import asyncio
|
|
110
|
+
|
|
111
|
+
skill = CodeSkill()
|
|
112
|
+
tools = skill.get_tools()
|
|
113
|
+
|
|
114
|
+
async def test_execute():
|
|
115
|
+
result = await tools[0].execute(code="result = 2 + 3")
|
|
116
|
+
return result
|
|
117
|
+
|
|
118
|
+
result = asyncio.run(test_execute())
|
|
119
|
+
assert "5" in result
|
|
120
|
+
|
|
121
|
+
def test_math_skill(self):
|
|
122
|
+
"""测试 MathSkill"""
|
|
123
|
+
from thinkai.skill import MathSkill
|
|
124
|
+
|
|
125
|
+
skill = MathSkill()
|
|
126
|
+
assert skill.name == "math"
|
|
127
|
+
tools = skill.get_tools()
|
|
128
|
+
assert len(tools) == 1
|
|
129
|
+
assert tools[0].name == "calculate"
|
|
130
|
+
|
|
131
|
+
def test_math_skill_calculate(self):
|
|
132
|
+
"""测试 MathSkill 计算"""
|
|
133
|
+
from thinkai.skill import MathSkill
|
|
134
|
+
import asyncio
|
|
135
|
+
|
|
136
|
+
skill = MathSkill()
|
|
137
|
+
tools = skill.get_tools()
|
|
138
|
+
|
|
139
|
+
async def test_calculate():
|
|
140
|
+
result = await tools[0].execute(expression="2 + 3 * 4")
|
|
141
|
+
return result
|
|
142
|
+
|
|
143
|
+
result = asyncio.run(test_calculate())
|
|
144
|
+
assert result == "14"
|
|
145
|
+
|
|
146
|
+
def test_file_skill(self):
|
|
147
|
+
"""测试 FileSkill"""
|
|
148
|
+
from thinkai.skill import FileSkill
|
|
149
|
+
|
|
150
|
+
skill = FileSkill()
|
|
151
|
+
assert skill.name == "file"
|
|
152
|
+
tools = skill.get_tools()
|
|
153
|
+
assert len(tools) == 2
|
|
154
|
+
tool_names = [t.name for t in tools]
|
|
155
|
+
assert "read_file" in tool_names
|
|
156
|
+
assert "write_file" in tool_names
|
|
157
|
+
|
|
158
|
+
def test_skill_manager(self):
|
|
159
|
+
"""测试 SkillManager"""
|
|
160
|
+
from thinkai.skill import SkillManager, MathSkill
|
|
161
|
+
|
|
162
|
+
manager = SkillManager()
|
|
163
|
+
manager.register(MathSkill())
|
|
164
|
+
|
|
165
|
+
skills = manager.list_skills()
|
|
166
|
+
assert len(skills) == 1
|
|
167
|
+
assert skills[0].name == "math"
|
|
168
|
+
|
|
169
|
+
skill = manager.get("math")
|
|
170
|
+
assert skill is not None
|
|
171
|
+
assert skill.name == "math"
|
|
172
|
+
|
|
173
|
+
def test_skill_manager_get_all_tools(self):
|
|
174
|
+
"""测试 SkillManager 获取所有工具"""
|
|
175
|
+
from thinkai.skill import SkillManager, MathSkill, CodeSkill
|
|
176
|
+
|
|
177
|
+
manager = SkillManager()
|
|
178
|
+
manager.register(MathSkill())
|
|
179
|
+
manager.register(CodeSkill())
|
|
180
|
+
|
|
181
|
+
all_tools = manager.get_all_tools()
|
|
182
|
+
assert len(all_tools) == 2
|
|
183
|
+
tool_names = [t.name for t in all_tools]
|
|
184
|
+
assert "calculate" in tool_names
|
|
185
|
+
assert "execute_python" in tool_names
|
|
186
|
+
|
|
187
|
+
def test_global_skill_manager(self):
|
|
188
|
+
"""测试全局 skill_manager 预注册"""
|
|
189
|
+
from thinkai.skill import skill_manager
|
|
190
|
+
|
|
191
|
+
skills = skill_manager.list_skills()
|
|
192
|
+
skill_names = [s.name for s in skills]
|
|
193
|
+
|
|
194
|
+
assert "web_search" in skill_names
|
|
195
|
+
assert "code" in skill_names
|
|
196
|
+
assert "math" in skill_names
|
|
197
|
+
assert "file" in skill_names
|
|
198
|
+
|
|
199
|
+
def test_skill_get_agent(self):
|
|
200
|
+
"""测试 Skill 创建 Agent"""
|
|
201
|
+
from thinkai.skill import MathSkill
|
|
202
|
+
from thinkai.agent import FunctionCallingAgent
|
|
203
|
+
|
|
204
|
+
skill = MathSkill()
|
|
205
|
+
agent = skill.get_agent()
|
|
206
|
+
|
|
207
|
+
assert isinstance(agent, FunctionCallingAgent)
|
|
208
|
+
assert agent.name == "math-agent"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class TestToolOpenAIFormat:
|
|
212
|
+
"""工具 OpenAI 格式转换测试"""
|
|
213
|
+
|
|
214
|
+
def test_tool_to_openai_format(self):
|
|
215
|
+
"""测试工具转 OpenAI 格式"""
|
|
216
|
+
from thinkai.agent import Tool
|
|
217
|
+
|
|
218
|
+
def dummy_tool_func(x: int, y: str) -> str:
|
|
219
|
+
"""Dummy tool"""
|
|
220
|
+
return y * x
|
|
221
|
+
|
|
222
|
+
tool = Tool(
|
|
223
|
+
name="dummy",
|
|
224
|
+
description="Dummy tool",
|
|
225
|
+
func=dummy_tool_func,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
spec = tool.to_openai_format()
|
|
229
|
+
assert spec["type"] == "function"
|
|
230
|
+
assert spec["function"]["name"] == "dummy"
|
|
231
|
+
assert spec["function"]["description"] == "Dummy tool"
|
|
232
|
+
assert "parameters" in spec["function"]
|
|
233
|
+
|
|
234
|
+
def test_tool_parameters_inference(self):
|
|
235
|
+
"""测试参数推断"""
|
|
236
|
+
from thinkai.agent import Tool
|
|
237
|
+
|
|
238
|
+
def calc(a: int, b: float, c: str) -> str:
|
|
239
|
+
return c
|
|
240
|
+
|
|
241
|
+
tool = Tool(name="calc", description="calc", func=calc)
|
|
242
|
+
params = tool.parameters
|
|
243
|
+
|
|
244
|
+
assert params["properties"]["a"]["type"] == "integer"
|
|
245
|
+
assert params["properties"]["b"]["type"] == "number"
|
|
246
|
+
assert params["properties"]["c"]["type"] == "string"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class TestToolCallsParsing:
|
|
250
|
+
"""Tool Calls 解析测试"""
|
|
251
|
+
|
|
252
|
+
def test_parse_response_with_tool_calls(self):
|
|
253
|
+
"""测试解析带 tool_calls 的响应"""
|
|
254
|
+
from thinkai.providers.base import BaseProvider
|
|
255
|
+
from thinkai.core.models import ToolCall, FunctionCall, ChatMessage
|
|
256
|
+
|
|
257
|
+
response_data = {
|
|
258
|
+
"id": "test-123",
|
|
259
|
+
"model": "gpt-4",
|
|
260
|
+
"choices": [
|
|
261
|
+
{
|
|
262
|
+
"index": 0,
|
|
263
|
+
"message": {
|
|
264
|
+
"role": "assistant",
|
|
265
|
+
"content": None,
|
|
266
|
+
"tool_calls": [
|
|
267
|
+
{
|
|
268
|
+
"id": "call_abc",
|
|
269
|
+
"type": "function",
|
|
270
|
+
"function": {
|
|
271
|
+
"name": "calculate",
|
|
272
|
+
"arguments": '{"expression": "2+3"}',
|
|
273
|
+
},
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
"finish_reason": "tool_calls",
|
|
278
|
+
}
|
|
279
|
+
],
|
|
280
|
+
"usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30},
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
class MockProvider(BaseProvider):
|
|
284
|
+
name = "mock"
|
|
285
|
+
default_model = "mock-model"
|
|
286
|
+
default_api_base = "http://mock.com"
|
|
287
|
+
|
|
288
|
+
async def chat(self, request):
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
async def chat_stream(self, request):
|
|
292
|
+
pass
|
|
293
|
+
|
|
294
|
+
provider = MockProvider()
|
|
295
|
+
parsed = provider._parse_response(response_data)
|
|
296
|
+
|
|
297
|
+
assert parsed.id == "test-123"
|
|
298
|
+
assert len(parsed.choices) == 1
|
|
299
|
+
assert parsed.choices[0].message.tool_calls is not None
|
|
300
|
+
assert len(parsed.choices[0].message.tool_calls) == 1
|
|
301
|
+
assert parsed.choices[0].message.tool_calls[0].function.name == "calculate"
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class TestModelDefinitions:
|
|
305
|
+
"""模型定义测试"""
|
|
306
|
+
|
|
307
|
+
def test_tool_call_model(self):
|
|
308
|
+
"""测试 ToolCall 模型"""
|
|
309
|
+
from thinkai.core.models import ToolCall, FunctionCall
|
|
310
|
+
|
|
311
|
+
tc = ToolCall(
|
|
312
|
+
id="call_123",
|
|
313
|
+
type="function",
|
|
314
|
+
function=FunctionCall(
|
|
315
|
+
name="search",
|
|
316
|
+
arguments='{"query": "test"}',
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
assert tc.id == "call_123"
|
|
321
|
+
assert tc.function.name == "search"
|
|
322
|
+
|
|
323
|
+
def test_chat_message_with_tool_calls(self):
|
|
324
|
+
"""测试带 tool_calls 的 ChatMessage"""
|
|
325
|
+
from thinkai.core.models import ChatMessage, ToolCall, FunctionCall, MessageRole
|
|
326
|
+
|
|
327
|
+
tc = ToolCall(
|
|
328
|
+
id="call_123",
|
|
329
|
+
function=FunctionCall(name="calc", arguments='{"expr": "1+1"}'),
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
msg = ChatMessage.assistant(content=None, tool_calls=[tc])
|
|
333
|
+
|
|
334
|
+
assert msg.role == MessageRole.ASSISTANT
|
|
335
|
+
assert msg.content is None
|
|
336
|
+
assert len(msg.tool_calls) == 1
|
|
337
|
+
|
|
338
|
+
def test_chat_request_with_tools(self):
|
|
339
|
+
"""测试带 tools 的 ChatRequest"""
|
|
340
|
+
from thinkai.core.models import ChatRequest, ChatMessage, Tool, FunctionDefinition
|
|
341
|
+
|
|
342
|
+
tool = Tool(
|
|
343
|
+
type="function",
|
|
344
|
+
function=FunctionDefinition(
|
|
345
|
+
name="calculate",
|
|
346
|
+
description="Calculate",
|
|
347
|
+
parameters={"type": "object", "properties": {}},
|
|
348
|
+
),
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
request = ChatRequest(
|
|
352
|
+
model="gpt-4",
|
|
353
|
+
messages=[ChatMessage.user("1+1=?")],
|
|
354
|
+
tools=[tool],
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
assert request.tools is not None
|
|
358
|
+
assert len(request.tools) == 1
|
|
359
|
+
assert request.tools[0].function.name == "calculate"
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
if __name__ == "__main__":
|
|
363
|
+
pytest.main([__file__, "-v"])
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ThinkAi - Enterprise-grade AI Framework
|
|
3
|
+
基于Python异步的企业级AI大模型集成框架
|
|
4
|
+
开箱即用,支持多模型,RAG,Agent,Skill等核心能力
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "0.3.0"
|
|
8
|
+
__author__ = "ThinkAi Team"
|
|
9
|
+
|
|
10
|
+
from thinkai.core.client import ThinkAI
|
|
11
|
+
from thinkai.core.config import Settings
|
|
12
|
+
from thinkai.session.manager import SessionManager
|
|
13
|
+
from thinkai.prompt.template import PromptTemplate
|
|
14
|
+
from thinkai.rag.pipeline import RAGPipeline
|
|
15
|
+
from thinkai.agent.base import Agent
|
|
16
|
+
from thinkai.agent.react import ReActAgent
|
|
17
|
+
from thinkai.agent.function_calling import FunctionCallingAgent
|
|
18
|
+
from thinkai.agent.tool import Tool, tool
|
|
19
|
+
from thinkai.skill import Skill, SkillManager, skill_manager
|
|
20
|
+
from thinkai.skill import WebSearchSkill, CodeSkill, MathSkill, FileSkill
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"ThinkAI",
|
|
24
|
+
"Settings",
|
|
25
|
+
"SessionManager",
|
|
26
|
+
"PromptTemplate",
|
|
27
|
+
"RAGPipeline",
|
|
28
|
+
"Agent",
|
|
29
|
+
"ReActAgent",
|
|
30
|
+
"FunctionCallingAgent",
|
|
31
|
+
"Tool",
|
|
32
|
+
"tool",
|
|
33
|
+
"Skill",
|
|
34
|
+
"SkillManager",
|
|
35
|
+
"skill_manager",
|
|
36
|
+
"WebSearchSkill",
|
|
37
|
+
"CodeSkill",
|
|
38
|
+
"MathSkill",
|
|
39
|
+
"FileSkill",
|
|
40
|
+
]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from thinkai.agent.base import Agent, AgentConfig
|
|
3
3
|
from thinkai.agent.tool import Tool, tool
|
|
4
4
|
from thinkai.agent.react import ReActAgent
|
|
5
|
+
from thinkai.agent.function_calling import FunctionCallingAgent
|
|
5
6
|
|
|
6
7
|
__all__ = [
|
|
7
8
|
"Agent",
|
|
@@ -9,4 +10,5 @@ __all__ = [
|
|
|
9
10
|
"Tool",
|
|
10
11
|
"tool",
|
|
11
12
|
"ReActAgent",
|
|
13
|
+
"FunctionCallingAgent",
|
|
12
14
|
]
|