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):

WebSocket帧结构:

帧类型
负载

HEARTBEAT

{agent_id, timestamp}

TASK

{task_id, description, ...}

ACTION

{action_type, tool_call}

RESULT

{action_id, result_data}

CONTROL

{command: pause/resume/stop}

特点:

  • 长连接保证高实时性

  • 帧类型的设计明确了各种通信场景

  • Heartbeat机制支持长期运行的Agent

2.4.5 版本控制和向后兼容性

当Harness系统演进时,接口的向后兼容性变得重要。

2.4.6 总结

良好的接口设计包括:

  1. 统一的消息格式:所有层间通信都使用结构化的消息

  2. 工具调用协议:标准化的请求和响应格式

  3. 事件流规范:异步通信的统一事件定义

  4. 版本控制:为系统演进预留向后兼容的机制

这些接口的清晰定义,使得Harness系统的各个组件可以独立开发和测试,同时保持整体的一致性。

最后更新于