跳转至

围餐智能体:把零散经验变成可追溯、可执行的围餐方案

答辩人:杨佳宇
岗位:AI 应用工程师
项目周期:3 周

开场:我做的不是一个只会聊天的机器人

大家好,我叫杨佳宇,是一名 AI 应用工程师。[这个部分后面会改的]

我想先请大家想象一位新来的餐厅经理。上班第一天,他拿到的可能不是一张统一的业务表,而是餐厅经理、厨师长、服务和食安人员分别维护的多个 Excel:每一份格式都不一样,标题、备注和小表东一块西一块;有些信息没有写进表里,还停留在其他文件或口头交接中。

熟悉业务的老员工可以靠经验把这些信息拼起来,但新人第一眼很难知道哪份是最新版本、每一列到底表示什么、哪些数字已经确认、哪些内容根本没有记录。结果就是理解成本高、信息容易残缺、格式不规范,而且每做一次方案都要重新找人、找表、核对和解释。

这不是说每家餐厅都完全处于同一种状态,而是从现有围餐资料中抽象出的典型问题:信息依赖人来拼,责任和来源没有形成统一链路。

flowchart TB
    subgraph BEFORE["没有系统:信息靠人拼"]
        direction LR
        B1["经理、厨师长等<br/>分别手工填表"] --> B2["每份 Excel<br/>结构和叫法不同"]
        B3["其他文件 / 口头交接"] --> B4["信息散落、残缺<br/>版本难确认"]
        B2 --> B5["新人找人、找表、猜含义"]
        B4 --> B5
        B5 --> B6["理解成本高<br/>容易漏项或误用旧数据"]
    end

    subgraph ACTION["系统做的治理"]
        direction LR
        A1["保留原始证据"] --> A2["整理为标准字段"]
        A2 --> A3["不确定项由人确认"]
        A3 --> A4["形成正式事实<br/>与可检索历史"]
    end

    subgraph AFTER["有系统:信息按责任流动"]
        direction LR
        C1["统一查看字段、来源和状态"] --> C2["本次事实与历史参考分开"]
        C2 --> C3["Agent 按规则生成并校验"]
        C3 --> C4["责任人确认可执行方案"]
    end

    BEFORE --> ACTION --> AFTER

我这三周做的项目叫“围餐智能体”。它解决的不是“让 AI 写一段漂亮方案”这么简单,而是把上述混乱先整理成可追溯的事实,再让系统帮助人生成方案。

所以我给这个项目定的目标是:

把 Excel 中的零散资料变成有来源的业务事实,再让 Agent 根据本次真实需求调用这些事实和历史经验,生成一份可以检查、可以修改、可以确认的方案。

这里有一个很重要的边界:模型可以提出建议,但不能直接把建议写成正式业务事实。

小黑在方案装配工位上同时处理本次事实、历史参考与规则校验

这张图先帮观众记住一句话:Agent 负责调度,事实、规则和人负责兜底。

第一部分:业务上到底解决了什么

把刚才的业务现状拆开看,有三个工程问题。

第一,Excel 是给人看的,不是给系统看的。同一份工作簿里可能同时有标题、备注、合并单元格、并排小表和布场示意图。人可以凭经验理解,程序却容易把备注当数据、把菜名当表头。

第二,历史资料和本次需求容易混在一起。比如历史方案写了 10 桌,不代表今天也是 10 桌;历史结算金额也不能直接变成本次报价。

第三,AI 输出很流畅,但流畅不代表可靠。如果人数、餐标、食安状态都没有确认,模型依然可能给出一份看起来完整的方案。

我的处理方式是把系统分成四个角色:

角色 通俗理解 实际职责
Excel 解析 资料整理员 保留原文件和单元格证据,把表格转成标准记录
PostgreSQL 事实保险柜 保存来源、版本、审核状态和正式业务事实
WISE 历史资料检索员 根据语义找相似经验,但不决定本次硬数字
Agent 调度员 理解用户想做什么,按顺序调用查询、生成、校验等能力

全局只看两条链路

