内容
# OpenRath
<p align="center">
<img src="assets/readme/logos/openrath-logo-white.png" alt="OpenRath logo" width="860" />
</p>
<p align="center">
<a href="https://pypi.org/project/openrath/"><img src="https://img.shields.io/pypi/v/openrath.svg" alt="PyPI"></a>
<a href="https://pypi.org/project/openrath/"><img src="https://img.shields.io/pypi/pyversions/openrath.svg" alt="Python"></a>
<a href="https://github.com/Rath-Team/OpenRath/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-BSD--3--Clause-blue.svg" alt="License"></a>
<a href="https://docs.openrath.com"><img src="https://img.shields.io/badge/docs-openrath.com-blue" alt="Docs"></a>
<a href="https://arxiv.org/abs/2606.19409"><img src="https://img.shields.io/badge/arXiv-2606.19409-b31b1b.svg?logo=arxiv&logoColor=white" alt="arXiv"></a>
</p>
<div align="center">
简体中文 | [English](README.md)
</div>
---
**OpenRath 是一个类似 PyTorch 的多智能体和多会话框架。**
它将智能体的运行时状态转换为显式、可组合的 Python 对象:
- **会话** 承载对话状态和智能体间协作的血统。
- **沙盒** 决定工具实际运行的位置。
- **内存** 在运行之间持久化智能体的内存状态。
- **工具** 是面向模型的类似操作的可调用接口。
- **智能体** 是一个可重用、可组合的会话转换层。
- **工作流** 将多个智能体和工作流组合成更大的系统。
- **选择器** 在运行时在自我描述的工作流之间路由,因此 `if` / `while` 控制流保持为纯 Python。
---
## OpenRath 在 PyTorch 视角下的体现
<p align="center">
<img src="assets/readme/diagrams/pytorch-lens.png" alt="OpenRath in the PyTorch Lens" width="860" />
</p>
| PyTorch 概念 | OpenRath 概念 | 含义 |
| --- | --- | --- |
| `Tensor` | `会话` | 流动的运行时值:有序块、位置、血统和用法。 |
| `设备` | `沙盒` / `后端` | 工具运行的执行环境:本地进程、OpenSandbox 或其他后端。 |
| `参数` | `内存` | 绑定到智能体或存储的持久状态,在运行之间被回忆和提交。 |
| `函数` | `工具` | 具有模型可见模式和运行时行为的可调用操作。 |
| `nn.Linear` | `智能体` | 一个可重用的层,通过提示、提供者、工具和内存将一个会话映射到另一个。 |
| `nn.Module` | `工作流` | 智能体、工具、会话转换和嵌套工作流的可组合容器。 |
| 控制流 | `选择器` | 一个 LLM 支持的路由器,在运行时选择下一个工作流,实现动态 `if` / `while` 控制流。 |
大多数智能体框架从智能体循环开始。OpenRath 从 **会话** 开始。这种差异在单个应用程序需要多个智能体、多个分支、持久内存、沙盒执行和可追溯的血统时很重要。
OpenRath 设计用于:许多智能体跨多个分支会话协作,同时仍然跟踪每个角色、工作区、内存写入和最终输出。
<p align="center">
<img src="assets/readme/diagrams/paradigm-map.png" alt="Multi-Agent Multi-Session Map" width="860" />
</p>
| 范式 | 典型形状 | 示例 |
| --- | --- | --- |
| 单智能体,单会话 | 一个模型在一个对话上 | ChatGPT 风格的聊天 |
| 多智能体,单会话 | 几个角色读取和写入一个共享状态 | 子智能体风格的多智能体协作 |
| 单智能体,多会话 | 一个智能体管理多个会话分支 | OpenClaw 风格的会话分支 |
| 多智能体,多会话 | 许多智能体共享多个会话并通过会话协作或演化 | **OpenRath** |
---
## 为什么选择多智能体多会话范式
智能体是会话上的转换层,因此真正需要被 fork、合并、重用和跟踪的是会话数据流——而不是由每个智能体维护的单独消息历史。
<p align="center">
<img src="assets/readme/diagrams/multi-agent-multi-session.png" alt="Why Multi-Agent Multi-Session" width="860" />
</p>
OpenRath 的设计解决了当智能体系统从单个助手扩展到大型集群时出现的问题:
- **会话作为数据流核心。** 上下文存储为结构化块而不是重复复制的消息字符串。工作流可以重用、分支、压缩和直接传递上下文,从而大大提高了上下文重用率并减少了令牌消耗。
- **会话图适用于大规模智能体集群。** 大型运行需要解释哪些角色、分支、工具调用和工作区产生了答案。会话血统为运行时提供了一个图状的溯源层,而不是一堆事后日志。
- **会话加上智能体内存。** 短期会话状态和长期内存共同工作:智能体可以在运行前回忆事实,并在运行后提交新知识,因此智能体集群可以在使用过程中不断改进。
- **模块化工作流。** 管理数百或数千个智能体成为一个组合问题而不是提示混乱。智能体是小型层;工作流是嵌套的、可重用的、可检查的模块,使大规模智能体管理变得可行。
- **沙盒作为后端。** 执行不限于一个 shell。本地、OpenSandbox 或未来的第三方后端可以位于同一个会话放置模型后面,因此第三方执行后端可以灵活地插入。
- **内存作为后端。** 回忆不限于一个数据库。本地内存、OpenViking 或未来的第三方内存系统可以共享一个内存平面,因此第三方内存后端可以灵活地插入。
结果是一个运行时,其中状态、执行、内存和编排保持解耦,但通过一个流动的值连接起来:`会话`。
---
## 最小但完整的 OpenRath 工作流
```python
from collections.abc import Mapping
from typing import Any
from pydantic import BaseModel, Field
from rath import flow
from rath.flow.tool import FlowToolCall
from rath.session import Session
class WordCountInput(BaseModel):
text: str = Field(description="文本计数。")
# OpenRath 工具
class WordCountTool(FlowToolCall):
@property
def name(self) -> str:
return "word_count"
@property
def description(self) -> str:
return "计算短文本中的单词数。"
@property
def parameters(self) -> Mapping[str, Any]:
return WordCountInput.model_json_schema()
def __call__(self, session: Session, arguments: Mapping[str, Any]) -> dict[str, int]:
data = WordCountInput.model_validate(dict(arguments))
return {"words": len(data.text.split())}
# OpenRath 工作流
class ReadmeWorkflow(flow.Workflow):
def __init__(self) -> None:
# OpenRath 提供者
provider = flow.Provider(model="gpt-5.5")
# OpenRath 智能体
self.agent = flow.Agent(
"使用 `word_count` 工具,然后简要回答。",
provider,
tools=[WordCountTool()],
memory="local",
)
# OpenRath 压缩器
self.compressor = flow.Compressor(
"将运行压缩为一个简洁的助手消息。",
provider,
)
def forward(self, session: Session) -> Session:
# OpenRath 内存
self.agent.remember_memory("用户喜欢简洁的技术总结。")
session = self.agent(session)
self.agent.commit_memory(session)
return self.compressor(session)
workflow = ReadmeWorkflow()
# OpenRath 会话
user_session = Session.from_user_message(
"计算以下文本中的单词数:OpenRath 使智能体集群可追溯。"
)
# OpenRath 沙盒
user_session = user_session.to("local", spec="./")
out = workflow(user_session)
```
这个小程序在短小的范围内展示了整个形状:`会话`承载数据,`沙盒`放置执行,`工具`注册在`智能体`上,`内存`在运行之间持久化,`工作流`组成路径,`压缩器`缩小生成的上下文。
---
## 运行时组件
### 会话 — 流动状态
`会话` 是 OpenRath 的中心运行时值。它包含一个有序的块表,包含系统、用户、助手和工具结果行。它还记录了沙盒放置、血统、令牌使用和待处理的工作。
这就是为什么 OpenRath 可以建模不仅仅是一个聊天记录。会话可以分支成一个新分支,与其父链分离,合并另一个兼容的分支,序列化为 JSONL,或交给不同的工作流。智能体侧的指令被表示为它们自己的会话块,并在循环之前预先添加,而不是重复粘贴到不透明的提示中。
常见入口点:
- `Session.from_user_message(...)` 创建一个用户侧的会话。
- `Session.from_agent_prompt(...)` 创建一个智能体/系统提示会话。
- `session.to("local", spec="./")` 绑定一个沙盒后端和工作区。
- `session.fork()` 创建一个可追溯的分支。
- `session.detach()` 创建一个没有父血统的新会话。
- `session.merge(...)` 组合兼容的分支并记录合并血统。
### 沙盒 — 工具落地
沙盒是会话的执行放置。它是 OpenRath 中决定计算在哪里执行的内容。工具不运行在抽象的提示中;它们运行在当前绑定到会话的沙盒中。
```python
session = Session.from_user_message("列出文件").to("local", spec="./")
```
`local`后端始终可用,并针对主机工作区运行文件、命令和代码工具。可选的`opensandbox`后端将相同的工具层连接到容器化的OpenSandbox运行时。返回的会话保留活动沙盒所有权,因此后续工具调用继续从同一个执行上下文中执行,而不是悄悄地转移到另一个目录或机器上。
### 内存 — 运行之间存储的内容
内存是与沙盒执行并行的持久平面。它不是工具结果,也不仅仅是提示文本;它是可以在运行前附加到智能体、回忆和运行后提交的状态。
基本安装包括一个零依赖的本地内存后端。它在 `.openrath/memory/` 下存储数据,支持词典 BM25 回忆而无需 LLM,并可以在配置嵌入提供者时使用嵌入。OpenViking 作为可选后端提供给用户,他们想要更丰富的外部内存服务。
```python
with flow.Agent("你记得有用的事实。", model="gpt-5.5", memory="local") as agent:
agent.remember_memory("用户主要使用 Python。")
hits = agent.recall_memory("首选编程语言")
```
智能体内存 API 故意可发现:
- `memory=` 在构造时绑定一个存储。
- `remember_memory(...)` 编写显式事实。
- `recall_memory(...)` 检索相关条目。
- `commit_memory(...)` 在运行后存储一个记录。
- `commit_on_forward=True` 可以自动提交。
### 工具 — 面向模型的调用函数
`FlowToolCall` 是面向模型的工具抽象。它拥有工具的两侧:名称、描述和 JSON 模式显示给 LLM,以及在 `会话` 上执行的 Python 调用。
这将工具模式和工具行为放在一起。内置工具涵盖常见的 filesystem、shell 和代码执行路径。自定义 Python 工具可以实现相同的接口,而 stdio MCP 工具可以作为普通的 `FlowToolCall` 实例适配到循环中。
重要的区别在于:
- `FlowToolCall` 是模型可见的流层函数。
- `BackendTool*` 是由沙盒后端消耗的较低级别的有效载荷。
### 智能体 — 一个可重用的层
`flow.Agent` 是大多数用户开始使用的最小可重用层。它更接近 `nn.Linear` 而不是完整应用程序:它有提示、提供者、可选工具、可选内存和 `forward(session) -> session` 路径。
智能体不拥有整个世界。会话循环仍然是引擎,沙盒仍然是会话放置,内存仍然是一个单独的存储。这在单智能体情况下保持简单,同时允许同一个智能体出现在更大的工作流中。
### 工作流 — 组合而非混乱
`flow.Workflow` 是组合表面。子类实现:
```python
def forward(self, session: Session) -> Session:
...
```
工作流可以链接智能体、分支会话、压缩上下文、调用工具、调度子工作流,并返回新的会话。由于输入和输出都是 `会话`,工作流可以无缝嵌套,而无需在每个层级发明新的状态格式。
对于依赖于运行时对话的路由,`flow.Selector` 是一个 LLM 支持的路由器,负责在自我描述的工作流(每个工作流都带有 `description`)之间进行路由。它返回下一个要运行的工作流,或在任务完成后返回一个不操作 `flow.EmptyWorkflow`,因此 `if` / `while` 保持为纯 Python:
```python
selector = flow.Selector(provider)
while not isinstance(
nxt := selector.forward(session, triage, tech, wrapup), flow.EmptyWorkflow
):
session = nxt(session)
```
---
## 快速安装
```bash
pip install openrath
```
可选的沙盒和内存集成:
```bash
pip install "openrath[opensandbox]"
pip install "openrath[openviking]"
```
对于源代码开发:
```bash
git clone https://github.com/Rath-Team/OpenRath.git
cd OpenRath
uv sync --group dev --group docs
```
大多数 LLM 示例使用 OpenAI 兼容的环境变量:
```bash
export OPENAI_API_KEY=sk-...
export OPENAI_BASE_URL=https://your-gateway/v1
export OPENAI_DEFAULT_MODEL=your-model-name
```
您也可以在 `~/.openrath/config.json` 中配置提供者。环境变量优先。
---
## 通过运行来学习
`example/` 目录是一个编号的学习阶梯。每个脚本都介绍一个概念,保持样板文件在 `_shared/` 中,并展示核心对象如何组合在一起。
运行第一个阶梯:
```bash
python example/01_hello_agent.py
```
| # | 文件 | 概念 | 需要密钥? |
| --- | --- | --- | :---: |
| 01 | [`01_hello_agent.py`](example/01_hello_agent.py) | 最小的 OpenRath 程序:构建 `flow.Agent`,在 `会话` 上调用它,流式传输响应。 | 是 |
| 02 | [`02_session_lineage.py`](example/02_session_lineage.py) | 使用 `fork` 分支会话,使用 `detach` 切割血统,检查会话图,导出 JSONL。 | 否 |
| 03 | [`03_sandbox_backend.py`](example/03_sandbox_backend.py) | 将相同会话放置在 `local` 或 `opensandbox` 上,并观察工具在哪里执行。 | 是 |
| 04 | [`04_tools_builtin.py`](example/04_tools_builtin.py) | 使用内置的文件系统和 shell 工具,每个循环都可以公开使用。 | 是 |
| 05 | [`05_custom_tool.py`](example/05_custom_tool.py) | 使用 JSON 模式和 Python 运行时行为实现自定义 `FlowToolCall`。 | 是 |
| 06 | [`06_mcp_tool.py`](example/06_mcp_tool.py) | 包装一个小的 stdio MCP 服务器,并借用其工具而无需编写新的工具类。 | 否 |
| 07 | [`07_streaming.py`](example/07_streaming.py) | 接收流式增量并检查累积令牌使用情况后运行。 | 是 |
| 08 | [`08_compress.py`](example/08_compress.py) | 使用 `flow.Compressor` 将长会话压缩为较小的上下文会话。 | 是 |
| 09 | [`09_memory.py`](example/09_memory.py) | 使用本地内存后端记住、回忆和可选地提交实时回合。 | 否 |
| 10 | [`10_provider_variation.py`](example/10_provider_variation.py) | 通过更改 `Provider` 交换模型供应商,同时保持 Session 和 Workflow 代码稳定。 | 是 |
| 11 | [`11_dynamic_selector.py`](example/11_dynamic_selector.py) | 使用 `flow.Selector` 在自我描述的工作流之间路由:`if` 分支和一个以 `flow.EmptyWorkflow` 结束的 `while` 循环。 | 是 |
阅读 [`example/README.md`](example/README.md) 以获取设置详细信息和共享帮助程序。
---
## 文档和链接
- 文档:[https://docs.openrath.com](https://docs.openrath.com)
- 仓库:[https://github.com/Rath-Team/OpenRath](https://github.com/Rath-Team/OpenRath)
- 问题:[https://github.com/Rath-Team/OpenRath/issues](https://github.com/Rath-Team/OpenRath/issues)
本地构建文档:
```bash
uv run sphinx-build -M html docs/source docs/_build
```
---
## 许可证
OpenRath 使用 BSD 风格的许可证。参见 [LICENSE](LICENSE)。
连接信息
猜你喜欢
暂无推荐服务器