news 2026/10/8 13:35:59

技术线05_端侧小模型不可靠先检查你的Agent架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
技术线05_端侧小模型不可靠先检查你的Agent架构

端侧 4B 模型不可靠?先检查你的 Agent 架构

面向读者:正在做 RAG、Agent、私有化部署或端侧 AI 应用的工程师。
示例系统:完全离线的质量体系助手,生成模型使用 Qwen3.5-4B,嵌入模型使用 bge-m3,存储使用 SQLite,回答要求可溯源。
结论先说:4B 模型不能像云端大模型那样承担“规划、检索、判断、表达、自检”的全部职责。更稳的做法是把架构拆成记忆预算、意图仲裁、证据计划、引用门禁和受控表达。模型可以参与,但不应该拥有最终裁决权。

一、先说问题:小模型经常不是“笨”,而是被架得太高

常见 Agent 链路很直接:prompt 里写清角色,把聊天记录拼进上下文,模型推理后决定是否查 RAG、是否调用工具,最后再由模型生成答案。

这种链路对大模型勉强可用,是因为大模型有较强的长上下文稳定性、格式遵循能力和隐式纠错能力。但换到端侧 4B 后,模型要同时做五件事:

  1. 理解当前问题;
  2. 继承历史对象;
  3. 规划检索和工具;
  4. 组织自然语言回答;
  5. 自查引用和格式。

一旦上下文变长、问法变短、工具参数变复杂,错误就会集中暴露。项目里最常见的失败不是“完全答不出”,而是四类更危险的问题:

失败类型表现风险
历史继承错对象上一轮问 A,这一轮短追问被接到 B回答流畅,但主体错了
短追问缺主语“还有吗”“必须改的有哪些”解析成宽泛问题检索范围漂移
JSON / 工具参数漂移多字段、多枚举、多目标时输出不稳定工具调用失败或调错入口
库外编号被误放行相似度高,模型就把库外标准当成命中的标准高置信地编造引用

第三类尤其值得展开。早期评测里出现过GJB 450A-2004的检索相似度约0.8015,但这个标准号并不在库内。这个问题说明:语义相似度只能衡量文本接近程度,不能证明编号真实存在。如果门禁只有相似度阈值,系统就会把“很像”当成“命中”。

所以,只往 prompt 里加“不要编造”“仔细判断”“严格输出 JSON”是不够的。小模型的可靠性要靠架构让它难错。

二、架构改法:把决定权从模型手里拿回来

这个项目的主链路可以压缩成下面这样:

用户输入 -> Context Core:有界记忆装配 -> Rule Intent:规则优先解析 -> LLM Intent Parser:受限语义提案 -> Intent Arbiter:确定性仲裁 -> Evidence Planner:生成证据计划 -> Retrieval / Tools:受控召回与工具执行 -> Quality Gate Precheck:生成前拦截 -> 4B 受控表达 -> Quality Gate Postcheck:引用后校验 -> 正常回答 / 澄清 / 拒答 / 摘录降级

核心分工是:

  • 规则管边界:域外、系统指令、明确对象、材料上下文优先由确定性逻辑处理。
  • 状态管继承:短追问继承的是结构化意图和目标 ID,不是自由复述聊天记录。
  • 计划管检索:先确定查什么、查多少、允许用什么工具,再执行检索。
  • 门禁管引用:编号、条款、来源必须在允许集合内。
  • 模型管表达:4B 只在受控输入上组织语言,或者输出必须可校验的结构化提案。

这不是不给模型用语义能力,而是把语义能力放在护栏中间。

三、Context Core:历史只补信息,不重写当前意图

长会话最大的问题不是“记得少”,而是“什么都记得”。如果把几十轮原文全部塞给 4B,当前问题很容易被旧主题带偏。

项目里没有把记忆做成一个聊天数组,而是拆成固定事实、滚动摘要、最近完整轮次和检索增强话题。关键预算直接写成常量:

