thinkai-framework 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.
Files changed (40) hide show
  1. thinkai/__init__.py +24 -0
  2. thinkai/agent/__init__.py +12 -0
  3. thinkai/agent/base.py +83 -0
  4. thinkai/agent/react.py +148 -0
  5. thinkai/agent/tool.py +115 -0
  6. thinkai/core/__init__.py +22 -0
  7. thinkai/core/client.py +397 -0
  8. thinkai/core/config.py +153 -0
  9. thinkai/core/models.py +182 -0
  10. thinkai/exceptions.py +102 -0
  11. thinkai/middleware/__init__.py +11 -0
  12. thinkai/middleware/base.py +63 -0
  13. thinkai/middleware/logging_middleware.py +34 -0
  14. thinkai/middleware/retry_middleware.py +48 -0
  15. thinkai/prompt/template.py +145 -0
  16. thinkai/providers/__init__.py +18 -0
  17. thinkai/providers/base.py +303 -0
  18. thinkai/providers/deepseek.py +109 -0
  19. thinkai/providers/ollama.py +151 -0
  20. thinkai/providers/openai.py +108 -0
  21. thinkai/providers/qwen.py +117 -0
  22. thinkai/providers/registry.py +56 -0
  23. thinkai/rag/__init__.py +14 -0
  24. thinkai/rag/chroma_store.py +68 -0
  25. thinkai/rag/document_loader.py +189 -0
  26. thinkai/rag/pipeline.py +201 -0
  27. thinkai/rag/text_splitter.py +148 -0
  28. thinkai/rag/vector_store.py +27 -0
  29. thinkai/session/__init__.py +12 -0
  30. thinkai/session/context.py +67 -0
  31. thinkai/session/manager.py +96 -0
  32. thinkai/session/memory.py +70 -0
  33. thinkai/session/storage.py +39 -0
  34. thinkai/streaming.py +36 -0
  35. thinkai_framework-0.1.0.dist-info/METADATA +382 -0
  36. thinkai_framework-0.1.0.dist-info/RECORD +40 -0
  37. thinkai_framework-0.1.0.dist-info/WHEEL +5 -0
  38. thinkai_framework-0.1.0.dist-info/entry_points.txt +2 -0
  39. thinkai_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
  40. thinkai_framework-0.1.0.dist-info/top_level.txt +1 -0
