本机 AI 适配器复盘:浏览器会话、回环隔离与伪流式响应
本文目录
这篇文章记录一个个人本机实验项目的工程取舍:用 Node.js 暴露一个兼容常见聊天请求形状的接口,再通过本机浏览器已建立的登录会话访问上游服务。它不是官方 SDK,也不是通用、可共享或可公开部署的 AI 网关。文章只描述可从当前源码和测试确认的边界,不公开上游地址、登录细节、会话凭据或特殊模型代号。
请求经过哪些边界
服务以 Express 提供聊天、模型列表、登录状态和健康检查等本机路由。聊天请求先把 system 指令、对话历史和工具描述整理为浏览器端请求内容,再通过 Puppeteer 的页面执行能力发起请求。浏览器会话负责已有的授权状态;服务不会要求用户把 Cookie 或令牌复制进 curl、环境变量或聊天记录。
页面复用意味着并发操作需要串行化。项目用互斥队列包住共享页面的请求过程,并在内存中按模型类别缓存会话标识,缓存有时间上限,进程退出即消失。这解决的是单个本机浏览器页面被多个请求同时改写的问题,不是多租户隔离,也不是持久化会话系统。若要支持并发用户,应改成隔离的浏览器上下文或独立工作进程,并另行设计资源上限和会话生命周期。
回环访问不是身份认证
源码将监听地址限制为回环接口,并在请求入口检查 TCP 对端、Host 和 Origin 是否属于同一台机器上的本地来源;IPv4、IPv6 与映射地址也有单独判断。CORS 配置只反射本地来源,不能把一个请求转换成可信身份。这样的门禁可以降低误配置到公网或被远程网页直接调用的风险,但同一台电脑上的其他进程仍可能访问该服务。
因此,监听回环地址是部署约束,不应被描述成完整认证。不要把端口转发到局域网、反向代理或公网;如果未来确实需要本机以外的调用者,必须先增加身份认证、TLS、限流、来源策略和独立威胁评估。浏览器来源检查也不能替代操作系统账户隔离或密钥保护。
浏览器会话与本机数据
浏览器配置文件可能包含登录态和站点数据,应视为敏感本地状态。项目文档明确要求不要复制 Cookie 或令牌;日志也只保留必要的状态和错误类别,不记录完整响应体、请求 URL 或模型回复。日志目录按仅当前用户可读写的权限创建。即使有这些保护,日志仍可能暴露使用时间与错误模式,不适合直接公开分享。
项目使用 Puppeteer Core 连接本机浏览器;启动器以可执行文件和参数数组调用子进程,不通过 shell 拼接命令。这样减少了参数被当作 shell 语法执行的机会,但不能证明浏览器二进制、用户配置目录或上游登录环境已经安全。启动前仍应验证浏览器路径和版本,并保持浏览器配置目录不进入版本控制或备份共享范围。
兼容格式不等于执行能力
适配器会把常见 chat messages 转换为目标页面理解的对话文本,并把 function/tool 描述交给模型。返回内容中的工具调用片段会被解析成结构化调用对象,但适配器本身不会执行这些工具。真正执行的客户端必须再次校验工具名称、参数 schema、用户授权和副作用;不能因为模型返回了 JSON 就直接运行命令、访问文件或调用业务接口。
代码将上游模型标识映射到页面使用的模型类别,未知值则按兼容路径继续处理。这个映射是适配层,不代表服务端实际部署了所有列出的模型,也不保证它们在每次登录、地区或账户权限下都可用。对外文档应把它描述成“请求选择值”,不能当成稳定的模型清单。
stream: true 目前并非实时流
上游响应采用事件流格式,但当前实现先读取完整响应,再逐行解析事件、拼出最终内容,之后才返回兼容结果。因此客户端即使设置 stream: true,也不能边生成边看到增量文本;长回答仍要等待完整响应,缓冲也会占用内存。把最终内容包装成 SSE 事件只是在协议形状上兼容,不等同真正的流式传输。
若要提供真实流式体验,需要从上游读取字节流并逐事件解析,向下游立即写出并在结束时发送终止事件;同时实现上游超时、客户端断开取消、背压、单请求最大字节数和错误帧映射。事件解析器还要正确处理跨 chunk 的多字节 UTF-8、CRLF、注释行、多行 data: 和末尾未完成事件,而不能假定每个网络块恰好对应一行。
有边界的重试
重试次数必须是有限正整数,且只对明确列出的可重试错误码执行。遇到可重试错误时会使缓存的会话标识失效,再创建新的上游会话。一个容易忽略的情况是:服务端可能已经接受请求,却返回了空响应;此时自动重放可能造成重复生成或重复计费,所以实现选择记录脱敏诊断并停止重试。后续若接入会产生副作用的工具,这条规则更重要,除非上游提供幂等键或能证明请求未被处理,否则不能只凭“没有内容”判定失败。
本机测试能证明什么
本次在项目目录执行 npm test,21/21 项通过。覆盖包括 IPv4/IPv6 回环判断、Host/Origin 与 TCP 对端组合、浏览器启动参数边界、重试预算、空成功响应不重放、日志不包含响应体或 URL,以及致命进程事件以非零状态退出。
这些是本机单元和边界测试,不会访问真实上游,也没有启动浏览器、读取账号会话、验证模型行为或测量真实流式延迟。它们能支撑源码行为的有限结论,不能替代第三方服务条款审查、登录授权确认或发布验收。
继续演进的优先级
- 把上游地址改为显式配置并限制可选目标,避免源码绑定个人或组织专属服务;配置文件和会话目录必须保持本地私有。
- 在只支持回环访问的前提下,为同机非可信进程增加短时随机凭据或用户确认,并补充跨来源请求的集成测试。
- 把完整响应缓冲改成真流式管线,覆盖取消、背压、请求/响应大小上限、超时和部分帧解析。
- 对请求角色、消息数量、单条文本长度、模型选择和工具 schema 进行服务端校验,并限制单个模型会话的缓存数量。
- 在隔离浏览器或模拟上游的测试环境里做端到端验证;不要为了“测试方便”把个人登录态复制到自动化用例。
参考资料:Express 4 API、Node.js net.BlockList、Puppeteer Page.evaluate、HTML Standard: Server-sent events。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。