// gjb-agent/src-tauri/src/context_core.rspubconstREAD_PAIRS:usize=12;pubconstRECENT_PAIRS:usize=4;pubconstRETRIEVAL_CONTEXT_PAIRS:usize=3;pubconstSUMMARY_MAX_CHARS:usize=1_500;pubconstPROMPT_MAX_CHARS:usize=10_000;

装配时也保持明确优先级:更早轮次进入摘要,最近 4 轮保留原文,固定事实优先于摘要,最后统一受 prompt 上限约束。

letsplit=turns.len().saturating_sub(RECENT_PAIRS);let(older,recent_turns)=turns.split_at(split);render_prompt_block(&summary,&recent_turns,&pinned_facts,PROMPT_MAX_CHARS,);

这里的重点是:历史上下文只允许补充缺失对象和任务背景,不能反过来改写当前意图。比如用户先问“技术归零是什么”,再问“它和管理归零有什么区别”,系统可以把“技术归零”作为补充对象;但如果当前问题已经显式切换到新对象,旧对象不能继续争夺解释权。

检索 query 也同样有界:

pubfnbuild_retrieval_query(question:&str,turns:&[ConversationTurn],)->String{letmutparts=vec![question.trim().to_string()];letrecent_questions:Vec<String>=turns.iter().rev().take(RETRIEVAL_CONTEXT_PAIRS).map(|turn|excerpt(&turn.question,150)).collect();if!recent_questions.is_empty(){parts.push(format!("相关话题:{}",recent_questions.join(";")));}ifletSome(last)=turns.last(){letconclusion=excerpt(&last.answer,PRIOR_CONCLUSION_EXCERPT);if!conclusion.is_empty(){parts.push(format!("上一轮结论:{conclusion}"));}}dedupe_query_parts(parts)}

这样“还有吗”这类短问不会把整个历史都拖进检索,只会补充最近有限的话题和上一轮结论。

四、意图层:模型输出是提案,不是最终决定

规则意图快、可解释、稳定,但语义泛化有限。LLM 意图解析能补语义,但 4B 输出不能直接相信。项目里的做法是让两者同时存在,再由确定性仲裁器裁决。

LLM Intent Parser 的预算写得很紧:

// gjb-agent/src-tauri/src/intent_parser.rspubconstLLM_INTENT_MAX_TOKENS:u32=128;pubconstLLM_INTENT_TIMEOUT_MS:u64=1_800;pubconstLLM_INTENT_TOTAL_TIMEOUT_MS:u64=2_000;

超时、schema 非法、目标非法都会失败。只有可重试的 schema / object 错误才允许修复,而且第一次调用如果已经超过 200ms,就不再重试,避免短追问被拖成两次完整生成。

letstarted=Instant::now();letfirst=self.invoke(user_prompt,budget,1,started);matchfirst.result{Ok(output)=>LlmIntentOutcome::succeeded(output,attempts),Err(code)if!code.retryable()=>{LlmIntentOutcome::failed(code,attempts,false)}Err(_)=>{ifstarted.elapsed().as_millis()asu64>200{LlmIntentOutcome::failed(LlmIntentFailureCode::RetryBudgetExceeded,attempts,false,)}else{self.retry_after_invalid(user_prompt,budget,started)}}}

模型返回的内容还要过三道校验:JSON schema、封闭枚举、ID 白名单。

lettrimmed=raw.trim();if!trimmed.starts_with('{')||!trimmed.ends_with('}'){returnErr(LlmIntentFailureCode::InvalidSchema);}letvalue:Value=serde_json::from_str(trimmed).map_err(|_|LlmIntentFailureCode::InvalidSchema)?;letmutoutput:LlmIntentOutput=serde_json::from_value(value).map_err(|_|LlmIntentFailureCode::InvalidSchema)?;whitelist.validate(&mutoutput)?;Ok(output)

白名单校验不是简单看类型,而是检查目标 ID、主题 ID、活跃引用 ID 是否都在当前领域上下文允许范围内:

fnvalidate(&self,output:&mutLlmIntentOutput)->Result<(),LlmIntentFailureCode>{validate_closed_set(&output.target_ids,&self.target_ids)?;validate_closed_set(&output.topic_ids,&self.topic_ids)?;validate_closed_set(&output.referenced_intent_ids,&self.active_intent_ids)?;validate_collection_size(&output.secondary_intents,2)?;validate_collection_size(&output.target_ids,5)?;validate_collection_size(&output.topic_ids,3)?;if!output.confidence.is_finite()||!(0.0..=1.0).contains(&output.confidence){returnErr(LlmIntentFailureCode::InvalidSchema);}ifoutput.needs_clarification&&output.ambiguity_code.is_none(){returnErr(LlmIntentFailureCode::InvalidSchema);}output.topic_ids=self.project_topic_ids(&output.target_ids);Ok(())}

确定性仲裁器再做最后裁决。域外硬边界不交给模型:

// gjb-agent/src-tauri/src/intent_arbiter.rsifinput.rule_state.domain_status==DomainStatus::OutOfDomain||input.snapshot.domain_guard_hint()=="reject_domain"||(input.rule_action==IntentAction::RejectDomain&&input.proposal.is_some_and(|proposal|{proposal.primary_intent==UserIntent::Unknown})){returndomain_guard(input);}

有效提案也不会直接采纳,而是先比较规则结果和模型结果是否一致,再根据显式目标、活跃引用、冲突惩罚、规则兜底加分等确定性策略裁决:

letagreement=proposals_agree(input.rule_state,proposal);letmutconfidence=self.base_confidence(input,proposal,agreement);ifcontext_switch_has_rule_task(input,proposal){returnrule_secondary_task_decision(input,confidence);}ifpure_continuation_rule_beats_system_misread(input,proposal){returnrule_decision(input,ArbitrationReason::RuleFallback,confidence.max(self.policy.execute_threshold),);}

这一层的价值在于:LLM 单路不准,不代表不能接入主链路;只要它的输出是可拒绝、可仲裁、可降级的提案,就能参与提高语义覆盖。

五、Evidence Planner:先开检索单,再查库

很多 Agent 的检索是“模型想查什么就查什么”,这在端侧 4B 上很危险。项目里检索前必须先生成EvidencePlan,里面明确证据类型、检索 query、直接来源、输出契约和允许工具。

// gjb-agent/src-tauri/src/evidence_planner.rspubconstMAX_RETRIEVAL_QUERIES:usize=3;pubconstMAX_DIRECT_SOURCES:usize=8;pubstructEvidencePlan{pubevidence_ids:Vec<EvidenceKind>,pubretrieval_queries:Vec<String>,pubrequired_direct_sources:Vec<String>,puboutput_contract:String,puballowed_tools:Vec<String>,}

域外问题不开证据,直接返回no_evidence;需要明确对象但对象缺失时,返回clarification,不让模型猜检索词。

ifstate.domain_status!=DomainStatus::InDomain{returnOk(EvidencePlan{evidence_ids:Vec::new(),retrieval_queries:Vec::new(),required_direct_sources:Vec::new(),output_contract:"no_evidence".into(),allowed_tools:Vec::new(),});}ifrule.requires_targets&&state.target_ids.is_empty()&&!current_material_scope{returnOk(EvidencePlan{evidence_ids:Vec::new(),retrieval_queries:Vec::new(),required_direct_sources:Vec::new(),output_contract:"clarification".into(),allowed_tools:Vec::new(),});}

所有计划也会做数量收敛:

direct_sources.truncate(MAX_DIRECT_SOURCES);

语义召回当然有用,但它必须被夹在证据计划中间:召回前知道范围和上限,召回后还要能校验来源。

六、Quality Gate:生成前后都要有门禁

生成前门禁不是走过场,而是检查任务路由、工具白名单、超时预算和证据状态。证据缺失时不进入 LLM。

