lll-web-agent 0.1.0 → 0.5.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/README.md +305 -298
- package/dist/lll-web-agent.js +1383 -0
- package/dist/lll-web-agent.min.js +86 -0
- package/package.json +22 -2
- package/src/agent.js +199 -45
- package/src/context-manager.js +201 -0
- package/src/index.js +9 -1
- package/src/intent-recognizer.js +117 -0
- package/src/knowledge-base.js +100 -0
- package/src/memory.js +178 -6
- package/src/plan-and-execute.js +568 -0
- package/src/tool-filter.js +35 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# lll-web-agent
|
|
2
2
|
|
|
3
|
-
开箱即用的 LLM Agent SDK
|
|
3
|
+
开箱即用的 LLM Agent SDK — 配个 API Key 就能跑。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
内置完整 Runtime 管线:意图识别 → 工具过滤 → 上下文管理(token 预算) → ReAct 循环。
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
@@ -10,386 +10,393 @@
|
|
|
10
10
|
npm install lll-web-agent
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## 快速开始
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### 基础用法(10 行代码)
|
|
16
16
|
|
|
17
|
-
```
|
|
18
|
-
import { Agent } from 'lll-web-agent'
|
|
17
|
+
```js
|
|
18
|
+
import { Agent, defineTool } from 'lll-web-agent'
|
|
19
|
+
|
|
20
|
+
const readFile = defineTool({
|
|
21
|
+
name: 'read_file',
|
|
22
|
+
description: '读取文件内容',
|
|
23
|
+
parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] },
|
|
24
|
+
execute: async ({ path }) => (await import('fs/promises')).readFile(path, 'utf-8'),
|
|
25
|
+
})
|
|
19
26
|
|
|
20
27
|
const agent = new Agent({
|
|
21
28
|
provider: 'openai',
|
|
22
29
|
apiKey: process.env.OPENAI_API_KEY,
|
|
23
30
|
model: 'gpt-4',
|
|
31
|
+
tools: [readFile],
|
|
24
32
|
})
|
|
25
33
|
|
|
26
|
-
const reply = await agent.chat('
|
|
34
|
+
const reply = await agent.chat('读取 package.json 并告诉我项目名称')
|
|
27
35
|
console.log(reply)
|
|
28
36
|
```
|
|
29
37
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
---
|
|
38
|
+
### Runtime 模式(完整管线)
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
```js
|
|
41
|
+
import { Agent, KnowledgeBase, createKnowledgeEntry } from 'lll-web-agent'
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
// 1. 构建知识库
|
|
44
|
+
const kb = new KnowledgeBase()
|
|
45
|
+
kb.addEntry(createKnowledgeEntry('ARCHITECTURE', '项目架构', '本项目使用 monorepo 结构...'))
|
|
46
|
+
kb.addEntry(createKnowledgeEntry('ERROR_PATTERN', '常见错误', '避免在循环中使用 await...'))
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return new Date().toISOString()
|
|
48
|
+
// 2. 创建 Agent(启用 Runtime 管线)
|
|
49
|
+
const agent = new Agent({
|
|
50
|
+
provider: 'deepseek',
|
|
51
|
+
apiKey: process.env.DEEPSEEK_API_KEY,
|
|
52
|
+
model: 'deepseek-chat',
|
|
53
|
+
tools: [readFile, shellExec],
|
|
54
|
+
enableIntentRecognition: true, // 启用意图识别(sidecar LLM 调用)
|
|
55
|
+
knowledgeBase: kb, // 注入知识库
|
|
56
|
+
tokenBudget: { // 自定义 token 预算
|
|
57
|
+
totalTokens: 60000,
|
|
58
|
+
systemPromptRatio: 0.15,
|
|
59
|
+
knowledgeRatio: 0.20,
|
|
60
|
+
historyRatio: 0.45,
|
|
61
|
+
toolsRatio: 0.20,
|
|
53
62
|
},
|
|
54
63
|
})
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
provider: 'openai',
|
|
59
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
60
|
-
model: 'gpt-4',
|
|
61
|
-
tools: [getCurrentTime],
|
|
62
|
-
})
|
|
65
|
+
const reply = await agent.chat('分析项目架构并找出潜在问题')
|
|
66
|
+
```
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
## 流式对话
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
for await (const event of agent.stream('帮我重构这个函数')) {
|
|
72
|
+
switch (event.type) {
|
|
73
|
+
case 'intent': console.log('意图:', event.intent); break
|
|
74
|
+
case 'delta': process.stdout.write(event.content); break
|
|
75
|
+
case 'tool_start': console.log(`\n🔧 ${event.name}(${JSON.stringify(event.arguments)})`); break
|
|
76
|
+
case 'tool_end': console.log(`✅ ${event.name} → ${event.result}`); break
|
|
77
|
+
case 'done': console.log('\n完成'); break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
68
80
|
```
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
## 架构
|
|
71
83
|
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
84
|
+
```
|
|
85
|
+
用户消息
|
|
86
|
+
│
|
|
87
|
+
├─ enableIntentRecognition=true?
|
|
88
|
+
│ └─ IntentRecognizer (sidecar LLM 调用)
|
|
89
|
+
│ → { clarity, complexity, recommendedStrategy, filteredToolNames }
|
|
90
|
+
│
|
|
91
|
+
├─ ToolFilter
|
|
92
|
+
│ → 根据 intent 过滤工具(BaseTool 始终保留)
|
|
93
|
+
│
|
|
94
|
+
├─ ContextManager (如果配置了 tokenBudget 或 knowledgeBase)
|
|
95
|
+
│ → 组装 prompt: systemPrompt + knowledge + history + tools
|
|
96
|
+
│ → 超预算时按优先级裁剪: TOOLS → HISTORY → KNOWLEDGE
|
|
97
|
+
│
|
|
98
|
+
└─ 执行策略(strategy)
|
|
99
|
+
├─ react(默认)
|
|
100
|
+
│ → LLM 调用 → 工具执行 → 观察结果 → 继续/完成
|
|
101
|
+
│
|
|
102
|
+
└─ plan_and_execute
|
|
103
|
+
→ Phase 1: Planning(LLM 生成结构化计划)
|
|
104
|
+
→ Phase 2: Execution(逐步执行,每步内部 ReAct 循环)
|
|
105
|
+
→ Phase 3: Synthesis(汇总结果,生成最终回答)
|
|
106
|
+
→ 支持自适应重规划(步骤失败时自动修订计划)
|
|
95
107
|
```
|
|
96
108
|
|
|
97
|
-
|
|
109
|
+
## 核心模块
|
|
98
110
|
|
|
99
|
-
Agent
|
|
111
|
+
### Agent
|
|
100
112
|
|
|
101
|
-
|
|
102
|
-
const listFiles = defineTool({
|
|
103
|
-
name: 'list_files',
|
|
104
|
-
description: '列出目录下的文件',
|
|
105
|
-
parameters: {
|
|
106
|
-
type: 'object',
|
|
107
|
-
properties: {
|
|
108
|
-
dir: { type: 'string', description: '目录路径' },
|
|
109
|
-
},
|
|
110
|
-
required: ['dir'],
|
|
111
|
-
},
|
|
112
|
-
execute: async ({ dir }) => {
|
|
113
|
-
const fs = await import('fs/promises')
|
|
114
|
-
const files = await fs.readdir(dir)
|
|
115
|
-
return files.join('\n')
|
|
116
|
-
},
|
|
117
|
-
})
|
|
113
|
+
主入口,支持两种模式:
|
|
118
114
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
| 参数 | 默认值 | 说明 |
|
|
116
|
+
|------|--------|------|
|
|
117
|
+
| `provider` | (必需) | 供应商: openai, deepseek, qwen, moonshot, zhipu, x-grok |
|
|
118
|
+
| `apiKey` | (必需) | API Key |
|
|
119
|
+
| `model` | `'gpt-4'` | 模型名称 |
|
|
120
|
+
| `tools` | `[]` | 工具列表 |
|
|
121
|
+
| `maxRounds` | `300` | 最大 ReAct 轮次 |
|
|
122
|
+
| `enableIntentRecognition` | `false` | 启用意图识别 |
|
|
123
|
+
| `knowledgeBase` | `null` | 知识库实例 |
|
|
124
|
+
| `tokenBudget` | `null` | token 预算配置 |
|
|
125
|
+
| `memory` | `SlidingWindowMemory(40)` | 自定义记忆实例 |
|
|
126
|
+
| `strategy` | `'react'` | 执行策略: `'react'` 或 `'plan_and_execute'` |
|
|
127
|
+
| `planAndExecuteOpts` | `{}` | PlanAndExecute 策略配置(见下方) |
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
const reply = await agent.chat('看看当前目录有什么文件,读一下 package.json 的内容')
|
|
128
|
-
```
|
|
129
|
+
### IntentRecognizer
|
|
129
130
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```javascript
|
|
133
|
-
defineTool({
|
|
134
|
-
name: 'my_tool',
|
|
135
|
-
description: '...',
|
|
136
|
-
parameters: { ... },
|
|
137
|
-
execute: async (params) => {
|
|
138
|
-
// params 是 LLM 传入的参数对象,结构与 parameters 定义一致
|
|
139
|
-
// 必须返回字符串(LLM 只能理解文本)
|
|
140
|
-
// 如果返回对象,会被自动 JSON.stringify
|
|
141
|
-
// 抛出异常时,错误信息会被发送给 LLM,LLM 可能会重试或换一种方式
|
|
142
|
-
return '执行结果'
|
|
143
|
-
},
|
|
144
|
-
})
|
|
145
|
-
```
|
|
131
|
+
Sidecar 方式独立 LLM 调用,分析用户请求:
|
|
146
132
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
```javascript
|
|
150
|
-
// Shell 命令执行
|
|
151
|
-
const shellExec = defineTool({
|
|
152
|
-
name: 'shell_exec',
|
|
153
|
-
description: '执行 shell 命令并返回输出',
|
|
154
|
-
parameters: {
|
|
155
|
-
type: 'object',
|
|
156
|
-
properties: {
|
|
157
|
-
command: { type: 'string', description: 'shell 命令' },
|
|
158
|
-
},
|
|
159
|
-
required: ['command'],
|
|
160
|
-
},
|
|
161
|
-
execute: async ({ command }) => {
|
|
162
|
-
const { execSync } = await import('child_process')
|
|
163
|
-
try {
|
|
164
|
-
return execSync(command, { encoding: 'utf-8', timeout: 10000 })
|
|
165
|
-
} catch (err) {
|
|
166
|
-
return `命令执行失败: ${err.message}`
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
})
|
|
133
|
+
```js
|
|
134
|
+
import { IntentRecognizer } from 'lll-web-agent'
|
|
170
135
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
parameters: {
|
|
176
|
-
type: 'object',
|
|
177
|
-
properties: {
|
|
178
|
-
url: { type: 'string', description: 'URL 地址' },
|
|
179
|
-
},
|
|
180
|
-
required: ['url'],
|
|
181
|
-
},
|
|
182
|
-
execute: async ({ url }) => {
|
|
183
|
-
const res = await fetch(url)
|
|
184
|
-
return await res.text()
|
|
185
|
-
},
|
|
136
|
+
const ir = new IntentRecognizer({
|
|
137
|
+
url: 'https://api.openai.com/v1/chat/completions',
|
|
138
|
+
apiKey: 'sk-xxx',
|
|
139
|
+
model: 'gpt-4',
|
|
186
140
|
})
|
|
187
141
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
name: 'calculate',
|
|
191
|
-
description: '计算数学表达式',
|
|
192
|
-
parameters: {
|
|
193
|
-
type: 'object',
|
|
194
|
-
properties: {
|
|
195
|
-
expression: { type: 'string', description: '数学表达式' },
|
|
196
|
-
},
|
|
197
|
-
required: ['expression'],
|
|
198
|
-
},
|
|
199
|
-
execute: async ({ expression }) => {
|
|
200
|
-
return String(Function(`"use strict"; return (${expression})`)())
|
|
201
|
-
},
|
|
202
|
-
})
|
|
142
|
+
const intent = await ir.analyze('帮我重构整个项目的错误处理', ['read_file', 'write_file', 'shell_exec'])
|
|
143
|
+
// → { clarity: 'CLEAR', complexity: 'COMPLEX', recommendedStrategy: 'plan_and_execute', ... }
|
|
203
144
|
```
|
|
204
145
|
|
|
205
|
-
|
|
146
|
+
### KnowledgeBase
|
|
206
147
|
|
|
207
|
-
|
|
148
|
+
项目知识管理,注入到 prompt 中:
|
|
208
149
|
|
|
209
|
-
|
|
150
|
+
```js
|
|
151
|
+
import { KnowledgeBase, createKnowledgeEntry } from 'lll-web-agent'
|
|
210
152
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
case 'tool_start': // 开始调用工具
|
|
218
|
-
console.log(`\n[调用工具: ${event.name}]`)
|
|
219
|
-
break
|
|
220
|
-
case 'tool_end': // 工具执行完成
|
|
221
|
-
console.log(`[结果: ${event.result}]`)
|
|
222
|
-
break
|
|
223
|
-
case 'done': // 对话完成
|
|
224
|
-
console.log('\n--- 完成 ---')
|
|
225
|
-
break
|
|
226
|
-
}
|
|
227
|
-
}
|
|
153
|
+
const kb = new KnowledgeBase()
|
|
154
|
+
kb.addEntry(createKnowledgeEntry('ARCHITECTURE', '技术栈', 'React + TypeScript + Vite'))
|
|
155
|
+
kb.addEntry(createKnowledgeEntry('ERROR_PATTERN', 'API 调用', '所有 API 调用必须有超时设置'))
|
|
156
|
+
|
|
157
|
+
console.log(kb.buildKnowledgePrompt())
|
|
158
|
+
// → ## 项目架构\n### 技术栈\nReact + TypeScript + Vite\n\n## 错误避免模式\n...
|
|
228
159
|
```
|
|
229
160
|
|
|
230
|
-
|
|
161
|
+
### ContextManager
|
|
231
162
|
|
|
232
|
-
|
|
163
|
+
Token 预算管理和 prompt 组装:
|
|
233
164
|
|
|
234
|
-
|
|
165
|
+
```js
|
|
166
|
+
import { ContextManager, defaultTokenBudget } from 'lll-web-agent'
|
|
235
167
|
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
168
|
+
const cm = new ContextManager()
|
|
169
|
+
const result = cm.assemblePrompt({
|
|
170
|
+
systemPrompt: '你是一个编程助手',
|
|
171
|
+
userMessage: '帮我写排序',
|
|
172
|
+
history: [{ role: 'user', content: '你好' }, { role: 'assistant', content: '你好!' }],
|
|
173
|
+
filteredTools: myTools,
|
|
174
|
+
tokenBudget: { ...defaultTokenBudget(), totalTokens: 8000 },
|
|
242
175
|
})
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// Agent 记住了上一轮的内容
|
|
246
|
-
await agent.chat('这个项目用了什么依赖?')
|
|
247
|
-
|
|
248
|
-
// 开始新会话
|
|
249
|
-
agent.reset()
|
|
250
|
-
await agent.chat('你好') // 不记得之前的对话了
|
|
176
|
+
// result.messages → 组装好的 messages 数组
|
|
177
|
+
// result.trimmed → 是否发生了裁剪
|
|
251
178
|
```
|
|
252
179
|
|
|
253
|
-
|
|
180
|
+
### Memory 策略
|
|
254
181
|
|
|
255
|
-
|
|
182
|
+
```js
|
|
183
|
+
import { SlidingWindowMemory, SummarizingMemory, TokenAwareMemory } from 'lll-web-agent'
|
|
256
184
|
|
|
257
|
-
|
|
258
|
-
const
|
|
185
|
+
// 滑动窗口(默认)
|
|
186
|
+
const sw = new SlidingWindowMemory(40)
|
|
259
187
|
|
|
260
|
-
//
|
|
261
|
-
|
|
188
|
+
// 摘要记忆(超阈值时 LLM 压缩)
|
|
189
|
+
const sm = new SummarizingMemory({
|
|
190
|
+
threshold: 20,
|
|
191
|
+
keepRecent: 5,
|
|
192
|
+
summarizer: async (text) => await myLlmSummarize(text),
|
|
193
|
+
})
|
|
262
194
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (err.name === 'AbortError') {
|
|
269
|
-
console.log('请求已取消')
|
|
270
|
-
}
|
|
271
|
-
}
|
|
195
|
+
// Token 感知记忆
|
|
196
|
+
const ta = new TokenAwareMemory(50000)
|
|
197
|
+
|
|
198
|
+
// 注入到 Agent
|
|
199
|
+
const agent = new Agent({ ..., memory: sm })
|
|
272
200
|
```
|
|
273
201
|
|
|
274
|
-
|
|
202
|
+
### ToolFilter
|
|
275
203
|
|
|
276
|
-
|
|
204
|
+
```js
|
|
205
|
+
import { ToolFilter, BASE_TOOLS } from 'lll-web-agent'
|
|
277
206
|
|
|
278
|
-
|
|
207
|
+
const filter = new ToolFilter()
|
|
208
|
+
const filtered = filter.filter(intentResult, allTools)
|
|
209
|
+
// BASE_TOOLS (keyword_search, read_file, write_file, shell_exec, project_tree) 始终保留
|
|
210
|
+
```
|
|
279
211
|
|
|
280
|
-
|
|
281
|
-
// OpenAI
|
|
282
|
-
new Agent({ provider: 'openai', apiKey: '...', model: 'gpt-4' })
|
|
212
|
+
### PlanAndExecute 执行策略
|
|
283
213
|
|
|
284
|
-
|
|
285
|
-
new Agent({ provider: 'deepseek', apiKey: '...', model: 'deepseek-chat' })
|
|
214
|
+
对应 Java 框架的 `PlanAndExecuteStrategy`。适用于复杂多步骤任务,相比 ReAct 的"边思考边行动",PlanAndExecute 先让 LLM 站在全局视角制定完整计划,然后逐步执行。
|
|
286
215
|
|
|
287
|
-
|
|
288
|
-
|
|
216
|
+
三阶段流程:
|
|
217
|
+
1. **Planning** — 调用 LLM 生成结构化执行计划(JSON 步骤列表)
|
|
218
|
+
2. **Execution** — 对每个步骤使用内部 ReAct 循环执行(支持工具调用)
|
|
219
|
+
3. **Synthesis** — 汇总所有步骤结果,生成最终回答
|
|
289
220
|
|
|
290
|
-
|
|
291
|
-
new Agent({ provider: 'x-grok', apiKey: '...', model: 'grok-2' })
|
|
221
|
+
#### 通过 Agent 切换策略
|
|
292
222
|
|
|
293
|
-
|
|
294
|
-
|
|
223
|
+
```js
|
|
224
|
+
import { Agent, defineTool } from 'lll-web-agent'
|
|
295
225
|
|
|
296
|
-
|
|
297
|
-
|
|
226
|
+
const readFile = defineTool({ name: 'read_file', description: '读取文件', /* ... */ })
|
|
227
|
+
const writeFile = defineTool({ name: 'write_file', description: '写入文件', /* ... */ })
|
|
228
|
+
const shellExec = defineTool({ name: 'shell_exec', description: '执行命令', /* ... */ })
|
|
298
229
|
|
|
299
|
-
//
|
|
300
|
-
new Agent({
|
|
230
|
+
// 使用 PlanAndExecute 策略
|
|
231
|
+
const agent = new Agent({
|
|
301
232
|
provider: 'openai',
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
233
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
234
|
+
model: 'gpt-4',
|
|
235
|
+
tools: [readFile, writeFile, shellExec],
|
|
236
|
+
strategy: 'plan_and_execute', // ← 切换策略
|
|
237
|
+
planAndExecuteOpts: { // ← 可选配置
|
|
238
|
+
maxPlanSteps: 10,
|
|
239
|
+
stepMaxRounds: 20,
|
|
240
|
+
maxReplanAttempts: 2,
|
|
241
|
+
},
|
|
305
242
|
})
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### 注册自定义供应商
|
|
309
243
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
registerProvider('my-llm', {
|
|
314
|
-
url: 'https://api.my-llm.com/v1/chat/completions',
|
|
315
|
-
})
|
|
244
|
+
// 同步对话 — 用法与 ReAct 完全一致
|
|
245
|
+
const reply = await agent.chat('重构项目中所有废弃的 API 调用')
|
|
246
|
+
console.log(reply)
|
|
316
247
|
|
|
317
|
-
|
|
248
|
+
// 流式对话 — 额外推送计划和步骤进度事件
|
|
249
|
+
for await (const event of agent.stream('分析项目架构并生成文档')) {
|
|
250
|
+
switch (event.type) {
|
|
251
|
+
case 'phase': console.log(`[${event.phase}] ${event.message}`); break
|
|
252
|
+
case 'plan_generated': console.log('计划:', event.plan); break
|
|
253
|
+
case 'step_start': console.log(`▶ Step ${event.index + 1}: ${event.description}`); break
|
|
254
|
+
case 'step_complete':
|
|
255
|
+
console.log(`${event.success ? '✅' : '❌'} Step ${event.index + 1} (${event.duration}ms)`)
|
|
256
|
+
break
|
|
257
|
+
case 'plan_revised': console.log('计划已修订:', event.plan); break
|
|
258
|
+
case 'done': console.log('最终结果:', event.content); break
|
|
259
|
+
}
|
|
260
|
+
}
|
|
318
261
|
```
|
|
319
262
|
|
|
320
|
-
|
|
263
|
+
#### 动态切换策略
|
|
321
264
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
apiKey: 'sk-xxx', // API Key
|
|
265
|
+
```js
|
|
266
|
+
// 根据任务复杂度动态选择策略
|
|
267
|
+
function chooseStrategy(message) {
|
|
268
|
+
const complexKeywords = ['重构', '迁移', '分析整个', '批量修改', '全面检查']
|
|
269
|
+
return complexKeywords.some(k => message.includes(k)) ? 'plan_and_execute' : 'react'
|
|
270
|
+
}
|
|
329
271
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
tools: [],
|
|
335
|
-
|
|
336
|
-
maxMessages: 40, // 记忆窗口大小(保留最近 N 条消息),默认 40
|
|
337
|
-
temperature: 1, // 温度,默认 1
|
|
272
|
+
const agent = new Agent({
|
|
273
|
+
provider: 'openai',
|
|
274
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
275
|
+
model: 'gpt-4',
|
|
276
|
+
tools: [readFile, writeFile, shellExec],
|
|
277
|
+
strategy: chooseStrategy(userMessage),
|
|
338
278
|
})
|
|
339
279
|
```
|
|
340
280
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
## 工作原理
|
|
281
|
+
#### 结合意图识别自动选择策略
|
|
344
282
|
|
|
345
|
-
|
|
283
|
+
```js
|
|
284
|
+
import { Agent, IntentRecognizer } from 'lll-web-agent'
|
|
346
285
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
|
354
|
-
执行工具 -> 将结果加入对话历史
|
|
355
|
-
|
|
|
356
|
-
回到顶部,再次调用 LLM
|
|
357
|
-
```
|
|
286
|
+
// 先用 IntentRecognizer 分析任务复杂度
|
|
287
|
+
const ir = new IntentRecognizer({
|
|
288
|
+
url: 'https://api.openai.com/v1/chat/completions',
|
|
289
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
290
|
+
model: 'gpt-4',
|
|
291
|
+
})
|
|
358
292
|
|
|
359
|
-
|
|
293
|
+
const intent = await ir.analyze(userMessage, toolNames)
|
|
294
|
+
// intent.recommendedStrategy → 'react' | 'plan_and_execute'
|
|
360
295
|
|
|
361
|
-
|
|
296
|
+
const agent = new Agent({
|
|
297
|
+
provider: 'openai',
|
|
298
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
299
|
+
model: 'gpt-4',
|
|
300
|
+
tools: myTools,
|
|
301
|
+
strategy: intent.recommendedStrategy, // ← 根据意图识别结果选择
|
|
302
|
+
})
|
|
362
303
|
|
|
363
|
-
|
|
304
|
+
const reply = await agent.chat(userMessage)
|
|
305
|
+
```
|
|
364
306
|
|
|
365
|
-
|
|
307
|
+
#### 独立使用 PlanAndExecuteStrategy
|
|
366
308
|
|
|
367
|
-
|
|
368
|
-
|------|------|
|
|
369
|
-
| `new Agent(opts)` | 创建 Agent 实例 |
|
|
370
|
-
| `agent.chat(message, opts?)` | 同步对话,返回 `Promise<string>` |
|
|
371
|
-
| `agent.stream(message, opts?)` | 流式对话,返回 `AsyncGenerator<Event>` |
|
|
372
|
-
| `agent.reset()` | 清空对话历史,开始新会话 |
|
|
309
|
+
不通过 Agent,直接使用策略类:
|
|
373
310
|
|
|
374
|
-
|
|
311
|
+
```js
|
|
312
|
+
import { PlanAndExecuteStrategy } from 'lll-web-agent'
|
|
375
313
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
314
|
+
const strategy = new PlanAndExecuteStrategy({
|
|
315
|
+
url: 'https://api.openai.com/v1/chat/completions',
|
|
316
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
317
|
+
model: 'gpt-4',
|
|
318
|
+
tools: [readFile, writeFile, shellExec],
|
|
319
|
+
maxPlanSteps: 10,
|
|
320
|
+
stepMaxRounds: 20,
|
|
321
|
+
maxReplanAttempts: 2,
|
|
322
|
+
|
|
323
|
+
// 进度回调
|
|
324
|
+
onPhase: (phase, msg) => console.log(`[${phase}] ${msg}`),
|
|
325
|
+
onPlanGenerated: (steps) => {
|
|
326
|
+
console.log('执行计划:')
|
|
327
|
+
steps.forEach(s => console.log(` ${s.index + 1}. ${s.description}`))
|
|
328
|
+
},
|
|
329
|
+
onStepStart: (i, desc) => console.log(`▶ 开始步骤 ${i + 1}: ${desc}`),
|
|
330
|
+
onStepComplete: (i, ok, result) => console.log(`${ok ? '✅' : '❌'} 步骤 ${i + 1}: ${result}`),
|
|
331
|
+
onPlanRevised: (steps) => console.log('计划已修订,剩余步骤:', steps.length),
|
|
332
|
+
})
|
|
382
333
|
|
|
383
|
-
|
|
334
|
+
// 同步执行
|
|
335
|
+
const { content, plan } = await strategy.execute('将项目从 CommonJS 迁移到 ESM')
|
|
336
|
+
console.log('最终结果:', content)
|
|
337
|
+
console.log('计划步骤:', plan.map(s => `${s.status} - ${s.description}`))
|
|
384
338
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
| `done` | `content` | 对话完成,包含完整回复 |
|
|
339
|
+
// 流式执行
|
|
340
|
+
for await (const event of strategy.stream('批量修复所有 lint 错误')) {
|
|
341
|
+
console.log(event)
|
|
342
|
+
}
|
|
343
|
+
```
|
|
391
344
|
|
|
392
|
-
|
|
345
|
+
#### PlanAndExecute 配置参数
|
|
346
|
+
|
|
347
|
+
| 参数 | 默认值 | 说明 |
|
|
348
|
+
|------|--------|------|
|
|
349
|
+
| `maxPlanSteps` | `35` | 计划步骤上限 |
|
|
350
|
+
| `stepMaxRounds` | `300` | 单个步骤内 ReAct 循环最大轮次 |
|
|
351
|
+
| `maxReplanAttempts` | `2` | 步骤失败时最大重规划次数 |
|
|
352
|
+
| `planningTimeoutMs` | `120000` | 规划阶段 LLM 调用超时(毫秒) |
|
|
353
|
+
| `synthesisTimeoutMs` | `120000` | 合成阶段 LLM 调用超时(毫秒) |
|
|
354
|
+
| `onPhase` | - | 阶段变更回调 `(phase, message) => void` |
|
|
355
|
+
| `onPlanGenerated` | - | 计划生成回调 `(steps) => void` |
|
|
356
|
+
| `onStepStart` | - | 步骤开始回调 `(index, description) => void` |
|
|
357
|
+
| `onStepComplete` | - | 步骤完成回调 `(index, success, result) => void` |
|
|
358
|
+
| `onPlanRevised` | - | 计划修订回调 `(steps) => void` |
|
|
359
|
+
|
|
360
|
+
#### 流式事件类型
|
|
361
|
+
|
|
362
|
+
| 事件 type | 字段 | 说明 |
|
|
363
|
+
|-----------|------|------|
|
|
364
|
+
| `phase` | `phase`, `message` | 阶段变更(planning / executing / synthesizing / completed / fallback) |
|
|
365
|
+
| `plan_generated` | `plan` | 计划生成完成 |
|
|
366
|
+
| `step_start` | `index`, `description` | 步骤开始执行 |
|
|
367
|
+
| `step_complete` | `index`, `success`, `result`, `duration` | 步骤执行完成 |
|
|
368
|
+
| `plan_revised` | `plan` | 计划被修订(步骤失败后重规划) |
|
|
369
|
+
| `done` | `content`, `plan` | 全部完成,包含最终结果和计划快照 |
|
|
370
|
+
|
|
371
|
+
## 与 Java Runtime 的对应关系
|
|
372
|
+
|
|
373
|
+
| JS SDK | Java Runtime | 说明 |
|
|
374
|
+
|--------|-------------|------|
|
|
375
|
+
| `Agent` | `Agent + AgentBuilder + AgentRuntime` | 高层 API |
|
|
376
|
+
| `Agent({ strategy: 'react' })` | `ReActStrategy` | ReAct 执行策略(默认) |
|
|
377
|
+
| `Agent({ strategy: 'plan_and_execute' })` | `PlanAndExecuteStrategy` | Plan & Execute 执行策略 |
|
|
378
|
+
| `PlanAndExecuteStrategy` | `PlanAndExecuteStrategy` | 独立使用的策略类 |
|
|
379
|
+
| `PlanStep` / `StepStatus` | `PlanStep` / `PlanStep.Status` | 计划步骤模型 |
|
|
380
|
+
| `IntentRecognizer` | `fc.runtime.IntentRecognizer` | sidecar 意图识别 |
|
|
381
|
+
| `ToolFilter` | `fc.runtime.ToolFilter` | 工具过滤 |
|
|
382
|
+
| `ContextManager` | `fc.state.ContextManager` | prompt 组装 + token 预算 |
|
|
383
|
+
| `KnowledgeBase` | `fc.runtime.KnowledgeBase` | 知识库管理 |
|
|
384
|
+
| `SlidingWindowMemory` | `fc.memory.SlidingWindowMemory` | 滑动窗口记忆 |
|
|
385
|
+
| `SummarizingMemory` | `fc.memory.SummarizingMemory` | 摘要记忆 |
|
|
386
|
+
| `TokenAwareMemory` | `fc.memory.AdaptiveMemory` | token 感知记忆 |
|
|
387
|
+
| `streamChat / syncChat` | `LlmClient` | LLM 通信 |
|
|
388
|
+
| `defineTool` | `Tool` 接口 | 工具定义 |
|
|
389
|
+
| `resolveProviderUrl` | `LlmProviderAdapterRegistry` | 供应商适配 |
|
|
390
|
+
|
|
391
|
+
## 浏览器使用
|
|
392
|
+
|
|
393
|
+
```html
|
|
394
|
+
<script src="https://unpkg.com/lll-web-agent/dist/lll-web-agent.min.js"></script>
|
|
395
|
+
<script>
|
|
396
|
+
const { Agent, defineTool, KnowledgeBase } = LllWebAgent
|
|
397
|
+
// ...
|
|
398
|
+
</script>
|
|
399
|
+
```
|
|
393
400
|
|
|
394
401
|
## License
|
|
395
402
|
|