@h-ai/cli 0.1.0-alpha.18 → 0.1.0-alpha.20

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 (77) hide show
  1. package/dist/{chunk-BPO34NRL.js → chunk-3BBXDQ4Y.js} +5 -5
  2. package/dist/chunk-3BBXDQ4Y.js.map +1 -0
  3. package/dist/cli-config-templates-IGGO7P45.js +5 -0
  4. package/dist/{cli-config-templates-JCS7T3NU.js.map → cli-config-templates-IGGO7P45.js.map} +1 -1
  5. package/dist/index.js +67 -39
  6. package/dist/index.js.map +1 -1
  7. package/dist/{src-N4NPS7AG.js → src-QNEJJ3BV.js} +261 -103
  8. package/dist/src-QNEJJ3BV.js.map +1 -0
  9. package/package.json +2 -2
  10. package/templates/apps/admin/messages/en-US.json +5 -0
  11. package/templates/apps/admin/messages/zh-CN.json +5 -0
  12. package/templates/apps/admin/src/routes/+layout.svelte.hbs +5 -5
  13. package/templates/apps/admin/src/routes/+page.svelte.hbs +32 -12
  14. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +37 -20
  15. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
  16. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
  17. package/templates/apps/android-app/src/lib/api.ts.hbs +5 -4
  18. package/templates/apps/android-app/src/lib/capacitor.ts +1 -1
  19. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +11 -10
  20. package/templates/apps/android-app/src/routes/+page.svelte.hbs +17 -6
  21. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +4 -1
  22. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +14 -0
  23. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +13 -0
  24. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +3 -0
  25. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server-app.ts.hbs +23 -3
  26. package/templates/apps/h5/messages/en-US.json +3 -0
  27. package/templates/apps/h5/messages/zh-CN.json +3 -0
  28. package/templates/apps/h5/src/routes/+layout.svelte.hbs +30 -29
  29. package/templates/apps/h5/src/routes/+page.svelte.hbs +17 -6
  30. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
  31. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
  32. package/templates/apps/website/src/routes/+layout.svelte.hbs +35 -26
  33. package/templates/apps/website/src/routes/+page.svelte.hbs +28 -10
  34. package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
  35. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +37 -34
  36. package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
  37. package/templates/base/package.json.hbs +30 -24
  38. package/templates/base/src/app.html.hbs +4 -0
  39. package/templates/base/src/hooks.server.ts.hbs +17 -7
  40. package/templates/base/src/lib/server/init.ts.hbs +20 -12
  41. package/templates/base/static/favicon.png +0 -0
  42. package/templates/base/tests/scaffold.test.ts.hbs +9 -1
  43. package/templates/base/vite.config.ts.hbs +3 -3
  44. package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +5 -5
  45. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +34 -32
  46. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +46 -48
  47. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +35 -31
  48. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +41 -38
  49. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +15 -7
  50. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +1 -2
  51. package/templates/skills/AGENTS.md +11 -1
  52. package/templates/skills/CLAUDE.md +2 -1
  53. package/templates/skills/copilot-instructions.md +22 -6
  54. package/templates/skills/hai-ai/SKILL.md +115 -646
  55. package/templates/skills/hai-ai/reference.md +197 -0
  56. package/templates/skills/hai-api-client/SKILL.md +7 -1
  57. package/templates/skills/hai-app-create/SKILL.md +1 -1
  58. package/templates/skills/hai-app-review/SKILL.md +1 -1
  59. package/templates/skills/hai-audit/SKILL.md +7 -2
  60. package/templates/skills/hai-cache/SKILL.md +2 -0
  61. package/templates/skills/hai-capacitor/SKILL.md +11 -9
  62. package/templates/skills/hai-core/SKILL.md +4 -1
  63. package/templates/skills/hai-crypto/SKILL.md +42 -8
  64. package/templates/skills/hai-deploy/SKILL.md +12 -9
  65. package/templates/skills/hai-iam/SKILL.md +2 -0
  66. package/templates/skills/hai-kit/SKILL.md +14 -5
  67. package/templates/skills/hai-payment/SKILL.md +5 -0
  68. package/templates/skills/hai-reach/SKILL.md +3 -1
  69. package/templates/skills/hai-reldb/SKILL.md +2 -0
  70. package/templates/skills/hai-scheduler/SKILL.md +2 -0
  71. package/templates/skills/hai-serv/SKILL.md +5 -0
  72. package/templates/skills/hai-storage/SKILL.md +10 -1
  73. package/templates/skills/hai-ui/SKILL.md +25 -11
  74. package/templates/skills/hai-vecdb/SKILL.md +8 -1
  75. package/dist/chunk-BPO34NRL.js.map +0 -1
  76. package/dist/cli-config-templates-JCS7T3NU.js +0 -5
  77. package/dist/src-N4NPS7AG.js.map +0 -1
@@ -3,733 +3,202 @@ name: hai-ai
3
3
  description: 使用 @h-ai/ai 进行 LLM 调用(OpenAI 兼容)、MCP 服务器创建、工具定义与注册、流式处理、记忆管理(objectId 隔离)、上下文压缩与会话持久化;当需求涉及 AI 对话、工具调用、MCP 协议、流式响应、记忆提取注入、上下文摘要压缩、会话管理或 AI 客户端时使用。
4
4
  ---
5
5
 
6
- # hai-ai
6
+ # hai-ai — @h-ai/ai 快速指南
7
7
 
8
- > `@h-ai/ai` 提供统一的 AI 能力,支持 LLM 调用(OpenAI 兼容 API)、MCP 服务器、工具定义与注册、流式处理、记忆管理(objectId 隔离)、上下文压缩与会话持久化。支持 Node.js 与浏览器双端。
8
+ `@h-ai/ai` 统一提供 LLM、工具、MCP、Embedding、Memory、Retrieval/RAG、Knowledge、Context、File、Rerank 与 A2A 能力。
9
9
 
