200字
Agent学习-Phase 2:Tool call
2026-04-25
2026-04-25

前置说明:这是一个我自己学习Agent Harness开发的一个笔记,上传到这里纯属方便,这个项目叫Odd, 是通过分多个Phase来完成一个能够支持Tools MCP Skill 子agent 任务清单和上下文压缩的Agent框架。我会分多个Phase让AI完成代码,并阅读代码学习

至于为什么用Ado当头图,那当然是因为Ado统治世界

仓库在:https://github.com/GC-SHIRO/Odd.git

一句话总结

工具系统 = Agent 的"手脚"。光有脑子(模型)不够,Agent 需要能真正动手做事情——比如执行命令、读写文件。


为什么模型本身不能直接操作电脑?

AI 模型本质上是一个文字生成器。它只会"说话",不会真的去敲键盘、点鼠标。

所以流程是这样的:

  1. 模型说"我想执行 ls 命令"

  2. Agent 听到后,自己去执行 ls

  3. 把执行结果(文件列表)再告诉模型

  4. 模型根据结果继续思考下一步

这就是著名的 ReAct 循环(推理 → 行动 → 观察)。工具系统负责的就是"行动"这一步。


核心零件

1. Tool 抽象基类(odd/tools/base.py

每个工具都必须回答两个问题:

  1. 你是谁?spec 属性:名字、功能描述、需要什么参数

  2. 你能做什么?execute() 方法:拿到参数后真正干活

ToolSpec 里的 parametersJSON 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 hello

  • python script.py

  • git 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)

学到的要点

  1. Agent = 大脑 + 手脚:模型负责思考,工具负责行动,两者缺一不可。

  2. 安全优先:给 Agent 开 shell 权限是很危险的事,必须加沙箱、拦截、超时。

  3. 注册表模式:工具动态注册,Agent 可以按需扩展能力,不需要改核心代码。

  4. 返回 JSON:工具执行结果统一返回 JSON 字符串,方便模型理解和后续处理。

评论