软工III迭代二文档

软工三迭代二设计文档

撰写人员:吴俊宏、戴冯洋、顾益铭

项目启动文档

项目名称

RAGQuest:基于 RAG 的智能问答系统。

Prompt 评估平台:用于基于 RAGAS 框架,对检索增强生成(RAG)系统的回答质量进行自动化评估,支持多个关键指标的综合测量。

项目背景

随着大语言模型(LLM)的广泛应用,基于检索增强生成(RAG, Retrieval-Augmented Generation)的问答系统逐渐成为实现企业级智能问答的重要方案。该项目旨在构建一个结合语义向量检索与大模型生成能力的智能问答平台,满足用户自然语言提问、信息查找等需求。

项目目标

搭建一个完整的 RAG 问答系统原型,支持知识库导入、模糊检索、上下文问答等功能。

支持用户注册、登录,进行个性化问答管理。

实现问答记录、自动标题生成、Zhipu 大模型调用等功能。

后端提供 RESTful 接口,便于前端集成展示。

为后续应用中部署提供参考框架。

开发一个用于评估 RAG 系统性能的综合性平台,支持多版本迭代管理、自动化评估和可视化分析。

项目范围

包含的内容:

  • 用户系统(注册、登录、认证)。

  • 聊天记录管理模块。

  • 向量知识库构建与检索。

  • 大模型问答模块(调用智谱AI接口)。

  • 文本预处理和知识切块服务。

  • 系统原型后端框架(基于Spring Boot)。

不包含的内容:

  • 复杂的权限控制或多租户架构。

  • 大规模并发支持。

项目里程碑及时间表

里程碑 完成时间
项目初始化、环境搭建等准备工作 3月20日
模块划分与数据库设计 3月25日
用户系统开发完成 4月1日
聊天功能实现 4月8日
知识库导入与检索实现 4月15日
模型调用与问答整合 4月20日
项目测试与文档撰写 4月25日

资源概览和任务分配

任务模块 工具/资源
项目初始化与 SpringBoot 搭建 Java, maven, IDEA
数据库与 pgvector 配置 PostgreSQL, pg_trgm
用户系统开发 Spring Security
问答服务与模型调用 ZhipuAI API, OkHttp
知识导入与切块 PDFBox, Lucene 分词
模糊搜索与 RAG 整合 SQL, 向量搜索
学号 姓名 职责
221250142 顾益铭 前端开发
221870148 周屿杨 后端开发
221250181 李俊材 后端开发
221250107 马俊淇 项目测试
221250046 戴冯洋 文档
221250134 吴俊宏 文档

沟通计划

每周定期会议:每周一进行 30 分钟会议,讨论进展与问题。

日常沟通工具:QQ、腾讯会议。

代码协作平台:GitLab 私有仓库。

文档协作:飞书文档工具。

需求规格说明书

引言

本项目旨在开发一个基于 RAG(Retrieval-Augmented Generation)技术的智能问答系统,名为“RagQuest”。该系统结合了语义搜索与大语言模型生成能力,能够基于知识库中的文档内容进行高质量的问答对话,适用于企业知识管理、教育培训、自助客服等场景。

本说明书将详细描述系统的功能性和非功能性需求,分析主要涉众,列出关键用例,并为后续的系统设计与开发提供需求依据。

总体描述

系统概览

RagQuest 系统由以下核心组件构成:

  • 用户系统:提供用户注册、登录与认证功能。
  • 聊天服务模块:支持用户基于知识库进行问答对话,保存问答记录。
  • 知识导入与处理模块:支持上传文档、文本切块、向量化与存入数据库。
  • 模糊搜索模块:利用 pg_trgmpgvector 进行相似语义检索。
  • 大模型交互模块:对接 ZhipuAI 接口,生成回答与会话标题。
  • 管理与存储:基于 PostgreSQL 数据库存储用户数据、知识片段、对话记录等。

系统整体采用前后端分离架构,后端基于 SpringBoot 实现,前端可独立拓展。

评估平台功能概述:

  • API 连接测试:在正式评估前,验证 ZhipuAI 配置是否正确,避免因 API 问题导致评估中断。
  • API 概览:FastAPI 实现的 RESTful 接口,提供以下核心功能:
    • 迭代版本管理
    • RAG 评估执行
    • 评估结果查询与比较

风险管控

风险项 可能性 影响 应对措施
评估指标不准确 多轮验证测试
大数据量性能问题 分页加载+缓存
第三方 API 限制 备用模型方案

错误处理

HTTP 状态码 错误信息 可能原因
400 Invalid JSON format 上传的数据文件不是有效的 JSON
400 Invalid data format 数据缺少必要字段
404 Iteration not found 指定的迭代 ID 不存在
500 Failed to evaluate 评估过程中出现内部错误

