1. 项目缘起:当数据需求撞上“零预算”的墙

做AI应用开发或者微调模型的朋友,肯定都体会过“数据饥渴症”。一个好想法,一个酷炫的架构,最后往往卡在第一步:没有高质量、对路子的数据集。公开数据集要么领域不匹配,要么格式混乱,标注质量参差不齐。找人工标注?成本高、周期长,对于个人开发者或小团队来说,基本是条死路。我自己最近在折腾一个行业知识问答的智能体,就遇到了这个经典难题——我需要一个包含多轮对话、带有明确意图和实体信息的结构化对话数据集,市面上根本找不到。

就在我几乎要放弃,准备手动编造几百条数据的时候,我注意到了两个工具的崛起: CrewAI Ollama 。CrewAI 是一个用于编排多个AI智能体协同工作的框架,而 Ollama 则让在本地运行大语言模型变得像喝咖啡一样简单。一个疯狂的念头冒了出来:能不能让AI智能体自己扮演“用户”和“助手”,互相聊天,从而批量生成我需要的对话数据?这个想法听起来有点“左脚踩右脚上天”,但理论上似乎可行。于是,我决定进行一次极限测试:用一台家用电脑,让 CrewAI 指挥多个本地运行的 Ollama 模型,进行一场为期72小时不间断的“数据生成马拉松”。

结果出乎意料地好。系统稳定运行了三天三夜,生成了 1,065 条高质量、结构化的对话条目,完全满足了我的项目需求。整个过程就像养了一群不知疲倦的数字员工,在自动为我生产数据原料。这篇文章,我就来详细拆解这个“自治数据集生成器”的构建思路、技术细节、踩过的坑以及最终的收获。如果你也受困于数据,不妨看看这个“自力更生”的方案。

2. 核心架构设计:让AI智能体“角色扮演”

这个项目的核心思想是“模拟”。与其去互联网上爬取杂乱无章的数据,不如在受控环境下,让AI模仿真实交互场景,自己创造数据。这就需要一套精密的编排系统。

2.1 为什么是 CrewAI + Ollama?

首先说说技术选型的考量。市面上智能体框架不少,比如 LangChain 的 Agent 模块、AutoGen 等。我选择 CrewAI 主要基于以下几点:

  1. 角色分工明确 :CrewAI 的“Agent”(智能体)、“Task”(任务)、“Process”(流程)概念非常清晰。我可以轻松定义不同的角色(如“用户提问者”、“专业助手”、“质量审核员”),并为每个角色分配专属的任务和工具,这完美契合了“多角色对话模拟”的需求。
  2. 流程编排直观 :它的流程控制(顺序执行、轮询执行等)让多个智能体间的协作逻辑变得可视化和可管理。我可以设定先由“提问者”发起问题,然后“助手”回答,接着“审核员”检查,形成一个闭环。
  3. 与 Ollama 集成简单 :CrewAI 原生支持将 Ollama 作为底层 LLM 驱动,配置起来几乎是一行代码的事情,省去了大量封装工作。

而选择 Ollama 的理由更直接:

  1. 零成本与隐私安全 :所有模型在本地运行,无需支付 API 费用,生成的所有数据完全私有,不存在数据泄露风险。这对于生成可能包含敏感或特定领域信息的数据集至关重要。
  2. 模型多样性 :Ollama 支持众多开源模型,如 Llama 3、Mistral、Gemma 等。我可以让不同的智能体使用不同特点的模型,比如让“提问者”用更天马行空的模型来生成多样性问题,让“助手”用更严谨、知识丰富的模型来回答。
  3. 可控性与稳定性 :本地部署避免了网络波动和第三方API的速率限制。虽然单次响应速度可能不如云端顶级API,但胜在稳定、可长时间高负荷运行,这正是72小时马拉松所需的关键特性。

这个组合搭建了一个低成本、高自主性的数据生产流水线。

2.2 智能体角色设计与任务链

我设计了三个核心智能体角色,它们组成了一条数据生成流水线:

角色一:场景与问题生成器 (Scenario & Question Generator)

  • 模型 :Llama 3 8B(创意性较好)。
  • 职责 :根据我提供的“种子主题”列表(例如,“云计算成本优化”、“Python异步编程疑难解答”、“健康饮食计划制定”),随机选择一个主题,并生成一个具体的、贴近真实的用户问题场景。它不仅要生成问题文本,还要以结构化格式输出该问题的“潜在用户意图”和“可能涉及的实体”。
  • 输出示例
    {
      “theme”: “云计算成本优化”,
      “user_scenario”: “我是一家初创公司的技术负责人,我们主要使用AWS,最近一个月EC2和RDS的费用突然增长了40%,但流量并没有明显变化。我应该从哪里开始排查?”,
      “intent”: “故障排查与成本分析”,
      “entities”: [“AWS”, “EC2”, “RDS”, “成本激增”]
    }
    