10
- ---
11
-
12
- ## 运行环境
13
-
14
- | 能力 | Node.js | 浏览器 |
15
- |------|---------|--------|
16
- | `ai.llm` LLM 调用 | ✅ | ❌(通过 API 端点代理) |
17
- | `ai.mcp` MCP 服务器 | ✅ | ❌ |
18
- | `ai.tools` 工具定义 | ✅ | ✅(纯函数,无需 init) |
19
- | `ai.stream` 流处理 | ✅ | ✅(纯函数,无需 init) |
20
- | `ai.memory` / `ai.conversation` | ✅ | ❌(通过 API 查询) |
21
- | `ai.knowledge` 知识库 | ✅ | ❌(通过 API 查询) |
10
+ > 详细 API 表、错误码与长示例见同目录 `reference.md`。只有需要完整契约或边界用例时再读取,避免把长参考塞进上下文。
22
11
 
23
- 浏览器端消费 AI 能力的标准模式:通过 `@h-ai/api-client` 的 typed contract 调用 `apiClient.ai.chats.*`;如需 SSE 流式输出,由应用显式暴露自定义流式 endpoint,再用 `fetch` / `apiFetch` 消费。
12
+ ## 使用边界
24
13
 
25
- ---
14
+ - `ai.tools`、`ai.stream` 是纯函数能力,无需 `ai.init()`。
15
+ - `ai.llm`、`ai.embedding`、`ai.memory`、`ai.retrieval`、`ai.rag`、`ai.knowledge`、`ai.context`、`ai.a2a` 需要先 `await ai.init(...)`。
16
+ - 默认 DB Provider 需要在 `ai.init()` 前完成 `reldb.init()` 与 `vecdb.init()`;自定义 `AIStoreProvider` 可跳过这两个依赖。
17
+ - 浏览器端不要直接调用 Node-only 能力;通过 `@h-ai/api-client` 或应用自定义 API/SSE endpoint 代理。
18
+ - 公共 API 返回 `HaiResult<T>` 时按 `if (!result.success) return result` 处理;不要用 `try/catch` 包裹正常业务错误。
26
19
 
27
- ## 依赖
20
+ ## 初始化与关闭
28
21
 
29
- | 模块 | 用途 | 是否必需 | 初始化要求 |
30
- | --- | --- | --- | --- |
31
- | `@h-ai/reldb` | 数据库(对话记录/会话/记忆/知识库持久化) | **必需** | 需在 `ai.init()` 前初始化 |
32
- | `@h-ai/vecdb` | 向量数据库(记忆向量检索/知识库检索) | **必需** | 需在 `ai.init()` 前初始化 |
33
- | `@h-ai/datapipe` | 数据管道(知识库文档切分) | 内部使用 | 无需手动初始化 |
22
+ ```ts
23
+ import { ai } from '@h-ai/ai'
24
+ import { reldb } from '@h-ai/reldb'
25
+ import { vecdb } from '@h-ai/vecdb'
34
26
 
35
- > `ai.tools` 和 `ai.stream` 为纯函数子系统,无需 init 即可使用。
27
+ await reldb.init(core.config.get('db'))
28
+ await vecdb.init(core.config.get('vecdb'))
36
29
 
37
- ---
30
+ const init = await ai.init(core.config.get('ai'))
31
+ if (!init.success) return init
38
32
 
39
- ## 适用场景
33
+ // ... 使用 ai.llm / ai.memory / ai.knowledge 等
40
34
 
41
- - 调用 LLM 进行对话(非流式/流式)
42
- - 定义和执行工具(Function Calling)
43
- - 创建 MCP 服务器(Streamable HTTP/SSE/Stdio)
44
- - 注册 MCP 资源与提示词
45
- - 自动提取和管理对话记忆
46
- - 上下文压缩与 Token 控制
47
- - 会话持久化与恢复(配合 reldb/vecdb)
48
- - 前端 AI 客户端集成(记忆/会话查询)
35
+ await ai.close()
36
+ ```
49
37
 
50
- ---
38
+ 自定义存储:
51
39
 
52
- ## 使用步骤
40
+ ```ts
41
+ await ai.init(core.config.get('ai'), { storeProvider: myProvider })
42
+ await ai.close()
43
+ ```
53
44
 
54
- ### 1. 配置
45
+ ## 配置要点
55
46
 
56
47
  ```yaml
57
- # config/_ai.yml
58
48
  llm:
59
49
  apiKey: ${HAI_AI_LLM_API_KEY:}
60
50
  baseUrl: ${HAI_AI_LLM_BASE_URL:https://api.openai.com/v1}
61
51
  model: ${HAI_AI_LLM_MODEL:gpt-4o-mini}
62
- maxTokens: ${HAI_AI_LLM_MAX_TOKENS:4096}
63
- temperature: 0.7
64
52
  timeout: 60000
53
+ scenarios:
54
+ chat: fast
55
+ reasoning: strong
56
+ embedding: embed
57
+
58
+ embedding:
59
+ dimensions: 1536
60
+ batchSize: 100
65
61
 
66
- # 存储配置(可选)
67
- store:
68
- mode: memory # memory | persistent(需 reldb + vecdb 已初始化)
69
-
70
- # 记忆管理(可选)
71
- memory:
72
- maxEntries: 1000 # 最大记忆条数
73
- extractModel: gpt-4o-mini # 提取用模型(默认用 LLM 配置模型)
74
- apiKey: # 可选,覆盖 LLM apiKey
75
- baseUrl: # 可选,覆盖 LLM baseUrl
76
- recencyDecay: 0.95 # 时间衰减系数
77
- embeddingEnabled: true # 启用向量检索
78
- defaultTopK: 10 # 默认检索数量
79
-
80
- # Token 估算(可选)
81
- token:
82
- tokenRatio: 0.25 # Token 估算系数(4 字符 ≈ 1 token)
83
-
84
- # 摘要生成(可选)
85
- summary:
86
- systemPrompt: # 自定义摘要系统提示词
87
-
88
- # 上下文压缩(可选)
89
- compress:
90
- defaultStrategy: hybrid # 压缩策略:summary | sliding-window | hybrid
91
- defaultMaxTokens: 0 # 0 = 取模型 maxTokens 的 80%
92
- preserveLastN: 4 # 保留最近 N 条消息
93
-
94
- # 知识库(可选)
95
62
  knowledge:
96
63
  collection: hai_ai_knowledge
97
64
  dimension: 1536
98
- enableEntityExtraction: true
99
- cleanOptions:
100
- removeHtml: true
101
- normalizeWhitespace: true
102
65
  chunkOptions:
103
- mode: markdown # sentence | paragraph | markdown | page | custom
66
+ mode: markdown
104
67
  maxSize: 1500
105
68
  overlap: 200
106
69
  ```
