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的识图功能,让它生成最初始的版本,再在其上修改。
思考题
请使用这节课介绍的技术,在其他场景中展开模型。
欢迎你在留言区分享自己的思考或疑惑,我们会把精彩内容置顶供大家学习讨论。
- 李威 👍(2) 💬(1)
请教老师:对于一个复杂的软件系统有大量的领域模型,所有的领域模型及其他们之间的关系我都用mermaid格式编写好,并添加相应的注释,但是最终生成的文本超过了LLM可接受最大字数限制,我譔怎么办呢? 当然我可以根据限界上下文或者功能模块将领域模型进行拆分,每次只为LLM提供部分领域模型的半结构化自然语言描述文本,这样可以让LLM针对部分业务需求为我提供相关的辅助。 还有一种办法是每次为LLM提供部分领域模型的半结构化自然语言描述文本,然后让其先总结一把,之后再输入另一部分的领域模型,继续让其总结以压缩文本内容。但是我试了一下发现,针对这种领域模型的半结构化自然语言的描述文本,LLM一总结就把重要的领域概念直接给总结没了,下次直接使用LLM总结后的文本重新发起一轮新的聊天对话,他就完全不知道自己在说什么了。 所以,请教老师,如何突破LLM对字数的限制,将大量的领域知识一把喂给LLM?
2024-03-26 - 一只豆 👍(1) 💬(2)
有个很模糊的直觉性感触:这两讲中的业务模型好像是比较 E-R 样子的,好像偏重于显性知识的核心脉络全写出来。看了编辑推荐的 《创造知识的企业》后,特别是SECI 模型,我在想 未来的模型是不是 不一定停留在显性知识范畴,而是从人类直接提取不可言说知识后形成的模型。所以我的问题是:我的推论是否合理?哪里偏差了?如果存在这种新模型,LLM 如何辅助我们展开,并增强业务理解?
2024-03-25 - 术子米德 👍(0) 💬(4)
08 | 使用LLM辅助业务理解 🤔☕️🤔☕️🤔 【R】Mermaid(🧜🏻♀️),用它来描述业务模型,能绘制成示意图,人瞄一眼就懂,LLM也能读懂,这样就双赢。 半结构化自然语言(即:写注释),一方面,作为自然语言的结构化补充,另一方面,作为结构化语言的自然补充,这样就双边补充、双边互通。 【.I.】之前,我敲代码,敲的时候,我Clear,跑一下发现不对,那就转到调试,调的时候,我到处打断点,待程序跑到那里,我停下来看看,我大概率是Complex、小概率是Chaotic。无论怎样,我总能一点点来,喝点水、走走路、熬个夜、睡一觉、问一问,总能搞定。 【Q】如今,自然语言的描述、加上半结构化的注释、再加上增强半结构化的Mermaid,输出的内容有个三长两短,除了一遍又一遍尝试,我咋个“逐行调试”法? — by 术子米德@2024年3月25日
2024-03-26 - 范飞扬 👍(0) 💬(4)
神操作! 问个细微的问题,请教一下老师和各位同学的经验: 对于比较庞大的领域模型,画图的方式和顺序有什么经验嘛?比如,应该采用以下哪种方式呢? 1、先用draw.io等类似工具画图,再让gpt生成 mermaid. (可能gpt看不懂?) 2、一开始就用mermaid来画图(可能有些没法用mermaid表达?或者不太灵活?) 3、迭代交织使用1和2。 4、还有更好的方式?
2024-03-25 - aoe 👍(2) 💬(0)
第二次学习,把示例中变量 {user_story}、{ac} 从 07 课中补充完整后询问 AI 获得了正常的答案 第一次学习时,直接粘贴了模板,AI 和我都懵了
2024-03-30 - 范飞扬 👍(1) 💬(0)
趁还没讲到测试驱动AI开发,我盲猜一下:生成 yaml 数据后,就可以用于编写 TDD的测试了,有了测试,“功能良好”的软件 就不是啥问题了。不过仅靠这些yaml,应该还没法保证“架构良好”?架构良好得靠CoT? 那CoT从哪来呢?直接复制粘贴架构的描述?(比如六边形架构的描述?)
2024-04-01 - 赫伯伯 👍(0) 💬(5)
所以,模型展开的用途是什么???
2024-04-10 - 范飞扬 👍(0) 💬(0)
和 chatGPT 的聊天:https://chat.openai.com/share/587f2e0f-53be-4fa0-8458-7f5658b30714
2024-04-04