先想好再回答:Needle 的置信度门控与工具检索是怎么串起来的

发布时间:2026/10/10 6:46:39
先想好再回答:Needle 的置信度门控与工具检索是怎么串起来的
先想好再回答Needle 的置信度门控与工具检索是怎么串起来的【免费下载链接】needleAutomation foundation model for tiny devices: 2-bit, 8-29 MB, tool calls, ASR, structured extraction and embeddings on phones, wearables, smart homes, robots, cars and microcontrollers.项目地址: https://gitcode.com/GitHub_Trending/needle20/needle端侧工具调用模型面临一个本质矛盾设备上只有 8–29 MB 的权重、约 28 MB 的运行内存却要在一个回合里决定该不该调用工具、调用哪个、参数怎么填而且不允许拿不准就瞎猜。Needle 给出的答案是把它拆成一条决策链模型先在一个有界的内存窗口里完成推理输出结构化 JSON 信封function_calls、reasoning、confidence再由置信度头给出的标量分数做门控只有过了阈值才真正执行工具。这篇文章从 needle/init.py、needle/model/architecture.py、needle/environments/_harness.py 三处源码出发把置信度头 → 工具检索 → 有界内存这条链子的每一环拆开并借门控失灵的故障场景反推设计意图。一条链从要不要动到动了再说先看整条链子的运行入口。Needle.run()在 needle/init.py 中是一个显式的循环先_complete(query)拿到引擎返回的 JSON 信封若type call且function_calls非空就逐个执行工具再把执行结果json.dumps回填给引擎继续下一轮_complete直到模型不再要求调用为止for _ in range(max_steps): calls response.get(function_calls) or [] if response.get(type) ! call or not calls: break ... for call in calls: fn self._functions.get(call.get(name)) if fn is None: results.append({error: unknown tool: name}) continue try: results.append(fn(**(call.get(arguments) or {}))) ... response self._complete(json.dumps(results, default_jsonable), max_new_tokens, groundFalse)每一轮信封里都带着三个字段function_calls工具名 参数、reasoning模型的思考文本、confidence置信度头的标量输出。注意执行顺序先由模型完整推理并产出调用计划才轮到 Python 侧执行——模型永远先想好再回答执行器只是按图索骥并在每轮之间把真实结果反馈回去。README 里对行为契约的描述可以看作这条链的设计目标ask for something no tool covers and you get an empty list, not a guess——覆盖不了的请求返回空列表而不是猜一个工具出来。置信度头学出来的拿不准不是温度参数confidence不是解码时拍脑袋加的后处理而是模型里一个真正的可学习模块。在 needle/model/architecture.py 中ConfidenceHead是ProbeHead的子类与EmbeddingHead、RouterHead并列组成三头class ConfidenceHead(ProbeHead): key, code, out_dim confidence_head, 2, 1 class RouterHead(ProbeHead): key, code, out_dim router_head, 3, 3 calibration_init (0.90, 0.00, 0.60)关键在ProbeHead的实现它把各层hidden_cells汇聚成cells用一组可学习的probes默认confidence_probes4做加权池化再经query、row_bias、proj投影成最终标量。forward_confidence返回confidence_head(...)[..., 0]即每个 token 位置一个 logit最终压缩成 0–1 的校准分数。它是在原始分布上学习并校准的这正是它不可随意微调的根源。.cact归档里三个头以 manifest 方式追加在final_norm之后见 needle/model/export.py 的格式注释heads.manifest按固定顺序1embedding、2confidence、3router记录头编码随后是每个头的probes/gain/query/row_bias/proj/bias张量RouterHead 还额外带一个calibrationFP16 三元组——也就是上面calibration_init (0.90, 0.00, 0.60)对应官方文档里提到的 act / confirm / refuse 三态路由。校准参数是固化进权重文件的运行时无从篡改。这个头的命运直接区分了两条微调路径。本地needle finetune走 LoRA只更新注意力投影置信度头不参与训练而 needle/model/finetune.py 在build_main里明确执行if ConfidenceHead.key in params: params {k: v for k, v in params.items() if k ! ConfidenceHead.key} print(f {dropped:9} the confidence head; it is not trained locally, so confidence reports None)未训练的置信度头会被直接丢弃导出的归档不再带 head。Python 侧则通过_confidence_head_present()读取 manifest 做检测needle/init.py若无头则强制response[confidence] None并给出警告these weights carry no confidence head trained for them。那么门控到底怎么用契约在 needle/environments/_harness.py 里写得很清楚——run_tests(min_confidence0.0)的 docstring 直接声明了生产语义act on a call only at or above the threshold, otherwise treat it as a refusal仅在调用达到或超过阈值时执行否则视为拒绝。判定逻辑是两段式if got and (validation.get(ungrounded) or validation.get(negation)): got [] if got and response.get(confidence, 0.0) min_confidence: got []第一段是接地校验grounding引擎自己标注的幻觉字段ungrounded或否定性请求negation直接清零调用列表第二段才是置信度门控。配套测试 tests/test_environments.py 还锁定了一个容易被忽视的边界test_min_confidence_keeps_a_call_at_the_threshold注明比较是严格小于——置信度恰好等于阈值也算通过不会被误杀。门控默认关闭min_confidence0.0传入正阈值才开启这是显式的生产契约而非模型强制的行为。工具检索先行有界内存兜底顺序是必然的问题来了一个内存只有几十 MB 的端侧模型凭什么能在长对话里不迷失答案藏在工具检索 有界 KV 内存的组合里而且两者的顺序是硬约束。先看检索。Needle.__init__接受tool_index_path参数最终经needle_init(system, tools_json, tool_index_path)传给引擎needle/init.py 第 242 行。这个needle_init的返回值是prefix_tokens——在 needle/_worker.py 的子进程协议里初始化成功后会回传{status: ready, prefix_tokens: prefix}。也就是说引擎在初始化阶段就根据你的工具 schema 建好索引每轮推理前按查询检索出最相关的工具把它们渲染成 prompt 前缀 token。应用侧传入的是全部工具清单一个tools.json可能有几十个函数而模型实际看到的是检索压缩后的子集。这是端侧内存约束下的必然设计把当前有哪些工具可用这件事从无限的工具空间压缩进有限的输入 token 里。再看有界内存。KV cache 的预算不是运行时参数而是写死在架构计算里的。在 needle/model/architecture.py 尾部KV_BUDGET_BYTES 11 * 1024 * 1024 512 * 1024 KV_GROUP 32 KV_WINDOW_MIN 160 def kv_budget_window(config): ... per_layer kd vd (kd // KV_GROUP vd // KV_GROUP) * 4 ... window (KV_BUDGET_BYTES // per_pos) // KV_GROUP * KV_GROUP return max(KV_WINDOW_MIN, min(window, config.max_seq_len))约 11.5 MB 的 KV 预算除以每位置字节数按 32 对齐取整再夹在[160, max_seq_len]之间——这就是每层注意力的有效窗口。sliding_window1024的局部注意力 少数global_layers全注意力层共同决定了模型的记忆上限。更关键的是kv_window与kv_bits被固化进.cact头字段needle/model/export.py 的注释对此毫不含糊a model quantized for one must be RUN at it - leaving either to a runtime flag silently serves the wrong numerics——量化过的 KV 宽度和窗口必须在推理时原样使用任何运行期覆盖都会悄悄给出错误的数值。把这两件事串起来顺序的意义就浮现了内存是有界的所以记忆必须靠检索来前置压缩。模型无法把整个对话历史装进 KV cache它记得的东西只有两部分——检索出的工具前缀 当前窗口内的 token。这也是为什么 needle/init.py 会在第 4 次未reset()的查询后发出警告every turn stays in the conversation, so unrelated queries lose accuracy and confidence。会话越长、越偏离检索前缀精度与置信度一起衰减——不是模型的缺陷而是有界内存设计下必须用 reset 切断会话、让检索重新主导的使用契约。门控失灵会怎样从故障反推设计意图把门控这环故意弄坏最能看清它存在的理由。场景一本地 LoRA 微调后的归档被当成生产模型部署。此时置信度头被丢弃response[confidence]恒为None而门控代码里取的是response.get(confidence, 0.0)——None直接落回0.0。于是任何min_confidence 0的配置都会把所有调用判为拒绝整个 Agent 变成只听不答。这不是 bug而是刻意的不对称模型宁可闭嘴也不在未校准的置信度上冒险。反过来说只有平台微调头随模型一起训练、按你的工具校准的归档才配开启门控这与 README 中local tuning leaves the confidence head untrainedplatform fine-tunes keep the head的表格一一对应。场景二门控的默认值。min_confidence0.0时只有第一段防线在起作用——引擎输出的validation.ungrounded/negation会把幻觉调用清零。也就是说Needle 的先想好实际是三层防御decode grammar 保证输出 JSON 必然可解析结构层、grounding 校验保证字段不脱离输入事实层、置信度门控保证低把握调用不执行决策层。三层任一层失灵行为都向更保守倾斜语法层失效会直接抛RuntimeError接地校验失败会抛ExtractionValidationError置信度不足则静默拒绝。设计意图由此清晰在端侧无人值守的环境里错误执行工具的代价远大于不执行所以整条链的错误方向必须单向指向不做。场景三内存几何被破坏。若用带错kv_bits/kv_window的引擎加载归档或长会话不 reset 导致 KV 溢出到窗口外模型的有效输入与训练分布脱节——检索到的工具前缀可能被截断置信度头在从未见过的上下文形态上输出失真的高分。这时门控不仅拦不住错误反而会为错误背书。这正是为什么kv_window、kv_bits要固化进权重文件、为什么_confidence_head_present要逐个归档检测置信度、内存几何、检索前缀三者绑定同一个归档任何一环被替换整个契约都失效。把链子再串一遍回到标题的设问Needle 的先想好再回答是怎么做到的答案是一条严格有序的链检索先行初始化时needle_init建好工具索引每轮按查询检索相关工具渲染成前缀 token——这是有界内存下唯一的全局知识来源推理限界KV 预算约 11.5 MB、窗口下限 160模型只能在窗口内完成推理kv_window/kv_bits固化在.cact中不容篡改置信度头收口ConfidenceHead从各层隐状态池化出校准标量随RouterHead的 act/confirm/refuse 三态路由一起打包进归档门控裁决接地校验先清幻觉confidence min_confidence再按拒绝处理且阈值相等也算通过循环推进只有通过全部检查的function_calls才会被执行结果回填后进入下一轮_complete。每一环的失败都指向同一个方向不执行、不猜测、不静默出错。对端侧 Agent 来说先想好再回答不是一个修辞而是一套可以用源码逐行验证的工程契约——而这恰恰是 14 MB 权重能在手机和手表上可靠地替你调用工具的原因。【免费下载链接】needleAutomation foundation model for tiny devices: 2-bit, 8-29 MB, tool calls, ASR, structured extraction and embeddings on phones, wearables, smart homes, robots, cars and microcontrollers.项目地址: https://gitcode.com/GitHub_Trending/needle20/needle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考