扣子API食用指南

简介

扣子API(Coze)是字节跳动推出的一站式AI Bot开发平台,旨在让用户快速、低门槛地创建和发布AI聊天机器人。无论用户是否具备编程经验,都可以在该平台上实现从简单问答到复杂逻辑对话的Bot开发。


简单上手

注册账号

注册地址:https://www.coze.cn/sign


创建token

依次点击左下角 扣子 api - API令牌 - 添加新令牌 ,设置好后点击确认复制生成的令牌并保存


创建Bot

点击左侧个人空间,创建bot,设置好名称图标确认后,跳转页面地址最后一个/后的数字就是bot_id,然后左上角可以选择模型,请保存好你选择的模型和对应的bot_id,后面将会用到

图标自取
  • 豆包,模型:豆包
    豆包

  • 海螺,模型:minimax-245k
    hailuo

  • 月之暗面,模型:moonshot-8K, moonshot-64K, moonshot-128K
    kimi.moonshot.cn

  • 通义千问,模型:通义千问-Max
    qwen

  • 左上角选择模型,右上角点击发布

  • 勾选渠道,若无豆包账号,可只勾选 Bot as API 然后右上角点击发布

创建worker

您需要有一个绑定了域名的cf账号,并创建名为 coze 的 KV 然后绑定到 worker,注意修改worker 上传密钥,CTRL+F 替换 your-key-here

worker.js
addEventListener('fetch', event => event.respondWith(handleRequest(event.request)));

const encoder = new TextEncoder();
const API_URL = "https://api.coze.cn/open_api/v2/chat";

async function handleRequest(request) {
  const url = new URL(request.url);
  if (url.pathname === '/upload' && request.method === 'POST') return handleUpload(request);
  if (request.method !== "POST") return new Response("Request method must be POST", { status: 405 });

  const authorizationHeader = request.headers.get("Authorization");
  if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) return new Response("Invalid API key", { status: 401 });
  const apiKey = authorizationHeader.slice(7);

  const { messages, model } = await request.json();
  const botConfigString = await coze.get("BOT_CONFIG");
  const botId = JSON.parse(botConfigString)[model];
  if (!botId) return new Response("Invalid model parameter", { status: 400 });

  const newRequestBody = {
    conversation_id: "123",
    bot_id: botId,
    user: "29032201862555",
    query: messages[messages.length - 1].content,
    stream: true,
    chat_history: messages.slice(0, -1).map(({ role, content }) => ({ role, content, content_type: "text" }))
  };

  const apiResponse = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`
    },
    body: JSON.stringify(newRequestBody)
  });

  let decoder = new TextDecoder();
  let reader = apiResponse.body.getReader();
  let contentBuffer = "";

  return new Response(new ReadableStream({
    async start(controller) {
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        contentBuffer += decoder.decode(value);
        while (contentBuffer.includes("\n")) {
          const newlineIndex = contentBuffer.indexOf("\n");
          const line = contentBuffer.slice(0, newlineIndex);
          contentBuffer = contentBuffer.slice(newlineIndex + 1);

          if (line.startsWith("data:")) {
            try {
              const data = JSON.parse(line.slice(5));
              if (data.event === "message" && data.message.type !== "verbose" && data.message.type !== "follow_up" && data.message.type !== "tool_response") {
                const formattedData = {
                  id: "chatcmpl-" + Math.random().toString(36).slice(2),
                  object: "chat.completion.chunk",
                  created: Math.floor(Date.now() / 1000),
                  model: botId,
                  choices: [{ index: 0, delta: { content: data.message.content }, finish_reason: data.is_finish ? "stop" : null }]
                };
                controller.enqueue(encoder.encode(`data: ${JSON.stringify(formattedData)}\n\n`));
              }
            } catch (error) {
              console.error("Error parsing JSON:", error, "Original data:", line);
            }
          }
        }
      }

      const doneData = {
        id: "chatcmpl-" + Math.random().toString(36).slice(2),
        object: "chat.completion.chunk",
        created: Math.floor(Date.now() / 1000),
        model: botId,
        choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
      };
      controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneData)}\n\n`));
      controller.enqueue(encoder.encode(`data: [DONE]\n\n`));
      controller.close();
    }
  }), { headers: { "Content-Type": "text/event-stream" } });
}

async function handleUpload(request) {
  const authorizationHeader = request.headers.get("Authorization");
  if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) return new Response("Invalid API key", { status: 401 });

  const apiKey = authorizationHeader.slice(7);
  if (apiKey !== "your-key-here") return new Response("Unauthorized", { status: 403 });

  const newBotConfig = await request.json();
  await coze.put("BOT_CONFIG", JSON.stringify(newBotConfig));
  return new Response("BOT_CONFIG updated successfully", { status: 200 });
}

上传配置

注意修改worker地址和上传密钥

curl -X POST https://your-worker-address/upload \
     -H "Authorization: Bearer your-key-here" \
     -H "Content-Type: application/json" \
     -d '{
           "model_name_1": "bot_id_1",
           "model_name_2": "bot_id_2"
         }'

编辑oneapi

base_url:你的worker地址
model:自定义
key:你的令牌


参考链接

31 个赞

感谢大爱分享,点赞

2 个赞

来了来了

1 个赞

学习一下,感谢大佬的教程

1 个赞

哪个模型最好用

1 个赞

感谢reno大佬

2 个赞

感谢分享

1 个赞

感谢大佬 已经用上啦

1 个赞

感谢分享

1 个赞

太强了!

1 个赞

希望 cf 的操作能写的更详细一些

4 个赞

你不会?不会吧?

忘了你是赛博坦星人

2 个赞

你看看 你要照顾我们这种外星人

3 个赞

佬牛

1 个赞

支持一下大佬

1 个赞

问一下,效果咋样,好使吗

1 个赞

来了来了

1 个赞

其实我那个就比较简单,只是转换了一下格式,key用coze申请的,模型用bot_id,cf的代码啥也不用改直接粘贴,也可以直接用demo站
https://linux.do/t/topic/96915

2 个赞

已经用了你的那个了

3 个赞

在我帖子下这样说真的好么 :smiling_face_with_tear:

3 个赞