2026年7月11日 3 分钟阅读

从零搭建 AI Agent:7 个必备工具系统实战

tinyash 0 条评论

AI Agent 的核心能力不只在于”能对话”,更在于能执行操作——在计算机上运行命令、读写文件、搜索代码、编辑内容、访问网络。这些能力通过工具(Tools) 来实现。

本文带你从零开始,为 AI Agent 实现一套完整的工具系统。代码使用 Python 标准库加 BeautifulSoup(网页解析),pip install beautifulsoup4 即可运行。

什么是 Agent 工具?

工具是暴露给 LLM 的可调用函数。Agent 在推理过程中,遇到需要外部操作的任务时(比如”看看当前目录有哪些文件”),LLM 会发出一个结构化的工具调用请求,由 Agent 框架执行并返回结果。

现代 LLM(GPT-4o、Claude Sonnet、DeepSeek V3 等)都原生支持 function calling——模型输出 JSON 格式的工具调用参数,框架执行后把结果送回上下文。

7 个核心工具实现

1. Bash 执行器

最强大的工具——让 Agent 能在计算机上运行任何命令:

import subprocess

def run_bash(command: str) -> str:
    result = subprocess.run(
        command, shell=True,
        text=True, capture_output=True
    )
    output = result.stdout
    if result.stderr:
        output += f"\nSTDERR:\n{result.stderr}"
    return output or "(no output)"

⚠️ 安全提示:bash 工具权限最大,生产环境需配合沙箱使用。

2. 文件读取器

支持行号和分页,避免一次性吞掉大文件:

from pathlib import Path

def read_file(path: str, offset: int = 1, limit: int = 200) -> str:
    p = Path(path)
    if not p.exists():
        return f"Error: file not found: {path}"
    lines = p.read_text(errors="replace").splitlines()
    selected = lines[offset-1:offset-1+limit]
    return "\n".join(
        f"{offset+i}: {line}"
        for i, line in enumerate(selected)
    )

3. 文件搜索(glob)

帮助 Agent 先探明目录结构:

import glob as glob_module

def glob_files(pattern: str, path: str = ".") -> str:
    matches = glob_module.glob(f"{path}/**/{pattern}", recursive=True)
    matches += glob_module.glob(f"{path}/{pattern}")
    return "\n".join(sorted(set(matches))) or "(no matches)"

4. 内容搜索(grep)

正则搜索文件内容,返回文件名+行号+匹配行:

import re

def grep(pattern: str, path: str = ".", include: str = "*") -> str:
    results = []
    for fp in glob_module.glob(f"{path}/**/{include}", recursive=True):
        p = Path(fp)
        if not p.is_file():
            continue
        try:
            for i, line in enumerate(p.read_text(errors="replace").splitlines(), 1):
                if re.search(pattern, line):
                    results.append(f"{fp}:{i}: {line}")
        except OSError:
            pass
    return "\n".join(results) or "(no matches)"

5. 文件写入器

自动创建父目录,让 Agent 不需要关心目录结构:

def write_file(path: str, content: str) -> str:
    p = Path(path)
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_text(content)
    return f"Wrote {len(content)} bytes to {path}"

6. 文件编辑器

这是最安全的修改方式——只替换特定字符串,避免全量覆写:

def edit_file(path: str, old_string: str, new_string: str) -> str:
    p = Path(path)
    if not p.exists():
        return f"Error: file not found: {path}"
    original = p.read_text()
    if old_string not in original:
        return f"Error: string not found"
    p.write_text(original.replace(old_string, new_string, 1))
    return f"Edited {path}"

7. 网页抓取器

让 Agent 能读取在线文档和网页内容:

import urllib.request
from urllib.parse import urlparse
from bs4 import BeautifulSoup

def webfetch(url: str) -> str:
    parsed = urlparse(url)
    if parsed.scheme not in ("http", "https"):
        return f"Unsupported scheme: {parsed.scheme}"
    req = urllib.request.Request(
        url, headers={"User-Agent": "agent/1.0"}
    )
    with urllib.request.urlopen(req, timeout=15) as resp:
        raw = resp.read().decode(errors="replace")
    soup = BeautifulSoup(raw, "html.parser")
    text = soup.get_text(separator="\n", strip=True)
    return re.sub(r"\n{3,}", "\n\n", text).strip()

