38、【Agent】【OpenCode】本地代理分析(二)
【声明】本博客所有内容均为个人业余时间创作所述技术案例均来自公开开源项目如GithubApache基金会不涉及任何企业机密或未公开技术如有侵权请联系删除背景上篇 blog【Agent】【OpenCode】本地代理分析一开始分析本地代理的实现该本地 HTTP 代理服务器可以接收来自 OpenCode或其他兼容 OpenAI API 的客户端的请求并将请求转发给 DashScope 的 API 兼容接口其整体结构使用 Node.js 内置模块 http 创建一个本地 HTTP 服务器该服务器监听本地的2048端口所有发往http://127.0.0.1:2048的请求都会进入这个回调函数该代理只处理 OpenAI 风格的聊天请求其中条件/v1/chat/completions是 OpenCode 默认发送的 endpoint然后详细分析了 endpoint 和 OpenAI 风格的概念下面继续分析OpenCode上篇 blog 分析了 endpoint 概念并简单提了下 OpenAI 风格下面继续分析 OpenAI 风格的核心特征首先是固定的 endpoint 路径/v1/chat/completions所有的聊天请求都会发到这里其次是请求格式统一{model:qwen-plus,messages:[{role:user,content:你好}],stream:true,temperature:0.7}统一的认证方式Authorization: Bearer sk-xxxxxxxxxxxx统一的流式响应格式SSE非流式{choices:[{message:{content:你好}}]}流式每块一个 JSON{choices:[{delta:{content:你}}]}{choices:[{delta:{content:好}}]}{choices:[{delta:{content:}}]}OpenCode 只发送 OpenAI 风格的 endpoint 和格式所以本地代理这里必须监听/v1/chat/completionsOpenAI 风格 endpoint然后接收 OpenAI 格式的 JSON再转发给 DashScope 的兼容接口/compatible-mode/v1/chat/completionsOK继续分析本地代理的内容// dashscope-proxy.jsconsthttprequire(http);consthttpsrequire(https);constserverhttp.createServer((req,res){console.log( Received${req.method}${req.url});if(req.methodPOSTreq.url/v1/chat/completions){letbody;req.on(data,chunkbodychunk);req.on(end,(){// 从原始请求中获取 Authorization 头constauthHeaderreq.headers[authorization]||;constoptions{hostname:dashscope.aliyuncs.com,port:443,path:/compatible-mode/v1/chat/completions,method:POST,headers:{Authorization:authHeader,// 直接透传Content-Type:application/json,Content-Length:Buffer.byteLength(body)}};constproxyReqhttps.request(options,(proxyRes){res.writeHead(proxyRes.statusCode,proxyRes.headers);proxyRes.pipe(res);// 自动处理流式/非流式 自动 end()});proxyReq.on(error,(e){console.error(Proxy error:,e.message);res.writeHead(502);res.end(Bad Gateway);});proxyReq.write(body);proxyReq.end();});return;}res.writeHead(404);res.end(Not Found);});server.listen(2048,127.0.0.1,(){console.log(✅ DashScope proxy with full OpenCode Ollama compatibility running on http://127.0.0.1:2048);});当收到的是指定请求/v1/chat/completions时开始拼接 request bodyletbody;req.on(data,chunkbodychunk);req.on(end,(){...});这里的 HTTP request body 可能是分块chunked传输的通过监听data事件把所有数据块拼成完整的字符串 body然后当end事件触发时说明整个 request body 已经接收完毕可以开始处理注意此时的 body 仍是个 JSON 字符串而不是 JS 对象除非像之前 blog 【Agent】【OpenCode】本地代理JavaScript 脚本 介绍的要用JSON.parse解析并修改 request body 的内容此时的 body 内容可能是这样的{model:qwen-plus,messages:[{role:user,content:你好}]}这里涉及比较多的点下面详细分析下首先是分块传输的概念分块传输Chunked Transfer Encoding是 HTTP/1.1 中一种动态传输数据的方式适合服务器在发送响应或客户端发送请求时还不知道整个内容的场景在分块传输中数据被分成多个块chunks进行发送每个块前面标明该数据块的大小最后一个大小为 0 的块表示结束举个原始 HTTP 响应片断的例子HTTP/1.1 200 OK Transfer-Encoding: chunked 5\r\n ← 第一块长度是 5 字节 Hello\r\n ← 实际数据 Hello 6\r\n ← 第二块长度是 6 字节 World\r\n ← 实际数据 World 0\r\n ← 长度为 0表示结束 \r\n最终数据流拼接起来就是Hello World另外注意Transfer-Encoding: chunked出现时不会同时有Content-Length字段在这段代码中letbody;req.on(data,chunkbodychunk);req.on(end,(){// 完整 body 内容});Node.js 底层已经自动解码了分块传输所以这里收到的每个 chunk 都是原始数据的一部分Buffer 或 string不需要手动解析十六进制长度所以无论是客户端是用Content-Length一次性发完数据还是用 chunked 分多次发送本地代理都能正确拼出完整 bodyOK下面再介绍下分块传输的适用场景场景说明流式响应如大模型聊天streamtrue一边生成 token一边发送动态生成内容服务器实时读取日志执行命令并输出上传大文件客户端可能分块上传虽然较少见但 HTTP 允许代理转发接收 OpenCode 请求时可能会收到 chunked body比如上面第一个流式响应所以本地代理这里监听data和end是处理 HTTP 请求的标准做法能兼容所有传输方式OK本篇先到这里如有疑问欢迎评论区留言讨论祝各位功力大涨技术更上一层楼更多内容见下篇 blog
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2486397.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!