agent-scene-toolkit 0.1.2 → 0.1.4

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
  *
@@ -314,13 +396,12 @@ declare function createAgent(options: AgentOptions): Agent;
314
396
  declare function createExpressHandler(agent: Agent): RequestHandler;
315
397
 
316
398
  /**
317
- * 构建 4 层 Prompt 拼接链。
399
+ * 构建 3 层 Prompt 拼接链。
318
400
  *
319
401
  * ```
320
- * ① Base 库内置固定指令(通用行为约束、防御性指令)
321
- * ② Profileagent.systemPrompt(角色身份)
322
- * ③ ToolKit 当前场景激活的 ToolKit.prompt(0~N 个)
323
- * ④ Scene — scene.prompt(sceneContext)(仅绑定 Scene 时)
402
+ * ① Profile agent.systemPrompt(角色身份)
403
+ * ② ToolKit当前场景激活的 ToolKit.prompt(0~N 个)
404
+ * ③ Scene scene.prompt(sceneContext)(仅绑定 Scene 时)
324
405
  * ```
325
406
  *
326
407
  * 各层以 `\n\n` 拼接,合并为单条 SystemMessage 字符串。
@@ -460,4 +541,4 @@ declare function transformStream(stream: AsyncIterable<any>, onToolEnd?: (toolNa
460
541
  */
461
542
  declare function formatSSE(event: SSEEvent): string;
462
543
 
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 };
544
+ 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
  *
@@ -314,13 +396,12 @@ declare function createAgent(options: AgentOptions): Agent;
314
396
  declare function createExpressHandler(agent: Agent): RequestHandler;
315
397
 
316
398
  /**
317
- * 构建 4 层 Prompt 拼接链。
399
+ * 构建 3 层 Prompt 拼接链。
318
400
  *
319
401
  * ```
320
- * ① Base 库内置固定指令(通用行为约束、防御性指令)
321
- * ② Profileagent.systemPrompt(角色身份)
322
- * ③ ToolKit 当前场景激活的 ToolKit.prompt(0~N 个)
323
- * ④ Scene — scene.prompt(sceneContext)(仅绑定 Scene 时)
402
+ * ① Profile agent.systemPrompt(角色身份)
403
+ * ② ToolKit当前场景激活的 ToolKit.prompt(0~N 个)
404
+ * ③ Scene scene.prompt(sceneContext)(仅绑定 Scene 时)
324
405
  * ```
325
406
  *
326
407
  * 各层以 `\n\n` 拼接,合并为单条 SystemMessage 字符串。
@@ -460,4 +541,4 @@ declare function transformStream(stream: AsyncIterable<any>, onToolEnd?: (toolNa
460
541
  */
461
542
  declare function formatSSE(event: SSEEvent): string;
462
543
 
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 };
544
+ 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,26 +30,29 @@ function defineScene(input) {
29
30
  return Object.freeze({ ...input });
30
31
  }
31
32
 
32
- // src/prompt.ts
33
- var BASE_PROMPT = `You are an autonomous AI agent. You can reason, plan, and take actions using the tools available to you.
34
-
35
- ## Core Behavior
36
- - When given a task, break it down into steps, then execute each step using the appropriate tools.
37
- - After each tool call, observe the result and decide the next action. Continue until the task is fully completed.
38
- - If no tools are needed, respond directly with your knowledge.
39
- - Never fabricate uncertain information. If you cannot complete a task, explain why honestly.
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
+ }
40
49
 
41
- ## Rules
42
- - Respond in the same language as the user.
43
- - Follow tool parameter schemas strictly \u2014 do not invent or omit required fields.
44
- - When multiple tools are available, choose the most relevant one for the current step.`;
50
+ // src/prompt.ts
45
51
  function buildPromptChain(params) {
46
52
  const layers = [
47
- // ① Base库内置固定指令
48
- BASE_PROMPT,
49
- // ② Profile — 角色身份提示词
53
+ // ① Profile角色身份提示词
50
54
  params.profile.systemPrompt,
51
- // ToolKit — 当前场景激活的能力包提示词
55
+ // ToolKit — 当前场景激活的能力包提示词
52
56
  ...params.toolkitPrompts
53
57
  ];
54
58
  if (params.scene) {
@@ -401,11 +405,81 @@ function createExpressHandler(agent) {
401
405
  }
402
406
  };
403
407
  }
408
+ function cosineSimilarity(a, b) {
409
+ let dot = 0;
410
+ let normA = 0;
411
+ let normB = 0;
412
+ for (let i = 0; i < a.length; i++) {
413
+ dot += a[i] * b[i];
414
+ normA += a[i] * a[i];
415
+ normB += b[i] * b[i];
416
+ }
417
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
418
+ return denom === 0 ? 0 : dot / denom;
419
+ }
420
+ async function initVectorStores(knowledgeBases, embeddings) {
421
+ const stores = [];
422
+ for (const kb of knowledgeBases) {
423
+ try {
424
+ const docs = typeof kb.documents === "function" ? await kb.documents() : kb.documents;
425
+ if (!docs.length) {
426
+ console.warn(`[initVectorStores] "${kb.name}" has no documents, skipping`);
427
+ continue;
428
+ }
429
+ console.log(`[initVectorStores] Embedding "${kb.name}" (${docs.length} documents)...`);
430
+ const vectors = await embeddings.embedDocuments(docs);
431
+ const records = docs.map((text, i) => ({
432
+ text,
433
+ vector: vectors[i]
434
+ }));
435
+ stores.push({ kb, records });
436
+ console.log(`[initVectorStores] "${kb.name}" ready (${records.length} vectors, dim=${vectors[0]?.length ?? 0})`);
437
+ } catch (error) {
438
+ const message = error instanceof Error ? error.message : String(error);
439
+ console.error(`[initVectorStores] Failed to embed "${kb.name}":`, message);
440
+ throw new Error(`Failed to initialize knowledge base "${kb.name}": ${message}`);
441
+ }
442
+ }
443
+ return stores;
444
+ }
445
+ async function searchVectorStore(store, query, embeddings) {
446
+ const topK = store.kb.topK ?? 3;
447
+ const queryVector = await embeddings.embedQuery(query);
448
+ const scored = store.records.map((record) => ({
449
+ text: record.text,
450
+ score: cosineSimilarity(queryVector, record.vector)
451
+ }));
452
+ scored.sort((a, b) => b.score - a.score);
453
+ return scored.slice(0, topK).map((item) => item.text);
454
+ }
455
+ function buildKnowledgeTools(stores, embeddings) {
456
+ return stores.map((store) => new DynamicTool({
457
+ name: store.kb.name,
458
+ description: store.kb.description,
459
+ func: async (query) => {
460
+ try {
461
+ const results = await searchVectorStore(store, query, embeddings);
462
+ if (results.length === 0) {
463
+ return "No relevant information found.";
464
+ }
465
+ return results.join("\n\n---\n\n");
466
+ } catch (error) {
467
+ const message = error instanceof Error ? error.message : String(error);
468
+ console.error(`[buildKnowledgeTools] Search failed for "${store.kb.name}":`, message);
469
+ return `Search failed: ${message}`;
470
+ }
471
+ }
472
+ }));
473
+ }
404
474
 
405
475
  // src/agent.ts
406
476
  var Agent = class {
407
477
  /** @internal */
408
478
  options;
479
+ /** RAG 知识库转换而来的 DynamicTool 列表 */
480
+ knowledgeTools = [];
481
+ /** 异步初始化 Promise(向量化知识库等) */
482
+ readyPromise;
409
483
  constructor(options) {
410
484
  this.options = {
411
485
  maxMessages: 50,
@@ -414,6 +488,26 @@ var Agent = class {
414
488
  ...options
415
489
  };
416
490
  this.validate();
491
+ this.readyPromise = this.init();
492
+ }
493
+ /**
494
+ * 异步初始化 — 向量化知识库并构建检索 Tool。
495
+ *
496
+ * 在构造函数中启动,chat() 首次调用时 await 确保完成。
497
+ * 若无 knowledgeBases,立即 resolve。
498
+ */
499
+ async init() {
500
+ const { knowledgeBases, embeddings } = this.options;
501
+ if (!knowledgeBases?.length || !embeddings) return;
502
+ try {
503
+ const stores = await initVectorStores(knowledgeBases, embeddings);
504
+ this.knowledgeTools = buildKnowledgeTools(stores, embeddings);
505
+ console.log(`[Agent] ${this.knowledgeTools.length} knowledge tool(s) ready`);
506
+ } catch (error) {
507
+ const message = error instanceof Error ? error.message : String(error);
508
+ console.error("[Agent] Knowledge base initialization failed:", message);
509
+ throw error;
510
+ }
417
511
  }
418
512
  /**
419
513
  * 发起对话,返回标准化 SSE 事件的异步生成器。
@@ -431,6 +525,7 @@ var Agent = class {
431
525
  */
432
526
  async *chat(chatOptions) {
433
527
  try {
528
+ await this.readyPromise;
434
529
  if (!chatOptions.message) {
435
530
  yield { type: "error", message: "message is required" };
436
531
  yield { type: "done" };
@@ -443,7 +538,11 @@ var Agent = class {
443
538
  }
444
539
  const scene = this.options.scene;
445
540
  const activeToolkits = scene ? this.options.toolkits.filter((tk) => scene.toolkits.includes(tk.name)) : this.options.toolkits;
446
- const tools = activeToolkits.flatMap((tk) => tk.tools);
541
+ const tools = [
542
+ ...activeToolkits.flatMap((tk) => tk.tools),
543
+ ...this.knowledgeTools
544
+ // RAG 知识库 Tool 注入
545
+ ];
447
546
  const toolkitPrompts = activeToolkits.map((tk) => tk.prompt);
448
547
  const isMultiAgent = this.options.agents.length > 1 && !!this.options.supervisor;
449
548
  let stream;
@@ -546,12 +645,15 @@ ${err.stack}` : ""}` : String(err);
546
645
  }
547
646
  }
548
647
  }
648
+ if (this.options.knowledgeBases?.length && !this.options.embeddings) {
649
+ throw new Error("embeddings is required when knowledgeBases is provided");
650
+ }
549
651
  }
550
652
  };
551
653
  function createAgent2(options) {
552
654
  return new Agent(options);
553
655
  }
554
656
 
555
- export { Agent, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent2 as createAgent, createExpressHandler, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
657
+ export { Agent, buildPromptChain, buildSingleGraph, buildSupervisorGraph, createAgent2 as createAgent, createExpressHandler, defineKnowledgeBase, defineProfile, defineScene, defineToolKit, formatSSE, transformStream };
556
658
  //# sourceMappingURL=index.js.map
557
659
  //# sourceMappingURL=index.js.map