迭代模型(Iteration

表名iterations

字段 类型 描述
id Integer 主键
name String(100) 迭代名称(必填)
description Text 迭代描述
created_at DateTime 创建时间(自动记录)

关系

  • evaluations:一对多关联到 Evaluation 模型。

评估模型(Evaluation

表名evaluations

字段 类型 描述
id Integer 主键
iteration_id Integer 外键关联到迭代(必填)
name String(100) 评估名称(必填)
description Text 评估描述
data Text 评估使用的原始数据(JSON 格式)
faithfulness Float 忠实度评分(0-1)
answer_relevancy Float 答案相关性评分(0-1)
context_recall Float 上下文召回率评分(0-1)
created_at DateTime 创建时间(自动记录)

关系

  • iteration:多对一关联到 Iteration 模型。

RagasMetrics

用于迭代比较的指标模型

字段 类型 描述
iteration_id int 迭代 ID
iteration_name str 迭代名称
faithfulness float 忠实度平均分
answer_relevancy float 答案相关性平均分
context_recall float 上下文召回率平均分

核心评估指标

指标名称 类型 评分范围 描述
faithfulness(忠实度) 生成质量 0-1 衡量答案与给定上下文的一致性程度,越高表示答案越忠实于上下文
answer_relevancy(答案相关性) 生成质量 0-1 评估答案与问题的相关程度,越高表示答案越切题
context_precision(上下文精确度) 检索质量 0-1 衡量检索到的上下文中相关部分的比例
context_recall(上下文召回率) 检索质量 0-1 评估系统检索到所有相关上下文的能力

评估执行流程:

  • 参数校验:检查输入数据长度一致性。

  • 模型初始化:

    • 使用智谱 AI GLM-4-Flash 作为 LLM。

    • 使用智谱 AI Embedding-3 作为嵌入模型。

  • 数据准备:将上下文列表转换为 "\n".join(ctx) 格式的参考文本。

  • 执行评估:使用RAGAS的 evaluate 函数计算四个核心指标。

数据验证规则

  • 字符串字段自动去除首尾空格。

  • 浮点数字段自动限制小数点精度。

  • 日期时间字段自动转换为ISO格式。

  • 所有请求字段都会进行类型验证。

主要依赖:

  • ragas:用于评估 RAG 任务的多指标评估框架。
  • datasets:用于处理和管理数据集。
  • ZhipuAI:调用 ZhipuAI 大模型进行辅助评估。

技术栈

  • 后端:Java + Spring Boot + JPA。
  • 数据库:PostgreSQL + pgvector + pg_trgm。
  • ONNX 模型推理:用于本地理解支持(如选配)。
  • 接口调用:ZhipuAI GLM-4-Flash。
  • 工具类库:Gson, OkHttp。

详细需求描述

RAG 应用涉众分析

涉众 描述 主要需求
项目开发者 系统设计与实现人员 模块可分、接口清晰、便于调试
普通用户 访问系统进行问答 问题响应快、界面友好、记录完整
知识提供者 上传/更新知识库 数据导入便捷、内容更新及时

RAG 应用功能性需求

功能需求 描述
用户注册与登录 支持用户名/手机号注册,密码加密存储
聊天管理 支持按用户保存会话、自动生成标题
提问与回答 用户输入问题,系统生成回答
知识导入 上传目录下 txt 文件自动切块、入库
相似匹配 使用 pg_trgm 和 pgvector 检索相关知识片段
会话历史查看 用户可查看所有问答内容
知识更新 知识可重复导入并更新

RAG 应用非功能性需求

需求类型 描述
性能 每次问答响应时间少于 5 秒
安全性 密码加密存储,用户身份验证
可扩展性 支持后续更换大模型接口或添加新模型
可维护性 模块职责清晰,便于维护与测试
可用性 具有良好的容错能力,不因单点失败崩溃

Prompt 评估平台功能性需求

迭代管理

  • 创建/查看迭代版本(名称、描述、时间)。
  • 迭代版本关联评估任务。

评估执行

  • 上传评估数据集(JSON 格式)。
  • 自动计算三大核心指标。

可视化分析

  • 多版本指标对比柱状图。
  • 单次评估雷达图分析。
  • 评估历史趋势图。

数据管理

  • 评估结果存储(SQLite)。
  • 原始数据版本控制。

Prompt 评估平台关键业务规则

规则编号 描述
BR001 每次评估必须关联到具体迭代版本
BR002 评估数据必须包含 questions/answers/contexts 字段
BR003 指标评分范围标准化为 0-1

Prompt 评估平台非功能性需求

质量属性

类型 要求 验收标准
性能 评估响应时间 < 30 s 95% 请求达标
可靠性 评估任务成功率 > 99% 错误重试机制
安全性 数据访问控制 RBAC 实现

技术约束

约束项 说明
C001 支持主流浏览器(Chrome/Firefox/Edge)
C002 评估数据集 < 5MB
C003 同时运行评估任务 ≤ 3个

关键用例描述

RAG应用

用例1:用户注册
  • 参与者:普通用户。

  • 前置条件:

    • 用户未在本系统注册过。

    • 用户拥有一个合法的手机号码。

  • 后置条件:系统中新建一个有效的用户账号,状态为“正常”。

  • 触发条件:用户打开注册页面并提交注册请求。

  • 主事件流程:

    • 用户在前端页面输入用户名、手机号、密码,并点击注册按钮。

    • 系统接收请求,首先根据用户名查询数据库,检查是否存在同名用户。

      • 若存在,抛出异常提示“Username is already in use”,注册流程终止。
    • 系统根据手机号查询数据库,检查是否存在同手机号用户。

      • 若存在,抛出异常提示“Phone number is already in use”,注册流程终止。
    • 系统使用加密模块(PasswordEncoder)对用户输入的密码进行加密处理。

    • 将用户名、手机号和加密后的密码封装为 UserPO对象并保存至数据库(通过 userRepository.save 方法)。

    • 系统返回注册成功响应,并生成对应的 UserVO 返回给前端。

  • 异常流程:

    • 输入的用户名已被占用 → 注册失败,提示“用户名已被使用”。

    • 输入的手机号已被注册 → 注册失败,提示“手机号已被使用”。

    • 系统内部错误(如数据库故障)→ 注册失败,提示“服务器错误”。

用例2:用户登录
  • 参与者:普通用户。

  • 前置条件:用户已经成功注册。

  • 后置条件:用户成功登录,获得访问授权。

  • 触发条件:用户打开登录页面并提交登录请求。

  • 主事件流程:

    • 用户输入用户名和密码,点击登录按钮。

    • 系统根据用户名查询用户信息(userRepository.findUserByUsername)。

      • 若无匹配用户,抛出异常提示“User not found”,登录流程终止。
    • 系统使用密码加密模块,验证输入密码与数据库中保存的加密密码是否匹配。

      • 若不匹配,抛出异常提示“Incorrect password”,登录流程终止。
  • 登录验证成功,系统封装用户信息为 UserVO 对象返回前端,供后续会话管理。

  • 异常流程:

    • 用户名输入错误(用户不存在) → 登录失败,提示“用户未找到”。

    • 密码输入错误 → 登录失败,提示“密码错误”。

    • 系统内部错误 → 登录失败,提示“服务器错误”。

用例3:用户提问并获取回答(RAG检索)
  • 参与者:普通用户。

  • 前置条件:

    • 用户已完成登录,拥有有效会话。
    • 系统内已有知识数据(数据库中有知识切块)。
  • 后置条件:系统返回与用户问题相关的回答。

  • 触发条件:用户在聊天窗口输入问题并提交。

  • 主事件流程:

    • 用户在前端界面输入问题文本(Prompt)并发送请求。

    • 系统调用 FuzzySearchService 模块,基于 pg_trgm 模糊匹配技术,从知识库中检索与问题最相关的知识块(Top-N 召回)。

    • 将检索到的知识内容与用户原问题一起打包成 Prompt。

    • 调用 ZhipuAIClient 模块,将 Prompt 发送到 ZhipuAI 大模型(glm-4-flash)。

    • 接收大模型返回的回答内容。

    • 调用 ChatService 模块,将用户问题和模型回答一起保存为一条聊天记录。

    • 系统将回答内容发送回前端页面,供用户查看。

  • 异常流程:

    • 检索不到相关知识 → 返回提示“未找到相关信息”,可选择直接调用模型进行自由问答。

    • 大模型接口调用失败 → 返回提示“当前服务不可用,请稍后再试”。

    • 系统内部错误(如数据库连接失败) → 返回统一错误提示。

用例4:导入知识到数据库
  • 参与者:系统管理员、开发者。

  • 前置条件:

    • 系统部署完成,数据库可用。

    • 指定的 data 文件夹存在文本格式的知识文件(.txt)。

  • 后置条件:知识文件被切块并存入数据库(PostgreSQL + pgvector)。

  • 触发条件:管理员启动应用并手动调用导入服务。

  • 主事件流程:

    • 管理员将知识文件(如常见问题、产品手册)放置到后端项目 /data 目录。

    • 启动 SpringBoot 应用,或者通过调用 KnowledgeImportService.importFromDirectoryByParagraphs(Path dataDir) 方法触发导入。

    • 系统读取每一个 .txt 文件,将其按段落(或者指定逻辑)切分成小块。

    • 使用文本向量化技术(如基于 ONNX 模型,或者其他 Embedding 方法)为每个知识块生成向量表示。

    • 将原文和向量存储到 PostgreSQL 数据库,供后续模糊检索或向量检索使用。

      系统输出导入完成日志,记录成功导入的知识数量。

  • 异常流程:

    • 未找到文件夹或文件为空 → 提示“未找到待导入的知识文件”。

    • 文件格式不正确(非 .txt 等) → 忽略并提示警告。

    • 数据库保存失败 → 记录错误日志并终止当前批次导入。

评估平台:

用例1:执行新版本评估
  • 前置条件:已创建迭代版本。

  • 主事件流程:

    • 系统显示上传表单。

    • 用户选择迭代版本。

    • 用户上传 JSON 数据文件。

    • 系统验证数据格式。

    • 系统执行 RAGAS 评估。

    • 系统保存评估结果。

    • 系统显示可视化报告。

  • 异常流程:

    • E1 数据格式错误 → 显示具体错误位置。

    • E2 评估超时 → 自动重试(最多3次)。

用例2:对比迭代版本
  • 触发条件:存在 ≥ 2 个迭代版本

  • 交互流程:

    • 用户进入比较页面。

    • 系统加载所有迭代列表。

    • 用户选择 2-4 个迭代版本。

    • 系统获取各版本最新评估。

    • 系统生成对比柱状图/雷达图。

    • 用户可查看详细指标差异。

用例3:查看评估趋势
  • 数据需求:至少 3 次历史评估。

  • 功能要点:

    • 系统自动按时间排序评估记录。

    • 生成四大指标的趋势折线图。

    • 支持时间范围筛选。

    • 可点击数据点查看详情。

项目设计文档

引言

编制目的

  • 本报告详细完成对 RagQuest 系统的详细设计,达到指导后续软件构造的目的,同时实现和测试人员以及用户的沟通。

  • 本报告面向开发人员、测试人员及最终用户而编写,是了解系统的导航。

产品概述

本项目旨在开发一个基于 RAG(Retrieval-Augmented Generation)技术的智能问答系统,名为“RagQuest”。该系统结合了语义搜索与大语言模型生成能力,能够基于知识库中的文档内容进行高质量的问答对话,适用于企业知识管理、教育培训、自助客服等场景。

RAG 架构图:

RAG 架构图

评估平台架构图:

评估平台架构图 1

评估平台架构图 2

体系结构设计概述

RAGAS 部分系统整体采用前后端分离架构,后端基于 SpringBoot 实现,前端采用 Vue 3 架构。

Evaluator 部分采用前后端分离架构,后端基于 FastAPI 实现,前端采用 Vue 3 架构。

结构视角

RAG 搭建过程

RAG 搭建过程

RAG 应用业务逻辑层的分解

开发包 依赖的开发包
com.nju.ragquest.config -
com.nju.ragquest.controller com.nju.ragquest.service, com.nju.ragquest.config
com.nju.ragquest.exception -
com.nju.ragquest.repository com.nju.ragquest.config
com.nju.ragquest.postgresRepository com.nju.ragquest.config
com.nju.ragquest.model.po -
com.nju.ragquest.model.vo -
com.nju.ragquest.service com.nju.ragquest.repository, com.nju.ragquest.postgresRepository, com.nju.ragquest.model
com.nju.ragquest.service.serviceImpl com.nju.ragquest.model, com.nju.ragquest.utils, com.nju.ragquest.ONNXModelLoader
com.nju.ragquest.utils -
com.nju.ragquest.ONNXModelLoader -

开发包图:

RAG 应用业务逻辑层开发包图

config

模块概述

config 模块是系统的基础设施配置中心,负责整合 SpringBoot 框架能力与项目特定配置需求。

核心职责为:多数据源管理、安全认证体系、框架整合配置、接口安全策略。

整体结构

config 整体结构

controller

模块概述

controller 模块负责处理 HTTP 请求和响应。

核心职责包括路由处理、参数绑定、权限控制和响应封装。

整体结构

controller 整体结构

exception

模块概述

exception 模块负责对异常进行集中处理,给前端或调用者提供统一、规范的错误响应。

核心职责为捕获所有异常。

整体结构

exception 整体结构

repository

模块概述

repository 模块主要负责与数据库进行交互,承担数据持久化的任务。它为上层服务提供数据的增删改查等操作,保证数据能在应用程序和数据库之间正确流转。

核心职责是通过不同的 repository 类实现与数据库的交互,包括基本的 CRUD 操作、自定义查询和批量插入等功能。

整体结构

repository 整体结构

postgresRepository

模块概述

postgresRepository 模块主要负责与 PostgreSQL 数据库进行交互,处理与知识块数据相关的存储、查询等操作。

整体结构

postgresRepository 整体结构

model

模块概述

model 模块承担着将数据库中的数据映射到 Java 对象,以及在应用程序和数据库之间进行数据交互的重要任务。

核心职责为:定义数据库实体、管理实体生命周期、处理实体关联关系、实现数据转换方法。

整体结构

model 整体结构

model.vo

模块概述

model.vo 模块用于前端展示或接口传输,封装业务层返回的数据。

核心职责为:封装业务数据、定义接口响应格式、支持前后端交互。

整体结构

model.vo 整体结构

service

模块概述

service 模块在项目里处于业务逻辑处理的核心位置,衔接了控制器层与数据访问层,负责实现具体的业务功能。

核心职责为:业务逻辑实现、数据交互协调、外部服务调用、数据导入处理。

整体结构

service 整体结构

关键方法
  • 知识库构建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void importFromDirectoryByParagraphs(Path directory) throws IOException {
Files.walk(directory)
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".txt"))
.forEach(this::processFileByParagraphs);
}

