Song's Blog

Song's Blog

记GPT Academic 中接入百度 Coding Plan 在线模型

2
2026-03-18
记GPT Academic 中接入百度 Coding Plan 在线模型

百度千帆 Coding Plan 是百度智能云推出的 AI 编程订阅服务,聚合了多款主流代码模型,包括 Kimi-K2.5、DeepSeek-V3.2、GLM-5、MiniMax-M2.5 等,并提供 OpenAI 兼容的 API 接口,方便开发者集成到各类编程工具中。相比按tokens使用量计费的API,按月订阅的Coding Plan虽然仅支持部分模型,但是只限制调用次数,费用要划算不少。GPT Academic 是一个广受欢迎的科研、编程辅助工具,支持接入多种大语言模型。但是GPT Academic并不支持接入百度 Coding Plan,虽然支持OpenAI接口,但是并不能直接套用OpenAI的配置文件将百度Coding Plan接入GPT Academic。本文将详细介绍如何将百度 Coding Plan 的模型接入到 GPT Academic 中。

通过阅读GPT Academic文档,得知要想接入项目未支持的新模型,需要修改request_llms 目录下的bridge_all.py 文件并新建一个bridge_coding_plan.py 文件。

准备工作

  1. 订阅 Coding Plan 套餐并获取专属 API Key
    访问百度千帆订阅管理页面购买套餐(Lite 或 Pro),然后在控制台创建专属 API Key。注意:Coding Plan 有独立的 API Key,不能混用普通千帆 API Key。

  2. 确保 GPT Academic 环境正常
    克隆或下载 GPT Academic 项目,安装依赖,确保能够正常运行。

  3. 了解 Coding Plan API 基本信息

    • 接口 Base URL:https://qianfan.baidubce.com/v2/coding/chat/completions

    • 支持的模型名:kimi-k2.5deepseek-v3.2glm-5minimax-m2.5

    • 请求格式:与 OpenAI Chat Completions 一致,支持流式输出。

修改GPT Academic接口

1. 创建接入文件 bridge_coding_plan.py

在 GPT Academic 的 request_llms 目录下新建 bridge_coding_plan.py 文件,实现与 Coding Plan API 的交互。通过参考其他模型接入文件,可以得知该文件要包含以下部分:

  • 配置读取函数 get_coding_plan_config(),用于获取 API Key 和端点(支持从配置文件或环境变量读取)。

  • 消息构造函数 generate_messages_payload(),将输入、历史对话和系统提示转换为 API 所需的 messages 格式。

  • 核心生成函数 generate_from_coding_plan(),发送请求并处理流式响应。

  • 两个标准接口函数 predict_no_ui_long_connection()(多线程无界面调用)和 predict()(单线程带界面调用),遵循 GPT Academic 的规范。

"""
百度千帆 Coding Plan 在线模型接入
支持模型:kimi-k2.5, deepseek-v3.2, glm-5, minimax-m2.5
文档参考:https://cloud.baidu.com/doc/qianfan/s/imlg0beiu
"""
import time
import json
import requests
from toolbox import get_conf, update_ui, log_chat
from toolbox import ChatBotWithCookies

model_name = '百度千帆Coding Plan'
CODING_PLAN_ENDPOINT = "https://qianfan.baidubce.com/v2/coding/chat/completions"

def get_coding_plan_config():
    """获取 Coding Plan 的配置信息"""
    try:
        CODING_PLAN_API_KEY = get_conf("CODING_PLAN_API_KEY")
    except:
        CODING_PLAN_API_KEY = None
##似乎key因未知原因无法从config.py配置文件获取,采取这种简单粗暴方式先尝试从配置文件获取,获取失败直接修改"None"给出key##
    try:
        CODING_PLAN_ENDPOINT_CONF = get_conf("CODING_PLAN_ENDPOINT")
    except:
        CODING_PLAN_ENDPOINT_CONF = CODING_PLAN_ENDPOINT

    endpoint = CODING_PLAN_ENDPOINT_CONF
    if not CODING_PLAN_API_KEY:
        raise RuntimeError(
            "请配置 CODING_PLAN_API_KEY!\n"
            "方法1:在 config.py 中设置 CODING_PLAN_API_KEY = 'your_api_key'\n"
            "方法2:在 config_private.py 中设置 CODING_PLAN_API_KEY = 'your_api_key'\n"
            "方法3:设置环境变量 CODING_PLAN_API_KEY=your_api_key"
        )
    return CODING_PLAN_API_KEY, endpoint

