Pie / Donut · 饼图 / 环形图#donut#leader-callout#small-multiples#category-palette
GenericAgent · Three donut charts of tool-call distribution per agent
GenericAgent · 三 agent 工具调用分布甜甜圈饼图
Reproduction of GenericAgent Figure 3. Three donut (hollow pie) charts, one per agent system (Claude Code / OpenClaw / GenericAgent), summarising the proportion of tool calls attributed to each major tool category. Tiny slices (<1%) are externalised with leader-line callouts; larger slices carry a centred percent label. A two-column legend sits below each donut.
GenericAgent Figure 3 复现。三个甜甜圈(中空饼图),分别对应 Claude Code / OpenClaw / GenericAgent,展示各 agent 系统主要工具的调用占比。<1% 的极小切片用引线标注外置,较大切片在切片中心显示百分比。每个甜甜圈下方有两列图例。
@paper · 来自论文
GenericAgent: A Token-Efficient Self-Evolving LLM Agent via Contextual Information Density Maximization
GenericAgent:基于上下文信息密度最大化的高效自进化 LLM Agent
Advantage AI Agent Lab (Shenzhen Aquaintelling & Fudan University) · arXiv 2026
// original from paper · 论文原图

// reproduced via genericagent_tool_donut.py · 脚本复现download png

genericagent_tool_donut.py
"""GenericAgent · Three donut (pie) charts of tool-usage distribution.
Reproduction of GenericAgent Figure 3 (Tool usage distribution across
Claude Code, OpenClaw, and GenericAgent).
Source: GenericAgent: A Token-Efficient Self-Evolving LLM Agent via
Contextual Information Density Maximization, arXiv:2604.17091.
Each donut summarises the proportion of tool calls attributed to each
major tool category in the corresponding agent system. The hollow centre
keeps the layout light; tiny slices have leader-line callouts.
"""
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams.update({
"font.family": "sans-serif",
"font.sans-serif": ["DejaVu Sans", "Arial"],
})
PALETTE = ["#A8D0E6", "#3F88C5", "#A6D8A8", "#5DAE5D",
"#F4D58D", "#EFAB6E", "#9C9C9C"]
CLAUDE_CODE = {
"title": "Claude Code",
"labels": ["AgentTool", "BashTool", "FileReadTool", "FileWriteTool",
"WebFetchTool", "WebSearchTool", "others(47)"],
"values": [50.4, 22.1, 10.6, 8.9, 7.1, 0.9, 0.0],
}
OPENCLAW = {
"title": "OpenClaw",
"labels": ["browser", "web_fetch", "exec", "read",
"write", "process", "others(16)"],
"values": [32.5, 15.7, 20.5, 14.5, 9.6, 7.2, 0.0],
}
GENERICAGENT = {
"title": "GenericAgent",
"labels": ["file_read", "file_write", "code_run", "web_scan",
"web_execute_js", "update_working_checkpoint", "others(2)"],
"values": [31.2, 3.1, 34.4, 17.2, 10.9, 0.0, 3.1],
}
CHARTS = [CLAUDE_CODE, OPENCLAW, GENERICAGENT]
fig, axes = plt.subplots(1, 3, figsize=(13, 5.2))
def draw_donut(ax, data):
sizes = [v if v > 0 else 1e-3 for v in data["values"]]
wedges, _ = ax.pie(
sizes,
startangle=90,
counterclock=False,
colors=PALETTE[: len(sizes)],
wedgeprops=dict(width=0.36, edgecolor="white", linewidth=1.2),
)
for w, label, v in zip(wedges, data["labels"], data["values"]):
ang = (w.theta2 + w.theta1) / 2.0
x = np.cos(np.deg2rad(ang))
y = np.sin(np.deg2rad(ang))
if v < 1.0:
xt = 1.25 * x
yt = 1.25 * y
ax.annotate(
f"{label}: {v:.1f}%".replace(".0%", "%"),
xy=(0.82 * x, 0.82 * y),
xytext=(xt, yt),
ha="center" if abs(x) < 0.3 else ("left" if x > 0 else "right"),
va="center", fontsize=9,
arrowprops=dict(arrowstyle="-", color="#666", lw=0.7),
)
else:
ax.text(0.82 * x, 0.82 * y, f"{v:.1f}%",
ha="center", va="center", fontsize=10,
color="#222", fontweight="normal")
ax.set_title(data["title"], fontsize=12, pad=18)
legend_handles = [plt.Rectangle((0, 0), 1, 1, color=PALETTE[i])
for i in range(len(data["labels"]))]
ax.legend(legend_handles, data["labels"],
loc="upper center", bbox_to_anchor=(0.5, -0.05),
ncol=2, fontsize=8.5, frameon=False, handlelength=1.2)
for ax, data in zip(axes, CHARTS):
draw_donut(ax, data)
plt.subplots_adjust(left=0.04, right=0.96, top=0.92, bottom=0.18, wspace=0.4)
plt.savefig("genericagent_tool_donut.png", dpi=300, bbox_inches="tight",
facecolor="white")
plt.close()
print("saved: genericagent_tool_donut.png")