十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LLM实战:给巴黎面包店排名,从数据清洗到稳定评分

LLM实战:给巴黎面包店排名,从数据清洗到稳定评分 看到这个项目标题我第一反应是有人用 LLM 给巴黎每一家面包店的 pain au chocolat 排名这个选题听起来像是把技术玩出了烟火气。仔细想了一下这个项目恰恰是处理 LLM 实际落地问题的一个很好样本不是让大模型写诗、写代码而是让它基于真实世界的非结构化信息做主观评价并输出可排序的结构化结果。这件事看起来轻松真要做扎实里面涉及数据清洗、评分标准设计、Prompt 编写、批量调用、输出稳定性、偏差处理、结果验证每一步都有坑。这篇文章就按我实际做这类 LLM 评测项目的经验把这个“用 LLM 给面包店排名”的玩法拆开讲清楚从想法到可复现实验的完整链路。1. 先想清楚这个项目到底是在排“面包”还是在排“文本”很多人看到标题会误会以为作者把巴黎七八百家面包店的巧克力面包全买回来让 LLM 一口一口试吃打分。现实不是这样也不可能这样。一个实际项目如果做成这样成本高到离谱跑两天两夜也测不完。这个项目的真实逻辑是把每家面包店的相关文本信息比如店名、地址、历史评价、媒体报道、社交媒体帖子、菜单描述、用户点评内容收集整理之后交给 LLM让它根据这些文本对一个原本非常主观的问题给出可比较的评分和排序。所以这里的关键判断是LLM 不是面包测评师它是文本评分器。它评价的不是面包本身而是文本中呈现出来的这家店的口碑、品质描述、产品特色、服务体验等信号。这个区别决定了项目能做什么、不能做什么也决定了结果可不可信。如果你也想复现这类玩法第一步不是急着写 Prompt而是先问自己我要排名的对象能不能被文本描述覆盖比如面包店这种场景评价信息分散在大量点评文本里文本能带出“酥皮层次”“巧克力浓度”“排队时长”“价格”这些信号这种场景就适合用 LLM 做初筛排序。如果换成“哪家面包店的巧克力味最纯正”这种连人类评测员都很难统一标准的问题那 LLM 也只能靠文本里的关键词和语境推断输出结果只能当参考不能当权威。从这个角度看这个项目的核心价值不在“巴黎面包店排名”这个结果本身而在于它演示了一套可复制的方法如何把一个主观问题拆成多个可评估维度如何把非结构化文本转化为结构化评分如何通过批量调用来完成全量排序以及如何验证这个排序稳定不可信。1.1 为什么选“pain au chocolat”这种具体品类而不是“哪家面包店更好”具体品类比笼统评价更容易用 LLM 做评估。原因是评分标准可以拆得更细。如果你问 LLM“巴黎哪家面包店更好”它只能泛泛地基于品牌声望和历史评价作答输出会比较空。但如果你问“哪家店的 pain au chocolat 更值得推荐”评分维度就清晰多了酥皮的层次感和黄油香气描述巧克力夹心的用料和浓度评价出炉时间和新鲜度相关的描述价格与份量的性价比反馈排队时间和服务体验的提及频率这些维度都能在点评文本里找到对应表达。LLM 擅长从文本中抽取这些信号并且能对同一条文本给出相对一致的多维评分。这就是为什么具体品类比抽象问题更适合作 LLM 排名项目。如果你要复现这个项目我也建议把对象锁定到足够具体的品类上。比如奶茶店排名可以评估“茶底、奶香、配料、甜度控制、出杯速度”咖啡馆排名可以评估“豆子风味、拉花水平、环境噪音、插座数量、咖啡价格”。对象越具体提示词越好写结果越有区分度。1.2 LLM 在这个项目里负责哪一段不负责哪一段明确边界很重要。LLM 在整条链路中主要负责两件事特征提取和评分生成。你把一家店的文本资料丢给它它返回一个 JSON里面包含各维度的分数、总结理由、推荐置信度。它不负责的事情有三件第一它不负责确定店铺清单从哪里来第二它不负责验证文本真实性第三它不负责把不同店的分数拉到同一个比较基准上。第一件和第三件需要你自己做工程处理。店铺清单通常通过地图开放数据或点评平台页面整理评分基准问题要么在 Prompt 里给出统一参照物要么在后处理时做归一化。第二件则是 LLM 项目的天然短板如果输入文本是营销软文LLM 很可能被带偏因为它分不清真实评价和商家自夸。所以在设计项目时我会给输入文本增加一个“来源类型”字段。来源是第三方用户点评、美食媒体测评还是店铺官方宣传分别处理权重。这样至少能在一定程度上降低商业文案对评分的污染。2. 数据收集这一步最能决定排名的可信度做这类项目时大家最喜欢把精力放在 Prompt 调优上但以我的实测经验数据收集和数据清洗对结果的影响远大于 Prompt 本身。一个人工智能模型再会读文本如果输入文本本身来源偏、噪音大、覆盖不均衡输出也不可能靠谱。这个项目的数据链路大致可以分成三块店铺清单、文本语料、清洗转换。店铺清单是排名的基本盘。全量覆盖很难做到通常会先圈定一批候选店铺。常见来源包括地图开放数据里的 POI 列表、点评类网站的热门榜单、本地生活社区的推荐帖。这里要注意一个问题不同数据源覆盖的店铺类型不一样。地图类数据覆盖全但评价信息少点评平台数据评价丰富但偏向热门店社区帖子数量少但描述质量高。我一般会做并集然后去重再按来源数量做标记。文本语料是喂给 LLM 的主要内容。每条店铺记录需要关联几条到几十条不等的文本片段。片段可以是用户点评的一句话也可以是媒体评价的摘要还可以是菜单描述里的关键词。这个阶段不用追求文本量特别大但要保证覆盖足够多元。比如一家店如果只有一条评价排名时置信度就明显低于有几十条评价的老牌店。清洗转换是很多人容易忽略的一步。评分前要先把文本统一编码、去掉明显广告词、过滤与店铺无关的噪声文本再按来源类型分组。如果文本里有“连锁品牌分店”和“独立小店”混在一起还要在数据里标注门店属性否则 LLM 在评分时容易被品牌先验影响。2.1 从真实世界里收集面包店数据没有官方接口怎么办如果你以为这个项目天生就能拿到一份完整的“巴黎面包店官方列表”那就错了。现实世界的公开数据往往是碎片化的。需要先从多个渠道收集再自己合并。以巴黎面包店为例比较稳的做法是使用开放地图数据按区域拉取 shopbakery 或 craftbakery 这类标签的 POI拿到基础店铺名单。针对名单里的每家店到美食点评社区去搜索对应的用户评价。注意很多店的名称在不同平台存在简写、别名、拼写差异匹配时要模糊处理。把每家店最近一年内的文字评价抓下来每条评价保留四个字段店铺编号、来源类型、评论文本、发布时间。这个步骤没有官方统一接口更多是通用的采集加整理。我的建议是小步快跑先选三个街区每家店集中抓 5 到 10 条文本跑通全流程后再扩展到整座城市。不要一开始就追求几百家店否则数据处理会非常痛苦。2.2 清洗文本把自然语言变成可评分字段采集到的原始文本不是直接丢给 LLM 的。以真实点评为例很容易出现表情符号、网络用语、拼写错误、中英文混杂、反讽表达等情况。这些都会干扰评分的稳定性。按我的习惯清洗阶段至少要做以下处理去掉无信息量的句子比如“哈哈哈哈”“前排”“路过”。将表情符号转换成情感标签比如笑脸换成 positive哭脸换成 negative。把明显重复的评论摘要去重防止一条好评重复刷屏。统一价格单位、时间表达方便后续做时空维度分析。清洗不是要把文本改成标准书面语而是要把噪音降到模型处理范围以内。LLM 本身对噪音有一定容忍度但如果十条评价里有五条都是“路过打卡”这种内容评分就会偏向极低置信度。这时宁可按无评价处理也不要硬评。2.3 文本覆盖不均衡时怎么处理比直接跑分更关键现实中一定有热门店和冷门店。热门店可能有几百条评价冷门店只有两三条。直接把这两类店放进同一个模型评分结果会偏向讨论度高的店铺。这就是文本覆盖不均衡问题。我常用的处理方式是分档处理评价量低于某条数的店归为“信息不足”不参与排名或者单独列成一个“待验证清单”评价量中等的店正常评分但降低置信度评价量大的店进入全量排名。这样做更诚实也更符合实际判断习惯。你真要回答“哪家店更好吃”时也不会对一家只有两条评价的店下绝对结论。这个逻辑同样适用于其他 LLM 评测项目。你要比较两个产品一个文档很全一个文档很少直接让 LLM 打分后者一定吃亏。分档处理虽然牺牲了部分覆盖度但换来了结果可信度。3. 评分标准才是 LLM 排名项目的灵魂数据准备好之后接下来就是整个项目最核心的部分定义评分标准。这个环节很多人会低估。常见的错误是把评分标准写得像通用提示词“请给这家面包店的 pain au chocolat 打分。”最后你会发现模型给的分数区分度很低大部分店都在 7 到 9 分之间排名完全拉不开。原因很简单你没有给模型足够的评分锚点。模型不是面包师它只能基于你提供的文本和它自己的知识做判断。如果你不给它一个清晰的评分维度、打分范围、分数含义、比较基准它就会根据自己的“偏好”输出一个模糊的分数。正确做法是像写测试用例一样写评分标准。先把“好吃”拆成一组可验证的子标准再为每个子标准定义 1 到 10 分的具体含义。只有当文本资料给出相应信号时才允许模型给高分。没有信号这一维就标为未知而不是默认给中等分。比如 pain au chocolat 的评分标准可以设计成这样评分维度1-3 分含义4-7 分含义8-10 分含义典型文本信号酥皮工艺文本提及酥皮较厚、油感重、不脆文本提及酥皮正常没有突出描述文本提及酥皮层多、黄油香、入口碎裂“酥皮层次”“黄油味”“表面焦脆”巧克力品质文本提及巧克力很少、甜腻、口感差文本没有对夹心做明确评价文本提及巧克力浓度高、微苦、用料讲究“巧克力爆浆”“法芙娜”“微苦平衡”新鲜度文本提及放凉、干硬、隔夜感文本没有明确描述文本提及现烤出炉、热吃体验好“刚出炉”“现烤”“还冒着热气”价格感受文本提及偏贵、份量小文本没有价格相关评价文本提及性价比高、份量扎实“单价实惠”“一个顶饱”综合推荐度文本以吐槽为主文本正面中性混存大量复购、推荐、排队也要买“为了它排队”“回购 N 次”这个表格写清楚之后Prompt 里的评分要求才真正可执行。3.1 用“评分函数”的思路设计 Prompt我把这类 Prompt 称为“评分函数”因为它本质上是一段让模型按照固定规则做输入到输出映射的指令。好的评分函数 Prompt 必须包含以下要素任务边界明确说明评分依据只有输入文本不依赖模型对品牌的主观印象。评分维度把上面表格里的维度逐条列出。分数含义对每个分数区间给出描述避免模型使用时随意发挥。输出格式要求模型返回 JSON字段固定包含置信度。拒绝规则允许模型在证据不足时返回 unknown。如果你做过本地 LLM 或远程模型 API 调用会发现这个 Prompt 其实就是一份解析规则模型不理解就说“证据不足”理解就返回结构化结果。这和让模型自由评论是完全不同的两种用法。3.2 Prompt 模板的设计细节我实际使用过的模板大致长这样你是烘焙产品评估助手。你要根据给定的面包店文本信息评估该店 pain au chocolat 的综合品质。 评分要求 1. 只依据输入文本中出现的描述不能使用你对品牌的已知印象。 2. 对每个维度输出 1-10 分。文本中没有提及的维度输出 null。 3. 最后输出 recommendationScore表示该店是否值得推荐。 4. rationale 字段用 3-5 句话说明打分依据必须引用输入文本中的关键表达。 输出 JSON 格式: { store_id: string, laminated_pastry: 0-10 或 null, chocolate_quality: 0-10 或 null, freshness: 0-10 或 null, price_value: 0-10 或 null, recommendationScore: 0-10, confidence: high|medium|low, rationale: string }这个模板的关键在于“没有提及就输出 null”而不是“没有提及就默认给 5 分”。默认给 5 分会把大量信息不足的店铺拉到平庸区间导致排名失真。输出 null 后后处理阶段可以直接把该店排除或者标记为“资料不足”这样更合理。如果你用的是支持函数调用的 LLM 框架还可以把上述 JSON 定义成一个 tool payload让模型按 schema 输出。实际操作时你会发现这种方式的输出解析成功率比让模型“自由输出 JSON”高很多。很多模型在自由格式下会漏字段、多加注释、甚至把 JSON 包在 Markdown 代码块里用工具定义可以显著减少解析报错。3.3 多次评分取聚合而不是一次出结果LLM 评分天然有随机性。即便 temperature 调成 0部分模型在复杂任务下仍可能因为上下文顺序、输入噪声等原因给出不一致结果。如果只让模型评一次结果偶然性很大。我一般会对每个对象做三次独立评分然后取中位数或者平均分。三次分数都比较接近说明模型对该店的判断稳定三次分数波动很大说明输入文本信息冲突或者评分标准覆盖不够需要人工复查。这个思路在你的个人项目里完全适用。比如你想比较十家店可以先每家店跑三次评分把三组结果并列展示再看排名是否一致。如果前两名的顺序每次都互换那说明这两家店文本差异不大排名本身没有明显意义。4. 从单店验证到全城批量跑通工程环节不能跳步评分标准写完之后很容易进入“马上跑全量”的冲动阶段。但我建议先把流程切成三段单店验证、小批量测试、全量任务。三段都过了再谈扩展。单店验证的目的是确认数据链路通。你拿一家店的数据手动构造输入跑一次评分函数查看输出 JSON 是否完整、字段是否符合预期、rationale 是否合理。这一步如果出现问题优先排查的是输入文本清洗和 Prompt 格式而不是模型。很多请求报 schema 或 tool payload 被拒绝往往不是模型问题而是提示词里答应了输出某种结构但实际输出没有严格对应框架解析失败。单店跑通之后是小批量测试。我一般会用五到十家店做一次完整流程演练重点验证两件事一是不同输入文本量下评分是否稳定二是批量任务会不会出现超时、限流、输出截断。这一步可以直接决定你后续要不要加重试机制和并发控制。下面是批量任务执行时比较重要的参数表参数建议取值说明单请求超时时间30-60 秒模型需要阅读大量文本时超时设太短容易失败最大重试次数3 次超过 3 次要考虑是不是输入有问题并发数5-10本地模型可以高一些远程接口控制到中低水平单次输入文本量不超过 2000 字长文本会显著增加耗时和费用输出目录结构按店分目录方便复查失败任务批量跑完后一定会出现失败任务。这个时候优先看输入格式和超时时间而不是反复重试。如果某家店的文本特别长或者文本中包含特殊符号很容易导致解析失败。先把这些异常数据摘出来处理再重新提交成功率会高很多。整个批量过程最好有日志。每次请求后把状态码、耗时、返回摘要写下来。后面排查时你会感谢这个习惯。4.1 跑单店时最容易踩的坑单店跑通阶段最常见的报错是“provider rejected the request schema or tool payload”。这个报错往往让人以为模型不能处理文本实际上通常是两处问题一是 Prompt 中声称输出 JSON但输出层配置里没有启用 JSON 模式模型自由生成时把说明文字也带进去了二是输入的文本里包含了无法被工具 schema 接受的格式比如过长的数组、空字段、非法字符。我建议单店验证时就把抓取到的原始文本和清洗后的文本分别保存一份。报错时先对比两份文件判断是不是清洗环节出了问题。这样比直接改 Prompt 更省时间。另外如果单店结果里 recommendationScore 字段出现空白或不在 0-10 范围不要急着用后处理补值。先看模型返回的原始内容确认它是不是把字段名写错了比如写成了 recommend 或 score。字段名不一致在小规模手动任务里不明显批量后会很痛苦。4.2 全量批量任务要关注的三个指标跑全量时我关注的指标有三个成功率、耗时分布、输出一致性。成功率很好理解失败请求占比越低越好。耗时分布看的是大多数请求是不是都落在合理区间如果某几家店耗时异常高说明文本太长或模型生成了过多 rationale。输出一致性看的是同一家店三次评分结果差异大不大。如果成功率低于 90%不要继续扩大任务先回到小批量排查。常见原因是并发过高导致限流、输入文本过长导致超时、个别数据格式异常导致整个批次中止。把这三类问题处理掉成功率通常能回升。如果输出一致性差说明评分标准或输入文本有问题。先去检查文本是否混杂了不同时间的评价或者评价中品牌名和店名混用导致模型混淆。实在不行可以把该店标记为“人工复核”而不是强行给分。5. LLM 评分结果的偏见与稳定性比分数高低更值得关心LLM 评分结果的偏见问题是这个项目最容易被忽视的地方。有经验的人拿到一份 LLM 排名表第一个问题不是“哪家第一”而是“这个排名为什么长这样”。如果答不上来排名就只是一个漂亮的输出文件技术上站不住脚。主要的偏见来源有三个顺序偏见、品牌先验、来源权重失衡。顺序偏见是指当你把几条评价按不同顺序输入时模型可能更重视前几条或后几条文本品牌先验是指模型对某些知名店铺有天然好感或坏感即使输入文本没有明确示意来源权重失衡是指官方宣传文本和真实用户评价在模型眼中没有明显区分但两者可信度完全不同。这些偏见不能完全消除但可以用工程手段降低影响。最实用的办法是打乱输入顺序多次采样。比如每店做三次评分时每次都把评价顺序随机打乱再把三次结果合并。如果三次结果差异很小说明顺序偏见影响不大如果差异很大你至少知道哪家店的结果不稳定。品牌先验的处理稍微复杂一点。可以在 Prompt 里反复强调“只依据输入文本”也可以在输入文本中把店名做脱敏处理比如改成 Store A、Store B。这个方法在实验阶段非常有效。当你需要比较十家店时把店名全部替换为编号让模型专注读文本而不是调用记忆里的品牌印象。来源权重失衡可以这样处理在输入文本前加入来源标签例如 [第三方点评]、[媒体文章]、[商家介绍]。再在评分规则里说明第三方点评权重最高媒体文章权重次之商家介绍仅作辅助参考。这样模型在生成评分时会按你的信任层级理解文本。5.1 温度参数怎么设置才合理很多人跑 LLM 评测任务时纠结 temperature 参数。我的经验是如果任务需要的是稳定排序temperature 调低一些比如 0 到 0.3如果任务需要的是多样化表述比如让模型写推荐语temperature 才需要调高。评分任务本质上是要稳定输出温度太高会导致每次分数波动很大排名完全没有可复现性。但要注意temperature 调成 0 不代表输出绝对一致。部分模型存在数据并行、采样算法差异温度设置只是降低不确定性不是消除不确定性。所以多次评分取聚合仍然有必要。5.2 如何判断排名结果是“稳定”还是“偶然”判断稳定性的简单方法是做两轮完整评分中间间隔一天。把两轮排名对比数一下有多少家店名次发生了大幅度变化。如果大量店铺名次跳变超过五位说明你的评分体系对输入文本或模型随机性太敏感不适合直接发布排名。更细的判断可以看前五名和后五名。如果头部和尾部的店在两次评分中都保持不变中段有浮动这个排名基本可信。因为中段店的文本差异往往较小评分区分度天然更低。还有一种判断方式是对同一批文本做扰动测试。比如删掉一条负面评价或增加一条正面评价再看该店评分变化幅度。变化不大说明评分依据分散模型不是只靠一两条文本做判断变化很大说明该店文本量太少结果需要存疑。5.3 推荐置信度字段该怎么用我在评分模板里设计了 confidence 字段这个字段在后处理中非常有用。high 表示该店有多条文本证据支撑中低表示文本不足或冲突。全量排名时自信度高的店进入主排名低的店进入“资料补充后再评”名单。这个字段不是给模型打分的而是让你在发布排名时知道哪些结果可以拍胸脯哪些只能算参考。如果你要基于排名结果做一些下游决策比如选店合作、生产推荐榜单置信度这个字段基本能决定你是否要安排人工二次确认。6. 从“巴黎面包店排名”延伸出去这套方法还能做什么这个项目的底层方法并不局限于美食排名。只要一个对象能被文本描述覆盖并且存在可拆解的多维评估标准就可以套用这条链路收集文本、清洗转换、设计评分标准、编写评分 Prompt、批量调用模型、聚合排序、验证稳定性。我在实操中已经见过不少类似应用。有些人在企业内部用这个思路给供应商服务文档质量排名判断标准来自响应速度、问题解决率、客户反馈关键词有些人用它给开源框架的文档体验排序标准拆成上手难易、示例完整性、API 注释质量还有人用它批量评估候选方案的可行性报告按成本、风险、收益、团队能力四个维度打散后排序。这些应用的共同点是评价对象都非常具体文本数据真实存在评分维度可以提前设计结果主要用于辅助决策而不是作为唯一依据。这正好是 LLM 的舒适区。如果你已经熟悉了本地运行 LLM 环境也可以考虑把整个流程做成一个可控的命令行工具或局域网服务。把店铺数据放一个目录评分标准写成一个配置文件模型通过接口读取数据并输出 JSON再汇总成一个 Markdown 报告。Karpathy 在 LLM Wiki 里提到过类似思路与其每次临时写 Prompt不如把评估标准、输入输出模板、测试样例都做成文档像维护 Wiki 一样维护它。这个做法放在这里非常合适。评分标准就是一个领域知识库数据样例就是回归测试集每次更新模型或调整 Prompt 后跑一遍样例就能快速确认变化是否合理。再往后延伸还可以把它做成一个 LLM Agent自动抓取指定城市的新增面包店列表自动生成评分数据自动更新城市榜单。这种 Agent 化的好处是可持续跟踪坏处是更容易因为数据源变化而失效。我的建议是先把静态排名做好再去考虑 Agent 化。不要一上来就追求全自动否则你会在数据异常、评价时效、店铺改名这些问题上耗尽精力。6.1 什么场景不建议用这个方法不是所有排名都适合用 LLM。如果问题需要实时实地感官体验比如现场吃一个面包然后判断是否酥脆这类任务就不适合用文本评分方案。模型没有舌头也没有嗅觉。它只能根据别人写的描述推测。如果评价文本里完全没有“酥皮厚”“黄油香”这类表达它就无从判断。如果评估标准本身充满争议比如“哪家店的巧克力面包最有高级感”这种问题人类评委都不一定达成共识LLM 评分也只是给出一种基于文本分布的观点不代表客观真相。这种场景我的处理方式是不做排名做分组。把评价文本按情感倾向分组让读者自己判断。还有一类场景是信息高度敏感的竞价排名、医疗建议、金融产品排序也不建议单纯依赖 LLM 评分结果。这些领域涉及专业判断和合规要求LLM 输出的排序只能作为线索必须经过专业人士复核。6.2 把结果公开之前要补哪些验证券材料如果你打算把这个排名作为一个公开项目比如发布到技术社区或者做成一个 Web 页面建议至少补充以下材料完整的评分维度定义每家店的文本数据量和来源分布模型名称、版本、temperature 等运行参数多次评分聚合方式置信度分组结果当批测试的时间和输入文本快照有了这些材料别人才能判断你的排名有多大参考价值。没有这些材料的排名本质上只是一个 LLM 生成的文本别人无法验证也就无法复用。这个项目的趣味性在于“用 LLM 给面包店排名”这个标题很抓眼球但真正有价值的是背后那套方法和边界意识。如果只是让模型输出一个榜单那和让模型写一段餐厅推荐没有什么区别。能稳定复现、能解释原因、能标出置信区间才是这类项目值得记录的原因。最后留几个我自己在复现这类项目时会优先检查的点数据文本有没有清洗干净评分标准里有没有“没提及就给默认分”的情况批量跑的时候有没有做超时和重试输出 JSON 字段名和解析逻辑一不一致最终结果有没有用多次评分的聚合值。这几处如果都处理好了LLM 排名项目基本就能从“玩具”变成“可用的参考工具”。
返回列表