maque-core 1.3.4__tar.gz

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.

Potentially problematic release.


This version of maque-core might be problematic. Click here for more details.

Files changed (45) hide show
  1. maque_core-1.3.4/LICENSE +21 -0
  2. maque_core-1.3.4/PKG-INFO +612 -0
  3. maque_core-1.3.4/README.md +576 -0
  4. maque_core-1.3.4/maque_core/__init__.py +28 -0
  5. maque_core-1.3.4/maque_core/config.py +80 -0
  6. maque_core-1.3.4/maque_core/contracts/__init__.py +17 -0
  7. maque_core-1.3.4/maque_core/contracts/llm.py +47 -0
  8. maque_core-1.3.4/maque_core/contracts/messages.py +264 -0
  9. maque_core-1.3.4/maque_core/contracts/tool.py +121 -0
  10. maque_core-1.3.4/maque_core/factory.py +105 -0
  11. maque_core-1.3.4/maque_core/kernel/__init__.py +8 -0
  12. maque_core-1.3.4/maque_core/kernel/agent.py +228 -0
  13. maque_core-1.3.4/maque_core/kernel/budget.py +69 -0
  14. maque_core-1.3.4/maque_core/kernel/errors.py +46 -0
  15. maque_core-1.3.4/maque_core/kernel/loop.py +320 -0
  16. maque_core-1.3.4/maque_core/llm/__init__.py +39 -0
  17. maque_core-1.3.4/maque_core/llm/errors.py +258 -0
  18. maque_core-1.3.4/maque_core/llm/mock.py +91 -0
  19. maque_core-1.3.4/maque_core/llm/openai_compatible.py +309 -0
  20. maque_core-1.3.4/maque_core/tools/__init__.py +19 -0
  21. maque_core-1.3.4/maque_core/tools/_global_registry.py +38 -0
  22. maque_core-1.3.4/maque_core/tools/decorator.py +256 -0
  23. maque_core-1.3.4/maque_core/tools/discovery.py +105 -0
  24. maque_core-1.3.4/maque_core/tools/executor.py +147 -0
  25. maque_core-1.3.4/maque_core/tools/impl/__init__.py +1 -0
  26. maque_core-1.3.4/maque_core/tools/impl/add_tool.py +17 -0
  27. maque_core-1.3.4/maque_core/tools/impl/echo_tool.py +19 -0
  28. maque_core-1.3.4/maque_core/tools/registry.py +299 -0
  29. maque_core-1.3.4/maque_core.egg-info/PKG-INFO +612 -0
  30. maque_core-1.3.4/maque_core.egg-info/SOURCES.txt +43 -0
  31. maque_core-1.3.4/maque_core.egg-info/dependency_links.txt +1 -0
  32. maque_core-1.3.4/maque_core.egg-info/entry_points.txt +2 -0
  33. maque_core-1.3.4/maque_core.egg-info/requires.txt +9 -0
  34. maque_core-1.3.4/maque_core.egg-info/top_level.txt +1 -0
  35. maque_core-1.3.4/pyproject.toml +72 -0
  36. maque_core-1.3.4/setup.cfg +4 -0
  37. maque_core-1.3.4/tests/test_contracts.py +543 -0
  38. maque_core-1.3.4/tests/test_error_propagation.py +163 -0
  39. maque_core-1.3.4/tests/test_factory.py +35 -0
  40. maque_core-1.3.4/tests/test_integration.py +436 -0
  41. maque_core-1.3.4/tests/test_kernel.py +1206 -0
  42. maque_core-1.3.4/tests/test_llm.py +837 -0
  43. maque_core-1.3.4/tests/test_llm_resilience.py +593 -0
  44. maque_core-1.3.4/tests/test_public_api.py +29 -0
  45. maque_core-1.3.4/tests/test_tools.py +541 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gqx123
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,612 @@
1
+ Metadata-Version: 2.4
2
+ Name: maque-core
3
+ Version: 1.3.4
4
+ Summary: Lightweight, extensible Python Agent framework with ReAct loop, auto tool discovery, and budget protection.
5
+ Author-email: gqx123 <1195544755@qq.com>
6
+ Maintainer-email: gqx123 <1195544755@qq.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/gqx123/maque-core
9
+ Project-URL: Repository, https://github.com/gqx123/maque-core
10
+ Project-URL: Documentation, https://github.com/gqx123/maque-core#readme
11
+ Project-URL: Issues, https://github.com/gqx123/maque-core/issues
12
+ Project-URL: Discussions, https://github.com/gqx123/maque-core/discussions
13
+ Keywords: agent,llm,ai-agent,llm-agent,react,tool-use,agent-framework,openai-compatible,lightweight,python-agent
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: httpx>=0.24.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
32
+ Requires-Dist: build>=1.0; extra == "dev"
33
+ Requires-Dist: twine>=4.0; extra == "dev"
34
+ Provides-Extra: webui
35
+ Dynamic: license-file
36
+
37
+ <div align="center">
38
+
39
+ # maque_core
40
+
41
+ **轻量级可扩展 Python Agent 框架**
42
+
43
+ [![Python](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
44
+ [![License](https://img.shields.io/github/license/gqx123/maque-core?color=success)](https://github.com/gqx123/maque-core/blob/main/LICENSE)
45
+ [![GitHub Stars](https://img.shields.io/github/stars/gqx123/maque-core?style=social)](https://github.com/gqx123/maque-core/stargazers)
46
+ [![GitHub Forks](https://img.shields.io/github/forks/gqx123/maque-core?style=social)](https://github.com/gqx123/maque-core/network/members)
47
+ [![Issues](https://img.shields.io/github/issues/gqx123/maque-core)](https://github.com/gqx123/maque-core/issues)
48
+ [![Discussions](https://img.shields.io/badge/Discussions-Join%20the%20chat-blueviolet?logo=github)](https://github.com/gqx123/maque-core/discussions)
49
+
50
+ > ReAct 循环 · 工具自动发现 · 预算保护 · 面向协议设计
51
+
52
+ [快速开始](#快速开始) · [文档](#架构概览) · [示例](#快速开始) · [讨论](https://github.com/gqx123/maque-core/discussions)
53
+
54
+ </div>
55
+
56
+ ---
57
+
58
+ ## ✨ 为什么选择 maque_core?
59
+
60
+ | 特性 | 说明 |
61
+ |------|------|
62
+ | 🪶 **超轻量** | 核心代码 < 2000 行,零冗余依赖,读得懂、改得动 |
63
+ | 🔌 **即插即用** | `@tool` 装饰器一键注册工具,自动发现、自动生成 Schema |
64
+ | 🛡️ **安全可靠** | 双重预算保护 + 错误分类 + 超时控制,防止 Agent 失控 |
65
+ | 🔄 **ReAct 循环** | 原生支持推理-行动循环,思考过程独立追踪 |
66
+ | 🧩 **面向协议** | 各层基于 Protocol 抽象,LLM / 工具 / 执行后端均可替换 |
67
+ | 🌐 **OpenAI 兼容** | 无缝对接 DashScope、OpenAI、Ollama 等所有兼容 API |
68
+ | 🧪 **测试完备** | 300+ 测试用例,覆盖契约、LLM、工具、内核、集成全链路 |
69
+ | 🖥️ **内置 WebUI** | 自带 Web 界面 + JSON API,开箱即用 |
70
+
71
+ ## 🚀 一分钟上手
72
+
73
+ ```python
74
+ from maque_core import create_agent
75
+
76
+ agent = create_agent(model="qwen-turbo", api_key="your-key")
77
+ answer = agent.ask("What is 2 + 2?")
78
+ print(answer)
79
+ ```
80
+
81
+ 就这么简单。不需要配置注册表、不需要手动注册工具、不需要写复杂的初始化代码。
82
+
83
+ ---
84
+
85
+ ## 架构概览
86
+
87
+ ```
88
+ ┌─────────────────────────────────────────────────┐
89
+ │ app.py / CLI │ 应用入口
90
+ ├─────────────────────────────────────────────────┤
91
+ │ kernel (Agent / ReAct) │ 内核层:推理+行动循环
92
+ ├──────────────────┬──────────────────────────────┤
93
+ │ llm (Adapter) │ tools (Registry) │ 能力层:LLM + 工具
94
+ ├──────────────────┴──────────────────────────────┤
95
+ │ contracts (Protocol) │ 契约层:接口定义 + 数据结构
96
+ └─────────────────────────────────────────────────┘
97
+ ```
98
+
99
+ **设计原则:**
100
+ - **面向协议编程**:各层依赖抽象(Protocol),而非具体实现,方便替换
101
+ - **全局注册器模式**:`@tool` 装饰器在导入时注册到全局字典,解决模块缓存导致的工具发现问题
102
+ - **双重预算保护**:最大迭代次数 + 最大工具调用数,防止 Agent 失控
103
+ - **可插拔执行后端**:工具执行支持线程池、子进程、远程等多种后端
104
+
105
+ ## 快速开始
106
+
107
+ ### 安装
108
+
109
+ ```bash
110
+ cd maque_core-project
111
+ pip install -r requirements.txt
112
+ ```
113
+
114
+ ### 运行 Demo
115
+
116
+ ```bash
117
+ python examples/demo.py
118
+ ```
119
+
120
+ ### 交互式使用
121
+
122
+ ```bash
123
+ # 需要先配置 API Key
124
+ export MAQUE_LLM_API_KEY=your-api-key
125
+ python app.py -i
126
+ ```
127
+
128
+ ### 单次提问
129
+
130
+ ```bash
131
+ python app.py "What is 2 + 2?"
132
+ ```
133
+
134
+ ### 列出所有工具
135
+
136
+ ```bash
137
+ python app.py --list-tools
138
+ ```
139
+
140
+ ## 项目结构
141
+
142
+ ```
143
+ maque_core-project/
144
+ ├── maque_core/
145
+ │ ├── __init__.py
146
+ │ ├── config.py # 配置管理(支持环境变量)
147
+ │ ├── factory.py # create_agent() 工厂函数(统一入口)
148
+ │ ├── contracts/ # 契约层:接口 + 数据结构
149
+ │ │ ├── messages.py # Role / Message / ToolCall / LLMResponse / Observation
150
+ │ │ ├── llm.py # LLMProvider Protocol
151
+ │ │ └── tool.py # ToolSpec / ToolRegistry Protocol / CallBudget
152
+ │ ├── llm/ # LLM 适配器层
153
+ │ │ ├── openai_compatible.py # OpenAI 兼容 API 适配器
154
+ │ │ ├── errors.py # LLMError 异常分类
155
+ │ │ └── mock.py # Mock LLM(用于测试)
156
+ │ ├── tools/ # 工具层
157
+ │ │ ├── _global_registry.py # 全局注册器(解决模块缓存问题)
158
+ │ │ ├── decorator.py # @tool 装饰器
159
+ │ │ ├── registry.py # ToolRegistry(注册 + 执行 + 钩子)
160
+ │ │ ├── executor.py # ToolExecutor(可插拔执行后端)
161
+ │ │ ├── discovery.py # 工具自动发现
162
+ │ │ └── impl/ # 内置工具实现
163
+ │ │ ├── echo_tool.py
164
+ │ │ └── add_tool.py
165
+ │ └── kernel/ # 内核层
166
+ │ ├── budget.py # RunBudget(双重预算保护)
167
+ │ ├── loop.py # ReAct 循环
168
+ │ ├── errors.py # AgentRunError 异常
169
+ │ └── agent.py # Agent 高层接口
170
+ ├── tests/ # 测试
171
+ │ ├── test_contracts.py
172
+ │ ├── test_llm.py
173
+ │ ├── test_llm_resilience.py
174
+ │ ├── test_tools.py
175
+ │ ├── test_kernel.py
176
+ │ ├── test_integration.py
177
+ │ ├── test_error_propagation.py
178
+ │ ├── test_factory.py
179
+ │ └── test_public_api.py
180
+ ├── examples/
181
+ │ ├── demo.py # 端到端 Demo
182
+ │ └── tools/ # 示例工具(不在内核中)
183
+ │ └── file_tool.py
184
+ ├── app.py # CLI 入口
185
+ ├── webui.py # Web UI / JSON API
186
+ ├── requirements.txt
187
+ └── README.md
188
+ ```
189
+
190
+ ## 如何添加新工具
191
+
192
+ 只需 3 步:
193
+
194
+ 1. 在 `maque_core/tools/impl/` 下创建新的 `.py` 文件
195
+ 2. 用 `@tool` 装饰器标记你的函数
196
+ 3. 自动发现会在启动时加载它
197
+
198
+ ```python
199
+ from maque_core.tools import tool
200
+
201
+ @tool
202
+ def weather(city: str) -> str:
203
+ """查询指定城市的天气。"""
204
+ # 你的实现...
205
+ return f"{city}:晴,25°C"
206
+ ```
207
+
208
+ 框架会自动:
209
+ - 从类型注解生成 JSON Schema
210
+ - 识别必填参数(无默认值的参数)
211
+ - 注册到全局工具注册表
212
+ - 在 Agent 启动时自动发现
213
+
214
+ ## 如何替换 LLM 后端
215
+
216
+ 框架使用 `LLMProvider` Protocol,任何实现了 `chat()` 方法的类都可以作为 LLM 后端。
217
+
218
+ ### 使用 OpenAI 兼容 API(默认)
219
+
220
+ ```python
221
+ from maque_core.llm import OpenAICompatibleProvider
222
+
223
+ llm = OpenAICompatibleProvider(
224
+ model="qwen-turbo",
225
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
226
+ api_key="your-key",
227
+ )
228
+ ```
229
+
230
+ ### 自定义 LLM 后端
231
+
232
+ ```python
233
+ from maque_core.contracts.llm import LLMProvider
234
+ from maque_core.contracts.messages import LLMResponse, Message
235
+ from typing import List, Optional, Any
236
+
237
+ class MyLLM:
238
+ def chat(self, messages: List[Message], tools=None, **kwargs) -> LLMResponse:
239
+ # 你的实现...
240
+ return LLMResponse(content="Hello!")
241
+ ```
242
+
243
+ ## 配置说明
244
+
245
+ 所有配置都可以通过环境变量覆盖(前缀 `MAQUE_`):
246
+
247
+ | 环境变量 | 默认值 | 说明 |
248
+ |---------|--------|------|
249
+ | `MAQUE_LLM_MODEL` | `qwen-turbo` | 模型名称 |
250
+ | `MAQUE_LLM_BASE_URL` | DashScope 兼容模式 | API 地址 |
251
+ | `MAQUE_LLM_API_KEY` | 空 | API 密钥 |
252
+ | `MAQUE_LLM_TEMPERATURE` | `0.7` | 采样温度 |
253
+ | `MAQUE_LLM_TIMEOUT` | `60` | 请求超时(秒) |
254
+ | `MAQUE_LLM_MAX_TOKENS` | `2048` | 单次生成的最大 token 数 |
255
+ | `MAQUE_MAX_ITERATIONS` | `10` | 最大推理轮次 |
256
+ | `MAQUE_MAX_TOOL_CALLS` | 无限制 | 最大工具调用次数 |
257
+ | `MAQUE_VERBOSE` | `false` | 详细输出 |
258
+ | `MAQUE_TOOLS_PACKAGE` | `maque_core.tools.impl` | 工具包路径 |
259
+
260
+ ## 运行测试
261
+
262
+ ```bash
263
+ # 运行所有测试
264
+ pytest tests/ -v
265
+
266
+ # 运行特定模块测试
267
+ pytest tests/test_contracts.py -v
268
+ pytest tests/test_tools.py -v
269
+ pytest tests/test_kernel.py -v
270
+ pytest tests/test_integration.py -v
271
+
272
+ # 统计测试数量
273
+ pytest tests/ --collect-only -q
274
+ ```
275
+
276
+ ## LLM 错误处理与截断识别
277
+
278
+ LLM 调用失败时**不会再伪装成正常回答**。`LLMResponse` 新增两个可选字段:
279
+
280
+ | 字段 | 类型 | 说明 |
281
+ |------|------|------|
282
+ | `error` | `Optional[str]` | 调用失败时为错误描述,`None` 表示真实模型输出。也可用 `response.is_error` 判断 |
283
+ | `finish_reason` | `Optional[str]` | 模型停止原因,原样透传:`stop` / `length` / `tool_calls` / `content_filter`。`length` 表示被 token 上限截断,也可用 `response.is_truncated` 判断 |
284
+
285
+ 失败时 `content` 仍保留错误文本(便于展示),但**上层必须判断 `error`,不能把 `content` 当答案**。
286
+
287
+ ### 两种失败处理模式
288
+
289
+ ```python
290
+ from maque_core.llm import OpenAICompatibleProvider, LLMError, LLMAuthError
291
+
292
+ llm = OpenAICompatibleProvider(model="qwen-turbo", api_key="your-key")
293
+
294
+ # 默认(raise_on_error=False)——兼容既有调用方:返回带 error 字段的响应
295
+ resp = llm.chat(messages)
296
+ if resp.is_error:
297
+ ... # 重试或告警
298
+
299
+ # raise_on_error=True——直接抛出分类异常
300
+ try:
301
+ resp = llm.chat(messages, raise_on_error=True)
302
+ except LLMAuthError: # 401 / 403,重试无意义
303
+ ...
304
+ except LLMError as err: # 其余情况
305
+ if err.retryable:
306
+ ... # 退避重试
307
+ ```
308
+
309
+ ### 异常分类(`maque_core/llm/errors.py`)
310
+
311
+ | 异常 | `category` | `retryable` | 触发场景 |
312
+ |------|-----------|-------------|---------|
313
+ | `LLMNetworkError` | `network` | ✅ | 连接失败、DNS、代理 |
314
+ | `LLMTimeoutError` | `timeout` | ✅ | 连接 / 读 / 写超时(`NetworkError` 的子类,但可区分) |
315
+ | `LLMHTTPError` | `http` | ❌ | 其余非 2xx |
316
+ | `LLMAuthError` | `auth` | ❌ | 401 / 403 鉴权失败 |
317
+ | `LLMRateLimitError` | `rate_limit` | ✅ | 429 限流 |
318
+ | `LLMServerError` | `server` | ✅ | 5xx 上游故障 |
319
+ | `LLMResponseError` | `response` | ❌ | 响应无法解析 / 结构异常 |
320
+
321
+ 所有异常携带 `status_code`、`original`(原始异常)与 `to_dict()`,便于结构化日志。
322
+
323
+ ### max_tokens
324
+
325
+ 请求体现在会带上 `max_tokens`,不再依赖服务端默认值:
326
+
327
+ ```python
328
+ llm = OpenAICompatibleProvider(max_tokens=2048) # 构造时设定默认值
329
+ llm.chat(messages, max_tokens=512) # 单次覆盖,不改动默认值
330
+ llm = OpenAICompatibleProvider(max_tokens=None) # 显式关闭,回到服务端默认
331
+ ```
332
+
333
+ 优先级:`chat(max_tokens=...)` > `chat(**kwargs)` > 构造参数;非正整数与 `bool` 会被忽略(`True` 是 `int` 子类,不会被当成 `1`)。
334
+
335
+ ## 模块职责
336
+
337
+ | 模块 | 职责 | 关键类/函数 |
338
+ |------|------|------------|
339
+ | **contracts** | 定义所有层之间的接口契约和数据结构 | `Message`, `LLMProvider`, `ToolRegistry`, `ToolSpec` |
340
+ | **llm** | LLM 后端适配器,将不同的 LLM API 统一成 LLMProvider 接口,并对失败做分类 | `OpenAICompatibleProvider`, `MockLLM`, `LLMError` |
341
+ | **tools** | 工具注册、发现、执行和验证 | `@tool`, `ToolRegistry`, `discover_tools()`, `ToolExecutor` |
342
+ | **kernel** | Agent 核心循环,管理 ReAct 流程和预算 | `Agent`, `react_loop()`, `RunBudget` |
343
+ | **app** | 应用入口,CLI 命令行界面 | `app.py`, `examples/demo.py` |
344
+
345
+ ## 安全机制
346
+
347
+ - **预算保护**:双重限制(最大迭代 + 最大工具调用),防止 Agent 无限循环
348
+ - **参数验证**:工具执行前验证参数类型和必填项
349
+ - **错误隔离**:工具执行错误被捕获并返回给 LLM,不会导致 Agent 崩溃
350
+ - **超时控制**:工具执行支持超时限制(通过 ToolExecutor)
351
+ - **钩子系统**:支持 before/after 钩子,可用于日志、审计、限流等
352
+
353
+ ## 思考内容(Reasoning)支持
354
+
355
+ 框架支持从 LLM 响应中提取思考内容(Chain-of-Thought / Reasoning),并以 `latest_reasoning` 属性暴露给调用方。
356
+
357
+ ### 核心特性
358
+
359
+ - **三级提取策略**:按优先级依次尝试 `reasoning_content`(Qwen3/DashScope 原生)→ `reasoning`(部分 API)→ 内联 `<think>...</think>` 标签剥离
360
+ - **只保留最新**:`agent.latest_reasoning` 每次 LLM 调用后覆盖更新,只保留最近一轮的思考内容,不会累积
361
+ - **不进入对话历史**:思考内容不会被添加到 messages 中,避免污染对话上下文和增加 token 消耗
362
+ - **独立于回答**:思考内容与最终回答分离,`content` 是纯文本回答,`reasoning` 是思考过程
363
+
364
+ ### 使用方式
365
+
366
+ ```python
367
+ from maque_core.kernel import Agent
368
+
369
+ agent = Agent(llm=my_llm, registry=my_registry)
370
+ answer = agent.ask("Explain quantum computing.")
371
+
372
+ # 访问最新一轮的思考内容
373
+ print("思考过程:", agent.latest_reasoning)
374
+ print("最终回答:", answer)
375
+ ```
376
+
377
+ ### 多轮工具调用场景
378
+
379
+ 在一次包含多轮工具调用的 `ask()` 中,`latest_reasoning` 只保留**最后一轮** LLM 调用的思考内容:
380
+
381
+ ```python
382
+ # 假设场景:用户问 (10 + 5) * 3
383
+ # 第 1 轮:LLM 思考 → 调用 add(10, 5) → reasoning = "先算加法"
384
+ # 第 2 轮:LLM 思考 → 调用 multiply(15, 3) → reasoning = "再算乘法"
385
+ # 第 3 轮:LLM 给出最终答案 → reasoning = "结果是 45"
386
+
387
+ answer = agent.ask("What is (10 + 5) * 3?")
388
+ print(agent.latest_reasoning) # 只输出 "结果是 45",前两轮的思考不保留
389
+ ```
390
+
391
+ ### 数据结构
392
+
393
+ `LLMResponse` 新增 `reasoning: Optional[str]` 字段:
394
+
395
+ ```python
396
+ @dataclass
397
+ class LLMResponse:
398
+ content: str
399
+ tool_calls: List[ToolCall] = field(default_factory=list)
400
+ reasoning: Optional[str] = None # 新增:思考内容
401
+ model: Optional[str] = None
402
+ ```
403
+
404
+ ## 多轮对话(Multi-turn)
405
+
406
+ 框架原生支持多轮对话记忆——每次 `agent.ask()` 会自动带上之前的对话历史,无需手动管理。
407
+
408
+ ### 基本用法
409
+
410
+ ```python
411
+ from maque_core.kernel import Agent
412
+
413
+ agent = Agent(llm=my_llm, registry=my_registry)
414
+
415
+ # 第一轮
416
+ answer1 = agent.ask("What's the capital of France?")
417
+ # → "Paris"
418
+
419
+ # 第二轮:自动带上第一轮的上下文
420
+ answer2 = agent.ask("What's its population?")
421
+ # → 模型知道 "its" 指代 Paris
422
+ ```
423
+
424
+ ### 重置对话
425
+
426
+ 用 `reset()` 清空历史,开始全新对话:
427
+
428
+ ```python
429
+ agent.reset()
430
+ answer = agent.ask("Let's talk about something else.")
431
+ # 此时历史中只有 system prompt + 这一轮
432
+ ```
433
+
434
+ ### REPL 模式下的多轮对话
435
+
436
+ 交互式模式(`-i` / `--interactive`)默认启用多轮记忆。可用命令:
437
+
438
+ | 命令 | 说明 |
439
+ |------|------|
440
+ | `/reset` | 重置对话,清空历史 |
441
+ | `/tools` | 列出所有可用工具 |
442
+ | `exit` / `quit` / `q` | 退出交互模式 |
443
+
444
+ ## 历史裁剪策略
445
+
446
+ 多轮对话会不断累积上下文,最终可能超过模型的上下文窗口。框架内置自动裁剪机制。
447
+
448
+ ### 工作原理
449
+
450
+ - 配置项 `max_history_turns`(默认 20 轮)控制保留多少轮对话
451
+ - 每次 `ask()` 开头自动检查并裁剪,保留 system prompt + 最近 N 轮完整对话
452
+ - 裁剪单位是"完整轮次"(user → assistant → tool calls → tool results 整体),不会截断半轮
453
+ - system prompt 永远保留在第 0 位
454
+
455
+ ### 配置方式
456
+
457
+ ```python
458
+ # 构造时设置
459
+ agent = Agent(llm=my_llm, registry=my_registry, max_history_turns=10)
460
+
461
+ # 或通过环境变量
462
+ export MAQUE_MAX_HISTORY_TURNS=10
463
+ ```
464
+
465
+ 设为 0 或负数时禁用裁剪(不推荐,上下文可能爆掉)。
466
+
467
+ ### 裁剪示意
468
+
469
+ ```
470
+ max_history_turns = 3,当前有 5 轮对话:
471
+
472
+ [system] [U1] [A1] [U2] [A2+tools] [U3] [A3] [U4] [A4] [U5] [A5]
473
+ ↑ ↑
474
+ 裁剪掉前 2 轮 保留最近 3 轮 + 新轮次
475
+
476
+ 裁剪后:
477
+ [system] [U3] [A3] [U4] [A4] [U5] [A5] + 新的 U6
478
+ ```
479
+
480
+ ## Reasoning 入历史策略
481
+
482
+ 默认情况下,每轮的 reasoning 只保存在 `latest_reasoning` 中,不进入对话历史。但多轮对话时,模型后续轮次可能需要看到之前的推理依据才能保持连贯。
483
+
484
+ ### "裁剪后带上"策略
485
+
486
+ 框架采用 **include_reasoning_in_history** 开关(默认 `True`):
487
+
488
+ - **开启时**:每轮的 reasoning 作为 assistant 消息的一部分存入历史(`Message.reasoning` 字段)
489
+ - **关闭时**:reasoning 只保留在 `latest_reasoning`,不进历史(省 token)
490
+ - 历史裁剪时,reasoning 随消息一起被裁剪
491
+ - 发送给 LLM 时,reasoning 通过 `reasoning_content` 字段传递(兼容 Qwen3 / DashScope 等模型)
492
+
493
+ ### 配置方式
494
+
495
+ ```python
496
+ # 开启(默认)
497
+ agent = Agent(llm=my_llm, registry=my_registry, include_reasoning_in_history=True)
498
+
499
+ # 关闭(省 token)
500
+ agent = Agent(llm=my_llm, registry=my_registry, include_reasoning_in_history=False)
501
+
502
+ # 或通过环境变量
503
+ export MAQUE_INCLUDE_REASONING_IN_HISTORY=false
504
+ ```
505
+
506
+ ### latest_reasoning 始终可用
507
+
508
+ 无论是否开启 reasoning 入历史,`agent.latest_reasoning` 始终指向最后一轮的思考内容:
509
+
510
+ ```python
511
+ agent = Agent(llm=my_llm, registry=my_registry, include_reasoning_in_history=False)
512
+ answer = agent.ask("Explain photosynthesis.")
513
+ print(agent.latest_reasoning) # 仍然可以访问最后一轮的思考
514
+ ```
515
+
516
+ ### Message 数据结构
517
+
518
+ `Message` 新增 `reasoning` 字段:
519
+
520
+ ```python
521
+ @dataclass
522
+ class Message:
523
+ role: Role
524
+ content: str = ""
525
+ tool_calls: List[ToolCall] = field(default_factory=list)
526
+ tool_call_id: Optional[str] = None
527
+ tool_name: Optional[str] = None
528
+ reasoning: Optional[str] = None # 新增:该消息关联的思考内容
529
+ ```
530
+
531
+ ## 输出截断自动续答(finish_reason)
532
+
533
+ 当 LLM 因为 token 限制截断输出(`finish_reason == "length"`)时,ReAct 循环会自动追加一条"请继续"的系统提示并重试一次,让模型把被截断的回答补完。
534
+
535
+ ### 行为说明
536
+
537
+ - 仅在 `finish_reason == "length"` 且还有迭代预算时触发
538
+ - 最多重试 1 次,防止无限循环
539
+ - 两轮内容自动拼接,调用方拿到的是完整答案
540
+ - 工具调用阶段的截断不触发重试(只在纯文本输出时生效)
541
+
542
+ ### 预算耗尽补 tool 消息
543
+
544
+ 当工具调用预算耗尽时,框架会为未执行的 tool_call 补充一条对应的 tool 消息(说明预算耗尽),保证消息历史中 `tool_calls` 和 `tool_result` 一一对应,避免某些模型 API 因结构不匹配报错。
545
+
546
+ ## 配置说明(完整)
547
+
548
+ 所有配置都可以通过环境变量覆盖(前缀 `MAQUE_`):
549
+
550
+ | 环境变量 | 默认值 | 说明 |
551
+ |---------|--------|------|
552
+ | `MAQUE_LLM_MODEL` | `qwen-turbo` | 模型名称 |
553
+ | `MAQUE_LLM_BASE_URL` | DashScope 兼容模式 | API 地址 |
554
+ | `MAQUE_LLM_API_KEY` | 空 | API 密钥 |
555
+ | `MAQUE_LLM_TEMPERATURE` | `0.7` | 采样温度 |
556
+ | `MAQUE_LLM_TIMEOUT` | `60` | 请求超时(秒) |
557
+ | `MAQUE_LLM_MAX_TOKENS` | `2048` | 单次生成的最大 token 数 |
558
+ | `MAQUE_MAX_ITERATIONS` | `10` | 单次 ask 内最大推理轮次 |
559
+ | `MAQUE_MAX_TOOL_CALLS` | 无限制 | 单次 ask 内最大工具调用次数 |
560
+ | `MAQUE_MAX_HISTORY_TURNS` | `20` | 多轮对话最大保留轮数 |
561
+ | `MAQUE_INCLUDE_REASONING_IN_HISTORY` | `true` | 是否将 reasoning 存入对话历史 |
562
+ | `MAQUE_VERBOSE` | `false` | 详细输出 |
563
+ | `MAQUE_TOOLS_PACKAGE` | `maque_core.tools.impl` | 工具包路径 |
564
+
565
+ ## License
566
+
567
+ MIT
568
+
569
+
570
+ ---
571
+
572
+ ## 🗺️ 路线图 (Roadmap)
573
+
574
+ 我们正在持续迭代,以下是规划中的功能:
575
+
576
+ - [ ] **多模态支持** — 支持图片输入的视觉 Agent
577
+ - [ ] **记忆系统** — 长期记忆 + 向量检索,让 Agent 记住上下文
578
+ - [ ] **流式输出** — SSE 流式响应,提升交互体验
579
+ - [ ] **更多内置工具** — 搜索、爬虫、代码执行等常用工具
580
+ - [ ] **工具沙箱** — 安全执行不受信任的工具代码
581
+ - [ ] **多 Agent 协作** — 支持多个 Agent 分工协作
582
+ - [ ] **LangChain 兼容层** — 无缝接入 LangChain 生态
583
+
584
+ 有想法?欢迎在 [Discussions](https://github.com/gqx123/maque-core/discussions) 里提出来!
585
+
586
+ ## 🤝 贡献指南
587
+
588
+ 欢迎贡献代码、文档或想法!请查看 [CONTRIBUTING.md](CONTRIBUTING.md) 了解详细流程。
589
+
590
+ **快速参与:**
591
+ - ⭐ **点个 Star** — 这是对我们最大的支持
592
+ - 🐛 **提交 Issue** — 发现 Bug 或有功能建议?[开一个 Issue](https://github.com/gqx123/maque-core/issues/new)
593
+ - 💬 **参与讨论** — 在 [Discussions](https://github.com/gqx123/maque-core/discussions) 分享你的使用经验
594
+ - 🔧 **提交 PR** — 修复 Bug、添加功能、改进文档都欢迎
595
+
596
+ ## 📄 许可证
597
+
598
+ 本项目基于 [MIT License](LICENSE) 开源,可自由使用、修改和分发。
599
+
600
+ ## 🙏 致谢
601
+
602
+ 感谢所有为这个项目做出贡献的人!
603
+
604
+ ---
605
+
606
+ <div align="center">
607
+
608
+ **如果这个项目对你有帮助,别忘了点个 ⭐ Star 支持一下!**
609
+
610
+ Made with ❤️ by [gqx123](https://github.com/gqx123)
611
+
612
+ </div>