角色二:专业回答生成器 (Expert Answer Generator)

  • 模型 :Mistral 7B(在逻辑和知识准确性上表现更稳定)。
  • 职责 :接收角色一输出的场景问题,扮演该领域的专家,生成一个详尽、专业、分步骤的解答。要求回答必须结构化,包含核心建议、具体操作步骤和注意事项。
  • 输出示例 :承接上面的问题,生成包含“检查CloudWatch警报与指标”、“分析Cost Explorer按资源细分”、“审查预留实例覆盖率”、“检查是否有闲置资源”等步骤的详细回答。

角色三:对话质量与格式审核器 (Dialogue Quality & Format Auditor)

  • 模型 :Gemma 7B(相对小巧,适合做分类和校验任务)。
  • 职责 :这是质量把关的环节。它接收前两个角色生成的“问题-回答”对,并执行以下检查:
    1. 相关性 :回答是否直接针对了问题?
    2. 逻辑性 :回答中的步骤是否合理、有序?
    3. 无害性 :内容是否安全、符合伦理?
    4. 格式规范性 :最终输出是否符合我预设的JSON格式。 只有通过审核的对话对,才会被写入最终的数据集文件。审核不通过的,会被记录日志并丢弃,系统自动开始生成下一条。

这三个角色通过 CrewAI 的 SequentialProcess 串联起来,形成一个自动化流水线。我通过设置“任务”的“异步”属性,让智能体们在等待模型响应时不会阻塞,最大化利用计算资源。

3. 实操搭建:从环境配置到稳定运行

有了设计图,接下来就是动手搭建。这个过程充满了细节上的调整。

3.1 本地模型部署与优化

首先是在 Ollama 中拉取和部署模型:

# 拉取所需模型
ollama pull llama3:8b
ollama pull mistral:7b
ollama pull gemma:7b

# 运行模型服务(通常Ollama默认在后台运行)

注意:同时运行多个模型对内存要求较高。我的机器是32GB RAM,这是能同时流畅运行这三个7B/8B级别模型的最低推荐配置。如果内存不足,可以考虑让智能体串行使用同一个模型,或者使用量化版本(如 q4_0 ),但可能会影响生成质量。

为了让模型更好地扮演角色, 系统提示词(System Prompt) 的编写至关重要。这是赋予智能体“灵魂”的地方。

以“专业回答生成器”为例,它的提示词不仅要求它扮演专家,还规定了输出格式:

你是一位资深的{theme}领域专家。你的任务是针对用户提出的具体问题,提供专业、可操作、分步骤的解决方案。
请严格按照以下JSON格式输出你的回答:
{
  “answer”: “你的完整回答内容,建议使用分点论述。”,
  “key_steps”: [“步骤一”, “步骤二”, “步骤三”],
  “important_notes”: “需要特别注意的事项”
}
请确保回答内容准确、务实,避免空泛的理论。

通过精心设计的提示词,可以极大地约束模型输出,提高生成数据的结构化程度和可用性。

3.2 CrewAI 智能体与任务编排

接下来是 CrewAI 部分的代码核心。我创建了一个 Python 脚本,主要结构如下:

from crewai import Agent, Task, Crew, Process
from crewai.llm import Ollama