flowchart TB
    X["真实 Excel"] --> E["证据化解析"]
    E --> Q{"含义明确吗?"}
    Q -- "明确" --> REVIEW["业务确认"]
    Q -- "不明确" --> C["受控模型候选"]
    C --> REVIEW
    REVIEW --> PG[("PostgreSQL 事实源")]
    PG --> O["Outbox 任务"]
    O --> W[("WISE 历史索引")]

    U["本次活动需求"] --> I["意图识别"]
    I --> A["Orchestrator 调用工具"]
    PG -- "硬事实" --> A
    W -. "历史参考" .-> A
    A --> G["规则生成方案"]
    G --> V{"校验通过?"}
    V -- "否" --> ASK["继续补充 / 修正"]
    V -- "是" --> HUMAN["有权限的人确认"]

讲这张图时不要逐个念模块,只强调三件事:PostgreSQL 管事实,WISE 管历史检索,Agent 管调用顺序。

第二部分:Excel 不是“读出来”就算解析成功

这一部分我会重点展开,因为它是项目里思考和迭代最多的一块。

工业界处理 Excel,常见做法包括转 HTML、转 Markdown,或者把每行铺成宽表放进 DuckDB。这些做法各有价值:HTML 擅长保留视觉结构,Markdown 适合送入 RAG,DuckDB 擅长对规则表做批量分析。

但我的数据有两个特点:第一,表格结构不稳定;第二,业务要求可追溯、可审核。因此我没有把某一种转换格式当成最终事实,而是采用:

原始证据保留 + 确定性解析 + 疑难区域模型候选 + 人工确认 + 正式业务投影。

换句话说,HTML 或 Markdown 更像一种“展示和检索格式”,DuckDB 更像一种“分析工具”,但 PostgreSQL 中带来源、版本和审核状态的记录,才适合作为正式事实。

具体过程分五层:

  1. 能不能安全打开文件,并保存文件哈希、Sheet、坐标、公式和非空单元格。
  2. 能不能识别一块连续区域是不是一张表。
  3. 能不能判断它属于菜单、食安、酒水、人员还是布场。
  4. 能不能把“菜品名称”“品名”等不同叫法统一成标准字段。
  5. 能不能形成正式业务行;不能确认的内容只保留证据,不强行猜测。

普通行列表格主要由可复现的代码处理。只有像平面布场这类依赖空间位置、合并单元格和图片关系的疑难区域,才交给视觉模型提出有限候选;模型结果必须绑定到真实 Sheet 和记录,再由 Reviewer 选择接受或仅保留原文。

我会在 Excel 专题 中讲清楚每一层、两次打开工作簿的原因、表块检测、字段白名单、模型边界和后续优化。

第三部分:为什么 PostgreSQL 后面还要接 Outbox 和 WISE

PostgreSQL 和 WISE 不是二选一。

  • PostgreSQL 擅长回答“本次到底有多少人、几桌、预算多少、食安是否通过”这种硬事实。
  • WISE 擅长回答“历史上类似活动出现过什么问题、有哪些经验可以参考”这种语义问题。

如果保存数据库时顺便同步调用 WISE,会出现一个工程问题:数据库成功、WISE 超时怎么办?如果回滚数据库,会丢掉已经确认的业务事实;如果不回滚,两边状态又不一致。

所以我采用 Transactional Outbox。数据库事务只做两件事:保存正式事实,同时写一张“待发布任务单”。后台 Worker 再领取任务、调用 WISE,失败就按退避策略重试。这样 WISE 临时不可用不会拖垮正式导入,系统也知道哪些任务排队、重试、成功或最终失败。

WISE 的读取我比较过三种接法:应用 HTTP、Skill API 和 MCP。评测发现 MCP 与 Skill API 实际调用的是同一个 WISE Agent Tool,检索算法没有本质差异。因此最终选 MCP,不是因为它“搜得更聪明”,而是因为它有标准的工具发现、参数结构和错误协议,更适合 Agent 扩展。

当前真实实现是:发布和删除仍走 WISE HTTP,检索走 MCP。 检索前先确认知识库可见,再调用 knowledge_search,必要时调用 read_chunks 取完整内容,最后还要回 PostgreSQL 做元数据过滤。

第四部分:Agent 到底做了什么

这里我不想用“自主智能体”包装一个普通接口调用,所以我把边界说清楚。

