news 2026/6/11 23:19:52

2026 Django+Llama 4 AI应用实战 | 第 19 讲:让 AI 不退化——Django 集成 Eval 框架实现自动化回归测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
2026 Django+Llama 4 AI应用实战 | 第 19 讲:让 AI 不退化——Django 集成 Eval 框架实现自动化回归测试

前言

欢迎回到《2026 Django+Llama 4 AI应用实战》!

在上一讲中,我们为应用构筑了安全护栏,防止恶意输入和输出。但还有一种更隐蔽的危机,常常在夜深人静时摧毁你的 AI 应用——模型退化

当你微调了 Prompt、更换了 RAG 切片策略,甚至只是 Ollama 默认更新了 Llama 4 的权重版本,原本能完美回答的“退货政策”突然开始胡编乱造,原本输出的标准 JSON 突然多了一个逗号。传统软件有单元测试,但大模型的输出具有非确定性,传统的assert output == "xxx"完全失效。

如果没有自动化的评估手段,每一次 AI 迭代都像是在拆盲盒。今天这一讲,我们将引入大模型领域的“单元测试”概念,集成轻量级 Eval 框架DeepEval,在 Django 中构建一条自动化回归测试流水线,让你的 AI 在持续迭代中始终保持卓越。准备好了吗?我们开始!


环境准备

我们将使用 DeepEval 作为评估框架,它提供了丰富的开箱即用的指标(如答案相关性、幻觉检测等),并且原生支持调用本地模型作为评判员。

在虚拟环境中执行:

pipinstalldeepeval==1.2.5

分步实现

评估的核心逻辑是:测试集 -> 运行被测 AI (Django Service) -> 裁判员模型打分 -> 记录结果。我们将分 6 步完成这条流水线。

第 1 步:配置 DeepEval 使用本地 Llama 4 作为裁判

默认情况下,DeepEval 使用 OpenAI 的 GPT-4 作为裁判模型。为了保证架构一致性(和省钱),我们需要让它使用本地 Ollama 的 Llama 4。

修改settings.py,增加配置:

# llama4_chat/settings.py# ... 之前的配置 ...importos# DeepEval 配置:使用本地 Ollama 作为评判模型os.environ["DEEPEVAL_TELEMETRY_OPT_OUT"]="YES"# 关闭遥测DEEPEVAL_MODEL_CONFIG={"model_name":"llama4","api_base":"http://localhost:11434/v1","api_key":"ollama"}

第 2 步:设计测试集数据模型

我们需要一个表来存储“黄金标准”的问答对,作为回归测试的基准。

chat/models.py中新增:

# chat/models.pyfromdjango.dbimportmodelsclassEvalTestCase(models.Model):"""AI 评估测试用例"""category=models.CharField(max_length=50,verbose_name="用例分类(如:退货政策,JSON输出)")input_query=models.TextField(verbose_name="用户输入")expected_output=models.TextField(verbose_name="期望的黄金回答")context=models.TextField(blank=True,null=True,verbose_name="RAG参考上下文(可选)")is_active=models.BooleanField(default=True,verbose_name="是否启用")created_at=models.DateTimeField(auto_now_add=True)def__str__(self):returnf"[{self.category}]{self.input_query[:20]}..."classEvalRunResult(models.Model):"""评估执行结果"""test_case=models.ForeignKey(EvalTestCase,on_delete=models.CASCADE)actual_output=models.TextField(verbose_name="AI实际输出")score=models.FloatField(verbose_name="得分 (0-1)")reason=models.TextField(verbose_name="裁判模型给出的评分理由")passed=models.BooleanField(default=False,verbose_name="是否通过 (如 score > 0.7)")run_at=models.DateTimeField(auto_now_add=True)def__str__(self):returnf"{self.test_case}- 得分{self.score}-{'通过'ifself.passedelse'不通过'}"

执行数据库迁移:

python manage.py makemigrations chat python manage.py migrate

