工具注册表:装配期把工具声明汇成一张表,运行期一次查表答完
从 chat-client 拆出来的一块。判据是「这些函数认识什么」——它们全部只认识
工具声明(:serial / :retry / :timeout / :return-direct / schema),
一个都不认识 ChatModel、filter 链或消息。chat-client 因此瘦回它的本分:
record + 装配 + 三个 invoke 原语。
对照 beamai 的 beamai_tool / beamai_tool_index——同样是把工具那一摊从
ChatClient 里分出去;Spring AI 对应的是 ToolCallback 注册表那一层。
装配期做掉,运行期只查表:build-tool-meta 在 build-chat-client 时把
var 工具与内联工具两个来源汇成 {keyword -> ToolMeta};此前四个查询函数
各自写一遍 (if-let [v (get tool-vars k)] (读 var 元数据) (查 inline-meta))
——同一段双分支手抄四遍,:timeout 就是在那种重复里漏掉 inline 分支、对内联
工具静默失效的。
本 ns 的查询函数吃 ChatClient(只读 :tool-meta / :tool-vars /
:tool-manager 三个键,不 require chat-client,故无循环依赖)。
工具注册表:装配期把工具声明汇成一张表,运行期一次查表答完
从 `chat-client` 拆出来的一块。判据是「这些函数认识什么」——它们全部只认识
**工具声明**(`:serial` / `:retry` / `:timeout` / `:return-direct` / schema),
一个都不认识 ChatModel、filter 链或消息。`chat-client` 因此瘦回它的本分:
record + 装配 + 三个 invoke 原语。
对照 beamai 的 `beamai_tool` / `beamai_tool_index`——同样是把工具那一摊从
ChatClient 里分出去;Spring AI 对应的是 `ToolCallback` 注册表那一层。
**装配期做掉,运行期只查表**:`build-tool-meta` 在 `build-chat-client` 时把
var 工具与内联工具两个来源汇成 `{keyword -> ToolMeta}`;此前四个查询函数
各自写一遍 `(if-let [v (get tool-vars k)] (读 var 元数据) (查 inline-meta))`
——同一段双分支手抄四遍,`:timeout` 就是在那种重复里漏掉 inline 分支、对内联
工具静默失效的。
本 ns 的查询函数**吃 ChatClient**(只读 `:tool-meta` / `:tool-vars` /
`:tool-manager` 三个键,不 require chat-client,故无循环依赖)。(build-registry var-tools var-map inline-tools schemas)把 var 工具与内联工具两个来源汇成一个 ToolRegistry。
校验先于建表:normalize-retry 会把非法声明 merge 成看似合法的策略,
先归一化就等于把错误藏起来。名字唯一又先于其余校验——重名时 var-map /
inline-handler-map 已经被 into 把重复悄悄吃掉了,再校验别的就是在错误的
地基上校验。
参数:
返回: ToolRegistry
把 var 工具与内联工具两个来源汇成一个 `ToolRegistry`。
**校验先于建表**:`normalize-retry` 会把非法声明 merge 成看似合法的策略,
先归一化就等于把错误藏起来。名字唯一又先于其余校验——重名时 var-map /
inline-handler-map 已经被 `into` 把重复悄悄吃掉了,再校验别的就是在错误的
地基上校验。
参数:
- var-tools: tool var 列表
- var-map: {keyword -> var}(调用方已建好,避免重复计算)
- inline-tools: 内联工具 map 列表(含 :handler)
- schemas: 已编译的 tool schema 列表(var + 内联)
返回: `ToolRegistry`(effective-timeout* chat-client tmeta)effective-tool-timeout 的表体,吃已查好的 ToolMeta——让 invoke-tool
能复用它已经查到的那一份,不必为超时再查一次表。
`effective-tool-timeout` 的表体,吃已查好的 `ToolMeta`——让 `invoke-tool` 能复用它已经查到的那一份,不必为超时再查一次表。
(effective-tool-timeout chat-client fn-name)该工具实际生效的超时(毫秒),nil = 不超时。
缺省不超时——框架不替调用方决定何时放弃。要限时须显式给出,两个来源:
工具声明 deftool {:timeout ms} > 引擎缺省 (...-tool-calling-manager {:timeout ms}) > 不超时
工具声明最优先——它最清楚自己要跑多久(长任务的逃生舱就是「声明一个大的」); 引擎缺省次之,让部署方能整体封顶而不必逐个改工具。
引擎缺省的读取优先走 *active-manager-timeout*(当前正在执行的 manager
的值,R4),回落到 chat-client 的 :tool-manager 字段(直调 invoke-tool 不经
manager 时)。
由 invoke-tool 的 terminal 消费并强制:开箱即生效,不需要挂任何 filter。
超时只包裹工具本体(terminal 内),不包裹 filter 链——审批等待不再吃掉超时
预算(R1)。
该工具**实际生效**的超时(毫秒),nil = 不超时。
**缺省不超时**——框架不替调用方决定何时放弃。要限时须显式给出,两个来源:
工具声明 `deftool {:timeout ms}` > 引擎缺省 `(...-tool-calling-manager
{:timeout ms})` > **不超时**
工具声明最优先——它最清楚自己要跑多久(长任务的逃生舱就是「声明一个大的」);
引擎缺省次之,让部署方能整体封顶而不必逐个改工具。
引擎缺省的读取优先走 `*active-manager-timeout*`(**当前正在执行的** manager
的值,R4),回落到 chat-client 的 `:tool-manager` 字段(直调 invoke-tool 不经
manager 时)。
由 `invoke-tool` 的 terminal 消费并强制:**开箱即生效,不需要挂任何 filter**。
超时只包裹工具本体(terminal 内),不包裹 filter 链——审批等待不再吃掉超时
预算(R1)。(find-function x fn-name)查找 var 工具(内联工具无 var,返回 nil)
参数:
返回: {:tool-var var} 或 nil
查找 var 工具(内联工具无 var,返回 nil)
参数:
- x: ChatClient 或 ToolRegistry
- fn-name: 函数名(关键字或字符串)
返回:
{:tool-var var} 或 nil(list-functions x)列出所有注册的 var 工具名(吃 ChatClient 或 ToolRegistry)
返回: 关键字列表
列出所有注册的 var 工具名(吃 ChatClient 或 ToolRegistry) 返回: 关键字列表
(registry-of x)取出工具注册表:ToolRegistry 原样返回,ChatClient 取其 :tool-registry。
查询函数一律经它,于是「传 ChatClient」与「传裸注册表」两种调用都成立—— 注册表是个独立的值,不是必须挂在客户端上才能用的一摊字段。
取出工具注册表:`ToolRegistry` 原样返回,ChatClient 取其 `:tool-registry`。 查询函数一律经它,于是「传 ChatClient」与「传裸注册表」两种调用都成立—— 注册表是个独立的值,不是必须挂在客户端上才能用的一摊字段。
(retry-policy chat-client fn-name)工具的 :retry 声明(归一化已在装配期做掉)。仅 :transient 类错误按此策略 重试;声明即承诺幂等(重试会重跑整条 tool filter 链)。
返回: nil(未声明,不重试)| {:max-retries n :initial-delay-ms ms}
工具的 :retry 声明(归一化已在装配期做掉)。仅 :transient 类错误按此策略
重试;声明即承诺幂等(重试会重跑整条 tool filter 链)。
返回: nil(未声明,不重试)| {:max-retries n :initial-delay-ms ms}(return-direct-tool? chat-client fn-name)工具是否声明 :return-direct(结果即最终答案,不再回灌 LLM)。
对标 Spring AI ToolCallingAdvisor 的 return direct。
工具是否声明 :return-direct(结果即最终答案,不再回灌 LLM)。 对标 Spring AI ToolCallingAdvisor 的 return direct。
(serial-tool? chat-client fn-name)工具是否声明 :serial(副作用工具;批内并行时整批退化为按序执行)。
工具是否声明 :serial(副作用工具;批内并行时整批退化为按序执行)。
(tool-meta x fn-name)工具的装配期预计算声明(ToolMeta record),未注册则 nil。
下面四个查询都是它的一层薄封装——var 与内联工具在装配期就汇成了一张表, 运行期没有分支可走岔。
工具的装配期预计算声明(`ToolMeta` record),未注册则 nil。 下面四个查询都是它的一层薄封装——**var 与内联工具在装配期就汇成了一张表**, 运行期没有分支可走岔。
(tool-schemas x)发给 LLM 的 tool schema 列表(var 工具与内联工具同列)。
(:tools chat-client) 的替代——四个工具字段收进 :tool-registry 之后,
ChatClient 上不再有 :tools。
发给 LLM 的 tool schema 列表(var 工具与内联工具同列)。 **`(:tools chat-client)` 的替代**——四个工具字段收进 `:tool-registry` 之后, ChatClient 上不再有 `:tools`。
(tool-timeout chat-client fn-name)工具自己声明的 :timeout(毫秒)。
只答「这个工具声明了什么」,不含引擎缺省——那一层见 effective-tool-timeout。
返回: nil(未声明)| 正整数毫秒
工具**自己声明**的 `:timeout`(毫秒)。 只答「这个工具声明了什么」,不含引擎缺省——那一层见 `effective-tool-timeout`。 返回: nil(未声明)| 正整数毫秒
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |