
把手机拍一道数学题几秒之后屏幕上出现的不只是答案还有完整步骤和易错点——这不是某个商业 App 的演示视频而是我用 DeepSeek 和 Dify 自己搭出来的智能拍照解题流程。今天把整个过程拆开讲透从 Dify 本地部署、DeepSeek 模型接入到 OCR 识别、Prompt 编写、工作流配置和常见报错排查你都能拿到一套可以直接复现的方案。整套方案适合三类人正在折腾 Dify 工作流的开发者想给家庭 NAS 或服务器加一个实用 AI 服务的爱好者还有做教育工具产品、需要快速做 PoC 验证的团队。1. 为什么是“DeepSeek Dify”这个组合解决什么问题1.1 拍照解题需求的真正难点拍照解题看起来很简单拍一张图识别文字丢给大模型。但真正做过就会发现问题全藏在细节里。首先OCR 识别出来的文字往往是乱的。拍试卷时会有反光、倾斜、手写字迹还有公式上下标。直接把 OCR 原文丢给大模型它会把“x²”识别成“x2”把“∫”识别成“f”推理结果自然就跑偏。更麻烦的是一道解答题通常包含题干、小问、已知条件OCR 结果里这些内容混在一起必须做结构化清洗。其次解题不是简单的“给答案”。学生需要的是步骤、是为什么这样做、是同类题怎么举一反三。这就意味着不能只调一次大模型就结束而是要做多步推理先理解题目类型再规划解题思路最后生成解析。这个过程如果用普通代码硬写判断逻辑又多又脆如果用单次 Prompt 硬怼输出质量又不稳定。第三数据链路问题。图片存储在哪儿、OCR 服务用哪个、结果怎么回传、失败时怎么重试这些在 Demo 里可以忽略落地上全是坑。1.2 DeepSeek 负责“聪明”Dify 负责“流程”这个项目里DeepSeek 和 Dify 的分工非常清晰。DeepSeek 提供推理能力Dify 提供流程编排和工程化能力。DeepSeek 的 API 走 OpenAI 兼容协议接入成本极低。而且它的数学推理表现和中文理解能力都在线尤其适合做解题这类强逻辑任务。价格也比主流闭源模型便宜不少跑大量 OCR 结果推理时成本压力小很多。想要数据完全不出内网还能通过 Ollama 本地部署 DeepSeek 模型Dify 会把它当作一个模型供应商来接入。Dify 解决的是工程问题。它提供了可视化工作流编排、变量管理、知识库、日志追踪和 API 开放能力。以前写一个解题服务要自己写 Flask 接口、Redis 队列、Prompt 管理后台现在在 Dify 里拉几个节点就能串起来。Dify 还能将工作流导出为 DSL 文件迁移、备份、版本管理都很方便这点对长期维护很重要。我选择这个组合还有一个现实原因Dify 是开源项目社区版可以本地部署数据不经过第三方平台DeepSeek 也支持本地模型。这样整套系统既能用云端 API 快速跑通也能在敏感场景下完全离线运行。2. 落地前的环境准备Dify 和 DeepSeek 的部署与接入2.1 先用 Docker 把 Dify 跑起来Dify 的部署方式很多最省心的是 Docker Compose。我自己的服务器是 8 核 16G 内存跑 Dify 加 OCR 服务完全没压力。如果你用的是飞牛 NAS 这类家庭设备只要支持 Docker同样能跑就是把内存尽量给足建议不低于 8G。官方推荐的方式是拉取源码仓库里的 docker 目录来启动git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d第一次启动会拉取多个镜像包括 API 服务、Worker、PostgreSQL、Redis、Sandbox 和 Nginx耐心等一会。启动完成后访问服务器 IP 的 80 端口会进入安装引导设置管理员邮箱和密码。装好之后建议做两件事一是改默认端口避免和其他服务冲突改.env里的NGINX_PORT二是确认持久化目录Docker 卷通常会落在/var/lib/docker/volumes下做备份前先搞清楚数据在哪。如果你不想用 Docker 编排也可以按官方文档手动部署。但我个人建议直接用 Docker Compose因为 Dify 依赖的中间件多手动装容易漏版本后续升级也麻烦。我用下来最顺的升级方式就是拉最新源码后执行docker compose pull docker compose up -d再跑一次迁移脚本。整个过程我在线上试过多次只要没有本地改过容器配置基本不会出问题。2.2 接入 DeepSeek 的两种方式云端 API 与本地模型DeepSeek 的接入分两种场景。第一种是直接用云端 API。先去 DeepSeek 开放平台注册账号、创建 API Key然后记住两个关键值模型名用deepseek-chatBase URL 用https://api.deepseek.com。它兼容 OpenAI 的接口协议所以在 Dify 里配置起来非常快。第二种是本地部署。用 Ollama 跑 DeepSeek 模型适合数据敏感、或需要完全离线运行的场景。命令很简单ollama run deepseek-r1:7b模型跑起来后在 Dify 的模型供应商里选择 Ollama填上 Ollama 服务地址默认是http://localhost:11434模型名对应填deepseek-r1:7b即可。需要注意Ollama 默认只监听本机地址如果 Dify 和 Ollama 不在同一台机器要设置环境变量OLLAMA_HOST0.0.0.0并开放防火墙端口。本地小模型在复杂解答题上的表现会弱于云端大模型所以我的建议是日常测试用本地模型追求效果时切换到云端 API。另外提一句目前不少国内云平台也转售 DeepSeek 的 API比如硅基流动这类服务商。它们的协议和 DeepSeek 官方一样也可以作为 Dify 模型供应商的备选。切换时只需改 Base URL 和 API Key工作流不用动。2.3 模型供应商配置与凭证校验的坑在 Dify 后台左侧菜单进入“设置 - 模型供应商”找到 DeepSeek填入 API Key。填完点保存正常会提示“校验成功”。但如果这一步就报an error occurred during credentials validation通常不是 Dify 的问题而是 Key 本身的问题。遇到凭证校验失败先按顺序排查确认 API Key 没有复制多余空格确认账号余额是否充足新注册账号没充值也可能会导致鉴权失败确认网络到 DeepSeek API 是否通畅。如果 Dify 部署在企业内网还要检查出口防火墙是否放行api.deepseek.com的 HTTPS 请求。有一个细节容易被忽略Dify 的模型供应商页面里有“自定义 API 端点”的选项。如果你用了代理网关或者中转服务一定要把 Base URL 填对并且确认协议是https://。我试过因为手滑把 URL 写成http://导致 Dify 去调一个不存在的明文接口报错信息非常误导人排查了半天才发现是协议写错了。说完 API Key再提醒一个后台管理相关的坑Dify 安装完成后连续输错管理员密码会被锁定提示too many incorrect password attempts. please try again later.。这不是 Bug而是防暴力破解的机制。遇到这个提示别硬试等锁定时间过了再登录如果忘了密码直接进 PostgreSQL 容器重置用户密码比反复尝试高效得多。3. 智能拍照解题核心工作流设计与实现3.1 工作流整体设计一张图看懂节点编排Dify 里可以创建两种应用Chatflow 和 Workflow。拍照解题这个场景我推荐用 Workflow因为它的执行路径固定上传图片 - 识别 - 清洗 - 推理 - 输出。Workflow 的逻辑更清晰便于调试和追踪每一步的输入输出。整个工作流包含八个核心节点开始节点、OCR 调用节点、条件分支节点、代码节点、知识库检索节点、LLM 节点、变量赋值节点、结束节点。下面我把每个节点的作用讲清楚。开始节点接收一个图片文件变量。Dify 的文件变量类型支持上传图片也可以把整张试卷图片作为输入。这里要注意如果你打算直接调用需要临时 URL 的 OCR 服务需要在开始节点把“文件类型”设为图片并在下游节点通过文件变量获取下载路径。条件分支节点很关键。OCR 识别可能会失败比如图片太暗、文字太小、拍的是空白区域。我习惯在 OCR 之后马上加一个条件判断识别文本为空或文本长度小于阈值就进入失败处理节点返回“请重新拍摄”的提示识别成功才进入后续推理路径。这样能避免把垃圾文本送到大模型既省 Token 又提升回答质量。LLM 节点是整个工作流的大脑。这里填 DeepSeek 模型专门负责解题推理。其余环节比如 OCR 格式整理、答案 JSON 解析尽量用代码节点处理不要交给大模型原因很简单代码处理是确定性的大模型处理是概率性的。能确定的事不要赌概率。3.2 OCR 节点让图片变成可处理的文本OCR 是这个项目最容易翻车的一环。我建议不要把 OCR 能力内置到 Dify 里而是通过一个外部服务接口来调用。Dify 的 HTTP 请求节点可以很方便地请求外部 API。第一步确认图片链接。Dify 文件变量默认会生成临时访问链接在 HTTP 请求节点里可以用{{#node.file.url#}}引用。如果你用的 OCR 服务要求公网可访问的图片 URL而 Dify 部署在内网就要把图片转成 Base64 直接提交给服务。目前主流 OCR API 基本都支持 Base64 传输优先选这种方式省去内网穿透的麻烦。第二步设置请求参数。我用的是一个通用 OCR API请求格式类似POST /ocr { image_base64: data:image/jpeg;base64,..., language_type: CHN_ENG, detect_direction: true }如果验签逻辑比较复杂建议在 Dify 里写一个代码节点生成签名参数再传给 HTTP 请求节点。把签名逻辑放在代码里比在大模型 Prompt 里折腾要可靠得多。第三步处理返回结果。OCR 服务返回的通常是按位置排列的文本块我们需要按照从上到下、从左到右的顺序拼接成完整文本。这一步可以用代码节点处理把结果按坐标排序逐行拼接顺便去掉多余的空格和换行。这个清洗过程直接决定后面大模型的推理质量。3.3 变量赋值与数据清洗把 OCR 结果整理成能用的题目Dify 的变量赋值节点很多人用得少其实它是流程可控性的关键。在这个项目里我用变量赋值节点维护三个核心变量raw_textOCR 原始文本、cleaned_text清洗后文本、question_type题目类型。先看代码节点里做清洗时发生了什么。OCR 输出的“x2 3x 0”很可能被识别成“x23x0”手写体还会把“5”识别成“6”。常规的正则替换能解决一部分问题比如把x2改成x^2、把全角符号转半角。但复杂公式的还原说实话很难靠规则解决。我的处理策略是分两级第一级在代码节点里做基础清洗第二级在 LLM 推理时让模型自行纠正 OCR 错误。比如 Prompt 里明确写“以下文本来自 OCR 识别可能存在字符错误请结合数学语义判断并修正。”实测下来DeepSeek 对常见 OCR 误识别的纠错能力很强。题目分类放在代码节点里完成用关键词匹配即可。出现“若”“证明”“求”这类词归为解答题出现“A. B. C. D.”归为选择题出现“填空”“等于”这类词归为填空题。分类结果存到question_type后面 LLM 节点根据这个变量走不同的推理模式。顺便说一个我在变量赋值上的常见错误Dify 变量有类型限制如果你把代码节点输出的对象直接赋给字符串变量下游 LLM 引用时会显示为空。解决办法是在代码节点里先String(result)或者JSON.stringify(result)再赋给变量。3.4 核心 LLM 推理节点手写一份可复用的解题 PromptLLM 节点的 Prompt 设计是拍题解题质量的分水岭。我的核心思路是不让模型自由发挥而是给它一个强结构化的输出框架。针对不同题型Prompt 要分版本。选择题要求输出答案和每个选项的对错原因填空题要求先推导再填解答题要求按“思路分析 - 详细步骤 - 最终答案 - 易错点”四段结构输出。在实际工作流里我用条件分支节点根据question_type选择对应的 Prompt 模板。下面这个是解答题的 Prompt 模板可以直接抄你是一位严谨的数学老师。请解决下面这道题。 题目来源于 OCR 识别请先结合数学语义修正可能的识别错误。 题目文本 {{#node.cleaned_text#}} 题目类型解答题 要求 1. 先用一段话概括题目考察的知识点。 2. 给出解题思路不需要直接写答案。 3. 逐步推导每一步必须给出依据。 4. 最后用一行写出最终答案。 5. 输出为 JSON 格式字段为 { knowledge_point: ..., thinking: ..., steps: [..., ...], answer: ..., pitfall: ... }把输出定义成 JSON 非常关键。这样结束节点可以直接解析并展示也方便后续做客服系统对接或者生成 HTML 页面。为了让 JSON 输出稳定我在模型参数里把 temperature 调到 0.1减少随机性。DeepSeek 的deepseek-chat模型对 JSON 输出的遵循度很高基本不会跑偏。另外如果你开启的是 Agent 模式而不是 Workflow可能会遇到一种报错提示deepseek messages tool calls need immediate results。这个问题的本质是模型发起了工具调用指令但工作流没有立刻把工具结果回传给模型模型等不到返回一轮对话就被判定失败。我的建议是解题这种固定流程不要用 Agent 的自主工具调用模式改用 Workflow 把每一步都固定下来彻底绕开这个不稳定因素。3.5 结束节点与结果输出格式结束节点负责把 LLM 输出整理成用户能直接看的内容。如果 LLM 节点输出的字段是 JSON 字符串这里可以用代码节点JSON.parse()之后再拼接成 Markdown 文本返回。我习惯返回三段式第一段“答案”直接显示最终答案第二段“解题步骤”用有序列表展示步骤第三段“考点分析”把knowledge_point和pitfall合并。这样前端拿到一个 Markdown 字符串直接渲染即可。结束节点的返回类型选择“文本”变量引用 LLM 节点输出。注意不要直接把原始 JSON 返回给用户体验很差。同时可以在结束节点旁边接一个“失败处理”分支统一返回“很抱歉这张图片未能识别出有效题目请重新拍摄”这类提示。4. 实操中高频报错与排查技巧实录4.1 SSL 错误与 403网络链路问题跑完工作流后最容易踩的坑集中在网络调用上。dify ssl 错误是我见过提问率最高的问题之一。它通常出现在 Dify 通过 HTTP 请求节点调用外部 API 的时候报错类似“SSL certificate verify failed”。原因一般是 Dify 容器里的系统证书过期或者目标 API 的证书链不完整。解决思路有两个方向。如果只是调用个别接口报 SSL 错误可以在 HTTP 请求节点的高级设置里把证书校验关掉但这个方法只适合调试生产环境别这么干。更稳妥的做法是把目标 CA 证书挂载到 Dify API 容器内更新系统信任库再重启容器docker cp ca.crt dify-api:/usr/local/share/ca-certificates/ docker exec dify-api update-ca-certificates docker restart dify-api另一个高频报错是dify 调用接口 403。403 不是证书问题而是鉴权或权限问题。先看接口是否要求带Authorization: Bearer token请求头再看调用方 IP 是否在服务商白名单内最后确认你的 OCR 服务是否设置了密钥过期时间。403 的排查顺序就是请求头 - IP 白名单 - 密钥有效期 - 告警频率限制。之前有个朋友死活调不通接口最后发现是 OCR 服务的 QPS 配额用完返回的 403 提示非常不显眼。4.2 凭证验证失败与密码锁定账户链路问题这一类的报错特征很典型。配置模型供应商时提示an error occurred during credentials validation运维后台登录时提示too many incorrect password attempts. please try again later.。凭证校验失败的处理思路上面已经提过检查 API Key、检查余额、检查网络、检查 Base URL。这里补一个容易忽略的细节DeepSeek 的 API Key 是有环境区分的生产 Key 和测试 Key 不能混用。如果在开发环境误用了生产 Key而生产 Key 没有开通对应模型权限同样会提示验证失败。后台密码锁定的问题多见于刚部署完 Dify 的那几天。密码输错五次左右就会触发锁定。第一次遇到别慌等 15 分钟再登录。如果特别急直接进数据库重置docker exec -it dify-db psql -U postgres -d dify UPDATE users SET password new_hashed_password WHERE email adminexample.com;密码哈希不能用明文建议用 Dify 源码里自带的加密工具重新生成。这个操作做完记得重启 API 容器。4.3 Tool Calls 报错Agent 工具调用链路问题在 Dify 的 Agent 应用里调用 DeepSeek菜单选择模型后如果工作流跑到一半报deepseek messages tool calls need immediate results很多人会一脸懵。这个报错的意思是模型已经返回了一个tool_calls指令要求调用某个工具但消息流里没有立刻出现工具执行结果系统判定本轮无法继续。出现这个问题的原因通常有两个。一是工具节点耗时太长比如知识库检索或 HTTP 请求超过模型等待时间二是工具结果没有按 OpenAI 协议里tool消息的格式返回模型识别不了。在拍照解题场景里最典型的是调用了“题目知识点查询”工具但检索结果过大或者返回格式不对。我的处理方案很直接解题流程不用 Agent 模式改用 Workflow。Workflow 每一步都是预设的不存在模型自主决定调用工具的问题。如果某些场景必须用 Agent那么确保所有工具都有超时兜底并在工具节点后立刻将结果转成tool类型消息回传模型。不要把一个耗时超过 30 秒的工具挂在 Agent 里模型早就等不及了。4.4 高频问题速查表报错现象可能原因处理建议SSL certificate verify failed系统证书过期或目标证书链不全更新容器 CA 证书或临时关闭证书校验调试调用接口返回 403请求头缺失、IP 白名单、密钥过期、QPS 限制按请求头 - 白名单 - 密钥 - 配额顺序排查Credentials validation 失败API Key 错误、余额不足、网络不通核对 Key 和 Base URL确认网络和余额Too many incorrect password attempts登录密码多次输错触发锁定等待锁定过期或进数据库重置密码Tools call need immediate results工具结果未及时回传或格式错误改用 Workflow 固定流程或检查工具返回格式OCR 识别为空图片太暗、文件变量 URL 失效转 Base64 传图增加条件分支兜底这张表是六个月踩坑总结出来的覆盖了我自己线上环境 90% 以上的异常。遇到新问题先对号入座别一上来就怀疑模型能力。5. 从“能用”到“好用”优化与扩展方向5.1 知识库与错题流水线让解题越用越准基础的拍照解题流程跑通后下一步就是加知识库。Dify 的知识库功能在这里有两个用途。第一是沉淀错题。学生的错题可以归入知识库每条记录包含题目、做错原因、关联知识点。下一次拍题时先做知识库检索如果命中相似题目直接给出这道题的历史讲解记录比重新推理更快更稳定。Dify 的知识库流水线支持文档解析、分段、向量化我把 Markdown 格式的错题集传进去它自动完成切分和索引不需要额外开发。第二是维护知识点体系。把教材目录、公式定理整理成文档导入知识库在 LLM 节点前增加一个知识库检索节点把检索结果作为上下文注入 Prompt。实测对解答题的效果提升很明显模型会把“考察知识点”那段回答得更准不再泛泛而谈。这里有一个性能注意事项知识库检索会带来额外延迟。Dify 的检索节点默认是向量召回每道题检索一遍大约增加 200~500 毫秒。拍照解题本身要求响应快所以检索知识库的范围要控制最好限定在高相关度的错题集合内而不是全量知识库。5.2 多租户、迁移、在线升级与二次开发如果这套系统要开放给一个班级或者一个团队用Dify 的角色权限和多租户就很有用了。新版 Dify 社区版已经支持多租户可以为不同班级配置独立的空间、知识库和 API Key。以前一个应用要复用给不同群体只能通过 Prompt 里加身份标识来区分现在直接在租户层面隔离数据互不干扰。迁移和备份方面Dify 的数据主要存在 PostgreSQL 和向量数据库里工作流配置可以导出为 DSL 文件。我的备份策略是每周导出一份 DSL同时把 PostgreSQL 和 Redis 的 Docker 卷打包归档。迁移到新服务器时先恢复数据库再导入 DSL整个过程半小时内完成。二次开发是另一个大方向。Dify 本身是开源项目如果要定制 OCR 节点走向、或者做更细分的学科分支可以改源码重新构建镜像。但这需要维护一个私有分支后续官方升级时要合并成本不低。我的建议是优先用工作流原生能力实现需求真的无法覆盖时才动源码。在线升级 Dify 也要谨慎。社区版升级前务必先备份尤其是向量数据库里的知识库索引。我见过有人在升级后检索结果全部失效的现象就是因为向量索引版本不兼容最后不得不从备份恢复。5.3 把解题能力接到更多入口Dify 的一大优势是每个应用都可以生成独立的 API。拍照解题工作流开发完成后发布为 API 接口就能接到小程序、公众号、企业内部工具。我在实际项目里还做过一次更开放的集成DeepSeek 的 API 协议本身就是 OpenAI 兼容的所以除了 Dify它也能直接接入 Codex、VSCode 插件等开发者工具Dify 则可以把知识库和解题应用通过 API 暴露出去让外部应用调用。这样解题能力就不只是停留在 Dify 页面里而是一个可以被任意客户端复用的服务。价格方面DeepSeek 的 API 成本很低拍一道题包含 OCR 和大模型推理按 token 估算通常几分钱一次。如果走本地模型加本地 OCR完全免费但需要一台配置还行的机器。我的建议是对外提供服务用云端 API内部高频场景用本地模型成本和体验能取得一个比较好的平衡。我个人在实际操作中最深的体会是这类项目最花时间的不是模型能力而是你愿意在工程细节上花多少功夫。OCR 清洗、Prompt 结构、错误兜底每一个环节的粗糙都会在下游放大。先把最简流程跑通再加知识库、再加租户管理、再开放 API一步步扩展这套系统的价值就会越来越大。