# 1. 初始化 Ollama LLM 配置
llm_llama = Ollama(model=“llama3:8b”, base_url=“http://localhost:11434”)
llm_mistral = Ollama(model=“mistral:7b”, base_url=“http://localhost:11434”)
llm_gemma = Ollama(model=“gemma:7b”, base_url=“http://localhost:11434”)

# 2. 创建智能体
question_generator = Agent(
    role=‘资深用户场景设计师’,
    goal=‘根据给定主题,生成一个真实、具体的用户问题场景,并分析其意图和实体。’,
    backstory=‘你擅长洞察用户在特定领域的痛点和疑问,并能将其转化为清晰的问题描述。’,
    llm=llm_llama,
    verbose=True  # 输出详细日志,调试时非常有用
)

answer_generator = Agent(
    role=‘领域专家’,
    goal=‘为用户问题提供专业、结构化、可操作的解答。’,
    backstory=‘你在多个技术领域拥有深厚知识,善于将复杂问题拆解为易懂的步骤。’,
    llm=llm_mistral,
    verbose=True
)

quality_auditor = Agent(
    role=‘数据质量审核专员’,
    goal=‘严格审核生成的对话对,确保其相关性、逻辑性、无害性及格式正确。’,
    backstory=‘你对文本质量和数据规范有极致要求,能精准发现瑕疵。’,
    llm=llm_gemma,
    verbose=True
)

# 3. 创建任务
task1 = Task(
    description=“””
    主题:{selected_theme}
    请生成一个用户问题。要求:
    1. 问题必须具体、真实,源于该主题下的常见场景。
    2. 以JSON格式输出,包含字段:`theme`, `user_scenario`, `intent`, `entities`。
    “””,
    agent=question_generator,
    expected_output=“一个符合格式要求的JSON对象,包含问题场景、意图和实体。”
)

task2 = Task(
    description=“””
    请基于以下用户问题,以领域专家的身份提供解答:
    问题场景:{user_scenario}
    请以JSON格式输出,包含字段:`answer`, `key_steps`, `important_notes`。
    “””,
    agent=answer_generator,
    context=[task1], # 此任务依赖于task1的输出
    expected_output=“一个符合格式要求的JSON对象,包含专业解答、关键步骤和注意事项。”
)

task3 = Task(
    description=“””
    请审核以下对话对:
    问题:{user_scenario}
    回答:{expert_answer}
    审核标准:1. 回答是否直接针对问题?2. 逻辑是否清晰合理?3. 内容是否安全无害?4. 格式是否符合JSON规范?
    请给出审核结果:`pass` 或 `fail`,并简要说明原因。
    “””,
    agent=quality_auditor,
    context=[task1, task2],
    expected_output=“审核结果(pass/fail)及原因说明。”
)

# 4. 组建团队并执行流程
crew = Crew(
    agents=[question_generator, answer_generator, quality_auditor],
    tasks=[task1, task2, task3],
    process=Process.sequential, # 顺序执行
    verbose=2
)

# 5. 在一个循环中执行,持续生成数据
results = []
for i in range(num_iterations):
    selected_theme = random.choice(themes_list)
    result = crew.kickoff(inputs={“selected_theme”: selected_theme})
    # ... 解析result,如果审核通过则存入results并保存到文件 ...

这个框架清晰地将角色、任务和流程分离开来。 context 参数确保了任务间的数据传递。

3.3 持久化、日志与容错机制

要让一个系统无人值守运行72小时,健壮性设计必不可少。

  1. 数据持久化 :我使用 Python 的 json 模块,每成功生成一条数据,就立即以追加模式写入到一个 .jsonl 文件(每行一个JSON对象)。这样即使程序意外崩溃,已生成的数据也不会丢失。

    import json
    with open(‘generated_dataset.jsonl’, ‘a’, encoding=‘utf-8’) as f:
        json_record = {“id”: idx, “theme”: theme, “Q”: user_scenario, “A”: expert_answer, “intent”: intent, “entities”: entities}
        f.write(json.dumps(json_record, ensure_ascii=False) + ‘\n’)
    
  2. 详细日志 :使用 Python logging 模块记录每一步操作:何时开始生成一条新数据、每个智能体的输出、审核结果、遇到的异常等。日志是后期排查问题的唯一依据。

  3. 容错与重试

    • 网络超时 :为每个 Ollama 调用设置合理的超时时间(如120秒),并使用 try-except 包裹。
    • 模型响应异常 :有时模型会返回非JSON格式的内容。我编写了健壮的解析函数,如果解析失败,则记录日志并将该次生成标记为失败,进入下一轮循环,而不是让整个程序崩溃。
    • 系统资源监控 :写了一个简单的守护脚本,定时检查主进程是否存活,以及内存使用情况。如果内存占用超过90%,会发送警告(虽然72小时里没触发)。

4. 72小时马拉松:遇到的问题与优化策略

实际运行远非一帆风顺。下面是我遇到的主要挑战及解决方案。

4.1 性能瓶颈与资源调度

最初的几个小时,我发现生成速度很慢,大约5-6分钟才能完成一轮(三个智能体依次执行)。分析发现,瓶颈在于 I/O等待 :当一个智能体在等待 Ollama 模型生成响应时,CPU 和 GPU 是空闲的,但整个流程却被阻塞了。

优化策略 :利用 CrewAI 任务的 异步(async) 执行特性。但需要注意的是,由于我的流程是强顺序依赖的(必须先有问题,再有回答,最后审核),无法将三个任务完全并行。我的优化点是:

  • 将模型加载改为常驻内存。确保 Ollama 服务稳定运行,避免每次调用都重新加载模型。
  • 在 CrewAI 的 Agent 层面,其实内部会处理与LLM的通信。我主要确保我的主循环脚本是异步的,并且处理好任务间的依赖关系。实际上,对于顺序流程,异步带来的提升有限,但确保了单个任务的网络调用不会阻塞事件循环。

更大的性能提升来自于 调整模型参数 。通过 Ollama 的 Modelfile 或调用参数,我降低了 temperature (减少随机性,使输出更稳定),并适当提高了 num_predict (允许生成长度稍长的内容),减少了因生成长度不足导致需要重复调用的次数。

4.2 数据质量与多样性的平衡

运行几小时后检查数据,发现了两个问题:

  1. 问题同质化 :针对同一个主题,生成的问题场景开始重复,例如总是围绕“AWS成本激增”。
  2. 回答模板化 :“专业回答生成器”的回答逐渐变得套路化,开头总是“首先,检查…其次,分析…”。

优化策略

  • 丰富“种子主题”和添加约束 :我不仅提供“云计算成本优化”,还提供更细分的子主题,如“云存储生命周期策略设置”、“容器服务网络费用排查”等。同时,在给“场景与问题生成器”的提示词中,增加约束:“避免生成与前10轮对话中类似的问题场景”。
  • 引入随机性与角色变体 :我准备了多个不同风格的“系统提示词”模板,每隔一段时间随机切换给“提问者”和“回答者”。例如,让“提问者”偶尔扮演“技术小白”而不是“技术负责人”,让“回答者”偶尔以“列出常见误区”的方式开头。这有效增加了数据的多样性。
  • 动态示例(Few-shot) :在提示词中,动态插入1-2条之前生成的、高质量的示例对话,给模型提供更直接的参考,引导其输出更符合要求的格式和风格。

4.3 长期运行的稳定性保障

长时间运行最怕内存泄漏和进程僵死。

  • 内存管理 :Ollama 本身对内存管理不错,但 CrewAI 和我的脚本可能存在对象累积。我定期(例如每生成50条数据后)强制进行垃圾回收 ( gc.collect() ),并清空一些大的中间变量。
  • 心跳与检查点 :除了日志,我还实现了一个“检查点”机制。每成功生成100条数据,脚本会将当前状态(如已生成数量、最后使用的主题索引等)保存到一个单独的 checkpoint.json 文件。如果程序因任何原因重启,可以从这个检查点恢复,而不是从头开始。
  • 输出目录监控 :我设置了一个简单的磁盘空间监控,确保存储数据的硬盘有足够空间。

5. 成果评估与后续应用

72小时后,我手动停止了脚本。最终得到了一个包含 1,065 条有效对话的 .jsonl 文件。

5.1 数据质量抽样分析

我随机抽取了100条数据进行人工评估,标准如下:

  • 相关性 :回答是否切题? 合格率约 94% 。少数不合格案例是回答略微偏题或包含了无关的通用建议。
  • 逻辑性与实用性 :回答的步骤是否清晰、可操作? 合格率约 89% 。大部分回答质量很高,少数存在步骤顺序不合理或过于笼统的问题。
  • 格式规范性 :是否均为合法JSON? 合格率 100% 。这得益于审核智能体的严格把关和解析函数的容错处理。
  • 多样性 :问题场景是否重复? 在100条抽样中,高度相似的问题出现不超过5组,多样性控制得较好。

总体而言,这批数据的质量远超我的预期,完全达到了用于模型微调或RAG系统测试的基准要求。

5.2 成本与效益分析

  • 成本 :几乎是 零现金成本 。唯一的成本是家用电脑72小时的耗电(约几度电)。如果使用GPT-4等高级API生成1000多条类似结构的数据,成本将是数百元级别。
  • 效益 :获得了一个 高度定制化、隐私安全、格式规整 的专属数据集。节省了大量寻找、清洗、标注数据的时间。

5.3 项目扩展与优化方向

这次实验成功后,我看到了更多可能性:

  1. 多轮对话生成 :目前的流程是单轮QA。可以设计更复杂的流程,让“用户”智能体根据“助手”的回答进行追问,从而生成多轮对话树,这对于训练对话机器人更有价值。
  2. 引入外部知识库 :让“专业回答生成器”在生成答案前,先通过检索工具(如 ChromaDB + 本地文档)查询相关知识片段,使回答更具依据性和时效性,而不仅仅是依赖模型的内置知识。
  3. 强化质量审核 :可以引入一个基于规则或轻量级模型的“一致性检查”,确保回答中的关键步骤与提及的实体没有矛盾。
  4. 分布式生成 :如果有多台机器,可以在每台机器上运行一个独立的生成“船员”,由一个中央调度器分配主题,实现数据生成的横向扩展。

这次“自治数据集生成器”的构建,本质上是一次利用现有AI工具进行“自我增强”的实践。它证明了,在开源模型和智能体框架日益成熟的今天,开发者完全有能力以极低的成本,创造出解决自身核心瓶颈(数据)的工具。这个过程不仅给了我一个急需的数据集,更让我对智能体协同工作的潜力和挑战有了更深的理解。如果你也在为数据发愁,不妨试试这个思路,从一个小领域开始,搭建你自己的数据工厂。

更多推荐