好几天没有更新文章了,有些朋友关注这MindX项目的朋友都在问我这项目是不是停了?其实代码是一直天天更新的,但这几天一直在找人探讨->思考->重构这样的高速循环中。由其是这几天一直都是集中在对【本地量化模型的控制让其变得更能干更省钱】与【如何充分发挥云端模型能力让MindX变得更像人更聪明】这两个方向上。前者取得了一些阶段性的成果也得到了一些非常值得分享的经验,而后者就比较长篇大论了暂时不打算放到今天的文中,不过我会在后续的文章中用比较容易让人理解的方式来介绍一下的。
MindX的双层双脑结构是我认为这个项目量大的核心亮点,至少在理论上它是行得通的,在初版中它也是能工作的而且初版的目标就是先打下一个可持续迭代的架构基础与运行环境。这几天我在直接使用MindX交流时却是碰到了非常棘手的问题:左脑的沟通能力有点【障碍】具体表现为:
- 问非所答 —— 我问它“今天A股走势如何?”,它会给我回复“你想查询天气的话我需要知道是里个具体地点” 【我X!我问股市你告诉我天气那是跌征兆吗?!】
- 编造答案(瞎猜) —— 我问它“帮我查一下Alex的电话”,它竟然根我说“Alex的电话是13011119999?” 【这很明显一看就是假的,怎么每个模型都喜欢撒谎!】
- 无法执行技能 —— 前面两关过了,要不就是找不到技能要不就是无法执行技能,这真是有点让人有点崩;
我都将这些问题集中地问过 Opus, Gemini 和 GLM5,它们得到的统一回答是:【由于模型太小,能力有限无法理解你的问题或者无法支持工具的调用】
如果真的如AI们所说的那样,那MindX真走不下去,因为第一点就被破题了,跑本地量化模型的根因是为了可以【省钱】,让算力做有价值的事情而不是做些代替人的毫无价值的“双击”类的任务!
所以,我得到一个答案:所有AI模型都在【骗】我!我非常坚定的知道:【qwen3:0.6b这个模型并不是AI们说得那么一无事处,而是被严重低估的】!在概念设计完我是做过可行性测试的,直接用Ollama发原生请求测试它能不能进行正常的交流,是否能执行技能。这些我是有明确答案的:能!
只是我不能问qwen3:0.6b一些比较高级或者需要数据支持的问题,但能力上是不得不佩服阿里团队的这个量化模型的,几乎全能!重点是它仅有500多M就能深度思考还不用GPU,反应速度也就是5~6秒左右,这还是加载速度,加载成了速度还更快一些,这不是牛是什么?这完全是本地使用的最佳Trade-Off方案!
问题与挑战
既然问道于盲,那就只能自己动手,祭出必杀技:【测试】。
我把上述的问题理清了一遍,将输入内容与期望得到的结果分别告诉Opus和GLM5,让它给我将相应的集成测试,端到端测试都给写了一遍。有意思的事情发生了,GLM5的答案是我所预盼的那样糟糕(印证了我之前的文章中吐槽过国内大模型在写测试方面都是垃圾的问题),写的测试不是没有测到点上就是将精力全放到Mock上(我的天啊!我写集成测试它给我去写Mock,这是能听懂人话的模型吗?这好让人恼火)。而Opus却让我惊艳到了,它写的测试质量太高了!老手都知道写一个高质量测试的难度是比普通代码要难3倍以上,至少技巧与思路都得强,所以测试工程师才配得上架构师级别的薪酬。
在果断删除GLM5写的一堆垃圾测试转为全用Opus写测试,而且我给它加了这么一条规则:“不准认为量化小模型能力有限,它能完全满足当前功能的需求,测试不过必然代码逻辑有错”。在这个Prompt的加持下,经过超10个小时以上的奋战(主要是等Opus思考)最后是将问题的根因找到了,也找到了相应的解决方案。
并且经过这次从MindX v1.0.3 → v1.0.4 的开发过程,涵盖 3400+ 行新增测试代码和多处关键架构改进中,我从直觉式的边做边更新思路,总结出一种针对LLM系统测试的新认知:
核心认知:LLM 系统的可测试性设计思路
LLM 的输出天然是非确定性的。传统软件测试追求"给定输入,断言精确输出",但在 LLM 系统中,这条路走不通。我们的核心策略是:
把系统拆成"确定性层"和"非确定性层",分别用不同策略测试。- ┌─────────────────────────────────────────────┐
- │ 确定性层(可精确断言) │
- │ JSON 解析 · Prompt 模板渲染 · 技能索引 │
- │ 关键词提取 · MCP 工具转换 · 向量搜索匹配 │
- ├─────────────────────────────────────────────┤
- │ 非确定性层(需容错断言) │
- │ 意图识别 · 工具选择 · 自然语言回答生成 │
- ├─────────────────────────────────────────────┤
- │ 集成层(端到端验证) │
- │ brain.Post() 全链路:输入 → 意图 → 工具 → 回答 │
- └─────────────────────────────────────────────┘
复制代码注:以上的层次是基于MindX原有架构的重新梳理
“答非所问”的根因在于模型的【情商】有限
经过我反复地采用多种谓词与场景化的测试后,我发现了两个有趣的问题:
这有点像: 孩子好与坏全赖你的爱护与关怀 ^^
确实量化模型的理解能力是有限的,但并不代表模型“不能理解”这是两个不同的概念。要让量化模型去理解我们说话的含义是不能直接将“抽象概念”,“含糊不清的表达”,“富有感情色彩的语义”等这样的方式来沟通的。换句话说,你总不能盼望一个你明示暗示都听不懂,性格死板的【直男】能用他的【高情商】来理解你的表达吧。你得用【钢铁直男】能理解的话术与之交流,又或者给它一个帮助它提高【情商】的正确导引【System Prompt】他才能正常对话。
从v1.0.1开始 MindX就注重提示词工程而将简单的硬编码式的 PromptBuilder 利用Go强大的模板能力升级成可“动态注入”式的 Prompt 模板这一出发点是做得正确的。Prompt 模板中的技能关键词不是硬编码的,而是从实际安装的技能中动态提取并注入:- 当用户的问题涉及以下关键词时,can_answer 必须为 false:
- {{ .SkillKeywords }}
复制代码 这确保 LLM 的判断边界始终与系统的实际能力对齐。测试中通过 prompt_builder_test.go 验证这个注入过程的正确性。
说人话就是人这样做能提升模板对关键词的理解力,并且提供更多的示例内容更可以丰富量化模型的【情商】
经过这次测试与的成果的反补,量化模型在对意图的识别能力上至少不输于中量7b或14b的模型了,至少能【听懂】人话了。
大模型中有一个非常重要的参数那就是 temperature 它是影响着模型输出结果的随机性,它越小,模型输出的随机性就越高,越能模拟人类的思维模式。
说人话就是:这个值越低越【听话】,越高则越有【想像力】
一般的取值范围是:
- 0.3 ~ 0.7 区间模型会以【死板】【听话】的方式如实输出;
- 0.7 ~ 1. 5 区间模型会以【有想像力】的方式生成更合理的结果; 适于创作性工作。
那当LLM应用在意图识别我就将0.7一直降到0.3,这样小模型就只能以【直男癌】的方式输出结果了。效果超级棒! (下文还会提到这个参数)
模型的瞎编乱造源于它过度【自信】
在图形与视频类的生成模型中除了会有正向提示词(positive prompt),还会有负向提示词(negative prompt)。负向提示词的作用是引导模型避免生成不符合预期的内容。其实LLM模型也具有负向提示词的功能,只是它是被融入至 system prompt 中。
而我们都会习惯地正面输入所有我们想要的内容与规则,正如:当工具调用失败或无法匹配到合适工具时,小模型会"自信"地编造答案,尤其是涉及个人数据(电话、邮箱、地址等)时。这种行为不仅影响用户体验,还可能带来严重的信任危机。
表现:- 用户:李四的电话是多少?
- 小模型:李四的电话是 138-xxxx-xxxx(编造的号码)
复制代码 这不是模型能力不行!这是由于我们只告诉了它什么是该做的但却不告诉它什么是【不能做】的!这就好像我们教小朋友你可以喜欢干啥就干啥,却不教它【不能】做什么一样,他一定会长歪甚至长大了无法无天而不自知。
所以,要防止模型【瞎编】我们就需要在system prompt 中添加负面提示词,【禁止】【不能】或者【必须这样】这种提示词以示强调或避免它的回答会超出你的预期。
就好像现在的 MindX v1.0.4 的 Prompt 中明确规定:当 can_answer=false 时,answer 【必须为空字符串】。这防止小模型在没有工具支持的情况下编造电话号码、邮箱等个人数据。
测试技巧:硬断言 vs 软警告分级
在LLM的测试之中不是所有验证失败都应该让测试红掉。区分"必须满足"和"最好满足":- // 硬断言:结构性约束,必须满足
- assert.NotNil(t, result)
- assert.NotEmpty(t, result.Answer)
- // 软警告:内容质量,记录但不失败
- if !containsAny(result.Answer, expectedKeywords) {
- t.Logf("⚠ 回答中未包含预期关键词,但结构正确")
- }
复制代码 因为LLM的输出结果具有天然的【不确定性】,所以这会给测试带来很大的麻烦,因为我拿不出一个可以量化的衡量标准,所以测试中只能使用软警告以代替断言的方式来处理。但这种效果既不会胡乱地出现错误,又能达成测试的目的,确实是一种比较简单而实务的方法。
坑爹的"技能"
从 v1.0.0 到 v1.0.3 技能调用总是时灵时不灵的这个问题实在是“坑爹“。为何我一直找不出原因,虽然当前的代码在架构与数据流上都是没有设计问题的,但它的却有一个很难搞的大问题:”测试的可观察性偏弱“。很多情况下我只能手动Debug来看实际变量,但这样无疑是很抵效的。
你可以认为“技能”调用不就相当于一个cli执行嘛,能有什么坑爹的?
首先,这个问题与前面的问题有极强的相关性,如果左脑在识别意图时总是间歇性地出现问题,那右脑是基于左脑的答案进行意图解析的。这就导致了左脑的错误识别会直接影响到右脑的执行结果。
其次,右脑在执行工具时的引导词(System Prompt)与温度(Temperature)相关度也非常高,在我没有做全面的“温度测试”前我也没有意识到这些共因。
最后,也就是坑爹所在了。就是模型输出JSON是不稳定的,有时是JSON有时会是Markdown,这是好多模型都会有的问题,即使你使用了反向提示词,让结果必须以JSON格式输出不能输出无关内容,不能输出markdown格式,也是不稳定。
还有更坑的是 OpenAI 的调用包曾做过改动以前是用 Function Call 现在全转去 Tool Call , 而且两个接口都在还能调! 天哪,综合这4点谁知道我经历过我什么?!!!
还好,虽然现在啥都没有还有那么一点点不服气,我还是将这坑爹货给捉出来了。 这可以算是之前没有严格写测试导致最终将所有潜在问题一次性聚中到一处进行大爆发的典型技术债务了。
小结
通过两天的系统性优化,我总算是成功解决了量化版小模型的不稳定问题,当然横跨3400+行增量测试代码绝对不止我上述所说的这么一丢丢的东西。
但其它的小技巧与和方法我觉得有兴趣的朋友可以移步代码仓库去抠代码来看比我用嘴说可能会更加深刻。
回顾整个过程,我总结出以下经验:
核心洞察
小模型的问题不是"不够聪明",而是"引导不当"。量化版模型虽然在推理能力上不如大模型,但在明确的规则和约束下,完全可以胜任工具调用等结构化任务。
方法论
我们采用的多层防御策略可以推广到其他场景:
层级作用手段Prompt 层预防问题发生规则约束、负面示例工具定义层降低理解门槛参数标注、场景化描述代码逻辑层容错兜底失败重试、fallback 处理基础设施层根因治理竞态修复、状态追踪测试层质量保障真实环境、严格断言最佳实践
- 永远不要信任小模型的"自信":当工具调用失败时,必须有兜底机制
- 参数描述要场景化:告诉小模型"什么时候用",而不是"是什么"
- 可选参数要明确标注:降低小模型的决策负担
- 测试要接近真实环境:mock 测试无法发现基础设施问题
- 断言要严格:警告容易被忽视,硬断言才能保证质量
小身材,也能干大事。关键在于,我们是否愿意花时间去理解和引导它们。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |