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 个文件只为了包装一行函数调用。
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.sh。bash -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 |
LLMExperimentSandbox | execute_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