bolt-boot 0.1.0__py3-none-any.whl
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.
- bolt/__init__.py +23 -0
- bolt/__main__.py +18 -0
- bolt/agent/__init__.py +39 -0
- bolt/agent/base.py +282 -0
- bolt/agent/example.py +94 -0
- bolt/agent/memory.py +375 -0
- bolt/agent/messages.py +48 -0
- bolt/agent/oxy/__init__.py +24 -0
- bolt/agent/oxy/engine.py +285 -0
- bolt/agent/oxy/llm_compat.py +132 -0
- bolt/agent/oxy/mapping.py +275 -0
- bolt/agent/oxy/mas_api.py +390 -0
- bolt/agent/oxy/runtime.py +588 -0
- bolt/agent/tools.py +125 -0
- bolt/api/__init__.py +85 -0
- bolt/api/deps.py +155 -0
- bolt/api/health.py +501 -0
- bolt/api/openapi.py +291 -0
- bolt/api/rate_limit.py +421 -0
- bolt/cli/commands/__init__.py +1 -0
- bolt/cli/commands/agent.py +114 -0
- bolt/cli/commands/docs.py +56 -0
- bolt/cli/commands/generate.py +535 -0
- bolt/cli/commands/init.py +277 -0
- bolt/cli/commands/migrate.py +277 -0
- bolt/cli/commands/rag.py +137 -0
- bolt/cli/console.py +8 -0
- bolt/cli/main.py +375 -0
- bolt/core/__init__.py +84 -0
- bolt/core/app.py +497 -0
- bolt/core/config.py +332 -0
- bolt/core/database.py +167 -0
- bolt/core/di.py +463 -0
- bolt/core/exceptions.py +419 -0
- bolt/core/lifecycle.py +144 -0
- bolt/core/logging.py +310 -0
- bolt/core/middleware.py +411 -0
- bolt/core/plugin.py +108 -0
- bolt/core/propagation.py +72 -0
- bolt/core/protocols.py +79 -0
- bolt/core/response.py +190 -0
- bolt/core/telemetry.py +214 -0
- bolt/domain/__init__.py +34 -0
- bolt/domain/events.py +220 -0
- bolt/domain/model.py +140 -0
- bolt/domain/repository/__init__.py +13 -0
- bolt/domain/repository/base.py +695 -0
- bolt/domain/repository/bulk.py +209 -0
- bolt/domain/repository/cache.py +134 -0
- bolt/domain/repository/filters.py +86 -0
- bolt/domain/repository/pagination.py +61 -0
- bolt/domain/schema.py +138 -0
- bolt/domain/service.py +251 -0
- bolt/domain/transaction.py +387 -0
- bolt/infrastructure/__init__.py +99 -0
- bolt/infrastructure/cache.py +252 -0
- bolt/infrastructure/cache_backends.py +237 -0
- bolt/infrastructure/config_center/__init__.py +349 -0
- bolt/infrastructure/distributed_lock.py +199 -0
- bolt/infrastructure/mq/__init__.py +242 -0
- bolt/infrastructure/mq/kafka.py +274 -0
- bolt/infrastructure/mq/rabbitmq.py +247 -0
- bolt/infrastructure/mq/rocketmq.py +254 -0
- bolt/infrastructure/observability/__init__.py +410 -0
- bolt/infrastructure/registry/__init__.py +73 -0
- bolt/infrastructure/registry/consul.py +209 -0
- bolt/infrastructure/registry/nacos.py +204 -0
- bolt/infrastructure/resilience/__init__.py +530 -0
- bolt/infrastructure/scheduler.py +444 -0
- bolt/infrastructure/scheduler_backends.py +186 -0
- bolt/infrastructure/scheduler_models.py +277 -0
- bolt/py.typed +0 -0
- bolt/rag/__init__.py +51 -0
- bolt/rag/advanced/__init__.py +40 -0
- bolt/rag/advanced/advanced_retriever.py +146 -0
- bolt/rag/advanced/citation.py +69 -0
- bolt/rag/advanced/compression.py +88 -0
- bolt/rag/advanced/reranker.py +215 -0
- bolt/rag/advanced/retriever.py +154 -0
- bolt/rag/advanced/search.py +149 -0
- bolt/rag/documents.py +28 -0
- bolt/rag/embeddings.py +241 -0
- bolt/rag/knowledge_graph/__init__.py +79 -0
- bolt/rag/knowledge_graph/extractor.py +114 -0
- bolt/rag/knowledge_graph/graph_rag.py +158 -0
- bolt/rag/knowledge_graph/models.py +69 -0
- bolt/rag/knowledge_graph/stores.py +462 -0
- bolt/rag/llm.py +159 -0
- bolt/rag/loaders.py +725 -0
- bolt/rag/multimodal/__init__.py +42 -0
- bolt/rag/multimodal/audio.py +118 -0
- bolt/rag/multimodal/base.py +38 -0
- bolt/rag/multimodal/image.py +186 -0
- bolt/rag/multimodal/loader.py +190 -0
- bolt/rag/multimodal/table.py +138 -0
- bolt/rag/multimodal/video.py +234 -0
- bolt/rag/retriever.py +382 -0
- bolt/rag/splitters.py +276 -0
- bolt/rag/vectorstore.py +448 -0
- bolt/security/__init__.py +135 -0
- bolt/security/api_key.py +250 -0
- bolt/security/audit.py +204 -0
- bolt/security/brute_force.py +177 -0
- bolt/security/jwt.py +575 -0
- bolt/security/jwt_blacklist.py +108 -0
- bolt/security/jwt_keys.py +80 -0
- bolt/security/password.py +174 -0
- bolt/security/permissions.py +272 -0
- bolt/security/tenant.py +489 -0
- bolt_boot-0.1.0.dist-info/METADATA +492 -0
- bolt_boot-0.1.0.dist-info/RECORD +114 -0
- bolt_boot-0.1.0.dist-info/WHEEL +4 -0
- bolt_boot-0.1.0.dist-info/entry_points.txt +2 -0
- bolt_boot-0.1.0.dist-info/licenses/LICENSE +21 -0
bolt/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Bolt - AI-Native FastAPI Framework"""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
__all__ = ["App", "create_app", "get_settings"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def __getattr__(name: str) -> Any:
|
|
11
|
+
if name == "App":
|
|
12
|
+
from bolt.core.app import App
|
|
13
|
+
|
|
14
|
+
return App
|
|
15
|
+
if name == "create_app":
|
|
16
|
+
from bolt.core.app import create_app
|
|
17
|
+
|
|
18
|
+
return create_app
|
|
19
|
+
if name == "get_settings":
|
|
20
|
+
from bolt.core.config import get_settings
|
|
21
|
+
|
|
22
|
+
return get_settings
|
|
23
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
bolt/__main__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""内置演示应用,``python -m bolt`` / 镜像默认 CMD 的可运行入口。
|
|
2
|
+
|
|
3
|
+
提供一个最小可用的 Bolt 实例(健康检查、指标等基础端点),
|
|
4
|
+
用于容器镜像冒烟与快速验证。业务应用请自行 ``create_app``
|
|
5
|
+
并覆盖容器的 CMD。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from bolt.core.app import create_app
|
|
11
|
+
|
|
12
|
+
app = create_app(title="Bolt Demo")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
import uvicorn
|
|
17
|
+
|
|
18
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
bolt/agent/__init__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Agent 模块 - 底层由 OxyGent MAS 驱动。
|
|
2
|
+
|
|
3
|
+
提供 AI Agent 开发能力:
|
|
4
|
+
- BoltAgent: Agent 基类(对话/工具循环/流式,OxyGent ReAct 驱动)
|
|
5
|
+
- ToolRegistry: 工具注册表
|
|
6
|
+
- ConversationMemory: 会话记忆(内存/Redis/数据库)
|
|
7
|
+
- MultiAgentSystem: 多 Agent 编排(master 委派 sub_agents)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from bolt.agent.base import AgentResult, BoltAgent, tool
|
|
11
|
+
from bolt.agent.memory import (
|
|
12
|
+
ConversationMemory,
|
|
13
|
+
DatabaseConversationMemory,
|
|
14
|
+
RedisConversationMemory,
|
|
15
|
+
create_memory,
|
|
16
|
+
)
|
|
17
|
+
from bolt.agent.messages import ChatMessage
|
|
18
|
+
from bolt.agent.oxy.mas_api import AgentSpec, AgentStreamEvent, MultiAgentSystem
|
|
19
|
+
from bolt.agent.tools import Tool, ToolRegistry
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
# Agent
|
|
23
|
+
"BoltAgent",
|
|
24
|
+
"AgentResult",
|
|
25
|
+
"tool",
|
|
26
|
+
"ChatMessage",
|
|
27
|
+
# 工具
|
|
28
|
+
"ToolRegistry",
|
|
29
|
+
"Tool",
|
|
30
|
+
# 多 Agent 编排
|
|
31
|
+
"MultiAgentSystem",
|
|
32
|
+
"AgentSpec",
|
|
33
|
+
"AgentStreamEvent",
|
|
34
|
+
# 记忆
|
|
35
|
+
"ConversationMemory",
|
|
36
|
+
"RedisConversationMemory",
|
|
37
|
+
"DatabaseConversationMemory",
|
|
38
|
+
"create_memory",
|
|
39
|
+
]
|
bolt/agent/base.py
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""Agent 基类 - 底层由 OxyGent MAS 驱动。
|
|
2
|
+
|
|
3
|
+
BoltAgent 的对话/工具循环/多 Agent 委派全部由内嵌的 OxyGent 引擎完成:
|
|
4
|
+
- 有工具的 Agent 映射为 OxyGent ``ReActAgent``(完整的工具调用循环)
|
|
5
|
+
- 无工具的 Agent 映射为 ``ChatAgent``
|
|
6
|
+
- MAS 实例进程级单例,懒启动(首次调用时初始化)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from collections import OrderedDict
|
|
13
|
+
from collections.abc import AsyncIterator, Callable
|
|
14
|
+
from typing import TYPE_CHECKING, Any, ParamSpec, TypeVar
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, Field
|
|
17
|
+
|
|
18
|
+
from bolt.agent.messages import ChatMessage
|
|
19
|
+
from bolt.agent.tools import Tool
|
|
20
|
+
from bolt.core.config import get_settings
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from bolt.agent.memory import ConversationMemory
|
|
24
|
+
from bolt.agent.oxy.engine import OxyEngine
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"BoltAgent",
|
|
28
|
+
"AgentResult",
|
|
29
|
+
"tool",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
P = ParamSpec("P")
|
|
33
|
+
R = TypeVar("R")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ============ 工具装饰器 ============
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def tool(
|
|
40
|
+
name: str | None = None,
|
|
41
|
+
description: str = "",
|
|
42
|
+
) -> Callable[..., Any]:
|
|
43
|
+
"""Tool 装饰器 - 标记方法为可被 Agent 调用的工具。
|
|
44
|
+
|
|
45
|
+
装饰后原函数原样返回(可直接调用),仅附加工具元信息;
|
|
46
|
+
元信息在 MAS 启动时桥接为 OxyGent FunctionTool。
|
|
47
|
+
|
|
48
|
+
用法:
|
|
49
|
+
@tool(description="搜索知识库")
|
|
50
|
+
async def search_kb(self, query: str) -> str:
|
|
51
|
+
return await self.kb.search(query)
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def decorator(func: Callable[P, R]) -> Callable[P, R]:
|
|
55
|
+
tool_name = name or func.__name__
|
|
56
|
+
tool_desc = description or func.__doc__ or ""
|
|
57
|
+
|
|
58
|
+
# 附加 Tool 元信息(MAS 启动时桥接为 FunctionTool)。
|
|
59
|
+
# 动态属性经 setattr 注入:ruff B010 豁免 + 规避函数对象属性声明
|
|
60
|
+
setattr(func, "_bolt_is_tool", True) # noqa: B010
|
|
61
|
+
setattr(func, "_bolt_tool_name", tool_name) # noqa: B010
|
|
62
|
+
setattr(func, "_bolt_tool_description", tool_desc) # noqa: B010
|
|
63
|
+
|
|
64
|
+
return func
|
|
65
|
+
|
|
66
|
+
return decorator
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ============ Agent 结果 ============
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class AgentResult(BaseModel):
|
|
73
|
+
"""Agent 执行结果"""
|
|
74
|
+
|
|
75
|
+
success: bool = Field(default=True, description="是否成功")
|
|
76
|
+
output: str = Field(default="", description="输出内容")
|
|
77
|
+
error: str | None = Field(default=None, description="错误信息")
|
|
78
|
+
messages: list[ChatMessage] = Field(default_factory=list, description="消息历史")
|
|
79
|
+
tool_calls: list[dict[str, Any]] = Field(default_factory=list, description="工具调用记录")
|
|
80
|
+
token_usage: dict[str, int] = Field(default_factory=dict, description="Token 使用")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# ============ Agent 基类 ============
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class BoltAgent(ABC):
|
|
87
|
+
"""Agent 基类 - 由 OxyGent 引擎驱动。
|
|
88
|
+
|
|
89
|
+
用法:
|
|
90
|
+
class CommentAgent(BoltAgent):
|
|
91
|
+
def __init__(self):
|
|
92
|
+
super().__init__(
|
|
93
|
+
name="comment_agent",
|
|
94
|
+
model="gpt-4o",
|
|
95
|
+
system_prompt="你是一个评论生成专家",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@tool(description="搜索相关笔记内容")
|
|
99
|
+
async def search_notes(self, query: str) -> str:
|
|
100
|
+
return await self.note_service.search(query)
|
|
101
|
+
|
|
102
|
+
async def run(self, note_url: str) -> AgentResult:
|
|
103
|
+
# invoke 内部由 OxyGent ReAct 循环驱动工具调用
|
|
104
|
+
comment = await self.invoke(f"为笔记生成评论: {note_url}")
|
|
105
|
+
return AgentResult(output=comment)
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def __init__(
|
|
109
|
+
self,
|
|
110
|
+
name: str,
|
|
111
|
+
*,
|
|
112
|
+
model: str | None = None,
|
|
113
|
+
provider: str | None = None,
|
|
114
|
+
system_prompt: str | None = None,
|
|
115
|
+
temperature: float = 0.7,
|
|
116
|
+
max_tokens: int = 4096,
|
|
117
|
+
) -> None:
|
|
118
|
+
self.name = name
|
|
119
|
+
self.model = model or get_settings().llm_default_model or "gpt-4o"
|
|
120
|
+
self.provider = provider or get_settings().llm_default_provider or "openai"
|
|
121
|
+
self.system_prompt = system_prompt
|
|
122
|
+
self.temperature = temperature
|
|
123
|
+
self.max_tokens = max_tokens
|
|
124
|
+
|
|
125
|
+
# 工具注册表(OxyGent MAS 启动时桥接为 FunctionHub)
|
|
126
|
+
self._tools: dict[str, Tool] = {}
|
|
127
|
+
self._register_tools()
|
|
128
|
+
|
|
129
|
+
# 会话记忆缓存(session_id -> ConversationMemory)。
|
|
130
|
+
# 有界(LRU 语义):对话型 Agent 的 session_id 是用户规模级的,
|
|
131
|
+
# 不设上限会随会话数慢性泄漏内存
|
|
132
|
+
self._memories: OrderedDict[str, ConversationMemory] = OrderedDict()
|
|
133
|
+
self._memories_maxsize = 1000
|
|
134
|
+
|
|
135
|
+
# 引擎句柄(懒创建)
|
|
136
|
+
self._engine: OxyEngine | None = None
|
|
137
|
+
|
|
138
|
+
# 登记到 OxyGent 运行时(纯同步登记;MAS 懒启动时物化)
|
|
139
|
+
from bolt.agent.oxy.runtime import get_oxy_runtime
|
|
140
|
+
|
|
141
|
+
get_oxy_runtime().register_agent(self)
|
|
142
|
+
|
|
143
|
+
def _register_tools(self) -> None:
|
|
144
|
+
"""自动注册带 @tool 装饰器的方法(沿 MRO 收集,父类工具可继承)。
|
|
145
|
+
|
|
146
|
+
反向遍历 MRO 使子类对同名工具的覆盖优先生效。
|
|
147
|
+
"""
|
|
148
|
+
seen: set[str] = set()
|
|
149
|
+
for klass in reversed(type(self).__mro__):
|
|
150
|
+
for attr_name, attr in klass.__dict__.items():
|
|
151
|
+
if not (callable(attr) and getattr(attr, "_bolt_is_tool", False)):
|
|
152
|
+
continue
|
|
153
|
+
if attr._bolt_tool_name in seen:
|
|
154
|
+
continue
|
|
155
|
+
seen.add(attr._bolt_tool_name)
|
|
156
|
+
self._tools[attr._bolt_tool_name] = Tool(
|
|
157
|
+
name=attr._bolt_tool_name,
|
|
158
|
+
description=attr._bolt_tool_description,
|
|
159
|
+
func=getattr(self, attr_name),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def get_tools(self) -> list[Tool]:
|
|
163
|
+
"""获取所有注册的工具"""
|
|
164
|
+
return list(self._tools.values())
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def has_tools(self) -> bool:
|
|
168
|
+
"""是否注册了工具(决定 ReAct / Chat 映射与流式策略)"""
|
|
169
|
+
return bool(self._tools)
|
|
170
|
+
|
|
171
|
+
def get_memory(self, session_id: str = "default") -> ConversationMemory:
|
|
172
|
+
"""获取(或创建)指定会话的记忆(同一 session_id 复用同一实例,LRU 淘汰最旧)。"""
|
|
173
|
+
if session_id not in self._memories:
|
|
174
|
+
self._memories[session_id] = get_memory_backend(session_id=session_id)
|
|
175
|
+
self._memories.move_to_end(session_id)
|
|
176
|
+
while len(self._memories) > self._memories_maxsize:
|
|
177
|
+
self._memories.popitem(last=False)
|
|
178
|
+
return self._memories[session_id]
|
|
179
|
+
|
|
180
|
+
# ============ OxyGent 引擎调用 ============
|
|
181
|
+
|
|
182
|
+
def _get_oxy_engine(self) -> OxyEngine:
|
|
183
|
+
from bolt.agent.oxy.engine import OxyEngine
|
|
184
|
+
from bolt.agent.oxy.runtime import get_oxy_runtime
|
|
185
|
+
|
|
186
|
+
if self._engine is None:
|
|
187
|
+
self._engine = OxyEngine(agent=self, runtime=get_oxy_runtime())
|
|
188
|
+
return self._engine
|
|
189
|
+
|
|
190
|
+
async def chat(
|
|
191
|
+
self,
|
|
192
|
+
messages: str | list[ChatMessage | dict[str, str]],
|
|
193
|
+
*,
|
|
194
|
+
use_tools: bool = True,
|
|
195
|
+
session_id: str | None = None,
|
|
196
|
+
timeout: float | None = None,
|
|
197
|
+
) -> ChatMessage:
|
|
198
|
+
"""调用 Agent 进行一轮对话。
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
messages: 单条消息或消息列表(ChatMessage / {"role","content"} dict)
|
|
202
|
+
use_tools: 是否允许工具调用(无工具 Agent 忽略)
|
|
203
|
+
session_id: 会话 ID;提供时启用会话记忆(多轮上下文)
|
|
204
|
+
timeout: 单轮超时秒数(None = 不限时)
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
assistant 消息
|
|
208
|
+
"""
|
|
209
|
+
return await self._get_oxy_engine().chat(messages, use_tools=use_tools, session_id=session_id, timeout=timeout)
|
|
210
|
+
|
|
211
|
+
async def invoke(
|
|
212
|
+
self,
|
|
213
|
+
message: str | list[ChatMessage | dict[str, str]],
|
|
214
|
+
*,
|
|
215
|
+
use_tools: bool = True,
|
|
216
|
+
session_id: str | None = None,
|
|
217
|
+
timeout: float | None = None,
|
|
218
|
+
) -> str:
|
|
219
|
+
"""简化调用 - 输入文本,返回文本。"""
|
|
220
|
+
return await self._get_oxy_engine().invoke(message, use_tools=use_tools, session_id=session_id, timeout=timeout)
|
|
221
|
+
|
|
222
|
+
async def stream(
|
|
223
|
+
self,
|
|
224
|
+
message: str | list[ChatMessage | dict[str, str]],
|
|
225
|
+
*,
|
|
226
|
+
use_tools: bool = True,
|
|
227
|
+
session_id: str | None = None,
|
|
228
|
+
timeout: float | None = None,
|
|
229
|
+
) -> AsyncIterator[str]:
|
|
230
|
+
"""流式输出文本块。
|
|
231
|
+
|
|
232
|
+
有工具的 Agent 采用缓冲策略(中间轮工具调用 JSON 不外漏,
|
|
233
|
+
最终以完整答案输出);无工具 Agent 逐段透传。
|
|
234
|
+
"""
|
|
235
|
+
async for chunk in self._get_oxy_engine().stream(
|
|
236
|
+
message, use_tools=use_tools, session_id=session_id, timeout=timeout
|
|
237
|
+
):
|
|
238
|
+
yield chunk
|
|
239
|
+
|
|
240
|
+
# ============ 抽象方法 ============
|
|
241
|
+
|
|
242
|
+
@abstractmethod
|
|
243
|
+
async def run(self, *args: Any, **kwargs: Any) -> AgentResult:
|
|
244
|
+
"""执行 Agent(子类实现)"""
|
|
245
|
+
pass
|
|
246
|
+
|
|
247
|
+
async def execute(self, *args: Any, **kwargs: Any) -> AgentResult:
|
|
248
|
+
"""执行 Agent(带错误处理,不吞没不可恢复异常)"""
|
|
249
|
+
try:
|
|
250
|
+
result = await self.run(*args, **kwargs)
|
|
251
|
+
return result
|
|
252
|
+
except (KeyboardInterrupt, SystemExit):
|
|
253
|
+
raise
|
|
254
|
+
except Exception as e:
|
|
255
|
+
from bolt.core.logging import get_logger
|
|
256
|
+
|
|
257
|
+
get_logger(f"bolt.agent.{self.name}").exception("Agent execution failed", exc=e)
|
|
258
|
+
return AgentResult(
|
|
259
|
+
success=False,
|
|
260
|
+
error=str(e),
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def get_memory_backend(session_id: str) -> ConversationMemory:
|
|
265
|
+
"""按 Settings 构建默认记忆后端。独立函数避免 base↔memory 模块级循环。
|
|
266
|
+
|
|
267
|
+
- ``memory``(默认):进程内存储
|
|
268
|
+
- ``redis``:跨 worker 共享(复用 ``settings.redis_url`` 与 ``settings.memory_ttl``)
|
|
269
|
+
"""
|
|
270
|
+
settings = get_settings()
|
|
271
|
+
backend = settings.memory_backend
|
|
272
|
+
if backend == "redis":
|
|
273
|
+
from bolt.agent.memory import RedisConversationMemory
|
|
274
|
+
|
|
275
|
+
return RedisConversationMemory(
|
|
276
|
+
session_id=session_id,
|
|
277
|
+
redis_url=settings.redis_url,
|
|
278
|
+
ttl=settings.memory_ttl,
|
|
279
|
+
)
|
|
280
|
+
from bolt.agent.memory import ConversationMemory
|
|
281
|
+
|
|
282
|
+
return ConversationMemory(session_id=session_id)
|
bolt/agent/example.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""示例 Agent - 评论生成 Agent。
|
|
2
|
+
|
|
3
|
+
演示如何使用 Bolt Agent 框架(OxyGent 引擎驱动)构建 AI Agent。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from bolt.agent.base import AgentResult, BoltAgent, tool
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CommentAgent(BoltAgent):
|
|
16
|
+
"""评论生成 Agent 示例。
|
|
17
|
+
|
|
18
|
+
用法:
|
|
19
|
+
agent = CommentAgent()
|
|
20
|
+
|
|
21
|
+
# 执行(invoke 内部由 OxyGent ReAct 循环驱动工具调用)
|
|
22
|
+
result = await agent.execute(note_url="https://xiaohongshu.com/note/123")
|
|
23
|
+
print(result.output)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
name: str = "comment_agent",
|
|
29
|
+
model: str = "gpt-4o",
|
|
30
|
+
provider: str = "openai",
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__(
|
|
33
|
+
name=name,
|
|
34
|
+
model=model,
|
|
35
|
+
provider=provider,
|
|
36
|
+
system_prompt="""你是一个专业的评论生成专家。
|
|
37
|
+
你的任务是根据笔记内容生成有深度、有见解的评论。
|
|
38
|
+
评论应该:
|
|
39
|
+
1. 紧扣笔记主题
|
|
40
|
+
2. 有独特的观点或见解
|
|
41
|
+
3. 语言自然、有亲和力""",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@tool(description="搜索小红书笔记内容")
|
|
45
|
+
async def search_note(self, note_url: str) -> str:
|
|
46
|
+
"""搜索小红书笔记内容。"""
|
|
47
|
+
# 这里应该调用实际的小红书 API
|
|
48
|
+
return "笔记内容摘要: 这是一篇关于美食探店的笔记..."
|
|
49
|
+
|
|
50
|
+
@tool(description="获取热门评论作为参考")
|
|
51
|
+
async def get_hot_comments(self, note_url: str, limit: int = 5) -> list[str]:
|
|
52
|
+
"""获取热门评论。"""
|
|
53
|
+
return [
|
|
54
|
+
"这家店我也去过!真的很好吃!",
|
|
55
|
+
"感谢分享,已经收藏了~",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
async def run(self, note_url: str, style: str = "friendly") -> AgentResult:
|
|
59
|
+
"""执行评论生成(工具调用由 ReAct 循环自动编排)。"""
|
|
60
|
+
prompt = f"""请为笔记 {note_url} 生成一条评论。
|
|
61
|
+
|
|
62
|
+
步骤:
|
|
63
|
+
1. 用工具搜索笔记内容
|
|
64
|
+
2. 用工具获取热门评论参考
|
|
65
|
+
3. 生成一条风格为「{style}」的评论,直接输出评论内容"""
|
|
66
|
+
|
|
67
|
+
response = await self.invoke(prompt)
|
|
68
|
+
return AgentResult(
|
|
69
|
+
success=True,
|
|
70
|
+
output=response,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# ============ 使用示例 ============
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def example_simple_agent() -> None:
|
|
78
|
+
"""简单 Agent 示例"""
|
|
79
|
+
logger.info("简单 Agent 示例")
|
|
80
|
+
|
|
81
|
+
agent = CommentAgent()
|
|
82
|
+
|
|
83
|
+
# 检查工具注册
|
|
84
|
+
tools = agent.get_tools()
|
|
85
|
+
logger.info("注册的工具: %s", [t.name for t in tools])
|
|
86
|
+
|
|
87
|
+
result = await agent.execute(note_url="https://xiaohongshu.com/note/123")
|
|
88
|
+
logger.info("结果: %s", result)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
import asyncio
|
|
93
|
+
|
|
94
|
+
asyncio.run(example_simple_agent())
|