08|使用LLM辅助业务理解

你好,我是徐昊,今天我们来继续学习 AI 时代的软件工程。

在上一节课,我们介绍了如何使用业务模型通过模型展开的方式,帮助我们理解业务。我们也谈到了,在使用模型展开的时候,我们处在庞杂的认知模式下。因此,提效的关键在于构造思维链,让 LLM 帮助我们更好地应用不可言说知识。

那么今天,我们就围绕之前的例子,看看如何通过 LLM 辅助我们理解不同的业务场景。

通过半结构化自然语言表示模型

当我们想让大语言模型(Large Language Model,LLM)帮助我们通过模型解释业务知识时,首先就会碰到一个问题,如何将我们的模型表达为大语言模型能够理解的形式。

其实这比想象中要容易得多,因为 LLM 不仅仅懂得自然语言,它还懂得各种编程语言或结构化描述语言。我们可以使用 Mermaid 描述我们的领域模型:

classDiagram
  Department "1" -- "*" Program 
  Department "1" -- "*" Offer 
  Offer  "1" -- "1" Program
  Program "1" -- "1" Curriculum 
  Curriculum "1" -- "*" Course 
  Student "1" -- "1" ProgramEnrollment
  ProgramEnrollment "1" -- "*" CourseEnrollment
  Student "1" -- "1" Offer
  ProgramEnrollment "1" -- "1" Program
  CourseEnrollment "1" -- "1" Course 
  
  class Department {
  }
  class Program {
  }
  class Curriculum {
  }
  class Course {
  }
  class Student {
  }
  class Offer {
  }
  class ProgramEnrollment {
  }
  class CourseEnrollment {
  }

当我们把这段 Mermaid 录入 LLM,它会为我们提供它的理解:

其中大部分的内容都是正确的,只是不够准确。比如领域概念的名字,在 LLM 中的解读部分就是错误的。再比如,关联所代表的含义,也不甚准确。图里 Department、Program、Offer 三个对象间的意思就不对。

这时候,我们可以使用一个我发明的技巧,叫半结构化自然语言。所谓半结构化自然语言,就是在结构化的描述中混入自然语言去补充对应的上下文。说人话就是写注释。

那为什么要叫半结构化自然语言呢?因为在 LLM 的视角来看,结构化的信息和非结构化的自然语言一样重要。半结构化自然语言既可以看作以自然语言给予结构化数据补充,也可以看作结构化数据赋予自然语言结构。而从赋予自然语言结构的角度,就能够解锁更多对于 LLM 应用的巧思。

首先我们来解决一下命名的问题。在 Mermaid 中增加注释,并给出解释和例子:

classDiagram
  ...
  %% 学院
  class Department {
  }
  %% 教学计划
  %% 比如,计算机科学与技术学士学位教学计划,或是计算机科学与技术硕士学位教学计划
  class Program {
  }
  %% 教学大纲
  class Curriculum {
  }
  %% 教学课程
  class Course {
  }
  %% 学生
  class Student {
  }
  %% 录取通知
  %% 通知学生被那个教学计划录取,比如张三录取为学士学位学生
  class Offer {
  }
  %% 学籍
  %% 根据录取通知将学籍注册到指定的教学计划,比如,张三根据录取通知注册为2023年入学的计算机科学与技术学士学位教学计划学生
  class ProgramEnrollment {
  }
  %% 选课
  %% 在学籍有效期内,需要根据教学大纲选课
  class CourseEnrollment {
  }

这就是半结构化自然语言为什么会被称作半结构化自然语言。我们通过注释,实际上使用了少样本迁移学习(Few Shots Example),在一个小范围的上下文中,给 LLM 提供了更为具体的迁移指引。

接下来我们用同样的方法来处理关联关系。通过 Mermaid 的语法,标注关系之间方向和含义,并提供注释:

classDiagram
  Department "1" *-- "*" Program: 提供不同学位的教学计划 >
  Department "1" *-- "*" Offer: 为学生发出录取通知 >
  Offer "1" --> "1" Program: 录取通知针对某个学位 >
  Program "1" --> "1" Curriculum: 教学计划对应的教学大纲 >
  Curriculum "1" *--> "*" Course: 组成教学大纲的课程 >
  Student "1" --> "1" ProgramEnrollment: 学生登录的学籍 >
  ProgramEnrollment "1" *-- "*" CourseEnrollment: 在学籍有效期内,需要根据教学大纲选课 >
  Student "1" --> "1" Offer : 学生拿到的入学通知 >
  ProgramEnrollment "1" --> "1" Program: 录取通知中指定的教学计划 >
  CourseEnrollment "1" --> "1" Course: 选定的课程 >
  %% ProgramEnrollment根据Offer生成,表示学生已经到校注册
  
  ...

至此,我们可以看到 LLM 已经可以理解我们包含在模型中的业务知识了。

围绕业务上下文进行模型的展开

让我们再看一下上节课中模型展开之后的结果:

可以明显看到,我们的模型展开了两次。第一次是根据 Given 描述的场景,寻找样例数据,然后再用模型实例化解释这个数据。第二次是根据 When 的描述,引入了数据改变,然后再用模型实例化解释这个数据。

这是一个典型的知识生成(Generated Knowledge)场景。下面我来展示一下这个知识提取的过程。让我们先做一个提示词模板,然后先给出第一个任务,让 LLM 根据验收条件生成样例数据。

领域模型
======
```mermaid
{model}
```
用户故事
======
{user_story}
验收场景
======
{ac}
任务
===
数据都以yaml格式给出。
首先,请根据领域模型理解用户故事中的场景,并针对验收场景中Given的部分,给出样例数据。

我们看到此处的模型展开与图中得到的结果是一样的,并且 LLM 按照模型的指引,在当前的上下文中给出了为什么如此展开的解释。最后 LLM 按照要求以 YAML 的格式给出数据,便于我们进行数据处理与准备。我们可以改进任务,让 LLM 帮助我们生成后续的结果。

任务
===
数据都以yaml格式给出。
首先,请根据领域模型理解用户故事中的场景,并针对验收场景中Given的部分,给出样例数据。
然后,参看验收场景中When的部分,给出样例数据会产生怎样的改变。

这个结果基本是正确的,但是在注册的时候,LLM 认为应该连同课程一起注册了。这并不是我们希望的结果。

那么我们可以继续在半结构化自然语言中,包含一部分思维链的内容(Chain of Thought,CoT),也就是解释一下为什么注册和选课应该是分开的环节,并不应该合并。

classDiagram
  Department "1" *-- "*" Program: 提供不同学位的教学计划 >
  Department "1" *-- "*" Offer: 为学生发出录取通知 >
  Offer "1" --> "1" Program: 录取通知针对某个学位 >
  Program "1" --> "1" Curriculum: 教学计划对应的教学大纲 >
  Curriculum "1" --> "*" Course: 组成教学大纲的课程 >
  Student "1" --> "1" ProgramEnrollment: 学生登录的学籍 >
  ProgramEnrollment "1" --> "*" CourseEnrollment: 在学籍有效期内,需要根据教学大纲选课 >
  Student "1" --> "1" Offer : 学生拿到的入学通知 >
  ProgramEnrollment "1" --> "1" Program: 录取通知中指定的教学计划 >
  CourseEnrollment "1" --> "1" Course: 选定的课程 >
  %% ProgramEnrollment根据Offer生成,表示学生已经到校注册
  %% 向ProgramEnrollment中添加CourseEnrollment,表示学生选课。选课与注册是不同的流程。

通过在模型描述的注释中,引入部分思维链的内容,我们成功地指导了 LLM 按照模型与我们的期待,完成了模型展开的部分。

小结

到此为止,我们通过将模型转化为 Mermaid 格式,并将其转化为半结构化自然语言,指导 LLM 帮助我们完成了模型展开。这里有几个问题需要注意。

第一,通过 Mermaid 描述的类图,极大地简化了我们构造 CoT 的难度。 这是因为 Mermaid 描述的类图,本身就是对于抽象概念的表述。而 LLM 可以理解 Mermaid 中的内容,这样 LLM 会自然而然地使用 Mermaid 中的概念,做下一步分解映射的指引。这也是目前为止(2023 年 12 月),我们构造思维链最简单的方法。

第二,在 LLM 通过 Mermaid 构造的原始思维链中,LLM 会更多地将它映射到方案域。 所以需要我们通过半结构化自然语言的方式,以问题域的角度,对思维链进行标注。也就是,通过注释给予更多的上下文信息,并且在 Mermaid 允许提供额外信息的地方,提供自然语言的说明。

第三,由于我们使用的是类图,一些隐含的关系需要通过额外的方式补充。 当然,如果我们愿意,还可以逐步引入关键逻辑的时序图,进一步帮助 LLM 理解业务上下文。但是,以我的经验,大部分时候,一些简单的补充就已经足够了。

最后,如果你不会写 Mermaid 或是别的结果描述,可以使用 ChatGPT-4 的识图功能,让它生成最初始的版本,再在其上修改。

思考题

请使用这节课介绍的技术,在其他场景中展开模型。

欢迎你在留言区分享自己的思考或疑惑,我们会把精彩内容置顶供大家学习讨论。