1. 选题定调为什么偏偏是“滴滴出行供需平衡优化”每年到了毕业设计开题季计算机专业的同学基本都会经历一轮“选题焦虑”。尤其是想做应用型、偏数据分析方向的人很容易被市面上五花八门的题目晃花了眼——什么“基于XX的推荐系统”“基于XX的舆情分析”“基于XX的智能问答”听着都挺唬人但真做起来很容易陷入两个极端要么调用现成API做完一个Demo就算完事论文毫无技术含量要么数据量根本撑不起题目里的“大数据”三个字。我当时决定做这个选题核心原因有三个。第一网约车出行数据本身是“低门槛高上限”的优质数据源。订单记录、GPS轨迹、时间戳、天气信息、区域热度这些字段既不需要我去爬什么敏感数据又有足够的体量可以做趋势分析、空间聚合、供需预测。相比很多同学用爬虫硬抓电商评论、影评之类的文本数据网约车数据天然带“时间空间数值”三维属性做可视化、做建模、做业务决策分析都非常顺。第二供需平衡本身是一个“真问题”不是一个自嗨的问题。平台关心运力调度司机关心高峰期去哪接单乘客关心等多久能有车。三方的核心诉求全部聚焦在“某个时间、某个区域车多还是车少”这个判断上。所以这个题目做出来不是那种“我设计了一个系统系统有登录和CRUD”式的毕业设计而是真的能回答业务问题的。第三DjangoLLM这个技术组合在毕业设计里很讨巧。Django负责完整的Web后端、ORM、Admin管理后台这些是传统Web开发的硬功夫LLM负责数据分析结果的自然语言解读、调度建议的生成这是加分项和创新点。同时用机器学习模型做供需预测又能覆盖到“算法设计”这个论文必查的环节。一个题目同时覆盖Web开发、数据分析、算法建模、大模型应用四个维度答辩的时候每个评委问到的方向你都有东西可讲。再说句实在话这类题目在毕业设计市场里出现频率高意味着有大量的源码、课程设计、论文范文可以参照起步难度低后程又能做得深。对大多数没有真实项目经历、时间又紧张的应届生来说这是一个性价比很高的选择。2. 系统的整体架构与数据流水线先铺路再盖楼很多同学拿到这类题目直接就开始写代码先建Django工程再定义几个模型然后发现数据没有来源预测不知道用什么算法LLM不知道怎么接进去。这是我见过最多的翻车姿势。正确顺序应该是先把系统的数据从哪来、流到哪去这个问题想清楚。2.1 四层架构设计从采集到展示的分工逻辑整个系统我拆成四层数据层、算法层、服务层、展示层。数据层负责原始数据的获取和存储包括订单表、GPS轨迹表、区域网格表、天气表。算法层是核心负责供需失衡检测、供需预测、调度建议生成三块逻辑。服务层是Django的View、Serializer、Celery任务队列把算法结果封装成API。展示层是前端页面包括实时供需热力图、趋势图表、预测结果面板以及LLM生成的文字分析报告。这样分层的好处是任何一个环节出问题都能独立排查和替换。比如你觉得当前预测算法准确率不行想从XGBoost换成LSTM只需要改算法层API不动、前端不动。论文里画架构图的时候也清晰很多评委一眼就能看懂系统边界。2.2 数据从哪来公开数据集的获取与合成数据的兜底方案这个题目的关键数据来源于某出行平台的公开数据集其中包含了订单ID、乘客上车经纬度、下车经纬度、行程开始结束时间、行程距离、计费金额等核心字段。这类公开数据集的体量通常在千万级已经能撑起“大数据毕业设计”的体量要求了。但这里有一个非常现实的坑公开数据集的字段完整性往往不稳定。我拿到的数据里有相当一部分记录的OD坐标缺失部分夜间时段的订单稀疏得没法看。如果直接把脏数据丢进模型结果会非常灾难。我的处理策略是“真实数据做主骨架合成数据做补充”。先说补充逻辑对于订单量过于稀疏的时段和区域我写了一个基于泊松分布的模拟生成器以周为单位统计每个时段每个网格的平均单量作为lambda参数随机补充生成订单。这样既保证了数据量的均匀又不会凭空捏造出一个完全脱离现实的分布。论文里要明确交代哪些是真实数据、哪些是模拟数据这个诚信问题不建议隐瞒评委其实更在意你知不知道自己在做什么。2.3 数据清洗与特征工程订单数据与天气、地图数据的融合真实的数据清洗环节比我预想的要耗时。坐标字段要排除“0,0”这种脏点要剔除行程时长小于1分钟或者大于5小时的反常记录计价金额为负的异常数据也必须单独处理。我单独写了一个预处理脚本把这些清洗规则固化下来保证每次重新跑数据流程时产出一致的结果。特征工程是整篇论文里最值得浓墨重彩写的部分。我构建的特征可以分为四个维度时间特征小时、是否工作日、是否早晚高峰时段。值得注意的一点是我额外构造了“距最近地铁站步行时间”这一分钟级特征因为网约车和地铁的接驳关系非常强。空间特征订单出发地所在的网格编号、该网格周边的POI密度。POI数据我用的是公开的地图兴趣点接口拉取的然后按网格聚合。天气特征温度、降水概率、风力等级。下雨天打车难是常识但模型不会主动知道这个常识必须喂给它。历史供需特征过去一小时内该网格的订单量、活跃车辆数、供需缺口。这些特征合并后就是一个以“时间-网格”为主键的宽表。每条记录对应某个时刻某个区域的供需状态描述。整个训练集做下来大概有几十万行这个规模对于LightGBM来说非常友好。3. 供需失衡预测核心算法的选型、训练与评测这一块是整个系统的技术重心也是论文里占篇幅最多的部分。想清楚怎么定义“供需失衡”比直接找模型调参要重要得多。3.1 怎么定义“供需失衡”三个指标的计算逻辑供需平衡不能拍脑袋说“车少就是失衡”得有一套量化的指标。我设计了三个核心指标供需比Supply-Demand Ratio定义为某区域内活跃车辆数除以订单需求量。比值小于0.8视为运力不足大于1.2视为运力过剩。接驾时长定义为从用户下单到司机接驾的时间间隔。这个指标是最贴近真实体验的接驾时间超过10分钟基本就属于严重失衡。订单取消率定义为乘客取消订单数量除以总订单数。高峰期打不到车或者等太久取消都会推高这个指标。三个指标不是并列关系我做了加权融合把它变成每个网格在某个时段的“失衡指数”取值范围0到1。超过0.7就触发调度干预。这部分的实现逻辑不复杂但有一个潜在坑是网格的粒度选择。网格太大会把失衡区域稀释掉网格太小又会导致很多网格没有数据矩阵非常稀疏。我反复试了500米、800米、1000米三种网格边长最后折中选了800米。在论文里可以用一个对比表格展示不同网格粒度下指标的有效覆盖比例。3.2 预测模型的选型与训练从统计基线到LightGBM预测模型的选型一开始我走了弯路。第一版直接用LSTM做时序预测训练慢、调参难、效果还不稳定尤其是预测未来两小时这种中长时段时误差会指数级放大。后来冷静下来分析问题本质——这是一个典型的“表格型回归问题”特征以类别和数值混合为主数据规模是万级到十万级这类问题的最佳实践是梯度提升树模型没有必要硬上深度学习。最终我用了LightGBM。输入特征就是前面构造的四维特征预测目标有两个未来30分钟的订单需求量未来30分钟的活跃车辆数。把两个预测值代入供需比公式就能得到预测的供需缺口。训练细节上面有个值得记录的点时间序列数据不能随便乱切训练集和测试集否则会造成数据泄露。我用的是按时间切分的方式前80%的时间段做训练最后20%的时间段做验证保证模型没有“偷看未来”。最终模型表现订单需求量预测的MAPE在11%左右在夜间和凌晨时段会上升到约18%。活跃车辆数预测的MAPE在13%左右。供需失衡分类的F1分数在0.82左右召回率比精确率稍低错判的主要原因是突发性事件比如演唱会散场、临时交通管制这类极端情况历史数据里没有类似样本模型自然学不到。3.3 效果评测与实际踩到的坑评测环节不要只看整体指标要按时段和区域拆开看。不同时段模型表现差异很大把整体MAPE拉低的主要是平峰期的大样本。夜间虽然误差高但夜间订单基数本身小误差的绝对量并没有那么夸张。实际操作中还有一个容易被忽视的坑预测模型在网格维度上的效果差异明显。商业区、火车站周边的预测误差小而郊区、新建城区的预测误差大因为供需波动更随机。这说明什么问题说明基于历史统计的机器学习模型在“长尾区域”的预测能力天然有上限。这也正是LLM派上用场的切入点——后续大模型生成的调度建议会重点参考模型在长尾区域的置信度低置信度区域直接给出偏保守的运力投放策略。4. LLM大模型在系统里的角色不是接个API聊天那么简单“LLM行业系统”是现在很多毕业设计都在蹭的热点。但如果只是做个聊天机器人放在页面右下角让用户问“今天天气怎么样”那就纯粹是挂羊头卖狗肉答辩的时候一定会被追问“你的大模型和系统核心逻辑有什么关联”。我在设计LLM模块的时候给自己定了一个原则大模型必须服务于供需平衡这个核心目标不能脱离业务瞎聊。4.1 三个实际落点调度建议生成、异常时段归因分析、可视化报告解读第一个落点是调度建议生成。预测模型输出的是冷冰冰的数值——某个区域未来30分钟供需比0.65失衡指数0.82。系统需要把这些数字翻译成可执行的建议比如“建议在朝阳区望京区域增加25辆运力优先覆盖下午6点到8点时段”。这个生成过程我先把结构化数据拼装成JSON然后通过预设的Prompt模板让LLM输出自然语言建议。第二个落点是异常时段归因分析。当某个网格的失衡指数突然从0.3跳到0.8时系统会自动把该时段前后的天气数据、周边POI事件数据、历史同期数据打包给LLM让它帮助分析可能的原因。比如“该区域附近有大型体育场馆今晚有赛事活动散场时段产生瞬时大客流”“该网格未来两小时降水概率超70%叠加晚高峰供需缺口明显加剧”。这些输出虽然不能做到绝对精确但能给运营人员提供有价值的排查方向。第三个落点是可视化报告解读。系统首页原本只是几张图表我让LLM基于图表背后的数据自动生成一段几百字的分析摘要叙述供需趋势、异常点、预测结论。评委打开系统时看到的不再是冷冰冰的图表而是一段条理清晰的文字总结这一点在答辩演示时观感提升非常明显。4.2 提示词设计与结构化输出约束LLM模块能不能稳定工作提示词设计是关键。我的做法是模板化加JSON约束。调度建议的Prompt结构大致是你是一名城市交通运营调度专家。请根据以下供需数据生成调度建议。 数据格式为JSON包含区域编号、区域名称、预测供需比、失衡指数、时段、置信度。 要求 1. 用简洁的自然语言给出3条以内建议 2. 每条建议必须包含具体区域、调节方向和大致运力数量 3. 若置信度低于0.6请标注“建议仅供参考” 4. 输出格式为JSON数组这里有一个很值得注意的细节LLM的输出必须做结构化约束不能让它自由发挥否则前端解析逻辑会变得很难维护。我在提示词里要求输出JSON同时在解析层做了兜底——解析失败就退回固定模板拼接的文本。生产环境里任何外部模型接口都有失效的可能兜底逻辑必须有。4.3 模型选型与部署概况LLM的选型我经历了几个阶段。一开始想用本地部署开源模型起了个Llama系列的小参数版本但硬件条件有限推理速度太慢响应时间动辄十几秒体验很差。后来改走API调用路线效果稳定很多就是需要考虑请求费用和网络延迟的问题。实际落地的时候我加了一层缓存。同一网格同一时段的调度建议20分钟内不重复请求LLM直接复用缓存结果。这样一来页面刷新时的响应速度能控制在两秒以内核心体验问题就解决了。5. Django落地实现的几个关键技术细节骨架搭好了算法也跑通了接下来最耗时的是把这一切都塞进Django这个Web框架里。下面几个点是我实际开发中感觉最值得写下来的经验。5.1 实时供需热力图的WebSocket推送方案供需热力图是系统首页的C位功能地图上的区块颜色实时反映供需状态。传统做法是前端定时轮询后端接口简单是简单但刷新频率不好平衡刷新快了接口压力大刷新慢了实时性差。我最后用的是Django Channels加WebSocket的方案。后端在Celery定时任务里每两分钟跑一次供需计算结果推送到Redis频道Django Channels的Consumer再从Redis订阅消息实时推给前端。前端地图收到数据后用ECharts的map系列重新渲染热力图。整个链路跑下来首屏加载走HTTP实时更新走WebSocket各司其职。有一点要提醒Django Channels的部署比普通Django麻烦不能用uwsgi要切成Daphne。如果你只需要在本地跑给老师看其实轮询方案也说得过去但你要是在论文里写“实时推送”这个功能点建议还是把WebSocket方案做出来这是实打实的技术亮点。5.2 大数据量查询的数据库方案与异步任务数据体量到了千万级订单规模单表查询已经扛不住了。我的方案是MySQL加按月分表订单表按月份拆成多张物理表。Django的ORM对分表不太友好所以我底层用原生SQL做查询聚合再手工映射成模型对象。论文答辩的时候你完全可以大大方方说“因为数据量大查询逻辑没有用ORM而是手写SQL加索引优化”这反而是一个加分项说明你真的处理过大规模数据。另外供需计算和预测这两个重活绝对不能放在请求线程里跑否则前端会长时间无响应。我把它们放进了Celery异步任务队列定时执行结果写回Redis和MySQL。前端只需要通过WebSocket接收结果就行。# Celery任务示例 shared_task def calculate_supply_demand(): 定时计算全网各网格的供需指标 df query_recent_orders() # 查询最近30分钟的订单数据 gdf aggregate_by_grid(df) # 按网格聚合 metrics compute_metrics(gdf) cache.set(supply_demand_metrics, metrics, timeout300) # 通过Redis频道通知WebSocket推送 redis_client.publish(metrics_update, json.dumps(metrics, ensure_asciiFalse))5.3 Django REST Framework接口设计与前端解耦后端API我用的是Django REST Framework全部采用前后端分离的结构。前端写了一个专门的驾驶舱页面用Vue3加ECharts通过Axios调后端API地图用Leaflet渲染。接口设计方面有一个体会很深的点不要把前端想要的字段直接透传成数据库字段一定要在后端做一次DTO转换。比如前端热力图需要的是“网格中心点经纬度失衡指数供需比”但数据库表里存的是网格编号、经纬度范围、订单量、车辆数。如果直接返回数据库原始数据前端就要自己去计算网格中心和指数这个逻辑放在前端很麻烦也容易出错。在后端View里把数据转成前端友好的结构前端只用做渲染这个分工是Web开发的基操。系统的权限设计也不复杂分了管理员和普通用户两种角色。管理员可以查看全部区域的详细分析和调度建议普通用户只能看汇总数据。用Django自带的User模型扩展一个Profile表就够了比单独搞一套用户系统省太多事。6. 性能优化与部署上线真实场景里的速度问题本地开发跑得飞快不代表部署到服务器上也流畅。这个项目因为涉及地图渲染、轮询、定时任务性能问题特别明显。6.1 数据库索引与慢查询优化订单表、GPS表这种千万级行数的表不加索引的查询会直接把数据库拖垮。我的索引方案是组合索引按业务查询习惯设计(订单创建时间, 网格编号)(上车经度, 上车纬度)(预约用车时间)用Django的ORM可以这样定义class Order(models.Model): order_id models.CharField(max_length64, uniqueTrue) pickup_time models.DateTimeField(db_indexTrue) pickup_grid models.CharField(max_length16, db_indexTrue) pickup_lat models.FloatField() pickup_lng models.FloatField() class Meta: indexes [ models.Index(fields[pickup_time, pickup_grid]), models.Index(fields[pickup_lat, pickup_lng]), ]加了索引之后某些高频聚合查询的时间能从2秒降到200毫秒左右体感差别非常明显。这还没算上SQL层面用EXPLAIN分析慢查询的进一步优化。在论文的测试章节里我专门用了一小节写索引优化前后的对比评委觉得很实在。6.2 缓存策略Redis在系统里的三个用法Redis在这个项目里承担了三份工作缓存供需指标计算结果5分钟有效避免前端频繁请求时重复计算。缓存LLM生成的调度建议20分钟有效控制成本和响应时间。作为WebSocket消息的Redis Pub/Sub通道在Celery和Channels之间传数据。说个具体的坑之前用缓存时没设置过期时间内存越吃越多服务器很快就报警了。排查后发现是一些历史查询结果永久留存在缓存里。后来统一加了TTL并且主动清理空key内存占用降了60%。6.3 部署方案与配置文件里的防坑清单部署我用的是Gunicorn加Nginx的组合Celery用Supervisor守护Redis和MySQL各自独立进程。部署阶段最容易出的问题有三个。一是Django的SECRET_KEY和数据库密码必须用环境变量管理不能硬编码在settings.py里二是STATIC_ROOT和MEDIA_ROOT的路径要单独配置否则静态文件会404三是Daphne和Gunicorn监听的是不同端口Nginx需要区分WebSocket流量和普通HTTP流量。# Nginx配置要点 location /ws/ { proxy_pass http://127.0.0.1:8001; # Daphne proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } location / { proxy_pass http://127.0.0.1:8000; # Gunicorn proxy_set_header Host $host; }把这个配置写对前后端分离部署基本就稳了。服务器我用的是一台2核4G的云主机跑整个系统压力不大Celery任务队列稍微吃一点内存也是在可控范围内。7. 论文与答辩准备容易被低估的临门一脚系统做出来了代码能跑了不代表项目就结束了。毕业设计的最后一道坎是论文和答辩这一部分我踩过不少坑值得单独说一下。7.1 论文结构安排与核心章节写作经验论文的结构我最终定下来是第一章绪论背景、意义、国内外研究现状。第二章相关技术Django、机器学习、LLM、WebSocket。第三章系统需求分析与总体设计包含用例图、架构图、功能模块划分。第四章核心算法设计供需指标定义、预测模型、LLM应用逻辑。第五章系统实现分模块讲关键代码和实现界面。第六章系统测试功能测试、性能测试、预测效果评估。第七章总结与展望。第四章是论文的灵魂所在供需指标的推导过程、预测模型的特征工程、LLM提示词设计的演进过程都要在这一章写透。导师给的反馈是“算法章节写得像一篇小论文逻辑完整”。还有一个要提醒的是论文里所有截图必须保证是系统真实运行的界面不要用临时样式的假图。评委里有人会现场打开系统对照论文截图看如果明显不一致会很尴尬。7.2 答辩现场常见问题与应对思路答辩时评委最喜欢问三类问题第一类是“你怎么保证预测结果是可信的”。这个问题要回答两点一是数据来源和处理过程的真实性二是评测指标的计算方法。把MAPE、F1这些指标的定义和数据切分方式讲清楚评委基本就满意了。第二类是“LLM在你的系统里到底起了什么作用不用行不行”。这个问题很尖锐也是区分“真创新”和“蹭热点”的分水岭。说实话预测模型本身确实不依赖LLM但LLM解决了“从数据到决策”的最后一公里。数据结果只有变成人话才能指导调度。我的回答是没有LLM系统只能展示图表有了LLM系统能直接输出可执行的调度建议和分析报告这是用户价值层面的提升。第三类是“你这个系统如果真的要部署到生产环境还有什么不足”。诚实回答就好。比如长尾区域的预测误差还比较大LLM偶尔会产生不准确的归因分析极端天气数据缺失导致模型泛化能力有限这些既是不足也是未来工作里顺理成章的改进方向。7.3 源码、LW与PPT的整理要点最后说交付物。源码仓库建议用Git管理每个功能模块按Django App的规范拆分每个App给一个简短的README说明。LW文档里除了论文正文建议把需求分析说明书、数据库设计说明书、测试报告、答辩PPT这四份材料都放进去。PPT控制在15到20页页面结构按“选题背景→系统架构→核心算法→效果展示→总结展望”来排逻辑非常清楚能帮你在答辩时把节奏带起来。有不少同学问我要源码我的回复是源码可以给但你必须先弄清每个模块为什么这么设计。毕业设计的价值不是拿到一个能跑的项目而是你能解释清里面的每个决策。把Django的ORM、Channels的异步机制、LightGBM的特征重要性、LLM的提示词约束都吃透了这个题目才算真正完成。进系统跑一遍看到地图上热力图随着时间流动而变化再看一眼LLM输出的调度建议那一刻你会觉得之前熬过的夜都值了。