nullpointexception-i/agent-sphere
GitHub: nullpointexception-i/agent-sphere
一个基于 ReAct 循环与多级记忆系统的 AI Agent 编排平台,支持通过 LLM 驱动浏览器、命令行及 MCP 工具实现感知到执行的自动化闭环。
Stars: 312 | Forks: 8
本项目是一个 AI Agent 编排平台。由基于 LLM 的决策引擎驱动,并结合多种能力(内置工具、MCP 协议、CLI 执行、浏览器自动化等),实现了 **感知 → 规划 → 执行 → 反馈** 的核心闭环。
## 支持配置不同的模型提供商:OpenAI、DeepSeek、QuickRouter(中转站)、BigModel(智谱 AI)、LiteLLM。
截图




▶ [点击观看视频演示](https://www.bilibili.com/video/BV1WqTT62Efq/)
[](https://www.bilibili.com/video/BV1WqTT62Efq/)
## 1. 开发快速入门
详见:[QUICK_START.md](QUICK_START.md)
## 2. 架构
### 2.1 整体结构

### 2.2 核心组件
#### 2.2.1 SessionRunner (ReAct 引擎)
管理 AI 会话的完整执行生命周期,实现了 **规划 → 执行 → 观察 → 学习** 循环:

**与 ReAct 模式的对应关系:**

#### 2.2.2 能力层
| 能力类型 | 实现方式 | 描述 | 示例 |
|-----------------|----------------|-------------|----------|
| **MCP (Model Context Protocol)** | MCP Server 客户端 | 标准协议,连接到任何 MCP Server | Jira, GitHub, Slack, 数据库 |
| **Builtin (内置工具)** | SPI: `CapabilityBuiltinToolSpi` | Java SPI 扩展 | WebFetch, WebRead, Chrome, Todowrite, DocWrite |
| **Chrome 浏览器** | Chrome 扩展桥接 | DOM 操作 + 实时视觉反馈 | 导航、点击、填写表单、截图 |
| **CLI (命令行)** | `ProcessBuilder` 执行 | 本地或远程 shell | Git 操作、构建/部署、系统管理 |
| **Skill (复合技能)** | 多步骤任务编排 | LLM 驱动的任务分解 | 跨系统工作流 |
#### 2.2.3 Chrome 扩展 (浏览器桥接)

## 3. 算法 — 核心算法
### 3.1 ReAct 执行循环
AgentSphere 的核心循环遵循 **ReAct (Reasoning + Acting)** 模式,结合了 LLM 的推理能力与工具执行能力:

**消息结构:**
```
[
{role: "system", content: "You are a browser assistant..."},
{role: "user", content: "Help me check the weather in Guangzhou"},
{role: "assistant", tool_calls: [{id: "call_1", name: "navigate", args: "..."}}]},
{role: "tool", tool_call_id: "call_1", content: '{"tabId": 42, "url": "..."}'},
{role: "assistant", content: "The weather in Guangzhou tomorrow is..."},
{role: "user", content: "What should I prepare for going out tomorrow"},
...
]
```
**多轮工具调用示例:**

### 3.2 多级记忆系统
AgentSphere 实现了多级记忆系统,覆盖了从持久化到运行时缓存的全链路:

#### 记忆层级详情
| 层级 | 存储方式 | 生命周期 | 容量 | 用途 |
|-------|---------|-----------|----------|---------|
| L1: KernelContext | ConcurrentHashMap | 运行期间 (TTL 30分钟) | 每个会话 1 个 | 工具列表、模型路由 |
| L2: Messages | ArrayList | 运行期间 | 数十轮 | LLM 输入/输出 |
| L3: LLM 交互 | PostgreSQL | 永久 | 可配置 | 调试与审计 |
| L4: 工具调用 | PostgreSQL | 永久 | 无限 | 重放、观察 |
| L5: 压缩记录 | PostgreSQL | 永久 | 累积 | 上下文压缩 |
| L6: Session | PostgreSQL | 永久 | 每个会话 1 个 | 元数据 |
#### 3.2.1 上下文组装
`HistoryLoader` 负责从持久化存储中加载历史消息,并将其组装为 LLM 上下文:

**工具结果压缩流程:**

#### 3.2.2 上下文压缩
当消息估算的 token 数超过 `maxInputTokens × budget-ratio` 时触发:

**完整压缩链流程:**

#### 3.2.3 工具调用记录状态机

每条记录包含:
- `callId` — LLM 生成的工具调用 ID(例如 `call_abc123`)
- `argumentsJson` — 原始输入参数
- `compressedArguments` — 输入 JSON 的压缩版本(写入时压缩)
- `artifact` — 原始返回结果
- `compressedArtifact` — 结果 JSON 的压缩版本(写入时压缩)
- 供 HistoryLoader 用于重放、观察面板展示以及审计
#### 3.2.4 工具结果压缩策略
```
jsonCompress(node, depth, maxValueChars) {
if (depth > 5) return "[deep nested]";
if (node instanceof Map) {
// Recursively compress each value
return map.mapValues(v -> jsonCompress(v, depth+1, maxValueChars))
}
if (node instanceof List) {
if (list.size() <= 5) return list.map(v -> jsonCompress(v, depth+1))
// Large array: keep first 3 + total count
return { _count: 13, _showing: 3, items: [...] }
}
if (node instanceof String) {
if (text.length() <= maxValueChars) return text
// Long string: first 100 + ellipsis + last 50
return text[0..100] + "...[+ N chars]...\n" + text[-50..-1]
}
return node // Number, Boolean pass-through
}
```
### 3.3 模型路由与降级
AgentSphere 提供了多级模型容错机制,以确保 LLM 调用的高可用性。
#### 路由配置

#### 降级执行流程

#### 压缩预算计算
```
budget = maxInputTokens × budget-ratio (default 0.7)
Example:
Route: GLM-4.1V-Thinking-Flash, maxInputTokens=1_000_000
→ budget = 1_000_000 × 0.7 = 700_000 tokens
→ When messages exceed 700K tokens → trigger compaction
Dynamic adjustment:
budget-ratio: 0.5 → Triggers earlier (preserves more context quality)
budget-ratio: 0.8 → Triggers later (saves compression overhead)
```
#### 超时参数
| 参数 | 默认值 | 描述 |
|-----------|---------|-------------|
| `llm.connect-timeout` | 30s | 连接 LLM API 的超时时间 |
| `llm.read-timeout` | 60s | 读取响应的超时时间 |
| `llm.stream-read-timeout` | 120s | 流式读取超时时间 |
| `llm.stream-timeout` | 120s | 流式调用的总超时时间 |
| `runner.turn-timeout` | 180s | 单次 LLM 轮次的总超时时间 |
### 3.4 浏览器操作流程

### 3.5 多标签页管理

### 3.6 超时与取消链路

### 3.7 会话追踪

## 4. 管理 — 运维与管理
### 4.1 配置参考
| 配置项 | 默认值 | 描述 |
|-------------|---------|-------------|
| `session.idle-timeout` | 30m | 会话空闲超时时间 |
| `session.max-concurrent-runs` | 10 | 最大并发执行数 |
| `runner.max-loop-count` | 128 | 每次运行的最大循环次数 |
| `runner.turn-timeout` | 180s | 单次 LLM 轮次超时时间 |
| `runner.compaction.budget-ratio` | 0.7 | 压缩触发阈值(占 maxInputTokens 的比例) |
| `llm.connect-timeout` | 30s | LLM API 连接超时时间 |
| `llm.read-timeout` | 60s | LLM API 读取超时时间 |
| `llm.stream-timeout` | 120s | 流式调用总超时时间 |
| `tool.max-parallel` | 3 | 最大并行工具执行数 |
| `tool.execution-timeout` | 60s | 单批次工具执行超时时间 |
| `tool.submit-timeout` | 30s | 工具提交超时时间 |
### 4.2 可观测性
AgentSphere 提供了三层观测系统:
#### 4.2.1 实时事件 (SSE 事件)
```
Real-time push of LLM call chain:
content_token → "The weather in Guangzhou tomorrow..."
reasoning_token → "🤔 The user is asking about weather, I need to open a weather website"
→ "⚙️ navigate: calling..."
→ "⚙️ navigate: succeeded ✅"
→ "⚙️ getContent: calling..."
→ "⚙️ getContent: succeeded ✅"
→ "⏹️ Run cancelled" or "✅ Run completed"
```
| SSE 事件 | 触发条件 | 前端效果 |
|-----------|---------|-----------------|
| `content_token` | LLM 文本生成 | 打字机效果 |
| `reasoning_token` | LLM 推理、工具状态 | 推理面板 |
| `browser_operation` | Chrome 操作指令 | 扩展执行 |
| `run_running` | 运行开始 | 状态指示器 |
| `run_completed` | 运行完成 | 完成通知 |
| `run_failed` | 运行失败 | 错误提示 |
| `tool_call_started` | 工具 PENDING(待处理) | 工具调用列表 |
| `tool_call_succeeded` | 工具完成 | ✅ 图标 |
| `tool_call_failed` | 工具失败 | ❌ 图标 |
| `compaction_running` | 压缩开始 | 推理面板 |
| `compaction_completed` | 压缩完成 | 推理面板 |
#### 4.2.2 运行活动 API
提供完整的工具调用历史查询:
```
GET /api/v1/instance/runs/{runId}/activities?offset=0&limit=20
Response:
{
"total": 20,
"records": [
{ "activityType": "llm_interaction",
"modelName": "deepseek-v4-flash",
"interactionType": "CHAT_REPLY",
"durationMs": 2588,
"requestBody": "{...}",
"responseBody": "{...}",
"success": true },
{ "activityType": "tool_call",
"toolName": "builtin_5",
"displayName": "builtin.CapabilityBuiltinToolChrome",
"argumentsJson": "{...}",
"artifact": "{...}",
"status": "SUCCEEDED" }
]
}
```
#### 4.2.3 会话面板
| 视图 | 内容 |
|------|---------|
| **运行列表** | 按会话查看历史运行,显示 userMessage + assistantReply |
| **工具调用列表** | 当前会话的最新工具调用记录(按创建时间降序排列) |
| **Todo 列表** | 当前会话的 Todo 清单,包含状态追踪 |
| **操作日志** | Chrome 扩展弹窗中的历史操作记录 |
### 4.3 日志系统
| Logger | 级别 | 用途 |
|--------|-------|---------|
| `ControllerLogAspect` | INFO | API 请求/响应日志 |
| `ChromeCallbackController` | WARN | 浏览器操作失败 |
| `FiberSet` | WARN | 工具超时/失败 |
| `SessionRunner` | INFO | 执行轮次与状态 |
| `LlmInteractionPersistListener` | DEBUG | LLM 交互记录持久化 |
| `RuntimeEventListener` | DEBUG | 工具调用生命周期事件 |
### 4.4 关键部署步骤
```
# 构建后端
cd agent-sphere
mvn compile -pl agent-sphere-bootstrap -am
# 启动后端
mvn spring-boot:run -pl agent-sphere-bootstrap
# 启动前端
cd agent-sphere-ui
npm run dev
# 加载 Chrome Extension
# Chrome → chrome://extensions → Developer mode → Load unpacked
# 选择 agent-sphere-chrome-extension 目录
# 配置 URL
# 点击扩展图标 → Settings Tab
# Frontend URL: http://localhost:8000
# Backend URL: http://localhost:8080
```
### 4.5 架构决策记录 (ADR)
| 决策 | 方案 | 原因 |
|----------|----------|--------|
| **SSE vs WebSocket** | Server-Sent Events | 单向推送无需客户端确认,浏览器原生支持 |
| **fetch+ReadableStream vs EventSource** | fetch + ReadableStream | EventSource 在 MV3 Service Worker 中无法携带 Authorization 头 |
| **Virtual Threads** | Java 21 虚拟线程 | 简化并发模型,每个工具分配一个虚拟线程 |
| **Chrome 扩展独立部署** | 独立项目 | 与 Web UI 解耦,权限隔离 |
| **多发射器 SSE** | 每个会话 `List` | Web UI 与扩展共享同一 SSE 通道 |
| **FiberSet cancel(true)** | `CompletableFuture.cancel(true)` | 在超时时有效中断阻塞的虚拟线程 |
| **工具结果写入时压缩** | `RuntimeEventListener` 压缩后写入 `compressed_artifact` | HistoryLoader 读取时无需重新压缩,减少冗余计算 |
| **基于 Token 预算的压缩触发** | `runTurn` 的 execute 回调中的 `shouldCompact` | 使用实际调用的模型路由的 maxInputTokens 以确保准确性 |
| **压缩游标** | `compactedUptoRunId` 标记已压缩的运行 | HistoryLoader 跳过已压缩的运行,仅加载后续运行 |
| **压缩保护循环** | 最大重试 3 次 | 防止因网络波动导致压缩失败时出现死循环 |
### 4.6 能力扩展
#### 添加新的内置工具
```
@Component
public class CapabilityBuiltinToolMyTool implements CapabilityBuiltinToolSpi {
@Override
public BuiltinToolEnum getToolType() { return BuiltinToolEnum.MY_TOOL; }
@Override
public ToolInfoVO getInfo() {
ToolInfoVO info = new ToolInfoVO();
info.setName(BuiltinToolConstants.NAME_PREFIX + "MyTool");
info.setDescription("Description for LLM");
info.setParamSchema(ToolSchemaUtil.generateParamSchema(MyToolDTO.class));
info.setResponseSchema(ToolSchemaUtil.generateParamSchema(MyToolResultVO.class));
return info;
}
@Override
public ExecuteResult execute(ExecuteContext ctx) {
MyToolDTO dto = (MyToolDTO) ctx;
// Implementation logic
return new MyToolResultVO(/* result */);
}
}
```
## 5. 项目结构

## 6. 技术栈
| 领域 | 技术 |
|--------|------------|
| **后端运行时** | Java 21, Spring Boot 3.4, Virtual Threads |
| **数据库** | PostgreSQL, Flyway 数据迁移 |
| **缓存/分布式锁** | Redis (Redisson) |
| **前端** | React, UmiJS, Ant Design Pro |
| **Chrome 扩展** | Manifest V3, Service Worker, Content Script |
| **实时通信** | SSE (Server-Sent Events), 多器广播 |
| **工具协议** | MCP (Model Context Protocol, Streamable HTTP) |
| **API 安全** | Bearer Token, @WithTenant 多租户 |
| **LLM 集成** | SPI provider 抽象,自动降级路由 |
## 7. MCP 集成示例
AgentSphere 支持通过 MCP 协议连接到任何外部服务。以 Jira 为例:
```
# 部署 Jira MCP Server
npx @roovet/jira-mcp --port 3100
# 在 AgentSphere 管理控制台中添加 MCP capability
curl -X POST /api/v1/capability/mcp \
-d '{"name":"Jira MCP","serverUrl":"http://localhost:3100","serverType":"streamable-http"}'
# 将其绑定到一个 Agent instance
curl -X POST /api/v1/instance/instance-capabilities \
-d '{"instanceId":1,"capabilityType":"mcp","capabilityId":1}'
# 用户只需在聊天中发送指令
# “帮我在 Jira 上查看我未完成的任务”
# → LLM 调用 MCP tool → Jira API → 返回结果
```

## 8. 许可证
MIT License
Copyright (c) 2026 Buukle
标签:DLL 劫持, JS文件枚举, LLM编排, MCP协议, ReAct模式, 域名枚举, 大语言模型, 测试用例, 浏览器自动化