第79章 自定义 Renderer
第61章建立了 Renderer 的基本概念:
Expression
↓
Template
↓
Renderer
↓
Rendered Result
↓
Adapter
↓
External Environment
第62章的 WebRenderer、第63章的 ApiRenderer,则说明了 Renderer 可以针对不同输出环境进行具体实现。
因此,自定义 Renderer 的作用是:
根据具体表现环境和输出要求,将 ICAI 已经形成的结构化 Expression 按确定规则转换成目标表现格式。
Renderer 不负责:
- 感知
- 认知
- 理解
- 推理
- 决策
- 学习
- 生成新的知识
它只负责表现转换。
1. Renderer Interface
Renderer Interface 是所有 Renderer 遵循的统一接口。
基本定义:
interface RendererInterface
{
public function getId();
public function getName();
public function getVersion();
public function supports($type);
public function render($expression, $template = null);
public function getState();
}
这样不同 Renderer 都可以被统一管理。
例如:
WebRenderer
ApiRenderer
DeviceRenderer
UiRenderer
JsonRenderer
XmlRenderer
CustomRenderer
统一形成:
RendererInterface
↓
具体 Renderer
Interface 的职责
Interface 规定:
Renderer
├── Identity
├── Version
├── Supported Type
├── Render
└── State
但是不规定具体表现形式。
例如:
WebRenderer
→ HTML
ApiRenderer
→ JSON
DeviceRenderer
→ Device Data
CustomRenderer
→ 自定义格式
因此:
RendererInterface
= 统一标准
Renderer
= 具体表现转换
Adapter
= 输出连接
2. 创建 Renderer
创建自定义 Renderer 首先要明确:
输入是什么?
输出是什么?
转换规则是什么?
例如创建:
StatusRenderer
它负责把系统中的状态 Expression 转换为简单的状态结构。
输入:
Expression
{
type: "STATE",
target: "Motor_A",
data: {
state: "RUNNING",
temperature: 65
}
}
输出:
{
"device": "Motor_A",
"state": "RUNNING",
"temperature": 65
}
创建:
class StatusRenderer implements RendererInterface
{
protected $state = 'READY';
public function getId()
{
return 'status';
}
public function getName()
{
return 'Status Renderer';
}
public function getVersion()
{
return '1.0.0';
}
public function supports($type)
{
return $type === 'STATE';
}
public function render($expression, $template = null)
{
if (!is_array($expression)) {
$this->state = 'ERROR';
return array(
'state' => 'FAILED',
'error' => 'Invalid expression'
);
}
if (!$this->supports(
isset($expression['type'])
? $expression['type']
: null
)) {
$this->state = 'ERROR';
return array(
'state' => 'FAILED',
'error' => 'Unsupported expression type'
);
}
$this->state = 'RUNNING';
$data = isset($expression['data'])
? $expression['data']
: array();
$result = array(
'device' => isset($expression['target'])
? $expression['target']
: null,
'state' => isset($data['state'])
? $data['state']
: 'UNKNOWN',
'temperature' => isset($data['temperature'])
? $data['temperature']
: null
);
$this->state = 'READY';
return array(
'state' => 'SUCCESS',
'output' => $result
);
}
public function getState()
{
return $this->state;
}
}
这个 Renderer 的工作非常明确:
STATE Expression
↓
StatusRenderer
↓
Status Output
3. Renderer 注册
Renderer 创建后,需要进入 Renderer Manager。
可以建立:
class RendererManager
{
protected $renderers = array();
public function register(RendererInterface $renderer)
{
$id = $renderer->getId();
$this->renderers[$id] = $renderer;
return true;
}
public function get($id)
{
if (!isset($this->renderers[$id])) {
return null;
}
return $this->renderers[$id];
}
public function render(
$id,
$expression,
$template = null
) {
$renderer = $this->get($id);
if (!$renderer) {
return array(
'state' => 'FAILED',
'error' => 'Renderer not found'
);
}
return $renderer->render(
$expression,
$template
);
}
}
注册:
$manager = new RendererManager();
$renderer = new StatusRenderer();
$manager->register($renderer);
形成:
RendererManager
↓
status
↓
StatusRenderer
Renderer Registry
如果需要持久化管理,还可以建立 Renderer Registry:
RendererRegistry
{
id
name
class
version
path
supported_types
state
enabled
}
例如:
{
"id": "status",
"name": "Status Renderer",
"class": "StatusRenderer",
"version": "1.0.0",
"path": "renderers/StatusRenderer.php",
"supported_types": [
"STATE"
],
"state": "REGISTERED",
"enabled": true
}
因此:
Registry
= 记录 Renderer
Manager
= 管理 Renderer
Renderer
= 执行表现转换
4. Expression 转换
Renderer 的核心就是:
Expression
↓
Render
↓
Rendered Result
例如 ICAI 已经形成:
Expression
{
id: 2001,
type: "STATE",
target: "Motor_A",
data: {
state: "RUNNING",
temperature: 65
}
}
Renderer 不应该重新判断:
Motor_A 是否应该运行?
这个问题已经由:
Reasoning
Decision
Behavior
Action
完成。
Renderer 只负责:
STATE
+
Motor_A
+
RUNNING
+
65
转换为目标表现结构。
例如:
{
"device": "Motor_A",
"state": "RUNNING",
"temperature": 65
}
所以:
Expression
= 表现什么
Renderer
= 转换成什么表现格式
Expression → Renderer
完整过程:
Expression
↓
Validate
↓
Check Type
↓
Check Supported
↓
Extract Data
↓
Apply Render Rules
↓
Build Output
↓
Rendered Result
如果 Expression 类型不支持:
Expression.type = ACTION
而:
StatusRenderer
supports = STATE
则不能继续转换:
StatusRenderer
↓
UNSUPPORTED
不能为了得到结果而强行解释。
5. 输出结果
Renderer 输出应该形成明确的 Rendered Result。
例如:
RenderedResult
{
id
renderer_id
expression_id
type
output
format
state
error
created_at
}
例如:
{
"id": 5001,
"renderer_id": "status",
"expression_id": 2001,
"type": "STATE",
"output": {
"device": "Motor_A",
"state": "RUNNING",
"temperature": 65
},
"format": "STATUS",
"state": "SUCCESS",
"error": null
}
Renderer 输出失败
例如 Expression 缺少必要数据:
Expression
{
type: "STATE",
target: "Motor_A"
}
如果 Renderer 要求:
data.state
则应该返回:
RenderedResult
{
state: "FAILED",
error: "State data is required"
}
不能自行补充:
state = RUNNING
因为这个状态并没有来自 Expression 的依据。
这也是 ICAI 表现层的重要原则:
Renderer 可以转换已有数据,但不能凭空增加未经确定的信息。
6. 自定义 Renderer 实例
下面建立一个更加完整的:
DeviceStatusRenderer
它把 ICAI 的 Device State Expression 转换成统一的设备状态 JSON 数据结构。
6.1 输入 Expression
Expression
{
id: 3001,
type: "DEVICE_STATE",
target: "Motor_A",
data: {
state: "RUNNING",
speed: 50,
temperature: 65
}
}
6.2 Renderer
class DeviceStatusRenderer implements RendererInterface
{
protected $state = 'READY';
public function getId()
{
return 'device_status';
}
public function getName()
{
return 'Device Status Renderer';
}
public function getVersion()
{
return '1.0.0';
}
public function supports($type)
{
return $type === 'DEVICE_STATE';
}
public function render($expression, $template = null)
{
if (!is_array($expression)) {
$this->state = 'ERROR';
return array(
'state' => 'FAILED',
'error' => 'Invalid expression'
);
}
$type = isset($expression['type'])
? $expression['type']
: null;
if (!$this->supports($type)) {
$this->state = 'ERROR';
return array(
'state' => 'FAILED',
'error' => 'Unsupported expression type'
);
}
if (!isset($expression['target'])) {
$this->state = 'ERROR';
return array(
'state' => 'FAILED',
'error' => 'Target is required'
);
}
$data = isset($expression['data'])
? $expression['data']
: array();
if (!isset($data['state'])) {
$this->state = 'ERROR';
return array(
'state' => 'FAILED',
'error' => 'Device state is required'
);
}
$this->state = 'RUNNING';
$output = array(
'device_id' => $expression['target'],
'state' => $data['state'],
'properties' => array(
'speed' => isset($data['speed'])
? $data['speed']
: null,
'temperature' => isset($data['temperature'])
? $data['temperature']
: null
)
);
$this->state = 'READY';
return array(
'state' => 'SUCCESS',
'format' => 'JSON',
'output' => $output,
'error' => null
);
}
public function getState()
{
return $this->state;
}
}
6.3 注册 Renderer
$rendererManager = new RendererManager();
$deviceStatusRenderer = new DeviceStatusRenderer();
$rendererManager->register(
$deviceStatusRenderer
);
6.4 调用 Renderer
$expression = array(
'id' => 3001,
'type' => 'DEVICE_STATE',
'target' => 'Motor_A',
'data' => array(
'state' => 'RUNNING',
'speed' => 50,
'temperature' => 65
)
);
$result = $rendererManager->render(
'device_status',
$expression
);
得到:
RenderedResult
{
state: "SUCCESS",
format: "JSON",
output: {
device_id: "Motor_A",
state: "RUNNING",
properties: {
speed: 50,
temperature: 65
}
}
}
自定义 Renderer 与完整 SAI 流程
现在把第61~79章连接起来:
Decision
↓
Behavior
↓
Action
↓
ActionResult
↓
Expression
↓
SATE
↓
Template
↓
Custom Renderer
↓
Rendered Result
↓
Adapter
↓
External Environment
如果只是向外表现信息:
Expression
↓
SATE
↓
Custom Renderer
↓
Rendered Result
↓
Output
如果需要连接外部环境:
Rendered Result
↓
Adapter
↓
External System / Device
而外部环境返回:
Device / System
↓
Response
↓
Adapter
↓
Feedback
↓
Information
↓
Perception
于是形成:
Expression
↓
Renderer
↓
Adapter
↓
External Environment
↓
Feedback
↓
ICAI
Renderer 与 Adapter 的最终边界
这两个组件容易混淆,但职责完全不同:
Expression
↓
Renderer
↓
Rendered Result
↓
Adapter
↓
External Environment
Renderer:
“我要把数据表现成什么形式?”
Adapter:
“我要把这个结果连接到什么环境?”
例如:
Expression
↓
ApiRenderer
↓
JSON
↓
ApiAdapter
↓
External API
或者:
Expression
↓
DeviceRenderer
↓
Device Data
↓
DeviceAdapter
↓
Motor_A
所以:
Renderer = 表现转换
Adapter = 环境连接
本章核心模型
RendererInterface
↓
Create Renderer
↓
Register
↓
RendererManager
↓
Expression
↓
Validate
↓
Supports Check
↓
Render
↓
RenderedResult
↓
Output / Adapter
完整扩展体系:
Extension
├── Custom Engine
│ ↓
│ EngineResult
│
├── Custom Renderer
│ ↓
│ RenderedResult
│
└── Custom Adapter
↓
External Environment
最终形成:
ICAI Core
│
├── Engine
│ └── 内部功能执行
│
├── Renderer
│ └── 表现形式转换
│
└── Adapter
└── 外部环境连接
本章核心定义
Renderer Interface:
Renderer Interface 是规定 Renderer 身份、版本、支持类型、表现转换和状态管理行为的统一接口。
Custom Renderer:
自定义 Renderer 是按照 Renderer Interface 创建,用于将特定 Expression 按确定规则转换为指定表现格式的独立组件。
Rendered Result:
Rendered Result 是 Renderer 对 Expression 完成表现转换后形成的结构化结果。
核心关系:
Expression
↓
Renderer
↓
Rendered Result
再与前面的 Adapter 连接:
Expression
↓
SATE
↓
Custom Renderer
↓
Rendered Result
↓
Custom Adapter
↓
External Environment
因此,第76~79章形成了一个完整的扩展体系:
Extension
├── Engine
│ → 执行内部功能
│
├── Renderer
│ → 转换外部表现
│
└── Adapter
→ 连接外部环境
三者互不替代,分别解决:
Engine = 怎么处理
Renderer = 怎么表现
Adapter = 怎么连接
这使 ICAI 可以在保持核心结构稳定的情况下,通过标准接口不断增加内部处理能力、表现能力和外部连接能力。