107
70
 
108
- ### 2. 初始化与关闭
71
+ `ai.config` 是脱敏快照;`apiKey`、`privateKey`、URL 内嵌凭证会被隐藏。
109
72
 
110
- ```typescript
111
- import { ai } from '@h-ai/ai'
112
- import { reldb } from '@h-ai/reldb'
113
- import { vecdb } from '@h-ai/vecdb'
73
+ ## 常用 API
114
74
 
115
- // 先初始化依赖
116
- await reldb.init(core.config.get('db'))
117
- await vecdb.init(core.config.get('vecdb'))
75
+ | 场景 | 首选 API | 备注 |
76
+ | --- | --- | --- |
77
+ | 非流式对话 | `ai.llm.chat({ messages })` | OpenAI 兼容 Chat Completion |
78
+ | 流式对话 | `ai.llm.chatStream({ messages })` | 返回 `AsyncIterable` |
79
+ | 工具定义 | `ai.tools.define(...)` | Zod schema 转 JSON Schema |
80
+ | 工具执行 | `registry.executeAll(toolCalls)` | 支持并行执行 |
81
+ | MCP 服务 | `createMcpServer(...)` | 按需连接 HTTP/SSE/Stdio transport |
82
+ | Embedding | `ai.embedding.embedText(text)` | 批量用 `embedBatch` |
83
+ | 记忆 | `ai.memory.extract/recall/injectMemories` | 用 `objectId` 做主体隔离 |
84
+ | Retrieval/RAG | `ai.retrieval.retrieve` / `ai.rag.query` | Retrieval source 先注册或由配置预置 |
85
+ | Knowledge | `ai.knowledge.setup/ingest/ask` | 入库前会调用 datapipe 清洗分块 |
86
+ | Context | `ai.context.createManager` | 编排 LLM + Memory + RAG + 压缩 |
87
+ | A2A | `ai.a2a.registerExecutor/handleRequest` | 延迟初始化 SDK handler |
118
88
 
119
- // 再初始化 AI 模块(自动使用已初始化的 reldb 和 vecdb 单例)
120
- ai.init(core.config.get('ai'))
121
- // 使用后
122
- ai.close()
123
- ```
89
+ ## LLM + 工具调用
124
90
 
125
- **特殊说明**:`ai.tools` 和 `ai.stream` 无需 init 即可使用;`ai.llm` 和 `ai.mcp` 操作需要先 init。
126
-
127
- ---
128
-
129
- ## 核心 API
91
+ ```ts
92
+ const registry = ai.tools.createRegistry()
93
+ registry.register(ai.tools.define({
94
+ name: 'get_weather',
95
+ description: '获取天气',
96
+ parameters: z.object({ city: z.string() }),
97
+ handler: async ({ city }) => ({ city, temperature: 20 }),
98
+ }))
130
99
 
131
- ### LLM 操作 — `ai.llm`
100
+ const messages: ChatMessage[] = [{ role: 'user', content: '北京天气?' }]
101
+ let result = await ai.llm.chat({ messages, tools: registry.getDefinitions() })
132
102
 
133
- | 方法 | 签名 | 说明 |
134
- | ------------ | ------------------------------------------------------ | ---------------- |
135
- | `chat` | `(options) => Promise<HaiResult<ChatCompletionResponse>>` | 对话(非流式) |
136
- | `chatStream` | `(options) => AsyncIterable<ChatCompletionChunk>` | 对话(流式) |
137
- | `listModels` | `() => Promise<HaiResult<string[]>>` | 获取可用模型列表 |
103
+ while (result.success && result.data.choices[0]?.finish_reason === 'tool_calls') {
104
+ const assistant = result.data.choices[0].message
105
+ const toolCalls = assistant.tool_calls ?? []
106
+ messages.push(assistant)
138
107
 
139
- ```typescript
140
- // 非流式
141
- const result = await ai.llm.chat({
142
- messages: [
143
- { role: 'system', content: '你是一个有帮助的助手' },
144
- { role: 'user', content: '你好' },
145
- ],
146
- tools: registry.getDefinitions(), // 可选
147
- })
148
- if (result.success) {
149
- const message = result.data.choices[0].message
150
- }
108
+ const toolMessages = await registry.executeAll(toolCalls, { parallel: true })
109
+ if (!toolMessages.success) return toolMessages
110
+ messages.push(...toolMessages.data)
151
111
 
152
- // 流式
153
- for await (const chunk of ai.llm.chatStream({ messages })) {
154
- const delta = chunk.choices[0]?.delta?.content
155
- if (delta)
156
- process.stdout.write(delta)
112
+ result = await ai.llm.chat({ messages, tools: registry.getDefinitions() })
157
113
  }
158
114
  ```
159
115
 
160
- ### 工具定义 — `ai.tools`
161
-
162
- ```typescript
163
- import { ai } from '@h-ai/ai'
164
- import { z } from 'zod'
165
-
166
- // 定义工具(Zod Schema 自动转 JSON Schema)
167
- const weatherTool = ai.tools.define({
168
- name: 'get_weather',
169
- description: '获取天气信息',
170
- parameters: z.object({
171
- city: z.string().describe('城市名称'),
172
- unit: z.enum(['celsius', 'fahrenheit']).optional(),
173
- }),
174
- handler: async ({ city, unit }) => {
175
- return { temperature: 20, city, unit: unit ?? 'celsius' }
176
- },
177
- })
178
-
179
- // 注册表管理
180
- const registry = ai.tools.createRegistry()
181
- registry.register(weatherTool)
182
-
183
- // 获取 OpenAI 工具定义(传递给 LLM)
184
- const definitions = registry.getDefinitions()
185
-
186
- // 执行 LLM 返回的工具调用
187
- const toolMessage = await registry.execute(toolCall)
188
- const toolMessages = await registry.executeAll(toolCalls, { parallel: true })
189
- ```
190
-
191
- > `ai.tools.define` 和 `ai.tools.createRegistry` 也可通过 `defineTool` / `createToolRegistry` 直接导入,两者等价。
192
-
193
- ### 流处理 — `ai.stream`
194
-
195
- ```typescript
196
- import { ai } from '@h-ai/ai'
116
+ ## 流式处理
197
117
 
