p-api-agent 0.0.3 → 0.0.5

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 (2) hide show
  1. package/README.md +204 -208
  2. package/package.json +18 -2
package/README.md CHANGED
@@ -1,283 +1,289 @@
1
- # P-API-Agent
1
+ # p-api-agent
2
2
 
3
- 一个基于 LLM 的智能 Agent 框架,支持工具函数调用和多轮对话。
3
+ 一个轻量、高效、模型无关的 LLM Agent 框架。
4
+
5
+ 采用 **ReAct 单调用循环**架构:每轮推理只发起一次 LLM 调用,通过将完整工具 Schema 注入系统提示词,让模型在单次响应中完成「是否用工具 + 选哪个工具 + 填什么参数」三步决策,相比传统多步判断方案减少 60% 以上的 API 调用次数。
4
6
 
5
7
  ## 特性
6
8
 
7
- - 🤖 **智能对话**: 基于 LLM 的智能对话能力
8
- - 🔧 **工具调用**: 支持动态注册和调用工具函数
9
- - 📝 **类型安全**: 完整的 TypeScript 类型定义
10
- - 🛡️ **错误处理**: 完善的错误处理和日志系统
11
- - ⚙️ **可配置**: 灵活的配置选项
12
- - 📊 **日志系统**: 多级别日志输出
9
+ - **ReAct 单调用循环** — 每轮只调用一次 LLM,无冗余中间步骤
10
+ - 🔌 **模型无关** — 只需注册一个 `async (messages) => string` 函数,兼容任意 LLM(OpenAI / Claude / 豆包 / 通义 / DeepSeek …)
11
+ - 🔧 **动态工具注册** 工具以独立文件方式组织,按目录自动加载
12
+ - 🔗 **链式 API** — 注册方法均返回 `this`,支持链式调用
13
+ - 🛡️ **完善容错** — LLM 重试、工具失败兜底、JSON 解析保护、循环上限防护
14
+ - 📦 **零侵入** — 不绑定任何 LLM SDK,按需引入
15
+
16
+ ---
13
17
 
14
18
  ## 安装
15
19
 
16
20
  ```bash
17
21
  npm install p-api-agent
22
+ # 或
23
+ pnpm add p-api-agent
24
+ # 或
25
+ yarn add p-api-agent
18
26
  ```
19
27
 
20
- ## 快速开始
28
+ ---
21
29
 
22
- ### 基础用法
30
+ ## 快速开始
23
31
 
24
32
  ```typescript
25
33
  import { Agent, FunctionCall } from 'p-api-agent';
34
+ import path from 'path';
26
35
 
27
- // 创建 Agent 实例
28
- const agent = new Agent({
29
- maxLoop: 20, // 最大循环次数
30
- debug: false // 调试模式
31
- });
36
+ const agent = new Agent({ maxLoop: 10 });
32
37
 
33
- // 注册 LLM 聊天能力
38
+ // 1. 注册 LLM 能力(替换成你自己的 LLM 调用)
34
39
  agent.register_llm_text_ability(async (messages) => {
35
- // 调用您的 LLM API
36
- const response = await yourLLMAPI(messages);
37
- return response;
40
+ const res = await yourLLMClient.chat(messages);
41
+ return res.content;
38
42
  });
39
43
 
40
- // 注册工具函数(可选)
41
- const functionCall = new FunctionCall('/path/to/tools');
42
- agent.register_function_call(functionCall);
43
-
44
- // 开始对话
45
- const result = await agent.create_chat('你好,请帮我完成任务');
46
- console.log(result);
47
- ```
48
-
49
- ### 创建工具函数
50
-
51
- 在工具目录下创建 `.js` 或 `.ts` 文件:
44
+ // 2. 注册工具函数目录(可选)
45
+ const fc = new FunctionCall(path.join(__dirname, 'tools'));
46
+ agent.register_function_call(fc);
52
47
 
53
- ```typescript
54
- // tools/get_weather.ts
55
- export function register() {
56
- return {
57
- name: 'get_weather',
58
- description: '获取指定城市的天气信息',
59
- input_schema: {
60
- type: 'object',
61
- properties: {
62
- city: {
63
- type: 'string',
64
- description: '城市名称',
65
- examples: ['北京', '上海', '深圳']
66
- }
67
- },
68
- required: ['city']
69
- },
70
- register_func: async (params: { city: string }) => {
71
- // 实现您的工具逻辑
72
- return {
73
- city: params.city,
74
- temperature: 25,
75
- weather: '晴天'
76
- };
77
- }
78
- };
79
- }
48
+ // 3. 发起对话
49
+ const result = await agent.create_chat('帮我查一下订单 12345 的收货地址');
50
+ console.log(result.result); // 最终答案
51
+ console.log(result.use_tools); // 调用过的工具记录
80
52
  ```
81
53
 
82
- ### 自定义提示词
54
+ 支持链式注册:
83
55
 
84
56
  ```typescript
85
- const agent = new Agent({
86
- customPresetPrompt: `
87
- 你是一个专业的助手...
88
- (自定义提示词内容)
89
- `
90
- });
57
+ const result = await new Agent({ maxLoop: 10 })
58
+ .register_llm_text_ability(llmFunc)
59
+ .register_function_call(fc)
60
+ .create_chat('你好');
91
61
  ```
92
62
 
93
- ## API 文档
94
-
95
- ### Agent 类
63
+ ---
96
64
 
97
- #### 构造函数
65
+ ## 工作原理
98
66
 
99
- ```typescript
100
- new Agent(options?: AgentOptions)
67
+ ```
68
+ 用户输入
69
+
70
+
71
+ 构建系统提示词(含所有工具完整 Schema)
72
+
73
+ ▼ ◄────────────────────────────────────────────────────────┐
74
+ 单次 LLM 调用 │
75
+ │ │
76
+ ├─ { command: "use_tool", tool_name, params } │
77
+ │ └─ 执行工具 → 结果作为 observation 注入历史 ──────────┘
78
+
79
+ ├─ { command: "end", result }
80
+ │ └─ 返回最终答案 ✓
81
+
82
+ └─ { command: "no_ability", result }
83
+ └─ 返回无法处理说明 ✓
101
84
  ```
102
85
 
103
- **选项:**
104
- - `maxLoop?: number` - 最大循环次数(默认:20)
105
- - `debug?: boolean` - 是否启用调试模式(默认:false)
106
- - `customPresetPrompt?: string` - 自定义预置提示词
86
+ 每轮推理固定 **1 次** LLM 调用。工具结果以 `[工具调用结果]` 前缀注入对话历史,模型可在下一轮基于结果继续推理、链式调用多个工具,最终输出 `end` 指令结束。
107
87
 
108
- #### 方法
88
+ ---
109
89
 
110
- ##### register_llm_text_ability(func)
90
+ ## 创建工具函数
111
91
 
112
- 注册 LLM 文字能力
92
+ 在工具目录下为每个工具创建一个独立文件,导出 `register()` 函数:
113
93
 
114
94
  ```typescript
