news 2026/8/23 7:54:05

AI 软件开发实战教程(十一):让系统找到可能同路的人

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI 软件开发实战教程(十一):让系统找到可能同路的人

“AI 软件开发实战教程”系列第 11 篇:不用模糊推荐分数,先把同路候选写成可以解释、可以反证、不会重复的业务规则,再用两个浏览器用户验证异步匹配。

上一篇把微信群中的“车找人”和“人找车”变成了结构化信息。但两条信息即使已经同时存在,也不会自动认识彼此。

例如,车主早上发布:

明早 8:05,万科悦城到软件新城,2 个座位

乘客可能隔几个小时才发布:

明早 8 点左右,万科悦城到软件新城

群聊里,较早的消息早已被刷走。邻行 K3 要做的是在第二条信息出现时,重新检查已经存在的另一类信息,为双方形成一个“可能同路”的候选。

这里最容易犯的错误,是一上来就设计一个看似聪明的匹配分数。首版数据少、地点粗、真实反馈也不足,一个 87 分的结果既难解释,也不能证明比明确规则更有用。

先写“不匹配”的条件

与其问“怎样算很像”,不如先问“什么情况下绝对不能形成候选”。

邻行把必要条件写成一组全部都要满足的判断:

同一个社区 一条车找人,一条人找车 不是同一个发布者 同一个出行日期 两条信息都仍然有效 双方匹配截止时间都还没到 车主仍至少有一个座位 可出发时间窗口存在交集 起点和终点相同,或命中管理员配置的路线兼容规则

其中任何一项失败,结果就是“不形成候选”,而不是降低几分后仍勉强推荐。

这样的规则对早期产品有两个好处:用户能理解为什么看到这条信息;开发者也能为每个反例写出确定测试。

用纯规则把反例固定下来

K3 仍从红灯开始。第一批测试导入尚不存在的apps.matching,测试收集阶段就失败,证明代码库确实没有这项能力。

随后建立evaluate_pair。它接收车主信息、乘客信息和明确的当前时刻,返回是否兼容、规则版本和结构化解释,不负责发送提醒。

参数化测试逐个破坏必要条件:

  • 把乘客改成同一个发布者;
  • 把日期推迟一天;
  • 把时间窗口错开三小时;
  • 把信息状态改为关闭;
  • 把匹配截止移到过去;
  • 使用没有兼容关系的地点。

每个变化都必须得到空结果。正例则检查解释中保存了日期相同、时间重合和路线依据。

纯规则的意义不只是代码好测。它迫使产品语言也保持克制:系统知道“大范围路线和时间可能合适”,不知道双方具体在哪个门上车,更不知道最后是否真的约定成功。

路线兼容为什么必须有版本

起点和终点完全相同时,邻行使用内置规则版本 1。社区管理员还可以维护显式兼容关系,例如:

车主:万科悦城 → 软件新城 乘客:悦城北门 → 中软 解释:大范围路线兼容 规则版本:3

候选会保存当时使用的版本和解释,而不是每次打开页面重新计算最新说法。

如果管理员以后发现这条关系不合适并发布版本 4,旧候选仍能说明自己为什么在版本 3 下产生,新计算则使用新规则。否则一次规则修改可能让历史页面突然换理由,排查投诉时也找不到当时事实。

兼容关系是有方向的。司机路线和乘客路线分别存储,不能默认反过来也成立,更不能把“附近”扩张成不受控的自由文本。

候选唯一不能只靠代码先查一次

发布服务在新信息保存后触发候选重算。它会扫描同社区、相反类型的有效信息,再交给纯规则判断。

但“先查询,没有再创建”挡不住两个请求同时发生。数据库因此对下面的组合建立唯一约束:

车主信息 + 乘客信息 + 规则版本

重算服务仍使用幂等的get_or_create,数据库约束负责最后防线。测试连续重算两次,最终只能得到:

1 个候选 1 个业务事件 双方各 1 条站内提醒

这比要求消息队列“保证只执行一次”更现实。任务可以重试,业务结果仍然稳定。

一件事,不等于一条通知记录

一个新候选对双方来说是同一件业务事实,但两个人的提醒结果可能不同。

因此数据分为三层:

Candidate └── BusinessEvent:candidate.created ├── 车主的站内提醒 + 渠道投递记录 └── 乘客的站内提醒 + 渠道投递记录

业务事件用稳定键保证同一候选只创建一次。每个接收者都有自己的站内提醒和渠道状态:待发送、成功、失败、结果未知或未启用。

K3 只创建这些持久化事实,不在发布请求里直接访问喵提醒。这样第三方变慢不会拖住发布事务,也不会因为其中一个人的喵码无效而抹掉另一个人的站内提醒。

没有启用外部渠道时,投递记录明确标为“未启用”,站内提醒仍然存在。自动测试专门断言了这个降级路径。

需要诚实说明的是:本节点还没有证明喵提醒真正发送成功。实际 Worker、错误分类、每小时上限和摘要属于 K7。现在通过的是事件与独立投递事实,不是外部送达。

候选页面为什么不能写“匹配成功”

用户在页面上看到的是:

可能同路,不是已确认同行 日期相同 时间窗口有交集 起终点相同 / 命中某条兼容规则 具体上下车位置仍需双方通过微信确认

页面没有匹配百分比,也不说系统已经替双方达成约定。

候选列表和详情只对两个参与者开放。其他登录成员即使猜到链接,也得到 404。页面此时不加载任何微信号或喵码,因为“可能同路”还不构成披露联系方式的授权。

这条边界也为下一节点留下清晰起点:只有参与者主动确认交换后,系统才同时向双方披露微信号。

用两个浏览器验证异步出现

单个浏览器无法证明双方看到的是同一个结果。K3 的 Playwright 测试创建两个完全隔离的浏览器上下文,分别保存自己的登录会话,移动视口都是 375×812。

测试流程是:

车主登录并发布 → 乘客登录并发布 → 第二次发布触发候选重算 → 车主进入候选列表和详情 → 乘客进入候选列表和详情 → 双方都看到“可能同路”和相同的微信确认提示

它验证了用户不必同时在线,也不必重新发送群消息。较早发布的人在后来者出现后仍能获得站内结果。

浏览器测试没有伪造复制微信或真实外部提醒;那些能力尚未实现。它只证明当前页面、会话隔离、发布触发和双方授权组成的纵向流程。

本节点怎样验收

K3 收口时得到:

  • 76 个非浏览器测试通过;
  • 分支覆盖率 90.74%;
  • Ruff、格式、mypy strict、迁移和 Django 检查通过;
  • V0 到 K3 共 4 条 Chromium 用户旅程通过;
  • 精确路线和版本化配置路线均有可解释正例;
  • 日期、时间、状态、截止和同用户等反例不会形成候选;
  • 重复重算不增加候选、事件或站内提醒;
  • 无外部渠道时双方站内提醒仍存在;
  • WebKit、PostgreSQL、微信真机和外部实际发送仍未被宣称通过;
  • 结果只形成本地提交,不推送。

验收矩阵中,AC-14 至 AC-17 可以自动通过。AC-18 和 AC-54 只能标为部分通过,因为本节点证明了事件和双方独立记录,却还没有执行 K7 的真实发送。AC-55 也只能部分通过:无渠道降级已经证明,一方失败不影响另一方仍待故障测试。

写在最后

匹配系统的第一版不需要显得聪明,需要显得可信。

明确必要条件、保存当时解释、用数据库保证唯一、把一个业务事实拆成双方独立通知结果,这些基础会让后续功能更容易演进。等真实试用产生足够反馈,再讨论扩大路线兼容、排序或推荐,才有数据可以判断改动是否真的更好。

