惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AWS News Blog
AWS News Blog
T
Tenable Blog
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
T
Threatpost
Security Latest
Security Latest
C
Cisco Blogs
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
Google Online Security Blog
Google Online Security Blog
NISL@THU
NISL@THU
AI
AI
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Last Watchdog
The Last Watchdog
G
GRAHAM CLULEY
Cloudbric
Cloudbric
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Hacker News: Front Page
U
Unit 42
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MyScale Blog
MyScale Blog
O
OpenAI News
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
P
Proofpoint News Feed
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
H
Heimdal Security Blog
S
Schneier on Security
阮一峰的网络日志
阮一峰的网络日志
Help Net Security
Help Net Security
D
DataBreaches.Net
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
N
News and Events Feed by Topic
WordPress大学
WordPress大学
P
Palo Alto Networks Blog

Cloudflare

爱上 cloudflare 了 - V2EX 我想问问现在 Cloudflare 能不能正常登陆? cfui:基于 go 的 cloudflared web UI 一套能让免费 CloudFlare 建的站部分访问延迟变低(几乎瞬间)的方法,不是优选,夸我或者给我找 bug 为了在 CF 上实现低延迟的效果,打开页面后每半分钟发送一个请求对赛博菩萨有多大伤害?我不想遭报应 Cloudflare 的 5 秒盾/Turnstile 真的无敌吗? CapSolver 这类 api 到底靠不靠谱? https://dash.cloudflare.com 登录不进去 Cloudflare 宣布裁员逾 1100 人 这两天大家能正常登录 cf 吗? cloudflare tunnel 会阻止 openai sdk 的请求,只允许 curl 请求,如何解决 Cloudflare WARP 现在还稳吗 cloudflare worker 懂行的 - V2EX 开启 Cloudflare 的 DNS 代理之后, frp 就无法正常工作 - V2EX cloudflare worker 能指定出口 ip 的国家吗? - V2EX Cloudflare 支持使用自定义域名发邮件了 [送码]做了个 Cloudflare 监控 App - FlareKit,送点兑换码 - V2EX 转移到 Cloudflare Registrar 的域名疑似被盗 为什么已经把 cloudflare 上的 Cache Rules 设置为绕过缓存,还是会被限制上传大小? vibe 了一个 gotify/server 的 cloudflare worker 版本 - V2EX 求助: cf 上面的域名被封了 - V2EX 被 CF 拦截了部分页面, Error 451 错误 - V2EX CF 的 ai 反爬 robots.txt 似乎部分情况下跟 Pages 机制冲突? Cloudflare 收购了 Astro - V2EX 最近发现 CF WARP 在 Win & Linux 上国内能直连,安卓不行 - V2EX Cloudflare Radar《2025 年度回顾》,挺有意思 - V2EX 刚注册的新域名放到了 cloudflare 一周后发现访问量逐渐增加,是爬虫吗 - V2EX 历时 20 多天, Cloudflare 弄丢的数据找回来了 - V2EX cloudflare worker 直连访问太慢了,求个替代 - V2EX 难道没人觉得 cloudflare 改版后,很难用吗? - V2EX Cloudflare 发表 12/5 的故障报告 - V2EX cloudflare 年度总结来了 - V2EX Cloudflare DNS 解析策略 请问 cloudflare 计费最近是不是出了问题?扣了我 5 美元的 workers 会员费, paypal 有扣费记录,也有发票,结果显示我还是免费计划 请教访问 Cloudflare Dashboard 的正确方式 - V2EX 我,吃饱了撑的注册了个域名, Cloudflare 账号没了,不建议将域名放在 Cloudflare - V2EX 听说 cloudflare tunnel 可以通过第二个域名和 ip 优选搞访问加速,有人做过吗?效果怎么样? - V2EX 想要开通 cf 的付费策略,但是苦于没有外币卡 - V2EX cloudflare workers 搭建的博客速度慢怎么优化 - V2EX 碰到了伪装 Cloudflare 钓鱼验证,差点中招 - V2EX 尝试复现 Cloudflare 2025-11-18 的故障 - V2EX (求助) 如何隐藏 OSS 报错信息中的 Bucket 域名 - V2EX 使用 CloudFlare,如何彻底不使用他的 https? - V2EX 这次 Cloudflare 宕机一个有趣的点 - V2EX 移动、电信、联通的固定家庭宽带,访问 Cloudflare 得到是美国的 CDN 节点(跨越整个太平洋)? 而不是中国周边如:首尔、东京、香港 这样的延迟低的节点? - V2EX Cloudflare 怎么给人一种草台班子的感觉? - V2EX cloudflare 全球挂了?? - V2EX cloudflare 炸了? - V2EX 大佬们有没有遇到过 Cloudflare 续订域名 504?换了好几个卡都不行, Paypal 也尝试了 - V2EX cloudflare 域名解析错误问题 - V2EX Worker 的 Editor 贴入代码后怎么总是失去格式,全部连成一条 - V2EX 问题总结 & 解决经验 | Cloudflare R2 og:image 跨域抓取失败 - V2EX tunnel 出错! 默认 cloudflare 不对网站做防护吗? - V2EX cloudflare 的 page 能绑定根域名吗 - V2EX 难以缓存的动态页面用免费 Cloudflare 服务器放在那里更快?用 CF 主要是为了防 DDoS。 Cloudflare 各个计划多少流量以下不会被客服催着买更高的计划? 我发现 cloudflare 用多了之后, 我所有的规划都想往上靠 - V2EX 网站上 cloudflare 之后的奇怪流量都是哪里来的 被 CF block 了账户,何解? Workers 额度超了导致静态站点报错 1027 - V2EX cf 买的域名竟然不支持改 NS 写了个小工具,免费中转 Gemini API Nginx 反向代理 CLoudflare 的 Pages 项目域名出错
白嫖 worker AI 的进 - V2EX
cfer · 2025-12-24 · via Cloudflare

我使用 workers + worker Ai 构建了一个兼容 openai 接口的适配器。但是只是实现了基本功能,现在需要完善工具调用功能。有大佬能帮我完善它嘛?

export default {
  async fetch(request, env, ctx) {
    // 处理 CORS 预检请求
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        status: 200,
        headers: {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type, Authorization',
          'Access-Control-Max-Age': '86400',
        },
      });
    }

    // 验证 API Key
    const authHeader = request.headers.get('Authorization');
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return new Response(JSON.stringify({
        error: { message: 'API key required', type: 'invalid_request_error', code: 'invalid_api_key' }
      }), { status: 401, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
    }

    const apiKey = authHeader.substring(7);
    const validApiKeys = env.VALID_API_KEYS ? env.VALID_API_KEYS.split(',') : ['your-api-key-here'];
    if (!validApiKeys.includes(apiKey)) {
      return new Response(JSON.stringify({
        error: { message: 'Invalid API key', type: 'invalid_request_error', code: 'invalid_api_key' }
      }), { status: 401, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
    }

    const url = new URL(request.url);

    // 模型映射
    const modelMap = {
      'deepseek-r1': '@cf/deepseek-ai/deepseek-r1-distill-qwen-32b',
      'gpt-oss-120b': '@cf/openai/gpt-oss-120b',
      'gpt-oss-20b': '@cf/openai/gpt-oss-20b',
      'llama-4-scout': '@cf/meta/llama-4-scout-17b-16e-instruct',
      'qwen32b': '@cf/qwen/qwq-32b',
      'gemma-3': '@cf/google/gemma-3-12b-it',
      'qwen3-embedding-0.6b': '@cf/qwen/qwen3-embedding-0.6b'
    };

    // 聊天接口
    if (url.pathname === '/v1/chat/completions' && request.method === 'POST') {
      try {
        const body = await request.json();
        if (!body.messages || !Array.isArray(body.messages)) {
          return new Response(JSON.stringify({
            error: { message: 'Messages must be an array', type: 'invalid_request_error', code: 'invalid_parameter' }
          }), { status: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
        }

        const model = body.model || 'deepseek-r1';
        const cfModel = modelMap[model];
        if (!cfModel) {
          return new Response(JSON.stringify({
            error: { message: `Model '${model}' not supported`, type: 'invalid_request_error', code: 'model_not_found' }
          }), { status: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
        }

        // 构造 AI 请求参数
        let aiRequest = {};
        let useResponsesAPI = cfModel.startsWith('@cf/openai/gpt-oss');

        if (useResponsesAPI) {
          // Responses API 格式
          const systemMsg = body.messages.find(m => m.role === 'system')?.content || "You are a helpful assistant.";
          const userMsgs = body.messages.filter(m => m.role === 'user').map(m => m.content).join("\n");

          aiRequest = {
            input: userMsgs,
            instructions: systemMsg,
            temperature: body.temperature ?? 0.7,
            top_p: body.top_p ?? 0.9,
            max_tokens: body.max_tokens ?? 2048,
            reasoning: body.reasoning ?? { effort: "medium" }
          };
        } else {
          // 旧模型:拼接 prompt
          let prompt = '';
          for (const message of body.messages) {
            if (message.role === 'system') prompt += `System: ${message.content}\n\n`;
            if (message.role === 'user') prompt += `User: ${message.content}\n\n`;
            if (message.role === 'assistant') prompt += `Assistant: ${message.content}\n\n`;
          }
          prompt += 'Assistant: ';

          aiRequest = {
            prompt,
            temperature: body.temperature ?? 0.7,
            top_p: body.top_p ?? 0.9,
            max_tokens: body.max_tokens ?? 4096,
          };
        }

        // 调用 Cloudflare AI
        const response = await env.AI.run(cfModel, aiRequest);

        const completionId = 'chatcmpl-' + Math.random().toString(36).substring(2, 15);
        const timestamp = Math.floor(Date.now() / 1000);

        // 获取最终回答内容
        let assistantContent = "";
        if (useResponsesAPI) {
          if (response.output && Array.isArray(response.output)) {
            assistantContent = response.output
              .flatMap(msg => msg.content
                .filter(c => c.type === "output_text")
                .map(c => c.text)
              )
              .join("\n");
          }
        } else {
          assistantContent = response.response ?? "";
        }
        

        // 流式输出
        if (body.stream) {
          const encoder = new TextEncoder();
          const stream = new ReadableStream({
            start(controller) {
              // 开始事件
              controller.enqueue(encoder.encode(`data: ${JSON.stringify({
                id: completionId,
                object: 'chat.completion.chunk',
                created: timestamp,
                model,
                choices: [{ index: 0, delta: { role: 'assistant', content: "" }, finish_reason: null }]
              })}\n\n`));

              // 模拟逐块输出
              const chunkSize = 20;
              for (let i = 0; i < assistantContent.length; i += chunkSize) {
                const chunk = assistantContent.slice(i, i + chunkSize);
                controller.enqueue(encoder.encode(`data: ${JSON.stringify({
                  id: completionId,
                  object: 'chat.completion.chunk',
                  created: timestamp,
                  model,
                  choices: [{ index: 0, delta: { content: chunk }, finish_reason: null }]
                })}\n\n`));
              }

              // 结束事件
              controller.enqueue(encoder.encode(`data: ${JSON.stringify({
                id: completionId,
                object: 'chat.completion.chunk',
                created: timestamp,
                model,
                choices: [{ index: 0, delta: {}, finish_reason: 'stop' }]
              })}\n\n`));
              controller.enqueue(encoder.encode('data: [DONE]\n\n'));
              controller.close();
            }
          });
          return new Response(stream, {
            headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*' },
          });
        }

        // 非流式输出
        const chatCompletion = {
          id: completionId,
          object: 'chat.completion',
          created: timestamp,
          model,
          choices: [{ index: 0, message: { role: 'assistant', content: assistantContent }, finish_reason: 'stop' }],
          usage: {
            prompt_tokens: Math.ceil(JSON.stringify(body.messages).length / 4),
            completion_tokens: Math.ceil(assistantContent.length / 4),
            total_tokens: Math.ceil((JSON.stringify(body.messages).length + assistantContent.length) / 4)
          }
        };
        return new Response(JSON.stringify(chatCompletion), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });

      } catch (error) {
        console.error('Error:', error);
        return new Response(JSON.stringify({
          error: { message: 'Internal server error', type: 'server_error', code: 'internal_error' }
        }), { status: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
      }
    }
    // 嵌入模型
    if (url.pathname === '/v1/embeddings' && request.method === 'POST') {
      try {
        const body = await request.json();
        if (!body.input) {
          return new Response(JSON.stringify({
            error: { message: 'Input is required', type: 'invalid_request_error', code: 'invalid_parameter' }
          }), { status: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
        }
    
        const model = body.model;
        const cfModel = modelMap[model];
        if (!cfModel) {
          return new Response(JSON.stringify({
            error: { message: `Model '${model}' not supported`, type: 'invalid_request_error', code: 'model_not_found' }
          }), { status: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
        }
    
        // 调用 AI 获取 embedding
        let embeddingResponse;

        // Responses API 假设支持 embedding
        embeddingResponse = await env.AI.run(cfModel, {
          text: body.input
        });
        
        // 构造返回
        const embedding = embeddingResponse.embedding || [0]; // 如果返回格式不同,需要根据实际结果调整
        return new Response(JSON.stringify(embeddingResponse), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
    
      } catch (error) {
        console.error('Embedding error:', error);
        return new Response(JSON.stringify({
          error: { message: 'Internal server error', type: 'server_error', code: 'internal_error' }
        }), { status: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
      }
    }

    // 模型列表
    if (url.pathname === '/v1/models' && request.method === 'GET') {
      const models = Object.keys(modelMap).map(id => ({
        id,
        object: 'model',
        created: Math.floor(Date.now() / 1000),
        owned_by: 'cloudflare',
        permission: [{ id: 'modelperm-' + id, object: 'model_permission', created: Math.floor(Date.now() / 1000), allow_create_engine: false, allow_sampling: true, allow_logprobs: false, allow_search_indices: false, allow_view: true, allow_fine_tuning: false, organization: '*', group: null, is_blocking: false }]
      }));
      return new Response(JSON.stringify({ object: 'list', data: models }), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
    }

    // 健康检查
    if (url.pathname === '/health' && request.method === 'GET') {
      return new Response(JSON.stringify({ status: 'healthy', timestamp: new Date().toISOString(), models: Object.keys(modelMap) }), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
    }

    // 404
    return new Response(JSON.stringify({
      error: { message: 'Not found', type: 'invalid_request_error', code: 'not_found' }
    }), { status: 404, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } });
  },
};