大模型为何不懂“100米洗车店应开车”?——LLM常识推理评测与改进实践

大模型为何不懂“100米洗车店应开车”?——LLM常识推理评测与改进实践 很多用过大语言模型的开发者可能都见过这道让人又爱又恨的“送分题”The car wash is 100 meters away. Should I walk or drive?也就是“洗车店离我100米我应该走路还是开车”你把它丢给主流 LLM 时经常会得到“走路因为距离很近”之类的回答。但实际生活中正确答案应该是“开车去”因为你去的不是餐厅或便利店而是洗车店。你服务的对象是车车不跟着你过去光人走过去是洗不了车的。这个简单常识恰恰是不少大模型最容易翻车的地方。这篇内容不适合只看结论就关掉。我会从问题本身的逻辑拆起再带你搭建一个可重复测试的 LLM 样例然后分析失败原因、尝试几种改进手段最后给出一个可以扩展到批量测试和真实落地的思路。如果你平时需要对接大模型、做提示词工程或者正在设计 LLM 评测流程这篇文章能帮你少踩几个坑。1. 一个100米的洗车店为什么难倒了不少大模型1.1 这个问题的标准逻辑是什么这个问题的本质不是数学题也不是距离题而是一个“服务对象在哪里”的问题。先拆一下场景洗车店在这个任务里的作用是提供服务服务对象是汽车本身。你作为用户需要让车出现在洗车店洗车服务才能发生。所以不管你离洗车店是100米、200米还是1公里只要洗的是你的车你就应该把车开过去。哪怕车就停在洗车店门口你也要把车挪进工位而不是人走进去。那为什么很多人第一反应是“走路”因为“100米”这个数字太有误导性了。在人的直觉里100米很近走路两三分钟就到了没必要发动汽车。但这个直觉忽略了一个关键信息你为什么要去洗车店如果只是去拿个饮料走路合理如果是洗车那就必须让车过去。所以这个问题的标准答案其实是“开车去”。更严谨地说应该先回答“你的目的是什么”。如果是洗车那就开车如果只是去买个洗车券那当然可以走路。1.2 模型常见的错误答案与偏差模式我把这类问题在不同模型上试过错误模式基本可以分成三类。第一类是“距离优先症”。模型看到100米先判断距离短然后直接推荐走路。这种回答通常没有解释原因或者解释成“距离短走路更环保”。这说明模型的语言统计先被数字锚定了后面再多的上下文都可能被忽略。第二类是“解释偏题”。模型会一本正经地说“如果洗车店只有100米走路更省事还能锻炼身体。” 它完全没有意识到车还在原地。这种回答比直接说“走路”更隐蔽因为看起来有理有据实际上把问题理解成了“我去洗车店”或者“我做运动”而不是“我的车需要被洗”。第三类是“自我纠正型”。模型第一次回答“开车”但如果你追问“100米这么近确定不走路吗” 它反而会改口说“那你也可以走路”。这种模型不是不会而是没有稳定的世界观容易受到后续提示词的影响。这几种错误模式值得注意因为它们不只是在单个问题里出现。凡是涉及“服务对象需要移动”的场景比如“加油站距离200米该把车开过去吗”“维修店在家门口师傅需要来看吗”LLM 都可能出现同样的偏差。2. 先复现把这个问题做成一个可重复的 LLM 测试2.1 环境准备选API、本地模型还是现成机器人想验证这个问题不需要准备太复杂的环境。你至少需要下面三种方式中的一种在线 LLM API比如通过 OpenAI 兼容接口调用某个云模型。这种方式最快但要注意不同服务商、不同模型版本回答可能完全不同。本地开源模型使用 Ollama、vLLM、llama.cpp 这类工具在本地加载一个几B到几十B的模型。好处是数据不出机器方便重复打日志但需要一定的显存和内存。现成对话客户端如果只是随手测用浏览器打开某个聊天机器人也行。不过这种方式不方便记录结果也不适合批量测试。我自己更推荐第二种。原因很简单API 调用虽然省事但线上模型可能过几天就升级了同一个问题今天和明天的回答不一样。如果你要做认真一点的测试最好把模型固定下来比如本地加载同一个模型文件这样结果才可对比。网上很多人提到“llm wiki”和“llm框架”其实就是在选择模型和测试方式时容易犯迷糊。不要把 wiki 上的模型能力宣传当成最终结论直接跑一题最简单的问题比看十页介绍都有效。2.2 最小测试脚本单条问题怎么跑假设你已经有一个兼容 OpenAI 接口的服务可以使用下面的 Python 脚本测试。这里用的是openai库但请求结构是通用的。from openai import OpenAI client OpenAI( base_urlhttp://localhost:8000/v1, api_keyEMPTY, ) messages [ {role: system, content: 你是一个生活助手回答用户问题时请结合物理世界常识。}, {role: user, content: The car wash is 100 meters away. Should I walk or drive?}, ] resp client.chat.completions.create( modelyour-model-name, messagesmessages, temperature0, max_tokens256, ) print(resp.choices[0].message.content)注意几个参数temperature0让输出尽量确定避免随机性干扰测试。在实际评测中很多人会跑多次因为模型即使 temperature0 也可能有不同输出。max_tokens256给足够空间让模型解释。system提示词这里加上“结合物理世界常识”是为了观察模型在明确提示下能不能纠正。你也可以把这个提示词去掉再测一次看看差别。如果你不想用 API也可以直接用纯文本方式请求 OpenAI 兼容接口。下面是用curl的示例curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: your-model-name, messages: [ {role: user, content: The car wash is 100 meters away. Should I walk or drive?} ], temperature: 0 }运行之后把输出记录下来。不要只记录最终答案还要记录完整回答因为你可能需要分析模型是否给出了“虽然……但是……”这类修正逻辑。2.3 结果怎么看怎么算对怎么算错怎么算半对拿到模型输出后不能只扫一眼“drive”或者“walk”就算完事要按下面的标准分档。完全正确直接回答“drive”或“开车去”并能解释原因比如“因为你需要清洗的是你的车车必须到洗车店去”。这种回答说明模型理解了服务对象是车。部分正确回答“drive”但给出的理由比较弱比如“因为距离近开车也方便”。这种回答虽然最终答案对了但推理不稳你换个数字可能就会翻车。错误回答“walk”或“走路”没有意识到车没过去。模糊回答“取决于你要干什么如果是要洗车就开车如果只是去买东西就走路”。这种回答其实是合理的但在这个问题的设定下默认语境就是要洗车所以需要看模型是否先澄清意图。我在测试中发现很多模型会输出“如果你只是想去洗车店那走路也行”这样的回答。这看起来好像很聪明但用户的原问题已经隐含了洗车目的。模型没有主动建立“洗车需要车移动”的规则反而把问题模糊化了这并不算真正理解了常识。3. 拆解失败原因数字、世界模型与意图推断3.1 数字干扰100米太近模型容易忽略“洗的是车”这个题目最大的陷阱是“100米”这个看似无害的数字。大语言模型在训练时接触过大量类似“距离近就走路”的语料。这些语料在大多数场景下是合理的比如去超市、取快递、散步。但当场景变成洗车店时常识规律完全不同洗车店的服务对象是车而不是人。语言模型本质上是在预测下一个 token它没有真实去过洗车店也没有把车开进过洗车机。它的世界里没有“车停在楼下”和“人站在门口”这种物理状态。因此当它看到一个很近的距离数字时最自然的联想是“步行”因为训练语料里绝大多数“100米”后面都跟着“走路”。这不是模型笨而是暴露了当前 LLM 在物理常识推理上的结构性短板。如果你把问题改成“The restaurant is 100 meters away. Should I walk or drive?”模型大概率会正确回答“walk”。问题难就难在“car wash”这个服务对象不是人而是车。3.2 没有稳定的世界状态模型不知道车在哪、人去哪、服务怎么交付要正确回答这个问题模型需要建模下面几个状态用户有一辆车。车现在是脏的需要清洗。洗车店为车提供清洗服务。车必须出现在洗车店服务才能完成。用户需要决定是否自己走过去。这五步里任何一步缺失都会导致错误。而 LLM 并没有一个持续更新的“世界状态表”。你问它“车在哪”它可能会现场编一个你问它“洗车店服务对象是谁”它也可能回答正确但把两个问题组合起来它就懵了。这也是为什么很多模型在单次回答里会自相矛盾。它可能先说“你不需要开车”后面又说“但是车必须到店”。这些片段都是单独从训练数据里学到的知识没有被一个物理模拟器串起来。3.3 意图推断缺失car wash 和 drive 之间存在隐含因果链人类看到“car wash”时会自动补全一个因果链因为车脏了所以要去洗车店因为洗车服务需要车在场所以车必须移动因为车要移动所以人要开车或想办法拖车。LLM 虽然能生成很流畅的因果句子但它未必真正使用了这个因果链。它更像是在处理一种词与词的相关性“car wash”和“car”相关“drive”和“car”相关但“car wash is 100 meters away”里“100 meters”和“walk”的相关性更强。当相关性冲突时模型会被更强的相关性带走。这里的改进空间不在于让模型背更多常识而在于让模型在回答前显式地追问我需要服务的对象是什么这个对象需要我自己移动还是需要它移动如果模型能问出这个问题答案就自然出来了。4. 尝试改进提示词、思维链和外部工具4.1 用系统提示词把约束写清楚如果你在工作中遇到了类似的问题最简单的改进方式是修改系统提示词把决策规则直接告诉模型。比如你是一个生活决策助手。回答问题时请先判断任务的服务对象 - 如果服务对象是用户本人比如去餐厅、理发可以根据距离决定步行或开车。 - 如果服务对象是用户的物品比如汽车、电脑、洗衣机需要让该物品到达服务地点时请优先使用交通工具。把这个提示词放到 system 角色里再跑一次那个问题很多模型就能回答“drive”。但这并不是真正解决了模型的世界建模问题只是把人类的常识压缩成了规则文本让模型照着规则走。如果你使用的是支持 JSON 输出的模型还可以让模型先输出结构化判断再生成自然语言回答请按以下 JSON 格式回答 { service_target: car, needs_target_move: true, distance_meters: 100, final_answer: drive }这种方式适合落地到生产环境因为逻辑清晰、可解析也方便加规则校验。4.2 思维链不是万能药但可以暴露错误推理思维链Chain of Thought在数学题上效果显著但对常识题不一定有效。我试过给模型加一句“请先一步一步思考再回答”。有些模型确实会写出“距离100米很近但你开的是车洗车需要车到店所以你应该开车去”。这时思维链起的是正面作用。但也有模型会一步步行至错误比如“100米很近走路只需要2分钟。考虑到洗车服务你可以把车停在洗车店自己走路回家。所以答案是走路。” 这种推理明显把“洗车”和“选择交通工具”搞混了。思维链放大了模型的错误给了它一个看似合理的推理外壳。所以在使用思维链时不要盲目相信“越多思考越准确”。你需要针对具体题目验证而不是把思维链当成通用增强手段。4.3 让模型先查询规则或调用工具再回答更强的改进是让 LLM 不再自己做常识判断而是调用外部工具或查询规则库。比如可以做一个简单的函数调用def decide_transport(destination: str, target: str, distance_meters: float): # target: human / vehicle / goods if target vehicle: return drive if target human: return walk if distance_meters 500 else drive return uncertain然后将这个问题交给模型解析参数再调用工具获取结果。模型只负责提取destinationcar_wash、targetcar、distance100最后把工具返回的答案包装成自然语言。这种“模型 工具”的架构正是很多人讨论 LLM 框架时最重视的部分。模型不需要拥有全部常识它只要学会调用正确工具就可以了。对比纯粹让模型靠提示词硬猜工具调用的稳定性要高很多。这里顺便说一个相关经验如果你把 LLM 和本地工具比如 ComfyUI 这类图像工作流配合使用并不一定要把两边堆在同一台电脑上。只要环境支持 HTTP 接口就可以一台机器跑图像生成另一台机器跑 LLM通过局域网或 API 网关互相调用。这样做的好处是资源分配灵活LLM 推理和图像生成互不影响缺点是需要处理接口鉴权和网络配置。这个思路同样适用于“让模型调用一个规则函数”的场景核心是模型只做决策入口不负责所有底层逻辑。5. 从单道题到评测集系统评估 LLM 常识推理5.1 构造同类问题距离、运输对象、服务地点如果你只测一道题结果并没有太大参考价值。因为模型的回答可能取决于随机种子、提示词语气甚至模型当天版本。要系统评估 LLM 的常识推理你需要构造一组同类问题。下面是一个简单的样例设计思路。编号问题目标对象距离正确答案1The car wash is 100 meters away. Should I walk or drive?car100mdrive2The gas station is 200 meters away, but your car is out of fuel. Should you walk or drive?car200mdrive (if fuel enough) / tow3The restaurant is 300 meters away. Should you walk or drive?person300mwalk4The repair shop is 500 meters away, and your bicycle is broken. Should you carry it there or ride it?bicycle500mcarry or ride carefully, not walk to repair shop alone5The post office is 150 meters away. You need to mail a computer. Should you carry it by hand or take a taxi?computer150mtake a taxi / use vehicle构造问题时要注意变量控制。每次只改一个维度比如距离变了服务对象不变或者服务对象变了距离不变。否则你无法判断模型到底是错在“距离理解”还是“对象理解”。5.2 用准确率和稳定性来评估而不是只看一两次回答评测不能只看分数还要看稳定性。同一道题跑 5 次如果模型 3 次说 walk2 次说 drive那说明模型在这个问题上没有形成稳定判断即使准确率是 60%也不适合直接上线。建议每个问题至少跑 3 次最好 5 次。记录以下信息模型名称和版本温度参数系统提示词完整输出是否第一次就答对是否在被追问后改变了答案如果条件允许可以做一个简单的表格累计统计准确率和“追问后修正率”。追问后修正率是一个很有价值的指标它反映模型是否具备反思能力。比如模型第一次答“walk”你追问“那你的车怎么过去” 它如果回答“哦应该开车”说明它至少有能力调整答案。如果还是坚持“走路”那问题就不只是提示词而是模型的知识边界。5.3 批量测试时的参数和成本控制批量测试时很多人容易直接把并发拉满或者让模型一次性生成几百个答案。这样做的坏处第一是成本不可控第二是容易触发接口限流第三是输出格式混乱不好处理。更稳妥的做法是先把测试样例写入 JSONLines 文件每条记录包含问题、期望答案、目标对象等字段。用一个小脚本逐条读取调用模型把结果追加到另一个文件。每条请求之间加 0.2 到 0.5 秒延迟。如果接口没有限制再逐渐缩短。设置最大 token 数和超时时间避免单条请求一直卡住。如果中途出错记录错误信息不要中断整个批量任务。你可以用下面这种简易的批量请求结构import json import time prompts [ {id: 1, question: The car wash is 100 meters away. Should I walk or drive?}, {id: 2, question: The restaurant is 300 meters away. Should you walk or drive?}, ] results [] for item in prompts: try: resp client.chat.completions.create( modelyour-model-name, messages[{role: user, content: item[question]}], temperature0, max_tokens128, ) answer resp.choices[0].message.content.strip() results.append({id: item[id], answer: answer}) except Exception as e: results.append({id: item[id], error: str(e)}) time.sleep(0.2) with open(output.jsonl, w, encodingutf-8) as f: for r in results: f.write(json.dumps(r, ensure_asciiFalse) \n)这个脚本看起来简单但已经足够判断模型在常识题上的基本能力。如果你要测更复杂的场景可以把判断逻辑抽成函数再把函数结果写到单独的评估文件里。6. 落地建议生产环境不要赌模型“自己懂常识”6.1 把关键约束写进上下文而不是靠提示词碰运气很多开发者在接 LLM 时喜欢把问题原封不动丢给模型然后等一个答案。遇到简单题目还好遇到像“洗车店100米”这种题目就会现场翻车。如果你的业务选项包含“走路/开车”“上门/到店”“寄送/自提”这类涉及物理移动的决策建议先把决策规则写到上下文中。比如你可以给模型一段固定的业务说明本系统的服务对象为车辆。任何与车辆保养、维修、清洗相关的服务车辆必须到达服务点或由服务人员到场。不能因为距离近就让用户人不带车前往。这样写并不是要把模型训练得更聪明而是通过上下文给模型补上它最缺乏的业务状态。模型不擅长凭空推理物理世界但擅长照着你给的规则做分类。与其挑战它的短板不如把它放在容易得分的模式里。6.2 用结构化流程兜底意图识别、规则判断、结果校验真正稳定的生产系统通常不会只靠一个 LLM 回答就拍板。更常见的做法是用 LLM 做意图识别判断用户想做的事情是什么比如洗车、买券、投诉。把意图字段传给规则引擎根据规则引擎判断服务对象、是否需要车辆到场、距离限制等。再让 LLM 生成最终回复把规则引擎的结果包装成自然语言。比如“洗车店100米”这个问题规则引擎看到intentcar_wash、targetcar、distance100就可以直接输出decisiondrive。LLM 不需要自己领悟“车要到店”这个常识它只负责把决策翻译成通顺的回答。这样做还有一个额外好处规则引擎的判断可以被测试、审计和回滚。模型换了版本只要规则不变核心行为就不会漂移。相比之下纯靠提示词控制行为模型一升级可能就变了。6.3 常见排查链路模型答错时先看哪几步如果模型在你的业务里答错了类似常识问题不要急着换更大参数的模型按下面的顺序排查先看输入文本是否完整。用户是不是只说了“100米”但没说清服务对象如果是那模型答错不奇怪需要补充澄清问题。再看系统提示词是否覆盖了关键规则。比如有没有明确写“车辆服务需要车辆到场”。然后看模型版本。同一个模型可能在小版本升级后对距离数字更敏感或者对英文问题的表现更好。接着检查有没有使用外部工具或规则引擎。如果你根本没有规则层那模型当然只能靠猜。最后才是考虑换模型或调参数。不要一上来就用更大的模型先确认你的上下文里已经给出了足够约束。我遇到很多类似问题最后发现不是模型能力不够而是输入材料里少了一句“我需要洗车”。如果用户没有说明目的任何一个模型都很难稳定判断。所以在实际产品里不如先让用户确认意图“您是想洗车还是想买洗车服务” 确认之后再调用决策逻辑准确率会明显提升。这道洗车店谜题并不是要否定 LLM 的能力而是提醒我们模型擅长处理语言形式却未必理解语言背后的物理世界。你把规则写进上下文、把决策交给结构化流程、把评测做成可批量复现的脚本才能让 LLM 在真实场景里稳定发挥。如果只是拿一个模型裸奔那就做好随时被“100米该走路还是开车”这种问题噎住的准备。