thinkai/__init__.py ADDED
@@ -0,0 +1,24 @@
1
+ """
2
+ ThinkAi - Enterprise-grade AI Framework
3
+ 基于FastAPI的企业级AI大模型集成框架
4
+ 开箱即用,支持多模型,RAG,Agent等核心能力
5
+ """
6
+
7
+ __version__ = "0.1.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
+
17
+ __all__ = [
18
+ "ThinkAI",
19
+ "Settings",
20
+ "SessionManager",
21
+ "PromptTemplate",
22
+ "RAGPipeline",
23
+ "Agent",
24
+ ]
@@ -0,0 +1,12 @@
1
+ """Agent模块"""
2
+ from thinkai.agent.base import Agent, AgentConfig
3
+ from thinkai.agent.tool import Tool, tool
4
+ from thinkai.agent.react import ReActAgent
5
+
6
+ __all__ = [
7
+ "Agent",
8
+ "AgentConfig",
9
+ "Tool",
10
+ "tool",
11
+ "ReActAgent",
12
+ ]
thinkai/agent/base.py ADDED
@@ -0,0 +1,83 @@
1
+ """Agent基类"""
2
+ from abc import ABC, abstractmethod
3
+ from typing import List, Optional, Dict, Any
4
+ from pydantic import BaseModel, Field
5
+
6
+ from thinkai.core.client import ThinkAI
7
+ from thinkai.core.models import ChatMessage
8
+ from thinkai.agent.tool import Tool
9
+
10
+
11
+ class AgentConfig(BaseModel):
12
+ """Agent配置"""
13
+ name: str = Field(default="agent", description="Agent名称")
14
+ max_iterations: int = Field(default=10, description="最大迭代次数")
15
+ max_execution_time: int = Field(default=300, description="最大执行时间(秒)")
16
+ verbose: bool = Field(default=False, description="是否输出详细日志")
17
+
18
+
19
+ class Agent(ABC):
20
+ """
21
+ Agent基类
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ name: str = "agent",
27
+ model: Optional[str] = None,
28
+ tools: Optional[List[Tool]] = None,
29
+ max_iterations: int = 10,
30
+ verbose: bool = False,
31
+ ai_client: Optional[ThinkAI] = None,
32
+ **kwargs,
33
+ ):
34
+ self.name = name
35
+ self.model = model
36
+ self.tools = tools or []
37
+ self.max_iterations = max_iterations
38
+ self.verbose = verbose
39
+ self.ai_client = ai_client
40
+ self.extra = kwargs
41
+
42
+ # 注册工具
43
+ self._tool_registry: Dict[str, Tool] = {}
44
+ for tool in self.tools:
45
+ self._tool_registry[tool.name] = tool
46
+
47
+ @abstractmethod
48
+ async def run(self, task: str, **kwargs) -> str:
49
+ """
50
+ 运行Agent
51
+
52
+ Args:
53
+ task: 任务描述
54
+ **kwargs: 额外参数
55
+
56
+ Returns:
57
+ 执行结果
58
+ """
59
+ pass
60
+
61
+ def add_tool(self, tool: Tool):
62
+ """添加工具"""
63
+ self._tool_registry[tool.name] = tool
64
+ self.tools.append(tool)
65
+
66
+ def remove_tool(self, tool_name: str):
67
+ """移除工具"""
68
+ if tool_name in self._tool_registry:
69
+ del self._tool_registry[tool_name]
70
+ self.tools = [t for t in self.tools if t.name != tool_name]
71
+
72
+ def get_tool(self, tool_name: str) -> Optional[Tool]:
73
+ """获取工具"""
74
+ return self._tool_registry.get(tool_name)
75
+
76
+ def list_tools(self) -> List[Tool]:
77
+ """列出所有工具"""
78
+ return list(self._tool_registry.values())
79
+
80
+ def _log(self, message: str):
81
+ """日志输出"""
82
+ if self.verbose:
83
+ print(f"[{self.name}] {message}")
thinkai/agent/react.py ADDED
@@ -0,0 +1,148 @@
1
+ """ReAct Agent - 推理+行动循环"""
2
+ from typing import Optional, List, Dict, Any
3
+ import json
4
+ import re
5
+ from thinkai.core.client import ThinkAI
6
+ from thinkai.core.models import ChatMessage
7
+ from thinkai.agent.base import Agent
8
+ from thinkai.agent.tool import Tool
9
+
10
+
11
+ class ReActAgent(Agent):
12
+ """
13
+ ReAct Agent - 推理(Reasoning)和行动(Acting)交替执行
14
+
15
+ 工作流程:
16
+ 1. 接收任务
17
+ 2. 思考下一步行动
18
+ 3. 调用工具(如果需要)
19
+ 4. 观察结果
20
+ 5. 重复2-4直到完成任务
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ name: str = "react-agent",
26
+ model: Optional[str] = None,
27
+ tools: Optional[List[Tool]] = None,
28
+ max_iterations: int = 10,
29
+ verbose: bool = False,
30
+ ai_client: Optional[ThinkAI] = None,
31
+ ):
32
+ super().__init__(
33
+ name=name,
34
+ model=model,
35
+ tools=tools,
36
+ max_iterations=max_iterations,
37
+ verbose=verbose,
38
+ ai_client=ai_client,
39
+ )
40
+
41
+ async def run(self, task: str, **kwargs) -> str:
42
+ """
43
+ 运行ReAct Agent
44
+
45
+ Args:
46
+ task: 任务描述
47
+ **kwargs: 额外参数
48
+
49
+ Returns:
50
+ 最终结果
51
+ """
52
+ if not self.ai_client:
53
+ raise ValueError("ai_client is required for ReActAgent")
54
+
55
+ # 构建工具描述
56
+ tools_desc = self._format_tools()
57
+
58
+ # 构建系统提示
59
+ system_prompt = f"""You are a helpful AI assistant that can use tools to complete tasks.
60
+
61
+ Available tools:
62
+ {tools_desc}
63
+
64
+ When you need to use a tool, respond with:
65
+ Thought: [your reasoning]
66
+ Action: [tool_name]
67
+ Action Input: [tool input as JSON]
68
+
69
+ After getting the tool result:
70
+ Observation: [tool result]
71
+
72
+ When you have enough information to answer:
73
+ Thought: [your reasoning]
74
+ Final Answer: [your final answer]
75
+
76
+ Remember to think step by step and use tools when needed."""
77
+
78
+ messages = [
79
+ ChatMessage.system(system_prompt),
80
+ ChatMessage.user(task),
81
+ ]
82
+
83
+ iteration = 0
84
+
85
+ while iteration < self.max_iterations:
86
+ iteration += 1
87
+ self._log(f"Iteration {iteration}")
88
+
89
+ # 获取LLM响应
90
+ response = await self.ai_client.chat(
91
+ messages=messages,
92
+ model=self.model,
93
+ )
94
+
95
+ content = response.content or ""
96
+ messages.append(ChatMessage.assistant(content))
97
+
98
+ self._log(f"Response: {content}")
99
+
100
+ # 检查是否有Final Answer
101
+ if "Final Answer:" in content:
102
+ final_answer = content.split("Final Answer:")[-1].strip()
103
+ self._log(f"Final Answer: {final_answer}")
104
+ return final_answer
105
+
106
+ # 解析Action
107
+ action_match = re.search(r"Action:\s*(\w+)", content)
108
+ action_input_match = re.search(r"Action Input:\s*(.+)", content, re.DOTALL)
109
+
110
+ if action_match and action_input_match:
111
+ tool_name = action_match.group(1)
112
+ try:
113
+ tool_input = json.loads(action_input_match.group(1).strip())
114
+ except json.JSONDecodeError:
115
+ tool_input = {"input": action_input_match.group(1).strip()}
116
+
117
+ self._log(f"Calling tool: {tool_name} with {tool_input}")
118
+
119
+ # 执行工具
120
+ tool = self.get_tool(tool_name)
121
+ if not tool:
122
+ observation = f"Error: Tool '{tool_name}' not found"
123
+ else:
124
+ try:
125
+ result = await tool.execute(**tool_input)
126
+ observation = str(result)
127
+ except Exception as e:
128
+ observation = f"Error: {str(e)}"
129
+
130
+ self._log(f"Observation: {observation}")
131
+
132
+ messages.append(ChatMessage.user(f"Observation: {observation}"))
133
+ else:
134
+ # 没有Action,直接返回
135
+ return content
136
+
137
+ return "Error: Max iterations reached"
138
+
139
+ def _format_tools(self) -> str:
140
+ """格式化工具描述"""
141
+ if not self.tools:
142
+ return "No tools available"
143
+
144
+ tools_str = []
145
+ for tool in self.tools:
146
+ tools_str.append(f"- {tool.name}: {tool.description}")
147
+
148
+ return "\n".join(tools_str)
thinkai/agent/tool.py ADDED
@@ -0,0 +1,115 @@
1
+ """工具定义"""
2
+ from typing import Callable, Optional, Dict, Any, List
3
+ import inspect
4
+ import json
5
+ from pydantic import BaseModel
6
+
7
+
8
+ class Tool:
9
+ """
10
+ 工具类 - 封装可被Agent调用的函数
11
+
12
+ 使用示例:
13
+ @tool
14
+ def search(query: str) -> str:
15
+ \"\"\"Search the web\"\"\"
16
+ return "results"
17
+
18
+ 或手动创建:
19
+ tool = Tool(
20
+ name="calculator",
21
+ description="Calculate math expressions",
22
+ func=calculate,
23
+ parameters={...}
24
+ )
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ name: str,
30
+ description: str,
31
+ func: Callable,
32
+ parameters: Optional[Dict[str, Any]] = None,
33
+ ):
34
+ self.name = name
35
+ self.description = description
36
+ self.func = func
37
+ self.parameters = parameters or self._infer_parameters(func)
38
+
39
+ def _infer_parameters(self, func: Callable) -> Dict[str, Any]:
40
+ """从函数签名推断参数schema"""
41
+ sig = inspect.signature(func)
42
+ properties = {}
43
+ required = []
44
+
45
+ for name, param in sig.parameters.items():
46
+ param_type = "string"
47
+ if param.annotation == int:
48
+ param_type = "integer"
49
+ elif param.annotation == float:
50
+ param_type = "number"
51
+ elif param.annotation == bool:
52
+ param_type = "boolean"
53
+ elif param.annotation == list:
54
+ param_type = "array"
55
+
56
+ properties[name] = {
57
+ "type": param_type,
58
+ "description": f"Parameter {name}",
59
+ }
60
+
61
+ if param.default == inspect.Parameter.empty:
62
+ required.append(name)
63
+
64
+ return {
65
+ "type": "object",
66
+ "properties": properties,
67
+ "required": required,
68
+ }
69
+
70
+ async def execute(self, **kwargs) -> Any:
71
+ """执行工具"""
72
+ if inspect.iscoroutinefunction(self.func):
73
+ return await self.func(**kwargs)
74
+ return self.func(**kwargs)
75
+
76
+ def to_openai_format(self) -> Dict[str, Any]:
77
+ """转换为OpenAI工具格式"""
78
+ return {
79
+ "type": "function",
80
+ "function": {
81
+ "name": self.name,
82
+ "description": self.description,
83
+ "parameters": self.parameters,
84
+ },
85
+ }
86
+
87
+ def __repr__(self) -> str:
88
+ return f"Tool(name='{self.name}', description='{self.description}')"
89
+
90
+
91
+ def tool(name: Optional[str] = None, description: Optional[str] = None):
92
+ """
93
+ 工具装饰器
94
+
95
+ 使用示例:
96
+ @tool
97
+ def search(query: str) -> str:
98
+ \"\"\"Search the web\"\"\"
99
+ ...
100
+
101
+ @tool(name="calc", description="Calculate")
102
+ def calculate(expr: str) -> str:
103
+ ...
104
+ """
105
+ def decorator(func: Callable) -> Tool:
106
+ tool_name = name or func.__name__
107
+ tool_desc = description or (func.__doc__ or "").strip()
108
+
109
+ return Tool(
110
+ name=tool_name,
111
+ description=tool_desc,
112
+ func=func,
113
+ )
114
+
115
+ return decorator
@@ -0,0 +1,22 @@
1
+ """核心模块"""
2
+ from thinkai.core.config import Settings
3
+ from thinkai.core.client import ThinkAI
4
+ from thinkai.core.models import (
5
+ ChatMessage,
6
+ ChatRequest,
7
+ ChatResponse,
8
+ ChatChoice,
9
+ Usage,
10
+ MessageRole,
11
+ )
12
+
13
+ __all__ = [
14
+ "Settings",
15
+ "ThinkAI",
16
+ "ChatMessage",
17
+ "ChatRequest",
18
+ "ChatResponse",
19
+ "ChatChoice",
20
+ "Usage",
21
+ "MessageRole",
22
+ ]