展示 HN:反转代理模型(应用作为客户端,聊天作为服务器和反思)
Show HN: Inverting Agent Model (App as Clients, Chat as Server and Reflection)

原始链接: https://github.com/RAIL-Suite/RAIL

## RAIL:一行代码实现对任何应用的AI控制 RAIL是一个通用桥梁,可以使用一行代码通过任何LLM(GPT、Claude、Gemini)控制*任何*应用——C#、C++、Python、Node.js。RAIL不是进行大量重写,而是将AI直接连接到您现有的方法。 核心是**RailOrchestrator**,一个处理LLM路由和ReAct代理循环的C#应用程序。它利用**RailBridge.Native**,一个通过命名管道进行跨语言通信的本地DLL。特定语言的SDK(**.NET**的**RailSDK.Universal**,**C++**的**RailSDK-Cpp**,**Python**的**RailSDK-Python**,**Node.js**的**RailSDK-Node**)简化了集成。**RailStudio**提供了一个用于应用扫描和清单生成的视觉工具。 **集成非常简单:** C#只需要一个引用;C++提供有或没有RTTR反射的选项;Python和Node.js使用包装包。一个`rail.manifest.json`文件定义了可访问的方法。 RAIL促进了自然语言控制:像“创建一个客户…”这样的AI提示可以直接调用相应的应用程序方法。示例集成展示了对C#应用、C++遗留系统(如Notepad++)和Python脚本的控制。它有效地将遗留应用与现代AI的力量连接起来。

## RAIL:一种反向代理通信层 一位开发者在Hacker News上介绍了RAIL(远程代理调用层),这是一种为代理工作流设计的桌面应用程序进程间通信(IPC)的新方法。与传统的客户端-服务器模型不同,RAIL反转了这种关系:**“Chat”(LLM 编排器)充当服务器,而桌面应用程序是客户端。** RAIL利用“内存逻辑注入 + 反射”,应用程序将它们的实例传递给一个库,允许编排器通过反射在应用程序的内存空间内远程触发方法。这避免了对大量API包装器的需求。 开发者正在寻求对架构的反馈——特别是这种“回拨”方法对于本地代理是否合理——以及潜在的优化方案。 担忧包括每次调用使用反射的性能影响(以及使用委托作为缓存是否有帮助),以及绕过传统API层带来的安全隐患,从而引发了对潜在用户签名能力清单的讨论。该项目专注于C#/.NET,并有其他语言的实验性连接器。
相关文章

原文

One line of code to make any application AI-controllable