118
+ ```ts
198
119
  const processor = ai.stream.createProcessor()
199
120
  for await (const chunk of ai.llm.chatStream({ messages })) {
200
121
  const delta = processor.process(chunk)
201
- if (delta?.content) { /* 实时显示 */ }
122
+ if (delta?.content) process.stdout.write(delta.content)
202
123
  }
203
-
204
- const result = processor.getResult()
205
- // { content: string, toolCalls: ToolCall[], finishReason: string | null }
206
124
  const message = processor.toAssistantMessage()
207
- // { role: 'assistant', content: '...', tool_calls?: [...] }
208
-
209
- // 快捷收集全部内容
210
- const collected = await ai.stream.collect(stream)
211
125
  ```
212
126
 
213
- > `ai.stream.createProcessor` / `ai.stream.collect` 也可通过 `createStreamProcessor` / `collectStream` 直接导入。
127
+ ## MCP 服务器
214
128
 
215
- ### MCP 服务器 — `createMcpServer`
216
-
217
- ```typescript
129
+ ```ts
218
130
  import { createMcpServer, StreamableHTTPServerTransport } from '@h-ai/ai'
219
- import { z } from 'zod'
220
-
221
- const mcp = createMcpServer({ name: 'my-server', version: '1.0.0' })
222
131
 
