@keo-ai/axiom 0.1.1 → 0.1.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.
@@ -0,0 +1 @@
1
+ export declare function embed(text: string, dimensions?: number): Promise<number[]>;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.embed = embed;
13
+ const EMBEDDING_URL = 'https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings';
14
+ const EMBEDDING_MODEL = 'text-embedding-v4';
15
+ function embed(text_1) {
16
+ return __awaiter(this, arguments, void 0, function* (text, dimensions = 1024) {
17
+ var _a;
18
+ const apiKey = process.env.BAILIAN_API_KEY;
19
+ if (!apiKey) {
20
+ throw new Error('BAILIAN_API_KEY environment variable is not set');
21
+ }
22
+ const body = {
23
+ model: EMBEDDING_MODEL,
24
+ input: text,
25
+ dimensions,
26
+ };
27
+ let response;
28
+ try {
29
+ response = yield fetch(EMBEDDING_URL, {
30
+ method: 'POST',
31
+ headers: {
32
+ 'Content-Type': 'application/json',
33
+ Authorization: `Bearer ${apiKey}`,
34
+ },
35
+ body: JSON.stringify(body),
36
+ });
37
+ }
38
+ catch (cause) {
39
+ throw new Error(`[embedding] ${cause instanceof Error ? cause.message : String(cause)}`);
40
+ }
41
+ if (!response.ok) {
42
+ const text = yield response.text();
43
+ throw new Error(`[embedding] HTTP ${response.status}: ${text}`);
44
+ }
45
+ const data = (yield response.json());
46
+ const vector = (_a = data.data[0]) === null || _a === void 0 ? void 0 : _a.embedding;
47
+ if (!vector) {
48
+ throw new Error('[embedding] No embedding in response');
49
+ }
50
+ return vector;
51
+ });
52
+ }
@@ -0,0 +1,27 @@
1
+ import type { Pool } from 'pg';
2
+ import type { EmbeddingSearchConfig, SearchResult } from './types';
3
+ /**
4
+ * 向量检索静态入口。
5
+ *
6
+ * 封装 embedding → pgvector 检索 → [可选 rerank] 的完整链路。
7
+ * PG 连接由外部传入,Axiom 不管理连接池生命周期。
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const results = await EmbeddingSearch.query('query文本', {
12
+ * enableRerank: true,
13
+ * embeddingTopK: 20,
14
+ * finalTopN: 5,
15
+ * embeddingThreshold: 0.7,
16
+ * rerankThreshold: 0.5,
17
+ * }, pgPool);
18
+ * ```
19
+ */
20
+ export declare class EmbeddingSearch {
21
+ static query(query: string, config: EmbeddingSearchConfig, pool: Pool): Promise<SearchResult[]>;
22
+ static vectorSearch(options: Omit<import('./pgvector').PgVectorSearchOptions, 'pool'> & {
23
+ pool: Pool;
24
+ }): Promise<SearchResult[]>;
25
+ }
26
+ export type { EmbeddingSearchConfig, SearchResult } from './types';
27
+ export { embed } from './embed';
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.embed = exports.EmbeddingSearch = void 0;
24
+ const pgvector_1 = require("./pgvector");
25
+ const embed_1 = require("./embed");
26
+ const RERANK_URL = 'https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank';
27
+ const RERANK_MODEL = 'qwen3-rerank';
28
+ function rerank(query, documents, topN, apiKey) {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ const body = {
31
+ model: RERANK_MODEL,
32
+ input: {
33
+ query,
34
+ documents: documents.map((d) => d.content),
35
+ },
36
+ parameters: {
37
+ return_documents: true,
38
+ top_n: topN,
39
+ },
40
+ };
41
+ let response;
42
+ try {
43
+ response = yield fetch(RERANK_URL, {
44
+ method: 'POST',
45
+ headers: {
46
+ 'Content-Type': 'application/json',
47
+ Authorization: `Bearer ${apiKey}`,
48
+ },
49
+ body: JSON.stringify(body),
50
+ });
51
+ }
52
+ catch (cause) {
53
+ throw new Error(`[rerank] ${cause instanceof Error ? cause.message : String(cause)}`);
54
+ }
55
+ if (!response.ok) {
56
+ const text = yield response.text();
57
+ throw new Error(`[rerank] HTTP ${response.status}: ${text}`);
58
+ }
59
+ const data = (yield response.json());
60
+ return data.output.results.map((r) => {
61
+ var _a, _b, _c, _d;
62
+ const doc = documents[r.index];
63
+ return {
64
+ index: r.index,
65
+ id: (_a = doc === null || doc === void 0 ? void 0 : doc.id) !== null && _a !== void 0 ? _a : r.index,
66
+ content: (_d = (_c = (_b = r.document) === null || _b === void 0 ? void 0 : _b.text) !== null && _c !== void 0 ? _c : doc === null || doc === void 0 ? void 0 : doc.content) !== null && _d !== void 0 ? _d : '',
67
+ score: r.relevance_score,
68
+ };
69
+ });
70
+ });
71
+ }
72
+ /**
73
+ * 向量检索静态入口。
74
+ *
75
+ * 封装 embedding → pgvector 检索 → [可选 rerank] 的完整链路。
76
+ * PG 连接由外部传入,Axiom 不管理连接池生命周期。
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * const results = await EmbeddingSearch.query('query文本', {
81
+ * enableRerank: true,
82
+ * embeddingTopK: 20,
83
+ * finalTopN: 5,
84
+ * embeddingThreshold: 0.7,
85
+ * rerankThreshold: 0.5,
86
+ * }, pgPool);
87
+ * ```
88
+ */
89
+ class EmbeddingSearch {
90
+ static query(query, config, pool) {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ const { enableRerank = true, embeddingTopK = 10, finalTopN = 5, embeddingThreshold = 0.8, rerankThreshold = 0.1, tableName, embeddingColumn, rerankKey = 'content', dimensions, filter, select, } = config;
93
+ const idColumn = 'id';
94
+ const actualTopK = enableRerank
95
+ ? Math.max(embeddingTopK, finalTopN)
96
+ : finalTopN;
97
+ const apiKey = process.env.BAILIAN_API_KEY;
98
+ if (!apiKey) {
99
+ throw new Error('BAILIAN_API_KEY environment variable is not set');
100
+ }
101
+ const queryVector = yield (0, embed_1.embed)(query, dimensions);
102
+ // 启用 rerank 时,确保能拿到 rerankKey 对应列的内容
103
+ let actualSelect = select;
104
+ if (enableRerank && actualSelect && !actualSelect.includes(rerankKey)) {
105
+ actualSelect = [...actualSelect, rerankKey];
106
+ }
107
+ const searchResults = yield (0, pgvector_1.vectorSearch)({
108
+ pool,
109
+ tableName,
110
+ vector: queryVector,
111
+ topK: actualTopK,
112
+ threshold: embeddingThreshold,
113
+ embeddingColumn,
114
+ filter,
115
+ select: actualSelect,
116
+ });
117
+ if (searchResults.length === 0) {
118
+ return [];
119
+ }
120
+ if (enableRerank) {
121
+ const missingRerank = searchResults.find((r) => r[rerankKey] === undefined);
122
+ if (missingRerank) {
123
+ throw new Error(`Rerank requires column "${rerankKey}" but it was not found. ` +
124
+ `Either create this column in your table, or set rerankKey to the correct column name.`);
125
+ }
126
+ }
127
+ if (!enableRerank) {
128
+ return searchResults.slice(0, finalTopN);
129
+ }
130
+ const rerankResults = yield rerank(query, searchResults.map((r) => ({
131
+ id: r[idColumn],
132
+ content: r[rerankKey],
133
+ })), finalTopN, apiKey);
134
+ let reranked = [];
135
+ for (const rr of rerankResults) {
136
+ if (rerankThreshold !== undefined && rr.score < rerankThreshold) {
137
+ continue;
138
+ }
139
+ const original = searchResults[rr.index];
140
+ if (original) {
141
+ reranked.push(Object.assign(Object.assign({}, original), { rerankScore: rr.score }));
142
+ }
143
+ }
144
+ // 如果用户没选 rerankKey 对应列,从返回结果中剔除
145
+ if (select && !select.includes(rerankKey)) {
146
+ reranked = reranked.map((r) => {
147
+ const _a = r, _b = rerankKey, _ = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
148
+ return rest;
149
+ });
150
+ }
151
+ return reranked;
152
+ });
153
+ }
154
+ static vectorSearch(options) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ return (0, pgvector_1.vectorSearch)(options);
157
+ });
158
+ }
159
+ }
160
+ exports.EmbeddingSearch = EmbeddingSearch;
161
+ var embed_2 = require("./embed");
162
+ Object.defineProperty(exports, "embed", { enumerable: true, get: function () { return embed_2.embed; } });
@@ -0,0 +1,19 @@
1
+ import type { Pool } from 'pg';
2
+ import type { SearchResult } from './types';
3
+ export interface PgVectorSearchOptions {
4
+ readonly pool: Pool;
5
+ readonly tableName: string;
6
+ readonly vector: number[];
7
+ readonly topK: number;
8
+ readonly threshold?: number;
9
+ readonly embeddingColumn?: string;
10
+ readonly filter?: Record<string, unknown>;
11
+ readonly select?: string[];
12
+ }
13
+ /**
14
+ * 使用 pgvector 执行 cosine similarity 检索。
15
+ *
16
+ * - `embedding <=> query` 为 cosine distance(范围 0~2,越小越相似)
17
+ * - `1 - cosine_distance` 为 cosine similarity(范围 -1~1,越大越相似)
18
+ */
19
+ export declare function vectorSearch(options: PgVectorSearchOptions): Promise<SearchResult[]>;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.vectorSearch = vectorSearch;
24
+ function validateIdentifier(name) {
25
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
26
+ throw new Error(`Invalid identifier: ${name}`);
27
+ }
28
+ }
29
+ /**
30
+ * 使用 pgvector 执行 cosine similarity 检索。
31
+ *
32
+ * - `embedding <=> query` 为 cosine distance(范围 0~2,越小越相似)
33
+ * - `1 - cosine_distance` 为 cosine similarity(范围 -1~1,越大越相似)
34
+ */
35
+ function vectorSearch(options) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ const { pool, tableName, vector, topK, threshold, embeddingColumn = 'embedding', filter, select } = options;
38
+ validateIdentifier(tableName);
39
+ validateIdentifier(embeddingColumn);
40
+ const vectorStr = JSON.stringify(vector);
41
+ const params = [vectorStr, topK];
42
+ const conditions = [];
43
+ let paramIndex = 3;
44
+ if (threshold !== undefined) {
45
+ conditions.push(`1 - ("${embeddingColumn}" <=> $1::vector) >= $${paramIndex}`);
46
+ params.push(threshold);
47
+ paramIndex++;
48
+ }
49
+ if (filter && Object.keys(filter).length > 0) {
50
+ for (const [key, value] of Object.entries(filter)) {
51
+ validateIdentifier(key);
52
+ if (Array.isArray(value)) {
53
+ const placeholders = value.map((_, i) => `$${paramIndex + i}`).join(', ');
54
+ conditions.push(`"${key}" IN (${placeholders})`);
55
+ params.push(...value);
56
+ paramIndex += value.length;
57
+ }
58
+ else if (value && typeof value === 'object') {
59
+ const ops = value;
60
+ for (const [op, opValue] of Object.entries(ops)) {
61
+ switch (op) {
62
+ case '$eq':
63
+ conditions.push(`"${key}" = $${paramIndex}`);
64
+ params.push(opValue);
65
+ paramIndex++;
66
+ break;
67
+ case '$gt':
68
+ conditions.push(`"${key}" > $${paramIndex}`);
69
+ params.push(opValue);
70
+ paramIndex++;
71
+ break;
72
+ case '$lt':
73
+ conditions.push(`"${key}" < $${paramIndex}`);
74
+ params.push(opValue);
75
+ paramIndex++;
76
+ break;
77
+ case '$gte':
78
+ conditions.push(`"${key}" >= $${paramIndex}`);
79
+ params.push(opValue);
80
+ paramIndex++;
81
+ break;
82
+ case '$lte':
83
+ conditions.push(`"${key}" <= $${paramIndex}`);
84
+ params.push(opValue);
85
+ paramIndex++;
86
+ break;
87
+ default:
88
+ throw new Error(`Unsupported filter operator: ${op}`);
89
+ }
90
+ }
91
+ }
92
+ else {
93
+ conditions.push(`"${key}" = $${paramIndex}`);
94
+ params.push(value);
95
+ paramIndex++;
96
+ }
97
+ }
98
+ }
99
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
100
+ const selectClause = select && select.length > 0
101
+ ? select.map((c) => { validateIdentifier(c); return `"${c}"`; }).join(', ')
102
+ : '*';
103
+ const sql = `
104
+ SELECT ${selectClause}, 1 - ("${embeddingColumn}" <=> $1::vector) as score
105
+ FROM "${tableName}"
106
+ ${whereClause}
107
+ ORDER BY "${embeddingColumn}" <=> $1::vector
108
+ LIMIT $2
109
+ `;
110
+ const result = yield pool.query(sql, params);
111
+ return result.rows.map((row) => {
112
+ const { score } = row, rest = __rest(row, ["score"]);
113
+ return Object.assign(Object.assign({}, rest), { embeddingScore: score });
114
+ });
115
+ });
116
+ }
@@ -0,0 +1,26 @@
1
+ export interface ComparisonOp {
2
+ readonly $eq?: unknown;
3
+ readonly $gt?: number;
4
+ readonly $lt?: number;
5
+ readonly $gte?: number;
6
+ readonly $lte?: number;
7
+ }
8
+ export type FilterValue = string | number | boolean | null | unknown[] | ComparisonOp;
9
+ export interface EmbeddingSearchConfig {
10
+ readonly enableRerank?: boolean;
11
+ readonly embeddingTopK?: number;
12
+ readonly finalTopN?: number;
13
+ readonly embeddingThreshold?: number;
14
+ readonly rerankThreshold?: number;
15
+ readonly tableName: string;
16
+ readonly embeddingColumn?: string;
17
+ readonly rerankKey?: string;
18
+ readonly dimensions?: number;
19
+ readonly filter?: Record<string, FilterValue>;
20
+ readonly select?: string[];
21
+ }
22
+ export interface SearchResult {
23
+ readonly [key: string]: unknown;
24
+ readonly embeddingScore: number;
25
+ readonly rerankScore?: number;
26
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -29,3 +29,6 @@ export { BailianProvider } from './predict';
29
29
  /** 模型注册表,定义模型与 Provider 的映射关系 */
30
30
  export { MODEL_REGISTRY } from './predict';
31
31
  export type { Model, PredictConfig, PredictWithMessagesConfig } from './predict';
32
+ /** 向量检索(Embedding + pgvector + Rerank) */
33
+ export { EmbeddingSearch, embed } from './embedding_search';
34
+ export type { EmbeddingSearchConfig, SearchResult } from './embedding_search';
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@
20
20
  * @packageDocumentation
21
21
  */
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.MODEL_REGISTRY = exports.BailianProvider = exports.Predictor = exports.LLM = void 0;
23
+ exports.embed = exports.EmbeddingSearch = exports.MODEL_REGISTRY = exports.BailianProvider = exports.Predictor = exports.LLM = void 0;
24
24
  /** LLM 静态入口类,封装 Provider 连接、故障转移和返回解析 */
25
25
  var predict_1 = require("./predict");
26
26
  Object.defineProperty(exports, "LLM", { enumerable: true, get: function () { return predict_1.LLM; } });
@@ -33,3 +33,7 @@ Object.defineProperty(exports, "BailianProvider", { enumerable: true, get: funct
33
33
  /** 模型注册表,定义模型与 Provider 的映射关系 */
34
34
  var predict_4 = require("./predict");
35
35
  Object.defineProperty(exports, "MODEL_REGISTRY", { enumerable: true, get: function () { return predict_4.MODEL_REGISTRY; } });
36
+ /** 向量检索(Embedding + pgvector + Rerank) */
37
+ var embedding_search_1 = require("./embedding_search");
38
+ Object.defineProperty(exports, "EmbeddingSearch", { enumerable: true, get: function () { return embedding_search_1.EmbeddingSearch; } });
39
+ Object.defineProperty(exports, "embed", { enumerable: true, get: function () { return embedding_search_1.embed; } });
@@ -1,4 +1,4 @@
1
- import type { Message, LLMResponse, StreamChunk } from './types';
1
+ import type { Message, StreamChunk } from './types';
2
2
  import type { PredictConfig, PredictWithMessagesConfig } from './config';
3
3
  /**
4
4
  * LLM 静态类。封装 Provider 连接、请求组装、故障转移和返回解析。
@@ -9,7 +9,7 @@ import type { PredictConfig, PredictWithMessagesConfig } from './config';
9
9
  * import { LLM } from 'axiom';
10
10
  *
11
11
  * const res = await LLM.predict({ model: 'qwen-max', prompt: '你好' });
12
- * console.log(res.content);
12
+ * console.log(res);
13
13
  * ```
14
14
  */
15
15
  export declare class LLM {
@@ -20,41 +20,33 @@ export declare class LLM {
20
20
  * 内部自动构造单条 user message,支持可选的 system prompt。
21
21
  *
22
22
  * 根据 `responseFormat` 返回不同类型:
23
- * - `'text'` → `string`
23
+ * - 未设置 / `'text'` → `string`
24
24
  * - `'json'` → 解析后的对象(`any`)
25
- * - 未设置 → `LLMResponse`
26
25
  *
27
26
  * @param config - 预测配置(模型、prompt、温度等)
28
27
  * @returns 模型生成的完整响应
29
28
  * @throws Error - Provider 未配置、模型不存在、或所有 Provider 均失败时抛出
30
29
  */
31
- static predict(config: PredictConfig & {
32
- responseFormat: 'text';
33
- }): Promise<string>;
34
30
  static predict(config: PredictConfig & {
35
31
  responseFormat: 'json';
36
32
  }): Promise<any>;
37
- static predict(config: PredictConfig): Promise<LLMResponse>;
33
+ static predict(config: PredictConfig): Promise<string>;
38
34
  /**
39
35
  * 使用自定义消息列表调用 LLM。适用于多轮对话等需要精细控制 message 结构的场景。
40
36
  *
41
37
  * 根据 `responseFormat` 返回不同类型:
42
- * - `'text'` → `string`
38
+ * - 未设置 / `'text'` → `string`
43
39
  * - `'json'` → 解析后的对象(可用泛型指定类型)
44
- * - 未设置 → `LLMResponse`
45
40
  *
46
41
  * @param messages - 消息列表(user/assistant 角色)
47
42
  * @param config - 预测配置(不含 prompt,因为由 messages 提供)
48
43
  * @returns 模型生成的完整响应
49
44
  * @throws Error - Provider 未配置、模型不存在、或所有 Provider 均失败时抛出
50
45
  */
51
- static predictWithMessages(messages: ReadonlyArray<Message>, config: PredictWithMessagesConfig & {
52
- responseFormat: 'text';
53
- }): Promise<string>;
54
46
  static predictWithMessages(messages: ReadonlyArray<Message>, config: PredictWithMessagesConfig & {
55
47
  responseFormat: 'json';
56
48
  }): Promise<any>;
57
- static predictWithMessages(messages: ReadonlyArray<Message>, config: PredictWithMessagesConfig): Promise<LLMResponse>;
49
+ static predictWithMessages(messages: ReadonlyArray<Message>, config: PredictWithMessagesConfig): Promise<string>;
58
50
  /**
59
51
  * 流式调用 LLM,逐块返回模型输出。
60
52
  *
@@ -69,16 +69,14 @@ function toLLMRequest(config, messages) {
69
69
  }
70
70
  function unwrapResponse(response, responseFormat) {
71
71
  var _a;
72
- if (responseFormat === 'text') {
73
- return (_a = response.content) !== null && _a !== void 0 ? _a : '';
74
- }
75
72
  if (responseFormat === 'json') {
76
73
  if (!response.content) {
77
74
  throw new Error('Empty response content when responseFormat is json');
78
75
  }
79
76
  return JSON.parse(response.content);
80
77
  }
81
- return response;
78
+ // 默认按 text 返回(包括未设置 responseFormat 的情况)
79
+ return (_a = response.content) !== null && _a !== void 0 ? _a : '';
82
80
  }
83
81
  /**
84
82
  * LLM 静态类。封装 Provider 连接、请求组装、故障转移和返回解析。
@@ -89,7 +87,7 @@ function unwrapResponse(response, responseFormat) {
89
87
  * import { LLM } from 'axiom';
90
88
  *
91
89
  * const res = await LLM.predict({ model: 'qwen-max', prompt: '你好' });
92
- * console.log(res.content);
90
+ * console.log(res);
93
91
  * ```
94
92
  */
95
93
  class LLM {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keo-ai/axiom",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "基于 LLM 的预测与推理库,支持多 Provider 切换",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",