当前系统是一个受控的 Agent 工作流,不是多个 Agent 自由讨论,也不是模型自己决定所有工具参数。

用户说一句话后,系统先把它解析成结构化动作,例如:新建需求、补充人数、查询规则、生成方案、重新生成、校验、确认或取消。这里采用“规则 + 大模型”的混合识别:

  • 大模型更擅长理解自然语言、省略和一句话里的多个动作。
  • 规则可以在模型不可用时兜底,还专门保护“确认方案”和“取消需求”这类高风险动作。
  • 地点、接待等级、酒水和物资还要经过后端受控目录归一化,模型不能发明选项。

识别完成后,不是让模型自由运行,而是 Python 调度器按动作顺序调用确定的应用服务,并检查状态机是否合法。

举个例子,用户说:“改成 120 人,然后重新出方案。”模型需要保留动作顺序:先更新人数,再重新生成。调度器先更新需求版本,再加载 PostgreSQL 事实、检索 WISE 经验、生成方案、运行校验,最后才让语言模型把结构化结果表达成人能读懂的话。

第五部分:多轮对话不是简单地把聊天记录全部塞给模型

多轮对话里,最危险的是旧消息覆盖新事实。例如用户先说 100 人,后来改成 120 人;如果模型只看聊天文本,可能同时看到两个数字。

因此上下文分成两类:

  • 权威状态:当前需求字段、每个字段是否确认、会话状态、最新方案 ID 和版本。
  • 语义参考:最近消息和较早对话摘要。

Prompt 明确规定:权威状态优先,摘要和历史消息不能覆盖它。上下文过长时,系统保留最近完整轮次,把更早的已完成轮次压缩成结构化摘要;摘要失败时退回有上限的最近上下文,不会阻断整个会话。

这不是让模型“永久记住一切”,而是用数据库状态保证事实连续,用摘要保证语义连续。

第六部分:方案生成里哪些地方真的用了 AI

这部分最容易被误解,所以我的结论放在前面:

当前方案主体不是用一个 Prompt 让大模型自由写出来的,代码里也不存在“围餐方案生成大 Prompt”。

实际分工如下:

阶段 是否使用模型 做什么
理解用户话语 输出受 Schema 约束的动作和需求补丁
调用什么能力 主要由代码 按动作枚举和状态机确定执行顺序
找历史经验 WISE MCP 检索相似菜单、食安和复盘证据
生成菜单、数量、人员、物资、日程、成本 主要由确定性代码 使用本次需求、目录规则和 PostgreSQL 事实计算
判断能不能确认 代码规则 检查缺失字段、食安、过敏、数量和证据
最终自然语言回复 只基于已提供的结构化结果和检索材料表达,并要求引用来源

例如,每桌物资数量按目录规则乘桌数,服务人数按接待等级比例向上取整,成本按单价乘数量,食安未通过会阻断确认。这些都不是模型临时编出来的。

诚实说明:三周做到了什么,没做到什么

三周时间里,我优先完成了最容易出事故的骨架:来源证据、模型权限边界、事务一致性、受控检索、需求状态和方案校验。

我没有把它说成成熟生产系统。当前不足包括:

  • 数据量不足,无法证明所有 Excel 格式都能稳定解析。
  • 平面布场只完成了受控任务候选,还不是完整的空间拓扑理解。
  • 菜单选择目前是可解释的顺序筛选,不是复杂的全局最优组合算法。
  • WISE 评测样本只有 24 问,能支持接入选型,不能代表大规模线上效果。
  • 当前是单 Orchestrator 的 Agent 工作流,不是多 Agent 专家 Handoff 系统。

如果时间继续增加,我不会第一步堆更多 Agent,而会先扩充真实样本、量化每层准确率、完善人工审核效率和线上可观测性。因为 AI 应用工程的价值,不只是“模型能回答”,而是系统知道什么可以信、什么需要确认、出了问题如何追踪。

结束语

这个项目对我最大的训练,是从“调用模型”走向“设计一个可信的 AI 应用”。

我最终想交付的不是一段看起来聪明的回答,而是一条完整链路:

资料有来源,事实可追溯,模型有边界,失败可恢复,方案能检查,人可以做最后决定。