章末自测

题目 1:为什么说“大模型没有真的执行函数”?

假设模型返回 read_file(path="app.py"),请从模型输出、Harness、Python 运行时、真实环境四个层次解释整个过程,并说明如果 Harness 拒绝执行,会发生什么。

模型只负责生成 Tool Call,也就是“希望调用 read_file,参数是 app.py”这一结构化意图。Harness 接收后负责查找工具、校验参数和安全规则;真正打开文件的是 Python 运行时中的 read_file()。因此模型本身没有直接文件系统权限。如果 Harness 判断该动作不允许并拒绝执行,文件不会被读取,真实环境也不会发生变化。这个边界说明 Tool Call 本质上是请求,而不是执行事实。

题目 2:代码阅读——下面代码有什么风险?

tool = TOOLS[tool_call["name"]]
result = tool(**tool_call["arguments"])

请至少指出四个风险,并给出改进方向。

风险包括:工具名不存在会触发 KeyError;参数缺失或多余会产生 TypeError;参数类型和值可能不合法;工具内部异常会直接中断 Agent;对于有副作用工具还缺少权限与安全检查。改进方向是先做 Tool Lookup,再做参数 Schema / Signature 校验,再经过业务与安全校验,最后用 try/except 执行,并统一返回 ToolResult。高风险工具还应经过 Middleware 或 Human Approval。

题目 3:判断题——Tool Schema 已经定义了参数类型,所以 Harness 不需要再校验,对吗?

请判断,并至少举两个“Schema 看起来合法,但业务上仍然危险”的例子。

不对。Schema 主要约束结构和基本类型,但很多业务规则无法只靠类型表达。例如 limit 是合法整数,但如果值是 999999999,可能拖垮数据库;path 是合法字符串,但如果是 ../../../../etc/passwd,存在路径逃逸风险。再比如日期是合法字符串,但范围可能超过允许的 30 天。因此 Tool Schema 只是第一层,Harness 和 Middleware 仍需要业务规则与安全校验。

题目 4:编程实现——写一个最小 Tool Executor

请实现 ToolCall、ToolResult、TOOLS 注册表和 execute_tool()。要求至少支持 read_file、list_files,并处理未知工具和执行异常。

#下面是一种完整实现:

from dataclasses import dataclass
from typing import Any, Callable


@dataclass
class ToolCall:
    name: str
    arguments: dict[str, Any]


@dataclass
class ToolResult:
    ok: bool
    tool_name: str
    result: Any = None
    error: str = ""


FILES = {
    "README.md": "Agent Demo"
}


def read_file(path: str) -> str:
    if path not in FILES:
        raise FileNotFoundError(path)

    return FILES[path]


def list_files() -> list[str]:
    return list(FILES.keys())


TOOLS: dict[str, Callable[..., Any]] = {
    "read_file": read_file,
    "list_files": list_files,
}


def execute_tool(
    call: ToolCall,
) -> ToolResult:
    if call.name not in TOOLS:
        return ToolResult(
            ok=False,
            tool_name=call.name,
            error="UnknownTool",
        )

    try:
        result = TOOLS[call.name](
            **call.arguments
        )

        return ToolResult(
            ok=True,
            tool_name=call.name,
            result=result,
        )

    except Exception as exc:
        return ToolResult(
            ok=False,
            tool_name=call.name,
            error=str(exc),
        )


if __name__ == "__main__":
    print(
        execute_tool(
            ToolCall(
                name="list_files",
                arguments={},
            )
        )
    )

    print(
        execute_tool(
            ToolCall(
                name="read_file",
                arguments={
                    "path": "README.md"
                },
            )
        )
    )
#这个版本还没有参数 Schema 和权限层,但已经具备最基础的 Tool Lookup、Execution 和结构化结果。

题目 5:综合应用——为什么 Tool Result 必须重新进入 Main Loop?

假设 Agent 第一次调用 read_file("app.py") 返回 FILE_NOT_FOUND。如果 Tool Result 只打印日志、不放回下一轮 Context,会发生什么?如果正确回传,模型可能怎么修正?

如果 Tool Result 只写日志,模型下一轮看不到上一轮真实结果,因此可能继续认为 app.py 存在,甚至重复调用同一个工具。正确回传后,FILE_NOT_FOUND 会成为 Observation,模型可以据此判断自己的路径假设错误,下一步改为 list_files() 或 search_files()。因此 Tool Calling 真正形成 Agent 能力的关键,不只是执行动作,而是把执行反馈重新送入下一轮决策。

题目 6:对比分析——直接生成 SQL 和调用 query_metric Tool 有什么差别?

请从灵活性、安全性、参数校验、权限控制、审计几个角度比较,并说明哪一种更适合什么场景。

直接生成 SQL 灵活性更高,适合受信任、受控环境中的复杂查询,但模型自由度也更大,需要更强 SQL Parser、安全校验、表白名单和权限控制。query_metric 这类业务 Tool 把动作空间收窄成结构化参数,Harness 可以统一限制 metric、dimension、日期范围、limit,因此更容易治理和审计。生产系统常会优先暴露高层业务 Tool,把原始 SQL 能力放在更严格的安全边界后。

题目 7:概念理解——为什么 Tool Calling 是 Agent 从“会想”到“会做”的分界线?

请说明 Tool Calling 自身为什么仍然不够,以及要形成完整 Agent 行动闭环还需要哪些组件。

Tool Calling 让模型第一次能够把“下一步想做什么”表达成程序可执行的结构化动作,因此是从纯文本推理走向外部行动的重要分界线。但它本身仍然不等于完整 Agent,因为还需要 Harness 查找与执行 Tool、参数和安全校验、Tool Result 结构化、Observation 回流、Main Loop 持续决策,以及 State 保存执行过程。只有这些组件连起来,模型的动作意图才能真正转化为可控的多步任务执行。

进一步阅读

  • Tool / Function Calling 官方文档:建议重点观察“模型输出 Tool Call”和“应用程序执行 Tool”之间的职责边界。
  • JSON Schema 相关资料:下一节会进一步学习如何用 Schema 描述 Tool 参数,让模型和程序共享统一协议。
  • Python inspect.signature 文档:可以用于函数参数绑定与基础校验。
  • Adapter Pattern 相关资料:理解不同 Provider 的 Tool Call 如何统一成内部 ToolCall。
  • Command Pattern 相关资料:Tool Call 可以从“命令对象”的角度理解,便于执行、记录和重放。
  • Input Validation 相关资料:Agent Tool Call 本质上也是外部输入,应采用不信任输入的工程思维。
  • Sandbox / Capability Security 相关资料:为后面 Shell、文件系统与高风险 Tool 的安全控制打基础。
  • Human in the Loop 相关资料:理解为什么部分 Tool Call 需要在真正执行前暂停审批。

术语表

  • 工具调用(Tool Calling):模型根据当前上下文选择某个外部能力,并以结构化形式输出工具名称和参数的机制。它表达的是动作意图,而不是动作已经发生。
  • 函数调用(Function Calling):Tool Calling 的一种常见形式,模型输出希望调用的函数名和参数。现代 Agent 中 Tool 的范围通常比普通 Python Function 更广。
  • 工具调用对象(Tool Call):Harness 内部表示模型动作请求的数据结构,通常包含 name、arguments,后续还可能包含 id、来源模型等信息。
  • 工具执行器(Tool Executor):负责根据 Tool Call 查找实际工具、校验参数、执行函数并统一返回结果的 Harness 组件,是模型与真实环境之间的关键执行边界。
  • 工具结果(Tool Result):Tool 真正执行后的结构化结果,可以包含成功值、错误类型、错误信息、耗时等。它通常会进一步转成 Observation。
  • 参数校验(Argument Validation):在执行工具前检查参数是否完整、类型是否正确、业务值是否合法的过程。模型输出不应被默认视为可信输入。
  • 未知工具(Unknown Tool):模型请求了 Registry 中不存在的工具。成熟 Harness 应把它结构化成可观察错误,而不是直接让程序崩溃。
  • 副作用(Side Effect):Tool 执行后会改变真实环境的行为,例如写文件、删除数据、发送邮件、执行 Shell。具有副作用的工具通常需要更严格的权限和审批。

本章总结

这一节是 Agent 真正开始“长出手脚”的第一步。

前面我们已经让 Agent 会循环、会保存 State、会通过 Provider 调模型。

但如果模型只能返回文本,它仍然只能“说”。

Tool Calling 则让模型第一次可以输出:

{
  "name": "read_file",
  "arguments": {
    "path": "app.py"
  }
}

不过这一节最重要的不是记住 JSON 长什么样,而是彻底建立一个边界,大模型没有真的执行函数。

模型只是,告诉 Harness:“我想调用这个工具。”

真正执行过程是:

模型产生 Tool Call
   ↓
Harness 解析
   ↓
查找工具
   ↓
参数校验
   ↓
权限与安全检查
   ↓
Python / API / SQL / Shell 真正执行
   ↓
Tool Result
   ↓
Observation
   ↓
回到 Main Loop

所以 Tool Calling 只是动作的开始,不是动作的结束。

我们还看到,Tool Executor 最少要处理:

Unknown Tool
Missing Arguments
Invalid Arguments
Tool Exception

而以后更复杂的 Tool 还要处理:

Permission
Timeout
Side Effect
Human Approval
Sandbox

如果你想验证自己是否真的学会这一节,可以不接任何真实 LLM。

自己造一个 FakeProvider,让它第一轮输出:

read_file("app.py")

Harness 执行后返回:

FILE_NOT_FOUND

第二轮再让模型输出:

list_files()

如果你能把这条链完整跑通:

Tool Call
 ↓
Tool Executor
 ↓
Tool Result
 ↓
Observation
 ↓
Next Tool Call

那么这一节最核心的能力就已经掌握了。

下一节我们会正式解决一个现在已经出现的问题,工具越来越多以后,怎么统一管理?

如果继续写:

if name == "read_file":
    ...
elif name == "list_files":
    ...
elif name == "run_python":
    ...

代码会越来越难维护。

所以第 07 节,我们会自己实现,Tool Registry

让所有工具可以注册、查询、枚举和统一执行。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容