ni.agentkit 0.3.1__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.
- agentkit/__init__.py +57 -0
- agentkit/_cli.py +72 -0
- agentkit/agents/__init__.py +0 -0
- agentkit/agents/agent.py +364 -0
- agentkit/agents/base_agent.py +59 -0
- agentkit/agents/orchestrators.py +62 -0
- agentkit/docs/Architecture.md +536 -0
- agentkit/docs/QuickStart.md +806 -0
- agentkit/docs/README.md +119 -0
- agentkit/docs/Reference.md +576 -0
- agentkit/docs/TestReport.md +80 -0
- agentkit/examples/__init__.py +0 -0
- agentkit/examples/ollama/01_basic_chat.py +34 -0
- agentkit/examples/ollama/02_tool_calling.py +70 -0
- agentkit/examples/ollama/03_skill_usage.py +86 -0
- agentkit/examples/ollama/04_multi_agent.py +84 -0
- agentkit/examples/ollama/05_guardrail.py +101 -0
- agentkit/examples/ollama/06_orchestration.py +123 -0
- agentkit/examples/ollama/07_sync_async_stream.py +180 -0
- agentkit/examples/ollama/08_memory.py +201 -0
- agentkit/examples/ollama/README.md +51 -0
- agentkit/examples/ollama/__init__.py +0 -0
- agentkit/examples/quickstart.py +204 -0
- agentkit/examples/standard/01_basic_chat.py +33 -0
- agentkit/examples/standard/02_tool_calling.py +70 -0
- agentkit/examples/standard/03_skill_usage.py +89 -0
- agentkit/examples/standard/04_multi_agent.py +87 -0
- agentkit/examples/standard/05_guardrail.py +104 -0
- agentkit/examples/standard/06_orchestration.py +122 -0
- agentkit/examples/standard/07_sync_async_stream.py +171 -0
- agentkit/examples/standard/08_memory.py +140 -0
- agentkit/examples/standard/README.md +31 -0
- agentkit/examples/standard/__init__.py +0 -0
- agentkit/examples/test_ollama.py +272 -0
- agentkit/llm/__init__.py +0 -0
- agentkit/llm/adapters/__init__.py +0 -0
- agentkit/llm/adapters/anthropic_adapter.py +192 -0
- agentkit/llm/adapters/google_adapter.py +184 -0
- agentkit/llm/adapters/ollama_adapter.py +250 -0
- agentkit/llm/adapters/openai_adapter.py +183 -0
- agentkit/llm/adapters/openai_compatible.py +35 -0
- agentkit/llm/base.py +66 -0
- agentkit/llm/cache.py +121 -0
- agentkit/llm/middleware.py +133 -0
- agentkit/llm/registry.py +138 -0
- agentkit/llm/types.py +191 -0
- agentkit/memory/__init__.py +0 -0
- agentkit/memory/base.py +47 -0
- agentkit/memory/mem0_provider.py +48 -0
- agentkit/runner/__init__.py +0 -0
- agentkit/runner/context.py +47 -0
- agentkit/runner/events.py +36 -0
- agentkit/runner/runner.py +105 -0
- agentkit/safety/__init__.py +0 -0
- agentkit/safety/guardrails.py +55 -0
- agentkit/safety/permissions.py +41 -0
- agentkit/skills/__init__.py +0 -0
- agentkit/skills/loader.py +90 -0
- agentkit/skills/models.py +106 -0
- agentkit/skills/registry.py +48 -0
- agentkit/tools/__init__.py +0 -0
- agentkit/tools/base_tool.py +44 -0
- agentkit/tools/function_tool.py +118 -0
- agentkit/tools/skill_toolset.py +199 -0
- agentkit/utils/__init__.py +0 -0
- agentkit/utils/schema.py +83 -0
- ni_agentkit-0.3.1.dist-info/METADATA +157 -0
- ni_agentkit-0.3.1.dist-info/RECORD +72 -0
- ni_agentkit-0.3.1.dist-info/WHEEL +5 -0
- ni_agentkit-0.3.1.dist-info/entry_points.txt +2 -0
- ni_agentkit-0.3.1.dist-info/licenses/LICENSE +21 -0
- ni_agentkit-0.3.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# AgentKit 架构设计
|
|
2
|
+
|
|
3
|
+
> 本文档介绍 AgentKit 框架的整体架构、分层设计、核心流程和设计决策。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 目录
|
|
8
|
+
|
|
9
|
+
- [设计背景](#设计背景)
|
|
10
|
+
- [设计原则](#设计原则)
|
|
11
|
+
- [六层架构](#六层架构)
|
|
12
|
+
- [核心执行流程](#核心执行流程)
|
|
13
|
+
- [异步执行模型](#异步执行模型)
|
|
14
|
+
- [LLM 适配层设计](#llm-适配层设计)
|
|
15
|
+
- [Skill 三级加载机制](#skill-三级加载机制)
|
|
16
|
+
- [Agent 协作模型](#agent-协作模型)
|
|
17
|
+
- [记忆系统](#记忆系统)
|
|
18
|
+
- [性能优化](#性能优化)
|
|
19
|
+
- [安全机制](#安全机制)
|
|
20
|
+
- [项目目录结构](#项目目录结构)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 设计背景
|
|
25
|
+
|
|
26
|
+
AgentKit 的设计基于对三大主流 Agent 框架源码的深入分析:
|
|
27
|
+
|
|
28
|
+
| 框架 | 借鉴的核心设计 |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| **Google ADK** | 三级渐进式 Skill 加载、SkillToolset 桥接模式、模板方法模式、Agent 树结构 |
|
|
31
|
+
| **OpenAI Agents SDK** | 声明式 Agent 定义、@function_tool 装饰器、Handoff + as_tool 双模式、Guardrail |
|
|
32
|
+
| **Anthropic Claude SDK** | 纯文件即 Skill、description 驱动触发、Hook 机制、权限分层 |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 设计原则
|
|
37
|
+
|
|
38
|
+
| 原则 | 解释 |
|
|
39
|
+
|------|------|
|
|
40
|
+
| **声明式优先** | Agent / Tool / Skill 都是配置对象,而非命令式代码 |
|
|
41
|
+
| **Skill 一等公民** | Skill 不是 Tool 的子集,而是独立的能力抽象层 |
|
|
42
|
+
| **按需加载** | 三级加载模型,避免 token 浪费 |
|
|
43
|
+
| **双协作模式** | 同时支持 Handoff(转介)和 as_tool(委派) |
|
|
44
|
+
| **模型无关** | 自研 LLM 适配层,不绑定特定厂商 |
|
|
45
|
+
| **安全内置** | Guardrail、权限控制不是可选项,而是架构级考虑 |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 六层架构
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
53
|
+
│ 第 1 层:Application(应用层) │
|
|
54
|
+
│ Runner — 驱动 Agent 运行循环 │
|
|
55
|
+
│ RunContext — 运行上下文(session / state / user_id) │
|
|
56
|
+
├──────────────────────────────────────────────────────────────────┤
|
|
57
|
+
│ 第 2 层:Agent(智能体层) │
|
|
58
|
+
│ Agent — 核心 LLM Agent │
|
|
59
|
+
│ SequentialAgent / ParallelAgent / LoopAgent — 编排 Agent │
|
|
60
|
+
│ Handoff — Agent 间控制权转移 │
|
|
61
|
+
├──────────────────────────────────────────────────────────────────┤
|
|
62
|
+
│ 第 3 层:Skill(技能层) │
|
|
63
|
+
│ SkillRegistry — 注册与发现 │
|
|
64
|
+
│ SkillToolset — Skill → Tool 桥接(4 个标准工具) │
|
|
65
|
+
├──────────────────────────────────────────────────────────────────┤
|
|
66
|
+
│ 第 4 层:Tool(工具层) │
|
|
67
|
+
│ FunctionTool / @function_tool — LLM 可调用的工具 │
|
|
68
|
+
│ BaseToolset — 工具集(可动态展开) │
|
|
69
|
+
├──────────────────────────────────────────────────────────────────┤
|
|
70
|
+
│ 第 5 层:Safety(安全层) │
|
|
71
|
+
│ InputGuardrail / OutputGuardrail — 双向安全护栏 │
|
|
72
|
+
│ PermissionPolicy — 三层权限控制 │
|
|
73
|
+
├──────────────────────────────────────────────────────────────────┤
|
|
74
|
+
│ 第 6 层:Foundation(基础设施层) │
|
|
75
|
+
│ LLM 适配层 — 5 个适配器(OpenAI / Anthropic / Google / Ollama / │
|
|
76
|
+
│ 国内兼容),前缀自动路由 │
|
|
77
|
+
│ LLMRegistry — 模型注册中心 │
|
|
78
|
+
│ MemoryProvider — 记忆系统(Mem0 集成) │
|
|
79
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**各层依赖关系**:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
Application → Agent → Skill → Tool → Foundation
|
|
86
|
+
↓ ↓
|
|
87
|
+
Safety Safety
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 核心执行流程
|
|
93
|
+
|
|
94
|
+
当你调用 `Runner.run(agent, input="...")` 时,框架内部的完整流程如下:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
用户输入
|
|
98
|
+
│
|
|
99
|
+
▼
|
|
100
|
+
Runner.run()
|
|
101
|
+
│
|
|
102
|
+
├─ 创建 RunContext
|
|
103
|
+
│
|
|
104
|
+
├─ 检查输入护栏(InputGuardrail)
|
|
105
|
+
│ └─ 如果触发 → 返回错误
|
|
106
|
+
│
|
|
107
|
+
├─ 执行 Agent.run()
|
|
108
|
+
│ │
|
|
109
|
+
│ ├─ ❶ before_agent_callback
|
|
110
|
+
│ │
|
|
111
|
+
│ ├─ Agent._run_impl()(核心循环)
|
|
112
|
+
│ │ │
|
|
113
|
+
│ │ ├─ 构建 instructions
|
|
114
|
+
│ │ │ ├─ 静态字符串 或 动态函数
|
|
115
|
+
│ │ │ ├─ 注入记忆(Memory 检索)
|
|
116
|
+
│ │ │ └─ 注入 Skill 列表(L1 信息)
|
|
117
|
+
│ │ │
|
|
118
|
+
│ │ ├─ 汇总工具
|
|
119
|
+
│ │ │ ├─ tools → FunctionTool
|
|
120
|
+
│ │ │ ├─ skills → SkillToolset(4 个桥接工具)
|
|
121
|
+
│ │ │ └─ handoffs → transfer_to_xxx
|
|
122
|
+
│ │ │
|
|
123
|
+
│ │ ├─ ❷ before_model_callback
|
|
124
|
+
│ │ ├─ 调用 LLM(通过适配器)
|
|
125
|
+
│ │ ├─ ❸ after_model_callback
|
|
126
|
+
│ │ │
|
|
127
|
+
│ │ ├─ 如果 LLM 发生错误:
|
|
128
|
+
│ │ │ └─ ❼ on_error_callback
|
|
129
|
+
│ │ │
|
|
130
|
+
│ │ ├─ 如果 LLM 要调用工具:
|
|
131
|
+
│ │ │ ├─ ❹ before_tool_callback
|
|
132
|
+
│ │ │ ├─ 权限检查(PermissionPolicy)
|
|
133
|
+
│ │ │ ├─ 执行工具
|
|
134
|
+
│ │ │ ├─ ❺ after_tool_callback
|
|
135
|
+
│ │ │ └─ 根据 tool_use_behavior 决定是否再调 LLM
|
|
136
|
+
│ │ │
|
|
137
|
+
│ │ ├─ 如果 LLM 要 handoff:
|
|
138
|
+
│ │ │ └─ 返回 handoff 事件 → Runner 切换 Agent
|
|
139
|
+
│ │ │
|
|
140
|
+
│ │ └─ 如果 LLM 给出最终回复:
|
|
141
|
+
│ │ ├─ 输出最终结果
|
|
142
|
+
│ │ └─ 存储记忆
|
|
143
|
+
│ │
|
|
144
|
+
│ └─ ❻ after_agent_callback
|
|
145
|
+
│
|
|
146
|
+
├─ 检查输出护栏(OutputGuardrail)
|
|
147
|
+
│ └─ 如果触发 → 返回错误
|
|
148
|
+
│
|
|
149
|
+
└─ 返回 RunResult
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**7 个回调点**标记为 ❶ ~ ❼,覆盖了 Agent、Model、Tool 三个层面的前后拦截及错误处理。
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 异步执行模型
|
|
157
|
+
|
|
158
|
+
### 设计原则
|
|
159
|
+
|
|
160
|
+
AgentKit 的**整个执行链都是异步的**——LLM 网络调用、工具执行、记忆检索都是异步 I/O,不阻塞线程。同时提供同步便捷入口,降低上手门槛。
|
|
161
|
+
|
|
162
|
+
### 内部架构
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
Runner.run_sync() ← 同步入口(内部调 asyncio.run)
|
|
166
|
+
│
|
|
167
|
+
▼
|
|
168
|
+
Runner.run() ← 异步核心(async def)
|
|
169
|
+
│
|
|
170
|
+
▼
|
|
171
|
+
Agent.run() ← 异步生成器(async generator,yield Event)
|
|
172
|
+
│
|
|
173
|
+
├─ LLM.generate() ← 异步调用(await)
|
|
174
|
+
├─ Tool.execute() ← 异步执行(await)
|
|
175
|
+
└─ Memory.search() ← 异步检索(await)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 三种运行方式
|
|
179
|
+
|
|
180
|
+
| 方式 | API | 适用场景 |
|
|
181
|
+
|------|-----|---------|
|
|
182
|
+
| **同步** | `Runner.run_sync(agent, input=...)` | 脚本、快速测试、简单场景 |
|
|
183
|
+
| **异步** | `await Runner.run(agent, input=...)` | Web 服务、并发任务、生产环境 |
|
|
184
|
+
| **流式** | `async for event in Runner.run_streamed(agent, input=...)` | 实时展示进度、逐 token 输出 |
|
|
185
|
+
|
|
186
|
+
### 为什么选择异步优先?
|
|
187
|
+
|
|
188
|
+
1. **LLM 调用是 I/O 密集型**:一次 LLM 调用可能耗时几秒到几十秒,异步可以在等待期间处理其他请求
|
|
189
|
+
2. **并行 Agent 需要并发**:`ParallelAgent` 并行执行多个子 Agent,必须用 `asyncio.gather`
|
|
190
|
+
3. **工具可能涉及网络**:调用外部 API、数据库查询等都是异步操作
|
|
191
|
+
4. **`run_sync()` 兜底**:不熟悉异步的用户可以直接用同步入口,零学习成本
|
|
192
|
+
|
|
193
|
+
### 流式运行示例
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
async def main():
|
|
197
|
+
async for event in Runner.run_streamed(agent, input="你好"):
|
|
198
|
+
if event.type == "llm_response":
|
|
199
|
+
print("LLM 思考中...")
|
|
200
|
+
elif event.type == "tool_result":
|
|
201
|
+
print(f"工具调用: {event.data}")
|
|
202
|
+
elif event.type == "final_output":
|
|
203
|
+
print(f"最终回复: {event.data}")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## LLM 适配层设计
|
|
209
|
+
|
|
210
|
+
### 架构
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
Agent / Skill
|
|
214
|
+
│
|
|
215
|
+
LLMRegistry(前缀自动路由)
|
|
216
|
+
│
|
|
217
|
+
BaseLLM(统一抽象接口)
|
|
218
|
+
│
|
|
219
|
+
┌──────────┬──────────┬──────────┬──────────┬────────────┐
|
|
220
|
+
│ OpenAI │Anthropic │ Google │ Ollama │ OpenAI兼容 │
|
|
221
|
+
│ Adapter │ Adapter │ Adapter │ Adapter │ Adapter │
|
|
222
|
+
│ openai │anthropic │google-genai│ aiohttp │ openai SDK │
|
|
223
|
+
│ SDK │ SDK │ SDK │ │+自定义base │
|
|
224
|
+
└────┬─────┘└────┬────┘└─────┬───┘└────┬───┘└──────┬─────┘
|
|
225
|
+
│ │ │ │ │
|
|
226
|
+
OpenAI Anthropic Google Ollama 国内厂商
|
|
227
|
+
API API API 本地API API
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 前缀自动路由规则
|
|
231
|
+
|
|
232
|
+
| 模型标识前缀 | 适配器 |
|
|
233
|
+
|------------|--------|
|
|
234
|
+
| `gpt-`、`o1`、`o3`、`o4` | OpenAIAdapter |
|
|
235
|
+
| `claude-` | AnthropicAdapter |
|
|
236
|
+
| `gemini-` | GoogleAdapter |
|
|
237
|
+
| `ollama/` | OllamaAdapter |
|
|
238
|
+
| `deepseek/`、`qwen/`、`zhipu/`、`moonshot/`、`baichuan/`、`azure/` | OpenAICompatibleAdapter |
|
|
239
|
+
|
|
240
|
+
### 各厂商核心差异
|
|
241
|
+
|
|
242
|
+
| 维度 | OpenAI | Anthropic | Google | Ollama |
|
|
243
|
+
|------|--------|-----------|--------|--------|
|
|
244
|
+
| 工具参数格式 | JSON 字符串 | dict 对象 | dict 对象 | dict 对象 |
|
|
245
|
+
| system 消息 | 在 messages 中 | 单独 system 参数 | 单独 system_instruction | 在 messages 中 |
|
|
246
|
+
| 工具结果角色 | `role: "tool"` | `role: "user"` + tool_result 块 | `role: "user"` + function_response | `role: "tool"` |
|
|
247
|
+
|
|
248
|
+
**所有差异由适配器内部处理,上层代码完全不感知。**
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Skill 三级加载机制
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
256
|
+
│ L1 — 发现层(始终在上下文中) │
|
|
257
|
+
│ name + description,~100 词/Skill │
|
|
258
|
+
│ → LLM 据此判断是否需要使用某个 Skill │
|
|
259
|
+
├─────────────────────────────────────────────────────────────┤
|
|
260
|
+
│ L2 — 指令层(按需加载) │
|
|
261
|
+
│ SKILL.md 正文,详细操作指令 │
|
|
262
|
+
│ → LLM 调用 load_skill 后加载 │
|
|
263
|
+
├─────────────────────────────────────────────────────────────┤
|
|
264
|
+
│ L3 — 资源层(按需加载) │
|
|
265
|
+
│ references/ + assets/ + scripts/ │
|
|
266
|
+
│ → 根据 L2 指令按需读取或执行 │
|
|
267
|
+
└─────────────────────────────────────────────────────────────┘
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### SkillToolset 桥接
|
|
271
|
+
|
|
272
|
+
Skill 通过 SkillToolset 暴露为 4 个 LLM 可调用的标准工具:
|
|
273
|
+
|
|
274
|
+
| 工具 | 对应层级 | 功能 |
|
|
275
|
+
|------|---------|------|
|
|
276
|
+
| `list_skills` | L1 | 列出所有可用 Skill |
|
|
277
|
+
| `load_skill` | L2 | 加载 Skill 的详细操作指令 |
|
|
278
|
+
| `load_skill_resource` | L3 | 读取参考文档 / 资源文件 |
|
|
279
|
+
| `run_skill_script` | L3 | 执行 Skill 中的脚本 |
|
|
280
|
+
|
|
281
|
+
### Skill 与 Agent 的边界
|
|
282
|
+
|
|
283
|
+
| Agent | Skill |
|
|
284
|
+
|-------|-------|
|
|
285
|
+
| ✅ 有自己的 LLM 和对话循环 | ❌ 没有独立对话循环 |
|
|
286
|
+
| ✅ 可以 handoff | ❌ 不能独立被交接 |
|
|
287
|
+
| ✅ 有回调和护栏 | ❌ 借用 Agent 的 |
|
|
288
|
+
| 类比:工程师 | 类比:操作手册 |
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Agent 协作模型
|
|
293
|
+
|
|
294
|
+
### Handoff(转介)
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
Agent A ──[transfer_to_B]──→ Agent B(接管完整对话历史)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
LLM 看到一个名为 `transfer_to_B` 的工具。调用时,Runner 将控制权完全交给 Agent B。
|
|
301
|
+
|
|
302
|
+
### as_tool(委派)
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
Agent A ──[call B.as_tool()]──→ Agent B ──[result]──→ Agent A
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Agent B 被包装成一个 FunctionTool,以嵌套方式执行。完成后结果返回给 Agent A。
|
|
309
|
+
|
|
310
|
+
### 编排 Agent
|
|
311
|
+
|
|
312
|
+
| 编排器 | 行为 |
|
|
313
|
+
|--------|------|
|
|
314
|
+
| `SequentialAgent` | 按顺序执行子 Agent,A → B → C |
|
|
315
|
+
| `ParallelAgent` | 并行执行子 Agent(分支隔离),合并结果 |
|
|
316
|
+
| `LoopAgent` | 循环执行直到某个子 Agent 发出 `escalate` 或达到上限 |
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 记忆系统
|
|
321
|
+
|
|
322
|
+
### 设计原则
|
|
323
|
+
|
|
324
|
+
AgentKit 的记忆系统遵循**可选、可插拔、自动化**三个原则:
|
|
325
|
+
|
|
326
|
+
- **可选**:默认不启用记忆,Agent 是无状态的。需要时通过 `memory=...` 配置
|
|
327
|
+
- **可插拔**:通过 `BaseMemoryProvider` 抽象接口,支持替换不同实现
|
|
328
|
+
- **自动化**:配好后框架自动在对话前检索、对话后存储,不需要额外代码
|
|
329
|
+
|
|
330
|
+
### 自动化流程
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
对话开始
|
|
334
|
+
│
|
|
335
|
+
├─ memory.search(用户输入) ← 自动检索相关记忆
|
|
336
|
+
├─ 将检索结果注入 system prompt ← 作为「相关记忆」章节
|
|
337
|
+
│
|
|
338
|
+
├─ Agent 正常执行(LLM 能看到记忆上下文)
|
|
339
|
+
│
|
|
340
|
+
├─ memory.add(对话内容) ← 自动存储新记忆
|
|
341
|
+
│
|
|
342
|
+
└─ 返回结果
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### 两层实现
|
|
346
|
+
|
|
347
|
+
| 层级 | 类 | 说明 |
|
|
348
|
+
|------|-----|------|
|
|
349
|
+
| **抽象接口** | `BaseMemoryProvider` | 定义 `add/search/get_all/delete` 四个方法 |
|
|
350
|
+
| **内置实现** | `Mem0Provider` | 基于 Mem0,语义搜索 + 持久化(需向量数据库) |
|
|
351
|
+
|
|
352
|
+
用户可自行实现 `BaseMemoryProvider` 创建轻量记忆(如内存字典、SQLite、Redis 等),无需依赖 Mem0。
|
|
353
|
+
|
|
354
|
+
### 多用户隔离
|
|
355
|
+
|
|
356
|
+
通过 `user_id` 参数实现记忆隔离:
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
# 不同用户的记忆互不干扰
|
|
360
|
+
await Runner.run(agent, input="我喜欢咖啡", user_id="user_A")
|
|
361
|
+
await Runner.run(agent, input="我喜欢茶", user_id="user_B")
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## 性能优化
|
|
367
|
+
|
|
368
|
+
AgentKit 内置三项性能优化机制,可按场景组合使用。
|
|
369
|
+
|
|
370
|
+
### 1. Thinking 模式(Ollama)
|
|
371
|
+
|
|
372
|
+
部分模型(如 qwen3.5)支持「深度思考」模式。OllamaAdapter **默认开启** thinking。可以根据实际场景选择关闭。
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
from agentkit.llm.registry import LLMRegistry
|
|
376
|
+
|
|
377
|
+
# 默认开启 thinking
|
|
378
|
+
llm = LLMRegistry.create("ollama/qwen3.5:cloud")
|
|
379
|
+
|
|
380
|
+
# 关闭 thinking(纯对话场景可能更快)
|
|
381
|
+
llm = LLMRegistry.create("ollama/qwen3.5:cloud")
|
|
382
|
+
llm.config.extra_params["think"] = False
|
|
383
|
+
agent = Agent(model=llm, ...)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
> ⚠️ **注意事项**:
|
|
387
|
+
> - cloud 模型的 thinking 本身很快,关闭后工具调用场景可能反而更慢
|
|
388
|
+
> - 本地小模型(如 4b/9b)关闭 thinking 效果更显著(纯对话加速约 2-3 倍)
|
|
389
|
+
> - 建议先测试再决定是否关闭
|
|
390
|
+
|
|
391
|
+
### 2. LLM 响应缓存
|
|
392
|
+
|
|
393
|
+
对相同的输入(messages + tools 组合)缓存 LLM 响应,避免重复调用。使用内存 LRU 缓存,支持 TTL 过期。**默认开启**,缓存绑定 Agent 实例生命周期。
|
|
394
|
+
|
|
395
|
+
```python
|
|
396
|
+
# 默认已开启,无需额外配置
|
|
397
|
+
agent = Agent(model="ollama/qwen3.5:cloud", ...)
|
|
398
|
+
|
|
399
|
+
# 需要关闭时:
|
|
400
|
+
agent = Agent(model="ollama/qwen3.5:cloud", enable_cache=False, ...)
|
|
401
|
+
|
|
402
|
+
# 手动清空缓存:
|
|
403
|
+
agent.clear_cache()
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**实测效果**:相同问题二次调用从秒级降至 **微秒级**。
|
|
407
|
+
|
|
408
|
+
> ⚠️ **注意事项**:
|
|
409
|
+
> - **不缓存工具调用响应**——因为工具结果可能随时间变化(如天气查询),只缓存纯文本回复
|
|
410
|
+
> - 适合 FAQ、重复查询等场景;不适合需要实时信息的场景
|
|
411
|
+
> - 缓存仅在单 Agent 实例内有效,重新创建 Agent 会清空缓存
|
|
412
|
+
> - 默认最大 128 条缓存,LRU 淘汰最久未使用的条目
|
|
413
|
+
|
|
414
|
+
### 3. 记忆异步写入
|
|
415
|
+
|
|
416
|
+
默认情况下,记忆存储采用 fire-and-forget 模式——不等记忆写入完成就立即返回结果,后台异步完成写入。
|
|
417
|
+
|
|
418
|
+
```python
|
|
419
|
+
# 默认:异步写入(更快,适合 Web 服务等对响应时间敏感的场景)
|
|
420
|
+
agent = Agent(memory=my_memory, memory_async_write=True, ...)
|
|
421
|
+
|
|
422
|
+
# 同步写入(等写完再返回,适合多轮串行对话需要即时读取记忆的场景)
|
|
423
|
+
agent = Agent(memory=my_memory, memory_async_write=False, ...)
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
> ⚠️ **注意事项**:
|
|
427
|
+
> - `memory_async_write=True`(默认)时,下一轮对话可能还没读到上一轮刚存的记忆
|
|
428
|
+
> - 多轮串行对话(如示例 08)建议设为 `False`,确保记忆即时可用
|
|
429
|
+
> - Web 服务等并发场景建议保持 `True`,避免慢存储阻塞响应
|
|
430
|
+
|
|
431
|
+
### 三项优化的推荐组合
|
|
432
|
+
|
|
433
|
+
| 场景 | thinking | 缓存 | 记忆写入 |
|
|
434
|
+
|------|---------|------|---------|
|
|
435
|
+
| **Web 服务 / API** | 按需 | ✅ 开启 | 异步(默认) |
|
|
436
|
+
| **多轮聊天** | 保持开启 | ❌ 关闭 | 同步 |
|
|
437
|
+
| **FAQ / 客服** | 关闭 | ✅ 开启 | 异步 |
|
|
438
|
+
| **复杂推理任务** | 保持开启 | ❌ 关闭 | 按需 |
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 安全机制
|
|
443
|
+
|
|
444
|
+
### 三层安全防护
|
|
445
|
+
|
|
446
|
+
```
|
|
447
|
+
┌─────────────────────────────────┐
|
|
448
|
+
│ 第 1 层:Guardrail(输入/输出) │ → 检查用户输入和 Agent 输出
|
|
449
|
+
├─────────────────────────────────┤
|
|
450
|
+
│ 第 2 层:PermissionPolicy │ → 控制哪些工具可被调用
|
|
451
|
+
├─────────────────────────────────┤
|
|
452
|
+
│ 第 3 层:SandboxExecutor │ → Skill 脚本在沙箱中执行
|
|
453
|
+
│ Level 1: 临时目录隔离 │
|
|
454
|
+
│ Level 2: 子进程隔离(默认) │
|
|
455
|
+
│ Level 3: Docker 容器隔离 │
|
|
456
|
+
└─────────────────────────────────┘
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### 关于 Docker:不是必须的
|
|
460
|
+
|
|
461
|
+
> ⚠️ **运行 Agent 不需要 Docker。** AgentKit 是纯 Python 框架,直接在本地 Python 环境即可运行。
|
|
462
|
+
|
|
463
|
+
Docker 仅用于 Skill 脚本沙箱执行的最高安全级别(Level 3)。以下是各场景的依赖说明:
|
|
464
|
+
|
|
465
|
+
| 场景 | 是否需要 Docker |
|
|
466
|
+
|------|:--------------:|
|
|
467
|
+
| 运行 Agent(纯对话) | ❌ |
|
|
468
|
+
| 运行带工具的 Agent(Function Calling) | ❌ |
|
|
469
|
+
| 运行带 Skill 的 Agent(仅指令,无脚本) | ❌ |
|
|
470
|
+
| Skill 脚本执行(Level 1 / Level 2) | ❌ |
|
|
471
|
+
| Skill 脚本执行(Level 3 最高安全) | ✅ |
|
|
472
|
+
|
|
473
|
+
大部分 Skill 只使用「指令 + 工具」组合,完全不涉及脚本执行,因此不需要任何沙箱。
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## 项目目录结构
|
|
478
|
+
|
|
479
|
+
```
|
|
480
|
+
agentkit/
|
|
481
|
+
├── __init__.py # 公共 API 导出(22 个符号)
|
|
482
|
+
├── pyproject.toml # 项目配置
|
|
483
|
+
│
|
|
484
|
+
├── agents/ # Agent 层
|
|
485
|
+
│ ├── base_agent.py # BaseAgent(模板方法基类)
|
|
486
|
+
│ ├── agent.py # Agent(核心 LLM Agent)
|
|
487
|
+
│ └── orchestrators.py # Sequential / Parallel / Loop
|
|
488
|
+
│
|
|
489
|
+
├── tools/ # Tool 层
|
|
490
|
+
│ ├── base_tool.py # BaseTool / BaseToolset
|
|
491
|
+
│ ├── function_tool.py # FunctionTool / @function_tool
|
|
492
|
+
│ └── skill_toolset.py # SkillToolset(4 个桥接工具)
|
|
493
|
+
│
|
|
494
|
+
├── skills/ # Skill 层
|
|
495
|
+
│ ├── models.py # Skill / SkillFrontmatter / SkillResources
|
|
496
|
+
│ ├── loader.py # load_skill_from_dir
|
|
497
|
+
│ └── registry.py # SkillRegistry
|
|
498
|
+
│
|
|
499
|
+
├── llm/ # LLM 适配层
|
|
500
|
+
│ ├── types.py # 统一类型系统
|
|
501
|
+
│ ├── base.py # BaseLLM 抽象接口
|
|
502
|
+
│ ├── registry.py # LLMRegistry(前缀路由)
|
|
503
|
+
│ ├── middleware.py # RetryMiddleware / CostTracker
|
|
504
|
+
│ └── adapters/
|
|
505
|
+
│ ├── openai_adapter.py
|
|
506
|
+
│ ├── anthropic_adapter.py
|
|
507
|
+
│ ├── google_adapter.py
|
|
508
|
+
│ ├── ollama_adapter.py
|
|
509
|
+
│ └── openai_compatible.py
|
|
510
|
+
│
|
|
511
|
+
├── runner/ # Runner 层
|
|
512
|
+
│ ├── runner.py # Runner(核心循环)
|
|
513
|
+
│ ├── context.py # RunContext
|
|
514
|
+
│ └── events.py # Event / RunResult
|
|
515
|
+
│
|
|
516
|
+
├── safety/ # 安全层
|
|
517
|
+
│ ├── guardrails.py # InputGuardrail / OutputGuardrail
|
|
518
|
+
│ └── permissions.py # PermissionPolicy
|
|
519
|
+
│
|
|
520
|
+
├── memory/ # 记忆系统
|
|
521
|
+
│ ├── base.py # BaseMemoryProvider
|
|
522
|
+
│ └── mem0_provider.py # Mem0Provider
|
|
523
|
+
│
|
|
524
|
+
├── utils/
|
|
525
|
+
│ └── schema.py # 函数签名 → JSON Schema
|
|
526
|
+
│
|
|
527
|
+
├── examples/ # 示例
|
|
528
|
+
│ ├── quickstart.py
|
|
529
|
+
│ └── test_ollama.py
|
|
530
|
+
│
|
|
531
|
+
└── docs/ # 文档
|
|
532
|
+
├── README.md
|
|
533
|
+
├── QuickStart.md
|
|
534
|
+
├── Architecture.md
|
|
535
|
+
└── Reference.md
|
|
536
|
+
```
|