在人工智能技术日新月异的今天,大模型(LLM)的表现常常让我们惊叹。豆包可以根据你的提问自动搜索网页;Claude 能够直接读取并分析复杂的 Excel 表格;更进一步的 AI Agent 甚至能够直接操作 Mac Mini 电脑。

面对这些神奇的现象,我们不禁会产生一个疑问:难道 AI 真的产生自我意识了吗?

作为开发者,我们需要理性地解构这一现象。事实上,所谓的“AI 拥有自我意识并主动操作工具”,只是一个被精心设计的技术错觉。在显卡中疯狂运转的大模型,本质上依然在玩一个“词语接龙”(Next Token Prediction)的概率游戏。它是被困在服务器里的“缸中大脑”,看不见屏幕,摸不到键盘,更无法直接与物理世界交互。

那么,一个只能预测下一个词出现概率的模型,究其根本是如何突破物理限制,去调用外部 API、读取数据库,甚至操作物理工具的?

大模型 + 工具(Tools)= Agent。本文将撕开 Agent 的神秘面纱,带你从底层逻辑到代码实战,一步步看清传统软件世界与大模型是如何完成这场精妙接驳的。


一、 工具调用的三大底层核心逻辑

要让一个纯文本模型使用工具,整个技术闭环由三个核心阶段组成:认知植入意图识别Runtime(运行时)介入

1. 认知植入:将工具降维成语言

大模型本身不懂什么是天气 API,也不明白如何执行 SQL 语句进行数据库查询,但它拥有极强的文本理解能力。因此,我们要做的第一步,就是将工具降维成语言

在将任务提交给大模型之前,开发者会在系统的全局提示词(System Prompt)中配置工具。我们使用一种结构化的数据格式——JSON Schema,将复杂的软件接口函数翻译成大模型能听懂的“使用说明书”。大模型具有概率随机性,因此这份说明书必须对函数的用途、参数的类型和含义进行极其具体、清晰的描述。在这个阶段,一个传统软件世界的复杂工具,被纯粹地降维成了一段文本。

2. 意图识别:大模型的自言自语

当用户提出一个时效性极强或需要特定计算的问题时(例如:“上海的天气怎么样?”),大模型的推理引擎开始工作。它首先评估自己的原始训练语料,发现无法直接回答;接着它会检索在“认知植入”阶段获得的工具说明书,发现其中恰好有一个名为 get_weather 的工具。

此时,大模型会停止与用户的直接对话,转而开始“自言自语”。它严格按照说明书的格式规范,生成一段特定结构的数据(tool_calls),表明自己想要调用哪个工具、需要传入什么参数。它本身无法执行这段代码,但它依托强大的模式识别能力,“赌”这段数据发出后,外部的传统软件环境会给予它响应。

3. Runtime 的介入:传统软件世界的接棒

大模型生成工具调用意图后,整个执行流程会陷入中断,传统软件的 Runtime(运行时环境,如 Node.js、Python 等) 正式介入。

Runtime 负责处理脏活累活。它捕获大模型发出的调用请求,解析其中的参数,真正去调用网络接口或执行本地函数。拿到执行结果后,Runtime 并不是直接将结果返回给用户,而是将结果重新“喂”回给大模型。大模型结合最开始的用户提问、自己之前的思考过程以及 Runtime 返回的工具结果,融会贯通,最终生成一段通顺的自然语言回答给用户。


二、 基础环境搭建与配置

在进入源码分析之前,我们需要配置一个标准的 Node.js 运行时环境(Runtime),来充当大模型的“手脚”。

1. 初始化项目与依赖安装

打开终端,在你的项目文件夹下依次执行以下指令。

首先,初始化 Node.js 项目配置文件:

npm init -y

接着,利用 pnpm 安装 OpenAI 官方 SDK(用于与大模型通信)以及管理环境变量的 dotenv 库:

pnpm i openai dotenv

2. 环境变量配置

在项目根目录下创建一个名为 .env 的文件,用于安全地存放大模型的 API 凭证及请求地址。

DEEPSEEK_API_KEY=你的DEEPSEEK密钥
DEEPSEEK_API_BASE_URL=https://api.deepseek.com/v1

三、 完整源码实现

以下是基于 Node.js 实现的工具调用完整闭环代码。我们通过模拟“获取股票收盘价”和“查询天气”两个场景,完整还原大模型与外部环境交互的全过程。

import OpenAI from 'openai'
import dotenv from 'dotenv'

// 加载环境变量配置
dotenv.config()

// 初始化大模型客户端(缸中大脑)
const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: process.env.DEEPSEEK_API_BASE_URL,
});

// 1. 认知植入:使用 JSON Schema 将函数功能降维成文本描述
const tools = [
  {
    "type": "function",
    "function": {
      "name": "get_closing_price",
      "description": "获取指定股票的收盘价",
      "parameters": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "股票名称"
          }
        },
        "required": ["name"]
      }
    }
  },
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "获取指定城市的天气",
      "parameters": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "城市名称"
          }
        },
        "required": ["city"]
      }
    }
  }
]

// 2. 传统软件世界:Runtime 真正执行的实体函数
function get_closing_price(name) {
  if (name === '青岛啤酒') {
    return '67.92';
  } else if (name === '贵州茅台') {
    return '148.92';
  } else {
    return '未找到该股票';
  }
}

function get_weather(city) {
  if (city === '北京') {
    return '晴,25°C';
  } else if (city === '上海') {
    return '多云,28°C';
  } else {
    return '未找到该城市天气信息';
  }
}

// 封装与大模型的通信接口
async function sendMessage(messages) {
  const res = await client.chat.completions.create({
    model: "deepseek-v4-pro",
    messages,
    tools, // 将工具说明书注入其中
    tool_choice: "auto", // 让大模型自主决定是否使用工具
  });
  return res;
}

// 3. 核心流程控制
async function main() {
  // 定义对话上下文,初始状态只有用户的提问
  let messages = [{
    role: "user",
    content: "青岛啤酒的收盘价是多少?"
  }];

  // 【第一次交互】大模型读取上下文并进行意图识别
  const response = await sendMessage(messages);
  const message = response.choices[0].message;
  console.log("模型返回message 对象:", JSON.stringify(message));

  // 检查大模型是否提出了工具调用申请
  if (response.choices[0].message.tool_calls) {
    
    // 关键细节:必须将大模型返回的包含 tool_calls 的 assistant 消息推入上下文中。
    // 否则,后续发送 tool 消息时会因上下文缺失前置关联而导致 API 报 400 错误。
    messages.push(response.choices[0].message);
    
    // 取出大模型要求调用的第一个工具
    const tool_calls = response.choices[0].message.tool_calls[0];
    
    // 【Runtime 介入】根据大模型指定的工具名称分支进行处理
    if (tool_calls.function.name === 'get_closing_price') {
      // 解析大模型生成的参数
      const args = JSON.parse(tool_calls.function.arguments);
      // 调用传统软件世界中的本地函数获取结果
      const price = get_closing_price(args.name);
      console.log("股票收盘价:", price);
      
      // 将工具的执行结果同步到对话上下文中
      messages.push({
        role: "tool", // 角色声明为工具
        content: price, // 工具执行的真实数据
        tool_call_id: tool_calls.id, // 用唯一的 id 与大模型的调用请求进行关联
      });
      
      console.log("更新后完整对话上下文:", messages);
      
      // 【第二次交互】将携带了外部真实数据的完整上下文再次送回大模型
      const finalRes = await sendMessage(messages);
      console.log("最终模型返回message 对象:", finalRes.choices[0].message.content);
      
    } else if (tool_calls.function.name === 'get_weather') {
      const args = JSON.parse(tool_calls.function.arguments);
      const weather = get_weather(args.city);
      console.log("天气:", weather);
      
      messages.push({
        role: "tool",
        content: weather,
        tool_call_id: tool_calls.id,
      });
      
      console.log("更新后完整对话上下文:", messages);
      const finalRes = await sendMessage(messages);
      console.log("最终模型返回message 对象:", finalRes.choices[0].message.content);
    }
  }
}

main();

四、 保姆级源码逐行细致讲解

为了让毫无编程背景的读者也能彻底理解,我们将上述长代码拆解为四个核心模块进行精细化剖析。

模块 1:大脑初始化与依赖配置

import OpenAI from 'openai'
import dotenv from 'dotenv'
dotenv.config()

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: process.env.DEEPSEEK_API_BASE_URL,
});
  • import 语句引入了我们之前通过命令安装的工具包。dotenv.config() 负责读取 .env 文件,将里面的密钥等敏感信息加载到运行环境中。
  • new OpenAI(...) 创建了一个大模型连接实例 client。这相当于在我们的代码环境与远程服务器中那个“缸中大脑”之间,架设了一根专用的通信光缆。