定义工具 Schema

有了实现还不够——Agent 需要知道每个工具是什么、做什么、参数是什么。OpenAI 风格的 function calling schema 如下:

def get_tool_schemas():
    return [
        {
            "type": "function",
            "function": {
                "name": "run_bash",
                "description": "Run a bash command on the user's machine and return the output.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "command": {
                            "type": "string",
                            "description": "The bash command to execute.",
                        }
                    },
                    "required": ["command"],
                },
            },
        },
        # ... 其他工具同理
    ]

整合到 Agent 循环

将工具 schema 传入 LLM 的 tools 参数,在 Agent 循环中检测 tool_calls 并分发执行:

tools_map = {
    "run_bash": run_bash,
    "read_file": read_file,
    "write_file": write_file,
    "edit_file": edit_file,
    "glob_files": glob_files,
    "grep": grep,
    "webfetch": webfetch,
}

response = client.chat.completions.create(
    model="your-model",
    messages=messages,
    tools=get_tool_schemas(),
)

if response.choices[0].message.tool_calls:
    for call in response.choices[0].message.tool_calls:
        fn_name = call.function.name
        args = json.loads(call.function.arguments)
        result = tools_map[fn_name](**args)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": str(result),
        })

实战场景:用工具系统搭建编码助手

假设你的 Agent 接到一个任务:”找到项目中所有未使用的 import,并清理掉。”

Agent 的执行流程大致如下:

  1. glob_files(“/*.py”)** → 发现所有 Python 文件
  2. grep(“os”, include=”/*.py”)** → 在代码中搜索 os 模块的使用
  3. read_file(“src/main.py”) → 读取可疑文件确认
  4. edit_file(“src/main.py”, “import os\n”, “”) → 删除确认未使用的导入
  5. 循环执行直至所有文件被审计

这个过程中,Agent 完全自主调用、验证、修正。你只需要下达目标,工具系统负责执行路径

工具设计的 4 个原则

  1. 幂等性优先:同一个工具的多次调用不应产生副作用(read_file 永远是安全的,edit_file 在字符串不存在时给出明确错误)
  2. 渐进式风险:从最安全的工具开始暴露,将 bash 这类高权限工具放在沙箱/审批流背后
  3. 返回值结构一致:每个工具都返回字符串,成功返回内容,失败返回错误信息——Agent 不需要针对不同工具做不同的解析
  4. 保留上下文扼要:glob_files 返回行数可控的结果,read_file 默认只读 200 行——避免工具结果撑爆 LLM 上下文窗口

扩展方向

这套基础工具系统可以继续进化为更强大的 Agent 平台:

  • MCP 协议接入:将每个工具包装为 MCP Server,让 Claude Desktop、Cursor 等任意 MCP 客户端都能使用
  • 权限分级:为 bash 工具增加”只读模式”——只允许执行 catlsgrep,禁止 rmcurl 等写操作
  • 沙箱隔离:将 bash 执行重定向到 Docker 容器或 Firecracker 微 VM,防止 Agent 操作损坏主机
  • 记忆增强:将工具调用结果持久化到向量数据库,让 Agent 能”记住”之前的文件结构和代码内容

总结

这 7 个工具构成了 AI Agent 操作计算机的核心能力集。它们的设计遵循一条原则:每个工具只做一件事,但把它做好。bash 提供无限可能,文件工具提供细粒度控制,web 抓取拓展信息边界。

这套系统最大的价值不在于单个工具的实现有多精妙,而在于组合使用时的涌现能力——Agent 可以利用搜索工具找到问题、读取工具理解上下文、编辑工具实施修改、bash 工具验证结果,自主完成从诊断到修复的闭环。

在此基础上,你可以继续添加 MCP 协议支持、安全沙箱、权限分级等功能。工具系统是 Agent 能力的杠杆——投入越多,Agent 能做越多。

相关链接


本文基于 HN 上 Roger Oriol 的系列教程编写,代码经过简化和中文适配。完整原版包含更多高级工具和错误处理细节。

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。