private void processFileByParagraphs(Path file) {
try {
String content = Files.readString(file, StandardCharsets.UTF_8);
String fileName = file.getFileName().toString();

List<String> chunks = textProcessor.processTextByParagraphs(content);

List<KnowledgeChunk> knowledgeChunks = IntStream.range(0, chunks.size())
.mapToObj(i -> new KnowledgeChunk(chunks.get(i), fileName, i))
.toList();

repository.batchInsert(knowledgeChunks);
} catch (IOException e) {
throw new RuntimeException("Failed to process file: " + file, e);
}
}

遍历所有文件,构建外部知识库。

  • 语义检索
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public List<KnowledgeChunk> smartSearch(String keyword, int minResults) {
// 计算需要获取的最大结果数
int maxLimit = calculateLimit(minResults, STEP);

// 单次数据库查询
List<FuzzySearchRepository.SearchResult> results = repository.similaritySearch(
keyword,
MIN_THRESHOLD,
maxLimit
);
;

if (results.isEmpty()) {
results = repository.easySearch(keyword);
}

if (results.isEmpty()) {
results = repository.normalSearch(keyword);
}

// 内存中过滤
return applyDynamicThreshold(results, minResults);
}

在外部知识库中根据语义查询需要的信息。

serviceImpl

模块概述

serviceImpl 模块作为 service 接口的具体实现层,承担着将业务逻辑具体化、与数据访问层交互以及调用外部服务来完成复杂业务功能的需求。

整体结构

serviceImpl 整体结构

关键方法
  • 问答生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public ContentVO ask(Long chatId, String question) {
ChatPO chatPO = chatRepository.findChatPOById(chatId);

ChatQuestionPO chatQuestionPO = new ChatQuestionPO();
chatQuestionPO.setQuestion(question);
chatQuestionPO.setChat(chatPO);
chatPO.getChatQuestions().add(chatQuestionPO);

ZhipuAIClient zhipuAIClient = new ZhipuAIClient();

if (chatPO.getChatQuestions().size() == 1) {
// update title
String newTitle;
String title_prompt = "The following is the first question in my conversation with the large model. " +
"Please help me come up with a title for this conversation. The language should be consistent with my prompt and highly summarize the content of the conversation, with no more than 10 words. \n" +
question;
try {
String jsonResponse = zhipuAIClient.sendRequest(title_prompt);
newTitle = zhipuAIClient.extractContent(jsonResponse);
chatPO.setTitle(newTitle);
System.out.println(newTitle);
} catch (Exception e) {
e.printStackTrace();
}
}

String answer;
try {
String jsonResponse = zhipuAIClient.sendRequest("用户问题:" + question +
"\n\n可用的知识库文件:2000年到2024年诺贝尔文学奖\n\n请直接返回需要查阅的一个文件名,格式为“20XX年诺贝尔文学奖”,如果需要多个文件请用英文逗号分隔。不要解释。");
String needFiles = zhipuAIClient.extractContent(jsonResponse);
System.out.println(needFiles);
String[] files = needFiles.split(",");
StringBuilder knowledgeFiles = new StringBuilder();
if (!fuzzySearchService.smartSearch(files[0], 1).isEmpty()) {
for (String file : files) {
knowledgeFiles.append(fuzzySearchService.smartSearch(file, 1).get(0).getContent()).append("\n\n");
}
}else {
jsonResponse = zhipuAIClient.sendRequest("用户问题:" + question +
"\n\n可用的知识库文件:2000年到2024年诺贝尔文学奖\n\n请直接返回需要查阅的文件名,请一定遵照回答格式,格式为“20XX年诺贝尔文学奖”,如果需要多个文件请用英文逗号分隔。不要解释。");
needFiles = zhipuAIClient.extractContent(jsonResponse);
files = needFiles.split(",");
if (!fuzzySearchService.smartSearch(files[0], 1).isEmpty()) {
for (String file : files) {
knowledgeFiles.append(fuzzySearchService.smartSearch(file, 1).get(0).getContent()).append("\n\n");
}
}else {
throw new Exception("No file found");
}
}
String supplyFile = zhipuAIClient.sendRequest("用户问题:" + question + "\n\n参考知识库内容:\n" + knowledgeFiles + "\n\n请结合上述信息给出专业回答");
answer = zhipuAIClient.extractContent(supplyFile);
} catch (Exception e) {
e.printStackTrace();
answer = "Failed to fetch the answer due to an exception";
}

ChatAnswerPO answerPO = new ChatAnswerPO();
answerPO.setAnswer(answer);
answerPO.setChat(chatPO);
chatPO.getChatAnswers().add(answerPO);
chatRepository.save(chatPO);

return answerPO.toAnswerVO();
}

该方法实现了自动重试机制(当首次文件查询失败时)和多步骤的 AI 协作流程,最终形成包含知识库内容支撑的专业回答。

utils

模块概述

utils 模块在整个项目里主要承担辅助性、通用性的功能需求,为其他模块提供基础支持,以保障项目的正常运行和功能的顺利实现。

核心职责为与 ZhipuAI 接口进行交互,为项目中的聊天服务等业务模块提供了获取 AI 回答的能力。

整体结构

utils 整体结构

RAG 应用展示层的分解

开发包 依赖的开发包
ChatDashBoard index, ChatsAPI
UserLogin index, UserAPI
UserRegister index, UserAPI
index -
ChatsAPI -
UserAPI -

开发包图:

RAG 应用展示层开发包图

ChatDashBoard

模块概述

ChatDashBoard 模块主要用于与 AI 对话,并管理多会话状态。

核心职责为:会话管理、消息处理、状态同步。

整体结构

ChatDashBoard 整体结构

UserLogin

模块概述

UserLogin 模块主要用于实现用户凭证验证,并提供安全登录流程,支持登录状态持久化。

主要职责为:认证流程控制、安全信息管理、UI 交互协调。

整体结构

UserLogin 整体结构

UserRegister

模块概述

UserRegister 模块主要用于新用户注册,采集用户信息并验证。