模块 2:精心编写的工具说明书(JSON Schema)

const tools = [
  {
    "type": "function",
    "function": {
      "name": "get_closing_price",
      "description": "获取指定股票的收盘价",
      "parameters": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "股票名称" }
        },
        "required": ["name"]
      }
    }
  },
  // ... 天气工具定义类似
]

这是认知植入的核心。我们定义了一个名为 tools 的数组,里面存放着一个个工具的描述:

  • "name": "get_closing_price":告诉大模型这个工具的文本代号。
  • "description": "获取指定股票的收盘价"这是最关键的一行。大模型通过这段中文描述来理解这个工具能干什么,从而在用户提问时做出精准的决策。
  • "parameters" 内部定义了参数约束:要求必须传入一个名为 name 的字符串(string),并且这个参数是必填的(required)。大模型会严格按照这个约定来生成调用参数。

模块 3:实体函数的落地实现

function get_closing_price(name) {
  if (name === '青岛啤酒') { return '67.92'; }
  // ... 后续逻辑
}

这是传统软件世界中真正的 JavaScript 函数。它拥有确定的逻辑:输入一个字符串,经过条件判断,返回对应的结果。大模型本身永远无法运行这个函数,它只负责在需要时发出调用申请,实际运行它的依旧是我们的 Node.js 运行时环境。

模块 4:核心流程控制(两轮交互的运转奥秘)

let messages = [{ role: "user", content: "青岛啤酒的收盘价是多少?" }];
const response = await sendMessage(messages);

首先,我们向大模型发送了用户的第一个问题。大模型拿到请求后,发现自己无法直接回答,但对比了 tools 说明书后,发现 get_closing_price 可以派上用场。

const message = response.choices[0].message;

大模型返回了一个特殊的 message 对象。此时如果你将其打印出来,它的 content 为空,但是其内部的 tool_calls 属性会包含如下内容:

{
  "id": "call_123456",
  "type": "function",
  "function": {
    "name": "get_closing_price",
    "arguments": "{\"name\":\"青岛啤酒\"}"
  }
}

大模型通过这种结构化的自然语言文本,告诉 Runtime:“请帮我调用 get_closing_price 函数,参数是青岛啤酒,调用凭证是 call_123456。”

messages.push(response.choices[0].message);

这是最容易出错的一步。 我们必须把大模型发出的这个“工具调用请求”追加到对话历史 messages 数组中。大模型平台(API)有着严格的校验机制,后续工具返回结果时,上下文中必须存在它配对的请求记录,否则整个通信链路会崩塌并报 400 错误。

const args = JSON.parse(tool_calls.function.arguments);
const price = get_closing_price(args.name);

Runtime 闪亮登场。我们将大模型生成的 JSON 字符串参数解析为标准的 JavaScript 对象,拿到 args.name(即“青岛啤酒”),并将其传入本地的实体函数中,成功拿到了股票价格 '67.92'

messages.push({
  role: "tool",
  content: price,
  tool_call_id: tool_calls.id,
});

我们将拿到的真实结果包装成一个角色为 "tool" 的新消息放入上下文,并通过 tool_call_id 声明:“这是针对此前 call_123456 请求的回复。”

const finalRes = await sendMessage(messages);
console.log(finalRes.choices[0].message.content);

最后,我们将包含了【用户初始提问 + 大模型的工具申请 + 传统 Runtime 返回的真实数据】的完整历史记录再次发送给大模型。大模型在充沛的上下文支持下,终于胜券在握,脱离了自言自语的状态,给用户输出最终的自然语言结语:“青岛啤酒的收盘价是 67.92 元。”


五、 总结

通过上述原理剖析与源码实战,我们可以清晰地看到:AI Agent 能够使用工具、操作电脑,并不是因为它衍生出了人类般的自主意识,而是因为开发者在外部环境构建了一套完美的响应机制

大模型负责理解意图、打破自然语言的模糊性,将其转化为高确定性的结构化文本(JSON Schema);而传统的 Runtime 环境则负责各司其职,承接实体函数的执行。正是这两者的完美融合,才编织出了如此令人惊叹的 Agent 智能化错觉。理解了这一底层逻辑,你就拿到了通往高级 AI 应用开发大门的钥匙。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