揭秘 AI Agent 核心:Tool Use 背后真正的技术逻辑(附 DeepSeek 实战代码)

7 阅读6分钟

导读:当我们看到豆包自动搜索网页、Claude 分析 Excel 表格、甚至 AI Agent 操作 Mac Mini 时,我们往往会惊叹:“AI 难道有自我意识了吗?”
作为开发者,我们需要清醒地认识到:这是一个精心设计的错觉
那个在显卡里疯狂跑的 LLM,本质上还是个“词语接龙”游戏,是被困在服务器里的“缸中大脑”。它看不见屏幕,摸不到键盘。那么,这个只能预测下一个 Token 的概率模型,是如何突破物理限制,去调用 API、读数据库、操作工具的?
本文将带你深入 Tool Use 的技术内核,并通过一段完整的 DeepSeek 实战代码,彻底搞懂 LLM + Tools = Agent 的真正含义。

一、 核心认知:工具即语言

在深入代码之前,必须先建立一个核心认知:大模型不懂什么是天气 API,也不懂数据库查询,但它听得懂语言。

Tool Use 的本质,不是让 AI 学会了编程,而是我们将工具降维成了语言。这个过程可以分为三个精密咬合的阶段:

1. 认知植入 (Cognitive Implantation)

在执行任务之前,我们在 System Prompt 或 API 请求中配置 tools 参数时,其实是在做一件非常精妙的事——认知植入

我们通过 JSON Schema 将复杂的软件接口函数,“翻译”成大模型能理解的使用说明书。例如,一个获取股票收盘价的函数 get_close_price,在大模型眼里只是一段文本描述:

json

编辑

1{
2  "name": "get_closing_price",
3  "description": "获取指定股票的收盘价",
4  "parameters": {
5    "type": "object",
6    "properties": {
7      "name": { "type": "string", "description": "股票名称" }
8    },
9    "required": ["name"]
10  }
11}

在这个阶段,复杂的软件工具被降维成了纯粹的文本约束。LLM 并不执行代码,它只是记住了:“当用户问股价时,我可以输出一段符合上述格式的文本。”

2. 意图识别与“自言自语”

当用户提问“青岛啤酒的收盘价是多少?”时,LLM 的推理引擎开始工作:

  1. 检索训练语料:发现自己无法直接回答实时股价。
  2. 回溯认知植入:发现工具列表里有 get_closing_price
  3. 生成调用指令:AI 会停止与用户的直接对话,转而开始“自言自语”。它严格按照说明书,生成一段结构化的自然语言(Tool Calls):

json

编辑

1tool_calls: [{
2  type: 'function',
3  function: {
4    name: 'get_closing_price',
5    arguments: "{"name": "青岛啤酒"}"
6  }
7}]

注意:此时 LLM 并没有执行函数!它只是在“赌”这段代码发出后,会有人(Runtime)响应。它依赖的是强大的模式识别和逻辑推理能力,将 API 的精确性转化为语言的概率预测。

3. Runtime 的介入

这是传统软件世界与 AI 世界的交汇点。

  • LLM 的职责:决策要调什么工具,传什么参。
  • Runtime (Node/Python/Java) 的职责:只管执行,拿到结果。

关键在于:工具执行的结果不是直接返回给用户,而是返回给大模型。大模型将工具返回的结果作为新的上下文(Context),再次进行推理,最终生成人类可读的自然语言回复。

这就是 LLM + Tools = Agent 的完整闭环。


二、 实战复现:从“缸中大脑”到“股票分析师”

下面我们通过一段基于 DeepSeek 的完整代码,在本地复现上述全过程。这段代码展示了新旧范式的融合:既有传统的函数定义,又有 AI 时代的认知植入。

1. 环境准备与工具定义

首先,我们将现实世界的函数“降维”为 JSON Schema:

javascript

编辑

