一步一步扒开问题,慢慢改进架构

1. 初步分析

这个项目第一眼看上去其实感觉很简单,就是一个动态规划问题,司机要在很多的限制下寻找最优解,尽可能赚更多的钱。

限制初步分析如下:

  • 司机偏好限制,即罚款(最大的限制)
  • 货源只有被搜索了才可见,并且有上架窗口和装货窗口,收益不同
  • 当前时间、位置。车辆状态、路线规划

但是往细了分析发现,还是有很大的挑战性的。

首先,司机的偏好是用自然语言给出的,具有很大的随机性,如果解析不对自然语言背后的偏好,很容易会出现罚款从而导致入不敷出;

其次货源的分布也具有很大的集中性,很多的货源都聚集在其中的某几个城市,而我们一开始是不知道会集中在哪几个城市,这就要求搜货也要有一定的策略,是否要搜?搜多少?

第三,根据司机的地理位置、时间来判断是否要接单,要接什么单,长单?短单?还是直接满足偏好去休息,这些都是需要去考虑的问题,虽然说我们能一股脑给大模型去决策,但是这效果并不好,对于小模型来说,我们还是需要一些能真实提升决策能力的小skill/lesson。

货源原始数据示例

{
"cargo_id": "520", 
"create_time": "2026-03-01 11:21:18", 
"remove_time": "2026-03-01 11:23:29", "cargo_name": "建材", 
"start": 
	{
	"city": "广东省惠州市龙门县", 
	"lat": 23.66, 
	"lng": 114.22
	},
"end": 
	{
	"city": "广东省广州市南沙区", 
	"lat": 22.92, 
	"lng": 113.41
	}, 
"load_time": ["2026-03-01 12:00:00", "2026-03-01 14:00:00"], 
"cost_time_minutes": 388, 
"price": 73908.06, 
"truck_length": ["4.2米", "5米"]
}

司机偏好示例

  {
    "driver_id": "D001",
    "name": "张三",
    "vehicle_no": "粤A12345",
    "truck_length": "4.2米",
    "cost_per_km": 1.5,
    "current_lat": 22.54,
    "current_lng": 114.06,
    "preferences": [
      {
        "content": "我这人熬不住连轴转,每天至少连续停车熄火休息满8小时。",
        "start_time": "2026-03-01 00:00:00",
        "end_time": "2026-03-31 23:59:59",
        "penalty_amount": 300,
        "penalty_cap": 3000
      },
      {
        "content": "不接货源品类为「化工塑料」或「煤炭矿产」的订单。",
        "start_time": "2026-03-01 00:00:00",
        "end_time": "2026-03-31 23:59:59",
        "penalty_amount": 500,
        "penalty_cap": 5000
      },
      {
        "content": "我就在深圳干活,不出市。从 22.54,114.06 这一带出车;跑车或停车时,车辆位置须始终在深圳市范围内(北纬22.42至22.89,东经113.74至114.66)。",
        "start_time": "2026-03-01 00:00:00",
        "end_time": "2026-03-31 23:59:59",
        "penalty_amount": 2000,
        "penalty_cap": 2000
      }
    ]
  },

司机每一步大概需要分析决策这些问题:

  • 根据偏好目前是否要接单,如果不能接单是否休息/转移地点(基本是为了满足偏好或者市场机会不好)
  • 如果要接单,根据当前可见货源是否满足接单条件(分析货源净收益、送到哪里)
  • 若不满足接单条件,那么需要搜货,搜哪里?搜几次?到什么条件停止。
项目难点分析草图
项目难点分析草图

2. 实验尝试记录

我们对这个项目的总体大框架发生过四次较为重大的改变。

  • 首先尝试最朴素的 Single Agent 框架,发现完全跑不了,需要将功能模块解耦。
  • 然后我们尝试规则模块 + Single Agent,发现能跑起来了,但是模型只会硬遵守规则,不会自己分析,更别说自己学会如何搜货、如何遵守偏好、如何决策了。
  • 之后试了 Agentic Workflow 框架,效果有了明显的改进。模型开始能搜索市场热点,显示遵守偏好做出取舍。虽然流程变得很agentic,但是依旧不能很好的管理偏好。这一框架中依旧有很多的规则执行,我们想的是,最终能不能尽量不要规则硬约束,最大限度发挥模型的能力?
  • 最后演进到了 Multi-Agent 框架,MemoryAgent 负责上下文压缩,Preference Agent 负责偏好约束解析与执行,SearchAgent 负责搜货策略,CargoAnalystAgent 负责货源分析,MainDecisionAgent 负责最终动作选择,SafetyValidator 负责合法性兜底。同时引入 DriverMemory、CargoMemory、MarketMemory 和 agent_io trace,让系统具备长期记忆、任务级上下文视图和逐节点复盘能力。

2.1 Single Agent

Single Agent 初版实验截图
Single Agent 初版实验截图

首先我们做了一个尝试,就是不额外处理信息,所有可以观测到的信息都原模原样给我们的Agent,直接让他做出决策。

LLM +司机信息 + 原始偏好限制 + 程序触发以自身为中心搜货源 + 搜到的货源的详细信息 = 决策

这很快暴露出了一堆问题,最轻的是这几个:

  1. 完全不理解偏好,或者说知道了偏好的存在但是不遵守
  2. 完全没办法对比各个货源之间的优劣
  3. 一直接到过期的货源

较为重的是这几个问题:

  1. 直接报错,几步之后,由于搜到的货物累积,input的token太多爆了
  2. 无法输出决策的正确格式,完全lost in middle,输出无限循环重复

这很正常,我早就预料到会这样。从这些错误中,我总结了一下一些模块必须要有:

  • 偏好解析模块:对自然语言偏好进行结构化处理。
  • 货源管理模块:发现了货源之后能够根据货源的在线时间自动更新
  • 货源收益计算模块:根据在线货源,初步对这些货源的收益做分析,并推荐给LLM决策大脑。

2.2 规则 + Single Agent

直接选择净收益最高的单

在这一个阶段,我们首先试了如果直接忽略司机的偏好需求,让他在以自身为中心搜索100件货源,并且选择计算收益最高的那一个接单。

\text{MonthlyNetIncome} = \text{GrossIncome} - \text{DistanceCost}

(其中DistanceCost是指卡车每开 1km 需要的成本,为1.5元/km)

在这个策略下,及时不用LLM,我们可以做到接近 8 万的收益

直接选择净收益最高单的 baseline
直接选择净收益最高单的 baseline

这给我们提供了一个 baseline,之后我们就先加入偏好的规则去优化模型。

加入偏好解析

由于不考虑偏好解析的情况下,我们的净收益非常差,甚至还出现了负数,因此必须要加入偏好解析,用偏好规则去约束司机的行动

这第一版的偏好解析非常的简单,用规则去提取司机的偏好,然后制定 hard block 规则,如果司机触犯了 hard block 规则会直接 fallback,去强制满足一些偏好。

偏好解析与 hard block 规则
偏好解析与 hard block 规则

这样改进之后跑下来的效果如下

加入偏好规则后的实验结果
加入偏好规则后的实验结果

偏好惩罚明显下降(14.7w→10.3w),且总净收益明显上升(8w→17w)。但是为什么偏好惩罚还是降不下去呢,明明已经安排了硬门禁去尽量避免惩罚。

分析了接货时间以及司机的动作后,我们发现门禁确实发挥了一定的作用,但是远远还没有达到它该有的作用,原因如下:

  • 偏好规则解析不能覆盖所有的偏好,由于偏好以自然语言的方式存在,例如“这周末要去xx一趟,接个啥”“这几天别给我安排接单”,这些偏好很难用规则完全覆盖到,因此还是会存在违反的现象
  • 司机在接上一单时,没有考虑到结束时间是否和要求的偏好窗口时间冲突,example:有个司机偏好要求 0-6 点休息,但是在前天22点时,司机接了一单,由于未在偏好窗口内,没有被硬规则拦下,而结束时间却在2点,这样的话,及时接完后强制休息,也算违反了偏好
  • 有些偏好是按月累积进度的,比如“每月休息5天”“每月空驶距离不能超过100km”,这类偏好如果没有一个专门的记忆管理模块,是很难履行正确的。

下一步计划

解耦几个模块,比如Search Cargo、记忆模块。 逐步引入 llm 当决策者,规则决策只能作为fallback时的选项。 现在还是规则固定搜索货源,要转变成 Agent 自己决定是否搜货源、搜哪里。 完善偏好解析模块,完善对货源打分模块。

2.3 Agentic Workflow

这一个架构的改变就是真正的引入了 LLM 当做决策者,完善了一些模块,增加了一些模块,有了Multi-Agent 的雏形。

Agentic Workflow 架构草图
Agentic Workflow 架构草图

主要是一个架构设计,经过前两个阶段的试错,我们初步想了一下需要哪些环节来保证 Agent 能在动态的环境中持续决策,并且达到最优收益,主要有以下环节

  • 偏好解析部分:这是大头,要求偏好解析尽可能没有错,解析出来的具体内容放到后面可执行
  • 搜货部分:需要了解市场热点,结合司机自身位置、时间动态做出是否搜货、搜哪里的决定。
  • 货源部分:需要精确计算货源是否值得接,接了会不会影响偏好履约
  • 决策部分:在接收了以上信息之后做出可能有最大收益的决策,包括空驶到市场热点、等待后续机会、接收益虽低但是风险小的单子等等,并且能给出理由
  • 记忆部分:记录偏好以及履约情况、市场热点、最近司机的动作
  • 校验部分:校验模型的输出是否合法,包括格式合法,动作是否合理,不合理返回对应原因retry
  • 自进化部分:记录每一个阶段的io trace,用模型去总结为什么做的好/为什么做的差,并且整理成相应的短 skill/lesson 给到各个 Agent ,实现持续的自进化学习。

在这个框架下我们测试了一个初版分数

Agentic Workflow 初版跑分
Agentic Workflow 初版跑分

2.4 Multi-Agent 架构

在 Agentic Workflow 的铺垫下,我们最终将系统拆分成多个专职模块 Agent。每个 Agent 只解决一个相对清晰的问题:

Multi-Agent 总体架构图
Multi-Agent 总体架构图
模块职责
HistoryFeedbackAgent读取近期历史,压缩近期行为反馈
MemoryAgent生成不同任务需要的 memory view
PreferenceAgent将自然语言偏好转为结构化表示
PreferenceTaskExecutor执行偏好任务,生成 hard block、bias、cargo_risk
SearchAgent判断是否搜索、在哪里搜索
SearchToolExecutor执行 search_cargo 并写入 CargoMemory
CargoAnalystAgent计算候选货源可达性、收益效率和偏好风险
MainDecisionAgent在压缩后的货盘和上下文中选择最终动作
SafetyValidator校验最终动作是否合法,并进行 rewrite / fallback
MemoryConsolidatorAgent定期压缩长期轨迹,沉淀经验和 skill candidate

最终的收益来到了

Multi-Agent 架构最终收益
Multi-Agent 架构最终收益

3 实验数据总览

这两张图展示了我们在做这个项目的跑分迭代过程,第一张图是净收益每次突破时的曲线,第二张图是每一次全量实验的完整跑分。

净收益突破曲线
净收益突破曲线
全量实验跑分总览
全量实验跑分总览