def generate_messages_payload(inputs, llm_kwargs, history, system_prompt):
    """生成符合 Coding Plan API 格式的消息载荷"""
    messages = []
    if system_prompt:
        messages.append({"role": "system", "content": system_prompt})
    # 添加历史对话
    conversation_cnt = len(history) // 2
    for i in range(conversation_cnt):
        user_msg = history[2*i]
        assistant_msg = history[2*i+1]
        if user_msg and assistant_msg:
            messages.append({"role": "user", "content": user_msg})
            messages.append({"role": "assistant", "content": assistant_msg})
    # 添加当前输入
    messages.append({"role": "user", "content": inputs})
    return messages

def generate_from_coding_plan(inputs, llm_kwargs, history, system_prompt):
    """调用 Coding Plan API 生成回复(流式输出)"""
    api_key, endpoint = get_coding_plan_config()
    model_name_actual = llm_kwargs.get("llm_model", "kimi-k2.5")
    messages = generate_messages_payload(inputs, llm_kwargs, history, system_prompt)

    payload = {
        "model": model_name_actual,
        "messages": messages,
        "stream": True,
        "temperature": llm_kwargs.get("temperature", 1.0),
        "max_tokens": llm_kwargs.get("max_length", 4096),
    }
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}",
    }
    proxies = get_conf("proxies")
    TIMEOUT_SECONDS = get_conf("TIMEOUT_SECONDS")

    response = requests.post(
        endpoint,
        headers=headers,
        json=payload,
        stream=True,
        proxies=proxies if proxies else None,
        timeout=TIMEOUT_SECONDS,
    )
    if response.status_code != 200:
        raise RuntimeError(f"API请求失败,状态码: {response.status_code}")

    buffer = ""
    for line in response.iter_lines():
        if not line:
            continue
        line_str = line.decode()
        if line_str.startswith("data: "):
            data_str = line_str[6:]
            if data_str.strip() == "[DONE]":
                break
            try:
                data = json.loads(data_str)
                if "choices" in data and data["choices"]:
                    delta = data["choices"][0].get("delta", {})
                    content = delta.get("content", "")
                    if content:
                        buffer += content
                        yield buffer
                    if data["choices"][0].get("finish_reason") == "stop":
                        break
            except json.JSONDecodeError:
                continue
    if not buffer:
        raise RuntimeError("获得空的回复")

def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", observe_window=[], console_silence=False):
    """多线程调用(无界面)"""
    response = ""
    for response in generate_from_coding_plan(inputs, llm_kwargs, history, sys_prompt):
        if observe_window:
            observe_window[0] = response
    return response

def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None):
    """单线程调用(带界面)"""
    chatbot.append((inputs, ""))
    yield from update_ui(chatbot=chatbot, history=history)

    try:
        response = ""
        for response in generate_from_coding_plan(inputs, llm_kwargs, history, system_prompt):
            chatbot[-1] = (inputs, response)
            yield from update_ui(chatbot=chatbot, history=history)
        history.extend([inputs, response])
        log_chat(llm_model=llm_kwargs["llm_model"], input_str=inputs, output_str=response)
        yield from update_ui(chatbot=chatbot, history=history)
    except Exception as e:
        from toolbox import trimmed_format_exc
        tb_str = '```\n' + trimmed_format_exc() + '```'
        chatbot[-1] = (chatbot[-1][0], tb_str)
        yield from update_ui(chatbot=chatbot, history=history, msg="异常")
        return

2. 修改 bridge_all.py 添加模型路由

编辑 request_llms/bridge_all.py,主要完成两件事:

  • 导入 bridge_coding_plan 中的两个函数。

  • model_info 字典中添加 Coding Plan 支持的四个模型,并指定对应的 endpoint 和函数。

  • (可选)在 endpoint 重定向部分添加 coding_plan_endpoint,便于通过配置文件重定向 API 地址。

关键修改部分:

在文件开头的导入部分添加:

from .bridge_coding_plan import predict_no_ui_long_connection as coding_plan_noui
from .bridge_coding_plan import predict as coding_plan_ui

在 endpoint 定义区域添加:

coding_plan_endpoint = "https://qianfan.baidubce.com/v2/coding/chat/completions"
# 并加入重定向处理
if coding_plan_endpoint in API_URL_REDIRECT:
    coding_plan_endpoint = API_URL_REDIRECT[coding_plan_endpoint]

model_info 添加部分(通常在“月之暗面”之后):

