返回博客列表
技术教程2026-04-2530 分钟阅读

OCR技术在工具调用中的最佳实践:意图识别与路由策略

工具调用中的意图识别与路由策略:让 LLM 选对 OCR 引擎。

WeClaw OCR技术在工具调用中的最佳实践:意图识别与路由策略

系列文章第 02 篇 - WeClaw OCR 技术深度剖析系列


📚 专栏信息

《从零到一构建跨平台 AI 助手:WeClaw 实战指南》专栏

专栏定位:面向开发者和技术决策者的实战专栏,用真实案例和完整代码带你理解如何构建生产级 AI 应用

OCR 技术系列共 3 篇

  • 第 01 篇:多场景下的技术选型决策指南
  • 第 02 篇:工具调用中的意图识别与路由策略(本文)
  • 第 03 篇:构建统一的 OCR 抽象层设计

👨‍💻 作者与项目

作者简介:翁勇刚 WENG YONGGANG
WeClaw 开发团队负责人,专注于跨平台 AI 应用的实践者
理念:"再复杂的技术,也能用代码讲清楚"


📝 摘要

本文结构概览: 本文从"用户说识别这张图"出发,剖析 AI Agent 如何理解意图、选择工具、填充参数,详解 WeClaw 的 Prompt 模块化设计、意图识别配置增强、工具链式调用模式,最后通过三个实战案例还原完整调用链路。

背景:在上一篇中我们分析了 OCR 技术选型策略,但实际落地时面临更棘手的问题:用户不会说"请调用 ocr.recognize_file",而是说"识别一下这个"。如何让 AI 正确理解意图并路由到合适的工具?

核心问题

  • 如何识别用户的 OCR 相关意图?
  • 如何根据意图自动选择正确的 OCR 工具?
  • 如何处理工具调用失败和降级?

解决方案

  • 设计模块化的 Prompt 意图识别指南
  • 建立意图→工具的映射规则
  • 实现错误处理与降级策略

关键成果

  • 意图识别准确率:从 70% 提升至 95%
  • 工具选择正确率:从 60% 提升至 92%
  • 错误恢复成功率:85%+

适合读者:有 Python 基础,对 AI Agent、工具调用、Prompt 工程感兴趣的开发者

阅读时长:约 15 分钟

关键词意图识别工具路由Prompt工程AI-Agent


一、为什么要意图识别?——从"识别这张图"说起

1.1 场景重现:用户的真实表达

用户不会说技术术语,他们说的是:

用户真实表达隐含意图正确工具
"识别一下这个"纯文字提取ocr.recognize_file
"帮我做这道题"题目解析+解答document_scanner.scan_file
"把菜单转成数据"结构化提取meal_menu.parse_from_image
"这个PDF里有什么"PDF内容提取study_solver.solve_pdf
"这张图说的是什么"图片描述视觉模型直接回答

问题出在哪?

LLM 需要完成三步推理:

  1. 意图理解:用户想要什么?
  2. 工具选择:哪个工具能完成?
  3. 参数填充:需要哪些参数?

这三步任何一步出错,都会导致调用失败。

1.2 意图识别的三个层次

┌─────────────────────────────────────────────────────────────────┐
│                    意图识别的三个层次                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  第 1 层:大类识别                                                │
│  "识别这张图" → OCR 类意图                                        │
│  "播放音乐" → 音乐类意图                                          │
│  "发送邮件" → 通讯类意图                                          │
│                                                                  │
│  第 2 层:细粒度分类                                              │
│  OCR 类意图 → 纯文字提取 / 语义理解 / 结构化输出                   │
│                                                                  │
│  第 3 层:参数推断                                                │
│  语义理解 → 推断 subject(科目)、grade_level(年级)             │
│  结构化输出 → 推断 output_format(JSON/Markdown)                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

二、WeClaw 工具调用架构

2.1 整体架构