主要职责为:注册流程控制。

整体结构

UserRegister 整体结构

index

模块概述

index 模块主要负责路由模块负责管理应用的不同页面之间的导航,定义 URL 路径与组件的映射关系,以及处理路由相关的逻辑。

主要职责为:认证隔离、会话保持。

整体结构

index 整体结构

ChatsAPI

模块概述

ChatsAPI 模块主要承担与聊天功能相关的 API 请求操作。

主要职责为:获取会话相关信息、创建新会话、获取聊天消息、向 AI 发送消息。

整体结构

ChatsAPI 整体结构

UserAPI

模块概述

ChatsAPI 模块主要承担与用户功能相关的 API 请求操作。

主要职责为:处理用户登录和注册。

整体结构

UserAPI 整体结构

Prompt 评估业务逻辑层的分解

开发包 依赖的开发包
app schemas, ragas_evaluator, models, database
schemas -
ragas_evaluator RAGAS
models -
database -

开发包图:

Prompt 评估业务逻辑层开发包图

app

模块概述

app 模块主要承担 RAG 迭代管理和评估流程控制以及数据可视化支持。

主要职责是管理评估平台的后端核心业务逻辑。

整体结构

app 整体结构

关键函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
async def create_evaluation(
iteration_id: int = Form(...),
name: str = Form(...),
description: Optional[str] = Form(None),
data_file: UploadFile = File(...),
db: Session = Depends(get_db)
):
"""上传数据并评估RAG性能"""
# 检查迭代是否存在
iteration = db.query(models.Iteration).filter(models.Iteration.id == iteration_id).first()
if not iteration:
raise HTTPException(status_code=404, detail="Iteration not found")

# 读取上传的数据
contents = await data_file.read()

# 解析数据格式 (假设是JSON格式)
try:
data = json.loads(contents)
# 验证数据结构
if not all(key in data for key in ["questions", "answers", "contexts"]):
raise HTTPException(status_code=400,
detail="Invalid data format. Required fields: questions, answers, contexts")

# 执行RAGAS评估 (添加重试机制)
max_retries = 3
retry_count = 0
last_error = None
while retry_count < max_retries:
try:
# 确保上下文格式正确
# 检查contexts是否是字符串列表的列表
if data["contexts"] and not isinstance(data["contexts"][0], list):
# 如果contexts是字符串列表而不是字符串列表的列表,则转换它
data["contexts"] = [[ctx] for ctx in data["contexts"]]

metrics = evaluate_rag_data(data["questions"], data["answers"], data["contexts"])
break
except Exception as e:
last_error = e
retry_count += 1
if retry_count >= max_retries:
raise HTTPException(status_code=500,
detail=f"Failed to evaluate after {max_retries} attempts: {str(e)}")
print(f"Evaluation attempt {retry_count} failed: {e}. Retrying...")
import time
time.sleep(2) # 短暂暂停后重试

# 保存评估结果
db_evaluation = models.Evaluation(
iteration_id=iteration_id,
name=name,
description=description,
data=contents.decode(),
faithfulness=metrics.faithfulness,
answer_relevancy=metrics.answer_relevancy,
context_precision=metrics.context_precision,
context_recall=metrics.context_recall
)
db.add(db_evaluation)
db.commit()
db.refresh(db_evaluation)

return db_evaluation
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="Invalid JSON format")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Evaluation failed: {str(e)}")

提供和前端交互的创建评估的 API。

schemas

模块概述

schemas 模块主要承担 API 的数据验证和序列化,主要用于定义传输的数据类型。

主要职责包括验证 API 请求数据、序列化数据库模型到响应,以及定义数据传输对象。

整体结构

schemas 整体结构

ragas_evaluator

模块概述

ragas_evaluator 模块主要承担自动化评估流程、多维度指标计算和 AI 适配。

主要职责为:评估流程控制、评估指标计算、接入 AI 模型。

整体结构

ragas_evaluator 整体结构

关键函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def evaluate_rag_data(
questions: List[str],
answers: List[str],
contexts: List[List[str]]
) -> RagasResult:
"""
使用RAGAS评估RAG系统的性能(智谱AI版本)

Args:
questions: 评估问题列表
answers: RAG系统生成的回答列表
contexts: 每个问题的上下文列表(每个元素是字符串列表)

Returns:
RagasResult: 包含各项评估指标的结果对象
"""
# 参数校验
if not all(len(questions) == len(lst) for lst in [answers, contexts]):
raise ValueError("输入数据长度不一致")

# 初始化API密钥
api_key = os.getenv("ZHIPUAI_API_KEY")
if not api_key:
raise EnvironmentError("ZHIPUAI_API_KEY 环境变量未设置")

# 初始化模型
chat_model = ChatZhipuAI(model="glm-4-flash", api_key=api_key)
embedding_model = ZhipuAIEmbeddings(model="embedding-3", api_key=api_key)

# 包装模型供RAGAS使用
ragas_llm = LangchainLLMWrapper(chat_model)
ragas_embeddings = LangchainEmbeddingsWrapper(embedding_model)

# 准备数据集 - 处理上下文格式
dataset_dict = {
"question": questions,
"answer": answers,
"reference": ["\n".join(ctx) for ctx in contexts],
"contexts": contexts
}

# 创建数据集
dataset = Dataset.from_dict(dataset_dict)

# 执行评估
try:
# 使用RAGAS的evaluate函数
result = ragas.evaluate(
dataset,
metrics=[
ragas.metrics.faithfulness,
ragas.metrics.answer_relevancy,
ragas.metrics.context_precision,
ragas.metrics.context_recall
],
llm=ragas_llm,
embeddings=ragas_embeddings
)

# 提取结果
# 修改后的返回结果部分(取指标的平均值)
return RagasResult(
faithfulness=sum(result['faithfulness']) / len(result['faithfulness']),
answer_relevancy=sum(result['answer_relevancy']) / len(result['answer_relevancy']),
context_precision=sum(result['context_precision']) / len(result['context_precision']),
context_recall=sum(result['context_recall']) / len(result['context_recall'])
)
except Exception as e:
raise RuntimeError(f"评估过程出错: {str(e)}")

使用 RAGAS 评估 RAG 系统的性能(智谱 AI 版本)。

models

模块概述

models 模块主要负责管理不同迭代版本和评估数据持久化。

主要职责是定义 ORM 模型,存储数据。

整体结构

models 整体结构

database

模块概述

database 模块主要负责数据库连接管理和会话工厂管理。

主要职责为:配置数据库连接,使用 SQLAlchemy 创建引擎和会话工厂。

整体结构

database 整体结构

