DeepSeek Harness 入门:从 Agent 循环到多模态识图插件接入
本地跑过 DeepSeek 的人都会有同一个感受模型的文本理解和推理能力很强但真正要完成一项任务时还缺一层“手脚”。直接把 API 封装成聊天窗口它只能回答问题想让模型读文件、改代码、执行命令、调用工具就需要一个 agent harness。DeepSeek harness 是这一类工具的总称它负责管理模型调用、工具循环、上下文窗口和会话状态让 DeepSeek 从一个聊天模型变成能完成多步任务的 Agent。这篇教程把安装、配置、运行验证拆到每一步命令和每一个配置项再从零接入多模态识图插件让 DeepSeek 也能“看懂”图片。文章默认读者没有接触过 agent 框架因此先讲原理再讲操作最后讲排查全程不依赖某一种特定操作系统。1. 理解 DeepSeek Harness它解决什么问题又是怎么工作的1.1 什么是 Agent Harness“harness”直译是马具、背带在 AI 工程里它指的是把模型能力“固定”到具体任务上的外层程序。通俗地说模型本身只会根据输入文本生成输出文本它不知道当前目录有什么文件、不知道怎么执行命令、也没有办法记住上一轮对话之外的信息。而一个 Agent Harness 就是负责把这些能力补齐的运行框架。技术上的定义更具体Agent Harness 是一个运行“模型-工具-环境”循环的程序至少包含以下职责把系统提示词、历史消息、工具定义组装成一次完整的模型请求。调用模型 API并处理返回的普通文本和工具调用指令。当模型要求调用工具时在本地执行对应命令或脚本。把工具执行结果写回上下文再次请求模型直到任务完成。管理会话持久化、日志、错误重试和上下文长度。所以“DeepSeek harness”并不是某一个官方软件的名称而是一类以 DeepSeek 为后端模型的 Agent 框架。社区常用的是开源项目如 harness-anything、Codex CLI 配合 DeepSeek Provider、以及各类本地代理方案。理解了这一层后面安装时就不会被不同项目之间的命令差异带偏。1.2 harness 与普通 API 调用的区别很多人第一次接触 agents 时会有一个困惑我已经会用 DeepSeek 的 API 了为什么还要装一个 harness原因是两者解决的问题不在同一个层面。直接调用 API 适合“单轮问答”而 harness 解决的是“多轮任务执行”。下面用表格说明差异维度直接调 DeepSeek API使用 Harness交互方式一次请求一次响应多轮 Agent 循环直到任务完成工具能力需要自己另外写程序调用内置工具注册、执行、结果回填上下文管理每轮自己拼 messages 数组框架自动维护历史消息和 token 截断文件与命令操作不感知本地环境可以读文件、执行命令、跑脚本插件扩展无统一机制通过插件或工具定义扩展能力典型场景聊天机器人、简单接口封装代码生成、批量文档处理、识图工作流一个典型的最小 Agent 循环可以用下面的流程描述1. 用户输入任务 2. harness 把系统提示词 历史消息 工具定义发给模型 3. 模型返回回复文本或返回 tool_call 指令 4. 如果是 tool_callharness 执行对应命令把结果作为 tool 消息追加到上下文 5. 重复步骤 2-4直到模型输出最终答案这也是后面安装多模态识图插件时要遵循的核心思路DeepSeek 不会直接“看”图harness 会调用一个识图工具工具把图片变成文字描述再把描述交给 DeepSeek 继续推理。1.3 为什么 DeepSeek 默认不能识图这是本教程最关键的一个技术前提。DeepSeek 的公开对话接口以文本输入为主请求里的messages内容是role加content字符串。而 OpenAI 兼容协议里的多模态请求通常长这样{ role: user, content: [ {type: text, text: 请描述这张图片的内容}, {type: image_url, image_url: {url: https://example.com/a.png}} ] }DeepSeek 当前的公开 API 对这种图片 content 块的支持非常有限绝大多数情况下不能直接把图片 URL 或 base64 图片发给它。所以“让 DeepSeek 拥有识图能力”的正确做法不是在模型内部改造而是在模型外围加一层桥接用一个视觉模型或 OCR 工具把图片转成文字再把文字交给 DeepSeek。这个桥接就是本教程要安装的多模态识图插件。1.4 本文适用的场景和前置要求这篇教程适合三类读者已经在用 DeepSeek API想把它接入代码助手或终端 Agent 的开发者。想给文本模型增加识图能力但不知道从哪里下手的人。接到过reasoning_content相关报错想搞清原理并解决的人。前置知识要求不高会打开终端、会设置环境变量、能看懂 JSON 结构即可。不需要提前了解 Agent 框架。2. 安装前的环境检查版本、源、密钥一个都不能少2.1 基础环境清单无论使用哪种 harness第一步都是确认本机环境。先按下面表格逐项核对项目最低要求推荐配置检查命令操作系统Windows 10 / macOS 12 / Ubuntu 20.04Windows 11 / macOS 14 / Ubuntu 22.04系统设置Node.js18.x20.x LTSnode -vnpm8.x10.x 或以上npm -vPython3.9识图插件需要3.10 - 3.12python3 --versionGit2.x最新稳定版git --version网络能访问 DeepSeek API稳定的开发网络curl -I https://api.deepseek.com这里要特别说明 Python 不是所有 harness 都必需但后面的多模态识图插件通常会用 Python 写所以提前装好能省很多事。Node.js 则是大多数现代 harness 的运行环境版本过低会导致安装报错。2.2 DeepSeek API Key 申请和最小配置项使用任何 harness 前需要先有一个 DeepSeek 平台的 API Key。申请路径通常是登录 DeepSeek 开放平台在 API Keys 页面创建密钥得到的密钥形如sk-开头的一串字符。拿到密钥后要理解以下几个核心配置项配置项含义示例值DEEPSEEK_API_KEYDeepSeek 平台分配的密钥sk-xxxxBASE_URLOpenAI 兼容接口地址https://api.deepseek.com 或 https://api.deepseek.com/v1MODEL对话模型deepseek-chatREASONER_MODEL推理模型deepseek-reasonerhttps://api.deepseek.com和https://api.deepseek.com/v1都能访问同一套 OpenAI 兼容接口不同 harness 对 base_url 的拼接方式不一样所以两个地址都可能在配置里出现。模型名需要理解deepseek-chat和deepseek-reasoner的差别后面排查 400 错误时经常和这两个名字有关。2.3 检查命令和预期输出在终端里依次执行node -v npm -v python3 --version git --version curl -I https://api.deepseek.com预期输出大致是v20.11.1 10.2.4 Python 3.11.9 git version 2.39.2 HTTP/2 200之后把密钥写入当前终端环境变量export DEEPSEEK_API_KEYsk-你的密钥 echo $DEEPSEEK_API_KEYWindows PowerShell 里写法略有不同$env:DEEPSEEK_API_KEYsk-你的密钥 echo $env:DEEPSEEK_API_KEY检查点很简单echo能原样打印出密钥说明变量已生效。这一步确认完再进入 harness 安装否则后面所有请求都会报 401。2.4 安装前最常见的三个坑第一个坑是 Node 版本过低。npm 全局安装现代 harness 时如果 Node 版本低于 18经常出现ERESOLVE或语法错误。处理方式是先升级 Node而不是反复重装包。第二个坑是 npm 源慢导致安装超时。在国内开发环境下可以换成镜像源npm config set registry https://registry.npmmirror.com npm config get registry这里需要说明更换 npm 源只是提升下载速度不影响依赖本身的功能。第三个坑是环境变量不持久。直接在终端export的变量只对当前窗口有效关闭终端后就会丢失。推荐把它写入 shell 配置文件例如~/.bashrc或~/.zshrc或者使用项目内的.env文件由 harness 自动加载。3. 安装 DeepSeek Harness 并跑通最小对话3.1 选择 harness 并全局安装本文的安装示例以开源项目 harness-anythingGitHub 仓库为 ppshobi/harness-anything为例。它是一款使用 Node.js 编写的终端 Agent Harness支持多种模型服务商可以通过 OpenAI 兼容协议接入 DeepSeek。选择它作为第一套练习环境的原因是安装链路短、配置项少而且社区讨论比较多遇到问题容易找到参考。安装命令通常是npm install -g harness-anything安装完成后确认版本harness --version这里要特别说明不同版本和不同仓库的包名、命令名可能调整如果执行后提示命令不存在请以对应项目 README 的最新说明为准。这类工具迭代很快教程只能保证思路正确不能保证命令永远不变。3.2 配置 DeepSeek Provider安装完成后需要告诉 harness 使用哪个模型服务商。常见做法是在项目目录创建.env文件HARNESS_PROVIDERdeepseek DEEPSEEK_API_KEYsk-你的密钥 HARNESS_MODELdeepseek-chat HARNESS_BASE_URLhttps://api.deepseek.com/v1不同 harness 的字段名可能不同有的叫provider有的叫model_provider但含义一致都是指定模型服务商和模型名。除了环境变量有些版本支持在config.json里配置{ provider: deepseek, model: deepseek-chat, baseUrl: https://api.deepseek.com/v1, apiKeyEnvVar: DEEPSEEK_API_KEY }这里建议把密钥放在环境变量里而不是直接写进 JSON避免配置文件被提交到 Git 后泄漏密钥。配置里几个关键参数的作用参数作用推荐值调大或调小的影响temperature控制输出随机性0.2 - 0.7越大越发散越小越稳定max_tokens单次回复最大 token 数4096 或 8192太小会截断长答案stream是否流式输出true关闭后等待时间长但便于调试日常代码任务建议把 temperature 设在 0.2 左右回答更稳定写作类任务可以调高到 0.7 以上。3.3 启动并验证最小对话配置完成后在终端启动harness进入交互界面后输入一个简单问题用三句话说明什么是 DeepSeek harness如果配置正确harness 会像普通聊天一样返回回答。此时还没有调用任何工具只是为了验证 DeepSeek API 连通性。很多 harness 会输出日志日志里通常能看到模型名、token 消耗、请求耗时等信息。看到这些内容说明最小链路已经跑通可以进入下一步。3.4 用 Codex CLI 接入 DeepSeek 的替代方案除了专用 harness另一个常见做法是让 Codex CLI 接入 DeepSeek。Codex 本身是面向代码任务的终端 Agent支持自定义模型服务商。社区里大量“codex 接入 deepseek”的教程都是这个思路。修改~/.codex/config.tomlmodel deepseek-chat model_provider deepseek [model_providers.deepseek] name DeepSeek base_url https://api.deepseek.com/v1 env_key DEEPSEEK_API_KEY wire_api chat然后设置环境变量并启动export DEEPSEEK_API_KEYsk-你的密钥 codex这里最关键的是wire_api参数。Codex 默认使用responses协议而 DeepSeek 更常用的是chat协议必须显式写成chat否则请求会打到不存在的/responses路径上。后面第 6 节会详细讲这一层协议不一致引发的错误。4. 多模态识图插件原理、选型与安装4.1 识图插件的本质是“桥接”前面已经解释了 DeepSeek 的公开 API 以文本为主所以多模态识图插件的本质不是给 DeepSeek 加参数而是建立一条“图片到文字”的翻译通道。完整链路是用户给出图片路径或图片 URL - harness 调用识图工具 - OCR 或视觉模型把图片转成文字描述 - 描述文本放回模型上下文 - DeepSeek 基于描述继续推理和回答这个设计的好处是文本模型不需要支持图片就能完成“看一张截图里的报错信息并给出修复建议”“识别一张架构图并解释流程”这类任务。缺点也很明显图片信息经过文字压缩会丢失部分细节所以描述质量直接影响最终回答质量。4.2 三种识图方案对比根据自己的场景选择识图方案不要盲目跟风。方案实现方式优点缺点适合场景云端视觉模型 APIQwen-VL、GLM-4V 等识别质量高、接入快需要额外密钥和费用学习、日常开发、复杂图片理解本地 OCRPaddleOCR免费、离线、中文支持好只能识别文字不能理解整体画面截图、文档、图片里的代码或文案本地多模态模型Ollama Qwen2.5-VL、Llava 等免费、离线、图文都能理解需要 GPU显存占用高数据敏感、完全离线环境学习阶段最推荐第二种PaddleOCR 安装简单、不依赖 GPU能立刻解决“图片里的文字提取”这个最高频需求。等需要理解图片整体语义时再切换到云端视觉模型或本地多模态模型。4.3 方案一云端视觉模型 API 插件先安装 OpenAI Python SDK它实际上是通用的 OpenAI 兼容客户端pip install openai然后创建vision_plugin.pyimport base64 import os import sys from openai import OpenAI client OpenAI( api_keyos.getenv(VISION_API_KEY), base_urlos.getenv(VISION_BASE_URL), ) def describe_image(image_path: str) - str: with open(image_path, rb) as f: image_data f.read() base64_image base64.b64encode(image_data).decode() response client.chat.completions.create( modelos.getenv(VISION_MODEL, qwen-vl-plus), messages[ { role: user, content: [ { type: text, text: 请详细描述这张图片包括文字、物体、场景、布局和颜色。 }, { type: image_url, image_url: { url: fdata:image/jpeg;base64,{base64_image} } } ], } ], ) return response.choices[0].message.content if __name__ __main__: image_path sys.argv[1] print(describe_image(image_path))设置对应的环境变量以阿里云百炼的 OpenAI 兼容接口为例export VISION_API_KEY你的百炼密钥 export VISION_BASE_URLhttps://dashscope.aliyuncs.com/compatible-mode/v1 export VISION_MODELqwen-vl-plus单独测试插件python3 vision_plugin.py /path/to/your/image.png只要终端能打印出图片的文字描述说明插件本身是通的。实际使用中VISION_MODEL的可用型号会随平台更新落地前需要到对应平台确认最新模型名。4.4 方案二本地 OCR 与本地视觉模型如果不想把图片发送到外部 API可以选择本地方案。PaddleOCR 的安装和使用都非常直接pip install paddleocr paddlepaddle创建ocr_plugin.pyfrom paddleocr import PaddleOCR ocr PaddleOCR(use_angle_clsTrue, langch) def extract_text(image_path: str) - str: result ocr.ocr(image_path, clsTrue) lines [] for page in result: if not page: continue for item in page: lines.append(item[1][0]) return \n.join(lines) if __name__ __main__: import sys print(extract_text(sys.argv[1]))运行验证python3 ocr_plugin.py /path/to/your/image.png另一种本地方案是使用 Ollama 运行视觉大模型ollama pull qwen2.5vl:7b ollama run qwen2.5vl:7b 请描述这张图片的内容 /path/to/your/image.png这个方案能理解图片整体语义但 7B 级别的视觉模型通常需要 8GB 以上显存纯 CPU 环境会非常慢。4.5 把插件注册进 harness无论选哪种方案最后一步都是让 harness 知道有这个工具。以 JSON 形式的工具配置为例{ tools: [ { name: vision_describe, description: 输入本地图片路径返回图片的文字描述支持中文场景, command: python3 /path/to/vision_plugin.py, input_type: argument } ] }不同 harness 注册工具的字段名不一样但核心要素一致工具名、描述、执行命令、输入参数。配置完成后重启 harness模型在需要看图片时就会自动调用这个工具。这里有一个使用建议工具描述写得越清楚模型越知道什么时候该调用它。比如描述里写明“当用户提到截图、图片、logo、照片时使用”比一句“识图工具”要可靠得多。5. 运行验证从文本问答到识图闭环5.1 先独立验证 DeepSeek API不要一上来就测试复杂 Agent 任务。先用 curl 直接验证 DeepSeek API 本身是否正常curl https://api.deepseek.com/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $DEEPSEEK_API_KEY \ -d { model: deepseek-chat, messages: [ {role: user, content: 用一句话解释 agent harness} ], stream: false }正常情况下会返回一段 JSON里面有choices[0].message.content。如果这一步成功说明密钥、网络、base_url 都没有问题后续问题就集中在 harness 配置和插件上。5.2 识图闭环验证在 harness 交互界面里输入一个需要看图的指令例如帮我看看 /tmp/screenshot.png 里写了什么并整理成 Markdown 列表预期的执行链路是1. DeepSeek 识别到任务需要图片内容 2. harness 调用 vision_describe 工具 3. 插件返回图片中的文字描述 4. DeepSeek 把描述整理成 Markdown 列表 5. harness 输出最终结果验证点有两个第一harness 日志里能看到工具被调用的记录第二最终回答的内容确实来自图片而不是模型凭空编造。如果模型没有主动调用工具先检查工具描述是否清晰再检查命令是否能单独运行。5.3 日志和失败输出怎么判断正常运行时harness 日志里会出现类似下面的关键字tool_call: vision_describe tool_result: ... model: deepseek-chat tokens: promptxxxx completionxxx判断问题时按优先级看日志请求是否真的发出去了有没有 401、400、429。模型返回的是普通文本还是 tool_call。工具命令是否执行成功返回是否为空。工具结果写回上下文后模型是否继续正常回答。工具执行失败的一个典型现象是插件单独运行没问题但 harness 调用时返回空内容。这通常是因为 harness 执行命令时的工作目录和图片绝对路径不一致或者 Python 环境与终端里不是同一个。检查时把工具命令改为绝对路径的python3并让插件脚本内部打印完整错误信息。6. 常见问题排查从 400 到 429 的完整链路6.1 认证错误 401 / 403现象是请求返回401 Unauthorized或403 Forbidden。可能原因有三个API Key 写错、环境变量没有加载、密钥额度或权限不足。检查方式按顺序执行echo $DEEPSEEK_API_KEY curl https://api.deepseek.com/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $DEEPSEEK_API_KEY \ -d {model: deepseek-chat, messages: [{role: user, content: hi}]}先确认终端里密钥非空再用 curl 排除 harness 配置问题。解决方案是重新生成密钥并正确写入环境变量同时检查是否有代码把密钥误写成硬编码且被覆盖。6.2 模型或接口错误 400重点讲 reasoning_content400 错误是所有 harness 使用者最常遇到的。常见表现形式invalid model: 请求里的模型名不存在这类原因最简单模型名写错写成DeepSeek-Chat或deepseek-v3之类的历史版本名。DeepSeek 平台当前可用的对话模型名以平台文档为准常用的是deepseek-chat和deepseek-reasoner。另一种 400 错误更隐蔽错误信息类似provider: deepseek; model: deepseek-v4-flash; upstream_status: http 400; cause: the reasoning_content in the thinking mode must be passed back to the api.这段错误的核心在reasoning_content。使用deepseek-reasoner推理模型时模型响应里会包含思考过程字段reasoning_content。DeepSeek 要求多轮请求里把上一轮 assistant 消息的reasoning_content原样回传否则拒绝请求。很多本地代理把 Codex 的/responses协议翻译成 DeepSeek 的 chat 协议时没有保留这个字段就会触发上面的错误。处理顺序升级本地代理和客户端到最新版本确认翻译层是否保留reasoning_content。把模型切成非推理模型deepseek-chat验证功能是否恢复。必须使用推理模型时检查请求的 messages 数组里有没有上一轮的 reasoning_content。如果历史消息被手工裁剪过先新开会话再测试。这个错误的预防建议是不要把一条会话的历史消息随意删减尤其是推理模型思维链字段也是多轮上下文的一部分。6.3 限流 429 与超时现象是请求偶尔成功、偶尔返回429 Too Many Requests或长时间无响应。原因通常是并发请求超过限制、token 消耗过快、或者网络到服务端不稳定。检查时看响应头和日志里的状态码确认为限流后采用指数退避重试同时在配置里调低并发。长时间任务建议开启 stream 模式至少能确认请求没有卡死。6.4 本地代理和 cc-switch 类工具的问题很多“codex 接入 deepseek”的方案会引入本地代理组件例如错误信息里出现的cc switch local proxy。它负责把 Codex 的/responses请求转发成 DeepSeek 能理解的请求。这类代理出问题时现象通常是“harness 或 codex 启动正常但一问就报 400”。检查路径是先绕过代理直接用 curl 调 DeepSeek API确认服务端正常。确认代理版本是否过旧查看代理日志里转发的请求内容。确认配置里wire_api是chat还是responses二者不一致时改成本地代理支持的协议。关闭代理直接用 codex 原生 model_providers 配置再试。这里的核心经验是本地代理多一层就多一个排查面。能用原生 model_providers 配置解决的尽量不要引入代理。6.5 排查顺序清单遇到任何问题按下面顺序排查不要跳步输入是否正确图片路径、URL、任务描述是否清晰。环境变量是否加载echo $DEEPSEEK_API_KEY。模型名和 base_url 是否与平台文档一致。用 curl 直接调 API确认服务端本身没问题。检查 harness 日志里的状态码和 tool_call 记录。插件单独运行确认命令本身能出结果。最后才怀疑框架或代理版本问题。7. 生产环境使用建议与最佳实践7.1 密钥、配置和日志安全学习环境里把密钥写在.env可以接受但生产环境必须更严格密钥不要硬编码在代码或 JSON 配置里改用环境变量或密钥管理服务。.env文件和包含密钥的配置文件加入.gitignore防止提交。harness 日志可能包含完整请求和响应生产环境要脱敏后再采集。如果图片要发送给云端视觉模型先确认这些图片是否允许外发涉及用户隐私或商业机密的图片不要走外部 API。7.2 成本控制与模型选择deepseek-chat和deepseek-reasoner的计费逻辑不同推理模型通常更贵。实际项目中不要把所有任务都交给 reasoner。可以用一个简单的路由策略普通代码生成和问答用deepseek-chat只有数学推导、复杂逻辑分析才切到deepseek-reasoner。成本控制的几个落地动作设置合理的max_tokens防止单次输出过长。要稳不要变的场景把 temperature 调低避免反复试错消耗 token。识图插件优先用本地 OCR 处理纯文字图片减少云端视觉模型调用。记录每次请求的 token 消耗定期观察趋势。具体价格请以平台计费页为准本教程不提供固定价格数据因为模型计价会随版本迭代调整。7.3 日常使用前的检查清单每次升级版本或更换环境后建议按这个清单快速验证检查项验证方式通过标准Node 和 Python 版本node -v / python3 --version满足依赖要求DeepSeek 密钥curl 直接调 chat/completions返回 200harness 模型配置启动后问一个简单问题正常回复识图插件独立可用单独运行插件脚本输出文字描述harness 工具注册输入识图指令日志出现 tool_call推理模型多轮对话连续问两个问题不报 reasoning_content 400这套清单同样适用于新人接手项目时的环境验收能快速定位是环境问题还是代码问题。8. 扩展方向从最小可运行走向更完整的 Agent8.1 本地化部署 DeepSeek如果不想依赖外部 API可以用 Ollama 或 vLLM 在本机部署 DeepSeek 的开源版本。引入本地模型后harness 的 provider 从云端切成本地服务地址流程和云端接入基本一致但需要提前估计显存和内存。只要模型服务地址支持 OpenAI 兼容协议harness 这一层不需要大改。8.2 多模态路由更完善的方案是建立多模态路由文本任务走 DeepSeek图片任务走视觉模型两者由 harness 统一调度。可以在插件脚本里先判断输入是图片还是文本也可以让 harness 根据用户输入自动选择工具。下面是一个简化思路def route_task(task, image_pathNone): if image_path: description describe_image(image_path) return deepseek_chat(f根据图片描述回答问题。描述{description}) return deepseek_chat(task)这种路由的好处是各模型做自己最擅长的事成本更低响应也更稳定。8.3 自定义插件和下一步建议识别插件只是第一个工具。按同样的模式可以继续扩展文件搜索、代码格式化、数据库查询、定时任务等工具。每加一个工具都要在 harness 里注册工具名、描述和执行命令并单独验证工具本身。对新手最有价值的练习路径是先用deepseek-chat跑通文本 Agent再单独跑通一个识图脚本最后才把两者接到 harness 里。任何时候出现问题都回到“先验证工具本身再验证 harness 调度”这个原则。这样一步步积累会比一次性搭一个复杂系统更容易定位问题也更能在生产环境长期维护。