agent-scene-toolkit 0.1.2 → 0.1.3

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/dist/index.d.cts CHANGED
@@ -2,6 +2,7 @@ import { StructuredToolInterface } from '@langchain/core/tools';
2
2
  import * as _langchain_langgraph from '@langchain/langgraph';
3
3
  import { BaseCheckpointSaver } from '@langchain/langgraph';
4
4
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
5
+ import { EmbeddingsInterface } from '@langchain/core/embeddings';
5
6
  import { RequestHandler } from 'express';
6
7
  import * as _langchain_core_utils_stream from '@langchain/core/utils/stream';
7
8
  import * as langchain from 'langchain';
@@ -72,6 +73,40 @@ interface Scene {
72
73
  /** 工具调用完成后的生命周期回调 */
73
74
  readonly onToolEnd?: (toolName: string, result: any) => void;
74
75
  }
76
+ /**
77
+ * 知识库 — 纯文本数据 + 语义检索描述。
78
+ *
79
+ * 库内部自动将文本向量化并包装为 LangChain Tool,AI 根据 `description` 自主决定何时检索。
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * const faqKB = defineKnowledgeBase({
84
+ * name: 'faq',
85
+ * description: '产品常见问题,当用户问功能、价格、退款等问题时检索',
86
+ * documents: ['7天内无理由退款', '基础版99元/月'],
87
+ * })
88
+ *
89
+ * // 也支持异步加载
90
+ * const dynamicKB = defineKnowledgeBase({
91
+ * name: 'dynamic-docs',
92
+ * description: '从数据库动态加载的文档',
93
+ * documents: async () => {
94
+ * const res = await fetch('/api/docs')
95
+ * return res.json()
96
+ * },
97
+ * })
98
+ * ```
99
+ */
100
+ interface KnowledgeBase {
101
+ /** 知识库唯一标识,也作为 Tool 名称 */
102
+ readonly name: string;
103
+ /** 描述知识库用途,AI 据此判断何时检索 */
104
+ readonly description: string;
105
+ /** 纯文本数据:静态数组或异步加载函数 */
106
+ readonly documents: string[] | (() => Promise<string[]>);
107
+ /** 返回最相关的前 K 条结果(默认 3) */
108
+ readonly topK?: number;
109
+ }
75
110
  /**
76
111
  * `createAgent()` 配置项。
77
112
  *
@@ -106,6 +141,10 @@ interface AgentOptions {
106
141
  maxMessages?: number;
107
142
  /** LangChain Callbacks */
108
143
  callbacks?: BaseCallbackHandler[];
144
+ /** 知识库列表,有值则启用 RAG(检索增强生成) */
145
+ knowledgeBases?: KnowledgeBase[];
146
+ /** 嵌入模型实例,当 knowledgeBases 存在时必填 */
147
+ embeddings?: EmbeddingsInterface;
109
148
  /** OpenAI 兼容网关配置(如中转商) */
