第 10 讲:不幻觉的任务型智能体——Genie Worksheet

Agentic AI · Lecture 10。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应:Stanford CS224V Fall 2026 Lecture 12(11/4 Minimizing hallucination in task-oriented agents);Fall 2025 的两次课(Task-Oriented Agents、Evaluation of Task-Oriented Agents)。 关于材料来源:2026 年这次课的幻灯片尚未公开。本讲依据:2025 年的两份幻灯片(Lam & Joshi);Genie Worksheet 论文(Joshi、Liu、Chen、Weigle、Lam,Controllable and Reliable Knowledge-Intensive Task-Oriented Conversational Agents with Declarative Genie Worksheets,ACL 2025,arXiv 2407.05674);课程表的描述(第一个高层的任务型智能体规格语言;开发者只关注要完成的任务,底层的对话实现交给语言的实现;形式化的对话状态、语义解析、对话状态追踪、回复生成)。 配套代码:code/lecture10/(只用 Python 标准库;04 号文件可选,需要 anthropic 包和 API 密钥) 预计阅读时间:3 小时左右(含运行代码)


0. 本讲导航

0.1 学完本讲,你应该能够

  1. 区分”知识型智能体”和”任务型智能体”,解释什么是混合主动权、什么是”不愉快的路径”,以及为什么它们是任务型对话的难点。
  2. 说出两种传统做法(对话树、对话动作的状态机)各自的局限,以及”LLM + 函数调用”在可控性上的问题。
  3. 描述 Genie Worksheet 的设计:开发者写声明式的工作表规格(只写”愉快的路径”),运行时系统处理”不愉快的路径”;LLM 只负责语义解析和回复生成。
  4. 解释 Genie 的技术细节:形式化的对话状态(记录)、五种智能体动作、运行时策略的算法、数据依赖的字段、查询和任务的组合。
  5. 说明怎样评估任务型智能体:为什么 WOZ 式的数据集不够、真实用户研究的四个指标,以及论文的结果。

0.2 先修知识

知识点用在哪里最低要求
第 3 讲第 1、2 节工具调用(函数调用);harness;工作流 vs 智能体
第 6、7 讲第 3、4 节语义解析;SUQL(知识查询用它)
第 4 讲第 1 节可问责、政策一致性
第 5 讲第 5 节模拟用户、真实用户评估

0.3 本讲地图

第1节  动机:任务型智能体、混合主动权、可控性                  ← 代码 01
第2节  以往的做法:对话树、对话动作的状态机、函数调用           ← 代码 01
第3节  Genie Worksheet 的设计                                 ← 代码 02 演示 1
第4节  技术细节:对话状态、智能体动作、运行时、解析器            ← 代码 02、04
第5节  评估:STARv2、真实用户研究                              ← 代码 03
第6节  讨论与边界
第7–11节 小结、与项目的关系、练习、延伸阅读、下一讲预告

0.4 本讲的玩具世界

代码 genie.py 是一个迷你的选课助手(幻灯片的例子):

  • 知识库:23 门虚构的课程(课程号、名称、方向、学分范围、评分方式、每周学时、评分、是否满足”重要实现要求”、上课时间、剩余名额),存在 SQLite 里;
  • 工作表:StudentInfo(姓名、学号、是否国际学生、签证类型——只在国际学生时问)和 CourseToTake(课程、评分方式、学分;各有校验;选课之前要确认;动作是调用选课 API);
  • 模拟用户:要选两门课。一半的用户直接知道课程号,另一半只有要求(“AI 方向、每周不超过 12 小时”),要先问智能体。用户会中途提问、一次说好几件事、改主意、一开始不愿意给学号;连续几次没被听懂就放弃;
  • 三种智能体:对话树、“LLM + 函数调用”(论文的基线)、Genie。

关于本讲的数字:幻灯片和论文里的真实数字会注明出处;模拟实验的数字都来自 01~03 号代码的实际输出。特别注意:没有真实的 LLM 和真实的用户;解析器、函数调用的 LLM 会犯哪些错、概率多大都是设定的参数。其中最关键的一条假设——函数调用的 LLM 遵守指令的概率随轮次下降,Genie 的解析器不会——是根据论文的观察设定的,不是模拟”跑出来”的结论。


1. 动机:任务型智能体

1.1 知识型智能体 vs 任务型智能体

前面几讲的智能体都在回答问题:用户问,智能体查(文本、数据库、知识图谱)、答。幻灯片第 4 页把它画成:

知识型智能体(用户主动):用户的话 → 语义解析 → 执行(RAG、Text-to-SQL)→ 回复生成
任务型智能体(混合主动):用户的话 → 语义解析 → 执行 → 智能体策略(决定说什么)→ 回复生成

任务型智能体要完成一件事:订餐厅、转账、提交工单、选课。它要向用户收集信息、遵守规则、在合适的时候执行有副作用的动作。多出来的那个部件——智能体策略(agent policy)——决定”下一步说什么、做什么”。

幻灯片第 2 页的例子:商用的虚拟助手(基于函数调用)——“斯坦福的天气怎么样?“答得很好(66°F);“帮我订一张去迈阿密的机票”——做不到,只会展示一堆搜索结果。

1.2 为什么混合主动权很难

只有智能体主动(“愉快的路径”):一个简单的智能体只要依次问所有的参数,用户依次给出预期的回答。幻灯片第 6 页:某航空公司的电话助手——“欢迎回来。请问需要什么帮助?您可以说’航班状态’或’里程账户’……”用户说”航班状态”。

