文章总结了汽车检测AI产品Inspecly的架构经验,强调先理清数据可靠性和处理职责,再考虑LLM选型。
当构建 AI 产品时,从时尚光鲜的组件入手是很诱人的做法。
然后把一切都接到 LLM 上,寄希望于最后的 prompt 能让一切变得有意义。
在构建 Inspecly 背后的汽车 AI 流水线时,我们最终几乎采取了完全相反的做法。
第一个问题不是:
我们应该用哪个 LLM?
而是:
我们实际拥有什么信息?它的可靠性如何?应该由哪个系统来处理它?
这个区别改变了整个架构。
驾驶员很少像机械师那样描述车辆问题。
"我的车启动时会发出奇怪的噪音。"
但一份请求也可能包含:
一段文字描述,
或者只有其中某几项。
这些输入并不具有相同的可靠性。
OBD 码是结构化的信息。
照片是视觉证据。
语音消息代表驾驶员观察到的情况。
车辆元数据可能需要精确查询。
将它们都当作等价的文本片段来处理是一个错误。
因此,在让 LLM 去推理问题之前,我们先对可用的证据进行规范化。
{ "vehicle": { "make": "...", "model": "...", "vin": "optional" }, "description": "The engine loses power when accelerating.", "voice_transcription": null, "obd_codes": ["..."], "images": [...] }
这个对象不包含诊断结果。
它描述的是我们实际知道的东西。
你完全可以这样做。
描述 + 图片 + OBD + 车辆信息 → 一个模型 → 最终答案。
对于原型来说,这非常有吸引力。
但也很难控制。
考虑这些输入:
OBD 码 → 确定性查询
照片 → 视觉分析
语音 → 转录
车辆信息 → 精确查询 / API
未知的技术信息 → 基于工具的检索
安全约束 → 明确的业务规则
这些是根本不同的操作。
把所有东西塞进一个巨大的 prompt 会掩盖这些差异。
而且会变得很难回答:
这个结论是从哪来的?
一旦系统超出 demo 阶段,这就成了一个严重的问题。
有一个设计决策对我们尤为重要:
如果可靠的结构化信息已经存在,就直接使用它。
例如,当 OBD 诊断故障码可用时,我们首先查询经过整理的 OBD 数据库。
一条记录可能包含如下信息:
{ "code": "...", "explanation": "...", "possible_causes": [], "possible_actions": [], "validation_status": "reviewed" }
当系统可以对经验证的字段执行精确查询时,为什么还要从文档中语义检索相似的段落?
这是一个重要的区别。
结构化数据和 RAG 解决的是不同的问题。
结构化数据适用于:
精确标识符、经验证的字段、受控记录、确定性查询。
RAG 在知识主要存在于文档内部时变得有用。
这就是 agent 变得有用的地方。
我们的内部数据库不可能包含每一种代码、每一种厂商特定的解释和每一种车辆配置。
当结构化知识缺失时,使用工具的 agent 可以搜索额外的信息。
但有一条重要的规则:
检索来的信息不应该悄无声息地变得与经验证的信息等价。
相反,要保留来源追踪。
{ "code": "...", "source_type": "tool_agent", "sources": [], "validation_status": "unverified" }
最终系统应该知道一条信息来自:
经过审核的内部数据库,一个外部技术来源,一个使用工具的 agent,图像分析,或者驾驶员本人。
模型不仅需要上下文。
它需要带来源追踪的上下文。
视觉模型是另一个有用的组件。
一张照片可能揭示:
仪表盘警告灯,
一个损坏的部件。
但照片几乎从来不会讲述完整的 story。
因此输出应该更接近于:
{ "observation": "Possible fluid trace", "confidence": "medium", "limitations": [ "The source is not visible" ], "requires_physical_inspection": true }
而不是:
你的车漏油了。
这个区别很重要。
AI 系统往往比证据实际允许的更加确定。
语音之所以有价值,是因为通过表单描述机械问题可能很困难。
消息被转录后,成为证据层的另一个输入。
"发动机过热了。"
并不一定是一个已确认的技术事实。
它是驾驶员报告的内容。
这个区别应该贯穿整个流水线。
今天,多条处理路径最终都可以为生成上下文贡献信息。
随着来源数量增加,简单的拼接变得越来越难控制。
你最终需要更接近于这样的结构:
{
"reported_symptoms": [],
"obd_findings": [],
"visual_findings": [],
"retrieved_information": [],
"missing_information": [],
"conflicts": [],
"safety_flags": []
}
最终的 LLM 可以从这个规范化的证据中生成,而不是接收一堵未经组织的文本墙。
这让很多事情变得更简单:
也使得架构更容易演进。
我们不是从一个大型汽车 RAG 流水线开始的。
这是有意为之。
向向量数据库添加 PDF 不是困难的部分。
困难的部分是知道检索到的流程是否适用于正确的:
一个完全正确检索到的技术流程,如果用在了错误的发动机代际上,对于你面前的车辆来说仍然可能是完全错误的。
所以我们当前的优先级是:
经过验证的结构化数据 ↓ 显式规则 / API ↓ 需要时使用工具检索 ↓ LLM 生成
当我们有了制造商手册和经过验证的技术文档的受控语料库时,RAG 变得更加有价值。
最终,来源路由可能大致如下:
经过验证的结构化记录
显式的安全 / 业务规则
检索到的已验证文档
这不是一个通用的层次结构。
更广泛的观点更重要:
生成的或检索到的段落不应该悄无声息地覆盖经过审核的事实。
另一个有趣的问题是,同一份证据需要不同的输出。
一方面是不确定性需要被清晰地解释,
以及下一步有用的行动。
另一方面是技术观察,
以及可能需要调查的方向。
我们不需要两个独立的 AI 分析。
我们需要同一份证据的两种表示。
这个区别已经成为产品架构的重要组成部分。
AI 响应的质量不是从最终的 prompt 开始的。
它开始得更早:
输入收集 ↓ 规范化 ↓ 来源路由 ↓ 证据 + 来源追踪 ↓ 冲突 / 不确定性处理 ↓ 生成
一个更好的模型可以改进生成。
但它无法修复一个所有来源都混在一个无法追踪的上下文中的架构。
我目前的收获很简单:
在知识是确定性的地方使用确定性系统。
在灵活性有用的地方使用 agent。
当文档检索确实是问题时使用 RAG。
并且保留不确定性,而不是让 LLM 在一个自信的答案背后隐藏它。
我写了一篇更详细的架构版本——包括当前的流水线、未来的证据层和计划的 RAG 架构——在这里:
Original deep dive: https://younes.hashnode.dev/inside-inspecly-s-automotive-ai-pipeline-from-driver-symptoms-to-actionable-garage-requests
我也在构建 AI DevList,在那里我整理关于 agent、LLM 工程、MCP、RAG、evals 和生产级 AI 的有用资源——并附有每条资源为什么重要的简短说明。
我很想知道其他团队如何处理这个问题:
你是从 LLM 开始向外构建,还是从证据开始向内构建?