# -=-=-=-=-=-=- 百度千帆 Coding Plan -=-=-=-=-=-=-
coding_plan_models = ["kimi-k2.5", "deepseek-v3.2", "glm-5", "minimax-m2.5"]
if any(item in coding_plan_models for item in AVAIL_LLM_MODELS):
    try:
        model_info.update({
            "kimi-k2.5": {
                "fn_with_ui": coding_plan_ui,
                "fn_without_ui": coding_plan_noui,
                "can_multi_thread": True,
                "endpoint": coding_plan_endpoint,
                "max_token": 128000,
                "tokenizer": tokenizer_gpt35,
                "token_cnt": get_token_num_gpt35,
            },
            "deepseek-v3.2": {
                "fn_with_ui": coding_plan_ui,
                "fn_without_ui": coding_plan_noui,
                "can_multi_thread": True,
                "endpoint": coding_plan_endpoint,
                "max_token": 64000,
                "tokenizer": tokenizer_gpt35,
                "token_cnt": get_token_num_gpt35,
            },
            "glm-5": {
                "fn_with_ui": coding_plan_ui,
                "fn_without_ui": coding_plan_noui,
                "can_multi_thread": True,
                "endpoint": coding_plan_endpoint,
                "max_token": 128000,
                "tokenizer": tokenizer_gpt35,
                "token_cnt": get_token_num_gpt35,
            },
            "minimax-m2.5": {
                "fn_with_ui": coding_plan_ui,
                "fn_without_ui": coding_plan_noui,
                "can_multi_thread": True,
                "endpoint": coding_plan_endpoint,
                "max_token": 128000,
                "tokenizer": tokenizer_gpt35,
                "token_cnt": get_token_num_gpt35,
            },
        })
    except Exception as e:
        logger.error(f"添加 Coding Plan 模型失败: {e}")

3. 配置 API Key

在 GPT Academic 的 config.pyconfig_private.py 中添加:

CODING_PLAN_API_KEY = "你的专属API Key"
# 如果不需要自定义端点,可以省略下面这行
CODING_PLAN_ENDPOINT = "https://qianfan.baidubce.com/v2/coding/chat/completions"

4. 更新可用模型列表

config.pyAVAIL_LLM_MODELS 中添加需要的 Coding Plan 模型,例如:

AVAIL_LLM_MODELS = [
    # ... 其他模型
    "kimi-k2.5",
    "deepseek-v3.2",
    "glm-5",
    "minimax-m2.5",
]

5. 接入测试(可选,非必要)

可以编写简单的测试脚本(如 test_llms.py)验证接入是否成功:

# test_coding_plan.py
from request_llms.bridge_coding_plan import predict_no_ui_long_connection

llm_kwargs = {
    "llm_model": "kimi-k2.5",  # 可切换为其他模型
    "max_length": 2048,
    "temperature": 0.7,
}
result = predict_no_ui_long_connection(
    inputs="请用一句话解释什么是人工智能?",
    llm_kwargs=llm_kwargs,
    history=[],
    sys_prompt="你是一个有帮助的助手"
)
print("回复:", result)

运行该脚本,若能正常输出回复,则说明接入成功。

6. 注意事项

  1. 专属 API Key 与普通千帆 API Key 的区别
    Coding Plan 有独立的 API Key,必须在请求时使用,且 endpoint 必须为 /v2/coding/chat/completions,否则会返回 coding_plan_api_key_required 错误。

  2. 模型切换
    通过在 llm_kwargs 中指定 llm_model 即可通过 GPT Academic 的模型路由机制实时切换模型,无需修改代码。

  3. 流式输出处理
    Coding Plan API 支持 SSE 流式输出,代码中通过迭代 response.iter_lines() 逐行解析,并逐步 yield 累积的文本,实现打字机效果。

  4. 错误处理
    代码中包含了常见的异常捕获和错误提示,如 API 请求失败、超时、空回复等,便于调试。

常见问题

  • Q: 调用时返回 403 错误,提示 coding_plan_not_subscribed
    A: 未订阅 Coding Plan 套餐,或使用的 API Key 不是 Coding Plan 专属 Key。请检查控制台订阅状态和 Key 类型。

  • Q: 返回 429 错误,提示 coding_plan_hour_quota_exceeded
    A: 5 小时额度已用尽,需等待额度刷新或升级套餐。

  • Q: 模型切换无效,始终使用默认模型
    A: 请确保在 bridge_all.py 中正确配置了每个模型的 fn_with_uifn_without_ui,且 llm_kwargs["llm_model"] 在调用时被正确传递。