混合主动权(“不愉快的路径”,第 7~9 页):用户随时可以说任何话,即使智能体正在问一个问题。用户可以:

  • 不理会、或拒绝回答;
  • 反过来要信息、或者发起一个新的动作;
  • 改主意、取消之前的操作;
  • 让智能体再说一遍、闲聊;
  • 说一些出乎意料的话(超出领域)。

同一个电话助手——用户回答”什么是航班状态?“——它就不知道怎么办了。幻灯片第 8 页的银行柜员例子:

柜员客户
您要转多少钱?我账户里有多少钱?(反问)
您想开一个定期储蓄账户吗?那是什么?(要信息)
您要转多少钱?算了。(取消)
(客户抱怨)……我要求一次免费的泰国之旅。——(超出范围的要求)

幻灯片的判断:LLM 非常擅长处理不愉快的路径。那为什么商用的聊天机器人还这么保守?

1.3 可控性:LLM 会说错话、做错事

幻灯片第 10~12 页:尽管 LLM 很成功,商用的聊天机器人仍然很保守——幻灯片说,OpenAI 自己的客服机器人仍然用对话树。为什么?两个真实的事件:

  • 加拿大航空的聊天机器人向乘客 Jake Moffatt 承诺了一个其实没有的折扣。不列颠哥伦比亚省民事仲裁庭裁定航空公司赔偿 812.02 加元(合 642.64 英镑)的损失和费用——公司要为聊天机器人说的话负责。
  • Cursor 的用户在不同设备之间切换时莫名其妙地被登出。用户联系客服,邮件回复(署名”Sam”)说这是新的登录政策下”预期的行为”——但根本没有这样的新政策,是 AI 编的。

所以智能体策略的设计目标有两个(幻灯片第 13 页):

  1. 可控:不能给出错误的信息;只采取允许的动作。
  2. 有帮助:理解用户在要什么;在规则允许的范围内提供帮助和信息。

这两个目标常常互相拉扯:对话树非常可控,但一点也不”有帮助”;LLM 很”有帮助”,但不可控。代码 01 的演示 3 展示了这种张力:用户在智能体问课程时反问”有哪些 AI 课?“、一次说好几件事、拒绝给学号、闲聊——对话树一律”Sorry, I didn’t understand”;一个理想的(总是遵守指令的)函数调用 LLM 和 Genie 都能得体地应对。函数调用 LLM 的问题不在”能不能应对”,而在能不能一直守规矩(第 5 节)。


2. 以往的做法

2.1 智能体策略的设计空间

幻灯片第 16 页:

  • 神经网络的策略 vs 编程的策略:神经网络的策略(让模型自己决定下一步)不能给开发者完全的控制。
  • 策略的规格,按抽象层次从低到高:
    1. 对话树:有限状态机;
    2. 对话动作:参数化的有限状态机;
    3. Genie Worksheet:声明式地规定”愉快的路径”和知识库,“不愉快的路径”由 Genie 的运行时处理。

2.2 对话树(今天商用系统的主流)

(幻灯片第 17~19 页)用户发起一个事务;智能体逐个索要”槽位”。自然语言理解(NLU)做意图分类(从一个很小的固定集合里选)和槽位填充:“我想转 100 美元” → 意图 TransferMoney,槽位 amount = $100.00。

餐厅预订的例子:

A:您好,需要什么帮助?
U:我想订 Valentine's Day 的餐厅。
A:什么样的餐厅?
U:California Ave 上的 Terun。   → Name = "Terun"
   ——或者——
U:有披萨的地方。                → Food = "pizza"
   ——或者——
U:我不知道,你推荐什么?         → ???(不在预先定好的意图里)

每个节点:意图 + 槽位 → 领域专用的规则 → 写死的句子。

优点:对对话的完全控制。缺点:

  1. 表达能力有限:意图和槽位能表达的东西很少。“机场附近或者 Fisherman’s Wharf 附近排名前三的餐厅”——一个槽位装不下。
  2. 繁琐:路径的数量指数级地增长(商品浏览时用户会用各种方式修改搜索条件);每个问题都要手工写。
  3. 脆弱:开发者不可能预料到所有的话;需要处理混合主动权、意外的回答。

代码 01 的演示 1 算了一笔账:选一门课要 8 步(7 个问题 + 确认),如果每一步用户除了”按预期回答”还可能做 kk 种别的事,要预料的路径数是 (k+1)8(k+1)^8——k=1k = 1 是 256 条,k=3k = 3 是 65,536 条,k=5k = 5 是 167 万多条。

演示 2:同一位用户(想找”满足重要实现要求的 Systems 课”),被问到课程时反问”有哪些……课?“——对话树连续回答”Sorry, I didn’t understand. Which course would you like to enroll in?”,用户放弃了。Genie 先回答问题(列出两门课),再回到”您想选哪门课?“,最后两门课都选上了(中间还遇到一门课满了)。

2.3 对话动作的状态机,以及 WOZ 数据集

(幻灯片第 20~26 页)MultiWOZ 是一个很有影响的大型对话数据集:剑桥的礼宾服务,每一轮都标注了领域和槽位;最初 7 个领域,后来去掉了质量差的两个(警察、医院),剩下 5 个(餐厅、酒店、景点、火车、出租车);30 个槽位;封闭的本体,1,829 个取值;表示是”槽位—值”对。

它用的是 Wizard-of-Oz(WOZ) 的方法:用户和”智能体”都是人(付费的众包工人),一个工人假扮自动的智能体,另一个按提示扮演用户、完成指定的任务。问题是不反映真实的生活——用户很少改主意、浏览各种选项,“智能体”也不会犯错。MultiWOZ 被重新标注过三次(Google、Amazon 等),仍然有很多错误。