1import OpenAI from 'openai';
2import dotenv from 'dotenv';
3dotenv.config();
4
5// 初始化“缸中大脑”
6const client = new OpenAI({
7  apiKey: process.env.DEEPSEEK_API_KEY,
8  baseURL: process.env.DEEPSEEK_BASE_URL
9});
10
11// 【认知植入】将函数降维为语言描述
12const tools = [
13  {
14    type: "function",
15    function: {
16      name: "get_closing_price",
17      description: "获取指定股票的收盘价", // 描述越清晰,LLM 决策越准
18      parameters: {
19        type: "object",
20        properties: {
21          name: { type: "string", description: "股票名称" }
22        },
23        required: ["name"]
24      }
25    }
26  }, 
27  {
28    type: 'function',
29    function: {
30      name: 'get_weather',
31      description: '获取指定城市的天气',
32      parameters: {
33        type: 'object',
34        properties: {
35          city: { type: 'string', description: '城市名称' }
36        },
37        required: ['city']
38      }
39    }
40  }
41];

2. 传统软件世界的“手脚”

LLM 做不了的事,由我们的 Runtime 来做:

javascript

编辑

1// 模拟真实的业务逻辑
2function get_closing_price(name) {
3  const stockData = {
4    '青岛啤酒': '67.92',
5    '贵州茅台': '1488.21'
6  };
7  return stockData[name] || '未找到该股票';
8}

3. 核心交互循环(Agent Loop)

这是整篇文章最核心的部分。请注意观察消息列表 messages 是如何在 User、Assistant、Tool 三种角色间流转的:

javascript

编辑

1async function sendMessage(messages) {
2  return await client.chat.completions.create({
3    model: 'deepseek-v4-pro', // 或其他支持 tool use 的模型
4    messages,
5    tools,
6    tool_choice: 'auto'
7  });
8}
9
10async function main() {
11  // 1. 用户发起提问
12  let messages = [
13    { role: 'user', content: '青岛啤酒的收盘价是多少?' }
14  ];
15
16  // 2. 第一次调用:LLM 进行意图识别
17  const response = await sendMessage(messages);
18  const message = response.choices[0].message;
19  
20  console.log('🤖 模型首次返回:', JSON.stringify(message));
21  
22  // 将模型的决策加入上下文
23  messages.push({
24    role: message.role,
25    content: message.content,
26    tool_calls: message.tool_calls
27  });
28
29  // 3. Runtime 介入:判断是否需要执行工具
30  if (message.tool_calls) {
31    const toolCall = message.tool_calls[0];
32    
33    if (toolCall.function.name === 'get_closing_price') {
34      // 解析 LLM 生成的参数
35      const args = JSON.parse(toolCall.function.arguments);
36      
37      // 执行传统函数
38      const price = get_closing_price(args.name);
39      console.log(`📊 工具执行结果: ${price}`);
40
41      // ⚠️ 关键步骤:将工具结果反馈给 LLM,而不是直接给用户
42      messages.push({
43        role: 'tool',           // 角色标识为 tool
44        content: price,         // 工具返回的内容
45        tool_call_id: toolCall.id // 通过 ID 关联之前的调用请求
46      });
47
48      console.log('🔄 更新后的完整上下文:', messages);
49
50      // 4. 第二次调用:LLM 根据工具结果生成最终回复
51      const finalRes = await sendMessage(messages);
52      console.log('✅ 最终回复:', finalRes.choices[0].message.content);
53    }
54  }
55}
56
57main();

三、 总结:如何在脑海复现这节课?

当你下次再看到 AI 调用工具时,请在脑海中运行以下三个画面:

  1. 配置阶段:想象你在给一个绝顶聪明但被关在黑屋子里的人塞纸条(JSON Schema),告诉他“如果有事找外界,就按这个格式写纸条”。
  2. 决策阶段:用户提问后,这个人没有直接回答,而是写了一张符合格式的纸条(tool_calls)递出窗口,然后停下来等待。
  3. 执行与反馈阶段:你(Runtime)在窗外接过纸条,查完数据库后,把结果写在另一张纸条上递回去。这个人看到结果后,才开口对用户说出了最终答案。

Tool Use 不是什么魔法,它是概率模型与传统软件工程的一次伟大握手。  LLM 负责“想”和“说”,Runtime 负责“做”,两者通过标准化的语言协议(JSON)无缝衔接。

掌握了这个底层逻辑,你就掌握了构建 AI Agent 的钥匙。无论是操作电脑、分析表格还是自动化办公,万变不离其宗。


希望这篇文章能帮你彻底打通 Tool Use 的任督二脉。如果你觉得有收获,欢迎点赞收藏,我们下节课见!