# AgentLiving - 技术规格文档 ## 1. Godot 项目结构 ``` ai-agent-living/ ├── assets/ │ ├── sprites/ │ │ ├── val/ │ │ │ ├── idle.png │ │ │ ├── walk.png │ │ │ └── interact.png │ │ └── furniture/ │ │ ├── sofa.png │ │ ├── fridge.png │ │ └── bed.png │ ├── tilesets/ │ │ └── apartment_floor.tres │ └── audio/ │ └── ambient.mp3 ├── scenes/ │ ├── main.tscn │ ├── apartment.tscn │ ├── val.tscn │ └── furniture/ │ ├── sofa.tscn │ └── fridge.tscn ├── scripts/ │ ├── val.gd │ ├── apartment.gd │ ├── bridge_client.gd │ └── state_manager.gd └── project.godot ``` ## 2. 关键类设计 ### 2.1 Val (CharacterBody2D) ```gdscript class_name Val extends CharacterBody2D @export var speed: float = 100.0 @onready var sprite: AnimatedSprite2D = $AnimatedSprite2D @onready var thought_bubble: Label = $ThoughtBubble var current_state: String = "idle" var target_position: Vector2 = Vector2.ZERO var agent_id: String = "val" func _ready(): BridgeClient.connect("action_received", _on_action) _connect_to_openclaw() func _physics_process(delta): match current_state: "walk": _handle_walk(delta) "interact": _handle_interact(delta) "think": _handle_think(delta) _: _handle_idle(delta) func move_to(pos: Vector2): target_position = pos current_state = "walk" sprite.play("walk") func _on_action(action: Dictionary): match action.cmd: "walk_to": move_to(Vector2(action.pos[0], action.pos[1])) "play_anim": sprite.play(action.anim) "show_thought": _show_thought(action.text) "update_state": _update_internal_state(action.key, action.value) ``` ### 2.2 BridgeClient (WebSocket) ```gdscript extends Node signal action_received(action: Dictionary) signal state_synced(state: Dictionary) var socket: WebSocketPeer var openclaw_url: String = "ws://127.0.0.1:18789" func _ready(): _connect() func _connect(): socket = WebSocketPeer.new() socket.connect_to_url(openclaw_url) func _process(delta): socket.poll() var state = socket.get_ready_state() if state == WebSocketPeer.STATE_OPEN: while socket.get_available_packets() > 0: var packet = socket.get_packet() var message = JSON.parse_string(packet.get_string_from_utf8()) _handle_message(message) func send_command(command: Dictionary): if socket.get_ready_state() == WebSocketPeer.STATE_OPEN: socket.send_text(JSON.stringify(command)) func _handle_message(msg: Dictionary): match msg.type: "action_sequence": for action in msg.actions: action_received.emit(action) "state_sync": state_synced.emit(msg.state) ``` ## 3. OpenClaw端集成 ### 3.1 AgentLiving Skill 创建 `~/.openclaw/skills/agent-living/`: ``` agent-living/ ├── SKILL.md ├── scripts/ │ └── bridge_server.py └── config.json ``` ### 3.2 Bridge Server (Python) ```python # bridge_server.py import asyncio import websockets import json from openclaw import session_manager class AgentLivingBridge: def __init__(self): self.agents = {} self.godot_clients = {} async def handle_godot(self, websocket, path): """处理Godot客户端连接""" async for message in websocket: data = json.loads(message) response = await self._process_command(data) await websocket.send(json.dumps(response)) async def _process_command(self, cmd: dict) -> dict: """将Godot指令转换为Agent动作""" if cmd["type"] == "user_command": # 调用OpenClaw Agent处理 agent_session = session_manager.get("val") result = await agent_session.send_message( f"用户在Godot中发出指令:{cmd}" ) return self._parse_agent_response(result) def _parse_agent_response(self, response: str) -> dict: """解析Agent回复为Godot动作序列""" # 提取动作序列,格式化为Godot可执行的JSON actions = [] # ... 解析逻辑 return {"type": "action_sequence", "actions": actions} # 启动服务器 async def main(): bridge = AgentLivingBridge() async with websockets.serve( bridge.handle_godot, "localhost", 8765 ): await asyncio.Future() # 永久运行 if __name__ == "__main__": asyncio.run(main()) ``` ## 4. 状态同步策略 ### 4.1 心跳机制 - Godot每5秒发送状态查询 - OpenClaw立即返回完整状态 - 差异超过阈值时触发同步 ### 4.2 事件驱动 - Agent状态变化 → 立即推送到Godot - 用户交互 → 立即发送到Agent - 避免轮询开销 ## 5. 性能优化 ### 5.1 Agent端 - 简单行为(走动、idle)用本地规则 - 复杂决策(任务分解)才调用LLM - 缓存常用响应 ### 5.2 Godot端 - 对象池复用粒子效果 - 远处角色降低动画帧率 - 按需加载房间(视野外不渲染) --- **下一步:** Week 1 开始Godot场景搭建