Appearance
API 调用与 Function Calling
本附录讲解如何用代码直接调用 AI API。当你想让 AI 融入自动化流程、构建 Agent、或做 AI 驱动的应用时,聊天界面就不够用了,你需要直接和 API 打交道。
这一章用 JavaScript 写例子。你不需要是 JavaScript 专家,能看懂基本语法就行。
准备工作
使用 OpenAI 的 API 之前,你需要:
- 注册账号并获取 API Key。
- 安装官方 SDK(推荐),或者直接用 fetch 调用。
bash
npm install openaiAPI Key 不要硬编码在代码里,用环境变量管理:
bash
export OPENAI_API_KEY="sk-xxxx"国内模型(豆包、Kimi、DeepSeek、Qwen)的 API 结构和 OpenAI 兼容,换一个 baseURL 就行。
方式一:用 OpenAI SDK
SDK 封装了 HTTP 请求、错误处理、流式输出等细节,推荐在正式项目中使用。
基本对话
javascript
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{ role: "system", content: "你是一个有用的助手。" },
{ role: "user", content: "用一句话解释什么是 API。" },
],
});
console.log(response.choices[0].message.content);SDK 会自动处理认证头、JSON 序列化、错误重试等。你只需要关注业务逻辑。
流式输出
javascript
const stream = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "写一首短诗。" }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) process.stdout.write(content);
}流式输出让前端可以逐字显示结果,ChatGPT 的“打字机”效果就是这么实现的。
传入图片
支持视觉输入的模型可以同时接收文字和图片。消息里的 content 不再只是字符串,而是一个内容数组:一段文字说明,加上一张或多张图片。
javascript
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "user",
content: [
{
type: "text",
text: "请描述这张图,并指出里面最重要的三个信息。",
},
{
type: "image_url",
image_url: {
url: "https://example.com/dashboard.png",
},
},
],
},
],
});
console.log(response.choices[0].message.content);如果图片在本地,可以把它转成 Base64,再作为 Data URL 传入:
javascript
import { readFile } from "node:fs/promises";
const imageBuffer = await readFile("screenshot.png");
const base64Image = imageBuffer.toString("base64");
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "user",
content: [
{ type: "text", text: "这张截图里的报错可能是什么原因?" },
{
type: "image_url",
image_url: {
url: `data:image/png;base64,${base64Image}`,
},
},
],
},
],
});
console.log(response.choices[0].message.content);这种调用适合处理截图分析、图表解读、设计稿反馈、资料整理等任务。它和图像生成不同:这里不是让模型画图,而是让模型读取图片并回答问题。
使用国内模型
国内模型大多兼容 OpenAI 格式,只需要换 baseURL:
javascript
// DeepSeek
const deepseek = new OpenAI({
baseURL: "https://api.deepseek.com",
apiKey: process.env.DEEPSEEK_API_KEY,
});
// 通义千问
const qwen = new OpenAI({
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
apiKey: process.env.QWEN_API_KEY,
});
// 用法和 OpenAI 完全一样
const response = await deepseek.chat.completions.create({
model: "deepseek-chat",
messages: [{ role: "user", content: "你好" }],
});方式二:用 fetch 直接调用
如果你不想装 SDK,或者想理解底层原理,可以直接发 HTTP 请求:
javascript
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "用一句话解释什么是 API。" }],
}),
});
const data = await response.json();
console.log(data.choices[0].message.content);SDK 和 fetch 的关系:SDK 是对 fetch 的封装。理解 fetch 能帮你理解 SDK 在做什么,但日常开发用 SDK 更方便。
推理模式
推理模型(如 o1、o3)在回答之前会进行内部思考。这个过程会消耗额外的 token,但能显著提升复杂任务的表现。
基本用法
javascript
const response = await client.chat.completions.create({
model: "o3",
messages: [
{ role: "user", content: "分析这段代码的时间复杂度,并给出优化方案" }
],
});
console.log(response.choices[0].message.content);推理模型会自动进行内部推理,你不需要额外配置。
控制推理深度
通过 reasoning_effort 参数,你可以控制模型推理的深度:
javascript
const response = await client.chat.completions.create({
model: "o3",
reasoning_effort: "medium", // low / medium / high
messages: [
{ role: "user", content: "解释快速排序的时间复杂度" }
],
});low:快速推理,适合简单问题。medium:平衡推理深度和速度(默认)。high:深度推理,适合复杂问题,但消耗更多 token。
提醒:推理模型的 token 价格通常更高。对于简单任务,用普通模型(如 gpt-4o)更划算。
生成参数
模型生成文本时,有几个参数可以控制输出的特性。这些参数不影响模型"理解"问题的能力,但会影响它"怎么回答"。
temperature
temperature 控制输出的随机性,取值范围通常是 0 到 2。
- 低 temperature(如 0):输出更确定、更集中。每次问同样的问题,得到的回答会很相似。适合需要一致性和准确性的场景,比如代码生成、数据提取。
- 高 temperature(如 0.8):输出更随机、更多样。适合创意写作、头脑风暴等需要多样性的场景。
javascript
// 低 temperature:确定性输出
const response = await client.chat.completions.create({
model: "gpt-4o",
temperature: 0,
messages: [{ role: "user", content: "写一个计算斐波那契数列的函数" }],
});
// 高 temperature:创意输出
const response = await client.chat.completions.create({
model: "gpt-4o",
temperature: 0.8,
messages: [{ role: "user", content: "写一首关于编程的诗" }],
});top_p
top_p(nucleus sampling)是另一种控制随机性的方式。它从概率最高的词开始累加,直到累积概率达到 top_p,然后只从这些词中选择。
top_p = 1:考虑所有可能的词(默认行为)。top_p = 0.9:只从累积概率前 90% 的词中选择,过滤掉最不可能的词。
javascript
const response = await client.chat.completions.create({
model: "gpt-4o",
top_p: 0.9,
messages: [{ role: "user", content: "解释量子计算" }],
});提醒:通常不需要同时调整
temperature和top_p。选择其中一个调整即可。大多数情况下,使用默认值就好。
什么时候需要调整这些参数?
大多数应用场景下,默认参数就够用了。以下是一些可能需要调整的场景:
- 需要高度一致的输出:把
temperature设为 0。适合代码生成、格式化输出、数据提取。 - 需要创意多样性:适当提高
temperature(如 0.7-0.9)。适合创意写作、生成多种方案。 - 需要过滤低概率输出:降低
top_p(如 0.9)。适合需要输出更"安全"的场景。
提醒:Agent 框架通常会帮你管理这些参数,你不需要手动设置。但理解这些参数有助于你调试 Agent 的行为——如果 Agent 的输出太随机或太死板,你可能需要调整这些参数。
Token 管理与成本
API 调用按 Token 计费。Token 是模型处理文本的最小单位,英文大约 1 个单词 ≈ 1 个 Token,中文大约 1 个字 ≈ 1.5-2 个 Token。
控制成本的方法:
- 控制输入长度:只给必要的上下文,不要把整本书塞进去。
- 控制输出长度:用 max_tokens 参数限制回复长度。
- 监控消耗:API 返回里包含 usage 字段。
javascript
const response = await client.chat.completions.create({
model: "gpt-4o",
max_tokens: 500, // 限制输出长度
messages: [{ role: "user", content: "简要介绍 JavaScript。" }],
});
console.log(`输入: ${response.usage.prompt_tokens} tokens`);
console.log(`输出: ${response.usage.completion_tokens} tokens`);
console.log(`总计: ${response.usage.total_tokens} tokens`);不同模型价格差异很大。简单任务用便宜模型(如 gpt-4o-mini),复杂任务再用贵的模型。
Embedding API:文本转向量
Embedding 把文本转换成一组数字(向量),用于语义搜索、聚类、相似度比较。这是 RAG 的基础。
javascript
const embedding = await client.embeddings.create({
model: "text-embedding-3-small",
input: "什么是机器学习?",
});
console.log(embedding.data[0].embedding); // 一个 1536 维的向量
console.log(embedding.usage.total_tokens); // 消耗的 Token 数批量处理多段文本:
javascript
const texts = [
"什么是机器学习?",
"深度学习和机器学习有什么区别?",
"今天天气真好。",
];
const embeddings = await client.embeddings.create({
model: "text-embedding-3-small",
input: texts,
});
// 返回的向量数组,可以用于相似度计算
for (const item of embeddings.data) {
console.log(`文本 ${item.index}: ${item.embedding.slice(0, 5)}...`);
}计算两个向量的余弦相似度:
javascript
function cosineSimilarity(a, b) {
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
const emb1 = embeddings.data[0].embedding;
const emb2 = embeddings.data[1].embedding;
const emb3 = embeddings.data[2].embedding;
console.log(cosineSimilarity(emb1, emb2)); // 接近 1(语义相似)
console.log(cosineSimilarity(emb1, emb3)); // 接近 0(语义无关)“什么是机器学习”和“深度学习和机器学习有什么区别”的相似度会很高,因为它们讨论的是相关话题。而“今天天气真好”和前两个的相似度会很低。
Image API:图像生成
用代码调用图像生成 API:
javascript
const image = await client.images.generate({
model: "gpt-image-1",
prompt: "一只橘猫坐在书桌上,旁边有一杯咖啡,水彩画风格",
size: "1024x1024",
});
console.log(image.data[0].url); // 生成图片的 URL图片通常以 URL 返回,你可以下载保存:
javascript
const imageUrl = image.data[0].url;
const buffer = await fetch(imageUrl).then((r) => r.arrayBuffer());
await fs.writeFile("cat.png", Buffer.from(buffer));用参考图进行编辑(Image Edit):
javascript
const edit = await client.images.edit({
model: "gpt-image-1",
image: fs.createReadStream("original.png"),
prompt: "把背景换成海滩",
});提醒:图像生成 API 的成本比文本 API 高得多。生成一张图的费用可能是几百次文本对话的总和。开发调试时用小尺寸,确认效果后再用大尺寸。
Audio API:语音识别
语音识别(ASR)的输入是音频文件,输出是文字。常见用途包括会议纪要、播客转写、视频字幕、语音笔记整理。
用 Whisper 转写音频:
javascript
import fs from "node:fs";
const transcript = await client.audio.transcriptions.create({
model: "whisper-1",
file: fs.createReadStream("meeting.mp3"),
language: "zh",
});
console.log(transcript.text);如果你想直接得到字幕格式,可以指定 response_format:
javascript
const subtitles = await client.audio.transcriptions.create({
model: "whisper-1",
file: fs.createReadStream("meeting.mp3"),
language: "zh",
response_format: "srt",
});
console.log(subtitles);语音识别的结果通常还需要后处理。比如分段、加标点、区分说话人、提取行动项,这些步骤可以继续交给文本模型完成。
Function Calling:让模型调用函数
Function Calling 让模型能调用你定义的函数。这是 Agent “使用工具”的底层实现。
第一步:定义函数的 Schema
javascript
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "获取指定城市的天气信息",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "城市名称,如'北京'" },
},
required: ["city"],
},
},
},
];第二步:发送请求,处理函数调用
javascript
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "北京今天天气怎么样?" }],
tools,
});
const message = response.choices[0].message;
if (message.tool_calls) {
const toolCall = message.tool_calls[0];
const args = JSON.parse(toolCall.function.arguments);
// 执行你自己的函数
const result = await getWeather(args.city);
// 把结果发回给模型
const finalResponse = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{ role: "user", content: "北京今天天气怎么样?" },
message,
{ role: "tool", tool_call_id: toolCall.id, content: JSON.stringify(result) },
],
tools,
});
console.log(finalResponse.choices[0].message.content);
}整个流程:用户提问 → 模型决定调用函数 → 你执行函数 → 把结果返回 → 模型生成最终回答。
这就是 Agent “使用工具”的底层实现。当你理解了这个流程,再回头看 Agent 的 Tool Use 和 Loop,就会明白它们是怎么工作的。
错误处理
API 调用可能失败。SDK 内置了一些重试机制,但你仍然需要处理异常:
javascript
import OpenAI from "openai";
const client = new OpenAI({ maxRetries: 3 });
try {
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "你好" }],
});
console.log(response.choices[0].message.content);
} catch (error) {
if (error.status === 429) {
console.error("请求太频繁,稍后再试");
} else if (error.status === 401) {
console.error("API Key 无效");
} else {
console.error(`请求失败: ${error.message}`);
}
}常见错误:
- 429 Too Many Requests:被限流了,SDK 会自动重试(指数退避)。
- 401 Unauthorized:API Key 无效或过期。
- 500 Server Error:服务端出错,通常重试就好。
小结
- SDK 封装了底层细节,推荐在正式项目中使用。fetch 调用帮你理解底层原理。
- 国内模型大多兼容 OpenAI 格式,换 baseURL 就行。
- 推理模型会自动进行内部思考,
reasoning_effort参数控制推理深度。 - 流式传输让前端可以逐字显示结果,改善用户体验。
temperature和top_p控制输出的随机性,大多数情况下使用默认值即可。- Token 决定了成本,控制输入输出长度是基本功。
- Embedding API 把文本变成向量,是 RAG 和语义搜索的基础。
- 支持视觉输入的模型可以通过 Chat Completions 接收图片,用于截图分析、图表解读和设计反馈。
- Image API 调用图像生成,成本比文本 API 高得多。
- Audio API 可以用 Whisper 把语音转成文字,再交给文本模型做整理和总结。
- Function Calling 是 Agent “使用工具”的底层实现。
练习
- 用 OpenAI SDK 写一个最简单的调用:发一条消息,打印回复。
- 用 Embedding API 把三段文本转成向量,计算它们两两之间的余弦相似度。
- 用 Chat Completions 传入一张截图,让模型解释截图里的主要信息。
- 用 Image API 生成一张图片,保存到本地。
- 用 Whisper 转写一段短音频,再让文本模型总结成三条要点。
- 实现一个完整的 Function Calling 流程:定义一个“查询股票价格”的函数,让模型在用户问到股票时自动调用它。