110
149
  llm?: {
111
150
  /** 兼容 OpenAI 的 base URL,例如 https://api.bltcy.ai */
@@ -223,6 +262,38 @@ declare function defineToolKit(input: ToolKit): Readonly<ToolKit>;
223
262
  */
224
263
  declare function defineScene(input: Scene): Readonly<Scene>;
225
264
 
265
+ /**
266
+ * 定义一个知识库。
267
+ *
268
+ * 校验必填字段后返回不可变对象。
269
+ * 库内部自动将文本向量化并包装为 LangChain Tool,AI 根据 `description` 自主决定何时检索。
270
+ *
271
+ * @param input - 知识库配置
272
+ * @returns 冻结的 KnowledgeBase 对象
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * // 静态文本
277
+ * const faqKB = defineKnowledgeBase({
278
+ * name: 'faq',
279
+ * description: '产品常见问题,当用户问功能、价格、退款等问题时检索',
280
+ * documents: ['7天内无理由退款', '基础版99元/月', '支持微信支付宝付款'],
281
+ * topK: 3,
282
+ * })
283
+ *
284
+ * // 从数据库/API 动态加载
285
+ * const dynamicKB = defineKnowledgeBase({
286
+ * name: 'dynamic-docs',
287
+ * description: '从数据库动态加载的文档',
288
+ * documents: async () => {
289
+ * const res = await fetch('/api/docs')
290
+ * return res.json()
291
+ * },
292
+ * })
293
+ * ```
294
+ */
295
+ declare function defineKnowledgeBase(input: KnowledgeBase): Readonly<KnowledgeBase>;
296
+
226
297
  /**
227
298
  * Agent 实例的内部已解析配置类型。
228
299
  *
@@ -243,7 +314,18 @@ interface ResolvedOptions extends AgentOptions {
243
314
  declare class Agent {
244
315
  /** @internal */
245
316
  readonly options: ResolvedOptions;
317
+ /** RAG 知识库转换而来的 DynamicTool 列表 */
318
+ private knowledgeTools;
319
+ /** 异步初始化 Promise(向量化知识库等) */
320
+ private readyPromise;
246
321
  constructor(options: AgentOptions);
322
+ /**
323
+ * 异步初始化 — 向量化知识库并构建检索 Tool。
324
+ *
325
+ * 在构造函数中启动,chat() 首次调用时 await 确保完成。
326
+ * 若无 knowledgeBases,立即 resolve。
327
+ */
328
+ private init;
247
329
  /**
248
330
  * 发起对话,返回标准化 SSE 事件的异步生成器。
249
331
  *
@@ -460,4 +542,4 @@ declare function transformStream(stream: AsyncIterable<any>, onToolEnd?: (toolNa
460
542
  */
461
543
  declare function formatSSE(event: SSEEvent): string;
462
544
 
463
- export { Agent, type AgentOptions, type AgentProfile, type ChatOptions, type SSEEvent, type Scene, type ToolKit, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent, createExpressHandler, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
545
+ export { Agent, type AgentOptions, type AgentProfile, type ChatOptions, type KnowledgeBase, type SSEEvent, type Scene, type ToolKit, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent, createExpressHandler, defineKnowledgeBase, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { StructuredToolInterface } from '@langchain/core/tools';
2
2
  import * as _langchain_langgraph from '@langchain/langgraph';
3
3
  import { BaseCheckpointSaver } from '@langchain/langgraph';
4
4
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
5
+ import { EmbeddingsInterface } from '@langchain/core/embeddings';
5
6
  import { RequestHandler } from 'express';
6
7
  import * as _langchain_core_utils_stream from '@langchain/core/utils/stream';
7
8
  import * as langchain from 'langchain';
@@ -72,6 +73,40 @@ interface Scene {
72
73
  /** 工具调用完成后的生命周期回调 */
73
74
  readonly onToolEnd?: (toolName: string, result: any) => void;
74
75
  }
76
+ /**
77
+ * 知识库 — 纯文本数据 + 语义检索描述。
78
+ *
79
+ * 库内部自动将文本向量化并包装为 LangChain Tool,AI 根据 `description` 自主决定何时检索。
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * const faqKB = defineKnowledgeBase({
84
+ * name: 'faq',
85
+ * description: '产品常见问题,当用户问功能、价格、退款等问题时检索',
86
+ * documents: ['7天内无理由退款', '基础版99元/月'],
87
+ * })
88
+ *
89
+ * // 也支持异步加载
90
+ * const dynamicKB = defineKnowledgeBase({
91
+ * name: 'dynamic-docs',
92
+ * description: '从数据库动态加载的文档',
93
+ * documents: async () => {
94
+ * const res = await fetch('/api/docs')
95
+ * return res.json()
96
+ * },
97
+ * })
98
+ * ```
99
+ */
100
+ interface KnowledgeBase {
101
+ /** 知识库唯一标识,也作为 Tool 名称 */
102
+ readonly name: string;
103
+ /** 描述知识库用途,AI 据此判断何时检索 */
104
+ readonly description: string;
105
+ /** 纯文本数据:静态数组或异步加载函数 */
106
+ readonly documents: string[] | (() => Promise<string[]>);
107
+ /** 返回最相关的前 K 条结果(默认 3) */
108
+ readonly topK?: number;
109
+ }
75
110
  /**
76
111
  * `createAgent()` 配置项。
77
112
  *
@@ -106,6 +141,10 @@ interface AgentOptions {
106
141
  maxMessages?: number;
107
142
  /** LangChain Callbacks */
108
143
  callbacks?: BaseCallbackHandler[];
144
+ /** 知识库列表,有值则启用 RAG(检索增强生成) */
145
+ knowledgeBases?: KnowledgeBase[];
146
+ /** 嵌入模型实例,当 knowledgeBases 存在时必填 */
147
+ embeddings?: EmbeddingsInterface;
109
148
  /** OpenAI 兼容网关配置(如中转商) */
110
149
  llm?: {
111
150
  /** 兼容 OpenAI 的 base URL,例如 https://api.bltcy.ai */
@@ -223,6 +262,38 @@ declare function defineToolKit(input: ToolKit): Readonly<ToolKit>;
223
262
  */
224
263
  declare function defineScene(input: Scene): Readonly<Scene>;
225
264
 
265
+ /**
266
+ * 定义一个知识库。
267
+ *
268
+ * 校验必填字段后返回不可变对象。
269
+ * 库内部自动将文本向量化并包装为 LangChain Tool,AI 根据 `description` 自主决定何时检索。
270
+ *
271
+ * @param input - 知识库配置
272
+ * @returns 冻结的 KnowledgeBase 对象
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * // 静态文本
277
+ * const faqKB = defineKnowledgeBase({
278
+ * name: 'faq',
279
+ * description: '产品常见问题,当用户问功能、价格、退款等问题时检索',
280
+ * documents: ['7天内无理由退款', '基础版99元/月', '支持微信支付宝付款'],
281
+ * topK: 3,
282
+ * })
283
+ *
284
+ * // 从数据库/API 动态加载
285
+ * const dynamicKB = defineKnowledgeBase({
286
+ * name: 'dynamic-docs',
287
+ * description: '从数据库动态加载的文档',
288
+ * documents: async () => {
289
+ * const res = await fetch('/api/docs')
290
+ * return res.json()
291
+ * },
292
+ * })
293
+ * ```
294
+ */
295
+ declare function defineKnowledgeBase(input: KnowledgeBase): Readonly<KnowledgeBase>;
296
+
226
297
  /**
227
298
  * Agent 实例的内部已解析配置类型。
228
299
  *
@@ -243,7 +314,18 @@ interface ResolvedOptions extends AgentOptions {
243
314
  declare class Agent {
244
315
  /** @internal */
245
316
  readonly options: ResolvedOptions;
317
+ /** RAG 知识库转换而来的 DynamicTool 列表 */
318
+ private knowledgeTools;
319
+ /** 异步初始化 Promise(向量化知识库等) */
320
+ private readyPromise;
246
321
  constructor(options: AgentOptions);
322
+ /**
323
+ * 异步初始化 — 向量化知识库并构建检索 Tool。
324
+ *
325
+ * 在构造函数中启动,chat() 首次调用时 await 确保完成。
326
+ * 若无 knowledgeBases,立即 resolve。
327
+ */
328
+ private init;
247
329
  /**
248
330
  * 发起对话,返回标准化 SSE 事件的异步生成器。
249
331
  *
@@ -460,4 +542,4 @@ declare function transformStream(stream: AsyncIterable<any>, onToolEnd?: (toolNa
460
542
  */
461
543
  declare function formatSSE(event: SSEEvent): string;
462
544
 
463
- export { Agent, type AgentOptions, type AgentProfile, type ChatOptions, type SSEEvent, type Scene, type ToolKit, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent, createExpressHandler, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
545
+ export { Agent, type AgentOptions, type AgentProfile, type ChatOptions, type KnowledgeBase, type SSEEvent, type Scene, type ToolKit, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent, createExpressHandler, defineKnowledgeBase, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { createAgent, createMiddleware } from 'langchain';
4
4
  import { HumanMessage, AIMessageChunk, ToolMessage } from '@langchain/core/messages';
5
5
  import { createReactAgent } from '@langchain/langgraph/prebuilt';
6
6
  import { createSupervisor } from '@langchain/langgraph-supervisor';
7
+ import { DynamicTool } from '@langchain/core/tools';
7
8
 
8
9
  // src/profile.ts
9
10
  function defineProfile(input) {
@@ -29,6 +30,23 @@ function defineScene(input) {
29
30
  return Object.freeze({ ...input });
30
31
  }
31
32
 
33
+ // src/knowledge.ts
34
+ function defineKnowledgeBase(input) {
35
+ if (!input.name) throw new Error("KnowledgeBase name is required");
36
+ if (!input.description) throw new Error("KnowledgeBase description is required");
37
+ if (!input.documents) throw new Error("KnowledgeBase documents is required");
38
+ if (typeof input.documents !== "function" && !Array.isArray(input.documents)) {
39
+ throw new Error("KnowledgeBase documents must be a string[] or () => Promise<string[]>");
40
+ }
41
+ if (Array.isArray(input.documents) && input.documents.length === 0) {
42
+ throw new Error("KnowledgeBase documents must not be empty");
43
+ }
44
+ if (input.topK !== void 0 && (typeof input.topK !== "number" || input.topK < 1)) {
45
+ throw new Error("KnowledgeBase topK must be a positive number");
46
+ }
47
+ return Object.freeze({ ...input });
48
+ }
49
+
32
50
  // src/prompt.ts
33
51
  var BASE_PROMPT = `You are an autonomous AI agent. You can reason, plan, and take actions using the tools available to you.
34
52
 
@@ -401,11 +419,81 @@ function createExpressHandler(agent) {
401
419
  }
402
420
  };
403
421
  }
422
+ function cosineSimilarity(a, b) {
423
+ let dot = 0;
424
+ let normA = 0;
425
+ let normB = 0;
426
+ for (let i = 0; i < a.length; i++) {
427
+ dot += a[i] * b[i];
428
+ normA += a[i] * a[i];
429
+ normB += b[i] * b[i];
430
+ }
431
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
432
+ return denom === 0 ? 0 : dot / denom;
433
+ }
434
+ async function initVectorStores(knowledgeBases, embeddings) {
435
+ const stores = [];
436
+ for (const kb of knowledgeBases) {
437
+ try {
438
+ const docs = typeof kb.documents === "function" ? await kb.documents() : kb.documents;
439
+ if (!docs.length) {
440
+ console.warn(`[initVectorStores] "${kb.name}" has no documents, skipping`);
441
+ continue;
442
+ }
443
+ console.log(`[initVectorStores] Embedding "${kb.name}" (${docs.length} documents)...`);
444
+ const vectors = await embeddings.embedDocuments(docs);
445
+ const records = docs.map((text, i) => ({
446
+ text,
447
+ vector: vectors[i]
448
+ }));
449
+ stores.push({ kb, records });
450
+ console.log(`[initVectorStores] "${kb.name}" ready (${records.length} vectors, dim=${vectors[0]?.length ?? 0})`);
451
+ } catch (error) {
452
+ const message = error instanceof Error ? error.message : String(error);
453
+ console.error(`[initVectorStores] Failed to embed "${kb.name}":`, message);
454
+ throw new Error(`Failed to initialize knowledge base "${kb.name}": ${message}`);
455
+ }
456
+ }
457
+ return stores;
458
+ }
459
+ async function searchVectorStore(store, query, embeddings) {
460
+ const topK = store.kb.topK ?? 3;
461
+ const queryVector = await embeddings.embedQuery(query);
462
+ const scored = store.records.map((record) => ({
463
+ text: record.text,
464
+ score: cosineSimilarity(queryVector, record.vector)
465
+ }));
466
+ scored.sort((a, b) => b.score - a.score);
467
+ return scored.slice(0, topK).map((item) => item.text);
468
+ }
469
+ function buildKnowledgeTools(stores, embeddings) {
470
+ return stores.map((store) => new DynamicTool({
471
+ name: store.kb.name,
472
+ description: store.kb.description,
473
+ func: async (query) => {
474
+ try {
475
+ const results = await searchVectorStore(store, query, embeddings);
476
+ if (results.length === 0) {
477
+ return "No relevant information found.";
478
+ }
479
+ return results.join("\n\n---\n\n");
480
+ } catch (error) {
481
+ const message = error instanceof Error ? error.message : String(error);
482
+ console.error(`[buildKnowledgeTools] Search failed for "${store.kb.name}":`, message);
483
+ return `Search failed: ${message}`;
484
+ }
485
+ }
486
+ }));
487
+ }
404
488
 
405
489
  // src/agent.ts
406
490
  var Agent = class {
407
491
  /** @internal */
408
492
  options;
493
+ /** RAG 知识库转换而来的 DynamicTool 列表 */
494
+ knowledgeTools = [];
495
+ /** 异步初始化 Promise(向量化知识库等) */
496
+ readyPromise;
409
497
  constructor(options) {
410
498
  this.options = {
411
499
  maxMessages: 50,
@@ -414,6 +502,26 @@ var Agent = class {
414
502
  ...options
415
503
  };
416
504
  this.validate();
505
+ this.readyPromise = this.init();
506
+ }
507
+ /**
508
+ * 异步初始化 — 向量化知识库并构建检索 Tool。
509
+ *
510
+ * 在构造函数中启动,chat() 首次调用时 await 确保完成。
511
+ * 若无 knowledgeBases,立即 resolve。
512
+ */
513
+ async init() {
514
+ const { knowledgeBases, embeddings } = this.options;
515
+ if (!knowledgeBases?.length || !embeddings) return;
516
+ try {
517
+ const stores = await initVectorStores(knowledgeBases, embeddings);
518
+ this.knowledgeTools = buildKnowledgeTools(stores, embeddings);
519
+ console.log(`[Agent] ${this.knowledgeTools.length} knowledge tool(s) ready`);
520
+ } catch (error) {
521
+ const message = error instanceof Error ? error.message : String(error);
522
+ console.error("[Agent] Knowledge base initialization failed:", message);
523
+ throw error;
524
+ }
417
525
  }
418
526
  /**
419
527
  * 发起对话,返回标准化 SSE 事件的异步生成器。
@@ -431,6 +539,7 @@ var Agent = class {
431
539
  */
432
540
  async *chat(chatOptions) {
433
541
  try {
542
+ await this.readyPromise;
434
543
  if (!chatOptions.message) {
435
544
  yield { type: "error", message: "message is required" };
436
545
  yield { type: "done" };
@@ -443,7 +552,11 @@ var Agent = class {
443
552
  }
444
553
  const scene = this.options.scene;
445
554
  const activeToolkits = scene ? this.options.toolkits.filter((tk) => scene.toolkits.includes(tk.name)) : this.options.toolkits;
446
- const tools = activeToolkits.flatMap((tk) => tk.tools);
555
+ const tools = [
556
+ ...activeToolkits.flatMap((tk) => tk.tools),
557
+ ...this.knowledgeTools
558
+ // RAG 知识库 Tool 注入
559
+ ];
447
560
  const toolkitPrompts = activeToolkits.map((tk) => tk.prompt);
448
561
  const isMultiAgent = this.options.agents.length > 1 && !!this.options.supervisor;
449
562
  let stream;
@@ -546,12 +659,15 @@ ${err.stack}` : ""}` : String(err);
546
659
  }
547
660
  }
548
661
  }
662
+ if (this.options.knowledgeBases?.length && !this.options.embeddings) {
663
+ throw new Error("embeddings is required when knowledgeBases is provided");
664
+ }
549
665
  }
550
666
  };
551
667
  function createAgent2(options) {
552
668
  return new Agent(options);
553
669
  }
554
670
 
555
- export { Agent, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent2 as createAgent, createExpressHandler, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
671
+ export { Agent, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent2 as createAgent, createExpressHandler, defineKnowledgeBase, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
556
672
  //# sourceMappingURL=index.js.map
557
673
  //# sourceMappingURL=index.js.map