版本: v2.0.0 | 最后更新: 2026-04-16 | 状态: Phase 1-12 重构完成
Nexa-net 提供多层次的 API 接口:
┌─────────────────────────────────────────────────────────────┐
│ API Architecture │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ SDK Layer (High-Level) │ │
│ │ - Python SDK │ │
│ │ - TypeScript/Node.js SDK │ │
│ │ - Rust SDK │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Local API (Nexa-Proxy) │ │
│ │ - REST API (localhost:7070) │ │
│ │ - Unix Socket │ │
│ │ - gRPC (localhost:7071) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Network API (Supernode) │ │
│ │ - gRPC (supernode:443) │ │
│ │ - REST API (supernode:443/api) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
所有 API 遵循语义化版本控制:
- 主版本号 (Major): 不兼容的 API 变更
- 次版本号 (Minor): 向后兼容的功能新增
- 修订号 (Patch): 向后兼容的问题修复
API 版本格式: v1.0.0
请求头指定版本:
Accept: application/vnd.nexa.v1+json
| API 类型 | 认证方式 | 描述 |
|---|---|---|
| 本地 API | 无需认证 | 仅监听 localhost |
| 网络 API | DID + 签名 | 请求签名验证 |
| 管理 API | API Key | 管理操作需要额外认证 |
Base URL: http://127.0.0.1:7070/v1
POST /call
发起网络调用请求。
请求体:
{
"intent": "translate English PDF to Chinese",
"data": "<base64-encoded-data>",
"data_type": "application/pdf",
"max_budget": 50,
"timeout_ms": 30000,
"options": {
"target_language": "zh",
"preserve_formatting": true
}
}响应:
{
"call_id": "call-abc123",
"status": "success",
"result": {
"data": "<base64-encoded-result>",
"data_type": "application/pdf",
"metadata": {
"pages_processed": 10,
"characters_translated": 5000
}
},
"cost": 25,
"latency_ms": 2500,
"provider": {
"did": "did:nexa:provider123...",
"endpoint_id": "translate_document"
}
}错误响应:
{
"call_id": "call-abc123",
"status": "error",
"error": {
"code": "NO_MATCHING_SERVICE",
"message": "No service found matching the intent",
"details": {
"similarity_threshold": 0.7,
"best_match_score": 0.45
}
}
}GET /capabilities
获取本地注册的能力列表。
响应:
{
"capabilities": [
{
"endpoint_id": "process_document",
"name": "Document Processing",
"description": "Process and analyze documents",
"status": "active",
"calls_total": 150,
"calls_success": 148
}
]
}POST /capabilities
注册新的能力。
请求体:
{
"endpoint_id": "analyze_sentiment",
"name": "Sentiment Analysis",
"description": "Analyze sentiment of text",
"input_schema": {
"type": "object",
"properties": {
"text": { "type": "string" }
},
"required": ["text"]
},
"output_schema": {
"type": "object",
"properties": {
"sentiment": { "type": "string", "enum": ["positive", "negative", "neutral"] },
"confidence": { "type": "number" }
}
},
"cost": {
"model": "per_call",
"base_price": 5
}
}DELETE /capabilities/{endpoint_id}
注销能力。
GET /channels
获取状态通道列表。
响应:
{
"channels": [
{
"channel_id": "chan-xyz",
"peer_did": "did:nexa:peer123...",
"status": "open",
"balance_local": 750,
"balance_remote": 250,
"total_deposit": 1000,
"created_at": "2026-03-30T00:00:00Z",
"expires_at": "2026-03-31T00:00:00Z"
}
]
}POST /channels
开启新的状态通道。
请求体:
{
"peer_did": "did:nexa:peer123...",
"deposit": 1000,
"timeout_seconds": 86400
}POST /channels/{channel_id}/close
关闭状态通道。
请求体:
{
"reason": "normal_close"
}GET /balance
获取 Token 余额。
响应:
{
"did": "did:nexa:abc123...",
"total": 10000,
"available": 7500,
"locked": 2500,
"pending": 0
}GET /balance/history
获取余额变更历史。
查询参数:
start: 开始时间 (ISO 8601)end: 结束时间 (ISO 8601)limit: 返回条数限制
响应:
{
"history": [
{
"timestamp": "2026-03-30T07:00:00Z",
"type": "service_payment",
"amount": -25,
"balance_after": 9975,
"description": "Payment for translate_document"
}
]
}GET /identity
获取当前身份信息。
响应:
{
"did": "did:nexa:abc123...",
"public_key": "base64-encoded-public-key",
"created_at": "2026-01-01T00:00:00Z",
"status": "active"
}POST /identity/rotate-key
轮换密钥。
请求体:
{
"reason": "scheduled_rotation"
}响应:
{
"old_key_id": "key-1",
"new_key_id": "key-2",
"transition_period_ends": "2026-04-06T00:00:00Z"
}GET /health
健康检查端点。
响应:
{
"status": "healthy",
"version": "1.0.0",
"uptime_seconds": 86400,
"components": {
"network": "healthy",
"identity": "healthy",
"economy": "healthy",
"registry": "healthy"
}
}GET /ready
就绪检查端点。
响应:
{
"ready": true,
"checks": {
"supernode_connection": true,
"identity_loaded": true,
"channels_ready": true
}
}对于本地高性能通信,可使用 Unix Socket:
Socket Path: /var/run/nexa-proxy.sock
协议格式与 REST API 相同,通过 HTTP over Unix Socket。
Base URL: https://supernode.example.com/api/v1
POST /register
注册 Agent 能力。
请求头:
Authorization: Bearer <signed-token>
Content-Type: application/json
请求体:
{
"did": "did:nexa:abc123...",
"capabilities": {
"endpoints": [
{
"id": "translate_document",
"name": "Document Translation",
"description": "Translate documents while preserving formatting",
"input_schema": { ... },
"output_schema": { ... },
"cost": { ... }
}
]
},
"metadata": {
"region": "asia-east",
"endpoint": "https://proxy.example.com:7070"
},
"signature": "base64-encoded-signature"
}响应:
{
"registration_id": "reg-xyz",
"status": "success",
"registered_at": "2026-03-30T00:00:00Z",
"expires_at": "2026-04-30T00:00:00Z"
}POST /route
查询匹配的服务。
请求体:
{
"intent": "translate English PDF to Chinese",
"intent_vector": [0.12, -0.34, ...],
"max_results": 5,
"filters": {
"max_cost": 50,
"min_quality": 0.8,
"region": "asia-east"
}
}响应:
{
"candidates": [
{
"rank": 1,
"did": "did:nexa:provider123...",
"endpoint_id": "translate_document",
"similarity": 0.92,
"estimated_cost": 25,
"estimated_latency_ms": 2000,
"quality_score": 0.95,
"metadata": {
"name": "Advanced Translation Service",
"region": "asia-east"
}
}
],
"query_time_ms": 15
}GET /nodes/{did}/status
获取节点状态。
响应:
{
"did": "did:nexa:abc123...",
"online": true,
"last_heartbeat": "2026-03-30T07:00:00Z",
"load": {
"cpu": 0.45,
"memory": 0.60,
"concurrent_calls": 5
},
"performance": {
"avg_latency_ms": 150,
"success_rate": 0.98
}
}GET /did/{did}
解析 DID Document。
响应:
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:nexa:abc123...",
"verificationMethod": [
{
"id": "did:nexa:abc123...#key-1",
"type": "Ed25519VerificationKey2020",
"publicKeyMultibase": "z6MkhaXgBZDvotDkL5257fc8M9Zr3g..."
}
],
"service": [
{
"id": "did:nexa:abc123...#nexa-proxy",
"type": "NexaProxyEndpoint",
"serviceEndpoint": "https://proxy.example.com:7070"
}
]
}GET /admin/nodes
获取所有注册节点列表。
请求头:
Authorization: Bearer <admin-api-key>
响应:
{
"nodes": [
{
"did": "did:nexa:abc123...",
"status": "online",
"registered_at": "2026-01-01T00:00:00Z",
"capabilities_count": 3,
"calls_total": 1000
}
],
"total": 100,
"page": 1,
"per_page": 20
}DELETE /admin/nodes/{did}
注销节点。
GET /admin/network/status
获取网络整体状态。
响应:
{
"total_nodes": 100,
"online_nodes": 95,
"total_capabilities": 250,
"total_calls_today": 50000,
"total_volume_today": 1000000,
"avg_latency_ms": 150,
"success_rate": 0.98
}// nexa_proxy.proto
syntax = "proto3";
package nexa.proxy.v1;
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
// Nexa-Proxy 服务
service NexaProxy {
// 网络调用
rpc Call(CallRequest) returns (CallResponse);
rpc CallStream(stream CallRequest) returns (stream CallResponse);
// 能力管理
rpc RegisterCapability(RegisterCapabilityRequest) returns (RegisterCapabilityResponse);
rpc UnregisterCapability(UnregisterCapabilityRequest) returns (UnregisterCapabilityResponse);
rpc ListCapabilities(ListCapabilitiesRequest) returns (ListCapabilitiesResponse);
// 通道管理
rpc OpenChannel(OpenChannelRequest) returns (OpenChannelResponse);
rpc CloseChannel(CloseChannelRequest) returns (CloseChannelResponse);
rpc ListChannels(ListChannelsRequest) returns (ListChannelsResponse);
// 余额管理
rpc GetBalance(GetBalanceRequest) returns (GetBalanceResponse);
rpc GetBalanceHistory(GetBalanceHistoryRequest) returns (stream BalanceHistoryEntry);
// 身份管理
rpc GetIdentity(GetIdentityRequest) returns (GetIdentityResponse);
rpc RotateKey(RotateKeyRequest) returns (RotateKeyResponse);
// 健康检查
rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
rpc ReadyCheck(ReadyCheckRequest) returns (ReadyCheckResponse);
}
// Call 请求
message CallRequest {
string intent = 1;
bytes data = 2;
string data_type = 3;
uint32 max_budget = 4;
uint32 timeout_ms = 5;
google.protobuf.Struct options = 6;
}
// Call 响应
message CallResponse {
string call_id = 1;
CallStatus status = 2;
bytes result_data = 3;
string result_data_type = 4;
google.protobuf.Struct result_metadata = 5;
uint32 cost = 6;
uint32 latency_ms = 7;
ProviderInfo provider = 8;
ErrorInfo error = 9;
}
enum CallStatus {
CALL_STATUS_UNSPECIFIED = 0;
CALL_STATUS_SUCCESS = 1;
CALL_STATUS_ERROR = 2;
CALL_STATUS_TIMEOUT = 3;
CALL_STATUS_CANCELLED = 4;
CALL_STATUS_INSUFFICIENT_BUDGET = 5;
}
message ProviderInfo {
string did = 1;
string endpoint_id = 2;
}
message ErrorInfo {
string code = 1;
string message = 2;
google.protobuf.Struct details = 3;
}
// 能力注册请求
message RegisterCapabilityRequest {
string endpoint_id = 1;
string name = 2;
string description = 3;
google.protobuf.Struct input_schema = 4;
google.protobuf.Struct output_schema = 5;
CostModel cost = 6;
}
message CostModel {
string model = 1; // per_call, per_page, per_token, etc.
uint32 base_price = 2;
repeated CostModifier modifiers = 3;
}
message CostModifier {
string condition = 1;
float multiplier = 2;
}
message RegisterCapabilityResponse {
string endpoint_id = 1;
bool success = 2;
string message = 3;
}
// 通道管理
message OpenChannelRequest {
string peer_did = 1;
uint64 deposit = 2;
uint64 timeout_seconds = 3;
}
message OpenChannelResponse {
string channel_id = 1;
ChannelStatus status = 2;
uint64 balance_local = 3;
uint64 balance_remote = 4;
}
enum ChannelStatus {
CHANNEL_STATUS_UNSPECIFIED = 0;
CHANNEL_STATUS_OPENING = 1;
CHANNEL_STATUS_OPEN = 2;
CHANNEL_STATUS_CLOSING = 3;
CHANNEL_STATUS_CLOSED = 4;
}
// 余额查询
message GetBalanceRequest {}
message GetBalanceResponse {
string did = 1;
uint64 total = 2;
uint64 available = 3;
uint64 locked = 4;
uint64 pending = 5;
}
// 健康检查
message HealthCheckRequest {}
message HealthCheckResponse {
HealthStatus status = 1;
string version = 2;
uint64 uptime_seconds = 3;
map<string, HealthStatus> components = 4;
}
enum HealthStatus {
HEALTH_STATUS_UNSPECIFIED = 0;
HEALTH_STATUS_HEALTHY = 1;
HEALTH_STATUS_DEGRADED = 2;
HEALTH_STATUS_UNHEALTHY = 3;
}// supernode.proto
syntax = "proto3";
package nexa.supernode.v1;
import "google/protobuf/timestamp.proto";
// Supernode 服务
service Supernode {
// 注册服务
rpc Register(RegisterRequest) returns (RegisterResponse);
rpc Unregister(UnregisterRequest) returns (UnregisterResponse);
rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);
// 路由服务
rpc Route(RouteRequest) returns (RouteResponse);
rpc RouteStream(stream RouteRequest) returns (stream RouteResponse);
// DID 服务
rpc ResolveDID(ResolveDIDRequest) returns (ResolveDIDResponse);
// 状态服务
rpc GetNodeStatus(GetNodeStatusRequest) returns (GetNodeStatusResponse);
rpc WatchNodeStatus(WatchNodeStatusRequest) returns (stream NodeStatusEvent);
}
// 注册请求
message RegisterRequest {
string did = 1;
CapabilitySchema capabilities = 2;
NodeMetadata metadata = 3;
bytes signature = 4;
}
message CapabilitySchema {
repeated Endpoint endpoints = 1;
}
message Endpoint {
string id = 1;
string name = 2;
string description = 3;
bytes input_schema = 4; // JSON Schema
bytes output_schema = 5;
CostModel cost = 6;
repeated float semantic_vector = 7;
}
message NodeMetadata {
string region = 1;
string endpoint = 2;
uint32 max_concurrent = 3;
}
message RegisterResponse {
string registration_id = 1;
bool success = 2;
google.protobuf.Timestamp registered_at = 3;
google.protobuf.Timestamp expires_at = 4;
}
// 心跳
message HeartbeatRequest {
string did = 1;
NodeStatus status = 2;
bytes signature = 3;
}
message NodeStatus {
float cpu_load = 1;
float memory_load = 2;
uint32 concurrent_calls = 3;
uint32 queue_length = 4;
PerformanceMetrics performance = 5;
}
message PerformanceMetrics {
uint32 avg_latency_ms = 1;
uint32 p99_latency_ms = 2;
float success_rate = 3;
}
message HeartbeatResponse {
bool acknowledged = 1;
uint64 timestamp = 2;
}
// 路由请求
message RouteRequest {
string intent = 1;
repeated float intent_vector = 2;
uint32 max_results = 3;
RouteFilters filters = 4;
}
message RouteFilters {
uint32 max_cost = 1;
float min_quality = 2;
string region = 3;
repeated string required_tags = 4;
}
message RouteResponse {
repeated RouteCandidate candidates = 1;
uint32 query_time_ms = 2;
}
message RouteCandidate {
uint32 rank = 1;
string did = 2;
string endpoint_id = 3;
float similarity = 4;
uint32 estimated_cost = 5;
uint32 estimated_latency_ms = 6;
float quality_score = 7;
map<string, string> metadata = 8;
}
// DID 解析
message ResolveDIDRequest {
string did = 1;
}
message ResolveDIDResponse {
bytes document = 1; // JSON DID Document
google.protobuf.Timestamp cached_at = 2;
}pip install nexa-netfrom nexa_net import NexaClient, Capability, CostModel
# 初始化客户端
client = NexaClient(config_path="~/.nexa/config.yaml")
# 发起网络调用
result = await client.call(
intent="translate English PDF to Chinese",
data=open("document.pdf", "rb").read(),
max_budget=50
)
print(f"Result: {result.data}")
print(f"Cost: {result.cost} NEXA")
# 注册能力
capability = Capability(
endpoint_id="analyze_sentiment",
name="Sentiment Analysis",
description="Analyze sentiment of text",
input_schema={
"type": "object",
"properties": {
"text": {"type": "string"}
}
},
output_schema={
"type": "object",
"properties": {
"sentiment": {"type": "string"},
"confidence": {"type": "number"}
}
},
cost=CostModel(model="per_call", base_price=5)
)
await client.register_capability(capability)class NexaClient:
"""Nexa-net Python SDK 客户端"""
def __init__(
self,
config_path: str = None,
proxy_url: str = "http://127.0.0.1:7070"
):
"""初始化客户端"""
pass
# 网络调用
async def call(
self,
intent: str,
data: bytes = None,
max_budget: int = None,
timeout_ms: int = 30000,
options: dict = None
) -> CallResult:
"""发起网络调用"""
pass
async def call_stream(
self,
intent: str,
data_stream: AsyncIterator[bytes],
max_budget: int = None
) -> AsyncIterator[StreamResult]:
"""流式网络调用"""
pass
# 能力管理
async def register_capability(self, capability: Capability) -> str:
"""注册能力"""
pass
async def unregister_capability(self, endpoint_id: str) -> bool:
"""注销能力"""
pass
async def list_capabilities(self) -> list[Capability]:
"""列出已注册能力"""
pass
# 通道管理
async def open_channel(
self,
peer_did: str,
deposit: int
) -> Channel:
"""开启状态通道"""
pass
async def close_channel(self, channel_id: str) -> Settlement:
"""关闭状态通道"""
pass
async def list_channels(self) -> list[Channel]:
"""列出状态通道"""
pass
# 余额管理
async def get_balance(self) -> Balance:
"""获取余额"""
pass
async def get_balance_history(
self,
start: datetime = None,
end: datetime = None
) -> list[BalanceChange]:
"""获取余额历史"""
pass
# 身份管理
async def get_identity(self) -> Identity:
"""获取身份信息"""
pass
async def rotate_key(self) -> KeyRotation:
"""轮换密钥"""
pass
# 上下文管理
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.close()
async def close(self):
"""关闭客户端"""
passnpm install @nexa-net/sdk
# 或
pnpm add @nexa-net/sdkimport { NexaClient, Capability, CostModel } from '@nexa-net/sdk';
// 初始化客户端
const client = new NexaClient({
configPath: '~/.nexa/config.yaml'
});
// 发起网络调用
const result = await client.call({
intent: 'translate English PDF to Chinese',
data: fs.readFileSync('document.pdf'),
maxBudget: 50
});
console.log(`Result: ${result.data}`);
console.log(`Cost: ${result.cost} NEXA`);
// 注册能力
const capability: Capability = {
endpointId: 'analyze_sentiment',
name: 'Sentiment Analysis',
description: 'Analyze sentiment of text',
inputSchema: {
type: 'object',
properties: {
text: { type: 'string' }
}
},
outputSchema: {
type: 'object',
properties: {
sentiment: { type: 'string' },
confidence: { type: 'number' }
}
},
cost: {
model: 'per_call',
basePrice: 5
}
};
await client.registerCapability(capability);interface NexaClientConfig {
configPath?: string;
proxyUrl?: string;
timeout?: number;
}
interface CallOptions {
intent: string;
data?: Buffer | ArrayBuffer;
maxBudget?: number;
timeoutMs?: number;
options?: Record<string, unknown>;
}
interface CallResult {
callId: string;
status: CallStatus;
data?: Buffer;
metadata?: Record<string, unknown>;
cost: number;
latencyMs: number;
provider: ProviderInfo;
}
class NexaClient {
constructor(config?: NexaClientConfig);
// 网络调用
call(options: CallOptions): Promise<CallResult>;
callStream(options: CallOptions): AsyncIterable<StreamResult>;
// 能力管理
registerCapability(capability: Capability): Promise<string>;
unregisterCapability(endpointId: string): Promise<boolean>;
listCapabilities(): Promise<Capability[]>;
// 通道管理
openChannel(peerDid: string, deposit: number): Promise<Channel>;
closeChannel(channelId: string): Promise<Settlement>;
listChannels(): Promise<Channel[]>;
// 余额管理
getBalance(): Promise<Balance>;
getBalanceHistory(options?: HistoryOptions): Promise<BalanceChange[]>;
// 身份管理
getIdentity(): Promise<Identity>;
rotateKey(): Promise<KeyRotation>;
// 关闭
close(): Promise<void>;
}# Cargo.toml
[dependencies]
nexa-net = "1.0.0"
tokio = { version = "1", features = ["full"] }use nexa_net::{NexaClient, Capability, CostModel};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 初始化客户端
let client = NexaClient::new("~/.nexa/config.yaml").await?;
// 发起网络调用
let result = client.call(
"translate English PDF to Chinese",
std::fs::read("document.pdf")?,
Some(50), // max_budget
).await?;
println!("Result: {:?}", result.data);
println!("Cost: {} NEXA", result.cost);
// 注册能力
let capability = Capability {
endpoint_id: "analyze_sentiment".to_string(),
name: "Sentiment Analysis".to_string(),
description: "Analyze sentiment of text".to_string(),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"text": { "type": "string" }
}
}),
output_schema: serde_json::json!({
"type": "object",
"properties": {
"sentiment": { "type": "string" },
"confidence": { "type": "number" }
}
}),
cost: CostModel {
model: "per_call".to_string(),
base_price: 5,
},
};
client.register_capability(capability).await?;
Ok(())
}use nexa_net::discovery::{Embedder, VectorizerBuilder};
use std::path::PathBuf;
// 创建 Vectorizer
let vectorizer = VectorizerBuilder::new()
.mock(384) // Mock embedder
.build()?;
// 或使用 ONNX
let vectorizer = VectorizerBuilder::new()
.onnx(PathBuf::from("models/model.onnx"), 512)
.build()?;
// 向量化文本
let vector = vectorizer.vectorize("translate English to Chinese")?;
let batch = vectorizer.vectorize_batch(&["text1", "text2"])?;
// 获取信息
println!("Dimensions: {}", vectorizer.dimensions());
println!("Model: {}", vectorizer.model_name());use nexa_net::storage::MemoryStore;
use nexa_net::types::CapabilitySchema;
let store = MemoryStore::default_store();
// 存储能力
store.register_capability(schema).await?;
// 查询能力
let cap = store.get_capability("did:nexa:service").await?;
let caps = store.list_capabilities().await?;
let by_tags = store.find_capabilities_by_tags(&["nlp".to_string()]).await?;
// 缓存操作
store.cache_set("key", serde_json::json!({"data": "value"})).await?;
let cached = store.cache_get("key").await?;
// 统计
let stats = store.stats().await;use nexa_net::security::{
AuditLogger, KeyRotator, KeyRotationPolicy,
RateLimiter, RateLimitConfig, RateLimitKey,
SecureKeyStorage,
};
// 审计日志
let audit = AuditLogger::with_logging();
audit.log_auth_success("did:nexa:user", AuthMethod::Signature, None)?;
// 密钥轮换
let rotator = KeyRotator::new(KeyRotationPolicy::default());
rotator.register_key("key-1", "signing").await?;
if rotator.needs_rotation("key-1").await? {
rotator.mark_rotated("key-1").await?;
}
// 速率限制
let limiter = RateLimiter::new(RateLimitConfig::default());
let key = RateLimitKey::Did("did:nexa:user".to_string());
match limiter.check(&key).await? {
RateLimitResult::Allowed => { /* 处理 */ }
RateLimitResult::Denied { reason, retry_after } => { /* 拒绝 */ }
}
// 加密存储
let storage = SecureKeyStorage::new(Some(encryption_key));
storage.store_key("key-1", "signing", key_data, None).await?;
let (data, meta) = storage.get_key("key-1").await?.unwrap();| 错误码范围 | 类别 | 示例 |
|---|---|---|
1xxx |
网络错误 | 1001 连接超时 |
2xxx |
身份错误 | 2001 DID 无效 |
3xxx |
路由错误 | 3001 无匹配服务 |
4xxx |
传输错误 | 4001 协议协商失败 |
5xxx |
经济错误 | 5001 余额不足 |
6xxx |
业务错误 | 6001 参数无效 |
7xxx |
系统错误 | 7001 内部错误 |
{
"error": {
"code": "3001",
"name": "NO_MATCHING_SERVICE",
"message": "No service found matching the intent",
"details": {
"intent": "translate English PDF to Chinese",
"similarity_threshold": 0.7,
"best_match_score": 0.45
},
"retryable": false,
"documentation_url": "https://docs.nexa-net.io/errors/3001"
},
"request_id": "req-abc123",
"timestamp": "2026-03-30T07:00:00Z"
}from nexa_net import NexaClient, NexaError, NoMatchingServiceError
async def safe_call():
client = NexaClient()
try:
result = await client.call(
intent="translate document",
data=document_bytes
)
return result
except NoMatchingServiceError as e:
print(f"No service found: {e.message}")
# 尝试降低要求或使用备用方案
except InsufficientBalanceError as e:
print(f"Insufficient balance: {e.details['required']} NEXA needed")
# 提示用户充值
except NexaError as e:
print(f"Nexa-net error: {e.code} - {e.message}")
# 通用错误处理
except Exception as e:
print(f"Unexpected error: {e}")
# 其他错误- 整体架构设计 - 四层架构总览
- 身份与零信任网络层 - 身份 API 设计
- 语义发现与能力路由层 - 路由 API 设计
- 传输与协商协议层 - 传输 API 设计
- 资源管理与微交易层 - 经济 API 设计
新增 7 个 REST API 端点(基于 Axum),对应 src/api/rest.rs:
| 端点 | 方法 | 功能 |
|---|---|---|
/v1/call |
POST | 发起网络调用 |
/v1/register |
POST | 注册本地能力 |
/v1/discover |
POST | 按意图发现能力 |
/v1/channels |
GET | 列出开放通道 |
/v1/balance/:did |
GET | 查询 DID 余额 |
/v1/status |
GET | Proxy 状态 |
/v1/health |
GET | 健康检查 |
基于 tonic_health 实现标准 gRPC Health Checking Protocol,监听 localhost:7071。
参见 src/api/grpc.rs。
新增 TestProxy 和 MockNetwork (tests/common/mod.rs),用于 REST API 端到端测试:
TestProxy — 轻量级 HTTP 测试服务器:
- 基于
TcpListener::bind("127.0.0.1:0")随机端口 +RestServer::build_router()+axum::serve().with_graceful_shutdown() - 支持直接内部操作(
register_capability,open_channel)和 HTTP 操作(health,discover,register,call,status) - 自动配置 SemanticRouter 为测试模式(min_similarity=-1.0, min_quality=0.0)
MockNetwork — 模拟网络拓扑:
- 创建 N 个 TCP listener 端点模拟真实网络节点
- 支持
mark_unavailable/mark_available模拟节点故障和恢复 - 用于故障恢复和容错 E2E 测试场景
HTTP E2E 测试 (tests/e2e_http_test.rs):
- 注册 → 发现 → 通道 → 预算 → 状态 全链路验证
- 5 个测试场景,运行时间 < 1.5s
新增 api_benches Criterion 组 (benches/nexa_bench.rs):
| 基准 | 均值延迟 | 说明 |
|---|---|---|
api/rest_health |
1.2 ms | GET /v1/health |
api/rest_register |
1.3 ms | POST /v1/register |
api/rest_discover |
1.4 ms | POST /v1/discover |
使用与 TestProxy 相同的服务器 setup 模式(随机端口 + axum serve + oneshot shutdown)。
新增 Rust SDK (src/api/sdk.rs),提供 NexaClient 和 NexaClientBuilder,
支持 call(), register(), discover(), list_channels(), get_balance() 等方法。