对话动作把句子”分解”成动作 + 参数:同一个意图触发相似的转移。对话状态机的例子(第 23 页):知识库浏览(Query → QueryResponse)、动作(RequestAction → SlotFillQuestion → … → ConfirmAction → AskToConfirm → ActionResponse)、取消……动作名与领域无关,具体内容与领域有关。

形式化的对话状态(第 25 页,X-RiSAWOZ,Moradshahi 等 2023):用形式化的状态代替自然语言的历史——用户的话、置信状态(belief state,用户的对话状态的一部分)、查询结果、智能体的对话动作、智能体的话;一个多任务的神经网络(mBART)完成对话状态追踪、动作决定、动作生成、回复生成四个任务。“形式化的状态捕捉了所有有用的信息”。

小结(第 26 页):形式化的对话状态总结了对话;抽象的、“与领域无关”的有限状态机;但智能体策略没有被规定出来(隐含在智能体的回复里),而且局限于槽位填充,偶尔推荐订个餐厅或酒店。

2.4 LLM + 函数调用

第三种做法:把能做的事写成一组函数(查询、提交……),开发者的规则写进一长段指令,让 LLM 自己决定什么时候问什么、什么时候调用哪个函数。它擅长处理各种说法(2.2 节的问题它都能应对)。问题是:下一步做什么完全由 LLM 决定。论文和幻灯片的观察(第 5 节详述):

  • 对话越长,越难保持相关的上下文信息、越不遵守指令(“LLM 不能遵守所有的指令""LLM 在开发者定义的、训练数据里少见的政策上很吃力”);
  • 即使有知识库,它也会编出不存在的课程;
  • 它会过早地调用提交的 API、不先确认就执行。

3. Genie Worksheet 的设计

3.1 一个案例:选课

(幻灯片第 29~37 页)一位 CS 硕士生要选课。要参考的东西有:所有开设的课程(描述、老师、开课时间、学分);项目单(program sheet)——每个专业方向一份,规定了基础课、重要实现要求、广度要求(四个领域选三个)、深度要求、学分上限、评分方式……;课程的评分、评论、每周学时、选课结果、先修顺序。学生问:“我是 CS 专业的,想完成’重要实现要求’,哪些课最省事?“——这需要查知识库(SELECT … WHERE significant_implementation_requirement = TRUE ORDER BY average_hours_spent LIMIT 5),再帮他填一张复杂的、嵌套的选课表。

3.2 设计原则

(幻灯片第 56~57 页)

  • 完全的混合主动权;
  • 高层的声明式规格:工作表 + 知识库。工作表的能力类似网页表单;开发者只规定”愉快的路径”(智能体的主动权),运行时系统用给定的知识资源处理”不愉快的路径”——尽量少写代码,同时得到一个有效的智能体。

具体的原则:

  1. 开发者的控制:实现智能体的目标;
  2. 响应用户:用户的主动权永远优先;
  3. 完整地、自动地支持知识查询:用 SUQL(第 7 讲);
  4. 表达能力:知识查询和任务语句可以任意组合;
  5. 长对话也有效:用工作表做形式化的对话状态追踪。

幻灯片第 58~59 页的两个例子:

用户:我想选一门 AI 课,3 学分,按字母成绩。                    (用户的主动权:一次给了三个信息)
助手:这几门 AI 课评分最高:CS 224V、CS 224N、CS 205。您想选哪门?  (智能体的主动权)
用户:数学理论那门看起来不错,我选它。
助手:我将为您选 CS 205,字母成绩,3 学分,确认吗?               (智能体的主动权:执行前确认)
用户:确认!

用户:CS 224V 什么时候上课?                                   (用户的主动权:反问)
助手:CS 224V 周一、周三下午 3 点上课。您要选它吗?               (先回答,再回到任务)

开发者的控制(第 60~61 页):开发者能够不费力地控制关键的方面——对话的流程、动作的时机、向用户收集哪些信息。例如课满了的时候说什么:开发者可以规定”找几门秋季开的类似课程”,也可以规定”如果你快毕业了,可以申请特别许可”。代码里的 enroll_action 实现了后一种。

3.3 工作表

任务工作表(第 63 页):

  • 任务的定义:名字、谓词(什么时候适用)、种类、动作;
  • 字段的定义:谓词、名字、种类、类型、说明、“不要问”、是否必填、是否需要确认;
  • 名字和说明的语义很重要——它们就是提示词的一部分;
  • 动作用 Python 代码定义,给开发者灵活性;内置的动作有 say、propose。

知识库工作表(第 65 页):真实的查询常常同时涉及结构化和非结构化的数据——用 SUQL 处理混合的知识查询。

幻灯片第 39~40 页的选课助手:主工作表 course_enrollment(字段:course_to_take、student_info_details,动作是 enroll(...));StudentInfo(姓名、学号、邮箱);CourseToTake(课程名、评分方式——枚举 Credit/No Credit 或 Letter、学分、确认)。知识库有四张表:courses(课程号、名称、学分范围、评分方式、一般要求、基础要求、是否满足重要实现要求、广度领域、先修课……)、offerings(星期、时间、老师、学期)、programs(学位、专业方向、项目单的要求)、ratings(评分、评分人数、学年、学期、评论)。

代码 02 的演示 1 打印了本讲的工作表规格:

工作表 StudentInfo(执行前要确认:否;动作:无)
  name          str   Name of the student
  student_id    str   Student's ID number
  international bool  Is the student an international student?
  visa          enum  Visa type                     取值 ['F1', 'J1'];只在国际学生时问
工作表 CourseToTake(执行前要确认:是;动作:enroll_action)
  course        str   The course to enroll in       校验 _course_exists
  grade_type    enum  The desired grading basis     取值 ['Letter', 'CR/NC'];校验 _grading_ok
  units         int   The number of units           校验 _units_ok

这就是开发者写的全部东西。用户插话、改主意、拒绝……”不愉快的路径”一行也没写。


4. 技术细节

4.1 从规格到 Python,形式化的对话状态

Genie 把工作表的规格翻译成 Python 的数据类(dataclass),根据用户的话执行它们(幻灯片第 67 页)。LLM 很难在较长的对话里保持相关的上下文信息;Genie 用形式化的对话状态追踪对话:智能体运行时,解析器生成一组要应用到对话状态上的改动(第 68 页)。

对话状态是一组记录(第 69 页):

  • 每条记录有名字和种类;
  • 任务记录:字段名和值;
  • 知识记录:自然语言的问题、形式化的查询(SUQL)、结果。

4.2 五种智能体动作

(第 70 页)

动作含义
Report报告执行一条记录(任务或知识查询)的结果
Confirm请用户确认一条记录里某个字段的值
Say明确地说一句给定的话
Propose向用户提议一个新的任务或查询
Ask问一条记录里某个字段的值

4.3 一轮对话

(第 71~84 页)一轮对话的输入:

  • 自然语言:只给上一轮的对话(这改善了语义解析的效果)和当前用户的话;
  • 形式化的语言:对话状态(记录以 Python 代码的形式交给解析器)、上一轮的智能体动作、工作表规格。

流程:

用户的话 ──► 解析器 ──► 填写后的工作表 ──► 智能体策略(运行时)──► 更新后的工作表 + 智能体动作 ──► 回复生成器 ──► 回复

解析器有三个模块(第 76~78 页):

  • 上下文语义解析器(CSP):自然语言 → 工作表的表示。用户可以:给现有的工作表提供值;修改之前填的值或删掉它;发起一个新的任务或查询(生成一条新记录)。
  • 知识解析器(KP):自然语言 → SUQL 查询。它把知识的接入和 CSP 分开:CSP 只把”知识查询”交给 KP,KP 可以用更高级的解析方法(ReAct、思维树……)。
  • 更新模块:执行代码,更新对话状态。

智能体策略(第 80~82 页):LLM 不生成智能体的回复;Genie 用一个运行时系统计算智能体的回复——执行知识查询、执行动作、生成智能体动作。算法:

输出:一组智能体动作 A
知识查询:缺少必需的参数 → 把"问这个参数"加进 A;查询完整了 → 执行,更新变量
工作表:  某个字段需要确认 → 把"请求确认"加进 A,或者执行
         工作表完整了 → 执行动作
         有必填的字段还没填 → 把"问这个字段"加进 A

为什么这样做(第 81 页):LLM 在开发者定义的、训练数据里少见的政策上很吃力;LLM 不能遵守所有的指令;智能体动作迫使 LLM 生成受智能体策略约束的、可靠的回复。用一个算法模块计算必要的动作,提高了 LLM 遵守指令的能力。

回复生成器(第 84 页):一个 LLM,把形式化的智能体动作转换成自然语言;对话状态和用户的话为回复提供上下文。

4.4 一段完整的对话

代码 02 的演示 2 用写好的 14 轮用户输入(解析器出错率设为 0)展示了每一轮的解析结果、对话状态和智能体动作。节选:

第 1 轮  用户:My name is Ana Lee, I am an international student.        (一次说两件事)
         解析器:student.name = 'Ana Lee'; student.international = True
         智能体动作:ask(student_id)
第 2 轮  用户:Why do you need my student ID? I'd rather not say.        (拒绝)
         智能体动作:say, ask(student_id)
         智能体:I need your student ID to enroll you in courses; it is only used for enrollment. What is your student ID?
第 3 轮  …… 第 4 轮 智能体动作:ask(visa)                                  (说了是国际学生,才问签证)
第 5 轮  用户:What are some AI courses with at most 12 hours of work per week?   (中途提问)
         对话状态:+ answer('What are some AI courses …') -> "SELECT … WHERE area = 'AI' AND hours <= 12 …" -> 3 rows
         智能体动作:report, ask(course)                                 (先回答,再回到任务)
第 7 轮  用户:For a CR/NC.
         智能体:CS 191 must be taken for a letter grade. Would you like …   (校验失败,说明原因)
第 8 轮  智能体动作:confirm(Shall I enroll you in CS 191 for 3 units, Letter?)
第 9 轮  用户:Yes → 智能体动作:report(You are enrolled in CS 191 …)
第 11 轮 (第二门课)智能体:Unfortunately, there are no seats available for CS 196. You can ask for special
         permission if you are graduating soon.                           (开发者指定的回复)
第 13 轮 用户:Actually, I changed my mind: CR/NC instead.               (改主意)
         对话状态:CourseToTake(course='CS 278', grade_type='CR/NC', units=3)   (值变了,确认被清掉)
         智能体动作:confirm(重新确认)

4.5 Genie 能支持什么

