Skip to content

系统架构 ​

OryxOS 是一个 Spring Boot 3 单体应用,跑在 JDK 21 上,基于 Spring AI Alibaba 做 LLM 调用,自己实现 ReAct 循环作为 Agent 核心,打包成一个可执行 JAR。

技术栈一句话:JDK 21 + Spring Boot 3 + Spring AI Alibaba + 自实现 ReAct + SQLite + Picocli。

OryxOS 整体架构

分层视图 ​

层组成职责
接入层CLI Channel、Web Service(REST)、AgentScheduler消息进出。CLI 和 REST 是"人推",定时任务是"钟推"
统一入口AgentService三个入口共用的编排者,不区分消息来源
引擎层ReActLoop、PromptBuilder、ToolExecutorAgent 的大脑
能力层Provider、Memory、Tool给引擎提供 LLM 调用、上下文和执行能力
基础层AgentLoader、ContextLoader、ConfigLoader、SQLite、文件系统Agent 定义加载、配置与密钥、持久化

一句话:Provider、Memory、Tool 三块能力供养 ReAct 引擎,引擎的能力通过 CLI、Web Service、定时任务三个入口对外提供。

所有能力收敛在一个进程内;外部依赖(LLM 厂商 API、外部 MCP server、企业 IM)都在应用边界之外,并且每一次跨边界调用都经过沙箱校验、写入审计。

一次消息的处理流程 ​

text
消息从 CLI / REST API / 定时任务进来
  → AgentService.process(Session, message)
    → PromptBuilder 组装 Prompt
       (AGENT.md 正文 + Bootstrap + Skill 元数据 + 当前时间 + 长期记忆 + 对话历史 + 工具列表)
    → ProviderService 调用 LLM                         ── 写 llm_calls
       ├─ 无工具调用 → 返回最终响应
       └─ 有工具调用 → ToolExecutor:查找工具 → 沙箱校验 → 执行  ── 写 tool_invocations
                      → 结果追加到对话历史 → 回到组装 Prompt
    → 达到最大迭代次数(默认 10)强制结束
  → Session 持久化

核心能力 ​

对接 LLM ​

ProviderService 统一管理所有 Provider,对 ReAct 循环屏蔽厂商差异。多个 Provider 并存时,维护一份显式的 provider name → ChatModel 映射,不靠扫描容器里的 Bean 类型来区分。每次调用记录 token 用量、Provider 和模型,写入 llm_calls。

ReAct 循环 ​

ReActLoop 是 OryxOS 最核心的一段代码,自己实现,不依赖 Spring AI 的 Agent 抽象。Spring AI 在 OryxOS 里只做两件事:Provider 协议转换和 @Tool 的 JSON Schema 生成;它自带的自动工具执行被禁用,工具的调度完全由 ToolExecutor 负责,避免工具被调用两次。

记忆 ​

MemoryService 是三层记忆的统一门面,ReAct 循环只问它一个接口:

  • 会话记忆:委托 SessionManager,持久化到 SQLite,重启可恢复;过长时截断早期对话
  • 长期记忆:委托 LongTermMemoryStore,默认实现是 .oryxos/memory/MEMORY.md,分「核心记忆 / 归档记忆」两区;核心区永不截断,截断和检索只作用于归档区;每次重新读取、不缓存,写入后下一轮立即可见
  • 情景记忆:扩展阶段补齐

Agent 通过 save_memory / recall_memory 两个内置工具主动写入和检索。

工具体系 ​

所有工具(内置、MCP、@Tool Bean)都被包装成统一的 OryxTool,ReAct 循环不感知工具来源:

方式门槛做法
零代码(主推)最低写 Agent 目录 + 在 mcp_servers.yaml 复用现成 MCP server
轻代码中用任意语言写 MCP server,OryxOS 作为 MCP Client 连接
重代码高用 @Tool 注解写 Java Spring Bean,进程内调用

AGENT.md 和 Skill 不是工具。 Agent 正文由 ContextLoader 注入 system prompt;Agent 绑定的 Skill 每轮只注入名称、描述和路径,正文由模型用 read_file 按需读取(渐进式披露)。

对外服务 ​

Web Service 是 OryxOS 的对外门面,核心阶段提供 10 个 REST 端点(会话管理 4 个、Agent 调用 1 个、Agent / 记忆 / 工具查询 3 个、健康与信息 2 个)。约束:单条消息 ≤ 32KB,历史最多返回 100 条,Agent 调用 60 秒超时。

安全:沙箱与审计 ​

沙箱 ​

沙箱遵循"接口先行":先定一个不携带任何实现细节的接口 Sandbox.enforce(action),核心阶段只实现应用层白名单这一档:

动作校验
文件读写路径标准化后比对白名单,防止 ../ 路径穿越
Shell 命令只执行白名单内的可执行文件,参数数组直传,不经 shell 解释
HTTP 请求解析 host 后按域名白名单匹配
SMTP按 host:port 精确放行

扩展阶段按需求升级到容器隔离、microVM,接口不变,只新增实现。

WARNING

应用层白名单是"劝阻级"防线,防的是模型误操作,防不住蓄意绕过。核心阶段不要用它运行完全不可信的代码,或对外提供多租户服务。

审计 ​

每次 LLM 调用写 llm_calls,每次工具调用(包括失败和沙箱拒绝)写 tool_invocations。审计数据从第一天就落库,而不是事后从日志里反解析。

关键技术决策 ​

#决策选择理由
1ReAct 实现自实现完全可控,保留定制循环行为的空间
2Spring AI 边界只用协议转换 + schema 生成,禁用自动工具执行避免工具被调两次,循环由 OryxOS 掌控
3执行模型同步阻塞 + Java 21 virtual thread代码直观,单节点撑高并发
4工具注册@Tool 注解 + OryxTool 抽象统一内置工具与 MCP 工具
5HTTP 服务层Spring MVC + virtual thread同步直观,后续用 SseEmitter 支持流式
6沙箱接口先行 + 应用层白名单SecurityManager 在 JDK 21 已不可用;换实现不改调用方
7持久化SQLite + Spring Data JPA + MEMORY.md单二进制部署,审计表第一天写入

数据持久化 ​

数据存储说明
会话SQLite sessions对话历史 JSON 序列化,跨重启恢复
审计SQLite tool_invocations、llm_calls每次调用一条记录
定时任务SQLite scheduled_tasks、task_executions任务状态与执行历史
通知渠道SQLite notify_channels全局注册表,Agent 按名称引用
Agent 定义、Bootstrap、长期记忆、MCP 配置文件系统 .oryxos/用户可直接编辑、git 跟踪、备份

模块划分 ​

OryxOS 是一个 Maven 多模块项目,核心阶段共 9 个模块:

模块职责
oryxos-core核心抽象与引擎:ReActLoop、PromptBuilder、ToolExecutor、AgentService、AgentLoader、ContextLoader、AgentScheduler
oryxos-providerLLM Provider 抽象,provider name 显式映射
oryxos-memoryMemoryService 门面、长期记忆存储、记忆工具
oryxos-tool内置工具、MCP Client、ToolRegistry、沙箱、通知推送
oryxos-channel-cliCLI 对话渠道
oryxos-webREST API、统一异常处理、OpenAPI 文档
oryxos-storageSQLite 持久化
oryxos-cliPicocli 命令行入口、配置与密钥加载
oryxos-bootSpring Boot 启动与依赖聚合

模块之间通过接口解耦:oryxos-core 不依赖任何内部模块,实现类依赖 core 中的接口。扩展阶段加新渠道或新工具时只加新模块,不改核心引擎。