// gjb-agent/src-tauri/src/quality_gate.rspubfnprecheck(input:PrecheckInput<'_>)->PrecheckOutcome{ifinput.elapsed_ms>=input.timeout_ms{returnrejected("run_timeout");}ifinput.route_id.is_none(){returnrejected("route_unmatched");}ifletSome(tool)=input.required_tools.iter().find(|tool|{!input.allowed_tools.iter().any(|allowed|allowed==**tool)}){returnrejected_tool(tool);}if!input.has_public_evidence&&!input.has_material&&!input.has_template{returnrejected("evidence_missing");}PrecheckOutcome{passed:true,code:None,}}

生成后门禁继续校验标准号和条款号。允许集合不是模型自己声明的,而是由本轮命中文档、片段和结构化上下文构造出来的。

letmutallowed_docs=allowed_from_docs(hits.iter().map(|hit|hit.doc.clone()));allowed_docs.extend(hits.iter().flat_map(|hit|profile.extract_standard_codes(&hit.snippet)).map(|token|normalized_code(&token)),);letbad_standards=unknown_tokens(profile.extract_standard_codes(&answer),&allowed_docs,);let(cleaned,removed_standards,_)=strip_unknown_token_sentences(&answer,&bad_standards);ifremoved_standards>0{violations.push(repaired("citation_standard_removed","答案含非本轮引用的标准号",false,));answer=cleaned;}

也就是说,模型可以写出一段流畅回答,但如果其中引用了本轮证据之外的标准号,包含这个引用的句子会被剥离。这个动作可能让回答变得保守,但比“高置信编造”更可接受。

七、验证结果:单路不稳,主链路可控

架构不能只讲故事。项目用封闭评测集、真实链路压测和功能回归来验证。

1. 语义意图评测

一组 60 例语义评测的对比:

指标Rule 单路LLM 单路Arbiter 主链路
意图准确率60.00%76.67%100.00%
上下文继承准确率54.17%83.33%100.00%
对象准确率70.27%89.19%100.00%
域外误放行-00
误澄清率-1.67%0
LLM P95 延迟-1600ms1600ms

这组数据容易被误读成“4B 达到 100%”。更准确的解释是:Rule 和 LLM 单路都没有达到稳定接主链路的水平,但经过确定性仲裁、域外守卫和白名单校验后,主链路在这组封闭题集里表现可控。

2. 引用压力集

100 题连续压力集首轮为98/100,暴露的是指代链和证据兜底长度问题。修复指代词表、当前任务继承和硬上限后,完整重跑达到100/100。

这里的重点不是“永远满分”,而是失败能被定位到具体机制,并且能进入回归。

3. 多功能真实链路回归

另一组覆盖标准问答、模板中心、研制过程评审、评审模拟和资格审查的评测:

项结果
真实链路执行750 次
唯一题目450 道
三轮机器判定均通过
引导题86/86 命中目标功能
落库展示一致750/750

这组测试里只有 138 题进入生成回答,大量问题由结构化引导、模板目录、规则知识或审查结果直接回答。这也说明一个端侧 Agent 的稳定性,不只来自“模型答得好”,还来自“很多问题根本不需要把解释权交给模型”。

当然要保留边界:这些是封闭域、固定题集、带校验和仲裁的机器判定结果,不能直接推广为开放域能力,也不能替代业务盲评。

八、可复用的工程经验

1. 不要让 4B 同时做规划、检索、判定和表达

大模型 Agent 可以把多角色压在一个推理过程里,4B 不适合。更稳的结构是每个模块只负责一件可验证的事。

2. 约束要写成常量和契约,不要写成提示词态度

“最近 4 轮保留原文”“query 最多 3 条”“来源最多 8 个”“单次解析 1800ms”这类规则,应该出现在代码、配置和 schema 里,而不是只出现在系统提示词里。

3. 模型输出必须可拒绝

JSON schema、封闭枚举、目标白名单、置信度范围、重试次数、总延迟都要校验。模型解析失败时,系统应该回退规则路径,而不是把非法输出继续往下传。

4. 检索不是自由行动,而是受控任务