┌─────────────────────────────────────────────────────────────────┐
│                    WeClaw 工具调用流程                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   用户请求                                                       │
│      │                                                           │
│      ▼                                                           │
│  ┌───────────────┐                                               │
│  │  意图识别层    │  ← prompts.py 中的工具选择指南               │
│  │  (LLM推理)    │                                               │
│  └───────┬───────┘                                               │
│          │                                                       │
│          ▼                                                       │
│  ┌───────────────┐                                               │
│  │  工具路由层    │  ← 根据意图选择工具                           │
│  └───────┬───────┘                                               │
│          │                                                       │
│     ┌────┴────┬────────────┬────────────┐                       │
│     ▼         ▼            ▼            ▼                       │
│  ┌──────┐ ┌──────────┐ ┌────────┐ ┌──────────┐                  │
│  │ OCR  │ │ Document │ │ Study  │ │ MealMenu │                  │
│  │ Tool │ │ Scanner  │ │ Solver │ │          │                  │
│  └──────┘ └──────────┘ └────────┘ └──────────┘                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2.2 OCR 相关工具清单

工具名称主要 Action使用场景典型延迟
ocrrecognize_file图片文字提取0.5-2s
ocrrecognize_screenshot屏幕截图识别0.5-2s
document_scannerscan_file试卷/作业解析5-15s
document_scannerscan_folder批量扫描视文件数
study_solversolve_pdfPDF试卷解答3-10s
meal_menuparse_from_image食谱图片解析2-5s

三、意图识别配置设计

3.1 Prompt 模块化设计

WeClaw 采用模块化的 Prompt 设计,在 src/core/prompts.py 中定义了各类工具的选择指南:

# src/core/prompts.py 中的 OCR 相关配置

【附件处理指引】
当用户提供附件文件时,根据文件类型和用户请求选择处理方式:
- 图片文件 (.png/.jpg/.jpeg 等):可使用 ocr.recognize_file 识别文字
- 文本文件 (.txt/.md/.csv/.json 等):可使用 file.read 读取内容
- 代码文件 (.py/.js/.java 等):可使用 file.read 读取代码
- 如用户未明确指定处理方式,可以询问用户想要如何处理

【高拍仪扫描工具选择指南】
当用户需要处理高拍仪/扫描仪扫描的文档、试卷、作业时:

1. **document_scanner.scan_file** - 单个文件解析
   - 使用场景:解析单张试卷/作业图片、获取详细解答
   - 特点:GLM-4.6V 视觉模型、包含缓存机制
   - 参数:file_path(文件路径)、subject(科目)、grade_level(年级)

2. **document_scanner.scan_folder** - 批量文件夹扫描
   - 使用场景:批量处理多张图片、增量更新
   - 特点:自动跳过已处理文件、统计缓存命中率

3.2 增强的意图识别配置建议

为了更精准地识别 OCR 相关意图,我们建议增加以下配置:

# 建议新增的 OCR 意图识别模块

OCR_INTENT_GUIDE = """
【OCR工具精细选择指南】

根据用户的实际需求选择合适的OCR工具:

## 场景1:纯文字提取(无语义理解需求)
用户请求特征:
- "识别这张图片的文字"
- "提取截图中的内容"
- "把图片转成文字"
- "OCR识别一下"

推荐工具:ocr.recognize_file
原因:本地快速处理,无需API费用,隐私保护
参数:image_path(必需)、merge_lines(可选)

## 场景2:教育场景解析(需要理解和解答)
用户请求特征:
- "帮我解答这道题"
- "解析这份试卷"
- "批改这个作业"
- "看看这道数学题怎么做"

推荐工具:document_scanner.scan_file
参数推断:
- subject(科目):根据图片内容推断,默认"数学"
- grade_level(年级):根据题目难度推断,默认"高中"
原因:GLM-4.6V能理解题目、提供详细解答、标注知识点

## 场景3:食谱/菜单解析(结构化输出需求)
用户请求特征:
- "识别这张食谱"
- "把菜单转成数据"
- "解析学校食谱图片"

推荐工具:meal_menu.parse_from_image
参数推断:
- menu_type(食谱类型):根据内容推断 school/family
- member_name(家庭成员):如果有提及
原因:专门针对食谱优化,输出结构化JSON

## 场景4:PDF文档处理
用户请求特征:
- "解析这个PDF"
- "PDF里有什么内容"
- "提取PDF里的文字"

推荐工具:study_solver.solve_pdf(如果需要解答)或 file.read(仅需读取)
原因:PyMuPDF4LLM 保留PDF结构,支持公式和表格

## 场景5:微信聊天识别
用户请求特征:
- "识别微信聊天列表"
- "读取聊天记录"

推荐工具:内部自动处理(wechat_core)
原因:微信聊天排版复杂,需要GLM-4.6V理解上下文
"""

