面向对象第八次实验指导书

实验仓库

公共信息发布: exp_8

个人仓库:oo_homework_2025/homework_2025_你的学号_exp_8

请同学们作答完成后,将 md 文件与 json 文件提交到个人仓库,并将需要提交的md文件内容填入内容提交区,再在本页面下方选择对应的 commit,最后点击最下方的按钮进行提交。详细的提交过程请参见_实验结果提交_章节。

实验说明

本实验需要大量使用大语言模型,你可以自由选择任意大语言模型完成你的实验。

实验各个阶段的输入设计请参考“LLM提示方法指导”一节以及oolens推送,助教会检查输入设计的合理性。不要完全照抄示例的Prompt

实验目标

  • 体会大语言模型(LLM)在长文本情景下正向建模的能力。

  • 通过分阶段生成类与关系,理解LLM建模中问题分解(Question Decomposition)的重要性。

  • 理解并掌握设计高效Prompt与Chain-of-Thought(COT)的关键技巧。

实验情景

题目情景

1
2
3
4
5
一个城市正在使用公交运输管理系统(BTMS)来简化与城市相关的日常活动,以下是BTMS有关的功能介绍
BTMS负责管理城市的公交线路分配和运营,知晓所有公交车、司机、公交线路、公交站点的信息。每辆公交车具有唯一标识的车牌号、车辆类型、最大载客量等基本信息,其中车辆类型包括燃油公交车和电动公交车,燃油公交车需要记录油量,电动公交车需要记录电量。BTMS记录每位司机的姓名、性别、年龄并自动为每个司机分配一个唯一的ID。公交线路由固定的首末站、中途站点构成,并假设城市内任意两站点间的行驶路线唯一。BTMS会记录每个公交站点的名称和地理位置信息。公交线路由BTMS确定的唯一数字编号标识。公交线路编号的数字范围是0-9999,而车牌号码的长度固定为由数字和大写英文字母组成的8个字符。
BTMS会提前一年为公交路线分配公交车。每天可能会有几辆公共汽车被分配到一条路线。每辆巴士每天最多服务一条路线,但可能会在不同的日子分配到不同的路线。每条公交路线都有三个班次:早班、下午班和夜班。在特定的一天,BTMS会为特定的公交车分配一名司机。BTMS为城市工作人员提供了极大的灵活性,即公交车司机每天轮班次数没有限制,最多一天可以为公交车司机分配两个班次。
BTMS支持增删改查公交车和司机的信息。然而,由于BTMS提前一年就规划好了路线表,如果司机师傅请病假或公交车正在维修,那么就无法安排司机或为公交车分配路线,原计划的路线安排就要临时取消。
对于给定的一天,BTMS需要给出一张车次表,每一表项具备唯一ID,内容包括日期、路线编号、指定公交车的车牌号、班次、发车时间、指定司机的ID和姓名以及路线状态(正常/取消)。BTMS可以通过查询得知途径每个站点的路线编号。BTMS可以查询每个司机今日的状态以及分配的公交车和班次,也可以查询每辆公交车今日的状态和分配的司机和班次。

任务要求

按照题目情景描述的需求,设计出符合情景的类图,只需要包括类、成员属性、关系(关联、实现、泛化)可以使用大语言模型帮助生成

格式要求:

为方便评测,需要将回答统一成以下格式:

(1) 对于每个类和属性,请固定使用对应格式:

  • 枚举类枚举类名(枚举项1名称, 枚举项2名称,......)

  • 接口interface 接口名()

  • 一般类和成员属性类名(属性1类型: 属性1名称, 属性2类型: 属性2名称, ......)

  • 抽象类abstract 类名(属性1类型: 属性1名称, 属性2类型: 属性2名称, ......)

(2) 对于每个关系,请固定使用对应格式,其中()内表示可选项,*用于表示1对多关系:

  • 关联类A名 associates (*)类B名,表示类A关联了类B(A的一个成员类型是B)
  • 实现类A名 implements 接口B名,表示类A实现了接口B
  • 泛化类A名 extends 类B名,表示子类A继承了父类B

(3) 提交最终答案的输出格式以json格式给出,参考如下:

1
{ "Enumeration": [ "Enum1(ONE, TWO, THREE)" ], "Class": [ "Class1(int: attribute1, Class2: attribute2)", "Class2(Enum1: attribute3, List<Class3>: attribute4)", "Class3(int: attribute5)" ], "Relationship": [ "Class1 associates *Class2", "Class2 associates Enum1", "Class2 extends Class3" ] }

为了方便建模,以下属性类型不需要额外定义类:

  • 基本数据类型(int, char, boolean, double等)
  • 引用数据类型(String, List<>, Map<>等)
  • 表示时间的数据类型(日期:LocalDate,时间:LocalTime)

实验步骤

实验1:直接建模

请尝试直接将完整的题目情景、任务要求、格式要求复制粘贴给大模型输入,不添加任何额外的提示词

1
2
3
[题目情景] 一个城市正在使用公交运输管理系统(BTMS)……
[任务要求] 按照题目情景描述的需求,……
[格式要求] 为方便评测,需要将回答统一成以下格式:……

观察模型输出结果并思考:

  • 类的命名是否清晰?成员属性的类型是否合理?

  • LLM是否遗漏关键类或属性?(有没有主类?)

  • LLM是否构建了冗余的类或属性?

  • 定义的枚举类、抽象类、接口类是否有合理性?

  • 类之间的关系是否合理?是否有遗漏的关系?

请将LLM的输入输出保存至template.md的相应位置。

实验2:分阶段建模

首先让我们回顾一下我们人类在正向建模中的思考过程是什么样的呢?一般来说,我们会先从需求中抽象提取出对象,确定这些对象包含的属性和方法,再把这些对象包装成,然后分析并建立类之间的关系。因此我们很自然的想到,如果想要提升大语言模型的建模能力,可以让模型按照人类的思考方式来执行。本实验也需要你分三阶段利用LLM完成类图的设计:

阶段1:初步分析需求

让LLM从情景中理解需求,识别出关键对象,并抽象成类。

首先我们希望LLM利用其强大的上下文信息捕捉能力,抽象出关键的对象,并提炼相关的属性,包装成类。

我们需要告诉LLM:

  1. 你的任务是什么:从情景中完成需求分析并抽象出类
  2. 任务提示:任务的关键要求有哪些?需要抽象出哪些层次行为?类的成员属性可能有哪些?
  3. 情景描述

注意,这一阶段我们不着急让模型按照规定格式直接输出类图,因为在面向对象的建模中,从需求中识别类是一项至关重要的任务,对后续步骤有深远的影响,而提前固定输出形式可能会限制模型的思考。

请参考“LLM提示方法指导”中的“ROSES设计”完成这一阶段的模型输入设计,将阶段1 LLM的输入输出保存至template.md的相应位置。

阶段2:提炼类

让LLM回顾阶段1的总结,重新审核并按输出格式提炼类。

如何让AI在生成结果后,能够像人类一样进行自我审视和改进,从而提升输出质量,成为了AI研究者们关注的焦点。而反思模式,正是为了解决这一问题而应运而生。我们希望模型通过反思机制自我识别问题,并给出修改和优化。

我们需要告诉LLM:

  1. 你的任务是什么:反思并按格式输出类及属性
  2. (可选项)明确指出回答中出现的问题
  3. 任务提示:从哪些角度进行反思?核心判断标准是什么?(准确性/完整性/必要性)
  4. 格式要求

在这一阶段我们需要LLM反思自己的答案,并且按照我们要求的格式给出回答。

请参考“LLM提示方法指导”中的“ROSES设计”完成这一阶段的模型输入设计,并对比实验1的类图结果,分析分阶段提问效果是否更好?将阶段2 LLM的输入输出保存至template.md的相应位置。

阶段3:提取关系

完成了类的提取之后,接下来我们要完成类之间关系的提取。我们推荐将“提取关系”这一大任务拆分成“提取xx关系”等几个子任务,针对不同关系设计不同的输入。

在生成类的时候,你可能已经体会到了模型反思的重要性,同样我们希望模型在提取关系时也能自我反思。这次我们采取设计思维链(Chain of Thought,COT)的方法完成模型自反思。

抽象的讲,我们可以这样提问LLM:

  1. 明确任务要求:要求模型寻找xx关系
  2. (可选项)提示模型什么是xx关系
  3. 思维链提示:(示例)
    • step 1: 初步寻找xx关系
    • step 2: 检查找到的关系是否存在问题
    • step3: 修改并完善结果
    • step4: 按格式要求输出结果
  4. 格式要求
  5. (可选项)完整的情景描述和阶段1得到的类图结果

请参考“LLM提示方法指导”中的“COT设计”完成关联关系提炼的模型输入设计,并对比实验1的关系结果,分析利用COT提取关联关系的效果是否更好?请将阶段3 LLM的输入输出保存至template.md的相应位置。

注意,阶段2需要提交的结果只有关联关系的提炼过程,但你应当完成提炼其他关系的对话,以完成最终结果的提交。

实验结果提交

请将阶段1、2和3得到的类图结果汇总,按照原问题的输出格式提交answer.json文件。

1
{ "Enumeration": [ "枚举类1(枚举项1, 枚举项2, 枚举项3)" ], "Class": [ "类1(类型1: 属性1, 类型2: 属性2)" ], "Relationship": [ "类1 关系名 类2", "类1 关系名 *类2" ] }

同时,按照仓库中template.md的格式,将template.md中的部分内容替换成与大模型对话的结果,并在开头填写上使用的大模型名称:

1
> 使用的大模型是:*填写使用的大模型名称,如 deepseek-r1, GPT-4o等* # 实验1输入 (此处粘贴与大模型对话的原输入) # 实验1输出 (此处粘贴与大模型对话的原输出) # 实验2阶段1输入 (此处粘贴与大模型对话的原输入) # 实验2阶段1输出 (此处粘贴与大模型对话的原输出) # 实验2阶段2输入 (此处粘贴与大模型对话的原输入) # 实验2阶段2输出 (此处粘贴与大模型对话的原输出) # 实验2阶段3输入 (此处粘贴与大模型对话的原输入) # 实验2阶段3输出 (此处粘贴与大模型对话的原输出)

请将实验1和实验2的相关结果template.mdanswer.json一起提交到个人仓库下,并将template.md中的内容填入内容提交区

LLM提示方法指导

什么是Prompt

Prompt是指在大语言模型应用中,用简单的“提示词”来唤醒模型以解决特定任务的提问方式。简单来说,prompt就是一把钥匙,可以引导模型从预训练的海量信息中捕捉到能满足用户需求的信息,可以显著提升模型理解复杂文本、提取信息、逻辑推理、总结结论等能力。设计优质的prompt对利用好大语言模型意义重大。

prompt的基本要素包括:

  • 指令:指定模型需要完成的任务
  • 上下文:额外信息,引导LLM更好响应任务
  • 输入数据:用户的问题或内容
  • 输出指示:输出格式或规范

为什么需要Prompt

用户需求的多样性推动了prompt的广泛应用,涉及信息获取、内容创作和问题解答等多个方面。通过设计有效的prompt,用户能够快速获取所需信息,提升工作效率,减少反复试错的过程。

针对具体的情景我们需要设计不同的prompt,以下推荐一些简单好用的prompt设计框架:

RTF框架

RTF(Role-Task-Format)框架是一个非常简单通用的提示框架,其基本思想是让LLM担当某一角色(程序员、研究员、算法工程师等等),让模型能够快速响应相关领域的问答。适用于明确角色、任务、格式的简单任务。

  • Role:指定大模型担当的角色
  • Task:告诉大模型任务定义和要求
  • Format:定义大模型返回回答的格式

例如:

1
2
3
4
5
6
[Role] 你是一位资深市场分析师。
[Task] 分析当前新能源汽车行业的市场趋势,重点包括技术发展、竞争对手动态和消费者偏好变化。
[Format] 输出一份结构化报告,包含以下部分:
1. 标题:清晰概括主题;
2. 关键趋势(分点列出技术、竞争、消费三方面);
3. 结论与建议(不超过200字)。

ROSES框架

ROSES框架在RTF框架的基础上将输入细分为5个核心部分,以确保清晰、有目的的交互。ROSES在明确角色和目标的基础上,更强调场景和解决方案。

  • Role:指定大模型担当的角色
  • Objective:描述想要实现的目标或想要完成的任务
  • Scenario:提供与请求相关的背景信息或上下文
  • Expected Solution:描述期望解决方案或结果
  • Steps:询问实现问题的具体方法或步骤

例如:

1
2
3
4
5
6
7
8
9
[Role] 你是某科技公司的公关经理。
[Objective] 为即将发布的智能手表撰写一篇吸引投资人和媒体的演讲稿。
[Scenario] 发布会面向投资者、科技媒体和潜在消费者,需突出产品创新性和市场潜力。
[Expected Output] 一篇800字左右的演讲稿,包含开场白、产品亮点、技术参数、市场定位和结尾呼吁。
[Steps]
1. 用故事或数据开场,引起听众兴趣;
2. 分模块介绍核心功能(健康监测、续航能力、设计美学);
3. 引用第三方机构的市场预测数据;
4. 结尾强调品牌愿景,呼吁合作。

COT模式

COT(Chain of Thought)模式适合分析型逻辑推理型或分析型任务,可以很好的改善大模型的推理能力,在一些决策步骤中能发挥高效作用。我们需要提供情景下模型思考问题或解决问题的步骤样例,引导模型形成一个完整的推理逻辑链,并在输入的最后加上“让我们逐步思考”,这样完成了COT的设计。

例如如下问题场景:

1
2
问题:甲从A地以5km/h速度出发,乙1小时后从B地以7km/h速度出发,AB两地相距20km。问:乙需要多久追上甲?  
要求:分步骤给出解题过程,最后用公式总结答案。

可以给模型如下示例:

1
2
3
4
步骤1:设乙出发后经过t小时追上甲,则甲的行驶时间为(t+1)小时。  
步骤2:甲行驶距离 = 5*(t+1),乙行驶距离 = 7*t。
步骤3:追上时两人距离相等:5*(t+1) + 20 = 7*t → 5t + 5 + 20 = 7t → 2t = 25 → t=12.5小时。
答案:乙需12.5小时追上甲。

这样就能引导模型按照示例提供的逻辑链进行思考,给出完整的推理过程。

其他框架

其他常用的prompt框架还有诸如SAGESCOPERISEN等,同时prompt还有一些关键方法,例如零样本提示(Zero-shot)或少样本提示(Few-shot),同学们可以自行学习并在日常与大模型的交流对话中使用。

使用示例

理论学习之后少不了实战,下面举一个来自课堂的例子:

1
2
设出租车的状态有四种:服务状态(把乘客送往目的地过程中所处的状态),接单状态(被派遣了乘客请求后,去接乘客过程中所处的状态),等待服务状态(无服务可接单的空车运行状态)和停止服务状态(无服务、不接单)。出租车在等待服务状态时可以获得派单,从而变成接单状态,一旦接到乘客,即变为服务状态。出租车只能从等待服务状态变为停止服务状态。
系统一旦收到乘客的叫车请求,会设置一个抢单时间窗口,在时间窗口内系统向处于等待服务状态的出租车广播发送乘客的叫车请求。系统同时最多向一个出租车发送三个叫车请求。在抢单时间窗口关闭时,系统在抢单的出租车中,随机选择一辆派单。如果没有出租车抢单,则系统提示用户无出租车响应。一辆出租车可以对广播收到的请求进行抢单,但每辆车最多只能被选中并指派一单。

首先为了提取类,我们采用ROSES模版向大模型提问:

1
2
3
4
5
6
7
8
9
[Role]你是一个面向对象设计专家,擅长从业务场景中识别核心实体并构建对象模型。
[Objective]我希望你根据给定的情景描述,精准提取出系统中的核心类、成员属性。情景如下:
[Scenario] **情景**
[Expected Output]请你准确抽象出系统中的核心类和成员属性。
[Steps]你可以参考以下步骤:
1. 通读情景描述,识别核心业务实体对象
2. 按照对象共性的多少对实体进行分组,以抽象出分析模型中的实体类
3. 从描述中分析实体类的属性,不要使用程序化的语言精确定义属性和属性的类型
4. 如果发现复杂属性,则把这个属性抽象成为一个独立的类分离出去

接着为了总结类之间的关系,我们采用COT模版向大模型提问(关联关系和聚合关系):

1
2
3
4
5
6
7
8
9
10
11
12
你是一名资深面向对象设计专家,擅长分析类之间的关系。你需要结合之前的出租车派单系统需求说明和你提炼出的类,分析类之间的UML类图关系。你只需要考虑关联关系和聚合关系。你可以参考以下步骤完成:
步骤1:基于之前提供给你的&lt;{描述}&gt;和你分析出的&lt;{类列表}&gt;,按格式列出所有关联关系:[类1] associates (*)[类2]。其中()内*是可选项,表示1对多关系。
步骤2:语义检查,删除冗余的双向关联(无需展示结果)
步骤3:基于之前提供给你的&lt;{描述}&gt;和你分析出的&lt;{类列表}&gt;,按格式列出所有聚合关系:[类1] aggregates (*)[类2]。其中()内*是可选项,表示1对多关系。
步骤4:派生关系识别,识别可能的派生关系(无需展示结果)
步骤5:删除派生关系,移除步骤4发现的关系(无需展示结果)
步骤6:按照规定的格式输出经过校验的关系。展示格式:
[类1] associates (*)[类2]
[类3] aggregates (*)[类4]
......
下面给出题目情景:**情景**
让我们逐步思考,请给出你总结的关系结果。

写到最后

本次实验目的并不是希望教大家怎么用大模型,而是希望引导大家更高效、更智慧的运用大模型。在这个过程中,我们不是简单地把任务要求抛给大模型,而是希望通过一些设计,引导大模型获得更好的结果,这就需要同学本身对正向建模设计有一定的理解,不然只会适得其反。

目前也有研究表明似乎LLM建模的思路与人类思路是不完全一样的,或许本次实验中使用Prompt的效果还不如直接生成,但设计Prompt引导大模型完成任务的方法已经在很多领域得到了验证。即使抛开UML建模的设计,我们也可以在其他场景中尝试设计更好的提示来提升提问效果。

本学期OO最后一次实验也落下帷幕,回归了面向对象的设计,也拥抱了大模型,希望能对同学们有所帮助!