115
- agent.register_llm_text_ability(async (userInput) => {
116
- // 返回 LLM 响应
117
- return llmResponse;
95
+ // tools/get_weather.ts
96
+ import type { RegisterInfo } from 'p-api-agent';
97
+
98
+ export const register = (): RegisterInfo => ({
99
+ name: 'get_weather',
100
+ description: '获取指定城市的实时天气信息',
101
+ input_schema: {
102
+ type: 'object',
103
+ properties: {
104
+ city: {
105
+ type: 'string',
106
+ description: '城市名称',
107
+ examples: ['北京', '上海', '深圳'],
108
+ },
109
+ date: {
110
+ type: 'string',
111
+ description: '日期,格式 YYYY-MM-DD,不传则默认今天',
112
+ },
113
+ },
114
+ required: ['city'],
115
+ },
116
+ register_func: async (params: { city: string; date?: string }) => {
117
+ // 实现你的业务逻辑
118
+ return { city: params.city, temperature: 25, weather: '晴' };
119
+ },
118
120
  });
119
121
  ```
120
122
 
121
- ##### register_function_call(functionCall)
123
+ `register_func` 接收 LLM 生成的参数对象,返回值会被序列化后注入对话上下文供模型读取。
122
124
 
123
- 注册工具函数管理器
125
+ ---
124
126
 
125
- ```typescript
126
- const functionCall = new FunctionCall('/path/to/tools');
127
- agent.register_function_call(functionCall);
128
- ```
127
+ ## API 文档
129
128
 
130
- ##### create_chat(userInput)
129
+ ### `new Agent(options?)`
131
130
 
132
- 创建聊天会话
131
+ | 选项 | 类型 | 默认值 | 说明 |
132
+ |---|---|---|---|
133
+ | `maxLoop` | `number` | `20` | 最大推理循环轮次,防止无限循环 |
134
+ | `retryTimes` | `number` | `2` | LLM 调用失败时的重试次数 |
135
+ | `customSystemPrompt` | `string` | — | 完全覆盖内置系统提示词 |
133
136
 
134
- ```typescript
135
- const result = await agent.create_chat('用户输入');
136
- // 或使用消息数组
137
- const result = await agent.create_chat([
138
- {
139
- role: 'user',
140
- content: [{ type: 'text', text: '用户输入' }]
141
- }
142
- ]);
143
- ```
137
+ ---
144
138
 
145
- ##### set_max_loop(maxLoop)
139
+ ### `agent.register_llm_text_ability(func)`
146
140
 
147
- 设置最大循环次数
141
+ 注册 LLM 文字调用函数,返回 `this`。
148
142
 
149
143
  ```typescript
150
- agent.set_max_loop(30);
144
+ agent.register_llm_text_ability(
145
+ async (messages: Message[]) => Promise<string>
146
+ )
151
147
  ```
152
148
 
153
- ##### set_preset_prompt(prompt)
149
+ `messages` 格式遵循 OpenAI Chat Completions 标准,兼容绝大多数主流 LLM。
154
150
 
155
- 设置自定义预置提示词
151
+ ---
156
152
 
157
- ```typescript
158
- agent.set_preset_prompt('自定义提示词内容');
159
- ```
153
+ ### `agent.register_function_call(fc)`
160
154
 
161
- ### FunctionCall
162
-
163
- #### 构造函数
155
+ 注册工具函数集合,返回 `this`。`FunctionCall` 会自动扫描目录下所有文件并调用 `register()` 加载。
164
156
 
165
157
  ```typescript
166
- new FunctionCall(toolPath: string)
158
+ const fc = new FunctionCall('/absolute/path/to/tools');
159
+ agent.register_function_call(fc);
167
160
  ```
168
161
 
169
- **参数:**
170
- - `toolPath` - 工具函数所在目录的绝对路径
171
-
172
- #### 方法
162
+ ---
173
163
 
174
- ##### get_tools_list()
164
+ ### `agent.create_chat(input)`
175
165
 
176
- 获取所有工具函数列表
166
+ 发起一轮对话,返回 `Promise<CreateChatResult>`。
177
167
 
178
168
  ```typescript
179
- const tools = functionCall.get_tools_list();
180
- // [{ name: 'tool1', description: '...' }, ...]
181
- ```
169
+ // 字符串输入
170
+ const result = await agent.create_chat('查询用户 123 的信息');
182
171
 
183
- ##### has_tool(name)
172
+ // 消息数组输入(携带多轮历史)
173
+ const result = await agent.create_chat([
174
+ { role: 'user', content: [{ type: 'text', text: '你好' }] },
175
+ { role: 'assistant', content: [{ type: 'text', text: '你好!' }] },
176
+ { role: 'user', content: [{ type: 'text', text: '帮我查一下...' }] },
177
+ ]);
178
+ ```
184
179
 
185
- 检查工具函数是否存在
180
+ **返回值:**
186
181
 
187
182
  ```typescript
188
- const exists = functionCall.has_tool('get_weather');
183
+ interface CreateChatResult {
184
+ result: string // 最终返回给用户的文本答案
185
+ use_tools: { // 本次对话中调用过的工具记录
186
+ tool_name: string
187
+ params: any
188
+ exec_result: any
189
+ }[]
190
+ }
189
191
  ```
190
192
 
191
- ##### exec_function(name, params)
193
+ ---
192
194
 
193
- 执行工具函数
195
+ ### `agent.set_system_prompt(prompt)`
194
196
 
195
- ```typescript
196
- const result = await functionCall.exec_function('get_weather', { city: '北京' });
197
- ```
197
+ 运行时覆盖系统提示词,返回 `this`。**注意:** 覆盖后工具列表不再自动注入,需在自定义提示词中手动声明。
198
198
 
199
- ### Logger 工具
199
+ ---
200
200
 
201
- ```typescript
202
- import { Logger, LogLevel } from 'p-api-agent';
201
+ ### `agent.set_max_loop(n)`
203
202
 
204
- // 设置日志级别
205
- Logger.setLevel(LogLevel.DEBUG);
203
+ 动态调整最大循环轮次,返回 `this`。
206
204
 
207
- // 使用日志
208
- Logger.debug('调试信息');
209
- Logger.info('普通信息');
210
- Logger.warn('警告信息');
211
- Logger.error('错误信息');
212
- ```
205
+ ---
206
+
207
+ ### `new FunctionCall(toolPath)`
208
+
209
+ | 方法 | 说明 |
210
+ |---|---|
211
+ | `get_tools_list()` | 返回工具名称 + 描述列表 |
212
+ | `get_tools_with_schema()` | 返回工具完整 Schema(含参数定义) |
213
+ | `gen_tool_doc(name)` | 生成单个工具的可读说明文档字符串 |
214
+ | `exec_function(name, params)` | 执行指定工具,返回工具执行结果 |
215
+
216
+ ---
213
217
 
214
- ### 错误类型
218
+ ## 类型定义
215
219
 
216
220
  ```typescript
217
- import {
218
- AgentError,
219
- ToolNotFoundError,
220
- ToolExecutionError,
221
- ValidationError,
222
- LLMError,
223
- MaxLoopExceededError
221
+ import type {
222
+ AgentOptions,
223
+ UserChatInput,
224
+ Message,
225
+ CreateChatResult,
226
+ ToolRecord,
227
+ RegisterInfo,
224
228
  } from 'p-api-agent';
225
-
226
- try {
227
- await agent.create_chat('...');
228
- } catch (error) {
229
- if (error instanceof ToolNotFoundError) {
230
- console.error('工具函数不存在');
231
- } else if (error instanceof MaxLoopExceededError) {
232
- console.error('超出最大循环次数');
233
- }
234
- }
235
229
  ```
236
230
 
237
- ## 工作原理
231
+ ---
238
232
 
239
- 1. **用户输入** → Agent 接收用户请求
240
- 2. **LLM 分析** → LLM 判断是否需要调用工具
241
- 3. **工具调用** → 如需要,先获取工具文档,再执行工具
242
- 4. **结果处理** → 整合工具结果,返回给用户
243
- 5. **循环控制** → 最多循环 maxLoop 次,防止无限循环
233
+ ## 完整示例(OpenAI)
244
234
 
245
- ## LLM 响应格式
235
+ ```typescript
236
+ import { Agent, FunctionCall } from 'p-api-agent';
237
+ import OpenAI from 'openai';
238
+ import path from 'path';
239
+
240
+ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
241
+
242
+ const agent = new Agent({ maxLoop: 15, retryTimes: 3 })
243
+ .register_llm_text_ability(async (messages) => {
244
+ const res = await openai.chat.completions.create({
245
+ model: 'gpt-4o',
246
+ messages: messages as any,
247
+ });
248
+ return res.choices[0].message.content ?? '';
249
+ })
250
+ .register_function_call(
251
+ new FunctionCall(path.join(__dirname, 'tools'))
252
+ );
253
+
254
+ const { result, use_tools } = await agent.create_chat(
255
+ '帮我查询订单 12345 的购买者信息和商品价格'
256
+ );
257
+
258
+ console.log('答案:', result);
259
+ console.log('调用了工具:', use_tools.map(t => t.tool_name));
260
+ ```
246
261
 
247
- LLM 需要返回 JSON 格式的指令:
262
+ ---
248
263
 
249
- ### 结束指令
250
- ```json
251
- {
252
- "command": "end",
253
- "result": "最终返回给用户的结果"
254
- }
255
- ```
264
+ ## 自定义系统提示词
256
265
 
257
- ### 获取工具文档
258
- ```json
259
- {
260
- "command": "get_tool_doc",
261
- "tool_name": "工具函数名称"
262
- }
263
- ```
266
+ 如需完全控制 Agent 人设,使用 `customSystemPrompt` 选项:
264
267
 
265
- ### 调用工具
266
- ```json
267
- {
268
- "command": "use_tool",
269
- "tool_name": "工具函数名称",
270
- "params": { "参数名": "参数值" }
271
- }
268
+ ```typescript
269
+ const agent = new Agent({
270
+ customSystemPrompt: `
271
+ 你是一个专业的电商客服助手,负责处理订单查询和退换货问题。
272
+
273
+ ## 指令格式
274
+ 每次只能输出以下 JSON 之一,不能附带多余文字:
275
+ - 调用工具: {"command":"use_tool","tool_name":"工具名","params":{...}}
276
+ - 任务完成: {"command":"end","result":"最终答案"}
277
+ - 无法处理: {"command":"no_ability","result":"原因说明"}
278
+
279
+ ## 可用工具
280
+ - get_order_info: 根据订单号查询订单详情
281
+ - get_user_info: 根据用户 ID 查询用户信息
282
+ `.trim(),
283
+ });
272
284
  ```
273
285
 
274
- ## 最佳实践
275
-
276
- 1. **错误处理**: 始终使用 try-catch 包裹 Agent 调用
277
- 2. **日志记录**: 生产环境建议设置为 INFO 或 WARN 级别
278
- 3. **循环次数**: 根据实际需求调整 maxLoop,避免过多循环
279
- 4. **工具设计**: 工具函数应该功能单一、职责明确
280
- 5. **参数验证**: 在工具函数中进行充分的参数验证
286
+ ---
281
287
 
282
288
  ## 开发
283
289
 
@@ -288,22 +294,12 @@ npm install
288
294
  # 构建
289
295
  npm run build
290
296
 
291
- # 测试
292
- npm test
297
+ # 运行示例
298
+ npx tsx examples/test.ts
293
299
  ```
294
300
 
295
- ## 许可证
296
-
297
- ISC
298
-
299
- ## 贡献
301
+ ---
300
302
 
301
- 欢迎提交 Issue 和 Pull Request!
303
+ ## License
302
304
 
303
- ## 更新日志
304
-
305
- ### v0.0.1
306
- - 初始版本发布
307
- - 支持基本的 Agent 功能
308
- - 工具函数调用
309
- - 完善的类型定义和错误处理
305
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "p-api-agent",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "main": "./dist/index.cjs",
5
5
  "module": "./dist/index.mjs",
6
6
  "files": [
@@ -18,7 +18,23 @@
18
18
  },
19
19
  "author": "",
20
20
  "license": "ISC",
21
- "description": "",
21
+ "description": "一个轻量、高效、模型无关的 LLM Agent 框架,采用 ReAct 单调用循环架构",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/p-shoko/p-api-agent.git"
25
+ },
26
+ "homepage": "https://github.com/p-shoko/p-api-agent#readme",
27
+ "bugs": {
28
+ "url": "https://github.com/p-shoko/p-api-agent/issues"
29
+ },
30
+ "keywords": [
31
+ "agent",
32
+ "llm",
33
+ "react",
34
+ "function-call",
35
+ "openai",
36
+ "ai"
37
+ ],
22
38
  "devDependencies": {
23
39
  "@types/lodash": "4.17.16",
24
40
  "@types/node": "^25.3.5",