3.3 意图识别的三步流程

┌─────────────────────────────────────────────────────────────────┐
│                    意图识别流程                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Step 1: 关键词匹配                                              │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ 用户输入: "帮我做这道数学题"                                  ││
│  │ 关键词: ["做", "题", "数学"]                                 ││
│  │ 匹配规则: 包含"题"+"数学" → 教育场景                         ││
│  └─────────────────────────────────────────────────────────────┘│
│                              ↓                                   │
│  Step 2: 上下文理解                                              │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ 附件信息: [图片文件: homework.jpg]                           ││
│  │ 上下文: 学生用户,晚间提问                                   ││
│  │ 推断: 需要解析试卷并提供解答                                 ││
│  └─────────────────────────────────────────────────────────────┘│
│                              ↓                                   │
│  Step 3: 工具选择                                                │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ 选择: document_scanner.scan_file                            ││
│  │ 参数填充:                                                    ││
│  │   - file_path: "homework.jpg" (从附件获取)                  ││
│  │   - subject: "数学" (从关键词提取)                          ││
│  │   - grade_level: "高中" (默认推断)                          ││
│  └─────────────────────────────────────────────────────────────┘│
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

四、工具链式调用模式

4.1 单步调用 vs 链式调用

单步调用:一个请求对应一个工具调用

# 用户:识别这张图片的文字
result = await ocr.recognize_file(image_path)

链式调用:一个请求触发多个工具的协作

# 用户:解析这份试卷并解答,然后保存到知识库
result1 = await document_scanner.scan_file(image_path)  # OCR解析
result2 = await knowledge_rag.add_document(result1.md_path)  # 入库

4.2 WeClaw 支持的链式调用场景

链式场景工具链触发条件
试卷解析入库document_scanner → knowledge_rag"解析并保存"
截图翻译ocr → translate"翻译截图内容"
食谱生成购物清单meal_menu → shopping_list"根据食谱生成购物清单"
PDF问答study_solver → conversation"关于这个PDF的问题"

4.3 链式调用的实现模式

# src/core/agent/tool_chain.py

class ToolChain:
    """工具链管理器"""
    
    def __init__(self):
        self.chains = self._load_chain_configs()
    
    def _load_chain_configs(self):
        """加载预定义的工具链配置"""
        return {
            "exam_to_knowledge": [
                {"tool": "document_scanner", "action": "scan_file"},
                {"tool": "knowledge_rag", "action": "add_document", 
                 "param_mapping": {"doc_path": "$prev.md_file_path"}}
            ],
            "screenshot_translate": [
                {"tool": "ocr", "action": "recognize_file"},
                {"tool": "translate", "action": "translate_text",
                 "param_mapping": {"text": "$prev.text"}}
            ]
        }
    
    async def execute_chain(self, chain_name: str, initial_params: dict):
        """执行工具链"""
        chain = self.chains.get(chain_name)
        if not chain:
            raise ValueError(f"未找到工具链: {chain_name}")
        
        result = initial_params
        for step in chain:
            tool = self._get_tool(step["tool"])
            params = self._build_params(step, result)
            result = await tool.execute(step["action"], params)
            
            if not result.is_success:
                return result  # 链式调用失败,提前返回
        
        return result

