前置说明:这是一个我自己学习Agent Harness开发的一个笔记,上传到这里纯属方便,这个项目叫Odd, 是通过分多个Phase来完成一个能够支持Tools MCP Skill 子agent 任务清单和上下文压缩的Agent框架。我会分多个Phase让AI完成代码,并阅读代码学习
至于为什么用Ado当头图,那当然是因为
Ado统治世界仓库在:https://github.com/GC-SHIRO/Odd.git
一句话总结
工具系统 = Agent 的"手脚"。光有脑子(模型)不够,Agent 需要能真正动手做事情——比如执行命令、读写文件。
为什么模型本身不能直接操作电脑?
AI 模型本质上是一个文字生成器。它只会"说话",不会真的去敲键盘、点鼠标。
所以流程是这样的:
模型说"我想执行
ls命令"Agent 听到后,自己去执行
ls把执行结果(文件列表)再告诉模型
模型根据结果继续思考下一步
这就是著名的 ReAct 循环(推理 → 行动 → 观察)。工具系统负责的就是"行动"这一步。
核心零件
1. Tool 抽象基类(odd/tools/base.py)
每个工具都必须回答两个问题:
你是谁? →
spec属性:名字、功能描述、需要什么参数你能做什么? →
execute()方法:拿到参数后真正干活
ToolSpec 里的 parameters 是 JSON Schema 格式,这样模型一看就知道该怎么调用这个工具。

2. 注册表(odd/tools/registry.py)
Agent 可能有很多工具(shell、文件操作、搜索、数据库……)。注册表就是一个工具大管家:
register():把工具登记进来get(name):按名字找工具list_tools():列出所有可用工具
我们用一个全局注册表 registry,这样工具定义好就自动可用,Agent 启动时不需要手动一个个添加。
"""工具注册表。
维护 工具名称 -> Tool 实例 的映射,使 Agent 能在运行时动态查找并执行工具。
"""
from typing import Dict, List, Optional
from odd.tools.base import Tool
class ToolRegistry:
"""追踪可用的工具。"""
def __init__(self):
# 内部映射: 工具名称 -> Tool 实例。
self._tools: Dict[str, Tool] = {}
def register(self, tool: Tool) -> None:
"""注册一个工具实例。"""
self._tools[tool.spec.name] = tool
def get(self, name: str) -> Optional[Tool]:
"""按名称检索工具,未找到时返回 None。"""
return self._tools.get(name)
def list_tools(self) -> List[Tool]:
"""返回所有已注册的工具。"""
return list(self._tools.values())
def clear(self) -> None:
"""移除所有已注册的工具(测试时有用)。"""
self._tools.clear()
# 应用使用的全局注册表实例。
registry = ToolRegistry()
def register(tool: Tool) -> Tool:
"""在全局注册表中注册工具实例的助手函数。
可作为装饰器使用,或直接调用。
"""
registry.register(tool)
return tool
3. Shell 工具(odd/tools/builtin/shell.py)
让 Agent 能在电脑上执行命令。比如:
echo hellopython script.pygit status
安全机制
Agent 能力越大,风险越大。Shell 工具加了这些限制:
工作目录锁定:所有命令只能在指定目录里跑,默认是项目根目录
目录穿越拦截:命令里带
..就直接拒绝,防止 Agent 跑到系统其他目录搞破坏超时保护:命令最多跑 60 秒,防止死循环进程拖垮系统
4. 文件系统工具(odd/tools/builtin/filesystem.py)
让 Agent 能读写文件。支持三种操作:
read:读取文件内容
write:写入文件(会自动创建父目录)
list:列出目录内容
安全机制
同样做了沙箱限制:
根目录锁定:所有路径都相对于配置的根目录解析
路径逃逸拦截:如果路径解析后跑到根目录外面去了,直接报错拒绝
举个例子:根目录是 ./scripts/sandbox,Agent 想读 ../prd.md,会被拒绝,因为 .. 会跑到项目根目录外面去。
使用案例
from odd.tools.registry import registry
from odd.tools.builtin.shell import ShellTool
from odd.tools.builtin.filesystem import FileSystemTool
registry.clear()
s = ShellTool() # 已经定义的shell工具
f = FileSystemTool() # 已经定义的filesystem工具
registry.register(s)
registry.register(f)学到的要点
Agent = 大脑 + 手脚:模型负责思考,工具负责行动,两者缺一不可。
安全优先:给 Agent 开 shell 权限是很危险的事,必须加沙箱、拦截、超时。
注册表模式:工具动态注册,Agent 可以按需扩展能力,不需要改核心代码。
返回 JSON:工具执行结果统一返回 JSON 字符串,方便模型理解和后续处理。