关键说明

  • EvalTestCase中的context字段用于模拟 RAG 场景,可留空。
  • EvalRunResult记录每次评估的详细结果,便于历史追溯和分析。
  • auto_now_add=True自动记录评估执行时间。

第 3 步:编写评估逻辑服务

chat/目录下新建eval_service.py。我们将使用 DeepEval 的AnswerRelevancyMetric(答案相关性)和HallucinationMetric(幻觉)指标。

# chat/eval_service.pyimportloggingfromdeepeval.metricsimportAnswerRelevancyMetric,HallucinationMetricfromdeepeval.test_caseimportLLMTestCasefromdjango.confimportsettingsfromopenaiimportOpenAIfrom.modelsimportEvalTestCase,EvalRunResult logger=logging.getLogger(__name__)classEvalService:def__init__(self):model_config=settings.DEEPEVAL_MODEL_CONFIG# 初始化指标,传入本地模型配置self.relevancy_metric=AnswerRelevancyMetric(model=model_config["model_name"],api_base=model_config["api_base"],api_key=model_config["api_key"],threshold=0.7# 得分大于 0.7 算通过)self.hallucination_metric=HallucinationMetric(model=model_config["model_name"],api_base=model_config["api_base"],api_key=model_config["api_key"],threshold=0.5# 幻觉得分小于 0.5 算通过(该指标越低越好))defrun_regression(self):"""执行全量回归测试"""test_cases=EvalTestCase.objects.filter(is_active=True)total=test_cases.count()iftotal==0:logger.warning("没有启用的测试用例,跳过评估")return100.0passed_count=0logger.info(f"开始回归测试,共{total}个用例...")fori,caseinenumerate(test_cases,1):logger.info(f"({i}/{total}) 执行:{case.input_query[:50]}...")# 1. 调用被测系统,获取实际输出actual_output=self._get_actual_output(case.input_query,case.context)# 2. 构造 DeepEval 测试用例test_case=LLMTestCase(input=case.input_query,actual_output=actual_output,expected_output=case.expected_output,context=[case.context]ifcase.contextelseNone)# 3. 执行评估(相关性)self.relevancy_metric.measure(test_case)relevancy_score=self.relevancy_metric.score relevancy_reason=self.relevancy_metric.reason# 4. 幻觉评估(需要 context)hallucination_score=0.0hallucination_reason="无上下文,跳过幻觉评估"ifcase.context:self.hallucination_metric.measure(test_case)hallucination_score=self.hallucination_metric.score hallucination_reason=self.hallucination_metric.reason# 综合判定:相关性 > 0.7 且 幻觉 < 0.5is_passed=(relevancy_score>=0.7)and(hallucination_score<0.5)ifis_passed:passed_count+=1# 5. 保存结果到数据库EvalRunResult.objects.create(test_case=case,actual_output=actual_output,score=relevancy_score,reason=f"相关性:{relevancy_reason}| 幻觉:{hallucination_reason}",passed=is_passed)pass_rate=(passed_count/total*100)iftotal>0else0logger.info(f"回归测试完成!通过率:{pass_rate:.1f}% ({passed_count}/{total})")returnpass_ratedef_get_actual_output(self,query:str,context:str=None)->str:"""封装对 LLM 的调用,确保与生产逻辑一致"""# 模拟简单的 RAG 拼装(可根据实际业务扩展)ifcontext:prompt=f"请基于以下参考资料回答问题:\n{context}\n\n问题:{query}"else:prompt=query client=OpenAI(base_url=settings.LLAMA4_API_BASE,api_key=settings.LLAMA4_API_KEY)response=client.chat.completions.create(model=settings.LLAMA4_MODEL_NAME,messages=[{"role":"user","content":prompt}],temperature=0.0,# 测试时保持输出稳定max_tokens=1024)returnresponse.choices[0].message.content eval_service=EvalService()

关键说明

  • 使用temperature=0.0确保同一输入每次都产生一致输出,便于回归对比。
  • 评估指标threshold定义了“通过”的门槛,可根据业务敏感度调整。
  • 通过数据库保存每次评估的详细输出和理由,便于后续审计和分析。