(幻灯片第 85~90 页)

  • 组合查询和 API:把一个工作表实例的结果当作另一个工作表的字段。“我想在情人节订一家纽约的意大利餐厅,两个人”→ BookRestaurant(restaurant=Answer(SELECT * FROM restaurants WHERE 'italian' = ANY(cuisines) AND location = 'NYC'), date="02/14/2024", num_people=2);
  • 完成多个任务(选两门课);
  • 数据依赖的字段:有些字段只有部分用户需要(“您是国际学生吗?”——“是的,学生签证。”——“是 F1 还是 J1?”);
  • 一句话里有多个知识查询:“推荐几门评分高的 NLP 课?另外,下学期什么时候开学?”→ 一个 SUQL 查询课程表,一个查 FAQ 的自由文本;
  • 一句话里同时有任务和知识请求;
  • 记住关键的信息;
  • 允许不愉快的路径,例如改之前的答案:“我想 8 号从纽约飞洛杉矶。……哦等等,8 号我有个会,改成 9 号吧。”

4.6 工作表 vs 对话状态机

(2025 年第二份幻灯片第 12 页)

相似:都声明槽位,自动问槽位填充的问题、请求确认。

不同:工作表的运行时不是一个有限状态机——

  • 一句话里可以有多个查询和请求;
  • 查询和动作请求可以任意地交错;
  • 智能体的问题不一定马上得到回答!用户随时可以提问,智能体要回到尚未完成的请求上。

小测验:能不能用一个栈来回到未完成的请求?——不够:用户可以随时修改任何字段的值,不只是栈顶的那个。Genie 的做法是:每一轮都扫描整个工作表,处理所有未完成的请求。代码 genie.py 的 GenieAgent.policy 就是这样:先处理所有还没报告的知识记录,再按顺序找第一条”有字段没填 / 需要确认 / 可以执行”的任务记录。

4.7 为什么解析器只看”上一轮 + 对话状态”

代码 02 的演示 3 粗略地估计了两种做法的输入长度(按词数):

轮次Genie:上一轮 + 状态 + 规格函数调用:完整历史 + 指令
163264
7131411
14135561

对话状态把”到目前为止发生了什么”压缩成了几条记录;函数调用的 LLM 每一轮都要从越来越长的历史和一长段指令里决定下一步。论文的结论之一:LLM 需要简洁的上下文和更少的指令,才能在不熟悉的领域里表现好。


5. 评估

5.1 STARv2:和以往的工作比较

STAR 数据集(Mosig 等):13 个领域、22 个任务,评测”预测下一个动作”,并提供了描述对话流程的策略图;STARv2(Zhao 等,AnyTOD 论文)更新了置信状态和动作状态的标注、给表结构写了更直观的说明。指标:用户动作 F1、系统动作 F1(根据对话状态和用户的对话动作,智能体下一步该做什么)、联合目标准确率。论文选了逻辑最复杂的三个领域:银行、问答(trivia)、行程。

当时最好的 AnyTOD:在除测试领域以外的全部领域(约 6,000 个样本)上微调 T5 XXL,并用程序实现逻辑。Genie:语义解析用 3 个示例;以银行领域为例,智能体策略在工作表里只要 9 行代码(AnyTOD 要 31 行)。论文表 1(系统动作 F1):

系统银行行程问答
AnyTOD(PROG + SGD,微调 T5)65.062.986.3
GPT-4 Turbo(函数调用,零样本)55.142.782.5
GPT-4o-mini(函数调用)50.843.869.8
Genie + GPT-4 Turbo82.583.492.7
Genie + GPT-4o-mini82.580.590.3
Genie + Llama 3.1 70B82.175.982.2

Genie 比以往最好的成绩分别高 17.5、20.5、6.4 个点;而且 Genie + GPT-4o-mini 在三个领域都超过了 GPT-4 Turbo 直接做函数调用——好的结构让弱一些的模型胜过强的模型。大部分错误来自数据标注的不一致(AnyTOD 的论文也指出过)。

但是(第二份幻灯片第 18 页):WOZ 数据集不现实——很少有不愉快的路径;对 LLM 来说太简单(简单的槽位填充);标注比 LLM 的输出还差!幻灯片的批注:“LLM 跑赢了传统的 NLP 评估。“所以必须用真实的用户评估真实的应用。

代码 03 的演示 1 也重现了这一点(模拟):“愉快的路径”上(用户按顺序回答、直接知道课程号,像 WOZ 的用户),三种智能体的任务完成率是对话树 100%、函数调用 96%、Genie 100%——分不出好坏。

5.2 真实用户研究

三个复杂程度不同的真实应用(第一份幻灯片第 97~98 页,论文第 7 节):

  • 订餐厅:用 Yelp 的真实数据(第 7 讲);用户被要求像和人类客服说话一样,不限于问规定的槽位;
  • 提交工单:复刻大学学生服务门户的一部分任务(ServiceNow 的一部分 API),有多个任务和子任务,还有学生提交前要看的自由文本资料;
  • 选课:斯坦福 CS 课程的真实数据(四张表),要查课程要求、评论和评分,同时填写复杂的嵌套表单。

基线:GPT-4 Turbo + 函数调用,并且给它和 Genie 一样的知识解析器,能执行 SUQL 访问混合的知识库。(论文还试过 NeMo Guardrails,发现它在基本的任务型对话上就失败了。)用户:在 Prolific 上招募参与者做订餐厅和提交工单,另外招了 20 名大学生评估选课助手;随机分配到两个外观相同的系统;共 62 位参与者。

指标(人工逐轮检查):

  • 语义解析准确率(SP):用户的话是否对应了正确的 API、数据库和填写的字段;
  • 执行准确率(EX):智能体是否执行了正确的 API 和数据库查询、参数是否正确;
  • 对话动作准确率(DA):智能体是否遵守开发者提供的政策;
  • 任务完成率(GCR):用户能否在智能体的帮助下完成任务。

论文表 2:

全部订餐厅提交工单选课
SP(Genie)91.493.885.894.1
EX:GPT-4 (FC) / Genie65.4 / 86.550.0 / 88.058.6 / 80.079.2 / 89.7
DA:GPT-4 (FC) / Genie69.1 / 89.257.7 / 92.567.6 / 82.577.8 / 92.9
GCR:GPT-4 (FC) / Genie21.8 / 82.854.5 / 91.60.0 / 80.010.0 / 80.0
  • GPT-4 (FC) 在订餐厅上相对好一些(54.5%)——这是它最熟悉的领域,在现有的对话数据集里很常见;在不熟悉的提交工单和选课上几乎完全失败。论文推测,提交工单的谓词更多、要遵守的指令更多,对 GPT-4 (FC) 特别难。
  • 第二份幻灯片的评语:GPT-4 的结果是不可接受的——即使订餐厅的 54.5% 也不够好;选课时它会编出不存在的课程,尽管它用了知识库的结果。Genie Worksheet 是唯一一种在查询结果和动作上都不幻觉的基于 LLM 的技术,再加一些工程就可以部署——当时正在和几家公司试点。

5.3 错误分析

  • 随轮次的变化(论文图 5):Genie 的对话动作准确率一直在 80% 以上,从对话开始到结束只下降约 8%;GPT-4 (FC) 下降约 43%——支持”LLM 很难在长交互里保持上下文,形式化的对话状态缓解了这个问题”的假设。
  • GPT-4 (FC) 的幻觉:尽管能用知识解析器和 SUQL,在选课、提交工单、订餐厅三个领域分别有 7/10、4/11、5/10 段对话出现了幻觉;在三个领域都过早地调用了提交的 API,不遵守指令(例如调用 API 之前不先请求确认)。
  • Genie 的解析错误:各应用的语义解析错误率在 6.2%~14.2% 之间。以提交工单为例(论文图 6):最常见的失败(21%)是用户拒绝提供必需的信息,智能体无法继续;21% 是 API 调用不正确;最大的错误来源(43%)是 Answer 动作用错了(查了不相关的知识源、或者漏了查询);14% 是解析器没有新建工作表,而是错误地更新了已有的一张。选课和订餐厅的错误主要分布在”API 调用不正确”和”Answer 用错了”之间。
  • 怎样应对解析错误(论文第 7.5 节):回答查询时明确地引用它理解的问题,让用户能发现偏差;所有有副作用的动作执行前都要确认——这让用户可以在下一轮纠正,智能体相应地更新对话状态。即使对话状态里有错误的条目,也能帮助后续的消歧和纠正,不应该过早丢弃。

5.4 模拟实验

代码 03 用 100 位”愉快”的模拟用户和 100 位”真实”的模拟用户分别测了三种智能体:

用户智能体SPEXDAGCR平均轮数放弃编造
愉快的路径对话树–100%100%100%11.400
愉快的路径LLM + 函数调用–75%70%96%17.300
愉快的路径Genie93%100%100%100%13.300
真实的用户对话树–100%88%5%6.7950
真实的用户LLM + 函数调用–62%62%69%18.5048
真实的用户Genie94%99%99%97%13.800

对话动作准确率随轮次的变化(演示 2):

第 1-5 轮第 6-10 轮第 11-15 轮第 16-30 轮
LLM + 函数调用84%69%52%38%
Genie100%99%99%100%
  • 对话树:每一步都可控(EX 100%),但真实的用户一中途提问就被卡住,95 位放弃了。
  • 函数调用的 LLM:违反指令的次数(演示 3)——跟丢之前的信息、重问已经回答过的问题 500 次;没确认就调用选课 API 114 次;不理用户的提问 56 次;提交时用了改主意之前的旧值 47 次;跳过签证类型 4 次;38 段对话出现了编造。演示 4 的一段对话:它在推荐课程时编出了一门不存在的 “CS 388 Advanced Systems Topics”,用户选了它(所以输出里用户”想选”的第一门课显示为 CS 388),之后又在用户纠正学分时直接提交——一路出错。
  • Genie:1,383 轮里解析错了 86 轮(SP 94%),但只有 3 段对话失败——执行前的确认让用户在大多数解析错误造成后果之前就纠正了。
  • 再强调一次:函数调用的 LLM 随轮次变差,是根据论文的观察设定的。练习 2 把这两个机制(随轮次变差、编造)关掉,它的任务完成率就升到 97%,和 Genie 一样——差距完全来自这两点。模拟的价值在于让你看清哪个机制导致了差距,以及 Genie 的哪个设计(形式化的状态、程序决定的策略、执行前确认、回复只能来自智能体动作)挡住了它们。

6. 讨论与边界

6.1 Genie 把 LLM 限制在哪里

Genie 的核心思想(论文摘要):一个算法化的运行时系统实现开发者提供的策略,把 LLM 限制在两件事上——(1) 用简洁的对话历史解析用户的输入;(2) 根据给定的上下文生成回复。这又是计算思维:LLM 不擅长”在长对话里一直遵守几十条规则”,程序擅长;LLM 擅长”理解各种说法”和”把动作说成自然的话”,程序不擅长。

6.2 Genie 没有解决什么

  • 规格本身要写对、写全。工作表漏了一个字段、一条规则,Genie 就会”可靠地”做错。幻灯片列的研究项目正是针对这一点:GenieWorksheetWizard——用模拟发现任务型智能体缺失的能力(以 Fidelity 的投资业务为案例);从真实的对话自动生成一个完整的 Genie 工作表;心衰用药助手。
  • 解析错误仍然存在(6%~14%),只是大部分被确认挡住了。用户拒绝提供必需的信息时,智能体也无能为力。
  • 知识查询的错误:Answer 用错是 Genie 最大的错误来源——知识解析和第 6~8 讲的问题是同一个问题。

