智能测试用例生成:分块实现大模型完整回答的最佳策略

发布于:2025-03-30 ⋅ 阅读:(296) ⋅ 点赞:(0)

Deepseek API+Python 测试用例一键生成与导出 V1.0.5工具,随着需求文档和接口文档的复杂性和长度不断增加,基于大模型生成测试用例的任务也变得更加挑战。尤其当文档内容过多时,大模型可能因输入长度限制而无法提供完整的回答。这种情况下,合理的分词策略不仅可以有效解决问题,还能提升生成过程的效率和准确性。


1. 为什么需要分块?

大模型(如 GPT 系列)通常对输入长度有严格限制。如果直接将超长的文档内容传递给大模型:

  1. 输入超限:模型会截断多余的输入,导致关键信息丢失。
  2. 结果不完整:输出内容可能因为未处理完所有输入而中断。
  3. 生成效率低:过长的输入可能导致生成时间显著增加。

通过将文档内容合理分块,不仅可以规避上述问题,还可以优化生成质量,将完整的测试用例输出整合起来。

** 1.1 常见分块策略**

在处理大模型输入时,输入分块是解决长文本或大数据量输入问题的重要方法。分块方法直接影响模型性能、计算效率以及结果的质量。以下是几种常见的输入分块方法及其比较,最后提出最优选择的建议。


1.1.1 滑动窗口分块

原理:
将输入按固定长度切分为多个块,每个块之间有部分重叠。滑动窗口的大小和重叠步长可以根据具体任务调整。

  • 优点:

    • 能捕捉到跨分块的上下文信息。
    • 对于需要上下文连续性的任务(如问答、摘要)效果较好。
  • 缺点:

    • 计算成本高,因存在重叠,处理的文本量增加。
    • 可能导致某些信息重复处理,增加冗余。
  • 适用场景:

    • 长文本情感分析。
    • 长篇文档摘要生成。
    • 文档问答任务。

1.1.2 固定长度分块

原理:
将输入按照固定长度(如模型的最大输入长度)切分为多个不重叠的片段,直接输入模型。

  • 优点:

    • 实现简单,计算效率高。
    • 适合需要高吞吐量的任务。
  • 缺点:

    • 跨块的上下文信息可能丢失。
    • 对于长距离依赖的任务效果较差。
  • 适用场景:

    • 文本分类任务。
    • 信息抽取任务。

1.1.3 按语义分块

原理:
基于文本的语义结构(如段落、句子)进行切分,而不是固定长度。通常使用分句工具或自然语言处理技术进行分块。

  • 优点:

    • 分块更自然,能够保持语义完整性。
    • 有效避免因切割位置不当导致的语义丢失。
  • 缺点:

    • 分块长度可能不均匀,处理时需注意填充或截断。
    • 对模型输入的最大长度有一定要求。
  • 适用场景:

    • 文档摘要生成。
    • 长文档的主题提取。

1.1.4. 动态分块

原理:
根据模型的最大输入长度动态调整分块长度,尽可能利用模型的输入容量。结合前后上下文信息,灵活切分。

  • 优点:

    • 更高效地利用模型的输入容量。
    • 上下文保留更完整。
  • 缺点:

    • 实现复杂,需动态调整。
    • 对计算资源要求较高。
  • 适用场景:

    • 多轮对话任务。
    • 需要动态上下文处理的任务。

1.1.5 分层分块

原理:
首先按层次结构将输入切分成若干大块(如按章节或段落),然后针对每个大块再细分为小块,逐层输入模型。

  • 优点:

    • 保持全局语义信息。
    • 分层的上下文信息利用较充分。
  • 缺点:

    • 实现复杂,需分层处理。
    • 时间和计算成本较高。
  • 适用场景:

    • 多文档摘要。
    • 长文档的分段问答。

1.1.6 方法比较
方法 上下文保留 计算效率 复杂度 适用场景
滑动窗口分块 上下文相关任务
固定长度分块 高吞吐量任务
按语义分块 语义完整性要求高的任务
动态分块 灵活上下文需求的任务
分层分块 全局语义相关任务

