1. 从零开始:认识千帆大模型平台与API
如果你对AI大模型感兴趣,想自己动手做一些智能应用,比如做个聊天机器人、写个智能客服,或者让程序帮你自动生成文案,那么百度智能云的千帆大模型平台绝对是一个值得你花时间研究的“宝藏”。我自己在接触各种AI服务时,发现千帆平台的一个巨大优势:它把国内多个顶尖的大模型,比如文心一言、ChatGLM等,都集成在了一个统一的平台上,并且提供了非常清晰、标准的API接口。这意味着,你不需要分别去研究每个模型的复杂接入方式,只需要学会调用千帆的一套API,就能根据你的需求,灵活选择背后最适合的模型来驱动你的应用。
简单来说,千帆平台就像是一个功能强大的“AI模型超市”。你作为开发者,不需要自己去训练和维护一个动辄需要几百张GPU、成本高昂的大模型,你只需要通过API这个“购物车”,按需调用超市里已经准备好的、开箱即用的模型能力。无论是文本生成、对话、内容理解还是代码编写,你都能找到对应的“商品”。而我们要做的,就是学会如何使用这个超市的“购物流程”——也就是API调用。
这个过程听起来技术性很强,但实际操作起来,比你想象的要简单得多。核心流程可以概括为四步:创建应用、获取密钥、拿到访问凭证、发起调用。无论你用Node.js写后端服务,用Python做数据分析脚本,还是用Golang构建高性能应用,这个流程都是相通的。接下来,我就以这三种最流行的编程语言为例,带你完整走一遍这个流程,把每一步的细节、可能遇到的“坑”以及我的实战经验都分享给你,保证你看完就能上手操作。
2. 准备工作:创建应用与获取密钥
在写任何代码之前,我们得先在千帆平台上“注册”一下,拿到我们身份的“钥匙”。这个过程完全在网页上完成,不需要写代码。
首先,打开浏览器,访问千帆大模型平台的官方网站。在首页你就能找到登录入口,使用你的百度账号登录即可。登录后,你会进入控制台界面。这里就是管理你所有AI应用的大本营。
找到“应用管理”或类似的菜单,点击“创建应用”。你需要给应用起个名字,比如“我的第一个AI助手”,描述可以简单写一下用途,比如“用于测试多语言API调用”。创建时,平台可能会让你选择需要调用的模型范围,对于新手,我建议直接选择“默认”或“全部模型”,这样后续调用时选择面更广。创建成功后,页面会刷新,并展示你这个应用的详细信息。
这里有两个关键信息你需要像保存密码一样妥善保管:API Key 和 Secret Key。它们通常显示为两长串字符。你可以把它们理解成用户名和密码的组合。API Key是公开的,用于标识你的应用身份;而Secret Key是绝密的,用于生成临时访问令牌,千万不能泄露。在后续的代码里,我们会用到它们。平台通常也会提供一个AppID,但在基础的API鉴权中,我们主要使用前面两个Key。
有个好消息是,在千帆平台,应用创建成功后,默认就拥有了调用平台内大多数API的权限,不需要你再额外去申请授权。这省去了很多麻烦。准备工作到此就完成了,接下来我们进入实战的代码环节。
3. 核心第一步:获取Access Token
拿到了API Key和Secret Key,我们并不能直接用它们去调用对话、生成等模型API。百度云的服务通常采用一种叫OAuth 2.0 Client Credentials的授权模式。我们需要用刚才的密钥对,去换取一个短期的“通行证”,这个通行证就是access_token。这个access_token通常有效期为30天,我们需要在代码里定期刷新它。
获取access_token的接口地址是固定的,这是一个标准的HTTP POST请求。它的原理很简单:把你的API Key当作客户端ID(client_id),Secret Key当作客户端密钥(client_secret),以特定的格式发送给百度的鉴权服务器,服务器验证通过后,就会返回一个包含access_token的JSON数据。
下面,我分别用Node.js、Python和Golang来实现这个步骤,你可以对比着看,理解不同语言下的实现逻辑是多么相似。
3.1 使用Python获取Token
Python以其简洁易读著称,我们用最常用的requests库来实现。首先确保安装了它:pip install requests。
import requests
import json
# 替换成你在千帆控制台获取的真实密钥
API_KEY = "你的API Key"
SECRET_KEY = "你的Secret Key"
def get_access_token():
"""
使用 API Key 和 Secret Key 获取 access_token
"""
url = "https://aip.baidubce.com/oauth/2.0/token"
params = {
"grant_type": "client_credentials",
"client_id": API_KEY,
"client_secret": SECRET_KEY
}
# 发送POST请求,数据以x-www-form-urlencoded格式编码
response = requests.post(url, params=params)
if response.status_code == 200:
result = response.json()
# 从返回的JSON中提取access_token
access_token = result.get("access_token")
if access_token:
print(f"获取access_token成功: {access_token[:20]}...") # 只打印前20位
return access_token
else:
print("响应中未找到access_token字段")
return None
else:
print(f"请求失败,状态码: {response.status_code}, 响应: {response.text}")
return None
# 测试获取
if __name__ == "__main__":
token = get_access_token()
if token:
# 在实际项目中,你可以将token缓存起来,避免频繁请求
# 例如存入文件、数据库或内存缓存,并在过期前刷新
print("Token获取流程完毕,可以用于后续API调用。")
这段代码非常直白。我们构造了请求参数,发送POST请求,然后解析返回的JSON。这里我加了一些简单的错误处理和日志打印,在实际开发中你可能需要更完善的异常处理机制。拿到access_token后,通常我们会把它缓存起来,比如放在一个全局变量或者文件里,因为同一个token在有效期内可以重复使用,没必要每次调用模型API都去申请一次。
3.2 使用Node.js获取Token
Node.js环境下,我们可以使用原生的https模块,或者更流行的axios库。这里我用axios来演示,因为它语法更友好。先安装:npm install axios。
const axios = require('axios');
const qs = require('querystring'); // Node内置模块,用于格式化表单数据
// 替换成你在千帆控制台获取的真实密钥
const API_KEY = '你的API Key';
const SECRET_KEY = '你的Secret Key';
/**
* 获取千帆平台的access_token
* @returns {Promise<string>} 返回access_token字符串
*/
async function getAccessToken() {
const url = 'https://aip.baidubce.com/oauth/2.0/token';
// 鉴权请求要求参数以 application/x-www-form-urlencoded 格式发送
const params = new URLSearchParams();
params.append('grant_type', 'client_credentials');
params.append('client_id', API_KEY);
params.append('client_secret', SECRET_KEY);
try {
const response = await axios.post(url, params.toString(), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
if (response.data && response.data.access_token) {
const token = response.data.access_token;
console.log(`获取access_token成功: ${token.substring(0, 20)}...`);
return token;
} else {
throw new Error('响应中未找到access_token字段');
}
} catch (error) {
console.error('获取access_token失败:', error.message);
// 可以根据error.response.status做更细致的错误处理
if (error.response) {
console.error('错误详情:', error.response.data);
}
throw error; // 将错误向上抛,由调用者处理
}
}
// 异步函数立即执行,用于测试
(async () => {
try {
const token = await getAccessToken();
console.log('Token获取成功,准备进行模型调用。');
// 这里可以将token存储起来,例如使用全局变量或缓存模块
// global.accessToken = token;
} catch (err) {
console.error('测试流程失败:', err);
}
})();
注意,我们使用了URLSearchParams来构建表单格式的数据体,并设置了正确的Content-Type请求头。这是符合OAuth 2.0客户端模式的标准做法。在Node.js的异步世界里,使用async/await可以让代码逻辑看起来更清晰,就像同步代码一样。
3.3 使用Golang获取Token
Golang以高性能和简洁的语法受到后端开发者喜爱。我们使用标准库的net/http和strings等包来完成请求。
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
// 请替换为你的实际密钥
const (
apiKey = "你的API Key"
secretKey = "你的Secret Key"
)
// getAccessToken 获取鉴权令牌
func getAccessToken() (string, error) {
authURL := "https://aip.baidubce.com/oauth/2.0/token"
// 构建表单数据
formData := url.Values{}
formData.Set("grant_type", "client_credentials")
formData.Set("client_id", apiKey)
formData.Set("client_secret", secretKey)
// 创建HTTP POST请求
req, err := http.NewRequest("POST", authURL, strings.NewReader(formData.Encode()))
if err != nil {
return "", fmt.Errorf("创建请求失败: %v", err)
}
// 设置请求头
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("发送请求失败: %v", err)
}
defer resp.Body.Close() // 确保关闭响应体
// 读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应失败: %v", err)
}
// 检查HTTP状态码
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("鉴权服务器返回错误状态码: %d, 响应: %s", resp.StatusCode, string(body))
}
// 解析JSON响应
var result map[string]interface{}
if err := json.Unmarshal(body, &result); err != nil {
return "", fmt.Errorf("解析JSON响应失败: %v", err)
}
// 提取access_token
token, ok := result["access_token"].(string)
if !ok {
return "", fmt.Errorf("响应中缺少access_token字段或类型错误")
}
fmt.Printf("获取access_token成功: %s...\n", token[:20]) // 打印前20位
return token, nil
}
func main() {
token, err := getAccessToken()
if err != nil {
fmt.Printf("获取token失败: %v\n", err)
return
}
fmt.Println("Access Token 已就绪,可用于API调用。")
// 在实际应用中,应将token保存到结构体或全局变量中供后续使用
// 并考虑实现一个带缓存的Token管理机制,避免频繁请求。
}
Golang的代码看起来步骤稍多,因为它错误处理非常明确。每一步操作后都检查错误,这是Go语言的哲学,能让你写出更健壮的程序。我们同样构建了表单数据,发送请求,然后解析JSON。拿到access_token后,就完成了最关键的身份认证环节。
4. 实战调用:让大模型回答你的问题
拿到了“通行证”(access_token),我们就可以真正去调用大模型的能力了。千帆平台提供了多个模型端点(Endpoint),我们以最常用的聊天补全接口为例,它对应的是文心一言等模型的对话能力。接口地址的基本格式是:https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=YOUR_TOKEN
你需要将YOUR_TOKEN替换为上一步获取的真实access_token。请求体是一个JSON对象,其中messages字段是核心,它包含一个由对话角色(role)和内容(content)组成的数组。通常,我们从用户(user)的一条消息开始。
4.1 Python调用聊天接口
我们继续用Python的requests库,这次是调用另一个接口。
def call_chat_completion(access_token, question):
"""
调用千帆平台的聊天补全接口
:param access_token: 上一步获取的访问令牌
:param question: 用户提出的问题
:return: 模型返回的回复内容
"""
url = f"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token={access_token}"
# 构造请求数据
payload = {
"messages": [
{
"role": "user",
"content": question
}
],
# 以下是一些可调参数,用于控制模型生成行为
"temperature": 0.7, # 温度,控制随机性 (0-1],值越高越随机
"top_p": 0.8, # 核采样,控制词汇选择的集中度
"penalty_score": 1.0, # 重复惩罚,降低重复生成的可能
"stream": False # 是否使用流式输出,False为一次性返回
}
headers = {
'Content-Type': 'application/json'
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status() # 如果状态码不是200,抛出HTTPError异常
result = response.json()
# 解析返回结果。不同模型的返回结构可能略有差异,这里是通用格式
if "result" in result:
return result["result"]
elif "choices" in result and len(result["choices"]) > 0:
# 有些接口格式可能类似OpenAI,返回在choices里
return result["choices"][0]["message"]["content"]
else:
print("无法解析的响应结构:", result)
return None
except requests.exceptions.RequestException as e:
print(f"请求接口时发生错误: {e}")
return None
except json.JSONDecodeError as e:
print(f"解析响应JSON时发生错误: {e}")
return None
# 整合前两步,完成一个完整的问答流程
if __name__ == "__main__":
# 1. 获取Token
token = get_access_token()
if not token:
print("无法获取Token,程序退出。")
exit(1)
# 2. 调用聊天接口
user_question = "用简单的语言解释一下什么是机器学习?"
print(f"正在向AI提问: {user_question}")
answer = call_chat_completion(token, user_question)
if answer:
print("\n--- AI的回答 ---")
print(answer)
print("-----------------")
else:
print("未能获得有效回答。")
这段代码定义了一个通用的调用函数。我添加了几个常用的参数:temperature(创造性)、top_p(多样性)和penalty_score(防重复)。你可以根据实际需求调整它们。最后,我们把获取Token和调用接口的流程串联起来,形成了一个完整的从提问到获取答案的脚本。
4.2 Node.js调用聊天接口
在Node.js中,我们继续使用axios来调用聊天接口。
/**
* 调用千帆聊天补全API
* @param {string} accessToken - 访问令牌
* @param {string} userMessage - 用户消息
* @returns {Promise<string>} - AI的回复内容
*/
async function callChatAPI(accessToken, userMessage) {
const url = `https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=${accessToken}`;
const requestData = {
messages: [
{
role: "user",
content: userMessage
}
],
temperature: 0.7,
top_p: 0.8,
penalty_score: 1.0,
stream: false
};
try {
const response = await axios.post(url, requestData, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
const data = response.data;
// 处理响应,适配可能的返回格式
if (data.result) {
return data.result;
} else if (data.choices && data.choices.length > 0) {
return data.choices[0].message.content;
} else {
console.warn('未知的响应格式:', JSON.stringify(data, null, 2));
throw new Error('无法从响应中提取回复内容');
}
} catch (error) {
console.error('调用聊天API失败:');
if (error.response) {
// 服务器返回了错误状态码 (4xx, 5xx)
console.error('状态码:', error.response.status);
console.error('响应数据:', error.response.data);
} else if (error.request) {
// 请求已发出但没有收到响应
console.error('未收到响应,请检查网络。');
} else {
// 请求配置出错
console.error('请求配置错误:', error.message);
}
throw error;
}
}
// 完整的示例流程
(async () => {
try {
console.log('开始千帆API调用示例...');
// 1. 获取Token
const token = await getAccessToken();
console.log('Token获取成功。');
// 2. 准备问题并调用
const question = "Node.js有哪些优势适合后端开发?";
console.log(`提问: ${question}`);
const answer = await callChatAPI(token, question);
console.log('\n--- AI回复 ---');
console.log(answer);
console.log('---------------');
} catch (error) {
console.error('流程执行出错:', error.message);
}
})();
Node.js的异步特性让整个流程可以很优雅地用async/await串联。错误处理部分我写得比较详细,区分了网络错误、服务器错误等不同情况,这在调试时非常有用。实际开发中,你可能还需要考虑设置请求超时、重试机制等。
4.3 Golang调用聊天接口
最后,我们看看Golang如何实现模型调用。逻辑是相通的:构造请求体,设置Header,发送POST请求,解析响应。
// callChatModel 调用千帆聊天模型
func callChatModel(accessToken, userInput string) (string, error) {
apiURL := fmt.Sprintf("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=%s", accessToken)
// 构造请求体结构
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type RequestBody struct {
Messages []Message `json:"messages"`
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"top_p,omitempty"`
PenaltyScore float64 `json:"penalty_score,omitempty"`
Stream bool `json:"stream,omitempty"`
}
reqBody := RequestBody{
Messages: []Message{
{Role: "user", Content: userInput},
},
Temperature: 0.7,
TopP: 0.8,
PenaltyScore: 1.0,
Stream: false,
}
// 将结构体序列化为JSON字节
jsonData, err := json.Marshal(reqBody)
if err != nil {
return "", fmt.Errorf("序列化请求体失败: %v", err)
}
// 创建HTTP请求
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Content-Type", "application/json")
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("发送请求失败: %v", err)
}
defer resp.Body.Close()
// 读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应体失败: %v", err)
}
// 检查HTTP状态
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("API调用失败,状态码: %d, 响应: %s", resp.StatusCode, string(body))
}
// 解析响应JSON
var response map[string]interface{}
if err := json.Unmarshal(body, &response); err != nil {
return "", fmt.Errorf("解析响应JSON失败: %v", err)
}
// 尝试从不同可能的字段中提取结果
if result, ok := response["result"].(string); ok {
return result, nil
}
// 如果返回格式是choices数组(兼容OpenAI格式)
if choices, ok := response["choices"].([]interface{}); ok && len(choices) > 0 {
if firstChoice, ok := choices[0].(map[string]interface{}); ok {
if message, ok := firstChoice["message"].(map[string]interface{}); ok {
if content, ok := message["content"].(string); ok {
return content, nil
}
}
}
}
return "", fmt.Errorf("无法从响应中提取文本内容,响应体: %s", string(body))
}
func main() {
// 1. 获取Access Token
token, err := getAccessToken()
if err != nil {
fmt.Printf("初始化失败,无法获取Token: %v\n", err)
return
}
// 2. 调用聊天模型
question := "Golang在并发编程上有什么特点?"
fmt.Printf("提问: %s\n", question)
reply, err := callChatModel(token, question)
if err != nil {
fmt.Printf("调用模型失败: %v\n", err)
return
}
fmt.Println("\n--- AI回复 ---")
fmt.Println(reply)
fmt.Println("--------------")
}
Golang是静态类型语言,所以我们先定义了请求体和消息的结构体,这能让代码更清晰,也便于编译器检查。在解析响应时,我处理了两种可能的返回格式(千帆原生格式和类OpenAI格式),提高了代码的兼容性。这种显式的类型断言和错误检查是Go的典型风格,虽然代码量稍多,但运行起来非常可靠。
5. 进阶技巧与避坑指南
走通了基本流程,你可能已经成功让AI回答了几个问题。但在实际项目开发中,仅仅会调用是远远不够的。下面我分享几个进阶技巧和容易踩坑的地方,这些经验很多是我在项目中真金白银换来的。
第一,一定要管理好你的Token生命周期。 access_token有有效期(通常是30天),但并不意味着你可以获取一次就用到底。网络波动、服务重启都可能导致Token丢失。一个健壮的做法是:实现一个简单的Token管理模块。这个模块在启动时尝试从缓存(比如文件、Redis)读取Token,如果不存在或已过期(你可以记录获取时间并判断),则重新向千帆平台申请,然后将新的Token缓存起来。在Python中,你可以用cachetools库;在Node.js中,可以用node-cache;在Golang中,可以使用sync.Map或第三方缓存库。核心思想就是避免不必要的重复鉴权请求。
第二,理解并善用模型参数。 我在代码示例中用了temperature、top_p和penalty_score。这几个参数对生成结果影响巨大:
temperature(温度):值越高(接近1),模型的输出越随机、越有创造性,但也可能更不连贯;值越低(接近0),输出越确定、越保守,容易重复最常见的回答。写文案、创意生成可以调高(如0.8-0.95),做事实性问答、代码生成建议调低(如0.1-0.3)。top_p(核采样):和温度类似,也控制多样性。通常调整其中一个即可,不建议两者同时大范围调整。penalty_score(重复惩罚):如果你发现模型总在重复说同一句话,可以适当增加这个值(比如从1.0调到1.2)。max_tokens(最大生成长度):这个参数我上面没写,但非常重要。它限制模型单次回复的最大token数(可以粗略理解为字数)。如果你需要长文生成,务必把这个值调大,否则回复可能会被截断。但也要注意,更大的max_tokens会消耗更多的计算资源,响应可能更慢。
第三,构建多轮对话上下文。 上面的例子都是单轮问答。真正的对话机器人需要记住历史。千帆的API通过messages数组支持多轮对话。你只需要在请求中,按顺序将用户和AI的历史对话都放入这个数组即可。例如:
"messages": [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!我是AI助手。"},
{"role": "user", "content": "刚才我们打招呼了,现在请介绍一下你自己。"}
]
注意,这个上下文长度是有限的(不同模型有不同限制,通常是几千个token)。当对话轮次很多时,你需要设计一个策略,比如只保留最近N轮对话,或者总结之前的对话内容,以避免超出限制导致API调用失败。
第四,做好错误处理与重试。 网络服务不可能100%稳定。你的代码必须能处理API调用失败的情况。常见的错误有:网络超时、Token失效、请求频率超限(Rate Limit)、模型服务暂时不可用等。一个基本的策略是:遇到网络错误或5xx服务器错误时,进行指数退避重试(比如隔1秒、2秒、4秒后重试,最多3次)。对于Token失效,应该触发Token刷新流程。对于频率超限,需要根据返回头中的提示信息,让程序暂停一段时间再试。
第五,关注成本与用量。 在千帆控制台,你可以查看每个应用、每个模型的调用次数和Token消耗情况。不同模型定价不同,在开发测试阶段,可以多用性价比较高的模型。正式上线前,一定要根据预估的请求量做好成本测算。
521



被折叠的 条评论
为什么被折叠?