先由意图和状态生成 Evidence Plan,再执行检索。query 数量、来源数量、允许工具、输出契约都应该提前声明。

5. 相似度阈值不是引用门禁

相似度只能帮助排序,不能证明标准号、条款号真实存在。引用校验必须基于本轮证据、库内编号和结构化上下文构造允许集合。

6. 拒答和澄清是系统能力

no_evidence、clarification、evidence_missing、citation_standard_removed不是失败文案,而是把不确定挡在系统边界外的机制。端侧垂直 Agent 更需要这种保守性。

7. 判断一个端侧 Agent,先问四个问题

  1. 意图谁仲裁?
  2. 证据谁选择?
  3. 引用谁校验?
  4. 超时怎么降级?

这四个问题答不清楚,换更大的模型也只是把错误往后推。

落地检查清单

  1. 列出模型当前能决定的所有事项,把域外、对象继承、工具选择和最终引用裁决移到确定性模块。
  2. 为上下文、检索、LLM 解析和总链路定义显式预算,用常量或配置锁住,不允许调用方临时放宽。
  3. 给每个模型输出定义 schema、封闭枚举、ID 白名单、超时和失败回退路径。
  4. 在检索前生成 Evidence Plan,明确 query 数量、来源数量、证据类型、允许工具和输出契约。
  5. 建立四类回归:Rule 单路、LLM 单路、Arbiter 主链路、真实链路压测;指标至少覆盖意图、继承、域外误放行、引用违规和延迟。

结语

端侧 4B 的正确用法,不是把它当成缩小版专家,而是给它一张受控工单:输入有界、工具白名单化、证据可计划、输出可校验、失败可降级。

这个项目的实践可以压缩成一句话:

规则管边界,状态管继承,计划管检索,门禁管引用,模型管表达。

当架构先把错误路径拦住,4B 模型反而能在一个很窄但稳定的位置上发挥价值。


说明:文中数据来自示例系统内部评测记录,评测集版本、硬件、并发和阈值变化后,结果不能直接横向比较。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 13:34:43

AI应用架构设计图解:五层骨架、核心组件与落地避坑指南

AI应用架构设计这个词&#xff0c;这两年快被说烂了&#xff0c;但真正落地过的人都知道&#xff0c;它跟传统后端架构完全是两码事。你给一个CRUD系统画架构图&#xff0c;画的是表、接口、消息队列&#xff1b;给一个AI应用画架构图&#xff0c;画的是意图链路、上下文管理、…

作者头像 李华
网站建设 2026/10/8 13:33:06

容器内文件改了却没生效,可能是你没看懂 Mount Namespace

为什么容器内修改文件“石沉大海”&#xff1f;很多工程师在排查 Docker 容器问题时&#xff0c;都遇到过这种令人困惑的场景&#xff1a;进入容器&#xff0c;修改了某个配置文件&#xff0c;重启容器后改动消失&#xff1b;或者明明在容器里写入了大量数据&#xff0c;执行 d…

作者头像 李华
网站建设 2026/10/8 13:32:54

2026个人服务选哪家?专业厂家看这几点

2026年&#xff0c;制造业的竞争已经不再单纯拼产能、拼设备&#xff0c;而是拼“谁能把质量做到极致”。但很多老板在选质量顾问、选服务团队时&#xff0c;依然凭感觉、比价格&#xff0c;结果项目落地难、改善不持续&#xff0c;钱花了不少&#xff0c;客户该丢还是丢。从业…

作者头像 李华
网站建设 2026/10/8 13:32:50

秒档导出助手攻略+避坑:短视频创作者的抖音记录管理指南

前言做短视频的人&#xff0c;抖音私信和聊天记录就是"第二战场"。品牌方私信谈合作、报价、寄样&#xff1b;粉丝私信问问题、报需求&#xff1b;同行的经验交流、干货分享&#xff1b;评论区爆款话题、选题灵感……但这些记录&#xff0c;大部分人处理方式是&#…

作者头像 李华