ClawdBot测试用例:编写pytest验证OCR识别准确率与翻译一致性
1. ClawdBot是什么:一个可本地运行的AI助手框架
ClawdBot不是某个具体模型,而是一个面向个人开发者的轻量级AI网关平台。它像一个智能调度中心,把不同能力模块(大语言模型、OCR引擎、语音转写、翻译服务)统一接入、编排和暴露为标准化接口。你不需要从零搭建LLM服务或维护OCR模型推理环境,ClawdBot帮你把底层复杂性封装好,只留下清晰、可配置、可测试的API边界。
它的核心价值在于“可控”——所有模型运行在你自己的设备上,数据不出本地;所有配置通过JSON文件或Web UI管理;所有能力模块支持热插拔替换。比如你想把默认的PaddleOCR换成更轻量的EasyOCR,或者把vLLM后端切换成Ollama,只需修改几行配置,无需改代码。
特别值得注意的是,ClawdBot本身不直接提供OCR或翻译能力,而是作为能力集成层,调用外部模型服务。在MoltBot这个典型应用中,ClawdBot正是承载了PaddleOCR图像文字识别、Whisper语音转写、LibreTranslate/Google Translate双引擎翻译等多模态能力的底座。因此,对ClawdBot的测试,本质上是对它如何正确调用、组合、传递和验证这些外部能力的测试。
这决定了我们的测试重点不是“OCR模型本身有多准”,而是“ClawdBot是否把图片正确送给了OCR、是否正确解析了OCR返回结果、是否把识别文本准确传给了翻译模块、最终输出是否语义一致”。
2. 为什么需要专门测试OCR与翻译的一致性
在MoltBot这类多模态机器人中,用户发来一张中文菜单照片,期望得到英文翻译结果。整个链路是:图片 → ClawdBot路由 → PaddleOCR识别 → 中文文本 → ClawdBot转发 → 翻译引擎 → 英文文本 → 返回用户。
这个看似简单的流程,中间有多个容易出错的环节:
- OCR识别错误:把“糖醋排骨”识别成“糖醋排骨”或“糖醋排骨”(少字/错字)
- 文本截断或编码异常:长文本被意外截断,或中文乱码导致翻译失败
- 翻译上下文丢失:OCR返回的是分段文本,但翻译时未合并上下文,导致“红烧”和“肉”被分开翻译
- 引擎fallback逻辑缺陷:当LibreTranslate失败时,未正确触发Google Translate备用路径
- 元数据污染:OCR结果附带了坐标、置信度等元信息,若未清洗干净就直接送入翻译,可能引发API报错
这些问题不会在单模块单元测试中暴露。PaddleOCR自己测得再准,如果ClawdBot把它识别出的{"text": "糖醋排骨", "confidence": 0.98}原样发给翻译API,而翻译服务只接受纯字符串,那整个流程就崩了。
所以,我们写的不是“OCR测试”或“翻译测试”,而是端到端的业务逻辑一致性测试:输入一张图,检查最终输出的翻译结果,是否忠实反映了原始图像中的文字语义。这要求测试用例必须覆盖真实场景下的典型输入,而非理想化数据。
3. 构建可复现的测试环境与数据集
pytest测试的生命力在于可复现。我们不能依赖线上OCR服务或网络翻译API,因为它们不可控、有配额、会变更。ClawdBot的设计哲学是“离线优先”,测试也必须遵循这一原则。
3.1 本地化依赖模拟
我们采用分层mock策略:
- 完全mock网络请求:使用
responses库拦截所有HTTP调用,确保测试不发任何真实网络请求 - 精准模拟OCR行为:不启动PaddleOCR,而是用预定义的映射表模拟其输出。例如:
OCR_MOCK_MAP = { "menu_chinese.jpg": {"text": "糖醋排骨\n宫保鸡丁\n麻婆豆腐", "confidence": 0.95}, "sign_english.png": {"text": "Exit Only\nNo Smoking", "confidence": 0.92}, "receipt_japanese.webp": {"text": "ラーメン 800円\nチャーハン 600円", "confidence": 0.88}, } - 翻译引擎双模模拟:LibreTranslate和Google Translate分别用不同规则模拟:
- LibreTranslate:对中文→英文,用内置词典做直译(“糖醋排骨”→“Sweet and Sour Pork”)
- Google Translate:加入少量意译和润色(“宫保鸡丁”→“Kung Pao Chicken, spicy stir-fried diced chicken with peanuts”)
这样,每次运行测试,输入同一张图,必然得到同一段OCR文本,再经同一翻译规则,得到完全确定的输出。测试结果100%可复现,且执行速度极快(毫秒级)。
3.2 构建最小但有效的测试图像集
我们不追求海量数据,而是精选5类高价值样本,覆盖OCR与翻译中最易出问题的场景:
| 图像文件名 | 核心挑战 | 预期OCR文本 | 预期翻译(中→英) |
|---|---|---|---|
menu_chinese.jpg | 中文菜名含生僻字、多音字 | “糖醋排骨\n宫保鸡丁\n麻婆豆腐” | “Sweet and Sour Pork\nKung Pao Chicken\nMapo Tofu” |
receipt_japanese.webp | 日文混合数字,OCR易漏字符 | “ラーメン 800円\nチャーハン 600円” | “Ramen ¥800\nFried Rice ¥600” |
sign_english.png | 英文大写+缩写,需保持格式 | “Exit Only\nNo Smoking” | “仅限出口\n禁止吸烟” |
handwritten_note.jpg | 手写体识别率低,测试容错 | “Meeting @3pm\ntomorrow” | “会议@下午3点\n明天” |
blurry_idcard.png | 模糊图像,OCR返回空或低置信度 | {"text": "", "confidence": 0.32} | 应触发错误处理,返回友好提示 |
这些图像全部存放在项目tests/data/目录下,作为测试fixture加载。每张图都经过人工校验,确保其“应有”的OCR结果是明确、无歧义的。
4. 编写核心pytest测试用例
现在进入实战。我们编写一个名为test_ocr_translation_consistency.py的测试文件,聚焦三个关键维度:准确性、鲁棒性、一致性。
4.1 准确性测试:验证标准场景下的端到端正确率
# tests/test_ocr_translation_consistency.py import pytest import responses from pathlib import Path from clawdbot.services.ocr import PaddleOCRService from clawdbot.services.translate import TranslationService # 模拟OCR服务响应 @responses.activate def test_ocr_translation_accuracy(): # 注册mock响应:当ClawdBot调用OCR API时,返回预设结果 responses.add( responses.POST, "http://localhost:8001/ocr", json={"text": "糖醋排骨\n宫保鸡丁", "confidence": 0.96}, status=200 ) # 注册mock响应:当调用翻译API时,返回预设译文 responses.add( responses.POST, "http://localhost:8002/translate", json={"translatedText": "Sweet and Sour Pork\nKung Pao Chicken"}, status=200 ) # 初始化服务(实际项目中由ClawdBot容器注入) ocr_service = PaddleOCRService() trans_service = TranslationService() # 模拟ClawdBot处理流程 image_path = Path("tests/data/menu_chinese.jpg") ocr_result = ocr_service.recognize(image_path) assert ocr_result["text"] == "糖醋排骨\n宫保鸡丁" assert ocr_result["confidence"] > 0.9 translated = trans_service.translate(ocr_result["text"], src="zh", tgt="en") assert "Sweet and Sour Pork" in translated assert "Kung Pao Chicken" in translated这个测试的价值在于:它不关心OCR模型内部怎么工作,只关心ClawdBot调用它时,是否能拿到正确的文本,并且这个文本能否被后续翻译模块正确消费。这是对接口契约的验证。
4.2 鲁棒性测试:验证异常情况下的系统韧性
真实世界充满噪声。一张模糊的身份证照片,OCR可能返回空字符串;一段含特殊符号的日文,翻译API可能报错。ClawdBot必须优雅处理,而不是崩溃或返回乱码。
# 续写 test_ocr_translation_consistency.py @responses.activate def test_ocr_low_confidence_handling(): # 模拟低置信度OCR结果 responses.add( responses.POST, "http://localhost:8001/ocr", json={"text": "", "confidence": 0.25}, status=200 ) ocr_service = PaddleOCRService() result = ocr_service.recognize(Path("tests/data/blurry_idcard.png")) # ClawdBot应拒绝将空文本送入翻译,并返回明确错误 assert result["text"] == "" assert result["confidence"] < 0.5 # 此处应触发ClawdBot的fallback逻辑,如重试或返回提示 @responses.activate def test_translation_fallback(): # 第一次LibreTranslate失败 responses.add( responses.POST, "http://localhost:8002/translate", json={"error": "Rate limit exceeded"}, status=429 ) # 第二次Google Translate成功 responses.add( responses.POST, "http://localhost:8003/translate", json={"translatedText": "Hello World"}, status=200 ) trans_service = TranslationService() # 模拟ClawdBot的fallback调用链 result = trans_service.translate("你好世界", src="zh", tgt="en", engines=["libre", "google"]) assert result == "Hello World" # 最终结果应来自备用引擎这类测试确保ClawdBot不是一条脆弱的流水线,而是一个有判断力的协调者。
4.3 一致性测试:验证多轮交互中的状态保持
MoltBot支持群聊中连续发送多张图片。ClawdBot需要记住用户上下文,比如上一张图是日文菜单,下一张是英文说明,翻译时应保持术语统一(“Ramen”不应一会儿译“拉面”,一会儿译“日式面条”)。
# 续写 test_ocr_translation_consistency.py def test_context_aware_translation(): # 模拟ClawdBot的会话上下文管理器 from clawdbot.core.context import SessionContext ctx = SessionContext(user_id="test_user_123") # 第一次:日文菜单 ctx.update_context("receipt_japanese.webp", "ラーメン 800円") # 第二次:同一用户发来英文说明,ClawdBot应关联上下文 ctx.update_context("explanation_en.png", "This is ramen.") # 检查上下文是否建立术语映射 assert ctx.get_term_mapping("ラーメン") == "Ramen" assert "Ramen" in ctx.get_context_summary()这超越了单次请求测试,触及ClawdBot作为“助手”的核心——它要理解对话,而不仅是处理孤立任务。
5. 将测试集成到ClawdBot开发工作流
写完测试不是终点,让它真正发挥作用才是关键。我们推荐三个实践:
5.1 一键运行与覆盖率报告
在pyproject.toml中配置pytest:
[tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] addopts = [ "--cov=clawdbot", "--cov-report=html", "--cov-report=term-missing", "-v" ]执行poetry run pytest tests/test_ocr_translation_consistency.py --html=report.html,即可生成带高亮的HTML覆盖率报告。重点关注clawdbot/services/ocr.py和clawdbot/services/translate.py两个文件,确保核心逻辑分支100%覆盖。
5.2 CI/CD中自动触发
在GitHub Actions的.github/workflows/test.yml中添加:
- name: Run OCR & Translation Consistency Tests run: | poetry run pytest tests/test_ocr_translation_consistency.py -x # 失败即中断,防止带bug的代码合入主干每次PR提交,CI都会自动运行这套测试。如果新代码破坏了OCR与翻译的衔接逻辑,测试立刻失败,开发者收到明确反馈。
5.3 作为文档与验收标准
这份测试文件本身就是一份活文档。它用代码明确定义了:
- ClawdBot对OCR服务的期望输入/输出格式
- 翻译引擎fallback的触发条件与顺序
- 低质量图像的处理策略
- 多轮对话中上下文管理的契约
当产品需求变更(例如“增加对韩文的支持”),第一件事就是更新这个测试文件,先写一个test_korean_ocr_support(),让它失败;然后编写代码,直到测试通过。这就是测试驱动开发(TDD)在AI工程中的落地。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。