RAIL is a universal bridge that connects any application (C#, C++, Python, Node.js) to any LLM (GPT, Claude, Gemini). Instead of rewriting your application, you add one line of code and the AI can call your methods directly.


Project Purpose Language
RailOrchestrator Main AI application (UI + LLM routing) C# / WPF
RailBridge.Native Native DLL for cross-language IPC C# (Native AOT)
RailSDK.Universal Client SDK for .NET apps C# (.NET Standard)
RailSDK Analysis & manifest generation tools C#
RailSDK-Cpp Client SDK for C++ apps C++
RailSDK-Python Client SDK for Python apps Python
RailSDK-Node Client SDK for Node.js apps TypeScript
RailStudio Visual tool for scanning/analyzing apps C# / WPF
ConvertedProjectExample Example applications C#

The Brain - Main application that users interact with.

  • WPF desktop application (.NET 9)
  • Connects to LLMs (Gemini, OpenAI, Anthropic, Claude)
  • ReAct agent loop for multi-step reasoning
  • Hosts the Named Pipe server for client connections
  • Manages assets (Chips) and tool routing

Key files:

  • Services/Host/HostService.cs - Named Pipe server
  • Services/LLMService.cs - LLM API integration
  • Services/ReAct/ReActOrchestrator.cs - Agent loop

The Bridge - Native DLL that enables cross-language communication.

  • Compiled with Native AOT for C-ABI compatibility
  • Exposes functions callable from any language:
    • RAIL_Ignite() - Connect to host
  • Uses Named Pipes for IPC

Target: Python, C++, Node.js, Rust, Go


The .NET SDK - Client library for C# applications.

  • .NET Standard 2.0 (compatible with .NET Framework 4.6.1+)
  • Simple API: RailEngine.Ignite(this)
  • Auto-discovers methods via reflection
  • Loads RailBridge.dll for communication

Usage:

// In App.xaml.cs
RailEngine.Ignite(this);

RailSDK (RailFactory.Core)

The Toolkit - Assembly scanning and manifest generation.

Contains:

  • RuntimeRegistry - Detect .NET / Native binaries
  • AssemblyScanner - Extract methods from DLLs
  • CompositeManifest - Multi-module manifest format
  • DependencyAnalyzer - Analyze project dependencies
  • SolutionScanner - Scan entire .sln solutions

Used by: RailStudio, RailOrchestrator


The C++ SDK - Enable C++ applications to connect.

  • CMake-based build system
  • Loads RailBridge.dll via LoadLibrary
  • Callback-based command execution
  • Supports both x64 and x86 builds

Build:

build_x64.bat   # 64-bit
build_x86.bat   # 32-bit (legacy apps)

Usage:

Rail::ignite("MyApp", manifestJson, onCommand);

The Python SDK - Enable Python scripts to connect.

  • Uses ctypes to load RailBridge.dll
  • Decorator-based method registration
  • Simple API matching other SDKs

Usage:

from rail import RailEngine

engine = RailEngine()
engine.ignite([MyService()])

RailSDK-Node (Never tested)

The Node.js SDK - Enable TypeScript/JavaScript apps to connect.

  • Uses ffi-napi for native bridge access
  • TypeScript types included
  • Promise-based API

Usage:

import { RailEngine } from 'rail-sdk';
engine.ignite([new MyService()]);

The Visual Tool - Scan and analyze applications.

  • EXE/DLL to analyzer
  • Auto-generates rail.manifest.json
  • Visualizes dependencies
  • Solution-wide scanning

Use case: Preparing legacy apps for Rail integration


Example applications showing SDK integration.

Example Description
AgentTest Simple WPF app with customer database
WorkflowDemo Workflow automation example

Manifest Here you can find Manifest folder with all the "rail.manifest.json" already created for this example application


4. SDK Requirements for Developers

When converting your application to be AI-controllable, here's exactly what you need:

Language What to Add Automatically Included Notes
C# (.NET) RailSDK.Universal.dll RailBridge.dll (auto-copied) One reference, everything included
C++ (Modern) rail_sdk.dll + RailBridge.dll RTTR reflection, auto method discovery
C++ (Legacy) rail_sdk.dll + RailBridge.dll Custom dispatcher, manual routing
Python RailBridge.dll + rail package Load via ctypes
Node.js RailBridge.dll + rail-sdk npm Load via ffi-napi

C# Developers: One Reference Does It All

When you add RailSDK.Universal, the native bridge is automatically copied to your output:

📁 bin/Debug/net8.0/
├── YourApp.exe
├── RailSDK.Universal.dll   ← You add this reference
├── RailBridge.dll          ← Copied automatically!
└── rail.manifest.json      ← You create this

How to add:

<PackageReference Include="RailSDK.Universal" Version="2.0.0" />

C++ Developers: Two Options

C++ has two integration modes depending on your codebase:

Option A: Modern C++ with RTTR (Automatic Reflection)

For new applications or codebases that support C++17:

// Register your classes with RTTR macros
RTTR_REGISTRATION {
    rttr::registration::class_<OrderManager>("OrderManager")
        .method("CreateOrder", &OrderManager::CreateOrder);
}

// SDK auto-discovers methods
rail::RegisterInstance("OrderManager", &myManager);
rail::Ignite("MyApp");

Files needed:

📁 YourApp/
├── YourApp.exe
├── rail_sdk.dll            ← C++ wrapper (includes RTTR)
├── RailBridge.dll          ← Native IPC bridge
└── rail.manifest.json      ← Auto-generated

Option B: Legacy C++ with Custom Dispatcher (Manual Routing)

For legacy applications that can't use C++17 or RTTR (e.g., games, old codebases):

#define RAIL_NO_RTTR  // Disable RTTR

// Define your own command router
std::string MyDispatcher(const std::string& json) {
    if (json.find("MovePlayer") != std::string::npos) {
        MovePlayer();
        return "{\"result\": \"success\"}";
    }
    return "{\"error\": \"unknown\"}";
}

// Register and connect
rail::SetCustomDispatcher(MyDispatcher);
rail::Ignite("MyLegacyApp", "1.0", customManifest);

Files needed:

📁 YourApp/
├── YourApp.exe
├── rail_sdk.dll            ← C++ wrapper (no RTTR)
├── RailBridge.dll          ← Native IPC bridge
└── rail.manifest.json      ← You write this manually

Real Examples: Notepad++ and Doom were integrated using Option B (Custom Dispatcher) because their codebases couldn't support RTTR.


Python/Node.js Developers

📁 YourProject/
├── main.py (or index.ts)
├── RailBridge.dll          ← Copy manually
└── rail.manifest.json      ← You create this

Install the wrapper package that handles ctypes/ffi calls for you.


Architecture Overview

Architecture Workflow

┌─────────────────────────────────────────────────────────────┐
│                    RailOrchestrator                       │
│                    (Main AI Application)                    │
│                                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌───────────────┐   │
│  │  LLM APIs   │    │ HostService │    │ AssetService  │   │
│  │  (Gemini,   │    │ (Named Pipe │    │ (Chip/Manifest│   │
│  │   OpenAI)   │    │   Server)   │    │   Discovery)  │   │
│  └──────┬──────┘    └──────┬──────┘    └───────────────┘   │
└─────────┼──────────────────┼────────────────────────────────┘
          │                  │
          │         Named Pipe: "RailHost"
          │                  │
    ┌─────┴──────────────────┴─────────────────────┐
    │               RailBridge.Native            │
    │            (C-ABI Native DLL)                │
    └──────────────────┬───────────────────────────┘
                       │
       ┌───────────────┼───────────────┐
       │               │               │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ RailSDK   │ │ RailSDK   │ │ RailSDK   │
│ .Universal  │ │ -Cpp        │ │ -Python     │
│ (C# Apps)   │ │ (C++ Apps)  │ │ (Python)    │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
       │               │               │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│  Your C#   │ │  Your C++  │ │ Your Python │
│    App     │ │    App     │ │   Script    │
└─────────────┘ └─────────────┘ └─────────────┘
RailOrchestrator
    └── uses → RailSDK (RailFactory.Core) for manifest parsing
    
RailSDK.Universal
    └── loads → RailBridge.Native (DLL)
    
RailSDK-Cpp / RailSDK-Python / RailSDK-Node
    └── load → RailBridge.Native (DLL)

RailStudio
    └── uses → RailSDK (RailFactory.Core) for scanning

Example 1: Make a C# App AI-Controllable

// 1. Create your service
public class CustomerService
{
    public Customer GetCustomer(int id) => Database.Find(id);
    public void CreateCustomer(string name, string email) { ... }
}

// 2. Add one line in App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    RailEngine.Ignite(this);
}

// 3. Create rail.manifest.json (or use RailStudio)

Example 2: Control a C++ Application

// Define callback
const char* OnCommand(const char* json) {
    auto cmd = ParseJson(json);
    if (cmd.method == "MoveMachine") {
        Machine::Move(cmd.args["x"], cmd.args["y"]);
        return R"({"result": "OK"})";
    }
    return R"({"error": "Unknown"})";
}

// Connect
rail::ignite("CNCController", manifest, OnCommand);

Example 3: Python Script Integration

class DataProcessor:
    def analyze_data(self, file_path: str) -> dict:
        return {"rows": 1000, "status": "processed"}

engine = RailEngine()
engine.ignite([DataProcessor()])
engine.wait()

Example 4: Ask AI to Execute

With apps connected, ask in natural language:

"Create a customer named John Smith with email [email protected]"
→ AI calls CustomerService.CreateCustomer("John Smith", "[email protected]")

"Move the machine to position X=100, Y=200"
→ AI calls CNCController.MoveMachine(100, 200)

  1. Run RailOrchestrator - The main AI interface
  2. Connect your app - Add SDK and call Ignite()
  3. Ask AI - Natural language commands execute your code

RAIL Protocol - Bridging Legacy Applications and AI

联系我们 contact @ memedata.com