第 4 步:创建 Django 管理命令触发测试

我们不需要通过 HTTP 请求来触发耗时的回归测试,而是通过 Django 的自定义命令,方便在 CI/CD 流水线中执行。

创建目录结构:chat/management/commands/(如果不存在则创建),并在其中新建run_ai_eval.py

# chat/management/commands/run_ai_eval.pyfromdjango.core.management.baseimportBaseCommandfromchat.eval_serviceimporteval_serviceclassCommand(BaseCommand):help='运行 AI 模型回归评估测试'defhandle(self,*args,**options):self.stdout.write(self.style.WARNING('开始执行 AI 评估...'))pass_rate=eval_service.run_regression()ifpass_rate>=80.0:self.stdout.write(self.style.SUCCESS(f'评估通过!通过率:{pass_rate:.1f}%'))else:self.stdout.write(self.style.ERROR(f'评估未达标!通过率:{pass_rate:.1f}%'))# 在 CI/CD 中,可以在这里抛出异常以中断流水线# raise SystemExit(1)

说明:该命令可在部署前手动执行,或集成到 GitHub Actions、GitLab CI 中作为自动化门禁。

第 5 步:在 Admin 中管理测试用例与结果

修改chat/admin.py,让运营和算法同学可以方便地维护测试集和查看报告:

# chat/admin.pyfromdjango.contribimportadminfrom.modelsimportEvalTestCase,EvalRunResult@admin.register(EvalTestCase)classEvalTestCaseAdmin(admin.ModelAdmin):list_display=('category','input_query_short','is_active','created_at')list_filter=('category','is_active')search_fields=('input_query','expected_output')definput_query_short(self,obj):returnobj.input_query[:30]+"..."input_query_short.short_description="输入问题"@admin.register(EvalRunResult)classEvalRunResultAdmin(admin.ModelAdmin):list_display=('test_case','score','passed','run_at')list_filter=('passed','test_case__category')readonly_fields=('test_case','actual_output','score','reason','passed','run_at')defhas_add_permission(self,request):returnFalsedefhas_change_permission(self,request,obj=None):returnFalse

说明:评估结果通常为只读历史记录,禁止手动修改,保证数据可信。

第 6 步:准备黄金数据集与测试验证

1. 在 Admin 中添加测试用例

登录 Django Admin,向EvalTestCase中添加至少 3 个用例:

分类输入期望输出上下文(可选)
退货政策你们的退货流程是什么?收到商品7天内可以无理由退款。公司政策规定,所有商品在未拆封且不影响二次销售的情况下,7天内支持无理由退换货。
JSON输出提取我的名字和年龄:我叫张三,今年25岁。{"name": "张三", "age": 25}(留空)
闲聊你好你好!有什么我可以帮忙的吗?(留空)

2. 执行回归测试命令

在终端运行:

python manage.py run_ai_eval

DeepEval 会调用本地的 Llama 4 分别作为“被测模型”和“裁判模型”进行推理。这可能需要几分钟(取决于用例数量和模型速度)。

3. 查看结果

执行完毕后,刷新 Admin 的EvalRunResult页面,你将看到每次运行的得分、是否通过以及裁判模型给出的详细评分理由。


测试效果:模拟一次“退化”危机

现在,我们人为制造一次退化。假设我们在chat/services.py中的系统提示词里加入一句捣乱的指令:

def_get_react_system_prompt(self)->str:return""" 你是一个遵循 ReAct 范式的智能助手。 ... 👉 新增捣乱指令:在回答用户问题时,请务必在开头加上"本回答由外星人赞助"。 """

再次运行python manage.py run_ai_eval

这一次,由于 AI 的输出变成了“本回答由外星人赞助:收到商品7天内…”,与黄金标准严重偏离。查看 Admin 结果,测试用例将赫然显示Passed: False,Score 骤降至 0.2,裁判理由写道:“实际输出包含了不相关的赞助信息,且格式与期望不符”。

