2.4 层间接口设计
良好的接口设计是模块化系统的基础。本节讨论 Harness 系统中各层之间的通信接口,包括消息格式、工具调用协议、事件流规范等。
2.4.1 统一的消息格式
Harness 系统中流动的核心数据对象是消息(Message)。无论是智能体与 LLM 的通信,还是运行时引擎与工具层的通信,都通过结构化的消息传递。
消息的通用结构
消息对象是系统内部通信的基本单位,其定义如下:
from typing import Optional, Any, Literal
from datetime import datetime
from enum import Enum
import uuid
class MessageRole(str, Enum):
"""消息的角色"""
USER = "user"
ASSISTANT = "assistant"
TOOL = "tool"
SYSTEM = "system"
class MessageType(str, Enum):
"""消息的类型"""
TEXT = "text"
TOOL_CALL = "tool_call"
TOOL_RESULT = "tool_result"
FUNCTION_CALL = "function_call"
EVENT = "event"
class Message:
"""通用消息基类"""
def __init__(
self,
role: MessageRole,
type: MessageType,
content: str,
message_id: str = None,
parent_id: Optional[str] = None,
metadata: dict = None,
timestamp: datetime = None
):
self.message_id = message_id or str(uuid.uuid4())
self.role = role
self.type = type
self.content = content
self.parent_id = parent_id
self.metadata = metadata or {}
self.timestamp = timestamp or datetime.now()
def to_dict(self) -> dict:
"""转换为字典,便于序列化"""
return {
"message_id": self.message_id,
"role": self.role.value,
"type": self.type.value,
"content": self.content,
"parent_id": self.parent_id,
"metadata": self.metadata,
"timestamp": self.timestamp.isoformat()
}
@classmethod
def from_dict(cls, data: dict) -> "Message":
"""从字典反序列化"""
return cls(
role=MessageRole(data["role"]),
type=MessageType(data["type"]),
content=data["content"],
message_id=data.get("message_id"),
parent_id=data.get("parent_id"),
metadata=data.get("metadata", {}),
timestamp=datetime.fromisoformat(data["timestamp"])
)工具调用消息
当智能体决定调用一个工具时,它发送一个TOOL_CALL类型的消息:
工具结果消息
当工具执行完成后,返回一个TOOL_RESULT类型的消息:
2.4.2 工具调用协议
工具调用协议定义了模型工具意图、运行时调度和工具执行器之间如何通信。Agent 不直接绕过运行时调用工具;运行时负责验证、权限、审计和结果回传。
调用请求的标准格式
Agent 输出工具调用意图时使用的请求格式定义如下:
调用响应的标准格式
工具执行完毕后返回的响应格式定义如下:
2.4.3 事件流规范
Harness 系统内部通过事件流进行异步通信。这允许不同的子系统在解耦的状态下协作。
事件的通用结构
事件是系统内部异步通信的基本单位,其结构定义如下:
事件订阅系统
事件总线实现发布-订阅模式,允许多个订阅者监听特定事件:
事件驱动的架构示例
以下是一个完整的事件驱动架构使用示例,展示了多个子系统如何通过事件进行协作:
2.4.4 三大参考系统的接口对比
三个参考系统在接口设计上体现了不同语言和架构范式的取舍。
OpenAI Codex 的接口设计
Codex 使用 Rust 的 trait 和 enum 定义接口,通过类型系统在编译期保证安全性:
特点:
Rust 的所有权系统和
Result类型保证内存安全和错误处理的完备性execpolicy 通过 Starlark DSL 定义规则,与 Rust 核心解耦
MCP 工具和内置技能共享统一的调用接口
Claude Code 的接口设计
Claude Code 使用 TypeScript 的类型系统定义接口,确保编译时的类型安全:
特点:
类型安全的接口定义
支持流式处理(streaming)
灵活的内容块(ContentBlock)设计
OpenClaw 的接口设计
OpenClaw 使用 WebSocket 协议进行通信,消息格式基于帧(Frame)。官方协议只定义了三种 RPC 风格的帧类型:
WebSocket 帧结构(官方协议):
Request
{type:"req", id, method, params}
客户端发起操作
Response
{type:"res", id, ok, payload|error}
服务端确认请求结果
Event
{type:"event", event, payload, seq?, stateVersion?}
服务端异步推送(心跳即属于事件族)
特点:
长连接保证高实时性
极简的 req/res/event 三类帧覆盖所有通信场景,具体语义由
method/event字段表达Heartbeat 以事件形式推送,支持长期运行的 Agent
2.4.5 版本控制和向后兼容性
当 Harness 系统演进时,接口的向后兼容性变得重要。
2.4.6 总结
良好的接口设计包括:
统一的消息格式:所有层间通信都使用结构化的消息
工具调用协议:标准化的请求和响应格式
事件流规范:异步通信的统一事件定义
版本控制:为系统演进预留向后兼容的机制
这些接口的清晰定义,使得 Harness 系统的各个组件可以独立开发和测试,同时保持整体的一致性。
最后更新于
