告别LLM能力边界!30分钟掌握AI Tools调用核心逻辑
作为开发者,你是否曾困惑:
为什么大模型能查股票价格、查天气?
一个只会“词语接龙”的概率模型,怎么突破虚拟限制调用外部工具?
明明训练数据里没有实时数据,却能返回精准的股票收盘价?
这篇文章,我会用可直接运行的Node.js代码,拆解LLM工具调用的底层逻辑,从0到1实现股票价格查询的工具调用,让你彻底搞懂:
- 工具调用不是“黑魔法”,而是精心设计的交互流程
- 如何用JSON Schema给大模型“植入工具认知”
- 传统代码如何和大模型协作完成任务

一、核心认知:LLM本质是“缸中大脑”
先打破一个误区:大模型没有自我意识。
它本质上只是一个“Next Token Prediction”(下一个词预测)的概率模型,像被困在服务器里的“缸中大脑”——看不见屏幕、摸不到键盘,只能处理文本。
工具调用的核心,是把复杂的软件函数(比如查股票价格),降维成大模型能理解的自然语言说明书,再通过传统代码执行工具逻辑,最后把结果返回给大模型生成最终回答。
二、实战场景:实现股票收盘价查询工具调用
我们以“查询青岛啤酒收盘价”为例,完整实现一次LLM工具调用流程,技术栈:
- Node.js + dotenv(环境变量管理)
- OpenAI SDK(兼容DeepSeek API)
- 自定义工具函数 + 大模型交互逻辑
步骤1:环境准备与依赖安装
首先初始化项目,安装所需依赖:
# 初始化package.json
npm init -y
# 安装依赖
npm install openai dotenv
步骤2:完整可运行代码
创建index.js文件,复制以下代码(记得配置.env文件):
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();
// 初始化DeepSeek客户端(兼容OpenAI SDK)
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: process.env.DEEPSEEK_BASE_URL
});
// 1. 定义工具(给大模型的"使用说明书")
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. 传统软件逻辑:实现工具函数(真实场景可替换为API调用)
function get_closing_price(name) {
if (name === '青岛啤酒') {
return '67.92';
} else if (name === '贵州茅台') {
return '1488.21';
} else {
return '未找到该股票';
}
}
// 3. 封装大模型调用函数
async function sendMessage(messages) {
const res = await client.chat.completions.create({
model: 'deepseek-v4-pro', // 替换为你使用的模型
messages,
tools, // 传入工具定义
tool_choice: 'auto' // 让大模型自动决定是否调用工具
});
return res;
}
// 4. 核心交互逻辑
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));
// 将大模型的响应加入上下文
messages.push({
role: message.role,
content: message.content,
tool_calls: message.tool_calls
});
// 关键判断:如果大模型返回了工具调用指令
if (response.choices[0].message.tool_calls) {
const toolCall = response.choices[0].message.tool_calls[0];
// 处理股票价格查询工具
if (toolCall.function.name === 'get_closing_price') {
// 解析大模型传递的参数
const args = JSON.parse(toolCall.function.arguments);
// 执行传统工具函数,获取结果
const price = get_closing_price(args.name);
console.log('股票收盘价', price);
// 将工具执行结果加入上下文(关键:返回给大模型)
messages.push({
role: 'tool', // 标记为工具返回结果
content: price,
tool_call_id: toolCall.id // 通过ID关联工具调用
});
console.log('更新后完整对话上下文:', messages);
// 第二次调用大模型:基于工具结果生成最终回答
const finalRes = await sendMessage(messages);
console.log('最终模型返回:', finalRes.choices[0].message.content);
} else if (toolCall.function.name === 'get_weather') {
// 扩展:天气查询工具逻辑(可自行实现)
}
}
}
// 执行主函数
main();
步骤3:配置环境变量
创建.env文件,填入你的DeepSeek API信息:
DEEPSEEK_API_KEY=你的DeepSeek API密钥
DEEPSEEK_BASE_URL=DeepSeek API的baseURL(例如:https://api.deepseek.com/v1)
步骤4:运行代码
node index.js
运行后你会看到:
- 大模型先返回工具调用指令(而非直接回答)
- 代码执行
get_closing_price函数获取价格 - 工具结果返回给大模型
- 大模型生成最终的自然语言回答
三、关键拆解:工具调用的3个核心阶段
1. 认知植入:把工具“翻译”成大模型能懂的语言
代码里的tools数组,就是给大模型的“工具使用说明书”,核心是JSON Schema:
name:工具函数名(唯一标识)description:工具用途(大模型靠这个判断是否调用)parameters:参数约束(类型、描述、必传项)
⚠️ 踩坑提醒:
- 描述越具体,大模型调用越精准!比如把“股票名称”改成“股票名称,例如:青岛啤酒、贵州茅台”,能大幅降低参数错误率。
- 参数约束必须严格(比如
required),否则大模型可能漏传参数。
2. 决策阶段:大模型判断是否调用工具
当用户提问“青岛啤酒的收盘价是多少?”,大模型会:
- 检查自身训练数据:没有实时股票数据,无法直接回答
- 匹配工具列表:发现
get_closing_price工具能解决这个问题 - 返回
tool_calls字段:包含要调用的工具名、参数、唯一ID
3. Runtime介入:传统代码执行工具逻辑
这是最关键的“人类兜底”环节:
- 代码解析
tool_calls里的指令 - 调用对应的传统函数(
get_closing_price) - 获取结果后,把结果以
role: tool的形式加入对话上下文 - 再次调用大模型,让它基于工具结果生成自然语言回答
四、踩坑提醒(避坑指南)
-
工具描述模糊导致调用失败
❌ 错误示例:description: "查股票价格"
✅ 正确示例:description: "获取指定A股股票的当日收盘价,参数为股票全称" -
参数解析异常
大模型返回的arguments是字符串,必须用JSON.parse解析,建议加try-catch:let args; try { args = JSON.parse(toolCall.function.arguments); } catch (e) { console.error('参数解析失败:', e); args = {}; } -
上下文管理混乱
每次交互都要把大模型响应、工具结果加入messages数组,否则大模型会“失忆”,无法关联工具结果生成回答。 -
API兼容问题
不同厂商的LLM API(如DeepSeek、OpenAI)对tool_calls的格式略有差异,需根据文档调整。
五、总结
工具调用的本质,是LLM的语言能力 + 传统代码的执行能力的结合:
- 用JSON Schema给大模型“植入工具认知”
- 大模型做“决策”:判断是否调用工具、传什么参数
- 传统代码做“执行”:调用工具、获取结果
- 大模型做“总结”:把工具结果转换成自然语言回答
这套逻辑不仅适用于股票查询,还能扩展到天气查询、Excel分析、网页搜索等场景——这也是AI Agent的核心基础。
最后
本文的完整源码(包含天气查询工具的扩展实现)已整理好,你可以查看仓库获取:[完整源码地址](替换为你的源码地址,若无则注明“私信我获取完整源码”)。
掌握工具调用后,你可以解锁更多场景:让大模型调用API查实时数据、操作数据库、甚至控制硬件设备——这才是AI落地的核心能力。
如果这篇文章对你有帮助,欢迎点赞+收藏,后续会更新“AI Agent操作本地文件”“多工具串联调用”等实战内容!# 告别LLM能力边界!30分钟掌握AI工具调用核心逻辑
作为开发者,你是否曾困惑:
为什么大模型能查股票价格、查天气?
一个只会“词语接龙”的概率模型,怎么突破虚拟限制调用外部工具?
明明训练数据里没有实时数据,却能返回精准的股票收盘价?
这篇文章,我会用可直接运行的Node.js代码,拆解LLM工具调用的底层逻辑,从0到1实现股票价格查询的工具调用,让你彻底搞懂:
- 工具调用不是“黑魔法”,而是精心设计的交互流程
- 如何用JSON Schema给大模型“植入工具认知”
- 传统代码如何和大模型协作完成任务
一、核心认知:LLM本质是“缸中大脑”
先打破一个误区:大模型没有自我意识。
它本质上只是一个“Next Token Prediction”(下一个词预测)的概率模型,像被困在服务器里的“缸中大脑”——看不见屏幕、摸不到键盘,只能处理文本。
工具调用的核心,是把复杂的软件函数(比如查股票价格),降维成大模型能理解的自然语言说明书,再通过传统代码执行工具逻辑,最后把结果返回给大模型生成最终回答。
二、实战场景:实现股票收盘价查询工具调用
我们以“查询青岛啤酒收盘价”为例,完整实现一次LLM工具调用流程,技术栈:
- Node.js + dotenv(环境变量管理)
- OpenAI SDK(兼容DeepSeek API)
- 自定义工具函数 + 大模型交互逻辑
步骤1:环境准备与依赖安装
首先初始化项目,安装所需依赖:
# 初始化package.json
npm init -y
# 安装依赖
npm install openai dotenv
步骤2:完整可运行代码
创建index.js文件,复制以下代码(记得配置.env文件):
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();
// 初始化DeepSeek客户端(兼容OpenAI SDK)
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: process.env.DEEPSEEK_BASE_URL
});
// 1. 定义工具(给大模型的"使用说明书")
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. 传统软件逻辑:实现工具函数(真实场景可替换为API调用)
function get_closing_price(name) {
if (name === '青岛啤酒') {
return '67.92';
} else if (name === '贵州茅台') {
return '1488.21';
} else {
return '未找到该股票';
}
}
// 3. 封装大模型调用函数
async function sendMessage(messages) {
const res = await client.chat.completions.create({
model: 'deepseek-v4-pro', // 替换为你使用的模型
messages,
tools, // 传入工具定义
tool_choice: 'auto' // 让大模型自动决定是否调用工具
});
return res;
}
// 4. 核心交互逻辑
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));
// 将大模型的响应加入上下文
messages.push({
role: message.role,
content: message.content,
tool_calls: message.tool_calls
});
// 关键判断:如果大模型返回了工具调用指令
if (response.choices[0].message.tool_calls) {
const toolCall = response.choices[0].message.tool_calls[0];
// 处理股票价格查询工具
if (toolCall.function.name === 'get_closing_price') {
// 解析大模型传递的参数
const args = JSON.parse(toolCall.function.arguments);
// 执行传统工具函数,获取结果
const price = get_closing_price(args.name);
console.log('股票收盘价', price);
// 将工具执行结果加入上下文(关键:返回给大模型)
messages.push({
role: 'tool', // 标记为工具返回结果
content: price,
tool_call_id: toolCall.id // 通过ID关联工具调用
});
console.log('更新后完整对话上下文:', messages);
// 第二次调用大模型:基于工具结果生成最终回答
const finalRes = await sendMessage(messages);
console.log('最终模型返回:', finalRes.choices[0].message.content);
} else if (toolCall.function.name === 'get_weather') {
// 扩展:天气查询工具逻辑(可自行实现)
}
}
}
// 执行主函数
main();
步骤3:配置环境变量
创建.env文件,填入你的DeepSeek API信息:
DEEPSEEK_API_KEY=你的DeepSeek API密钥
DEEPSEEK_BASE_URL=DeepSeek API的baseURL(例如:https://api.deepseek.com/v1)
步骤4:运行代码
node index.js
运行后你会看到:
- 大模型先返回工具调用指令(而非直接回答)
- 代码执行
get_closing_price函数获取价格 - 工具结果返回给大模型
- 大模型生成最终的自然语言回答
三、关键拆解:工具调用的3个核心阶段
1. 认知植入:把工具“翻译”成大模型能懂的语言
代码里的tools数组,就是给大模型的“工具使用说明书”,核心是JSON Schema:
name:工具函数名(唯一标识)description:工具用途(大模型靠这个判断是否调用)parameters:参数约束(类型、描述、必传项)
⚠️ 踩坑提醒:
- 描述越具体,大模型调用越精准!比如把“股票名称”改成“股票名称,例如:青岛啤酒、贵州茅台”,能大幅降低参数错误率。
- 参数约束必须严格(比如
required),否则大模型可能漏传参数。
2. 决策阶段:大模型判断是否调用工具
当用户提问“青岛啤酒的收盘价是多少?”,大模型会:
- 检查自身训练数据:没有实时股票数据,无法直接回答
- 匹配工具列表:发现
get_closing_price工具能解决这个问题 - 返回
tool_calls字段:包含要调用的工具名、参数、唯一ID
3. Runtime介入:传统代码执行工具逻辑
这是最关键的“人类兜底”环节:
- 代码解析
tool_calls里的指令 - 调用对应的传统函数(
get_closing_price) - 获取结果后,把结果以
role: tool的形式加入对话上下文 - 再次调用大模型,让它基于工具结果生成自然语言回答

四、踩坑提醒(避坑指南)
-
工具描述模糊导致调用失败
❌ 错误示例:description: "查股票价格"
✅ 正确示例:description: "获取指定A股股票的当日收盘价,参数为股票全称" -
参数解析异常
大模型返回的arguments是字符串,必须用JSON.parse解析,建议加try-catch:let args; try { args = JSON.parse(toolCall.function.arguments); } catch (e) { console.error('参数解析失败:', e); args = {}; } -
上下文管理混乱
每次交互都要把大模型响应、工具结果加入messages数组,否则大模型会“失忆”,无法关联工具结果生成回答。 -
API兼容问题
不同厂商的LLM API(如DeepSeek、OpenAI)对tool_calls的格式略有差异,需根据文档调整。
五、总结
工具调用的本质,是LLM的语言能力 + 传统代码的执行能力的结合:
- 用JSON Schema给大模型“植入工具认知”
- 大模型做“决策”:判断是否调用工具、传什么参数
- 传统代码做“执行”:调用工具、获取结果
- 大模型做“总结”:把工具结果转换成自然语言回答
这套逻辑不仅适用于股票查询,还能扩展到天气查询、Excel分析、网页搜索等场景——这也是AI Agent的核心基础。
最后
本文的完整源码(包含天气查询工具的扩展实现)已整理好,你可以查看仓库获取:[Knowledge_Repository/ai/agent/tool_use at main · Guwen-yue/Knowledge_Repository](替换为你的源码地址,若无则注明“私信我获取完整源码”)。
掌握工具调用后,你可以解锁更多场景:让大模型调用API查实时数据、操作数据库、甚至控制硬件设备——这才是AI落地的核心能力。
如果这篇文章对你有帮助,欢迎点赞+收藏,后续会更新“AI Agent操作本地文件”“多工具串联调用”等实战内容!
更多推荐


所有评论(0)