最优选择建议

  1. 任务需要跨块上下文信息(如问答、摘要):

    • 推荐方法:滑动窗口分块动态分块
      滑动窗口更适合处理固定上下文长度的场景,而动态分块在需要灵活上下文处理时更优。
  2. 任务对语义完整性要求高(如摘要、主题提取):

    • 推荐方法:按语义分块
      保持语义一致性,适合需要精准语义理解的任务。
  3. 大规模文本分类或信息抽取任务(高吞吐量):

    • 推荐方法:固定长度分块
      简单高效,适合对上下文依赖性较低的任务。
  4. 需要全局上下文信息(如多文档处理):

    • 推荐方法:分层分块
      适合需要分层次分析的复杂任务。

2. 分块策略选择

根据常见分块策略,以下是适合需求文档和接口文档分块的策略:

2.1 固定长度分块

将文档内容按固定的字符数或单词数进行分块。例如,每 1000 个字符或每 200 个汉字为一个块。这种方式简单直接,适合一般文档。

优点

  • 实现简单,易于控制每块的大小。
  • 对于无特定逻辑的文档内容十分有效。

缺点

  • 分块可能会截断上下文逻辑,导致语义不连贯。

2.2 基于内容的分块

将文档按内容结构(如段落、标题、接口定义块)进行分割。例如,需求文档可以按功能模块分块,接口文档可以按接口名称分块。

优点

  • 保留了文档逻辑结构,语义连贯性好。
  • 更适合复杂的文档内容。

缺点

  • 实现相对复杂,需要根据文档内容的结构进行解析。

2.3 滑动窗口分块

在固定长度分块的基础上,添加一定的重叠区域。例如,每次分块包含上一块的最后 200 个字符,确保上下文连续。

优点

  • 避免了上下文丢失问题。
  • 可用于需要跨块关联的文档内容。

缺点

  • 会产生重复的内容,处理时需要去重。

2.4 推荐策略

基于需求和接口文档的特点,我们推荐组合使用 固定长度分块滑动窗口分块

  1. 固定长度分块:适合大多数文档,快速分割内容。
  2. 滑动窗口分块:适合需要上下文连续的内容(如接口定义中的依赖关系)。

3. 分块实现:Python 代码

以下是 Python 的分块实现代码,结合了固定长度和滑动窗口策略,适合处理需求文档和接口文档内容。

3.1 分块函数实现

def chunk_text(text, chunk_size=1000, overlap=200):
    """
    将文本按固定长度分块,同时添加滑动窗口重叠。

    参数:
    - text (str): 输入的长文本内容
    - chunk_size (int): 每块的最大字符数
    - overlap (int): 相邻块的重叠字符数

    返回:
    - list: 分块后的文本列表
    """
    print("开始分块...")
    chunks = []
    start = 0
    text_length = len(text)

    while start < text_length:
        end = min(start + chunk_size, text_length)
        chunk = text[start:end]
        chunks.append(chunk)

        # 滑动窗口:下一块的起始位置向后移动 chunk_size - overlap
        start += chunk_size - overlap

    print(f"分块完成,共生成 {len(chunks)} 个块。")
    return chunks

3.2 分块后的循环调用大模型

将分块后的内容逐块传递给大模型,并汇总结果。这一过程确保了所有内容都能够完整处理。

def process_chunks_with_model(chunks, model_call_function):
    """
    循环处理分块内容并汇总结果。

    参数:
    - chunks (list): 分块后的文本列表
    - model_call_function (function): 调用大模型的函数,接受单个块,返回结果

    返回:
    - str: 汇总后的完整结果
    """
    results = []

    for i, chunk in enumerate(chunks):
        print(f"正在处理第 {i + 1} 个块...")
        result = model_call_function(chunk)  # 调用大模型处理单个块
        results.append(result)

    # 将所有块的结果整合为一个完整的字符串
    combined_result = "\n".join(results)
    print("处理完成,已整合所有分块结果。")
    return combined_result

3.3 示例:对读取到的需求文档内容进行分块处理