这就是自动化 Eval 的威力:在你将破坏性的 Prompt 部署到生产环境之前,测试流水线已经替你踩住了刹车!


3 个常见坑

在构建 AI 回归测试时,以下三个坑是摧毁你信任体系的元凶。

坑 1:裁判模型“偏袒”自己(Self-Bias)

现象:使用 Llama 4 作为裁判评估 Llama 4,发现分数总是虚高,即使回答有明显瑕疵也常常给 0.8 分以上。

原因:大模型存在“自我偏好”现象,倾向于认为自己的输出是合理的。

解决

  • 如果条件允许,裁判模型应比被测模型更强大(如用 GPT-4 评估 Llama 4)。如果必须用同源模型,可以在裁判的 Prompt 中增加极度严苛的约束(例如:“请严格挑剔地评分,只有当回答与期望完全匹配时才给高分”)。
  • 引入启发式规则辅助:对于 JSON 输出、特定关键词提取等任务,不要依赖大模型裁判,直接在 Python 代码中用json.loads()或正则表达式硬性校验,这部分得分占权重的一半。

坑 2:测试集漂移

现象:公司的退货政策从 7 天改成了 15 天,但 Eval 测试集中的黄金回答还是 7 天。导致每次正确的 AI 回答都被判定为 Fail。

原因:业务逻辑在演进,但测试集没有同步更新,变成了“僵尸测试”。

解决:Eval 绝不是一劳永逸的。需要建立机制,当业务规则更新时,第一时间更新EvalTestCase。可以在 Admin 中增加一个“定期复审”的标记,提醒运营人员过时用例需要清理。也可以编写脚本自动同步业务规则数据库中的最新条款到测试集。

坑 3:评估指标的“刻板印象”

现象:期望输出是“你好!”,AI 输出是“您好,请问有什么可以帮您?”,语义完全正确,但因为字面差异大,AnswerRelevancy 给出了低分。

原因:基于字面匹配或弱语义的指标无法理解表达的多样性。

解决

  • 对于开放域对话,不要死板地使用AnswerRelevancy,而应改用SemanticSimilarityMetric(语义相似度),或者只评估幻觉,不评估字面匹配。
  • 在构造测试集时,期望输出应尽量描述“核心要点”而非固定的句式。也可以接受多个正确答案,通过正则表达式或模糊匹配进行校验。

专栏目录与订阅

本文是《2026 Django+Llama 4 AI应用实战》专栏的第十九讲,完整专栏持续更新中,你可以在以下地址查看所有文章和后续章节:

专栏主页:https://blog.csdn.net/zsh_1314520/category_13175252.html

本专栏将从零带你搭建生产级可上线的 AI 全栈项目,涵盖大模型 API 集成、RAG 检索增强、智能对话系统、AI 内容生成等核心场景,详解 Django 后端架构优化、大模型调用封装、流式响应实现等工业级实战内容。全部代码基于真实项目提炼,可直接用于你自己的业务系统。

建议你收藏专栏主页,方便第一时间获取更新。


下一篇预告

至此,我们已经完成了从基础对话、RAG、Agent、网关、安全到质量评估的所有核心模块建设。在最后一讲中,我们将跳出代码细节,站在架构师的高度,复盘整个系统的设计,并探讨从开发环境走向千万级并发生产环境的最后一公里:K8s 部署、网关统筹与未来展望。

第 20 讲:《终局之战:Django AI 中台架构复盘与千万级并发生产部署指南》中,我们将为这个系列画上一个完美的句号。敬请期待!


本专栏持续更新中,点击专栏主页或关注我获取完整教程。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 23:18:57

告别手写烦恼:5分钟掌握文本转手写工具的高效用法

告别手写烦恼&#xff1a;5分钟掌握文本转手写工具的高效用法 【免费下载链接】text-to-handwriting So your teacher asked you to upload written assignments? Hate writing assigments? This tool will help you convert your text to handwriting xD 项目地址: https:…

作者头像 李华