从普通请求到 SSE:AI 对话前后端实践
前端接入大模型时,最先跑通的通常是一个普通的 fetch:发送消息数组,等待服务端返回完整文本。它适合验证接口,却很难形成自然的对话体验。模型生成时间稍长,页面就像失去响应;请求中断、错误恢复和多轮上下文也会很快变成新的问题。
我用两个小实验拆开学习这条链路。公开的 AI-backend 用来验证服务端适配、流式输出和 Function Calling;另一个未公开的前端学习原型用来理解浏览器如何消费流、维护对话和取消请求。下面会明确区分两类证据,不把私有实验包装成可公开核对的项目成果。
公开代码可以核对的后端实践
AI-backend 基于 Express,把 DeepSeek 与 OpenAI 封装为统一的 provider adapter。控制器不需要知道具体厂商,只根据配置从工厂取得适配器,再调用普通对话或流式对话能力。这个结构并不复杂,但解决了一个实际问题:上层路由、日志和错误处理不必随着模型提供商一起复制。
仓库中可以看到标准聊天、服务端流式响应、Joi 请求校验、自定义错误类型、Winston 日志和耗时记录。SSE 的价值不只是“打字机效果”,而是把首个 token 更早交给页面,让用户知道请求仍在工作。服务端同时承担模型错误转换和连接结束处理,前端不需要理解不同提供商的原始异常结构。
Function Calling 采用注册表管理可调用函数及其参数 schema。模型返回工具调用后,服务端执行对应函数,把结果追加回消息,再继续请求模型,直到得到普通回答或达到边界。这个循环让我理解到,工具调用不是模型直接执行代码,而是模型提出结构化意图,应用仍需负责参数校验、权限和真实执行。
个人前端实验记录
在未公开的 React 学习原型中,我主要验证浏览器侧的过程:通过 ReadableStream 逐块读取响应,用 TextDecoder 处理字节,把不完整的 SSE 片段缓存在下一轮继续解析;通过 AbortController 在用户停止生成或页面切换时取消请求;多轮对话则由消息数组显式维护,而不是假设模型自动记住历史。
这些内容来自个人实验记录,当前没有公开仓库可以让读者独立复核,因此只能说明我探索过哪些前端问题,不能把它描述成已经稳定运行的产品。它的作用是帮助我理解流式协议与 UI 状态之间的关系:请求状态、已接收文本、当前消息和取消信号必须分开管理,否则很容易出现重复内容或停止后仍继续写入。
从流式回答到工具调用
把两端连起来后,我更明确了职责分配。前端关心可感知的进度、取消和消息状态;服务端关心密钥、模型适配、工具权限和统一错误;模型只负责生成文本或提出工具调用。任何一层都不能因为“用了 AI”就跳过普通工程约束。
尤其是 Function Calling,函数名称和参数 schema 只是入口。真正落地时还需要限制可调用集合、校验参数、处理超时,并记录每一步结果。这个认识后来也影响了我设计 MCP 工具和 Agent Skill:模型获得的工具越强,确定性验证和权限边界越应该先设计。
当前限制与结论
AI-backend 目前只有少量自动化测试,示例函数也主要用于验证调用循环;它不是生产级网关,没有完整的鉴权、限流、持久化会话和供应商故障切换。前端原型同样以理解协议为目标,没有公开部署和多人协作能力。
这组实验的价值在于把“AI 对话框”拆回普通的软件问题:HTTP 流、状态机、取消、错误、权限和日志。模型接口会变化,但这些基础边界相对稳定。公开的服务端实现可以在 AI-backend 中查看。