AI Agent 入门教程:06-工具系统

把零散函数收进 Tool Registry,按副作用级别处理 Schema、权限、结果上限、超时、有限重试、稳定错误和业务幂等键。故障矩阵用于验证每条恢复策略。

本文目录7 个章节

普通函数进入 Agent 后会多出哪些风险

Fake Model 和行为测试已经固定了“搜索—读取—结束”这条基线。现在可以在不改变行为的前提下,把 dispatch_tool() 换成统一的 Tool Registry。

search_local_sources() 单独调用很简单。进入 Agent Loop 后,模型可能重复请求、传入极长参数,工具也可能超时或返回巨量内容。写工具还会出现更麻烦的情况:客户端认为超时,服务器已经完成写入,下一次重试造成重复副作用。

Tool Registry 给所有工具套上同一条执行边界。

TEXT
模型请求
   │
   ▼
Schema 校验 ─▶ 权限检查 ─▶ 超时与并发 ─▶ 执行函数
                                              │
                                              ▼
模型结果 ◀─ 稳定错误 ◀─ 截断与脱敏 ◀─ 原始结果

先给工具标出副作用

级别示例自动重试
read搜索、读取文档暂时故障可有限重试
reversible_write保存可覆盖草稿有幂等键并能查状态时重试
irreversible_write发送消息、付款默认不自动重试,进入审批

超时只表示调用方不知道结果,无法证明操作失败。读取操作可以再试,写入操作要先查询执行状态。

ToolSpec 把描述与策略放在一起

PYTHON
from dataclasses import dataclass
from typing import Any, Callable

@dataclass(frozen=True)
class ToolSpec:
    name: str
    description: str
    effect: str
    timeout_seconds: float
    max_attempts: int
    max_output_chars: int
    handler: Callable[..., Any]

class ToolRegistry:
    def __init__(self) -> None:
        self._tools: dict[str, ToolSpec] = {}

    def register(self, spec: ToolSpec) -> None:
        if spec.name in self._tools:
            raise ValueError("duplicate_tool")
        self._tools[spec.name] = spec

    def get(self, name: str) -> ToolSpec | None:
        return self._tools.get(name)

模型可见的描述、运行时策略和 handler 来自同一注册项,避免修改了 Schema 却忘记更新执行器。

统一调用结果

PYTHON
def invoke_tool(registry: ToolRegistry, name: str, arguments: dict) -> dict:
    spec = registry.get(name)
    if spec is None:
        return {"ok": False, "error": "unknown_tool", "retryable": False}
    try:
        value = spec.handler(**arguments)
        return {"ok": True, "data": str(value)[:spec.max_output_chars]}
    except PermissionError:
        return {"ok": False, "error": "forbidden", "retryable": False}
    except (ConnectionError, TimeoutError):
        return {"ok": False, "error": "transient_failure", "retryable": True}
    except TypeError:
        return {"ok": False, "error": "invalid_arguments", "retryable": False}
    except Exception:
        return {"ok": False, "error": "tool_failure", "retryable": False}

模型只看到稳定错误码和 retryable。异常堆栈留给服务日志。retryable=True 也要受 max_attempts 和任务总预算限制。

写工具需要业务幂等键

保存简报时,幂等键可以由 task_id + path + content_hash 计算。相同业务意图重复提交,返回首次结果,不再写第二次。

PYTHON
class IdempotencyStore:
    def __init__(self) -> None:
        self._results: dict[str, dict] = {}

    def run_once(self, key: str, operation: Callable[[], dict]) -> dict:
        if key in self._results:
            return self._results[key]
        result = operation()
        if result.get("ok"):
            self._results[key] = result
        return result

网络 request ID 只能标识一次传输,不代表业务意图。进程重启后仍要去重时,幂等结果应放进数据库,并与输出文件状态一起提交。

用故障矩阵写测试

故障读工具写工具预期结果
参数缺失不执行不执行invalid_arguments
暂时断连最多重试 2 次先查状态计入总预算
权限拒绝不重试不重试forbidden
超时且结果未知可以重查禁止盲目重写outcome_unknown
输出过大截断截断回执记录原始长度

测试 handler 的实际调用次数。只断言最终错误码,无法发现执行器已经重复写了两次。

可靠工具层完成后的变化

Agent Loop 不再直接调用任意函数。所有行动经过注册表,错误和预算在同一位置可见。第 7 篇沿用这套 Tool Registry,把演示数据换成可检索资料库,并让 search_local_sourcesget_document 进入同一条 RAG 管线。

REFERENCES

参考链接

  1. 01Function Calling | OpenAI API
  2. 02Production Best Practices | OpenAI API
  3. 03LLM06:2025 Excessive Agency | OWASP GenAI Security Project

所属系列

AI AGENT 入门教程

下一步

继续浏览相关主题

沿着同一主题继续阅读。

查看最新资讯