多模态找房系统:聊天、读图与月度成本估算的工程实践

多模态找房系统:聊天、读图与月度成本估算的工程实践 看到 Show HN 项目标题 Home search that chats, reads the photos, and est. monthly costs我第一反应是这不是给房产搜索套了一个聊天框而是把三个独立问题放在同一条链路里处理了。用户用自然语言描述需求系统要能根据照片判断房源真实状态还要顺带估算出每月持有成本。这三个能力拆开都能找到现成方案合在一起才是难度所在。这篇内容主要面向正在做智能客服、房产信息产品、本地生活助手或者想把多模态模型接进结构化业务系统的人。如果你是产品经理可以重点看数据口径和展示逻辑如果你是后端工程师建议关注图像管道和估算模块的边界如果你只是作为用户去体验这类工具也应该知道它的能力边界在哪里。我先给出一个总体判断这类找房系统最值得关注的不是对话接得好不好而是系统能不能在信息不确定的情况下做出可靠决策。用户说“采光好”这不是一个现成的数据库字段用户问“月成本大概多少”背后的计算口径五花八门。没有业务层的字段设计模型再强也只能生成一堆读起来顺畅、但没法横向比较的答案。1. 它到底改变了找房过程的哪个环节1.1 传统搜索和聊天式筛选的差别不在聊天框传统房产平台的搜索本质是一张筛选表单。用户需要先选定城市、区域、整租或合租、价格上限、户型然后系统返回列表。这个过程不是不好而是要求用户在搜索之前先把模糊需求翻译成精确字段。举个例子。用户说“两个人住预算不高最好离地铁近”系统要正确拆出来这几层含义交易类型是租房房型大概率是一居或两居预算要设置一个上限交通要求是步行范围内有地铁。如果用户还说“能接受合租”这又多了一个候选集合。语言中的“最好”“可以接受”“不要”分别对应不同的约束强度不能全部当成硬条件。聊天式筛选把流程反过来了。它允许用户先讲一句完整的话再由系统负责把自然语言转成结构化查询。真正难的不是语言模型理解这句话而是它能不能把结果拆成“硬条件”和“软偏好”并且在缺信息时主动追问。如果系统只是把用户的问题拼接进关键词搜索那和传统搜索没有本质区别。多轮对话的价值在于当你第一次表达不完整时它能通过两三个问题把决策条件补全再去查房源。这也是为什么这个产品不能只做一个“能聊天的搜索框”。1.2 “读照片”不是看图说话而是抽出可排序字段标题里的 reads the photos 很容易被理解成“图像理解”但真正落到房产场景问题会具体很多。用户看重的是这套房有没有阳台、厨房台面是否完整、墙面有没有渗水痕迹、客厅采光是否充足、卧室衣柜是否够大。这些不是靠模型输出一段“这是一个现代风格的卧室”就能解决的。通用图像描述模型擅长形容风格和氛围但不擅长输出稳定、可用于检索的字段。你要拿它和一个筛选条件做比对就必须把照片结果转成结构化标签。我理解和标题匹配的正确做法是把照片拆成几类分别处理。实拍图用来识别房间类型、家具配套、装修状态、阳台和厨卫设备户型图用来识别房间数量、客厅朝向、过道面积和动线外景图或小区图则用来判断楼间距、是否有电梯、小区环境。这三类图的输出格式完全不同混在一起处理最容易出错。真正需要从一张卧室图片里拿到的不是“有一张床”这种显而易见的信息而是这张床和衣柜之间的距离是否合理、墙面和地板有没有明显损坏、窗帘后面有没有漏水痕迹。如果把这些判断都做成结构化字段比如defects: [wall_damp]、furnishing: partial后面才能支持“这套房毛病多不多”这类问题。1.3 月度成本估算为什么难在建口径项目标题里特别写了 est. monthly costs这很容易被当成一个小计算器但实际上它比聊天更难设计。买卖和租赁场景下的月成本不是一个概念。租房表面上是月租金但住进去以后还有物业费、水电燃气、宽带、停车费以及搬家费和中介费按租期分摊后的金额。如果房子家电老旧还需要预留维修或更换成本。买房就更复杂月供、物业费、供暖费、房屋保险和维修基金都要算进去而且房贷部分还涉及首付比例、贷款年限、还款方式和利率水平。把这么多项目揉成一个总数风险就出现了同一套房子甲算出来是 7800乙算出来是 9300两个人都说自己是“月成本”但口径不同。用户如果拿这个数字去和另一个平台对比也完全对不上。所以成熟的成本估算模块至少要做两层事情。第一层是把输入参数补齐比如租房要确认有没有物业费、是否包含水电第二层是展示分项让用户看到钱的构成。项目标题里用 est. 这个词本身也说明它应该展示成一个范围而不是一个精确数字。2. 想复现同类系统先理清数据流和模块边界2.1 建议的五层数据流我看到不少团队拿到这类需求后第一件事就是调一个多模态大模型想让它一次性完成“理解问题、看照片、算价格、返回结果”。这个做法在演示阶段可以但很难控制错误来源。更稳妥的结构是把系统拆成五层。第一层是房源数据层保存结构化的房产基础信息包括小区、面积、楼层、总价或月租、物业费、建筑年代、是否允许宠物等。第二层是图像特征层离线对房源图片做识别和清洗生成结构化的图片标签缓存。第三层是会话状态层记录当前用户已经确认的硬条件、软偏好和待确认问题。第四层是匹配与排序层先按硬条件过滤再按软偏好打分。第五层是费用估算层独立接收结构化房源数据和用户金融参数输出费用分项。把模块分开最大的好处是出错时能快速定位。用户说“推荐错了”你至少能判断是聊天语义解析的问题、房源过滤条件的问题还是图片标签打错导致排序偏差。如果所有逻辑都在同一个模型里完成排查时只能整段重跑效率会低很多。2.2 环境选型先搭数据再调模型关于技术栈项目源码细节我这里没有掌握所以下面只聊这类系统通用的落地路径。无论最终用什么框架第一次搭建时我都建议按“数据、字段、接口、模型”的顺序推进而不是先从聊天界面开始。先准备房源数据快照。不用多一个小区几十套就够重点是把价格、面积、户型、物业费、租赁状态这些字段整理干净。之后写一个普通后端接口完成传统的筛选。能跑通之后再去接语言模型做意图解析。图像处理放在最后因为图像管道成本最高而且如果连结构字段都没想清楚就不知道该让图片识别输出什么标签。开发环境方面纯业务原型用普通 Web 服务和加了 JSON 字段的数据库即可。图片离线处理可以先用少量样例验证再做批量队列。如果你的机器只有一块常见的消费级 GPU或者只有 CPU也不要急着放弃。对图片识别先用一批小分辨率样例把输出字段定下来再逐步扩大数据量。低配机器能跑通不代表适合批量跑更不代表适合线上实时响应。2.3 成本模块的参数面应该提前定义费用估算经常被放到最后做但我建议提前把参数面定义出来否则后续房源字段、图片标签和前端展示都会受影响。我先列一个比较通用的参数表供参考。场景必须输入项可选输入项说明租房月租金、押金、物业费水电燃气、宽带、停车费、租期、一次性中介费一次性费用建议按 12 或 24 个月分摊买房房屋总价、评估价、首付比例、贷款年限、还款方式物业费、供暖费、房屋保险、维修基金、税费税费和维修基金不是每月发生需要做摊销通用城市家庭人口、通勤距离、宠物数量这些会影响户型偏好和物业要求之所以强调参数面提前定义是因为你越晚确定这些字段后面补数据的成本就越高。如果前期只存了月租金之后想做拥有成本对比还得重新回去抓物业费和小区配套信息接口和页面也都要改动。3. 聊天、读图、算成本三个模块如何串联3.1 意图解析把自然语言变成结构化查询聊天模块最容易做错的地方是让模型直接生成 SQL 或直接调用搜索引擎。正确做法是先限定一个输出结构。这里我用 JSON 示例说明一种通用设计。{ intent: search, hard_constraints: { deal_type: rent, city: 上海, district: [浦东], bedrooms: 2, budget_max_monthly: 5500 }, soft_preferences: [ near_subway, quiet, recent_decoration ], missing_fields: [ lease_term, move_in_date ], follow_up_question: 你计划什么时候入住 }这个结构里最重要的不是 intent而是 hard_constraints、soft_preferences 和 missing_fields 三个字段。hard_constraints 用于强制过滤是用户不能妥协的内容。soft_preferences 用于排序是用户“最好有”的条件。missing_fields 表示系统还没掌握的决策信息用于触发追问。这样用户说“最好有电梯”时系统不会直接排除没有电梯的房源而是把它放到排序层优先展示有电梯的选项。当用户说“便宜又好的房子”时更要依赖这种拆分。“便宜”相对预算和周边均价而言“好”要拆成近地铁、装修状态、户型通透、小区环境等多个指标。系统不能把这种模糊说法原样丢给搜索接口。3.2 图像读取离线批量产标签在线只做查表图像模块的设计目标不是让用户上传一张照片然后让大模型“看图作文”。更合理的做法是在房源入库阶段先对整套图片做离线处理输出结构化标签用户提问时直接读取缓存结果。离线管道可以分两步。第一步先判断图片属于户型图、室内实拍、小区环境还是外景第二步再按类别做字段抽取。室内实拍可能输出房间类型、家具配套、装修状态、潜在问题等信息户型图则输出户型布局和面积分配。给一个简化示例{ image_type: interior_photo, room_type: bedroom, furnishing: partial, has_balcony: false, overall_condition: good, defects: [wall_stain] }输出限定为有限枚举和布尔值比让模型自由发挥更可靠。比如“阳台”不是靠关键词识别而是模型看到推拉门和窗外晾晒区后给出的判断“装修老旧”也不要用“看起来比较旧”这样的描述而是统一映射为等级字段。图片标签不能作为排序的唯一依据。用户问“这套房有没有漏水痕迹”系统应检查图片缺陷标签和房龄数据再结合描述字段回答如果只靠一张看起来不错的客厅照结果很容易失真。整个过程里原始图片和输出标签要保留来源关联方便人工复核。3.3 成本估算确定性计算不让模型自由发挥成本估算模块最好和语言模型完全分开。语言模型负责从用户对话中抽取输入字段计算过程由代码完成。这样既不会出现模型算错月供也方便向用户解释费用结构。下面是一个通用伪代码结构不代表某个具体项目的源码。def estimate_monthly_cost(deal_type, params): if deal_type rent: items { rent: params.rent, property_fee: params.property_fee, utilities: params.utilities, } monthly_total sum(items.values()) elif deal_type buy: monthly_payment calc_mortgage_payment(params) monthly_cost { mortgage: monthly_payment, property_fee: params.property_fee, heating: params.heating / 12, maintenance_reserve: params.maintenance_reserve / 12, } monthly_total sum(monthly_cost.values()) return build_cost_range(monthly_total)这里最关键的是每一次估算都要能拆开解释。用户能看到 7800 是由月租 6200、物业费 300、水电燃气预计 300、网费 100、停车费 900 组成的。这样即使估算不准用户也知道误差在哪一项。费用参数不要写死在代码里。城市、物业费、利率、收费政策都可能变化应该做成配置中心或数据表的字段并记录数据更新时间。3.4 对外接口会话状态和普通搜索要分开系统对外接口建议至少分成两类。一类是普通结构化搜索接口由前端筛选器或运营后台直接调用另一类是会话接口保存对话状态供聊天助手使用。普通搜索接口应该能够接收明确的 filters例如城市、区域、户型、价格区间。会话接口则负责把用户每一轮新说的内容合并进 session然后产生结构化查询。用一个示例说明接口组织方式POST /session POST /session/{id}/chat GET /homes/{id}/image_features GET /homes/{id}/cost_estimate把会话状态独立出来主要是为了处理多轮追问。用户问完预算后接着说“那今年新装修的有没有”系统必须知道当前候选范围是哪一批房源而不是重新去全量库里做一次模糊搜索。如果一定要做批量查询场景比如给用户一次推荐多个房源我更建议直接调用普通搜索接口而不是把多个房源塞进聊天上下文。聊天上下文越大模型越容易出现输出漂移。4. 怎么评测这类系统而不是只看演示效果4.1 建立五个验收指标评估一个聊天式找房系统不能只看“能不能聊”也不该只看“照片描述得像不像”。我建议重点看五个指标。测试目标测试方式判断口径自然语言转条件准确率准备 20 到 50 条用户问句人工标注期望字段硬条件字段准确率尽量达到 90% 以上多轮追问有效率记录一次会话中系统追问的次数和用户补充信息后的满意度追求一两轮内锁定候选避免连续追问图片标签准确率用 100 到 200 张房源照片与人工标注对比房间类型、阳台、厨卫设备等核心字段准确率应较高月成本估算误差抽样房源与人工计算口径对比稳定展示范围误差控制在上下 10% 到 15% 内比较理想端到端耗时模拟用户完整提问到返回列表的时间取决于网络和模型环境系统应明显小于用户等待容忍上限这些指标不一定一开始全做到但它们能帮你判断一个改动到底是在优化体验还是制造新问题。如果没有指标模型一次升级可能让回答变流畅却把硬条件解析搞坏了这种回归很难被发现。4.2 准备回归集文本、图片、费用三类样例每次改提示词、换模型、调整过滤逻辑离线跑一遍完整测试集能省去大量线上排查时间。文本回归集可以覆盖这些典型问题“预算 5500 以内精装两室最好在地铁站附近”“有没有允许养猫的一楼不要朝北”“这套房是哪一年的卖出的话税费高吗”“能月付吗押金多少”。每条都标注期望的硬条件、软偏好和是否需要追问。图片集则需要覆盖卧室、客厅、厨房、卫生间、阳台、外景和户型图。不要只挑高质量图片也要加入逆光、多角度、带人物、家具密集等复杂情况。这样才能判断图像管道的输出字段是否稳定。费用测试集建议使用同一套房分别按租赁和购买场景、一次性费用分摊和不分摊的口径来跑。重点看分项是否合理而不是只盯总数。4.3 资源占用和并发判断图像模块最容易让机器卡死因为识别一张图可能几秒识别一百张就是另一个量级。低配机器先处理 30 张以内的图片观察 GPU 或内存占用再决定是否扩容。真正要批量处理时用队列控制并发不要把一百张图片一次性塞进线程池。API 服务则要看语言模型外部调用时间。聊天接口本身不产生太多本地计算资源消耗但如果自己加载本地多模态模型显存占用会很高。一定要在批量跑之前先确认并发 5 个请求时机器剩余内存和显存是多少日志是否有超时或队列堆积。判断一套系统是不是适合批量跑我习惯用连续执行 20 套房源来验证。只看当前任务能不能跑通是不够的要看第 5 个、第 15 个任务是否仍然稳定输出文件是否一致失败任务能否自动重试或跳过。如果这些问题没解决就不要上生产。5. 实际跑起来最容易挂在哪些地方5.1 模糊需求处理错对话会变成连续逼问找房场景里用户的话术天然模糊因为大部分人并不清楚自己能把多少预算花在“舒适”上。比如“不要太贵”这个词不同收入水平的人理解完全不同。如果意图解析能把“不要太贵”理解成“预算低于周边均价优先选择性价比”问题就解决了一半。容易出现的错误是系统把“不要太贵”当成一个硬条件然后返回“预算范围缺失请重新输入”。这种交互就是在逼用户自己把需求量化。更合适的做法是先结合当前城市或小区给一个参考区间再让用户确认上限比如回答“你是希望每月租金控制在 4000 以内还是 6000 以内更合适”另一个常见问题是默认用全局搜索结果忽略会话历史。用户上一轮看中了某一套接着问“这个小区到公司通勤多久”系统不应该返回一批无关的小区而应该识别出指代对象是上一轮展示的房源。5.2 图片读错后用户会直接失去信任文本回答出错用户可能觉得表达不够清楚但图片判断错了用户会立刻怀疑整套系统。你告诉用户“阳台南向采光好”结果图片里根本没有独立阳台那前面聊得再顺畅都会前功尽弃。图片识别可能错的点很多把放在阳台上的储物柜识别成杂物间把卫生间误判成厨房把实景图误判成户型图。避免这些问题的方式不是让模型更聪明而是给输出加置信度和人工复核通道。当图片识别置信度较低时系统不应该硬答可以回复“我看出这套房有室内实拍和户型图但卫生间细节不确定建议你看一下房源描述或实地确认”。这种边界感反而能提升信任。5.3 费用口径不一致是最难解释的分歧费用估算出错很多时候不是模型不会算而是口径不统一。同一个“月成本”有人只算月租有人算包含水电物业的全部支出还有人把购房产生的契税和维修基金分摊到首年十二个月里。系统显示的口径必须能和用户解释清楚。建议把一次性和周期性支出分开成两类并给出总数时明确显示假设。不要只输出“预估月成本 7300 元”这样一句孤零零的数字。至少要把费用分解项完成否则用户很难判断这个数字是否适用于自己。如果用户问的是一套二手房“过户需要多少钱”那和月成本是不同的问题系统要能识别出这是税费咨询而不是直接调用成本估算模块。这类语义边界需要专门测试。5.4 一套可复用的排查顺序当系统出问题时请按这个顺序排查而不是先怀疑模型能力。先确认现象是报错、无输出、输出异常还是速度过慢。再检查输入内容用户说的话是否被完整传入、图片是否清晰、路径是否可访问、文件格式是否被支持。然后检查前置数据房源库中是否存在符合条件的数据图片缓存是否生成过费用配置参数是否被读取。最后检查参数和提示词过滤条件是否被正确解析、模型输出 JSON 是否合法、超时设置是否过短。很多“模型不聪明”的问题最后查出来都是上游数据没接好。比如房价字段没更新、图片标签跑了旧版本、物业费存放在另一个字段但成本模块没读。这类问题靠调提示词解决不了。6. 从 Demo 走向可用的找房助手还需要补什么6.1 先做单城市、小规模闭环如果我想在团队里复刻这个项目会先选一个城市、限定两三百套房源把闭环做完。不要一开始就追求全国房源。单城市的好处是费用政策、区域属性、物业数据都更容易校准。在这个封闭集合里把常见的找房意图、图片类型和费用口径都跑一遍。用户问“能不能步行到地铁”你要验证的是小区边界和地铁站坐标是否可靠用户问“物业费高不高”你要先有小区物业费的分级标准。这些业务知识没有整理好任何模型都无能为力。跑完一版之后再扩大到多城市。扩大时最需要改的不是模型而是城市配置和费用政策这些代码必须支持动态加载。6.2 数据更新和一致性先于模型调优找房场景对数据新鲜度非常敏感。昨天还在挂牌的房子今天可能已经被预订一周前的租金和现在可能完全不一样。如果数据源没有同步聊天助手再聪明也没用。我建议房源字段增加更新时间戳并保留数据来源快照。图片标签同样要记录生成时间。系统里应该有一张数据更新清单定期检查房源下架、价格变化和图片是否被替换。当房源描述和图片识别结果冲突时要有一个取舍规则。比如描述写“精装”但实拍图显示墙面多处污损我更建议优先相信实拍图同时提供人工纠错入口。这类一致性规则比追求模型精度更容易决定用户体验好坏。6.3 上线前检查项和可继续优化的方向最后留一份检查清单适合在项目上线前逐条过一遍。聊天接口是否具备降级方案如果大模型接口不可用后端能否退回传统结构化筛选。会话状态是否包含超时和清理机制防止长期占用资源。图片标签是否有置信度、来源、复核状态。费用估算是否展示分项和假设条件。数据是否记录了更新时间是否在页面上对用户可见。模糊需求是否被拆成硬条件和软偏好。图片离线任务是否有队列、失败重试和结果一致性校验。批量房源是否经过连续跑测而不只是演示了一条成功路径。后续可以扩展的方向包括按用户偏好订阅房源、设置移动端推送或者把会话入口接入 IM 类应用。不过这些都是在核心链路稳定后才能做的增量。如果把这个项目做成长期使用的工具最该盯住的不是功能列表而是数据准确性和成本口径。漂亮的聊天界面只能带来第一次点击真正让用户留下来的是系统提供的每一次判断都足够稳定、足够透明。