mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-26 20:33:15 +00:00
/v1/* 是**给外部程序用的**(IDE、脚本、agent 框架),不是给人看的聊天页。 它的行为必须真符合 OpenAI 协议,否则调用方直接坏掉。下面两条都在 **生产实测**中确认过,不是推理。 ## ① GET /v1/models → 404 几乎每个 OpenAI 客户端(curl 脚本、LangChain、OpenAI SDK、IDE 插件) 启动时都会先列模型来探测服务可用性。404 让它们直接判定「服务不可用」, 连试都不试 —— 这是集成方最容易踩空、也最难自查的缺口(表现为 「连不上」,而实际端点是通的)。 新增 handleOpenAIModels。返回什么模型**不重要**,结构合法才重要: 本端点不做模型选择(model 只是回显),所以只暴露 HomeAgent 自身。 不谎报 GPT 之类名字 —— 那会让用户以为能选模型,实际不能。 ## ② stream=true 是假流式 实测:首字节 7.79s,随后**整段**内容在一个 chunk 里到达。 根因:两条路径都走 InjectTextSyncNoMemory —— **同步等完整回复**才返回, 之后才把已拼好的全文切成 3 个 chunk 吐出去。客户端的「生成中」/取消/ 超时/进度条全部失效;300s 超时表现为「卡 5 分钟然后一次性出现」。 重写为真流式:先订阅 EventContentDelta / EventReasoningDelta **再**启动 注入(顺序反了会漏开头几个分片),边收边转成 chunk,最后用同步调用拿到的 完整回复补 usage、发 finish、[DONE]。沿用 handleSSE 的成熟结构 (批量 16ms 合并、独立 writer goroutine、done channel 而非 close)。 顺带处理内核的 reset 事件:流式失败回退非流式时内核会发 content="" + reset=true(见 internal/agent/core/process.go)。忽略它会让 客户端看到半截内容后又接上完整内容(重复且自相矛盾),故识别并丢弃累积。 ## 判据(4 条,变异验证) - TestOpenAIModelsEndpoint / RequiresAuth - TestOpenAIStreamIsActuallyStreaming - TestOpenAINonStreamUnchanged(别把非流式改坏) ★ **判据本身踩了两个坑,都已修正并记在测试注释里**: 1. `httptest.ResponseRecorder` 把整个响应**缓冲在内存里**,请求结束才交付 —— 它**根本观察不到流式**。用它写的流式判据必然是假的。故改用 `httptest.NewServer` + `bufio.Reader` 逐帧读。 2. 「要求首帧早于末帧」**抓不住**假流式:假流式确实是分多次 write 的, 帧间间隔是微秒级 > 0,任何 `> 0` 判据都绿(已实测)。 真正能区分的是:**首帧是否早于「内核产出最终答案」那一刻**。 于是假内核被构造成:发 3 个增量后**扣住**最终响应,直到消费者 表现出「已在读帧」才放行 —— 真流式首帧 0.35s,假流式首帧 3.30s。 3. 鉴权判据一度写错:未登录时门户 302 到 /login,若跟随重定向就会拿到 登录页的 200,把「被重定向」误判成「鉴权通过」。改用不跟随重定向的 客户端。 变异验证:去掉 /v1/models 路由 → 判红(还原 404); 不转发增量 → 判红(首帧 3.30s)。 全量:35 包全绿。