knight-agent 1.1.0
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.
- package/Host.d.ts +23 -0
- package/Host.d.ts.map +1 -0
- package/Host.js +23 -0
- package/Host.js.map +1 -0
- package/base/AbstractAgent.d.ts +100 -0
- package/base/AbstractAgent.d.ts.map +1 -0
- package/base/AbstractAgent.js +23 -0
- package/base/AbstractAgent.js.map +1 -0
- package/base/AbstractDialog.d.ts +54 -0
- package/base/AbstractDialog.d.ts.map +1 -0
- package/base/AbstractDialog.js +86 -0
- package/base/AbstractDialog.js.map +1 -0
- package/base/AbstractModule.d.ts +7 -0
- package/base/AbstractModule.d.ts.map +1 -0
- package/base/AbstractModule.js +13 -0
- package/base/AbstractModule.js.map +1 -0
- package/base/AbstractObject.d.ts +18 -0
- package/base/AbstractObject.d.ts.map +1 -0
- package/base/AbstractObject.js +25 -0
- package/base/AbstractObject.js.map +1 -0
- package/base/AbstractReason.d.ts +44 -0
- package/base/AbstractReason.d.ts.map +1 -0
- package/base/AbstractReason.js +23 -0
- package/base/AbstractReason.js.map +1 -0
- package/base/AbstractSkill.d.ts +25 -0
- package/base/AbstractSkill.d.ts.map +1 -0
- package/base/AbstractSkill.js +3 -0
- package/base/AbstractSkill.js.map +1 -0
- package/base/AbstractTool.d.ts +34 -0
- package/base/AbstractTool.d.ts.map +1 -0
- package/base/AbstractTool.js +3 -0
- package/base/AbstractTool.js.map +1 -0
- package/base/index.d.ts +8 -0
- package/base/index.d.ts.map +1 -0
- package/base/index.js +24 -0
- package/base/index.js.map +1 -0
- package/docs/ARCHITECTURE.md +601 -0
- package/docs/README.md +562 -0
- package/index.d.ts +4 -0
- package/index.d.ts.map +1 -0
- package/index.js +25 -0
- package/index.js.map +1 -0
- package/module/AgentModule/Agent.d.ts +55 -0
- package/module/AgentModule/Agent.d.ts.map +1 -0
- package/module/AgentModule/Agent.js +210 -0
- package/module/AgentModule/Agent.js.map +1 -0
- package/module/AgentModule/AgentModule.d.ts +26 -0
- package/module/AgentModule/AgentModule.d.ts.map +1 -0
- package/module/AgentModule/AgentModule.js +66 -0
- package/module/AgentModule/AgentModule.js.map +1 -0
- package/module/AgentModule/Memory.d.ts +55 -0
- package/module/AgentModule/Memory.d.ts.map +1 -0
- package/module/AgentModule/Memory.js +288 -0
- package/module/AgentModule/Memory.js.map +1 -0
- package/module/AgentModule/index.d.ts +2 -0
- package/module/AgentModule/index.d.ts.map +1 -0
- package/module/AgentModule/index.js +18 -0
- package/module/AgentModule/index.js.map +1 -0
- package/module/DialogModule/Dialog.d.ts +14 -0
- package/module/DialogModule/Dialog.d.ts.map +1 -0
- package/module/DialogModule/Dialog.js +27 -0
- package/module/DialogModule/Dialog.js.map +1 -0
- package/module/DialogModule/DialogModule.d.ts +39 -0
- package/module/DialogModule/DialogModule.d.ts.map +1 -0
- package/module/DialogModule/DialogModule.js +118 -0
- package/module/DialogModule/DialogModule.js.map +1 -0
- package/module/DialogModule/index.d.ts +3 -0
- package/module/DialogModule/index.d.ts.map +1 -0
- package/module/DialogModule/index.js +19 -0
- package/module/DialogModule/index.js.map +1 -0
- package/module/ReasonModule/ChainReason.d.ts +11 -0
- package/module/ReasonModule/ChainReason.d.ts.map +1 -0
- package/module/ReasonModule/ChainReason.js +34 -0
- package/module/ReasonModule/ChainReason.js.map +1 -0
- package/module/ReasonModule/CommanderReason.d.ts +15 -0
- package/module/ReasonModule/CommanderReason.d.ts.map +1 -0
- package/module/ReasonModule/CommanderReason.js +151 -0
- package/module/ReasonModule/CommanderReason.js.map +1 -0
- package/module/ReasonModule/CompetitiveReason.d.ts +13 -0
- package/module/ReasonModule/CompetitiveReason.d.ts.map +1 -0
- package/module/ReasonModule/CompetitiveReason.js +133 -0
- package/module/ReasonModule/CompetitiveReason.js.map +1 -0
- package/module/ReasonModule/PlanReason.d.ts +25 -0
- package/module/ReasonModule/PlanReason.d.ts.map +1 -0
- package/module/ReasonModule/PlanReason.js +133 -0
- package/module/ReasonModule/PlanReason.js.map +1 -0
- package/module/ReasonModule/ReasonModule.d.ts +41 -0
- package/module/ReasonModule/ReasonModule.d.ts.map +1 -0
- package/module/ReasonModule/ReasonModule.js +83 -0
- package/module/ReasonModule/ReasonModule.js.map +1 -0
- package/module/ReasonModule/ReflectReason.d.ts +15 -0
- package/module/ReasonModule/ReflectReason.d.ts.map +1 -0
- package/module/ReasonModule/ReflectReason.js +86 -0
- package/module/ReasonModule/ReflectReason.js.map +1 -0
- package/module/ReasonModule/TreeReason.d.ts +16 -0
- package/module/ReasonModule/TreeReason.d.ts.map +1 -0
- package/module/ReasonModule/TreeReason.js +139 -0
- package/module/ReasonModule/TreeReason.js.map +1 -0
- package/module/ReasonModule/index.d.ts +8 -0
- package/module/ReasonModule/index.d.ts.map +1 -0
- package/module/ReasonModule/index.js +24 -0
- package/module/ReasonModule/index.js.map +1 -0
- package/module/SkillModule/SkillModule.d.ts +42 -0
- package/module/SkillModule/SkillModule.d.ts.map +1 -0
- package/module/SkillModule/SkillModule.js +134 -0
- package/module/SkillModule/SkillModule.js.map +1 -0
- package/module/SkillModule/index.d.ts +2 -0
- package/module/SkillModule/index.d.ts.map +1 -0
- package/module/SkillModule/index.js +18 -0
- package/module/SkillModule/index.js.map +1 -0
- package/module/ToolModule/ToolModule.d.ts +57 -0
- package/module/ToolModule/ToolModule.d.ts.map +1 -0
- package/module/ToolModule/ToolModule.js +220 -0
- package/module/ToolModule/ToolModule.js.map +1 -0
- package/module/ToolModule/ToolRAG.d.ts +38 -0
- package/module/ToolModule/ToolRAG.d.ts.map +1 -0
- package/module/ToolModule/ToolRAG.js +124 -0
- package/module/ToolModule/ToolRAG.js.map +1 -0
- package/module/ToolModule/index.d.ts +3 -0
- package/module/ToolModule/index.d.ts.map +1 -0
- package/module/ToolModule/index.js +19 -0
- package/module/ToolModule/index.js.map +1 -0
- package/module/index.d.ts +6 -0
- package/module/index.d.ts.map +1 -0
- package/module/index.js +22 -0
- package/module/index.js.map +1 -0
- package/package.json +19 -0
- package/utility/InterfaceUtility.d.ts +14 -0
- package/utility/InterfaceUtility.d.ts.map +1 -0
- package/utility/InterfaceUtility.js +3 -0
- package/utility/InterfaceUtility.js.map +1 -0
- package/utility/LogUtility.d.ts +41 -0
- package/utility/LogUtility.d.ts.map +1 -0
- package/utility/LogUtility.js +70 -0
- package/utility/LogUtility.js.map +1 -0
- package/utility/NetworkUtility.d.ts +91 -0
- package/utility/NetworkUtility.d.ts.map +1 -0
- package/utility/NetworkUtility.js +104 -0
- package/utility/NetworkUtility.js.map +1 -0
- package/utility/ObjectUtility.d.ts +134 -0
- package/utility/ObjectUtility.d.ts.map +1 -0
- package/utility/ObjectUtility.js +313 -0
- package/utility/ObjectUtility.js.map +1 -0
- package/utility/OpenAIUtility.d.ts +333 -0
- package/utility/OpenAIUtility.d.ts.map +1 -0
- package/utility/OpenAIUtility.js +95 -0
- package/utility/OpenAIUtility.js.map +1 -0
- package/utility/PromiseUtility.d.ts +9 -0
- package/utility/PromiseUtility.d.ts.map +1 -0
- package/utility/PromiseUtility.js +16 -0
- package/utility/PromiseUtility.js.map +1 -0
- package/utility/StringUtility.d.ts +10 -0
- package/utility/StringUtility.d.ts.map +1 -0
- package/utility/StringUtility.js +42 -0
- package/utility/StringUtility.js.map +1 -0
- package/utility/TimeUtility.d.ts +10 -0
- package/utility/TimeUtility.d.ts.map +1 -0
- package/utility/TimeUtility.js +24 -0
- package/utility/TimeUtility.js.map +1 -0
- package/utility/index.d.ts +9 -0
- package/utility/index.d.ts.map +1 -0
- package/utility/index.js +25 -0
- package/utility/index.js.map +1 -0
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
# Knight Agent 2.0 — 技术架构手册
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
- [一、架构全景图](#一架构全景图)
|
|
8
|
+
- [二、分层设计](#二分层设计)
|
|
9
|
+
- [三、模块详细设计](#三模块详细设计)
|
|
10
|
+
- [四、执行路径](#四执行路径)
|
|
11
|
+
- [五、Token 优化管线](#五token-优化管线)
|
|
12
|
+
- [六、设计决策记录](#六设计决策记录)
|
|
13
|
+
- [七、持久化模型](#七持久化模型)
|
|
14
|
+
- [八、扩展点](#八扩展点)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 一、架构全景图
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
22
|
+
│ 业务层 (Business Layer) │
|
|
23
|
+
│ 注册工具/技能 → 创建对话 → 启用技能 → dialog.send("...") │
|
|
24
|
+
└────────────────────────────────┬────────────────────────────────┘
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ Host (单例 — src/Host.ts) │
|
|
29
|
+
│ │
|
|
30
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
31
|
+
│ │ AgentModule │ │ ToolModule │ │ SkillModule │ │
|
|
32
|
+
│ │ (创建/销毁) │ │ (注册/执行/ │ │ (能力包/对话 │ │
|
|
33
|
+
│ │ Agent 池 │ │ 缓存/RAG) │ │ 级启用禁用) │ │
|
|
34
|
+
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
35
|
+
│ │ │ │ │
|
|
36
|
+
│ ┌──────┴───────┐ │ │ │
|
|
37
|
+
│ │ DialogModule │ │ │ │
|
|
38
|
+
│ │ (对话池/快照) │────────┼────────────────┘ │
|
|
39
|
+
│ └──────┬───────┘ │ │
|
|
40
|
+
│ │ │ │
|
|
41
|
+
│ ┌──────┴────────────────┴───────┐ │
|
|
42
|
+
│ │ ReasonModule │ │
|
|
43
|
+
│ │ (6种推理策略池/执行入口) │ │
|
|
44
|
+
│ │ Chain → Reflect → Tree │ │
|
|
45
|
+
│ │ → Plan → Competitive → Cmd │ │
|
|
46
|
+
│ └───────────────────────────────┘ │
|
|
47
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
48
|
+
│
|
|
49
|
+
▼
|
|
50
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
51
|
+
│ 基础设施层 (Base Layer — src/base/) │
|
|
52
|
+
│ │
|
|
53
|
+
│ AbstractObject ←── 全局ID + 对象池 + Host引用 │
|
|
54
|
+
│ │ │
|
|
55
|
+
│ ├── AbstractModule ←── 模块基类 │
|
|
56
|
+
│ ├── AbstractAgent ←── run()/send()/executeTool/snapshot │
|
|
57
|
+
│ ├── AbstractReason ←── execute()/buildRunOptions() │
|
|
58
|
+
│ ├── AbstractDialog ←── send()/switchStrategy()/snapshot() │
|
|
59
|
+
│ ├── AbstractTool ←── ToolDefinition/ToolContext 接口 │
|
|
60
|
+
│ └── AbstractSkill ←── Skill/SkillConstraints 接口 │
|
|
61
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
62
|
+
│
|
|
63
|
+
▼
|
|
64
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
65
|
+
│ 实现层 (Module Layer — src/module/) │
|
|
66
|
+
│ │
|
|
67
|
+
│ AgentModule/Agent.ts — Agent 实例 + ReAct 循环 │
|
|
68
|
+
│ AgentModule/Memory.ts — 消息缓存 + Token计数 + 3级压缩 │
|
|
69
|
+
│ ToolModule/ToolModule.ts — 工具注册表 + 缓存+重试+Compact Schema │
|
|
70
|
+
│ ToolModule/ToolRAG.ts — 语义检索 (关键词/Embedding) │
|
|
71
|
+
│ SkillModule/SkillModule.ts — 技能注册 + 通配展开 + Prompt聚合 │
|
|
72
|
+
│ DialogModule/Dialog.ts — 对话实例 (内部创建Agent) │
|
|
73
|
+
│ DialogModule/DialogModule.ts — 对话池 + 快照导入导出 │
|
|
74
|
+
│ ReasonModule/ReasonModule.ts — 策略注册 + 一次性执行入口 │
|
|
75
|
+
│ ReasonModule/*.ts — 6 个推理策略实现 │
|
|
76
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
77
|
+
│
|
|
78
|
+
▼
|
|
79
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
80
|
+
│ 工具层 (Utility — src/utility/) │
|
|
81
|
+
│ OpenAIUtility NetworkUtility LogUtility ObjectUtility │
|
|
82
|
+
│ StringUtility TimeUtility PromiseUtility InterfaceUtility │
|
|
83
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 文件依赖关系
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
src/
|
|
90
|
+
├── index.ts → 统一导出 (Host + modules)
|
|
91
|
+
├── Host.ts → 单例,组装5个模块
|
|
92
|
+
├── base/ → 抽象层 (6个文件, 仅接口+抽象类)
|
|
93
|
+
│ ├── AbstractObject.ts → 全局ID + 对象池
|
|
94
|
+
│ ├── AbstractModule.ts → 模块标识
|
|
95
|
+
│ ├── AbstractAgent.ts → Agent 抽象 (run/snapshot/restore)
|
|
96
|
+
│ ├── AbstractReason.ts → 推理抽象 (execute/buildRunOptions)
|
|
97
|
+
│ ├── AbstractDialog.ts → 对话抽象 (send/switchStrategy)
|
|
98
|
+
│ ├── AbstractTool.ts → ToolDefinition + ToolContext 接口
|
|
99
|
+
│ └── AbstractSkill.ts → Skill + SkillConstraints 接口
|
|
100
|
+
├── module/ → 实现层 (10个文件)
|
|
101
|
+
│ ├── AgentModule/
|
|
102
|
+
│ │ ├── AgentModule.ts → Agent 池管理
|
|
103
|
+
│ │ ├── Agent.ts → Agent 实现 (ReAct循环)
|
|
104
|
+
│ │ └── Memory.ts → 记忆管理 (Token计数+压缩)
|
|
105
|
+
│ ├── ToolModule/
|
|
106
|
+
│ │ ├── ToolModule.ts → 工具注册表+执行调度
|
|
107
|
+
│ │ └── ToolRAG.ts → 语义检索
|
|
108
|
+
│ ├── SkillModule/
|
|
109
|
+
│ │ └── SkillModule.ts → 技能管理
|
|
110
|
+
│ ├── DialogModule/
|
|
111
|
+
│ │ ├── DialogModule.ts → 对话池+快照
|
|
112
|
+
│ │ └── Dialog.ts → 对话实例
|
|
113
|
+
│ └── ReasonModule/
|
|
114
|
+
│ ├── ReasonModule.ts → 策略池+执行入口
|
|
115
|
+
│ ├── ChainReason.ts → 链式推理
|
|
116
|
+
│ ├── ReflectReason.ts → 反思推理
|
|
117
|
+
│ ├── TreeReason.ts → 思维树推理
|
|
118
|
+
│ ├── PlanReason.ts → 计划执行推理
|
|
119
|
+
│ ├── CompetitiveReason.ts → 竞争推理
|
|
120
|
+
│ └── CommanderReason.ts → 指挥调度推理
|
|
121
|
+
└── utility/ → 工具函数层 (8个文件)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 二、分层设计
|
|
127
|
+
|
|
128
|
+
### 2.1 基础抽象层 (src/base/)
|
|
129
|
+
|
|
130
|
+
所有对外接口和抽象类统一在 `src/base/` 定义。实现层 (src/module/) 负责具体逻辑,业务层仅依赖抽象层。
|
|
131
|
+
|
|
132
|
+
**设计原则**:
|
|
133
|
+
- **接口优先**: ToolDefinition、Skill、AgentConfig 等均为 interface,业务层无实现依赖
|
|
134
|
+
- **抽象方法**: AbstractAgent/AbstractReason/AbstractDialog 定义核心契约,实现类填充细节
|
|
135
|
+
- **单向依赖**: 实现层引用抽象层,抽象层不可引用实现层
|
|
136
|
+
|
|
137
|
+
### 2.2 模块体系 (AbstractModule)
|
|
138
|
+
|
|
139
|
+
所有功能模块继承 `AbstractModule → AbstractObject`:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
AbstractObject
|
|
143
|
+
├── .id: string // GUID 自动分配
|
|
144
|
+
├── .key: string // 类名
|
|
145
|
+
├── .host: Host // 向上访问 Host 单例
|
|
146
|
+
└── static objects: MapPool<AbstractObject> // 全局对象池
|
|
147
|
+
|
|
148
|
+
AbstractModule extends AbstractObject
|
|
149
|
+
// 模块标识,当前无额外成员
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
任何 `AbstractObject` 子类都可以通过 `this.host` 访问所有模块,无需依赖注入。
|
|
153
|
+
|
|
154
|
+
### 2.3 单例 Host
|
|
155
|
+
|
|
156
|
+
`Host` 是唯一的组装点,创建并持有 5 个模块实例。模块之间通过 `this.host` 互相访问,形成星型拓扑:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
┌───────┐
|
|
160
|
+
│ Host │
|
|
161
|
+
└──┬────┘
|
|
162
|
+
┌──────────┼──────────────┐
|
|
163
|
+
│ │ │
|
|
164
|
+
AgentModule ToolModule SkillModule
|
|
165
|
+
│ │ │
|
|
166
|
+
└──────────┼──────────────┘
|
|
167
|
+
│
|
|
168
|
+
ReasonModule
|
|
169
|
+
│
|
|
170
|
+
DialogModule
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 三、模块详细设计
|
|
176
|
+
|
|
177
|
+
### 3.1 AgentModule — 智能体生命周期
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
AgentModule
|
|
181
|
+
├── createAgent(config) → Agent // 创建 + 注入 systemPrompt
|
|
182
|
+
├── destroyAgent(id) // 销毁 + 清理 Memory
|
|
183
|
+
├── destroyAll() // 批量销毁
|
|
184
|
+
├── getAgent(id) → Agent? // 查询
|
|
185
|
+
└── getAllAgents() → Agent[] // 全量
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Agent 内部结构**:
|
|
189
|
+
```
|
|
190
|
+
Agent extends AbstractAgent
|
|
191
|
+
├── config: AgentConfig // 配置副本
|
|
192
|
+
├── memory: Memory // 消息缓存 + Token管理
|
|
193
|
+
├── state: AgentState // Idle/Thinking/Running/WaitingTool/Error/Done
|
|
194
|
+
├── turnCount: number // 对话轮次
|
|
195
|
+
├── sendUserMessage(content) // 缓存用户消息 → 发送 → 缓存回复
|
|
196
|
+
├── sendRequest() // 直接发送当前缓存
|
|
197
|
+
├── executeTool(toolCall) → result // 委托给 ToolModule.Execute()
|
|
198
|
+
├── addToolResult(result, callId) // 添加工具结果到缓存
|
|
199
|
+
├── run(input, options?) → AgentRunResult // ReAct 主循环
|
|
200
|
+
├── snapshot() → AgentSnapshot // 导出
|
|
201
|
+
└── restore(snapshot) // 恢复
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**ReAct 主循环 (Agent.run)**:
|
|
205
|
+
```
|
|
206
|
+
1. sendUserMessage(input) → 发送用户消息
|
|
207
|
+
2. if no response → Error
|
|
208
|
+
3. while finish_reason == "tool_calls":
|
|
209
|
+
a. for each tool_call: executeTool → addToolResult
|
|
210
|
+
b. sendRequest() → 提交工具结果继续
|
|
211
|
+
c. addAssistantMessage(...) → 缓存 assistant 消息
|
|
212
|
+
4. return final result
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 3.2 Memory — 记忆管理
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
Memory
|
|
219
|
+
├── messages: Message // OpenAI 格式消息队列
|
|
220
|
+
├── scratchpad: string // 思维草稿区
|
|
221
|
+
├── toolResults: Map<id, result> // 工具结果缓存
|
|
222
|
+
├── estimateTokens() → number // tiktoken 精确计数
|
|
223
|
+
├── checkPressure() → MemoryPressure // 压力检测
|
|
224
|
+
├── optimize(level) // 分级压缩
|
|
225
|
+
├── summarize(msgs) → string // LLM 摘要
|
|
226
|
+
└── extractEntities(msgs) → {} // LLM 实体提取
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**MemoryPressure 压缩策略**:
|
|
230
|
+
|
|
231
|
+
| 级别 | 算法 | 描述 |
|
|
232
|
+
|------|------|------|
|
|
233
|
+
| Mild | 早期摘要 | 前 30% 非系统消息 → 1 次 LLM 调用生成摘要,替换原文 |
|
|
234
|
+
| Moderate | 5层裁剪 | 系统消息 + 远期实体提取 + 中间摘要 + 保留最近 6 轮 + 工具配对 |
|
|
235
|
+
| Critical | 激进裁剪 | 保留最近 3 轮 + 工具配对 + 其余拼接为纯文本摘要 (无 LLM 调用) |
|
|
236
|
+
|
|
237
|
+
### 3.3 ToolModule — 工具管理
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
ToolModule
|
|
241
|
+
├── register(tool) // 单个注册 + RAG 索引
|
|
242
|
+
├── registerAll(tools) // 批量注册
|
|
243
|
+
├── unregister(name) // 移除 + 清缓存 + 去索引
|
|
244
|
+
├── get(name) → ToolDefinition? // 查询
|
|
245
|
+
├── list() → ToolDefinition[] // 全量
|
|
246
|
+
├── listByCategory(cat) → [] // 按分类
|
|
247
|
+
├── selectTools(query, candidates?, topK) → string[] // RAG 排序
|
|
248
|
+
├── ToAPITools(names?, compact?) → ToolCall[] // 导出 OpenAI 格式
|
|
249
|
+
├── Execute(toolCall, ctx) → string // 执行 (含缓存+重试)
|
|
250
|
+
├── ExecuteBatch(toolCalls, ctx) → Map // 批量 (自动分组并行/串行)
|
|
251
|
+
├── invalidateCache(name?) // 缓存管理
|
|
252
|
+
├── clear() // 清空
|
|
253
|
+
└── setEmbeddingProvider(provider) // 设置 Embedding
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**工具执行流程 (ToolModule.Execute)**:
|
|
257
|
+
```
|
|
258
|
+
1. 查找工具定义
|
|
259
|
+
2. 解析 arguments JSON
|
|
260
|
+
3. 如果 cacheable: 检查缓存 → 命中则返回
|
|
261
|
+
4. 执行 handler(args)
|
|
262
|
+
- 失败 → 如果 retryable: 等待 delay → 重试 (最多 maxRetries 次)
|
|
263
|
+
5. 如果 cacheable: 写入缓存
|
|
264
|
+
6. 返回结果字符串
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Compact Schema (stripSchema)**:
|
|
268
|
+
递归裁剪 `description` 和 `default`,仅保留核心结构字段:
|
|
269
|
+
```
|
|
270
|
+
保留: type, enum, required, properties, items
|
|
271
|
+
移除: description, default
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 3.4 ToolRAG — 工具语义检索
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
ToolRAG
|
|
278
|
+
├── _provider: IEmbeddingProvider? // 可插拔 Embedding 提供者
|
|
279
|
+
├── _index: Map<name, vector> // 向量索引 (仅 Embedding 模式)
|
|
280
|
+
├── setProvider(p) // 设置后触发重建索引
|
|
281
|
+
├── index(name, desc) // 索引入库
|
|
282
|
+
├── remove(name) // 移除索引
|
|
283
|
+
└── search(query, candidates, topK) → string[]
|
|
284
|
+
├── 有 provider → _semanticSearch() (余弦相似度)
|
|
285
|
+
└── 无 provider → _keywordSearch() (中文1-2字滑动窗口 + 英文词匹配)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**选型理由**: 默认关键词匹配零依赖,避免引入 ML 依赖。IEmbeddingProvider 接口允许业务层按需接入任意 Embedding 服务。
|
|
289
|
+
|
|
290
|
+
### 3.5 SkillModule — 技能管理
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
SkillModule
|
|
294
|
+
├── register(skill) // 注册技能定义
|
|
295
|
+
├── unregister(name) // 移除 + 清理所有对话绑定
|
|
296
|
+
├── get / list / listByCategory // 查询
|
|
297
|
+
├── enable(dialogId, skillName) // 对话级启用
|
|
298
|
+
├── disable(dialogId, skillName) // 对话级禁用
|
|
299
|
+
├── getEnabled(dialogId) → string[] // 获取启用列表
|
|
300
|
+
├── resolveTools(dialogId) → ToolDefinition[] // 解析可用工具 (展开通配符)
|
|
301
|
+
├── buildPrompt(dialogId) → string // 聚合 systemPrompt
|
|
302
|
+
└── clearDialog(dialogId) // 清理
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**resolveTools 通配符展开逻辑**:
|
|
306
|
+
```
|
|
307
|
+
输入: skill.tools = ["pc/*", "web/search"]
|
|
308
|
+
1. "pc/*" → 遍历 ToolModule 全部工具名, 匹配 "pc/" 前缀
|
|
309
|
+
2. "web/search" → 精确查找
|
|
310
|
+
输出: [ToolDefinition(pc/screenshot), ToolDefinition(pc/clipboard), ToolDefinition(web/search)]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 3.6 ReasonModule — 推理策略
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
ReasonModule
|
|
317
|
+
├── _reasons: MapPool<AbstractReason> // 策略池 (6个内置 + 可扩展)
|
|
318
|
+
├── register(name, reason) // 注册自定义策略
|
|
319
|
+
├── get(name) → AbstractReason? // 获取实例
|
|
320
|
+
├── execute(input, config, strategy) → ReasonResult // 一次性执行入口
|
|
321
|
+
└── list() → [{name, type}]
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**策略内部对 useAgent 的处理**:
|
|
325
|
+
```
|
|
326
|
+
单 Agent 策略 (Chain/Reflect/Tree/Plan):
|
|
327
|
+
agent = config.useAgent ?? createAgent(config.baseConfig)
|
|
328
|
+
try: agent.run(input, runOptions)
|
|
329
|
+
finally: if (!config.useAgent) destroyAgent(agent)
|
|
330
|
+
|
|
331
|
+
多 Agent 策略 (Competitive/Commander):
|
|
332
|
+
主Agent(裁判/指挥) = config.useAgent ?? createAgent(...)
|
|
333
|
+
临时Agent(竞争者/工人) = createAgent(...) → 自动销毁
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 3.7 DialogModule — 对话管理
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
DialogModule
|
|
340
|
+
├── _dialogs: MapPool<Dialog> // 对话池
|
|
341
|
+
├── create(title, config, strategy?) → Dialog
|
|
342
|
+
├── destroy(dialogId) // 委托 Dialog.destroy()
|
|
343
|
+
├── get(dialogId) → Dialog?
|
|
344
|
+
├── list() → [{dialogId, title, strategy}]
|
|
345
|
+
├── export(dialogId) → DialogSnapshot? // 导出快照
|
|
346
|
+
└── import(snapshot, config) → Dialog? // 恢复 (需重新提供 apiKey)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 四、执行路径
|
|
352
|
+
|
|
353
|
+
### 路径一: 一次性推理
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
ReasonModule.execute(input, config, strategy)
|
|
357
|
+
│
|
|
358
|
+
├── 查找策略: _reasons.Get(strategy)
|
|
359
|
+
├── reason.execute(input, config)
|
|
360
|
+
│ ├── 创建 Agent: agentModule.createAgent(config.baseConfig)
|
|
361
|
+
│ ├── agent.run(input, buildRunOptions(config))
|
|
362
|
+
│ │ ├── sendUserMessage → OnSendRequest
|
|
363
|
+
│ │ │ ├── memory.checkPressure() → optimize()
|
|
364
|
+
│ │ │ ├── ToAPITools(names, compact=true)
|
|
365
|
+
│ │ │ └── HTTP POST → LLM
|
|
366
|
+
│ │ └── tool_calls loop → executeTool → sendRequest
|
|
367
|
+
│ ├── 销毁 Agent: agentModule.destroyAgent(agent.id)
|
|
368
|
+
│ └── return ReasonResult
|
|
369
|
+
└── return result
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 路径二: 持久化对话
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
Dialog.send(input)
|
|
376
|
+
│
|
|
377
|
+
├── 获取策略: reasonModule.get(this.strategy)
|
|
378
|
+
├── 过滤工具: skillModule.resolveTools(this.id) → ToolDefinition[]
|
|
379
|
+
├── 排序工具: toolModule.selectTools(input, toolNames, topK) → string[]
|
|
380
|
+
├── 聚合提示: skillModule.buildPrompt(this.id) → string
|
|
381
|
+
├── 构建上下文: { agentId, dialogId, turnCount }
|
|
382
|
+
├── reason.execute(input, {
|
|
383
|
+
│ baseConfig: this.config,
|
|
384
|
+
│ useAgent: this.agent, // 复用持久化 Agent
|
|
385
|
+
│ toolNames, toolContext, skillPrompt
|
|
386
|
+
│ })
|
|
387
|
+
│ ├── ChainReason: agent.run(input, runOptions)
|
|
388
|
+
│ │ ├── memory.checkPressure() → optimize()
|
|
389
|
+
│ │ ├── ToAPITools(runOptions.toolNames, compact=true) // 仅 Skill 过滤后的工具
|
|
390
|
+
│ │ └── ReAct 循环
|
|
391
|
+
│ └── return ReasonResult
|
|
392
|
+
└── return DialogResult { ...result, dialogId }
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**关键差异**: Dialog 路径在 Agent 执行前多了三个步骤:
|
|
396
|
+
1. `resolveTools()` — Skill 过滤
|
|
397
|
+
2. `selectTools()` — RAG 语义排序
|
|
398
|
+
3. `buildPrompt()` — 注入 Skill 系统提示
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## 五、Token 优化管线
|
|
403
|
+
|
|
404
|
+
```
|
|
405
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
406
|
+
│ Skill 过滤 │ → │ RAG 排序 │ → │ Compact │ → │ Memory 压缩 │
|
|
407
|
+
│ (P-前置) │ │ (P3) │ │ (P0) │ │ (P1+P2) │
|
|
408
|
+
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
|
|
409
|
+
↓ ↓ ↓ ↓
|
|
410
|
+
resolveTools() selectTools() ToAPITools( checkPressure()
|
|
411
|
+
通配符展开 语义排序 compact=true) → optimize()
|
|
412
|
+
精确匹配 Top-K 裁剪 递归去 description tiktoken 计数
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**效果估算** (100 个工具注册):
|
|
416
|
+
|
|
417
|
+
| 阶段 | 工具数 | Token 估算 | 缩减率 |
|
|
418
|
+
|------|--------|-----------|--------|
|
|
419
|
+
| 原始注册 | 100 | ~50,000 | — |
|
|
420
|
+
| Skill 过滤后 | ~20 | ~10,000 | 80% |
|
|
421
|
+
| RAG Top-10 | 10 | ~5,000 | 50% |
|
|
422
|
+
| Compact Schema | 10 | ~1,500 | 70% |
|
|
423
|
+
| **最终** | **10** | **~1,500** | **97%** |
|
|
424
|
+
|
|
425
|
+
Memory 压缩在独立维度上工作,减少的是消息历史的 Token 开销,与工具优化互补。
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## 六、设计决策记录
|
|
430
|
+
|
|
431
|
+
### 6.1 Agent 缓存为何留在 Agent 内部而非 Dialog?
|
|
432
|
+
|
|
433
|
+
**考虑**: 将 `_cache` 从 ToolModule/ToolRAG 移到 Dialog?
|
|
434
|
+
|
|
435
|
+
**结论: 不迁移。**
|
|
436
|
+
|
|
437
|
+
原因:
|
|
438
|
+
- 一次性推理路径 (ReasonModule → Agent) 也需要缓存,不应与 Dialog 绑定
|
|
439
|
+
- 多 Agent 策略 (Competitive/Commander) 中多个 Agent 共享同一个 ToolModule,缓存归 ToolModule 更合理
|
|
440
|
+
- Memory 优化与 Agent 的消息历史紧密耦合,移到 Dialog 会导致循环依赖
|
|
441
|
+
|
|
442
|
+
### 6.2 工具为何是 MCP-agnostic?
|
|
443
|
+
|
|
444
|
+
框架不区分工具来源 (本地/MCP/API)。业务层在 `handler` 中封装所有调用逻辑,框架只负责:
|
|
445
|
+
- 注册表管理 (registry)
|
|
446
|
+
- 执行调度 (并行/串行分组)
|
|
447
|
+
- 结果缓存 + 失败重试
|
|
448
|
+
- 向 LLM 提供工具定义
|
|
449
|
+
|
|
450
|
+
这避免了框架对 MCP 协议的强依赖,同时允许业务层自由选择工具实现方式。
|
|
451
|
+
|
|
452
|
+
### 6.3 Skill 为何是 interface 而非 abstract class?
|
|
453
|
+
|
|
454
|
+
Skill 是纯数据定义 (工具包 + 提示词),不包含运行时逻辑。遵循"接口描述数据,抽象类描述行为"的原则:
|
|
455
|
+
- `interface Skill` — 数据契约,业务层直接构造对象
|
|
456
|
+
- `abstract class SkillModule` — 运行时行为,管理注册/过滤/聚合
|
|
457
|
+
|
|
458
|
+
这降低了业务层的使用门槛 (无需 `new` 或继承)。
|
|
459
|
+
|
|
460
|
+
### 6.4 三级 MemoryPressure 替代单一阈值
|
|
461
|
+
|
|
462
|
+
**旧设计**: `hasOverflow(): boolean` — 单一阈值 (70%),溢出后一刀切压缩。
|
|
463
|
+
|
|
464
|
+
**新设计**: `checkPressure(): MemoryPressure` — 4 级渐进式:
|
|
465
|
+
- `None` (< 70%): 零开销
|
|
466
|
+
- `Mild` (70-85%): 1 次 LLM 调用,温和压缩远期
|
|
467
|
+
- `Moderate` (85-95%): 1-2 次 LLM 调用,压缩远期 + 摘要中间
|
|
468
|
+
- `Critical` (> 95%): 0 次 LLM 调用,激进裁剪
|
|
469
|
+
|
|
470
|
+
**收益**: 避免轻度过量时执行昂贵的 LLM 压缩调用,同时保证极端情况下的可用性。
|
|
471
|
+
|
|
472
|
+
### 6.5 tiktoken 替代启发式估算
|
|
473
|
+
|
|
474
|
+
**旧方案**: `estimateTokens()` 使用 CJK 字符 ×1.5 + 英文词 ×1.3 的启发式公式。
|
|
475
|
+
|
|
476
|
+
**问题**: 误差 15-30%,可能导致过早压缩 (浪费 LLM 调用) 或过晚压缩 (超出上下文窗口)。
|
|
477
|
+
|
|
478
|
+
**新方案**: `tiktoken` 的 `cl100k_base` 编码器,与 DeepSeek/OpenAI 的 tokenizer 完全一致,误差 < 1%。
|
|
479
|
+
|
|
480
|
+
### 6.6 ToolRAG 默认关键词匹配
|
|
481
|
+
|
|
482
|
+
**选择**: 默认使用 `_keywordSearch()` (中英文分词 + 加权匹配),而非强依赖 Embedding API。
|
|
483
|
+
|
|
484
|
+
**理由**:
|
|
485
|
+
- 零依赖,即时可用
|
|
486
|
+
- 工具描述通常较短 (10-50 词),关键词匹配精度足够
|
|
487
|
+
- `IEmbeddingProvider` 接口允许业务层按需升级为语义检索
|
|
488
|
+
- 避免引入 ML 运行时依赖 (如 transformers.js)
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## 七、持久化模型
|
|
493
|
+
|
|
494
|
+
### 快照结构
|
|
495
|
+
|
|
496
|
+
```
|
|
497
|
+
DialogSnapshot
|
|
498
|
+
├── version: number // 格式版本 (当前 1)
|
|
499
|
+
├── createdAt: number // 创建时间戳
|
|
500
|
+
├── dialogId: string // 对话 ID
|
|
501
|
+
├── title: string // 对话标题
|
|
502
|
+
├── strategy: string // 当前推理策略
|
|
503
|
+
└── agentSnapshot:
|
|
504
|
+
├── version: number
|
|
505
|
+
├── agentId: string
|
|
506
|
+
├── turnCount: number // 对话轮次
|
|
507
|
+
├── messages: LLMMessage[] // 完整消息历史
|
|
508
|
+
├── scratchpad: string // 推理草稿
|
|
509
|
+
├── toolResults: [id, result][] // 工具结果缓存
|
|
510
|
+
└── config: // Agent 配置 (已剥离 apiKey/address)
|
|
511
|
+
├── model
|
|
512
|
+
├── systemPrompt
|
|
513
|
+
├── temperature
|
|
514
|
+
├── maxTokens
|
|
515
|
+
├── enableThinking
|
|
516
|
+
├── reasoningEffort
|
|
517
|
+
└── maxTurns
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### 导入导出流程
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
导出: Dialog.snapshot() → Agent.snapshot() → DialogSnapshot
|
|
524
|
+
↑ 不包含 apiKey / address (安全剥离)
|
|
525
|
+
|
|
526
|
+
导入: DialogModule.import(snapshot, config)
|
|
527
|
+
├── 合并 config (address/apiKey 从参数取, 其余从快照恢复)
|
|
528
|
+
├── new Dialog(title, mergedConfig, strategy)
|
|
529
|
+
└── agent.restore(agentSnapshot)
|
|
530
|
+
├── turnCount = snapshot.turnCount
|
|
531
|
+
├── scratchpad = snapshot.scratchpad
|
|
532
|
+
├── toolResults = Map(snapshot.toolResults)
|
|
533
|
+
└── messages = snapshot.messages
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### 安全设计
|
|
537
|
+
|
|
538
|
+
- `apiKey` 和 `address` 不会出现在任何快照中
|
|
539
|
+
- 恢复时必须重新传入完整的 `AgentConfig`(含 `apiKey`/`address`)
|
|
540
|
+
- 快照的 `config` 字段只包含非敏感的模型参数
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## 八、扩展点
|
|
545
|
+
|
|
546
|
+
### 自定义推理策略
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
import { AbstractReason, ReasonConfig, ReasonResult } from "knight-agent";
|
|
550
|
+
|
|
551
|
+
export class MyCustomReason extends AbstractReason {
|
|
552
|
+
public readonly type = "MyCustomReason";
|
|
553
|
+
|
|
554
|
+
async execute(input: string, config: ReasonConfig): Promise<ReasonResult> {
|
|
555
|
+
const agent = (config.useAgent as Agent)
|
|
556
|
+
?? this.host.agentModule.createAgent(config.baseConfig);
|
|
557
|
+
const runOptions = this.buildRunOptions(config);
|
|
558
|
+
try {
|
|
559
|
+
const result = await agent.run(input, runOptions);
|
|
560
|
+
return { ...result, strategy: this.type };
|
|
561
|
+
} finally {
|
|
562
|
+
if (!config.useAgent) this.host.agentModule.destroyAgent(agent.id);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
Host.reasonModule.register("MyCustomReason", new MyCustomReason());
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### 自定义 Embedding 提供者
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
Host.toolModule.setEmbeddingProvider({
|
|
574
|
+
dims: 1536,
|
|
575
|
+
embed: async (text) => {
|
|
576
|
+
// 调用任意 Embedding 服务
|
|
577
|
+
const res = await fetch("https://your-embedding-api.com/embed", {
|
|
578
|
+
method: "POST",
|
|
579
|
+
body: JSON.stringify({ text }),
|
|
580
|
+
});
|
|
581
|
+
return (await res.json()).vector;
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### 扩展模块
|
|
587
|
+
|
|
588
|
+
所有模块继承 `AbstractModule`,自动获得:
|
|
589
|
+
- 全局唯一 `id`
|
|
590
|
+
- `this.host` 访问其他模块
|
|
591
|
+
- 注册到全局对象池 `AbstractObject.objects`
|
|
592
|
+
|
|
593
|
+
```typescript
|
|
594
|
+
import { AbstractModule } from "knight-agent";
|
|
595
|
+
|
|
596
|
+
export class MyModule extends AbstractModule {
|
|
597
|
+
// 通过 this.host.toolModule / this.host.agentModule 等访问其他模块
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
将其挂载到 `Host` 即可集成到框架体系中。
|