分布式Actor框架

一个为仓颉编程语言设计的分布式 Actor 框架,提供基于 Actor 的并发与分布式计算能力,支持本地与远程通信,并可将 Actor 集成到 AI 智能体中。

  • by cangjielanguage-sig
  • Cangjie
  • 本地部署
  • 更新于
在 GitHub 查看 cangjielanguage-sig/distributed-actors-cj

使用说明

distributed-actors-cj

介绍

一个为仓颉编程语言设计的分布式 Actor 框架,提供基于 Actor 的并发与分布式计算能力,支持本地与远程通信,并可通过 MCP 协议将 Actor 以工具形式集成到 AI 智能体中。

项目特性

  • Actor 编程模型:基于异步方法调用的主动对象抽象
  • 分布式 Actor:用于定义分布式 Actor 接口与实现的声明式语法
  • TCP Actor 系统:基于 TCP 的分布式 Actor 系统实现
  • TCP 集群:基于集群的分布式 Actor 系统,支持多节点部署和自动 actor 放置
  • 智能体集成:通过 MCP 协议将 Actor 以工具形式提供给 AI 智能体使用

项目计划

  • [x] 类型安全的 Actor 代理
  • [x] 可序列化的代理
  • [ ] 同地协作 actor 的快捷 receiver 调用
  • [ ] 消息传递语义(至少一次 vs 最多一次)
  • [ ] 失败消息传递的重试机制
  • [ ] 增强异常与错误处理
  • [ ] 可重入的 Actor
  • [x] 集群

项目架构

源码目录

actors                   # 核心 Actor 编程模型与本地 Actor 系统
├── ActorFuture          # 异步结果处理
├── SequentialDispatcher # 线程安全的任务调度器
│
├── actors.distributed      # 分布式 Actor 接口与元数据
│   ├── ActorHost           # Actor 注册接口
│   ├── ActorClient         # 远程 Actor 访问接口
│   ├── ActorProxy          # 远程 Actor 的客户端代理
│   ├── DistributedFuture   # 分布式操作结果
│   ├── ActorCluster
│
├── actors.macros          # 编译期 Actor 与接口生成
│   ├── @Actor             # 将类转换为 Actor
│   ├── @ActorInterface    # 将接口转换为 Actor 接口
│   └── @Receiver          # 将方法转换为接收函数
│
├── actors.tcp_actor_system # 基于 TCP 的分布式 Actor 实现
    ├── TCPActorHost        # 基于 TCP 的 Actor 主机
    ├── TCPActorClient      # 基于 TCP 的 Actor 客户端
    ├── TCPActorSystem      # TCP Actor 系统的主配置
    │
    └── actors.tcp_actor_system.cluster  # 基于集群的分布式 Actor 系统
        └── TCPCluster                   # 集群管理器(头服务器和工作节点)

subpackages
└── actors-mcp                 # 独立 MCP 扩展包(actors_mcp)
    └── actors_mcp             # Model Context Protocol (MCP) 集成
        ├── ActorToolManager   # Actor 客户端 MCP 工具管理器
        └── ReceiverTool       # Actor 接收器 MCP 工具封装

接口说明

有关详细的 API 参考,请参阅 API 文档.

使用说明

使用 Git 依赖(推荐)

在你的 cjpm.toml 中添加如下内容:

[dependencies]
  actors = { git = "https://gitcode.com/Cangjie-TPC/distributed-actors-cj.git", branch = "main", version = "0.2.0" }

如果需要 MCP 集成,请额外添加本仓库内的 MCP 包:

[dependencies]
  actors_mcp = { path = "/path-to/actors-mcp" }

编译构建

在构建该包之前,请确保已经完成以下操作:

  1. 配置好 Cangjie 编译器,例如:source /path-to-cangjie-compiler/envsetup.sh
  2. 配置好 stdx 的路径,例如:export CANGJIE_STDX_PATH=/path-to-stdx-lib/dynamic/stdx
  3. 将 stdx 路径添加到库加载路径中,例如:
  • 在 macOS 上:export DYLD_LIBRARY_PATH=$CANGJIE_STDX_PATH:$DYLD_LIBRARY_PATH
  • 在 Linux 上:export LD_LIBRARY_PATH=$CANGJIE_STDX_PATH:$LD_LIBRARY_PATH
