我把差旅系统想了一遍:AI代订,不是"AI帮你填表"
说实话,这个方案我想了挺久才想清楚。
起因很简单:公司30人左右,但出差流程已经很繁琐了。飞书提申请,等上级批,批完自己去分贝通App找票,订完还要回来通知行政和经理。每次出差,这套流程要折腾半小时以上——而且这半小时全是低价值的信息传递工作。
自然就想:AI能不能把这些事情全接了?
但这里有个陷阱很容易掉进去:AI代你填表,和AI代你完成事情,是两件不同的事。
大多数"AI助手"其实是"AI填表员"
我最开始设计的方案,也犯了这个错。员工用AI聊天,AI帮忙把出差申请表填好,然后员工自己去点提交、自己去App订票。
这没什么不好,但这不是AI价值密度最高的用法。
真正有价值的是:员工说一句话,AI完成整个链路。 审批、搜票、下单、日历写入、通知经理行政——全部。员工全程不打开分贝通App。
前者是"减少了一点输入",后者是"完成了一件事"。体感完全不一样。
这套方案的五步设计
整个流程从员工发消息开始,到行程落地通知结束,分五步:
Step 0(员工无感): 飞书Bot收到消息的瞬间,系统自动把飞书身份映射到分贝通的员工ID。这步员工感知不到,但是后面所有API调用的基础。
Step 1: 员工说一句话,AI解析意图,推一张确认卡片。"确认:上海→北京,周三出发,周五回,高铁往返。对吗?" 员工点确认。这里用的是Claude的自然语言理解,把一句话转成结构化字段——出发地、目的地、日期、交通方式。
Step 2: 自动走审批。金额在阈值内,飞书审批自动通过(调飞书审批API的NodeAutoApprovalList节点);超出阈值,经理收到审批卡片,一键通过或驳回。异步的——经理批完之后,系统收到事件推送,继续后续流程。
Step 3: 审批通过后,Agent立刻调用分贝通API搜索合规票,推给员工选。界面大概是这样:前三个合规选项,价格+时间+座位类型,还有一个"帮我选最优"按钮。如果员工选了"帮我选",AI按最早到达+最低价自动选定。
Step 4: 员工确认选项,Agent直接下单。订单成功后,同步触发三件事:创建飞书日历出差事件(Bot应用身份,邀请员工)、向员工+经理+行政推送行程摘要、打出差标签和成本中心。
整个过程,员工只做了两件事:说一句话,点两次确认。
技术上最难的,是"不能崩"
这是我在推敲这套方案时花时间最多的地方。一个串行的Happy Path很好设计,五步画下来,流程图也好看。
但生产系统的复杂度在于:每一步都可能失败,失败的方式各不相同,处理方式也完全不同。
我用一个最典型的例子来说明这件事:订票API超时。
你调用了分贝通的订票API,等了30秒,没有响应。这时候面临一个决策:
- 直接重试?万一第一次实际上已经成功了,重试就是重复订票,公司账户多扣一次款。
- 直接报失败?万一第一次成功了但响应没回来,报失败就是冤枉,而且订单悬在空中,员工以为没票,实际上票出了。
- 什么都不做?员工不知道发生了什么,一直等。
正确的做法是:写一个booking_unknown状态——这不是failed,是"结果未知,禁止操作"。告诉员工"正在确认中,请勿重复提交",然后后台每5分钟查一次分贝通的订单状态,直到确认成功或失败。
这是微信支付、Stripe处理支付超时的标准做法。听起来不复杂,但很多系统没有这个unknown状态——一超时就直接报failed,导致"钱扣了票没出"的事故。
踩过坑才知道这个状态有多重要。
另一个容易忽视的问题:审批事件的重复投递。
飞书的审批事件推送是at-least-once的:审批通过了,飞书推一次通知给你的服务,如果你的服务没有及时返回200,它会再推(间隔5秒、5分钟、1小时、6小时,最多4次重试)。
这意味着同一个审批通过事件,你的系统可能收到两次。如果没有做去重,就会触发两次搜票和订票。
解法是维护一个event_id去重表,每次处理审批事件前先查是否处理过。简单,但不做就是坑。
还有用户并发问题。 员工在手机和电脑同时发起了出差申请,系统会产生两个并发会话。两个会话都会尝试创建审批流程、搜索票、下单。不加保护,可能订两张票。
解法是给会话状态表加一个version整型字段——每次写状态时先读version,提交时验证version没变,变了就说明有并发写,丢弃当前操作。这是乐观锁的标准模式。
OpenClaw的定位:纯函数处理器,不是智能体
理解了这些技术细节之后,我对OpenClaw(我用的Claude Code基础设施)在这个系统里的角色有了更清晰的认识。
OpenClaw是无状态的纯函数处理器,不是有记忆的智能体。
每次调用:
- 输入:从飞书多维表格读取的session_data + 用户这条消息
- 处理:推理、决策、生成文案
- 输出:要执行的动作
状态不在OpenClaw里,订单不在OpenClaw里,所有东西都在外面。飞书多维表格管Agent数据,分贝通管严肃的订单数据。
这个定位决定了一件事:OpenClaw消费数据、产生指令,由外部系统执行并持久化。 它不拥有任何数据。一旦对这个定位有误解,就会对状态持久化产生错误的预期,然后在某次服务重启后发现数据全没了。
数据分层:Agent数据 vs 严肃数据
基于上面的认识,我把这套系统里的数据分成两类:
Agent数据(会话状态、意图解析结果、搜索结果缓存):存在飞书多维表格,允许丢失,可以重建,有TTL(48小时过期)。这里的数据错了可以重跑,Bitable就是权威来源。
严肃数据(订单号、审批记录、付款记录):分贝通和飞书审批才是权威来源,Bitable里只做append-only的审计日志——只追加,不修改。
这个区分决定了错误处理策略完全不同:Agent数据错了,重跑;严肃数据有歧义,必须查外部系统,不能相信本地缓存。
用户确认是两类数据之间的边界门——AI解析出的意图(Agent数据)在用户点确认之前,不能触发任何严肃操作。点确认之后,才算经用户认可的指令,才能调外部API。
分贝通是这套方案最大的变量
坦白说,整套方案有一个核心不确定性:分贝通的开放API能力。
搜索API有吗?订票API有吗?支持企业账户直扣吗?API支持幂等key防重试吗?这些都是待确认的。
有意思的是,分贝通本身的差标权限系统已经做了合规兜底——超标的订单在分贝通侧直接无法下单。这意味着AI层不需要重新实现一套政策引擎,直接把合规性外包给分贝通就行。这反而是一个省力的地方。
如果订票API不支持,退化方案是展示选项后推一个分贝通深链接,员工在App里完成最后一步——方案价值部分保留,但"全程不打开App"就做不到了。如果连搜索API都没有,就换携程商旅的开放API,分贝通只负责差标读取和费用归集。
我觉得这种"先把架构想清楚,再去填API能力"的方式是对的。API能力的边界决定fallback方案,不决定系统的整体设计逻辑。
这些问题不只属于差旅系统
最后说一件事。
这篇文章里的技术细节——状态机、幂等设计、Sweeper兜底机制、会话恢复、数据分层——不是差旅系统专属的。
任何把AI接入到有副作用的业务流程里的系统,都会遇到这些问题:API超时结果未知怎么处理?并发操作怎么保护?用户中断了隔天回来怎么恢复?事件重复推送怎么去重?
这些是AI落地的基础工程问题。踩过坑才知道,它们的重要程度不亚于选什么AI模型、写什么提示词。
方案目前还在推进中。如果你也在做类似的飞书AI自动化,欢迎交流。