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.
Files changed (163) hide show
  1. package/Host.d.ts +23 -0
  2. package/Host.d.ts.map +1 -0
  3. package/Host.js +23 -0
  4. package/Host.js.map +1 -0
  5. package/base/AbstractAgent.d.ts +100 -0
  6. package/base/AbstractAgent.d.ts.map +1 -0
  7. package/base/AbstractAgent.js +23 -0
  8. package/base/AbstractAgent.js.map +1 -0
  9. package/base/AbstractDialog.d.ts +54 -0
  10. package/base/AbstractDialog.d.ts.map +1 -0
  11. package/base/AbstractDialog.js +86 -0
  12. package/base/AbstractDialog.js.map +1 -0
  13. package/base/AbstractModule.d.ts +7 -0
  14. package/base/AbstractModule.d.ts.map +1 -0
  15. package/base/AbstractModule.js +13 -0
  16. package/base/AbstractModule.js.map +1 -0
  17. package/base/AbstractObject.d.ts +18 -0
  18. package/base/AbstractObject.d.ts.map +1 -0
  19. package/base/AbstractObject.js +25 -0
  20. package/base/AbstractObject.js.map +1 -0
  21. package/base/AbstractReason.d.ts +44 -0
  22. package/base/AbstractReason.d.ts.map +1 -0
  23. package/base/AbstractReason.js +23 -0
  24. package/base/AbstractReason.js.map +1 -0
  25. package/base/AbstractSkill.d.ts +25 -0
  26. package/base/AbstractSkill.d.ts.map +1 -0
  27. package/base/AbstractSkill.js +3 -0
  28. package/base/AbstractSkill.js.map +1 -0
  29. package/base/AbstractTool.d.ts +34 -0
  30. package/base/AbstractTool.d.ts.map +1 -0
  31. package/base/AbstractTool.js +3 -0
  32. package/base/AbstractTool.js.map +1 -0
  33. package/base/index.d.ts +8 -0
  34. package/base/index.d.ts.map +1 -0
  35. package/base/index.js +24 -0
  36. package/base/index.js.map +1 -0
  37. package/docs/ARCHITECTURE.md +601 -0
  38. package/docs/README.md +562 -0
  39. package/index.d.ts +4 -0
  40. package/index.d.ts.map +1 -0
  41. package/index.js +25 -0
  42. package/index.js.map +1 -0
  43. package/module/AgentModule/Agent.d.ts +55 -0
  44. package/module/AgentModule/Agent.d.ts.map +1 -0
  45. package/module/AgentModule/Agent.js +210 -0
  46. package/module/AgentModule/Agent.js.map +1 -0
  47. package/module/AgentModule/AgentModule.d.ts +26 -0
  48. package/module/AgentModule/AgentModule.d.ts.map +1 -0
  49. package/module/AgentModule/AgentModule.js +66 -0
  50. package/module/AgentModule/AgentModule.js.map +1 -0
  51. package/module/AgentModule/Memory.d.ts +55 -0
  52. package/module/AgentModule/Memory.d.ts.map +1 -0
  53. package/module/AgentModule/Memory.js +288 -0
  54. package/module/AgentModule/Memory.js.map +1 -0
  55. package/module/AgentModule/index.d.ts +2 -0
  56. package/module/AgentModule/index.d.ts.map +1 -0
  57. package/module/AgentModule/index.js +18 -0
  58. package/module/AgentModule/index.js.map +1 -0
  59. package/module/DialogModule/Dialog.d.ts +14 -0
  60. package/module/DialogModule/Dialog.d.ts.map +1 -0
  61. package/module/DialogModule/Dialog.js +27 -0
  62. package/module/DialogModule/Dialog.js.map +1 -0
  63. package/module/DialogModule/DialogModule.d.ts +39 -0
  64. package/module/DialogModule/DialogModule.d.ts.map +1 -0
  65. package/module/DialogModule/DialogModule.js +118 -0
  66. package/module/DialogModule/DialogModule.js.map +1 -0
  67. package/module/DialogModule/index.d.ts +3 -0
  68. package/module/DialogModule/index.d.ts.map +1 -0
  69. package/module/DialogModule/index.js +19 -0
  70. package/module/DialogModule/index.js.map +1 -0
  71. package/module/ReasonModule/ChainReason.d.ts +11 -0
  72. package/module/ReasonModule/ChainReason.d.ts.map +1 -0
  73. package/module/ReasonModule/ChainReason.js +34 -0
  74. package/module/ReasonModule/ChainReason.js.map +1 -0
  75. package/module/ReasonModule/CommanderReason.d.ts +15 -0
  76. package/module/ReasonModule/CommanderReason.d.ts.map +1 -0
  77. package/module/ReasonModule/CommanderReason.js +151 -0
  78. package/module/ReasonModule/CommanderReason.js.map +1 -0
  79. package/module/ReasonModule/CompetitiveReason.d.ts +13 -0
  80. package/module/ReasonModule/CompetitiveReason.d.ts.map +1 -0
  81. package/module/ReasonModule/CompetitiveReason.js +133 -0
  82. package/module/ReasonModule/CompetitiveReason.js.map +1 -0
  83. package/module/ReasonModule/PlanReason.d.ts +25 -0
  84. package/module/ReasonModule/PlanReason.d.ts.map +1 -0
  85. package/module/ReasonModule/PlanReason.js +133 -0
  86. package/module/ReasonModule/PlanReason.js.map +1 -0
  87. package/module/ReasonModule/ReasonModule.d.ts +41 -0
  88. package/module/ReasonModule/ReasonModule.d.ts.map +1 -0
  89. package/module/ReasonModule/ReasonModule.js +83 -0
  90. package/module/ReasonModule/ReasonModule.js.map +1 -0
  91. package/module/ReasonModule/ReflectReason.d.ts +15 -0
  92. package/module/ReasonModule/ReflectReason.d.ts.map +1 -0
  93. package/module/ReasonModule/ReflectReason.js +86 -0
  94. package/module/ReasonModule/ReflectReason.js.map +1 -0
  95. package/module/ReasonModule/TreeReason.d.ts +16 -0
  96. package/module/ReasonModule/TreeReason.d.ts.map +1 -0
  97. package/module/ReasonModule/TreeReason.js +139 -0
  98. package/module/ReasonModule/TreeReason.js.map +1 -0
  99. package/module/ReasonModule/index.d.ts +8 -0
  100. package/module/ReasonModule/index.d.ts.map +1 -0
  101. package/module/ReasonModule/index.js +24 -0
  102. package/module/ReasonModule/index.js.map +1 -0
  103. package/module/SkillModule/SkillModule.d.ts +42 -0
  104. package/module/SkillModule/SkillModule.d.ts.map +1 -0
  105. package/module/SkillModule/SkillModule.js +134 -0
  106. package/module/SkillModule/SkillModule.js.map +1 -0
  107. package/module/SkillModule/index.d.ts +2 -0
  108. package/module/SkillModule/index.d.ts.map +1 -0
  109. package/module/SkillModule/index.js +18 -0
  110. package/module/SkillModule/index.js.map +1 -0
  111. package/module/ToolModule/ToolModule.d.ts +57 -0
  112. package/module/ToolModule/ToolModule.d.ts.map +1 -0
  113. package/module/ToolModule/ToolModule.js +220 -0
  114. package/module/ToolModule/ToolModule.js.map +1 -0
  115. package/module/ToolModule/ToolRAG.d.ts +38 -0
  116. package/module/ToolModule/ToolRAG.d.ts.map +1 -0
  117. package/module/ToolModule/ToolRAG.js +124 -0
  118. package/module/ToolModule/ToolRAG.js.map +1 -0
  119. package/module/ToolModule/index.d.ts +3 -0
  120. package/module/ToolModule/index.d.ts.map +1 -0
  121. package/module/ToolModule/index.js +19 -0
  122. package/module/ToolModule/index.js.map +1 -0
  123. package/module/index.d.ts +6 -0
  124. package/module/index.d.ts.map +1 -0
  125. package/module/index.js +22 -0
  126. package/module/index.js.map +1 -0
  127. package/package.json +19 -0
  128. package/utility/InterfaceUtility.d.ts +14 -0
  129. package/utility/InterfaceUtility.d.ts.map +1 -0
  130. package/utility/InterfaceUtility.js +3 -0
  131. package/utility/InterfaceUtility.js.map +1 -0
  132. package/utility/LogUtility.d.ts +41 -0
  133. package/utility/LogUtility.d.ts.map +1 -0
  134. package/utility/LogUtility.js +70 -0
  135. package/utility/LogUtility.js.map +1 -0
  136. package/utility/NetworkUtility.d.ts +91 -0
  137. package/utility/NetworkUtility.d.ts.map +1 -0
  138. package/utility/NetworkUtility.js +104 -0
  139. package/utility/NetworkUtility.js.map +1 -0
  140. package/utility/ObjectUtility.d.ts +134 -0
  141. package/utility/ObjectUtility.d.ts.map +1 -0
  142. package/utility/ObjectUtility.js +313 -0
  143. package/utility/ObjectUtility.js.map +1 -0
  144. package/utility/OpenAIUtility.d.ts +333 -0
  145. package/utility/OpenAIUtility.d.ts.map +1 -0
  146. package/utility/OpenAIUtility.js +95 -0
  147. package/utility/OpenAIUtility.js.map +1 -0
  148. package/utility/PromiseUtility.d.ts +9 -0
  149. package/utility/PromiseUtility.d.ts.map +1 -0
  150. package/utility/PromiseUtility.js +16 -0
  151. package/utility/PromiseUtility.js.map +1 -0
  152. package/utility/StringUtility.d.ts +10 -0
  153. package/utility/StringUtility.d.ts.map +1 -0
  154. package/utility/StringUtility.js +42 -0
  155. package/utility/StringUtility.js.map +1 -0
  156. package/utility/TimeUtility.d.ts +10 -0
  157. package/utility/TimeUtility.d.ts.map +1 -0
  158. package/utility/TimeUtility.js +24 -0
  159. package/utility/TimeUtility.js.map +1 -0
  160. package/utility/index.d.ts +9 -0
  161. package/utility/index.d.ts.map +1 -0
  162. package/utility/index.js +25 -0
  163. 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` 即可集成到框架体系中。