Liking cljdoc? Tell your friends :D

D6 / D7 — 响应路径与 wire 知识整理

状态:✅ 全部完成、已结案(2026-07-16 复核:原 §3「暂缓」两项均已不成立, 见 §3)。D7 死代码清理 2026-06;D6 按「中立层容许别名」定调; 双消息体系统一已于 2026-07-10 落地(v0.2):删除 model/types.clj, tool-call 全库统一为 {:id :name(字符串) :args}(与中立消息同构), response→neutral 桥退化为形状复位。 来源:2026-06-10 全量审查 D6「core 泄漏厂商 wire 知识」、D7「重复抽象」。


1. 已完成(2026-06-10)

D7 — 删除死抽象 / 死方法

审查指「4 份响应归一化 + 协议死方法 + 双消息体系」。经调用方核查,先清掉确证为死的部分:

删除项位置核查结论
协议方法 build-result-messages / build-assistant-messagemodel.clj 协议定义 + extend-type Object 默认实现 + 4 个 provider record(base/anthropic/bailian/mock)+ 全部测试 reify:build-result-msgs 由 service 构造但从不被调用;历史由 advisor/memory/response->neutral(中立消息)构建。全链路无消费者。
call-with-toolsmodel.clj核心里的「第 4 份归一化」,仅测试调用,生产路径走 service/normalize-response。
:build-result-msgs service 键model/service.clj/create-service同上,构造即死。
response-assistant-msg / :assistant-msgmodel/response.clj(ILLMResponse 协议 + LLMResponse 字段 + make-response 参数)仅由已删的 build-assistant-message 填充,从不被读取。
独立函数 build-assistant-messagecommon/openai_compat.clj无调用方。

附带一致性修复:service/normalize-response(同步路径)现也调 response/extract-reasoning, 与 stream / response_parser 路径对齐(此前只有流式/解析器路径提取 reasoning)。

净效果:协议从 11 方法减到 9(必需 5 + 可选 4);响应归一化从「4 份」收敛为 2 份活路径(service/normalize-response 同步 + stream/* 流式,二者输入不同—— 原始响应 map vs 流式累积 state——是合理分工,不再有第 3、4 份冗余)。测试 196→192 (删掉 4 个针对死方法的测试),断言数稳定,0 失败。

D6 — wire 知识收敛到单一来源

清掉 call-with-tools 后,"原始响应里 usage/finish-reason/reasoning 在哪" 的知识 只剩一处权威实现:model/response.clj 的 normalize-usage / normalize-finish-reason / extract-reasoning。service/normalize-response 与 common/response_parser 都委托它,不再各写一份。


2. D6 的设计定调:中立层「容许已知别名」

model/response.clj 的归一化函数仍然"认识"各家字段名(OpenAI prompt_tokens、 Anthropic cache_creation_input_tokens、DeepSeek prompt_cache_hit_tokens、 GLM sensitive 等)。这是有意保留的中立层设计,而非 D6 残留 bug:

  • 这些是permissive 归一化器——接受任一已知别名并产出统一 key,不需要"知道这是哪个 provider"。
  • 与 extract-text / extract-tool-calls(协议方法,provider 自取)不同,usage/finish-reason 在多数 provider 间只有两种常见位置(顶层 or choices[0]),permissive 双查足够鲁棒。
  • 彻底 DIP 化(给协议加 extract-usage / extract-finish-reason,每个 provider 自实现) 是破坏性变更:协议加方法 → 所有 provider record + 所有测试 reify 都要实现。 收益(新增"第三种 usage 位置"的 provider 才需改 core)与破坏面不成比例。

结论:保留 permissive 单一来源;新增 provider 若用非主流字段,只需在 model/response.clj 一处加别名。若未来要做破坏性大版本,再考虑协议化。


3. 原「暂缓」两项——均已结案(2026-07-16 复核)

本节原题「暂缓(需专项 / 破坏性大版本)」,列了 D7 剩余与 D6 剩余两项。 复核发现两项都已不成立,且本文档头部状态与本节自相矛盾(头部写「双消息体 系统一已于 2026-07-10 落地」,本节还写着「建议作为 v0.2 专项」)。现结案:

✅ D7 剩余 — 双消息体系统一:已完成(2026-07-10,v0.2)

model/types.clj 已删除——model/ 下现只有 message / response / error / service。tool-call 全库统一为 {:id :name(字符串) :args}(与中立消息同构), response→neutral 桥退化为形状复位。scripts/check_docs.clj 已为 model.types 立墓碑,防文档复活这个幽灵 ns。

❌ D6 剩余 — converter/json_schema 的 provider 分发:对象已不存在

原文说「converter/json_schema.clj 按 :openai/:anthropic/:zhipu/:gemini 生成 结构化输出格式,是 core 里另一处『认识各家 wire』,随 v0.2 一并处理」。

整个 converter/ 子系统已在 c1a3ab1(「删除无消费者的 converter + prompt 子系统」)中删除——json_schema.clj / api.clj / json.clj / protocol.clj / retry.clj 全没了,core 里 im.ttalk.agent.converter 零引用。 这项工作的对象本身不存在了,无从「随 v0.2 处理」。 (结构化输出现由 advisor/structured_output.clj 承担,JSON 解析经 :parse-fn 注入——core 不内置解析器,见 advisor-alignment-design.md §3。)

❌ D6 主项 — 彻底协议化(extract-usage / extract-finish-reason):不做

保留 permissive 中立层(认识各家字段别名)就是 D6 的结论(见本文头部「定调」)。 协议化是破坏性变更、收益/破坏不成比例,且无真实需求——原记「留 v0.2」, 而 v0.2 已发布、0.3 亦在途,无人触发。按 design-principles.md §1,触发条件到期无人问津即证其为 假想需求,故结案不再挂账。

4. 影响 / 风险

  • 破坏性:移除了协议方法 build-result-messages/build-assistant-message 与响应协议 response-assistant-msg。外部若有自定义 provider 实现了这些方法——删掉即可(运行时本就不调用); 若读取过 response-assistant-msg——该值本就恒为 nil。属安全的破坏。
  • 回归:全套 192 tests / 759 assertions / 0 失败;删除的是死方法专属测试。

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close