@zhin.js/ai 1.0.0 → 1.0.2
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/CHANGELOG.md +13 -0
- package/README.md +131 -497
- package/lib/agent.d.ts +54 -6
- package/lib/agent.d.ts.map +1 -1
- package/lib/agent.js +468 -116
- package/lib/agent.js.map +1 -1
- package/lib/compaction.d.ts +132 -0
- package/lib/compaction.d.ts.map +1 -0
- package/lib/compaction.js +370 -0
- package/lib/compaction.js.map +1 -0
- package/lib/context-manager.d.ts.map +1 -1
- package/lib/context-manager.js +10 -3
- package/lib/context-manager.js.map +1 -1
- package/lib/conversation-memory.d.ts +192 -0
- package/lib/conversation-memory.d.ts.map +1 -0
- package/lib/conversation-memory.js +619 -0
- package/lib/conversation-memory.js.map +1 -0
- package/lib/index.d.ts +25 -163
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +24 -1122
- package/lib/index.js.map +1 -1
- package/lib/output.d.ts +93 -0
- package/lib/output.d.ts.map +1 -0
- package/lib/output.js +176 -0
- package/lib/output.js.map +1 -0
- package/lib/providers/anthropic.d.ts +7 -0
- package/lib/providers/anthropic.d.ts.map +1 -1
- package/lib/providers/anthropic.js +5 -0
- package/lib/providers/anthropic.js.map +1 -1
- package/lib/providers/ollama.d.ts +10 -0
- package/lib/providers/ollama.d.ts.map +1 -1
- package/lib/providers/ollama.js +19 -4
- package/lib/providers/ollama.js.map +1 -1
- package/lib/providers/openai.d.ts +7 -0
- package/lib/providers/openai.d.ts.map +1 -1
- package/lib/providers/openai.js +11 -0
- package/lib/providers/openai.js.map +1 -1
- package/lib/rate-limiter.d.ts +38 -0
- package/lib/rate-limiter.d.ts.map +1 -0
- package/lib/rate-limiter.js +86 -0
- package/lib/rate-limiter.js.map +1 -0
- package/lib/session.d.ts +7 -0
- package/lib/session.d.ts.map +1 -1
- package/lib/session.js +47 -18
- package/lib/session.js.map +1 -1
- package/lib/storage.d.ts +68 -0
- package/lib/storage.d.ts.map +1 -0
- package/lib/storage.js +105 -0
- package/lib/storage.js.map +1 -0
- package/lib/tone-detector.d.ts +19 -0
- package/lib/tone-detector.d.ts.map +1 -0
- package/lib/tone-detector.js +72 -0
- package/lib/tone-detector.js.map +1 -0
- package/lib/types.d.ts +84 -8
- package/lib/types.d.ts.map +1 -1
- package/package.json +13 -42
- package/src/agent.ts +518 -135
- package/src/compaction.ts +529 -0
- package/src/context-manager.ts +10 -9
- package/src/conversation-memory.ts +816 -0
- package/src/index.ts +121 -1406
- package/src/output.ts +261 -0
- package/src/providers/anthropic.ts +4 -0
- package/src/providers/ollama.ts +23 -4
- package/src/providers/openai.ts +8 -1
- package/src/rate-limiter.ts +129 -0
- package/src/session.ts +47 -18
- package/src/storage.ts +135 -0
- package/src/tone-detector.ts +89 -0
- package/src/types.ts +95 -6
- package/tests/agent.test.ts +123 -70
- package/tests/compaction.test.ts +310 -0
- package/tests/context-manager.test.ts +73 -47
- package/tests/conversation-memory.test.ts +128 -0
- package/tests/output.test.ts +128 -0
- package/tests/providers.test.ts +574 -0
- package/tests/rate-limiter.test.ts +108 -0
- package/tests/session.test.ts +139 -48
- package/tests/setup.ts +82 -240
- package/tests/storage.test.ts +224 -0
- package/tests/tone-detector.test.ts +80 -0
- package/tsconfig.json +4 -5
- package/vitest.setup.ts +1 -0
- package/TOOLS.md +0 -294
- package/lib/tools.d.ts +0 -45
- package/lib/tools.d.ts.map +0 -1
- package/lib/tools.js +0 -194
- package/lib/tools.js.map +0 -1
- package/src/tools.ts +0 -205
- package/tests/ai-trigger.test.ts +0 -369
- package/tests/integration.test.ts +0 -596
- package/tests/providers.integration.test.ts +0 -227
- package/tests/tool.test.ts +0 -800
- package/tests/tools-builtin.test.ts +0 -346
package/README.md
CHANGED
|
@@ -1,564 +1,198 @@
|
|
|
1
1
|
# @zhin.js/ai
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## ✨ 特性
|
|
6
|
-
|
|
7
|
-
- 🔌 **多模型支持**:OpenAI、Claude、DeepSeek、Moonshot、智谱、Ollama
|
|
8
|
-
- 🔄 **流式输出**:实时响应,提升用户体验
|
|
9
|
-
- 🛠️ **工具调用**:Function Calling / Tool Use 支持
|
|
10
|
-
- 🤖 **Agent 能力**:自动规划、工具调用、多轮推理
|
|
11
|
-
- 💬 **会话管理**:上下文记忆、自动过期、持久化
|
|
12
|
-
- 📝 **内置工具**:计算器、时间、HTTP 请求等
|
|
13
|
-
- 💾 **数据库持久化**:自动使用 Zhin 数据库存储会话,支持更长记忆
|
|
14
|
-
- 📊 **消息记录**:自动记录所有平台消息,构建智能上下文
|
|
15
|
-
- 🧠 **智能总结**:自动总结历史对话,保持上下文简洁
|
|
16
|
-
- 🎯 **AI 触发中间件**:支持 @机器人、前缀触发、私聊直接对话
|
|
17
|
-
- 🔧 **统一工具服务**:Tool ↔ Command 双向转换,AI 可调用现有命令
|
|
18
|
-
- 🎨 **富媒体支持**:AI 可输出图片、音频、视频、@用户等富媒体内容
|
|
19
|
-
- 🔒 **权限控制**:基于平台、场景、用户权限的工具过滤
|
|
20
|
-
|
|
21
|
-
## 📦 安装
|
|
3
|
+
框架无关的 AI 引擎,提供 LLM Provider 抽象、Agent 循环、会话管理、记忆与压缩等能力。
|
|
22
4
|
|
|
23
|
-
|
|
24
|
-
pnpm add @zhin.js/ai
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## 🚀 快速开始
|
|
28
|
-
|
|
29
|
-
### 1. 配置
|
|
30
|
-
|
|
31
|
-
在 `zhin.config.yml` 中添加配置:
|
|
32
|
-
|
|
33
|
-
```yaml
|
|
34
|
-
ai:
|
|
35
|
-
enabled: true
|
|
36
|
-
defaultProvider: openai
|
|
37
|
-
providers:
|
|
38
|
-
openai:
|
|
39
|
-
apiKey: sk-xxx
|
|
40
|
-
# baseUrl: https://api.openai.com/v1 # 可选,自定义 API 地址
|
|
41
|
-
anthropic:
|
|
42
|
-
apiKey: sk-ant-xxx
|
|
43
|
-
deepseek:
|
|
44
|
-
apiKey: sk-xxx
|
|
45
|
-
moonshot:
|
|
46
|
-
apiKey: sk-xxx # 月之暗面 API Key
|
|
47
|
-
zhipu:
|
|
48
|
-
apiKey: sk-xxx # 智谱 AI API Key
|
|
49
|
-
ollama:
|
|
50
|
-
baseUrl: http://localhost:11434 # 本地 Ollama 服务
|
|
51
|
-
sessions:
|
|
52
|
-
maxHistory: 200 # 最大历史消息数(数据库模式默认200)
|
|
53
|
-
expireMs: 604800000 # 会话过期时间(7天)
|
|
54
|
-
useDatabase: true # 使用数据库持久化(默认开启)
|
|
55
|
-
context:
|
|
56
|
-
enabled: true # 启用消息记录和智能上下文
|
|
57
|
-
maxRecentMessages: 100 # 读取最近消息数量
|
|
58
|
-
summaryThreshold: 50 # 触发自动总结的消息数量
|
|
59
|
-
keepAfterSummary: 10 # 总结后保留的最近消息数
|
|
60
|
-
maxContextTokens: 4000 # 上下文最大 token 估算
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### 2. 启用插件
|
|
64
|
-
|
|
65
|
-
```yaml
|
|
66
|
-
plugins:
|
|
67
|
-
- ai
|
|
68
|
-
```
|
|
5
|
+
不依赖任何 IM/Bot 概念,可独立用于 Web 后端、CLI 工具、自动化脚本等任意 Node.js 应用。
|
|
69
6
|
|
|
70
|
-
##
|
|
7
|
+
## 核心模块
|
|
71
8
|
|
|
72
|
-
|
|
9
|
+
### Provider(LLM 提供者)
|
|
73
10
|
|
|
74
|
-
|
|
11
|
+
统一的 LLM 提供者接口,内置多种主流模型支持:
|
|
75
12
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| 字段 | 类型 | 说明 |
|
|
79
|
-
|------|------|------|
|
|
80
|
-
| platform | text | 平台标识:icqq, kook, discord 等 |
|
|
81
|
-
| scene_id | text | 场景ID:群号/频道ID/用户ID |
|
|
82
|
-
| scene_type | text | 场景类型:group, private, channel |
|
|
83
|
-
| scene_name | text | 场景名称 |
|
|
84
|
-
| sender_id | text | 发送者ID |
|
|
85
|
-
| sender_name | text | 发送者名称 |
|
|
86
|
-
| message | text | 消息内容 |
|
|
87
|
-
| time | integer | 时间戳(毫秒) |
|
|
88
|
-
|
|
89
|
-
### 智能上下文
|
|
90
|
-
|
|
91
|
-
当使用 `/chat` 命令时:
|
|
92
|
-
|
|
93
|
-
1. **自动读取历史**:读取当前场景最近 100 条消息
|
|
94
|
-
2. **包含历史总结**:如果有之前的总结,会作为背景信息
|
|
95
|
-
3. **理解多人对话**:AI 能区分不同用户的发言
|
|
96
|
-
4. **自动总结**:当消息过多时自动总结,保持上下文简洁
|
|
13
|
+
```typescript
|
|
14
|
+
import { OpenAIProvider, OllamaProvider, AnthropicProvider } from '@zhin.js/ai'
|
|
97
15
|
|
|
98
|
-
|
|
16
|
+
const provider = new OpenAIProvider({
|
|
17
|
+
apiKey: 'sk-...',
|
|
18
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
19
|
+
model: 'gpt-4o',
|
|
20
|
+
contextWindow: 128000,
|
|
21
|
+
models: ['gpt-4o', 'gpt-4o-mini'],
|
|
22
|
+
capabilities: { vision: true, streaming: true, toolCalling: true },
|
|
23
|
+
})
|
|
99
24
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
maxRecentMessages: 100 # 读取最近消息数量
|
|
105
|
-
summaryThreshold: 50 # 超过此数量触发自动总结
|
|
106
|
-
keepAfterSummary: 10 # 总结后保留最近几条消息
|
|
107
|
-
maxContextTokens: 4000 # 上下文最大 token(估算)
|
|
25
|
+
const response = await provider.chat({
|
|
26
|
+
model: 'gpt-4o',
|
|
27
|
+
messages: [{ role: 'user', content: '你好' }],
|
|
28
|
+
})
|
|
108
29
|
```
|
|
109
30
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
AI 插件默认使用 Zhin 的数据库服务进行会话持久化存储,提供以下优势:
|
|
113
|
-
|
|
114
|
-
### 优势
|
|
115
|
-
|
|
116
|
-
- **更长的记忆能力**:数据库模式默认保存 200 条消息历史(内存模式 100 条)
|
|
117
|
-
- **持久化存储**:机器人重启后会话不丢失
|
|
118
|
-
- **更长的过期时间**:数据库模式默认 7 天过期(内存模式 24 小时)
|
|
119
|
-
- **自动切换**:数据库就绪时自动从内存切换到数据库存储
|
|
120
|
-
|
|
121
|
-
### 配置选项
|
|
122
|
-
|
|
123
|
-
```yaml
|
|
124
|
-
ai:
|
|
125
|
-
sessions:
|
|
126
|
-
# 最大历史消息数
|
|
127
|
-
# 数据库模式默认 200,内存模式默认 100
|
|
128
|
-
maxHistory: 200
|
|
129
|
-
|
|
130
|
-
# 会话过期时间(毫秒)
|
|
131
|
-
# 数据库模式默认 7 天,内存模式默认 24 小时
|
|
132
|
-
expireMs: 604800000
|
|
133
|
-
|
|
134
|
-
# 是否使用数据库持久化
|
|
135
|
-
# 默认 true,设为 false 使用内存存储
|
|
136
|
-
useDatabase: true
|
|
137
|
-
```
|
|
31
|
+
内置 Provider:
|
|
138
32
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
|
144
|
-
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `config` | json | 会话配置 |
|
|
148
|
-
| `created_at` | integer | 创建时间戳 |
|
|
149
|
-
| `updated_at` | integer | 更新时间戳 |
|
|
150
|
-
|
|
151
|
-
## 🎯 AI 触发方式
|
|
152
|
-
|
|
153
|
-
AI 插件提供独立的触发中间件,支持多种触发方式:
|
|
154
|
-
|
|
155
|
-
### 触发配置
|
|
156
|
-
|
|
157
|
-
```yaml
|
|
158
|
-
ai:
|
|
159
|
-
trigger:
|
|
160
|
-
enabled: true
|
|
161
|
-
prefixes: # 前缀触发
|
|
162
|
-
- '#'
|
|
163
|
-
- 'AI:'
|
|
164
|
-
- 'ai:'
|
|
165
|
-
respondToAt: true # @机器人触发
|
|
166
|
-
respondToPrivate: true # 私聊直接对话
|
|
167
|
-
ignorePrefixes: # 忽略的前缀(避免与命令冲突)
|
|
168
|
-
- '/'
|
|
169
|
-
- '!'
|
|
170
|
-
timeout: 60000 # 超时时间
|
|
171
|
-
# thinkingMessage: '🤔 思考中...' # 可选提示
|
|
172
|
-
```
|
|
33
|
+
| Provider | 说明 |
|
|
34
|
+
|----------|------|
|
|
35
|
+
| `OpenAIProvider` | OpenAI 及兼容 API |
|
|
36
|
+
| `DeepSeekProvider` | DeepSeek(继承 OpenAI) |
|
|
37
|
+
| `MoonshotProvider` | Moonshot / Kimi(继承 OpenAI) |
|
|
38
|
+
| `ZhipuProvider` | 智谱 GLM(继承 OpenAI) |
|
|
39
|
+
| `AnthropicProvider` | Anthropic Claude |
|
|
40
|
+
| `OllamaProvider` | Ollama 本地模型 |
|
|
173
41
|
|
|
174
|
-
###
|
|
42
|
+
### Agent(Agent 引擎)
|
|
175
43
|
|
|
176
|
-
|
|
177
|
-
# 使用 # 前缀触发
|
|
178
|
-
# 今天天气怎么样?
|
|
44
|
+
无状态的多轮 tool-calling 循环引擎:
|
|
179
45
|
|
|
180
|
-
|
|
181
|
-
|
|
46
|
+
```typescript
|
|
47
|
+
import { Agent, createAgent } from '@zhin.js/ai'
|
|
182
48
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
49
|
+
const agent = createAgent(provider, logger, {
|
|
50
|
+
maxIterations: 5,
|
|
51
|
+
timeout: 60000,
|
|
52
|
+
})
|
|
186
53
|
|
|
187
|
-
|
|
54
|
+
const result = await agent.run({
|
|
55
|
+
messages: [
|
|
56
|
+
{ role: 'system', content: '你是一个助手' },
|
|
57
|
+
{ role: 'user', content: '今天天气怎么样?' },
|
|
58
|
+
],
|
|
59
|
+
tools: [weatherTool],
|
|
60
|
+
})
|
|
61
|
+
```
|
|
188
62
|
|
|
189
|
-
|
|
63
|
+
### SessionManager(会话管理)
|
|
190
64
|
|
|
191
|
-
|
|
192
|
-
|------|------|------|
|
|
193
|
-
| `/ai.models` | 列出可用模型 | `/ai.models` |
|
|
194
|
-
| `/ai.clear` | 清除对话历史 | `/ai.clear` |
|
|
195
|
-
| `/ai.stats` | 查看场景消息统计 | `/ai.stats` |
|
|
196
|
-
| `/ai.tools` | 列出所有可用工具 | `/ai.tools` |
|
|
197
|
-
| `/ai.summary` | 生成对话总结 | `/ai.summary` |
|
|
198
|
-
| `/ai.health` | 检查 AI 服务健康状态 | `/ai.health` |
|
|
65
|
+
管理对话会话的创建、检索和过期:
|
|
199
66
|
|
|
200
|
-
|
|
67
|
+
```typescript
|
|
68
|
+
import { createMemorySessionManager, createDatabaseSessionManager } from '@zhin.js/ai'
|
|
201
69
|
|
|
202
|
-
|
|
70
|
+
// 内存模式
|
|
71
|
+
const sessionManager = createMemorySessionManager({
|
|
72
|
+
maxHistory: 50,
|
|
73
|
+
expireMs: 3600000,
|
|
74
|
+
})
|
|
203
75
|
|
|
76
|
+
// 数据库持久化模式
|
|
77
|
+
const dbSessionManager = createDatabaseSessionManager(databaseModel, {
|
|
78
|
+
maxHistory: 50,
|
|
79
|
+
expireMs: 3600000,
|
|
80
|
+
})
|
|
204
81
|
```
|
|
205
|
-
# 基本对话(AI 能看到之前的群聊记录)
|
|
206
|
-
/chat 刚才大家在讨论什么?
|
|
207
82
|
|
|
208
|
-
|
|
209
|
-
/chat -n 你好,我们重新开始
|
|
83
|
+
### ContextManager(上下文管理)
|
|
210
84
|
|
|
211
|
-
|
|
212
|
-
/chat -s
|
|
213
|
-
```
|
|
85
|
+
管理消息记录和上下文摘要:
|
|
214
86
|
|
|
215
|
-
|
|
87
|
+
```typescript
|
|
88
|
+
import { createContextManager } from '@zhin.js/ai'
|
|
216
89
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
90
|
+
const contextManager = createContextManager(logger, {
|
|
91
|
+
enabled: true,
|
|
92
|
+
maxMessagesBeforeSummary: 100,
|
|
93
|
+
summaryRetentionDays: 30,
|
|
94
|
+
})
|
|
220
95
|
```
|
|
221
96
|
|
|
222
|
-
|
|
97
|
+
### ConversationMemory(对话记忆)
|
|
223
98
|
|
|
224
|
-
|
|
99
|
+
双层记忆系统:短期滑动窗口 + 长期链式摘要。
|
|
225
100
|
|
|
226
101
|
```typescript
|
|
227
|
-
import {
|
|
228
|
-
|
|
229
|
-
const plugin = usePlugin();
|
|
230
|
-
|
|
231
|
-
// 获取 AI 服务
|
|
232
|
-
plugin.useContext('ai', async (ai) => {
|
|
233
|
-
// 简单问答
|
|
234
|
-
const answer = await ai.ask('什么是 TypeScript?');
|
|
235
|
-
console.log(answer);
|
|
236
|
-
|
|
237
|
-
// 指定模型
|
|
238
|
-
const answer2 = await ai.ask('写一首诗', {
|
|
239
|
-
provider: 'anthropic',
|
|
240
|
-
model: 'claude-opus-4-20250514',
|
|
241
|
-
temperature: 0.9,
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
```
|
|
102
|
+
import { ConversationMemory } from '@zhin.js/ai'
|
|
245
103
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// 多轮对话
|
|
253
|
-
await ai.chatWithSession(sessionId, '我叫小明');
|
|
254
|
-
const response = await ai.chatWithSession(sessionId, '我叫什么?');
|
|
255
|
-
// response: "你叫小明"
|
|
256
|
-
|
|
257
|
-
// 流式响应
|
|
258
|
-
const stream = await ai.chatWithSession(sessionId, '讲个故事', { stream: true });
|
|
259
|
-
for await (const chunk of stream) {
|
|
260
|
-
process.stdout.write(chunk);
|
|
261
|
-
}
|
|
262
|
-
});
|
|
104
|
+
const memory = new ConversationMemory(provider, logger, {
|
|
105
|
+
shortTermWindow: 5,
|
|
106
|
+
minTopicRounds: 3,
|
|
107
|
+
topicChangeThreshold: 0.5,
|
|
108
|
+
})
|
|
263
109
|
```
|
|
264
110
|
|
|
265
|
-
###
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
plugin.useContext('ai', async (ai) => {
|
|
269
|
-
// 使用内置工具
|
|
270
|
-
const result = await ai.runAgent('计算 sin(45°) 的值');
|
|
271
|
-
console.log(result.content);
|
|
272
|
-
console.log('使用的工具:', result.toolCalls);
|
|
273
|
-
|
|
274
|
-
// 自定义工具
|
|
275
|
-
const agent = ai.createAgent({
|
|
276
|
-
model: 'gpt-4o',
|
|
277
|
-
tools: [{
|
|
278
|
-
name: 'search_database',
|
|
279
|
-
description: '搜索数据库',
|
|
280
|
-
parameters: {
|
|
281
|
-
type: 'object',
|
|
282
|
-
properties: {
|
|
283
|
-
query: { type: 'string', description: '搜索关键词' }
|
|
284
|
-
},
|
|
285
|
-
required: ['query']
|
|
286
|
-
},
|
|
287
|
-
async execute(args) {
|
|
288
|
-
// 实现搜索逻辑
|
|
289
|
-
return { results: ['结果1', '结果2'] };
|
|
290
|
-
}
|
|
291
|
-
}]
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
const result2 = await agent.run('搜索用户张三的信息');
|
|
295
|
-
});
|
|
296
|
-
```
|
|
111
|
+
### Compaction(上下文压缩)
|
|
297
112
|
|
|
298
|
-
|
|
113
|
+
管理上下文窗口,防止 token 超限:
|
|
299
114
|
|
|
300
115
|
```typescript
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
process.stdout.write(event.data);
|
|
308
|
-
break;
|
|
309
|
-
case 'tool_call':
|
|
310
|
-
console.log(`\n调用工具: ${event.data.name}`);
|
|
311
|
-
break;
|
|
312
|
-
case 'tool_result':
|
|
313
|
-
console.log(`工具结果: ${event.data.result}`);
|
|
314
|
-
break;
|
|
315
|
-
case 'done':
|
|
316
|
-
console.log('\n完成:', event.data.usage);
|
|
317
|
-
break;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
```
|
|
116
|
+
import {
|
|
117
|
+
estimateTokens,
|
|
118
|
+
evaluateContextWindowGuard,
|
|
119
|
+
pruneHistoryForContext,
|
|
120
|
+
compactSession,
|
|
121
|
+
} from '@zhin.js/ai'
|
|
322
122
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
| `get_weather` | 获取天气(模拟数据) |
|
|
330
|
-
| `web_search` | 网页搜索(需要配置 API) |
|
|
331
|
-
| `http_request` | HTTP 请求 |
|
|
332
|
-
| `run_code` | 执行 JavaScript 代码 |
|
|
333
|
-
|
|
334
|
-
### 添加自定义工具
|
|
335
|
-
|
|
336
|
-
```typescript
|
|
337
|
-
import { createCalculatorTool, createTimeTool } from '@zhin.js/ai';
|
|
338
|
-
|
|
339
|
-
const myTool = {
|
|
340
|
-
name: 'my_tool',
|
|
341
|
-
description: '我的自定义工具',
|
|
342
|
-
parameters: {
|
|
343
|
-
type: 'object',
|
|
344
|
-
properties: {
|
|
345
|
-
input: { type: 'string' }
|
|
346
|
-
}
|
|
347
|
-
},
|
|
348
|
-
async execute(args) {
|
|
349
|
-
return `处理结果: ${args.input}`;
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const agent = ai.createAgent({
|
|
354
|
-
tools: [myTool],
|
|
355
|
-
useBuiltinTools: true, // 同时使用内置工具
|
|
356
|
-
});
|
|
123
|
+
const guard = evaluateContextWindowGuard({
|
|
124
|
+
messages: history,
|
|
125
|
+
maxContextTokens: 128000,
|
|
126
|
+
maxHistoryShare: 0.5,
|
|
127
|
+
})
|
|
128
|
+
// guard.status: 'ok' | 'warning' | 'critical'
|
|
357
129
|
```
|
|
358
130
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
AI 插件提供统一的工具服务,支持 Tool ↔ Command 双向转换:
|
|
131
|
+
### Output(输出解析)
|
|
362
132
|
|
|
363
|
-
|
|
133
|
+
将 AI 文本回复解析为结构化元素:
|
|
364
134
|
|
|
365
135
|
```typescript
|
|
366
|
-
import {
|
|
367
|
-
|
|
368
|
-
const plugin = usePlugin();
|
|
369
|
-
|
|
370
|
-
// 使用链式调用定义工具
|
|
371
|
-
const weatherTool = new ZhinTool('weather')
|
|
372
|
-
.desc('查询天气信息')
|
|
373
|
-
.param('city', { type: 'string', description: '城市名称' }, true)
|
|
374
|
-
.param('days', { type: 'number', description: '预报天数' })
|
|
375
|
-
.platform('qq', 'telegram') // 限定平台
|
|
376
|
-
.scope('group', 'private') // 限定场景
|
|
377
|
-
.permission('user') // 权限级别
|
|
378
|
-
// AI 调用时执行
|
|
379
|
-
.execute(async (args, ctx) => {
|
|
380
|
-
return `${args.city} 的天气是晴天`;
|
|
381
|
-
})
|
|
382
|
-
// 可选:生成命令(与 MessageCommand.action 一致)
|
|
383
|
-
.action(async (message, result) => {
|
|
384
|
-
return `天气查询: ${result.params.city}`;
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
plugin.addTool(weatherTool);
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
### 使用 defineTool 辅助函数
|
|
136
|
+
import { parseOutput, renderToPlainText } from '@zhin.js/ai'
|
|
391
137
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const plugin = usePlugin();
|
|
396
|
-
|
|
397
|
-
const calculatorTool = defineTool<{ expression: string }>({
|
|
398
|
-
name: 'calculator',
|
|
399
|
-
description: '计算数学表达式',
|
|
400
|
-
parameters: {
|
|
401
|
-
type: 'object',
|
|
402
|
-
properties: {
|
|
403
|
-
expression: {
|
|
404
|
-
type: 'string',
|
|
405
|
-
description: '数学表达式',
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
required: ['expression'],
|
|
409
|
-
},
|
|
410
|
-
// 可选:命令配置
|
|
411
|
-
command: {
|
|
412
|
-
pattern: 'calc <expression:rest>',
|
|
413
|
-
alias: ['计算'],
|
|
414
|
-
usage: ['计算数学表达式'],
|
|
415
|
-
},
|
|
416
|
-
execute: async (args) => {
|
|
417
|
-
// args.expression 有完整类型提示
|
|
418
|
-
const result = eval(args.expression);
|
|
419
|
-
return `结果: ${result}`;
|
|
420
|
-
},
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
plugin.addTool(calculatorTool);
|
|
138
|
+
const elements = parseOutput(aiResponse)
|
|
139
|
+
const text = renderToPlainText(elements)
|
|
424
140
|
```
|
|
425
141
|
|
|
426
|
-
|
|
142
|
+
支持的元素类型:`TextElement`、`ImageElement`、`AudioElement`、`VideoElement`、`CardElement`、`FileElement`。
|
|
427
143
|
|
|
428
|
-
|
|
144
|
+
### RateLimiter(速率限制)
|
|
429
145
|
|
|
430
146
|
```typescript
|
|
431
|
-
|
|
432
|
-
.desc('管理员操作')
|
|
433
|
-
.permission('bot_admin') // 需要机器人管理员权限
|
|
434
|
-
.scope('group') // 仅在群聊可用
|
|
435
|
-
.execute(async (args) => {
|
|
436
|
-
return '操作成功';
|
|
437
|
-
});
|
|
438
|
-
```
|
|
147
|
+
import { RateLimiter } from '@zhin.js/ai'
|
|
439
148
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
- `bot_admin` - 机器人管理员
|
|
445
|
-
- `owner` - Zhin 拥有者
|
|
149
|
+
const limiter = new RateLimiter({
|
|
150
|
+
maxRequests: 10,
|
|
151
|
+
windowMs: 60000,
|
|
152
|
+
})
|
|
446
153
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
```
|
|
452
|
-
# AI 可以在回复中使用:
|
|
453
|
-
|
|
454
|
-
<image url="https://example.com/cat.jpg"/> # 图片
|
|
455
|
-
<video url="https://example.com/video.mp4"/> # 视频
|
|
456
|
-
<audio url="https://example.com/song.mp3"/> # 音频
|
|
457
|
-
<at user_id="123456"/> # @用户
|
|
458
|
-
<face id="178"/> # 表情
|
|
459
|
-
|
|
460
|
-
# 混合使用
|
|
461
|
-
今天天气不错!<image url="https://weather.com/sunny.jpg"/>
|
|
154
|
+
const result = limiter.check('user-123')
|
|
155
|
+
if (!result.allowed) {
|
|
156
|
+
console.log(`请等待 ${result.retryAfterMs}ms`)
|
|
157
|
+
}
|
|
462
158
|
```
|
|
463
159
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
## 🔌 支持的模型
|
|
467
|
-
|
|
468
|
-
### OpenAI
|
|
469
|
-
- gpt-4o, gpt-4o-mini
|
|
470
|
-
- gpt-4-turbo, gpt-4
|
|
471
|
-
- gpt-3.5-turbo
|
|
472
|
-
- o1, o1-mini, o1-preview, o3-mini
|
|
160
|
+
### Storage(存储抽象)
|
|
473
161
|
|
|
474
|
-
|
|
475
|
-
- claude-opus-4-20250514
|
|
476
|
-
- claude-sonnet-4-20250514
|
|
477
|
-
- claude-3-7-sonnet-20250219
|
|
478
|
-
- claude-3-5-sonnet-20241022
|
|
479
|
-
- claude-3-5-haiku-20241022
|
|
480
|
-
|
|
481
|
-
### DeepSeek
|
|
482
|
-
- deepseek-chat
|
|
483
|
-
- deepseek-coder
|
|
484
|
-
- deepseek-reasoner
|
|
485
|
-
|
|
486
|
-
### Moonshot (月之暗面)
|
|
487
|
-
- moonshot-v1-8k
|
|
488
|
-
- moonshot-v1-32k
|
|
489
|
-
- moonshot-v1-128k
|
|
490
|
-
|
|
491
|
-
### 智谱 AI
|
|
492
|
-
- glm-4-plus, glm-4
|
|
493
|
-
- glm-4-air, glm-4-flash
|
|
494
|
-
- glm-4v-plus
|
|
495
|
-
|
|
496
|
-
### Ollama (本地)
|
|
497
|
-
- llama3.3, llama3.2, llama3.1
|
|
498
|
-
- qwen2.5, qwen2.5-coder
|
|
499
|
-
- deepseek-r1, deepseek-v3
|
|
500
|
-
- mistral, mixtral
|
|
501
|
-
- phi4, gemma2
|
|
502
|
-
|
|
503
|
-
## 📚 类型扩展
|
|
162
|
+
统一存储后端,支持内存和数据库模式,可在运行时热切换:
|
|
504
163
|
|
|
505
164
|
```typescript
|
|
506
|
-
|
|
507
|
-
namespace Plugin {
|
|
508
|
-
interface Contexts {
|
|
509
|
-
ai: import('@zhin.js/ai').AIService;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
## 🔗 与 MCP 集成
|
|
165
|
+
import { MemoryStorageBackend, createSwappableBackend } from '@zhin.js/ai'
|
|
516
166
|
|
|
517
|
-
|
|
167
|
+
const backend = createSwappableBackend(new MemoryStorageBackend())
|
|
518
168
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
server.registerTool('ai_chat', {
|
|
522
|
-
description: '与 AI 对话',
|
|
523
|
-
inputSchema: z.object({
|
|
524
|
-
message: z.string(),
|
|
525
|
-
}),
|
|
526
|
-
}, async (args) => {
|
|
527
|
-
const ai = plugin.inject('ai');
|
|
528
|
-
const response = await ai.ask(args.message);
|
|
529
|
-
return { content: [{ type: 'text', text: response }] };
|
|
530
|
-
});
|
|
169
|
+
// 运行时切换到数据库
|
|
170
|
+
backend.swap(new DatabaseStorageBackend(model))
|
|
531
171
|
```
|
|
532
172
|
|
|
533
|
-
##
|
|
173
|
+
## 主要导出
|
|
534
174
|
|
|
535
|
-
|
|
175
|
+
| 导出 | 说明 |
|
|
176
|
+
|------|------|
|
|
177
|
+
| `OpenAIProvider` / `AnthropicProvider` / `OllamaProvider` | LLM 提供者 |
|
|
178
|
+
| `Agent` / `createAgent` | Agent 引擎 |
|
|
179
|
+
| `SessionManager` | 会话管理 |
|
|
180
|
+
| `ContextManager` | 上下文管理 |
|
|
181
|
+
| `ConversationMemory` | 对话记忆 |
|
|
182
|
+
| `compactSession` / `pruneHistoryForContext` | 上下文压缩 |
|
|
183
|
+
| `parseOutput` / `renderToPlainText` | 输出解析 |
|
|
184
|
+
| `RateLimiter` | 速率限制 |
|
|
185
|
+
| `detectTone` | 情绪检测 |
|
|
186
|
+
| `MemoryStorageBackend` / `createSwappableBackend` | 存储抽象 |
|
|
187
|
+
|
|
188
|
+
## 安装
|
|
536
189
|
|
|
537
|
-
```
|
|
538
|
-
ai
|
|
539
|
-
providers:
|
|
540
|
-
openai:
|
|
541
|
-
apiKey: sk-xxx
|
|
542
|
-
baseUrl: https://your-proxy.com/v1
|
|
190
|
+
```bash
|
|
191
|
+
pnpm add @zhin.js/ai
|
|
543
192
|
```
|
|
544
193
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
```typescript
|
|
548
|
-
import { OpenAIProvider } from '@zhin.js/ai';
|
|
549
|
-
|
|
550
|
-
// 创建自定义 provider
|
|
551
|
-
const customProvider = new OpenAIProvider({
|
|
552
|
-
apiKey: 'xxx',
|
|
553
|
-
baseUrl: 'https://api.custom.com/v1',
|
|
554
|
-
headers: {
|
|
555
|
-
'X-Custom-Header': 'value'
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
ai.registerProvider(customProvider);
|
|
560
|
-
```
|
|
194
|
+
> 也可通过 `zhin.js` 或 `@zhin.js/agent` 间接引入。
|
|
561
195
|
|
|
562
|
-
##
|
|
196
|
+
## 许可证
|
|
563
197
|
|
|
564
|
-
MIT
|
|
198
|
+
MIT License
|