# 拆解 OLAV v0.12→v0.13:从 12 个生成文件到 1 个通用工具的架构演进

0 阅读3分钟

v0.12 和 v0.13 两个版本,我们把 OLAV 从"网络查询工具"重构为"完整基础设施自动化平台"。本文用代码说话,拆解三个核心架构决策。

1. api_request:一个工具替代十二个

v0.12 架构(旧):

OpenAPI schema → 代码生成器 → 12+ 个 Python @tool 文件 → agent 调工具 → 工具内调 service_call()

每个 @tool 本质就是 service_call("netbox", "GET", "/api/dcim/devices/") 的薄封装。我们生成了 12 个文件只为了包装一行函数调用。

artistic-1.webp v0.13 架构(新):

# core/tools/api_request.py — 一个工具,适用于所有服务
@tool
def api_request(
    service: str,        # "netbox", "influxdb", "gitea"
    method: str = "GET",
    path: str = "/",
    params: dict = None,
    body: dict = None,
    confirmed: bool = False,   # HITL 确认后传 True
    page_size: int = None,     # -1 = 全量分页
) -> dict | list:
    # 写操作门控
    if method.upper() in _WRITE_METHODS:
        if not os.environ.get("OLAV_ENABLE_API_WRITE"):
            return {"status": "blocked", "reason": "Use --enable-api-write"}
    
    return service_call(service, method, path, confirmed=confirmed, ...)

注册服务后(olav registry register http://netbox:8000),生成的不是 Python 代码,而是 API reference markdown。Agent 读 markdown 知道 endpoint 结构,用 api_request 发请求。

实际效果:

olav --agent infra "对比 OLAV 数据库和 NetBox 的设备清单"
# agent 自动选择:
#   execute_sql("SELECT * FROM netops.devices")     ← 查本地
#   api_request(service="netbox", path="/api/dcim/devices/")  ← 查 NetBox
#   → 输出逐设备 diff 表

2. DevOps Agent:环境感知的代码生成

关键区别不是"能写代码"(ChatGPT 也能),而是"知道你的环境"。

olav --agent devops "写一个脚本备份所有路由器的 running-config"

Agent 先查 DB:

SELECT hostname, ip_address, platform FROM netops.devices
-- R1  192.168.100.101  juniper_junos
-- R2  192.168.100.102  cisco_ios
-- R3  192.168.100.103  cisco_ios
-- ...

然后生成 158 行 bash 脚本(实际输出,非模板):

#!/bin/bash
set -euo pipefail

readonly DEVS=(
  "R1 192.168.100.101 juniper_junos"
  "R2 192.168.100.102 cisco_ios"
  "R3 192.168.100.103 cisco_ios"
  "R4 192.168.100.104 cisco_ios"
  "SW1 192.168.100.105 cisco_ios"
  "SW2 192.168.100.106 cisco_ios"
)

backup_cisco() {
  # show running-config via expect + SSH
  ...
}
backup_juniper() {
  # show configuration via expect + SSH  
  ...
}

# 平台感知:Cisco 用 backup_cisco,Juniper 用 backup_juniper
for entry in "${DEVS[@]}"; do
  read -r hostname ip platform <<< "$entry"
  case "$platform" in
    cisco_ios)  backup_cisco "$hostname" "$ip" ;;
    juniper_*)  backup_juniper "$hostname" "$ip" ;;
  esac
done

输出到 exports/scripts/backup-running-configs.shbash -n 语法验证通过。

3. sandbox_guard hard_block:写操作的内核级防线

# sandbox_guard.py — network_isolation=True 时 HTTP 写不可批准
def scan_sandbox_code(code: str, *, network_isolation: bool = False):
    for reason, pattern in _SCAN_RULES:
        if pattern.search(code):
            if network_isolation and "HTTP mutation" in reason:
                return ApprovalResult(
                    requires_approval=True,
                    hard_block=True,  # ← 不可绕过,即使 --dangerously-skip-permissions
                    reason=f"HARD BLOCK: {reason}")
            return ApprovalResult(requires_approval=True, reason=reason)

运行时验证:

>>> execute_in_sandbox('httpx.post("http://api/config")', network_isolation=True)
{'status': 'hard_block', 'reason': 'HARD BLOCK: HTTP mutation via httpx — network_isolation=True'}
# 代码没有执行,在静态扫描阶段就被拦截

删掉了什么

删除替代
Creator Agent(8 个工具)olav registry register 一条命令
_generated/*.py(12+ 文件/服务)api_request + reference markdown
netbox/netbox-circuits/influxdb 独立 workspace(4 个)统一 infra agent
LLMExperimentSandboxexecute_in_sandbox()(platform sandbox)

架构对比

v0.12: 每个 API → 生成 Python 代码 → 注册到 workspace → agent 调用
v0.13: 每个 API → 生成 reference markdown → agent 直接用 api_request

v0.12: 脚本 = LLM 猜测你的环境
v0.13: 脚本 = 先查 DB 再写代码(真实 IP、真实设备名)

v0.12: 写安全 = HITL 审批(可绕过)
v0.13: 写安全 = 7 层纵深(默认锁死 + dry-run 必须通过 + 审批不可绕过)

详细博客: olavai.com/blog/olav-v013 | GitHub: github.com/olav-ai/olav