223
- // 注册工具
224
- mcp.registerTool('search', {
132
+ const server = createMcpServer({ name: 'my-server', version: '1.0.0' })
133
+ server.registerTool('search', {
225
134
  description: '搜索',
226
135
  inputSchema: { query: z.string() },
227
136
  }, async ({ query }) => ({
228
137
  content: [{ type: 'text', text: `Results for ${query}` }],
229
138
  }))
230
139
 
231
- // 注册资源
232
- mcp.registerResource('config', 'config://app', {
233
- description: '应用配置',
234
- }, async uri => ({
235
- contents: [{ uri: uri.href, text: '{}' }],
236
- }))
237
-
238
- // 注册提示词
239
- mcp.registerPrompt('summarize', {
240
- description: '总结文本',
241
- argsSchema: { text: z.string() },
242
- }, async ({ text }) => ({
243
- messages: [{ role: 'user', content: { type: 'text', text } }],
244
- }))
245
-
246
- // 连接传输层
247
- const transport = new StreamableHTTPServerTransport({
248
- sessionIdGenerator: () => randomUUID(),
249
- })
250
- await mcp.connect(transport)
251
- ```
252
-
253
- **传输层选项**:`StreamableHTTPServerTransport`(推荐,Web 场景)、`SSEServerTransport`、`StdioServerTransport`
254
-
255
- ### MCP 操作 — `ai.mcp`
256
-
257
- | 方法 | 签名 | 说明 |
258
- | ------------------ | ---------------------------------- | ---------- |
259
- | `registerTool` | `(def, handler) => void` | 注册工具 |
260
- | `callTool` | `(name, input) => Promise<HaiResult>` | 调用工具 |
261
- | `registerResource` | `(def, reader) => void` | 注册资源 |
262
- | `readResource` | `(uri) => Promise<HaiResult>` | 读取资源 |
263
- | `registerPrompt` | `(def, generator) => void` | 注册提示词 |
264
- | `getPrompt` | `(name, args) => Promise<HaiResult>` | 获取提示词 |
265
-
266
- ### 前端客户端
267
-
268
- ```typescript
269
- import { apiClient } from '@h-ai/api-client'
270
-
271
- await apiClient.init({ baseUrl: '/api/v1', auth: {} })
272
-
273
- // 非流式
274
- const response = await apiClient.ai.chats.createCompletion({ messages })
275
-
276
- // 便捷方法
277
- const reply = await apiClient.ai.chats.sendMessage({ message: '你好', systemPrompt: '系统提示' })
278
-
279
- // 记忆与会话查询
280
- const memories = await apiClient.ai.memories.recall({ query: '用户偏好', topK: 5, objectId: 'user-001' })
281
- const page = await apiClient.ai.memories.list({ objectId: 'user-001', limit: 20 })
282
- const sessions = await apiClient.ai.sessions.list({ objectId: 'user-001' })
140
+ await server.connect(new StreamableHTTPServerTransport({ sessionIdGenerator: crypto.randomUUID }))
283
141
  ```
284
142
 
285
- ### 记忆管理 — `ai.memory`
286
-
287
- | 方法 | 签名 | 说明 |
288
- | ----------------- | ------------------------------------------------------------- | ---------------------------------- |
289
- | `extract` | `(messages, options?) => Promise<HaiResult<MemoryEntry[]>>` | 从对话中自动提取记忆(LLM 驱动) |
290
- | `add` | `(entry) => Promise<HaiResult<MemoryEntry>>` | 手动添加一条记忆 |
291
- | `get` | `(memoryId) => Promise<HaiResult<MemoryEntry>>` | 获取指定记忆 |
292
- | `recall` | `(query, options?) => Promise<HaiResult<MemoryEntry[]>>` | 按查询检索最相关的记忆 |
293
- | `injectMemories` | `(messages, options?) => Promise<HaiResult<ChatMessage[]>>` | 将相关记忆自动注入消息列表 |
294
- | `remove` | `(memoryId) => Promise<HaiResult<void>>` | 删除指定记忆 |
295
- | `list` | `(options?) => Promise<HaiResult<MemoryEntry[]>>` | 列出记忆(支持类型/objectId 过滤) |
296
- | `listPage` | `(options?) => Promise<HaiResult<StorePage<MemoryEntry>>>` | 分页列出记忆 |
297
- | `clear` | `(options?) => Promise<HaiResult<void>>` | 清空记忆(支持按类型/objectId 清空)|
298
-
299
- ```typescript
300
- // 从对话中自动提取记忆
301
- const extracted = await ai.memory.extract(messages, { objectId: 'user-001' })
302
- if (extracted.success) {
303
- // extracted.data: MemoryEntry[](已自动存储)
304
- }
305
-
306
- // 手动添加记忆
307
- await ai.memory.add({
308
- content: '用户偏好使用中文',
309
- type: 'preference', // fact | preference | event | entity | instruction
310
- importance: 0.8,
311
- objectId: 'user-001', // 可选,不传为全局
312
- })
313
-
314
- // 检索相关记忆
315
- const memories = await ai.memory.recall('语言偏好', { topK: 5, objectId: 'user-001' })
316
-
317
- // 将记忆注入消息列表(自动检索 + 格式化 + 插入 system prompt)
318
- const enriched = await ai.memory.injectMemories(messages, { topK: 5, position: 'system' })
319
- if (enriched.success) {
320
- const response = await ai.llm.chat({ messages: enriched.data })
321
- }
322
- ```
323
-
324
- ### Token 估算 — `ai.token`
325
-
326
- | 方法 | 签名 | 说明 |
327
- | ------------------ | ----------------------------------- | ------------------------ |
328
- | `estimateMessages` | `(messages) => HaiResult<number>` | 估算消息列表的 Token 数 |
329
- | `estimateText` | `(text) => number` | 估算纯文本的 Token 数 |
330
-
331
- ```typescript
332
- // 估算消息列表 Token 数
333
- const tokens = ai.token.estimateMessages(messages)
334
- if (tokens.success) {
335
- // tokens.data — 估算的 Token 数
336
- }
337
-
338
- // 估算纯文本 Token 数
339
- const count = ai.token.estimateText('Hello world')
340
- ```
341
-
342
- ### 消息摘要 — `ai.summary`
343
-
344
- | 方法 | 签名 | 说明 |
345
- | ----------- | ----------------------------------------------------------------- | ----------------------------- |
346
- | `summarize` | `(messages, options?) => Promise<HaiResult<SummaryResult>>` | 对消息生成摘要(支持增量) |
347
- | `generate` | `(text, options?) => Promise<HaiResult<SummaryResult>>` | 对纯文本生成摘要 |
348
-
349
- ### 上下文压缩 — `ai.compress`
350
-
351
- | 方法 | 签名 | 说明 |
352
- | ------------- | ----------------------------------------------------------------- | ------------------------------------- |
353
- | `tryCompress` | `(messages, options?) => Promise<HaiResult<CompressResult>>` | 压缩消息列表至指定 Token 预算 |
354
-
355
- ```typescript
356
- // 压缩超长对话
357
- const result = await ai.compress.tryCompress(messages, {
358
- strategy: 'hybrid', // summary | sliding-window | hybrid
359
- maxTokens: 4000,
360
- preserveLastN: 4,
361
- })
362
- if (result.success) {
363
- // result.data.messages — 压缩后的消息列表
364
- // result.data.originalTokens / compressedTokens — 压缩前后 Token 数
365
- // result.data.summary — 生成的摘要文本
366
- }
367
- ```
368
-
369
- ### 上下文管理 — `ai.context`
370
-
371
- | 方法 | 签名 | 说明 |
372
- | ---------------- | ----------------------------------------------------------------- | ------------------------------------------------------- |
373
- | `createManager` | `(options?) => HaiResult<ContextManager>` | 创建有状态上下文管理器(压缩 + LLM/Memory/RAG 编排) |
374
- | `restoreManager` | `(scope, options?) => Promise<HaiResult<ContextManager>>` | 从持久化存储恢复上下文管理器 |
375
- | `listSessions` | `(objectId) => Promise<HaiResult<SessionInfo[]>>` | 列出指定对象的所有会话 |
376
- | `renameSession` | `(sessionId, title) => Promise<HaiResult<void>>` | 重命名会话 |
377
- | `removeSession` | `(sessionId) => Promise<HaiResult<void>>` | 删除会话 |
378
-
379
- **ContextManager 方法**:
380
- - `addMessage(msg)` — 追加消息(自动压缩)
381
- - `getMessages()` / `getTokenUsage()` / `getSummaries()` — 查询状态
382
- - `chat(message, options?)` — 发送消息并获取回复(编排 LLM + Memory + RAG + Reasoning)
383
- - `chatStream(message, options?)` — 流式对话(产出 delta*/done 事件)
384
- - `save()` — 持久化 / `reset()` — 重置
385
-
386
- ```typescript
387
- // 创建管理器并直接对话(推荐)
388
- const managerResult = ai.context.createManager({
389
- scope: { objectId: 'user-001', sessionId: 'sess-001' },
390
- systemPrompt: '你是一个友好的助手。',
391
- compress: { maxTokens: 8000, strategy: 'hybrid', auto: true },
392
- memory: { enable: true, enableExtract: true },
393
- })
394
- if (managerResult.success) {
395
- const manager = managerResult.data
396
- const result = await manager.chat('你好')
397
- // result.data.reply / result.data.model / result.data.usage
398
- await manager.save()
399
- }
143
+ ## 记忆、RAG 与知识库
400
144
 
401
- // 流式对话
402
- for await (const event of manager.chatStream('讲个故事')) {
403
- if (event.type === 'delta') process.stdout.write(event.text)
404
- }
145
+ ```ts
146
+ const enriched = await ai.memory.injectMemories(messages, { objectId: 'user-001', topK: 5 })
147
+ if (!enriched.success) return enriched
405
148
 
406
- // 恢复已有会话
407
- const restored = await ai.context.restoreManager(
408
- { objectId: 'user-001', sessionId: 'sess-001' },
409
- { compress: { maxTokens: 8000 }, memory: { enable: true } },
410
- )
149
+ const compressed = await ai.compress.tryCompress(enriched.data, { strategy: 'hybrid', maxTokens: 4000 })
150
+ if (!compressed.success) return compressed
411
151
 
412
- // 列出对象的所有会话
413
- const sessions = await ai.context.listSessions('user-001')
152
+ const answer = await ai.rag.query('核心架构是什么?', { sources: ['docs'], topK: 5 })
414
153
  ```
415
154
 
416
- ---
417
-
418
- ## 错误码 — `HaiAIError`
419
-
420
- | 错误码 | code | 说明 |
421
- | --------------------------------------------------- | -------------- | -------------------- |
422
- | `HaiAIError.INTERNAL_ERROR` | `hai:ai:000` | 内部错误 |
423
- | `HaiAIError.NOT_INITIALIZED` | `hai:ai:010` | 服务未初始化 |
424
- | `HaiAIError.CONFIGURATION_ERROR` | `hai:ai:011` | 配置错误 |
425
- | `HaiAIError.INIT_IN_PROGRESS` | `hai:ai:012` | 初始化进行中 |
426
- | `HaiAIError.RERANK_API_ERROR` | `hai:ai:020` | Rerank API 调用错误 |
427
- | `HaiAIError.RERANK_INVALID_REQUEST` | `hai:ai:021` | Rerank 请求参数无效 |
428
- | `HaiAIError.FILE_PARSE_FAILED` | `hai:ai:030` | 文件解析失败 |
429
- | `HaiAIError.FILE_UNSUPPORTED_FORMAT` | `hai:ai:031` | 不支持的文件格式 |
430
- | `HaiAIError.FILE_OCR_FAILED` | `hai:ai:032` | OCR 识别失败 |
431
- | `HaiAIError.FILE_INVALID_CONTENT` | `hai:ai:033` | 文件内容无效 |
432
- | `HaiAIError.API_ERROR` | `hai:ai:100` | API 调用错误 |
433
- | `HaiAIError.INVALID_REQUEST` | `hai:ai:101` | 无效请求 |
434
- | `HaiAIError.RATE_LIMITED` | `hai:ai:102` | 速率限制 |
435
- | `HaiAIError.TIMEOUT` | `hai:ai:103` | 请求超时 |
436
- | `HaiAIError.MODEL_NOT_FOUND` | `hai:ai:104` | 模型未找到 |
437
- | `HaiAIError.CONTEXT_LENGTH_EXCEEDED` | `hai:ai:105` | 上下文长度超限 |
438
- | `HaiAIError.LLM_RECORD_FAILED` | `hai:ai:106` | 对话记录保存失败 |
439
- | `HaiAIError.LLM_HISTORY_FAILED` | `hai:ai:107` | 对话历史查询失败 |
440
- | `HaiAIError.MCP_CONNECTION_ERROR` | `hai:ai:200` | MCP 连接错误 |
441
- | `HaiAIError.MCP_PROTOCOL_ERROR` | `hai:ai:201` | MCP 协议错误 |
442
- | `HaiAIError.MCP_TOOL_ERROR` | `hai:ai:202` | MCP 工具错误 |
443
- | `HaiAIError.MCP_RESOURCE_ERROR` | `hai:ai:203` | MCP 资源错误 |
444
- | `HaiAIError.MCP_SERVER_ERROR` | `hai:ai:204` | MCP 服务器错误 |
445
- | `HaiAIError.EMBEDDING_API_ERROR` | `hai:ai:300` | Embedding 调用错误 |
446
- | `HaiAIError.EMBEDDING_MODEL_NOT_FOUND` | `hai:ai:301` | Embedding 模型未找到 |
447
- | `HaiAIError.EMBEDDING_INPUT_TOO_LONG` | `hai:ai:302` | Embedding 输入过长 |
448
- | `HaiAIError.TOOL_NOT_FOUND` | `hai:ai:400` | 工具未找到 |
449
- | `HaiAIError.TOOL_VALIDATION_FAILED` | `hai:ai:401` | 工具验证失败 |
450
- | `HaiAIError.TOOL_EXECUTION_FAILED` | `hai:ai:402` | 工具执行失败 |
451
- | `HaiAIError.TOOL_TIMEOUT` | `hai:ai:403` | 工具执行超时 |
452
- | `HaiAIError.REASONING_FAILED` | `hai:ai:500` | 推理执行失败 |
453
- | `HaiAIError.REASONING_MAX_ROUNDS` | `hai:ai:501` | 推理轮次超限 |
454
- | `HaiAIError.REASONING_STRATEGY_NOT_FOUND` | `hai:ai:502` | 推理策略未找到 |
455
- | `HaiAIError.RETRIEVAL_FAILED` | `hai:ai:600` | 检索执行失败 |
456
- | `HaiAIError.RETRIEVAL_SOURCE_NOT_FOUND` | `hai:ai:601` | 检索源未配置 |
457
- | `HaiAIError.RAG_FAILED` | `hai:ai:700` | RAG 执行失败 |
458
- | `HaiAIError.RAG_CONTEXT_BUILD_FAILED` | `hai:ai:701` | RAG 上下文构建失败 |
459
- | `HaiAIError.KNOWLEDGE_SETUP_FAILED` | `hai:ai:800` | 知识库初始化失败 |
460
- | `HaiAIError.KNOWLEDGE_INGEST_FAILED` | `hai:ai:801` | 知识入库失败 |
461
- | `HaiAIError.KNOWLEDGE_RETRIEVE_FAILED` | `hai:ai:802` | 知识检索失败 |
462
- | `HaiAIError.KNOWLEDGE_ENTITY_EXTRACT_FAILED` | `hai:ai:803` | 实体提取失败 |
463
- | `HaiAIError.KNOWLEDGE_NOT_SETUP` | `hai:ai:804` | 知识库未初始化 |
464
- | `HaiAIError.KNOWLEDGE_COLLECTION_NOT_FOUND` | `hai:ai:805` | 集合不存在 |
465
- | `HaiAIError.MEMORY_EXTRACT_FAILED` | `hai:ai:900` | 记忆提取失败 |
466
- | `HaiAIError.MEMORY_STORE_FAILED` | `hai:ai:901` | 记忆存储失败 |
467
- | `HaiAIError.MEMORY_RECALL_FAILED` | `hai:ai:902` | 记忆召回失败 |
468
- | `HaiAIError.MEMORY_NOT_FOUND` | `hai:ai:903` | 记忆条目不存在 |
469
- | `HaiAIError.MEMORY_ENRICH_FAILED` | `hai:ai:904` | 记忆注入失败 |
470
- | `HaiAIError.CONTEXT_COMPRESS_FAILED` | `hai:ai:950` | 上下文压缩失败 |
471
- | `HaiAIError.CONTEXT_SUMMARIZE_FAILED` | `hai:ai:951` | 上下文摘要失败 |
472
- | `HaiAIError.CONTEXT_TOKEN_ESTIMATE_FAILED` | `hai:ai:952` | Token 估算失败 |
473
- | `HaiAIError.CONTEXT_BUDGET_EXCEEDED` | `hai:ai:953` | Token 预算超限 |
474
- | `HaiAIError.STORE_FAILED` | `hai:ai:960` | 存储操作失败 |
475
- | `HaiAIError.STORE_NOT_AVAILABLE` | `hai:ai:961` | 存储后端不可用 |
476
- | `HaiAIError.SESSION_NOT_FOUND` | `hai:ai:970` | 会话不存在 |
477
- | `HaiAIError.SESSION_FAILED` | `hai:ai:971` | 会话操作失败 |
478
- | `HaiAIError.A2A_NOT_CONFIGURED` | `hai:ai:980` | A2A 服务未配置 |
479
- | `HaiAIError.A2A_HANDLE_FAILED` | `hai:ai:981` | A2A 请求处理失败 |
480
- | `HaiAIError.A2A_REMOTE_CALL_FAILED` | `hai:ai:982` | A2A 远端调用失败 |
481
- | `HaiAIError.A2A_AUTH_FAILED` | `hai:ai:983` | A2A 认证失败 |
482
- | `HaiAIError.A2A_LIST_MESSAGES_FAILED` | `hai:ai:984` | A2A 消息查询失败 |
483
-
484
- ---
485
-
486
- ## 常见模式
155
+ 知识库流程:
487
156
 
488
- ### 带工具调用的对话循环
157
+ ```ts
158
+ const setup = await ai.knowledge.setup()
159
+ if (!setup.success) return setup
489
160
 
490
- ```typescript
491
- const registry = ai.tools.createRegistry()
492
- registry.register(weatherTool)
493
-
494
- const messages: ChatMessage[] = [
495
- { role: 'user', content: '北京天气怎么样?' },
496
- ]
497
-
498
- let result = await ai.llm.chat({
499
- messages,
500
- tools: registry.getDefinitions(),
161
+ const ingest = await ai.knowledge.ingest({
162
+ documentId: 'doc-001',
163
+ content: markdownText,
164
+ title: '产品手册',
165
+ enableEntityExtraction: true,
501
166
  })
167
+ if (!ingest.success) return ingest
502
168
 
503
- while (result.success && result.data.choices[0].finish_reason === 'tool_calls') {
504
- const toolCalls = result.data.choices[0].message.tool_calls!
505
- messages.push(result.data.choices[0].message)
506
-
507
- const toolMessages = await registry.executeAll(toolCalls)
508
- if (toolMessages.success)
509
- messages.push(...toolMessages.data)
510
-
511
- result = await ai.llm.chat({ messages, tools: registry.getDefinitions() })
512
- }
513
- ```
514
-
515
- ### 知识库完整流程(文档入库 → 问答)
516
-
517
- ```typescript
518
- import { ai } from '@h-ai/ai'
519
-
520
- // 初始化
521
- await ai.knowledge.setup()
522
-
523
- // 导入多篇文档
524
- for (const doc of documents) {
525
- const result = await ai.knowledge.ingest({
526
- documentId: doc.id,
527
- content: doc.content,
528
- title: doc.title,
529
- enableEntityExtraction: true,
530
- })
531
- if (!result.success) {
532
- // 按错误码处理
533
- switch (result.error.code) {
534
- case HaiAIError.KNOWLEDGE_INGEST_FAILED:
535
- // 入库失败
536
- break
537
- case HaiAIError.EMBEDDING_API_ERROR:
538
- // 嵌入调用失败
539
- break
540
- }
541
- }
542
- }
543
-
544
- // 问答
545
- const answer = await ai.knowledge.ask('项目核心架构是什么?')
546
- if (answer.success) {
547
- // answer.data.answer — LLM 生成的回答
548
- // answer.data.citations — 信源引用列表
549
- }
550
- ```
551
-
552
- ### SvelteKit API 端点
553
-
554
- ```typescript
555
- // src/routes/api/ai/+server.ts
556
- export async function POST(event) {
557
- const { valid, data } = await kit.validate.form(event.request, ChatSchema)
558
- if (!valid)
559
- return kit.response.badRequest('Invalid request')
560
-
561
- const result = await ai.llm.chat({ messages: data!.messages })
562
- if (!result.success)
563
- return kit.response.error(result.error.code, result.error.message)
564
-
565
- return kit.response.ok(result.data)
566
- }
567
- ```
568
-
569
- ### 记忆增强的多轮对话
570
-
571
- ```typescript
572
- import { ai } from '@h-ai/ai'
573
-
574
- const messages: ChatMessage[] = [
575
- { role: 'system', content: '你是一个有帮助的助手' },
576
- ]
577
-
578
- async function chat(userInput: string) {
579
- messages.push({ role: 'user', content: userInput })
580
-
581
- // 1. 注入相关记忆到消息列表
582
- const enriched = await ai.memory.injectMemories(messages, {
583
- topK: 5,
584
- position: 'system',
585
- })
586
- if (!enriched.success) return
587
-
588
- // 2. 压缩上下文以适应 Token 限制
589
- const compressed = await ai.compress.tryCompress(enriched.data, {
590
- maxTokens: 4000,
591
- strategy: 'hybrid',
592
- })
593
- if (!compressed.success) return
594
-
595
- // 3. 调用 LLM
596
- const result = await ai.llm.chat({ messages: compressed.data.messages })
597
- if (!result.success) return
598
-
599
- const reply = result.data.choices[0].message
600
- messages.push(reply)
601
-
602
- // 4. 从新对话中提取记忆(异步,不阻塞响应)
603
- ai.memory.extract(messages.slice(-2))
604
-
605
- return reply.content
606
- }
169
+ const answer = await ai.knowledge.ask('核心架构是什么?')
607
170
  ```
608
171
 
609
- ### 有状态上下文管理器
172
+ ## Context 管理器
610
173
 
611
- ```typescript
612
- import { ai } from '@h-ai/ai'
613
-
614
- // 创建管理器(嵌套配置 + 对话编排)
174
+ ```ts
615
175
  const managerResult = ai.context.createManager({
616
176
  scope: { objectId: 'user-001', sessionId: 'sess-001' },
617
177
  systemPrompt: '你是一个友好的助手。',
618
- compress: { maxTokens: 8000, strategy: 'hybrid', preserveLastN: 4, auto: true },
178
+ compress: { auto: true, strategy: 'hybrid', maxTokens: 8000 },
619
179
  memory: { enable: true, enableExtract: true },
620
180
  })
621
- if (!managerResult.success) throw new Error(managerResult.error.message)
622
- const manager = managerResult.data
623
-
624
- // 方式一:直接对话(推荐,自动编排 LLM + Memory + 压缩)
625
- const result = await manager.chat('你好')
626
- if (result.success) {
627
- // result.data.reply / result.data.model / result.data.usage
628
- }
629
-
630
- // 流式对话
631
- for await (const event of manager.chatStream('讲个故事')) {
632
- if (event.type === 'delta') process.stdout.write(event.text)
633
- }
634
-
635
- // 方式二:手动管理消息
636
- async function manualChat(userInput: string) {
637
- await manager.addMessage({ role: 'user', content: userInput })
638
- const msgs = manager.getMessages()
639
- if (!msgs.success) return
640
- const chatResult = await ai.llm.chat({ messages: msgs.data })
641
- if (!chatResult.success) return
642
- await manager.addMessage(chatResult.data.choices[0].message)
643
- await manager.save()
644
- return chatResult.data.choices[0].message.content
645
- }
646
- ```
647
-
648
- ---
649
-
650
- ## 浏览器端使用
651
-
652
- ### typed 对话调用
653
-
654
- 浏览器 / App 通过 `@h-ai/api-client` 调用由 `@h-ai/api-contract` 定义、`@h-ai/serv` 挂载的 AI contract:
655
-
656
- ```typescript
657
- import { apiClient } from '@h-ai/api-client'
658
-
659
- const result = await apiClient.ai.chats.createCompletion({
660
- messages: [{ role: 'user', content: '你好' }],
661
- })
181
+ if (!managerResult.success) return managerResult
662
182
 
663
- if (result.success) {
664
- appendToUI(result.data.choices[0]?.message?.content ?? '')
665
- }
183
+ const reply = await managerResult.data.chat('你好')
184
+ await managerResult.data.save()
666
185
  ```
667
186
 
668
- ### 流式对话(SSE,自定义 endpoint)
669
-
670
- 标准 `api-client` 不再提供旧的通用流式方法。若产品需要 SSE 流式输出,请在应用服务端显式定义流式 endpoint(例如 SvelteKit `+server.ts` 或 `@h-ai/serv` 自定义 route),浏览器端再用 `fetch` / `apiFetch` 消费。
187
+ ## SvelteKit API 端点模式
671
188
 
672
- ```typescript
673
- import { apiFetch } from '$lib/utils/api'
674
-
675
- const controller = new AbortController()
676
-
677
- const res = await apiFetch('/api/ai/chat-stream', {
678
- method: 'POST',
679
- headers: { 'Content-Type': 'application/json' },
680
- body: JSON.stringify({ conversationId: 'conv-1', content: '你好' }),
681
- signal: controller.signal,
189
+ ```ts
190
+ export const POST = kit.handler(async ({ request }) => {
191
+ const data = await kit.validate.body(request, ChatSchema)
192
+ const result = await ai.llm.chat({ messages: data.messages })
193
+ if (!result.success) return kit.response.error(result.error.code, result.error.message)
194
+ return kit.response.ok(result.data)
682
195
  })
683
-
684
- const reader = res.body!.getReader()
685
- const decoder = new TextDecoder()
686
- while (true) {
687
- const { done, value } = await reader.read()
688
- if (done)
689
- break
690
-
691
- appendToUI(decoder.decode(value))
692
- }
693
196
  ```
694
197
 
695
- 或直接使用原生 `fetch`(跨域公共 API 场景):
696
-
697
- ```typescript
698
- const res = await fetch(`${apiBase}/ai/chat-stream`, {
699
- method: 'POST',
700
- headers: { 'Content-Type': 'application/json' },
701
- body: JSON.stringify({ conversationId, content: userInput }),
702
- signal: controller.signal,
703
- })
704
-
705
- // 手动消费 SSE 流
706
- const reader = res.body!.getReader()
707
- const decoder = new TextDecoder()
708
- while (true) {
709
- const { done, value } = await reader.read()
710
- if (done) break
711
- appendToUI(decoder.decode(value))
712
- }
713
- ```
714
-
715
- ### 浏览器端使用 ai.stream(处理流式 chunk)
716
-
717
- `ai.stream` 是纯函数,浏览器端可直接使用:
718
-
719
- ```typescript
720
- import { ai } from '@h-ai/ai'
721
-
722
- const processor = ai.stream.createProcessor()
723
- // 将服务端返回的 SSE chunk 逐条 process,提取 delta
724
- ```
725
-
726
- ---
727
-
728
- ## 相关 Skills
198
+ ## 质量与安全检查
729
199
 
730
- - `hai-build`:模块初始化顺序
731
- - `hai-core`:配置与 HaiResult 模型
732
- - `hai-kit`:SvelteKit API 端点集成
733
- - `hai-vecdb`:向量数据库(Retrieval / RAG / Knowledge 的存储层)
734
- - `hai-reldb`:关系数据库(Knowledge 实体索引的存储层)
735
- - `hai-datapipe`:数据清洗与分块(Knowledge 入库前的数据处理)
200
+ - API Key 只从配置 / 环境变量读取,禁止写死。
201
+ - 工具 handler 必须校验输入;用户可见错误走 i18n/错误码。
202
+ - 批量导入、批量 embedding 用批量 API,避免 await-in-loop。
203
+ - 文件解析/OCR 失败按 `HaiAIError.FILE_*` 返回,不抛业务异常。
204
+ - A2A 认证失败返回 `A2A_AUTH_FAILED`;不要记录 token、apiKey、私钥等敏感字段。