# 构建包
make
# 构建示例
make example

测试

# 运行所有测试
make test

教程

完整教程可见于 教程。

功能示例

有关更详细的示例,请参考

  • 示例:演示各项功能的示例

本地 Actor

import actors.*
import actors.macros.*

@Actor
public class Counter {
    private var value: Int64 = 0

    @Receiver
    public func increment(): Int64 {
        value += 1
        return value
    }

    @Receiver
    public func getValue(): Int64 {
        return value
    }
}

main() {
    let counter = Counter()
    let future = counter.increment()
    println("Counter value: ${future.get()}")
}

执行结果如下:

1

分布式 Actor

import std.collection.*

import actors.*
import actors.macros.*
import actors.distributed.*
import actors.tcp_actor_system.*

import stdx.encoding.json.*
import stdx.serialization.serialization.*

@ActorInterface[distributed: true, description: "Bank service"]
public interface BankAccount {
    @Receiver[description: "Deposit money into the account"]
    func deposit(amount: Float64): Bool

    @Receiver[description: "Withdraw money from the account"]
    func withdraw(amount: Float64): Bool

    @Receiver[description: "Get the balance of the account"]
    func getBalance(): Float64
}

@Actor
public class BankAccountImpl <: BankAccount {
    private let name: String
    private var balance: Float64

    public init(name: String, balance: Float64) {
        this.name = name
        this.balance = balance
    }

    @Receiver
    public func deposit(amount: Float64): Bool {
        balance += amount
        true
    }

    @Receiver
    public func withdraw(amount: Float64): Bool {
        if (balance < amount) {
            return false
        }
        balance -= amount
        true
    }

    @Receiver
    public func getBalance(): Float64 {
        balance
    }
}

const PORT: UInt16 = 52165

main() {
    // Host side
    let tcpHost = TCPActorHost(addr: "localhost", bindAt: PORT)
    let serverFuture = tcpHost.serve() // start the server

    let bankAccount = BankAccountImpl("Steven", 0.0)
    tcpHost.export("Steven", bankAccount)

    // Client side
    let tcpClient = TCPActorClient.create("localhost", PORT)
    let proxy = tcpClient.getActor("Steven").getOrThrow()

    // Using untyped proxy
    proxy.ask("deposit", [100.0.serialize()]).get()
    let res = Float64.deserialize(proxy.ask("getBalance", []).get())
    println("Steven balance: ${res}") // 100.0

    // Using typed proxy
    let steven = BankAccount.getProxy(proxy)
    steven.deposit(100.0).get()
    let res2 = steven.getBalance().get()
    println("Steven balance: ${res2}") // 200.0
}

执行结果如下:

Steven balance: 100.0
Steven balance: 200.0

AI 智能体整合

import magic.prelude.*
import magic.dsl.*
import magic.config.Config

import actors_mcp.*
import actors.tcp_actor_system.*

@agent[model: "deepseek:deepseek-chat"]
class AssistantAgent {
    @prompt("You are a helpful assistant that can interact with distributed services.")

    init(toolManager!: ToolManager) {
        __TOOL_MANAGER__ = Some(toolManager)
    }
}

main() {
    let toolManager = ActorToolManager()
    let agent = AssistantAgent(toolManager: toolManager)

    let tcpClient = TCPActorClient.create("localhost", 8080)
    toolManager.addActorClient(tcpClient)

    let response = agent.chat("Transfer $100 from Alice to Bob")
    println("Assistant: ${response}")
}

约束与限制

目前代码仅在以下版本能够正确编译执行:

  • Cangjie 1.0.5(通用版)

如果使用了其他版本的 Cangjie SDK,可能需要直接修改项目源代码进行适配。

开源协议

MIT License

参与贡献

欢迎给我们提交PR,欢迎给我们提交Issue,欢迎参与任何形式的贡献。