下一篇进入 K4:当一方决定联系候选时,怎样再次检查权限和时效,在一个事务中同时向双方披露微信号,保存不会随资料修改而变化的加密快照,并让复制失败时仍可手动选择。

关键代码与操作

下面的简化测试把“形成一个候选”继续展开为解释、事件和双方提醒数量:

deftest_matching_pair_creates_explainable_candidate(driver_trip,passenger_trip):candidates=recompute_candidates_for_trip(trip=passenger_trip,now=timezone.now(),)assertlen(candidates)==1assertcandidates[0].explanation=={"date":"same","time":"overlap","route":"exact",}assertBusinessEvent.objects.count()==1assertInAppNotification.objects.count()==2

验证命令:make bugfix TEST=tests/matching/test_candidate_matching.py::test_matching_pair_creates_one_explainable_candidate_and_two_notifications

候选、解释和通知必须在同一条测试里对齐,否则页面可能显示一个无法追溯来源的结果。

本篇验证摘要

  • 候选只在同社区、角色互补、时间重叠且路线兼容时形成;
  • 路线规则带版本,历史候选保留当时使用的解释,不被后续配置改写;
  • 数据库唯一约束和稳定事件键避免重复候选与重复提醒;
  • 双方分别得到站内提醒和独立投递记录,一方失败不会回滚另一方;
  • 候选页面只展示形成原因和随机短编号,不提前披露联系方式。

附录:相关工具与仓库

gstack

仓库:garrytan/gstack
地址:https://github.com/garrytan/gstack

dev-harness

仓库:Dev-Wiki/dev-harness
地址:https://github.com/Dev-Wiki/dev-harness

UI UX Pro Max Skill

仓库:nextlevelbuilder/ui-ux-pro-max-skill
地址:https://github.com/nextlevelbuilder/ui-ux-pro-max-skill

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 7:47:58

TMAS:多智能体协同推理如何重构大模型计算成本与效率

1. 项目概述:当模型学会“开会”,推理成本如何被重构?最近在模型推理优化的圈子里,一个概念被反复提及:Test-Time Compute,也就是测试时计算。简单来说,这指的是模型在部署后,面对每…

作者头像 李华
网站建设 2026/8/23 7:44:03

高校实习管理平台开发实践与技术选型

1. 项目背景与需求分析高校实习管理一直是教育信息化中的痛点领域。我在参与多所高校信息化建设过程中,发现传统实习管理模式存在三个典型问题:首先是信息孤岛现象严重,企业发布的实习信息分散在各个院系微信群和辅导员邮箱;其次是…

作者头像 李华
网站建设 2026/8/23 7:42:00

Kubernetes部署

第一部分:理解 K8s 原理1.1 应用部署发展过程传统物理机部署:软件直接装在服务器。缺点:资源没法限制,一个程序吃满 CPU 内存,会把别的程序搞崩。虚拟机部署:一台物理机跑多台虚拟机,每台虚拟机…

作者头像 李华
网站建设 2026/8/23 7:40:44

基于 LangChain 的多 Agent 测试对话机器人:从测试领域知识到完整实现

摘要:如何让 AI 不只是"生成测试用例",而是像一个资深测试工程师一样思考——理解需求的业务闭环、枚举权限/组合/跨模块等复杂场景、在关键节点向用户确认疑问?本文构建了一个 8 Agent 对话式测试机器人,深度融合测试领域知识(需求理解六维度、测试点提炼十维度…

作者头像 李华
网站建设 2026/8/23 7:39:09

Java面试中HashMap与多线程编程的核心要点解析

1. 面试场景还原与技术能力评估那天下午三点半,阳光透过落地窗照进会议室,我作为技术面试官正准备开始一场Java后端开发岗位的面试。推门进来的候选人谢飞机,简历上写着"5年分布式系统开发经验",但接下来的90分钟却成了…

作者头像 李华