以下代码展示了一个完整的流程,鉴于小工具已读取到了文档内容,这里只对文档的内容进行分块即可,从读取需求文档到分块调用大模型,再到整合输出结果。

    def run(self):
        try:
            # todo 此处加入分块处理
            # 分块内容
            context_chunks = self.chunk_text(self.context)
            all_result_str = ""
            for context_chunk in context_chunks:
            	# 调用大模型
                result = self.generate_cases(context_chunk)
                if result is not None and isinstance(result, str):
                    all_result_str += result
                else:
                    print(f"{context_chunk}推理结果异常!")
            if 'json' in all_result_str:
                all_result_str = re.search(r"```json(.*)```", all_result_str, re.DOTALL)
                # 拼接成一个完整的 JSON 数组
                try:
                    # 将每个 JSON 字符串解析为字典
                    json_objects = [json.loads(js) for js in all_result_str]
                    # 将多个字典合并为一个 JSON 数组(或其他需要的结构)
                    combined_json = json.dumps(json_objects, indent=4)
                    print("Combined JSON:")
                    print(combined_json)
                except json.JSONDecodeError as e:
                    print(f"Error parsing JSON: {e}")
                # if all_result_str:
                #     json_str = all_result_str.group(1)
                #     result = json_str
            self.finished.emit(combined_json)
        except Exception as e:
            self.error.emit(str(e))


3.4 示例:调用大模型函数

以下是一个模拟的大模型调用函数,可替换为实际的 API 调用代码。

    def generate_cases(self, chunk_data):
        # 初始化OpenAI客户端
        client = OpenAI(
            # 如果没有配置环境变量,请用百炼API Key替换:api_key="sk-xxx"
            # api_key='sk-xxx',
            api_key='sk-xxx',  # todo 此处需更换
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
        )
        # chunked_context_list = self.chunk_data(self.context, chunk_size=2000)  # 根据需要调整 chunk_size
        all_results = []
        reasoning_content = ""  # 定义完整思考过程
        answer_content = ""  # 定义完整回复
        is_answering = False  # 判断是否结束思考过程并开始回复

        # 创建聊天完成请求
        completion = client.chat.completions.create(
            model="deepseek-r1",  # 此处以 deepseek-r1 为例,可按需更换模型名称
            messages=[
                {'role': 'user', 'content': f'所在行业:  {self.job_area};'
                                            f'文档内容: {chunk_data}; '
                                            f'生成的用例类型: {self.func_type}; '
                                            f'用例设计方法: {self.design_method}; '
                                            f'提示词:{self.prompt};'}
            ],
            stream=True,
            # 解除以下注释会在最后一个chunk返回Token使用量
            # stream_options={
            #     "include_usage": True
            # }
        )
        print("\n" + "=" * 20 + "思考过程" + "=" * 20 + "\n")
        for chunk in completion:
            # 如果chunk.choices为空,则打印usage
            if not chunk.choices:
                print("\nUsage:")
                print(chunk.usage)
            else:
                delta = chunk.choices[0].delta
                # 打印思考过程
                if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
                    print(delta.reasoning_content, end='', flush=True)
                    reasoning_content += delta.reasoning_content
                else:
                    # 开始回复
                    if delta.content != "" and not is_answering:
                        print("\n" + "=" * 20 + "完整回复" + "=" * 20 + "\n")
                        is_answering = True
                    # 打印回复过程
                    print(delta.content, end='', flush=True)
                    answer_content += delta.content
        return answer_content

4. 效果展示

4.1 示例输入

假设读取的需求文档内容如下:

这是一个示例需求文档,内容较长,因此需要分块处理。
文档包含多个功能模块,每个模块都有其独特的逻辑和流程。
需要设计全面的测试用例,包括正常场景、异常场景和边界场景。
接口文档部分定义了请求方法、URL、参数、响应格式等。
...

4.2 分块结果

分块后,每块内容如下:

  • 块 1:这是一个示例需求文档,内容较长,因此需要分块处理...
  • 块 2:文档包含多个功能模块,每个模块都有其独特的逻辑和流程...

4.3 汇总结果

调用大模型后,整合所有块的处理结果为完整的输出文档,确保内容无遗漏。


5. 总结

在测试用例生成工具中,合理的分块策略是确保大模型完整回答的关键。在本次优化中:

  1. 我们结合固定长度分块和滑动窗口分块,既保证了上下文的连贯性,又避免了模型输入超限的问题。
  2. 分块后的内容通过循环传递给大模型,逐步生成结果,最终整合为完整的测试用例输出。
  3. 提供了 Python 的分块实现代码,适合测试工程师快速集成到现有工具中。

通过这一优化,Deepseek API+Python 测试用例一键生成与导出 V1.0.5工具在处理超长文档时更加高效、稳定,是测试工程师设计高质量测试用例的绝佳助手!


网站公告

今日签到

点亮在社区的每一天
去签到