6.3 和第 3 讲的”工作流 vs 智能体”

Genie 是一个很好的例子,说明”工作流 vs 智能体”不是非此即彼:用户的话由 LLM 理解(灵活),下一步做什么由程序决定(可控)。对有副作用、有规则、要问责的任务(金融、医疗、政务),这种分工比”让 LLM 自己决定一切”更合适;对开放式的探索(第 8 讲的 SPINACH),让 LLM 决定下一步更合适。

6.4 本讲模拟的边界

  • 用户和 LLM 都是模拟的;用户说的话是模板生成的,解析器拿到的其实是结构化的用户动作,只是按设定的概率出错。
  • 函数调用的 LLM 随轮次变差、会编,是设定的;真实的 LLM 的表现取决于模型、指令的写法、对话的长度——你可以用 04 号文件的思路,自己做一个小的真实用户研究。
  • 课程是虚构的,任务比真实的选课简单得多(真实的项目单有几十条规则)。

7. 本讲小结

  1. 任务型智能体要完成有副作用的任务,需要一个智能体策略决定下一步。难点是混合主动权:用户随时可能反问、拒绝、改主意、闲聊(“不愉快的路径”)。LLM 很擅长处理这些说法,但不可控——加拿大航空和 Cursor 的事件说明,公司要为聊天机器人编出来的政策负责。
  2. 对话树完全可控但表达能力有限、路径指数级地多、很脆弱;对话动作的状态机和 WOZ 数据集(MultiWOZ)抽象了一层,但策略隐含在回复里,局限于槽位填充;LLM + 函数调用灵活,但对话越长越不守规矩、会编、会过早地执行。
  3. Genie Worksheet:开发者写声明式的规格(像网页表单:字段、类型、说明、数据依赖、校验、确认、动作)+ 知识库(SUQL);运行时系统处理不愉快的路径。LLM 只做两件事:上下文语义解析(上一轮 + 形式化的对话状态 → 对工作表的更新)和回复生成(智能体动作 → 话)。五种智能体动作:Report、Confirm、Say、Propose、Ask。运行时每一轮扫描整个工作表:先回答用户的提问,再推进任务;执行有副作用的动作之前一定确认。
  4. 评估:STARv2 上 Genie 比微调的 AnyTOD 高 6~20 个点,但 WOZ 数据集太简单、标注比 LLM 还差——必须做真实用户研究。62 位真实用户、三个应用:任务完成率 GPT-4 (FC) 21.8% vs Genie 82.8%;对话动作准确率随轮次下降 43% vs 8%;GPT-4 (FC) 在 7/10 段选课对话里出现幻觉。
  5. 设计启示:用户的话交给 LLM,下一步交给程序;给 LLM 简洁的上下文和少量的指令;执行前确认、回答时说明”我理解的问题是什么”。

8. 与项目的关系

  • 如果你的应用要完成任务(不只是回答问题),先写出它的”表单”:要收集哪些信息、哪些只在某些情况下需要、怎样校验、执行什么动作、执行前要不要确认。这份规格就是你和领域专家讨论的基础。
  • 区分”可以交给 LLM 的”(理解用户的各种说法、把结果说成话)和”必须由程序保证的”(规则、确认、调用 API 的参数、只能报告查到的结果)。
  • 评估一定要有真实的用户(或者至少是会”不按套路出牌”的模拟用户)。按”愉快的路径”写的测试集,几乎任何系统都能通过。
  • 按轮次统计你的智能体的准确率:如果随对话变长而下降,说明它依赖越来越长的上下文——考虑形式化的对话状态。

9. 练习

练习 1(写规格:数据依赖的字段)。选课助手要求:国际学生还要回答”是否需要 CPT(课程实习许可)“;如果需要,还要填写实习单位的名称。在 genie.py 的 STUDENT 工作表里加上这两个字段。运行时要改吗?对话树要改什么?

参考答案

只需要在规格里加两行:

Field("needs_cpt", "bool", "Does the student need Curricular Practical Training?",
      ask_if=lambda rec: rec.values.get("international") is True, question="Do you need CPT for an internship?"),
Field("cpt_employer", "str", "Name of the CPT employer",
      ask_if=lambda rec: rec.values.get("needs_cpt") is True, question="Which company is the internship with?"),

运行时(GenieAgent.policy)不用改:Record.missing() 已经会考虑 ask_if,按顺序问还没填、而且现在需要问的字段。模拟用户需要知道怎样回答这两个问题(在 SimUser.want 和 utter 里加上)。对话树则要改流程本身:在步骤列表里插入两步,并为”不是国际学生""不需要 CPT”两种情况写跳过的逻辑——每加一个条件,分支就多一层。这正是声明式规格的好处:开发者说”要什么”,不说”怎样问”。

练习 2(动手改代码:两个机制)。在 genie.py 的 PARAMS 里,把 fc_follow_decay 改成 0(函数调用的 LLM 不再随轮次变差)、把 fc_hallucinate 改成 0(不再编),分别和同时运行 03 号文件。函数调用的 LLM 的任务完成率、对话动作准确率怎样变化?这说明了什么?

参考答案

实测(100 位真实的模拟用户;任务完成率 / 对话动作准确率 / 平均轮数):默认 69% / 62% / 18.5;只去掉”随轮次变差” 79% / 94% / 16.2;只去掉”编” 77% / 67% / 16.8;两个都去掉 97% / 97% / 13.5——和 Genie(97% / 99% / 13.8)几乎一样。