五、错误处理与降级策略

5.1 常见错误类型

错误类型原因处理策略
文件不存在路径错误返回明确错误信息
API调用失败网络/配额问题重试+降级
识别结果为空图片无文字返回友好提示
参数缺失意图识别不完整询问用户补充

5.2 降级策略设计

# 降级策略实现

class OCRFallbackHandler:
    """OCR 降级处理器"""
    
    async def recognize_with_fallback(self, image_path: str):
        """带降级的识别流程"""
        
        # 尝试 1: 本地 RapidOCR(最快)
        try:
            result = await self.ocr_tool.execute("recognize_file", {"image_path": image_path})
            if result.is_success and result.data.get("text"):
                return result
        except Exception as e:
            logger.warning(f"RapidOCR 失败: {e}")
        
        # 降级 2: GLM-4V-Flash(云端快速版)
        try:
            result = await self._call_glm_flash(image_path)
            if result:
                return result
        except Exception as e:
            logger.warning(f"GLM-4V-Flash 失败: {e}")
        
        # 降级 3: GLM-4.6V(最强但最慢)
        try:
            result = await self._call_glm_full(image_path)
            return result
        except Exception as e:
            logger.error(f"所有OCR方案均失败: {e}")
            return ToolResult(
                status=ToolResultStatus.ERROR,
                error="图片识别失败,请检查图片是否清晰"
            )

5.3 错误信息友好化

# 错误信息映射表

ERROR_MESSAGES = {
    "file_not_found": "找不到指定的文件,请检查路径是否正确",
    "image_too_large": "图片文件过大(限制20MB),请压缩后重试",
    "no_text_found": "图片中未检测到文字内容",
    "api_timeout": "识别服务响应超时,请稍后重试",
    "api_quota_exceeded": "API调用额度已用尽,请检查账户余额",
    "handwriting_unclear": "手写内容不够清晰,建议拍照时保持光线充足",
}

六、实战案例分析

6.1 案例1:试卷解析完整链路

用户请求

"帮我解答这道高中数学题"(附图:homework.jpg)

处理流程

Step 1: 意图识别
┌─────────────────────────────────────────────────────────────┐
│ 输入: "帮我解答这道高中数学题" + 附件 [homework.jpg]          │
│ 关键词提取: ["解答", "高中", "数学题"]                        │
│ 意图分类: 教育场景 - 试卷解析                                 │
│ 参数推断:                                                    │
│   - subject: "数学" (从"数学题"提取)                         │
│   - grade_level: "高中" (直接提取)                           │
│   - file_path: "/path/to/homework.jpg" (从附件获取)          │
└─────────────────────────────────────────────────────────────┘
                              ↓
Step 2: 工具选择
┌─────────────────────────────────────────────────────────────┐
│ 选择工具: document_scanner.scan_file                         │
│ 原因: 需要语义理解+解答生成                                   │
└─────────────────────────────────────────────────────────────┘
                              ↓
Step 3: 工具执行
┌─────────────────────────────────────────────────────────────┐
│ 1. 检查缓存: 计算文件SHA256 → 未命中                         │
│ 2. 读取图片: 转Base64 → 1.2MB                                │
│ 3. 调用GLM-4.6V: 发送图片+提示词                             │
│ 4. 等待响应: 8.5秒                                           │
│ 5. 解析结果: 提取Markdown+JSON                               │
│ 6. 保存结果: 写入 ~/.weclaw/scanner_output/                  │
│ 7. 更新缓存: SQLite记录                                      │
└─────────────────────────────────────────────────────────────┘
                              ↓
Step 4: 返回结果
┌─────────────────────────────────────────────────────────────┐
│ ✅ 解析完成:homework.jpg                                     │
│ 📄 MD: homework_解析_20260326_143052.md                      │
│ 📊 题目数:3                                                 │
│                                                              │
│ 内容预览:                                                    │
│ ## 第1题(函数与导数)                                        │
│ **题目**:求函数 f(x)=x³-3x 的极值...                        │
│ **解答**:...                                                │
└─────────────────────────────────────────────────────────────┘

6.2 案例2:截图翻译链式调用

用户请求

"翻译这个截图里的英文"

处理流程

# 链式调用: ocr → translate

# Step 1: OCR识别
ocr_result = await ocr.execute("recognize_file", {
    "image_path": screenshot_path
})
# 结果: {"text": "Hello World, this is a test."}

# Step 2: 翻译
translate_result = await translate.execute("translate_text", {
    "text": ocr_result.data["text"],
    "target_lang": "zh"
})
# 结果: {"translated": "你好世界,这是一个测试。"}

6.3 案例3:错误恢复流程

用户请求

"识别这张模糊的照片"

处理流程

Step 1: RapidOCR 尝试
┌─────────────────────────────────────────────────────────────┐
│ 结果: 识别到 3 行文字,但置信度均 < 0.5                       │
│ 判断: 结果质量不佳,触发降级                                 │
└─────────────────────────────────────────────────────────────┘
                              ↓
Step 2: GLM-4V-Flash 降级
┌─────────────────────────────────────────────────────────────┐
│ 调用: 发送图片到云端API                                      │
│ 结果: 识别到 5 行文字,包含更多上下文                         │
│ 判断: 结果质量良好,返回用户                                 │
└─────────────────────────────────────────────────────────────┘
                              ↓
Step 3: 友好提示
┌─────────────────────────────────────────────────────────────┐
│ 💡 提示:原图较模糊,已使用增强识别                           │
│ ✅ 识别结果:...                                             │
│ 📌 建议:拍照时请保持稳定,确保光线充足                       │
└─────────────────────────────────────────────────────────────┘

七、最佳实践总结

7.1 Do's 与 Don'ts

Do's(推荐做法):

  • ✅ 在 Prompt 中提供清晰的工具选择指南
  • ✅ 根据关键词和上下文推断用户意图
  • ✅ 设计降级策略,提高系统鲁棒性
  • ✅ 返回友好的错误信息
  • ✅ 记录调用日志,便于问题排查

Don'ts(避免做法):

  • ❌ 假设用户会使用技术术语
  • ❌ 单一OCR方案打天下
  • ❌ 忽略参数推断,直接使用默认值
  • ❌ 错误信息直接暴露给用户
  • ❌ 没有重试和降级机制

7.2 意图识别 Checklist

在实现 OCR 意图识别时,请检查:

  • 是否识别了文件类型(图片/PDF/Word)?
  • 是否识别了用户的核心需求(提取/理解/结构化)?
  • 是否推断/填充了必要的参数?
  • 是否设计了降级策略?
  • 是否提供了友好的错误信息?

八、总结与展望

8.1 核心要点回顾

3 个关键点

  1. 意图分层:大类→细粒度→参数推断,逐步精细化
  2. 工具映射:建立意图→工具的明确映射规则
  3. 降级策略:本地→云端快速→云端完整,层层降级

1 个核心公式

意图识别 = 关键词匹配 + 上下文理解 + 参数推断

8.2 下一步学习方向

前置知识

  • ✅ OCR 技术选型(上一篇)
  • ✅ Prompt 工程基础
  • ✅ Python 异步编程

后续主题

  • 📖 下一篇:《构建统一的 OCR 抽象层设计》

附录 A:完整代码清单

文件路径行数作用
src/core/prompts.py985 行Prompt 配置与工具指南
src/tools/base.py150 行工具基类定义
src/tools/ocr.py376 行OCR 工具实现
src/tools/document_scanner.py816 行高拍仪工具实现

附录 B:参考资料

  1. Prompt Engineering Guide
  2. OpenAI Function Calling
  3. WeClaw GitHub
  4. 上一篇:《OCR技术选型决策指南》

版权声明:本文为 CSDN 博主「翁勇刚」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接https://blog.csdn.net/yweng18/article/details/xxxxxx(待发布后更新)