Prompt 评估展示层的分解

开发包 依赖的开发包
app Dashboard, IterationManagement, DataUpload, CompareView
index Dashboard, IterationManagement, DataUpload, CompareView
Dashboard api
IterationManagement api
DataUpload api
CompareView api
api -

开发包图:

Prompt 评估展示层整体结构

app

模块概述

app 模块作为父界面,用于展示通用的模块以及入口的作用。

主要职责:展示通用模块,作为程序入口。

整体结构

app 整体结构

index

模块概述

index 模块主要负责路由模块负责管理应用的不同页面之间的导航,定义 URL 路径与组件的映射关系,以及处理路由相关的逻辑。

主要职责为:导入依赖、定义路由规则、创建路由实例、导出路由实例。

整体结构

index 整体结构

Dashboard

模块概述

Dashboard 模块主要负责展示评估结果。

整体结构

Dashboard 整体结构

IterationManagement

模块概述

IterationManagement 模块主要负责迭代管理,用于展示和管理多个迭代。

整体结构

IterationManagement 整体结构

关键函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 创建新迭代
const createIteration = async () => {
if (!iterationForm.value.name) {
ElMessage.warning('请输入迭代名称')
return
}

submitLoading.value = true
try {
// eslint-disable-next-line no-unused-vars
const response = await axios.post('http://localhost:8000/iterations/', iterationForm.value)
ElMessage.success('创建迭代成功')
dialogVisible.value = false

// 重置表单
iterationForm.value = {
name: '',
description: ''
}

// 刷新数据
fetchData()
} catch (error) {
console.error('创建迭代失败:', error)
ElMessage.error('创建迭代失败')
} finally {
submitLoading.value = false
}
}

用于创建新迭代。

DataUpload

模块概述

DataUpload 模块主要负责上传迭代数据。

整体结构

DataUpload 整体结构

关键函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 提交上传
const submitUpload = async () => {
// 表单验证
if (!uploadForm.value.iteration_id) {
ElMessage.warning('请选择迭代版本')
return
}

if (!uploadForm.value.name) {
ElMessage.warning('请输入评估名称')
return
}

if (!uploadFile.value) {
ElMessage.warning('请上传数据文件')
return
}

// 验证文件格式
if (uploadFile.value.type !== 'application/json') {
ElMessage.warning('请上传JSON格式的文件')
return
}

uploading.value = true

try {
// 创建FormData
const formData = new FormData()
formData.append('iteration_id', uploadForm.value.iteration_id)
formData.append('name', uploadForm.value.name)
if (uploadForm.value.description) {
formData.append('description', uploadForm.value.description)
}
formData.append('data_file', uploadFile.value)

// 发送请求
// eslint-disable-next-line no-unused-vars
const response = await axios.post('http://localhost:8000/evaluations/',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
)

ElMessage.success('评估提交成功')

// 导航到仪表板
router.push('/')
} catch (error) {
console.error('提交评估失败:', error)

// 显示错误信息
if (error.response && error.response.data && error.response.data.detail) {
ElMessage.error(`提交失败: ${error.response.data.detail}`)
} else {
ElMessage.error('提交评估失败,请检查数据格式')
}
} finally {
uploading.value = false
}
}

用于提交上传。

CompareView

模块概述

CompareView 模块用于比较不同的迭代。

整体结构

CompareView 整体结构

关键函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 比较选定的迭代
const compareIterations = async () => {
if (selectedIterations.value.length < 2) {
ElMessage.warning('请至少选择两个迭代进行比较')
return
}

try {
// 将数组转换为 "iteration_ids=1&iteration_ids=2"
const queryString = selectedIterations.value
.map(id => `iteration_ids=${id}`)
.join('&');

const url = `http://localhost:8000/metrics/compare/?${queryString}`;
const response = await axios.get(url);

comparisonData.value = response.data;
} catch (error) {
console.error('比较数据获取失败:', error);
ElMessage.error('比较数据获取失败');
}
}

用于比较选定的迭代。

api

模块概述

api 模块主要承担所有的 API 请求操作。

主要职责为:与后端交互,传递迭代和评估信息。

整体结构

api 整体结构

依赖视角

下图是项目中各个包之间的依赖关系。

RAG 应用业务逻辑层:

RAG 应用业务逻辑层包间依赖关系

RAG 应用展示层:

RAG 应用展示层包间依赖关系

Prompt 评估业务逻辑层:

Prompt 评估业务逻辑层包间依赖关系

Prompt 评估展示层:

Prompt 评估展示层包间依赖关系


软工III迭代二文档
https://lngym.top/课程作业/软工III迭代二文档/
作者
lngym
发布于
2025年5月1日
许可协议