这说明模拟里两种做法的差距完全来自这两个机制:长对话里不守规矩、知识查询之后编造。真实的 LLM 是否有这两个问题、有多严重,是一个实验问题——论文的真实用户研究回答了它(DA 下降 43%,7/10 的选课对话出现幻觉)。Genie 的价值在于:不依赖 LLM 自己守规矩——下一步做什么由程序决定,回复只能来自智能体动作,知识查询的结果原样报告。

练习 3(动手改代码:确认的作用)。把 COURSE 工作表的 confirm 改成 False(不确认就直接选课),在默认的解析错误率(6%)和 20% 下运行 Genie。任务完成率怎样变化?

参考答案

实测(Genie 的任务完成率):有确认时,解析错误率 6% 是 97%、20% 是 95%;去掉确认,6% 时降到 87%、20% 时降到 71%。确认是对付解析错误的关键防线:解析器听错了学分、听反了评分方式,确认时用户会说”不对,是 4 学分”,运行时更新状态、重新确认。去掉确认,听错的值就直接提交了。(去掉确认后对话动作准确率也降到 79%,这是因为本讲的评判规则仍然按”执行前必须确认”这条政策打分。)论文的说法:“所有有副作用的动作执行前都要确认”——这让用户可以在下一轮纠正。

练习 4(思考:为什么 WOZ 数据集不够)。STARv2 上 Genie 比微调的 AnyTOD 高很多,幻灯片却说”WOZ 基准不现实、对 LLM 太简单、标注比 LLM 的输出还差”。结合代码 03 的演示 1,说说”愉快的路径”上的评估会误导我们什么?一个好的任务型智能体评估应该包括什么?

参考思路

“愉快的路径”上,对话树、函数调用的 LLM、Genie 都接近 100%——它测不出最关键的能力:处理用户的提问、改主意、拒绝、长对话里一直守规矩、不编。更糟的是,WOZ 数据里的”智能体”是人扮的,标注又有错,模型和标注不一致时,很难说是谁错了(“LLM 跑赢了传统的 NLP 评估”)。好的评估应该:(1) 用真实的用户、真实的应用(或者至少是有各种不愉快行为的模拟用户);(2) 逐轮检查多个指标(解析、执行、是否遵守政策),而不只是最后的任务完成率;(3) 按轮次分析,看长对话里会不会变差;(4) 统计幻觉;(5) 人工检查,因为自动指标和标注都可能有问题(第 5、7、8 讲反复出现的教训)。

练习 5(思考:Propose 动作)。本讲的代码没有实现 Propose(提议一个新的任务或查询)。举一个选课助手里适合用 Propose 的场景,说说运行时应该在什么条件下提议、提议之后用户拒绝了怎么办。

参考思路

例如:第一门课选完,学生的方向要求”广度要求还差一个领域”——运行时查到这一点,提议”您还需要一门人机交互方向的课来满足广度要求,要不要看看有哪些?“(Propose 一个知识查询);或者课满了,提议”要不要我帮您找同一时间段的类似课程?“。条件应该由开发者写在规格里(某个字段的值、某个查询的结果触发),而不是让 LLM 自由发挥——否则又回到了”不可控”。用户拒绝时,把这次提议记在对话状态里(例如一条”已拒绝”的记录),之后不再重复提议;这也是形式化的对话状态的好处——“用户已经拒绝过”是一个明确的事实,而不是埋在长长的对话历史里。


10. 延伸阅读

课程相关

  • Joshi、Liu、Chen、Weigle、Lam. Controllable and Reliable Knowledge-Intensive Task-Oriented Conversational Agents with Declarative Genie Worksheets. ACL 2025. arXiv 2407.05674. 代码:github.com/stanford-oval/genie-worksheets;网站:ws.genie.stanford.edu
  • Moradshahi 等. X-RiSAWOZ: High-Quality End-to-End Multilingual Dialogue Datasets and Few-shot Agents. Findings of ACL 2023.
  • Mosig、Mehri、Kober. STAR: A Schema-Guided Dialog Dataset for Transfer Learning. 2020.
  • Zhao 等. AnyTOD: A Programmable Task-Oriented Dialog System. EMNLP 2023.
  • Budzianowski 等. MultiWOZ — A Large-Scale Multi-Domain Wizard-of-Oz Dataset for Task-Oriented Dialogue Modelling. EMNLP 2018.

背景

  • Rebedea 等. NeMo Guardrails: A Toolkit for Controllable and Safe LLM Applications with Programmable Rails. EMNLP 2023 Demo.
  • 加拿大航空聊天机器人案(Moffatt v. Air Canada, 2024 BCCRT 149)的报道。

11. 下一讲预告

第 9 讲在一大批长文档上做深度研究:把文本变成数据库,再回答问题。如果知识本来就在一张很大的数据库里——例如 160 万行的武装冲突事件——而用户的问题是开放式的(“佩特罗的’全面和平’政策对哥伦比亚的暴力有什么影响?”),没有一条 SQL 能直接回答呢?第 11 讲讲 DataSTORM:

  • 探索性数据分析(EDA)和数据叙事(data storytelling)的原则;
  • 把”在结构化数据上做深度研究”重新表述为一个以论点驱动的分析过程:从数据里发现候选的论点,通过反复的、跨来源的调查验证它,再发展成一个连贯的分析叙事;
  • 规划者—执行者的分工、自下而上的统计摘要、查询一致性检测、论点的生成与修正;
  • 怎样评估”洞见”:InsightBench、ACLED 数据集、和 OpenAI Deep Research 的比较、新闻工作者的人工评估。
← 返回课程目录