DeepSeek Harness实战:从零搭建Agent与Skill插件机制 最近在折腾 Agent 项目时我发现“Harness”这个词开始频繁出现在 AI 开发者的讨论里。不管是围绕 DeepSeek 的 Harness 方案还是社区里越来越多的 Skill 插件生态大家都想搞清楚Agent 到底怎么从“能对话”变成“能干活”网上资料虽然多但大多只是概念介绍缺少一条从零开始就能跑通的实操路径。这篇文章我会用一个完整的实战案例带你从 0 到 1 搭建一套基于 DeepSeek 的 Harness 开发环境并实现“一切皆插件”的 Skill 扩展机制。整篇文章不仅包含 Harness、DeepAgent、Skill 的概念拆解还有完整的项目结构、可复制的 Python 代码、配置示例和常见问题排查方案。无论你是刚开始接触 AI 大模型应用开发的新手还是已经在做 Agent 落地的开发者都能从里面拿到一套能直接借鉴的方法。1. 背景与核心概念1.1 为什么突然都在聊 Harness先来给 Harness 下一个通俗的定义。它的本意是“马具、背带、安全带”在 AI 编程和 Agent 开发语境下Harness 可以理解为套在大模型外面的“运行骨架”或“调度外壳”。如果你只是调用 DeepSeek 的 API 做问答那不需要 Harness一个接口地址加一个 API Key 就够了。但当你希望模型能做这些事先分析用户任务再把任务拆成多个步骤然后调用外部工具去查数据库、执行脚本、读写文件最后根据工具返回结果决定下一步操作这时候就需要 Harness 来负责“编排”。它不负责具体算法而是把模型、工具、上下文、插件、执行步骤统一管理起来让 Agent 能真正完成复杂任务。从社区讨论来看DeepSeek Harness 并不是一个单一项目而是一类开源的 Agent 编排方案。它们核心思路一致以 DeepSeek 这类大模型作为决策大脑以 Harness 作为运行框架把能力封装成 Skill 插件按需加载。不同项目的安装方式、配置文件格式可能不同但理解其中一套迁移到其他方案会非常快。1.2 DeepAgent、Skill、Harness 三者关系很多读者会被这三个词搞混。我画一个简单的分工关系名词角色一句话理解Harness运行框架Agent 的运行环境、调度中枢、插件管理器DeepAgentAgent 执行体基于大模型驱动的智能体负责理解任务并决策Skill能力插件一个个可复用的技能包例如代码评审、SQL 优化、测试生成它们的协作关系是这样的用户把任务交给 DeepAgentDeepAgent 对任务进行拆解然后从 Harness 中加载对应 Skill执行 Skill 里的脚本或工具逻辑再把执行结果返回给 DeepAgent 判断。Harness 在中间负责“管理插件”和“记录执行轨迹”。Skill 可以理解成 Agent 的“工具箱”或“技能包”。以前我们给大模型加能力通常是把所有工具函数都写进一个巨大的工具列表里模型每次都要从几十个工具中挑。Skill 机制的好处是把同类型能力收敛成一个插件Agent 只需要根据任务描述选择相关 Skill 即可。1.3 为什么叫“一切皆插件”“一切皆插件”是 Harness 这类方案最核心的设计哲学。它的意思是工具、命令、脚本、知识库、MCP 服务、甚至一段提示词模板都可以封装成一个 Skill 插件。这样做有几个明显优势。第一按需加载。Harrness 启动时可以只扫描插件目录不实际加载插件内部所有内容等 Agent 选中某个 Skill 时才真正执行资源占用更小。第二可复用。你写好的一个 SQL 优化插件可以在不同项目、不同 Agent 之间复制使用。社区里现在也有很多现成 Skill 脚本直接下载就能用。第三可维护。每次新增能力不需要修改 Agent 主程序只需要在 skills 目录下新建一个文件夹写清楚描述和脚本Agent 就能自动发现它。这也是为什么“Skill 插件”会成为 AI 应用开发里的热门关键词。代码评审、SQL 生成、网络请求、Excel 处理这些东西都可以变成插件让大模型按需调用。2. 环境准备与版本说明2.1 硬件与运行环境我先说明一个核心原则如果使用 DeepSeek 的 API 服务你本地不需要 GPU也不需要很高的内存普通开发机能跑就行。推理都在云端完成本地 Harness 主要负责调度和调用插件。如果后续想尝试本地部署 DeepSeek 模型再考虑 GPU 环境。比如用 Ollama 或 vLLM 加载开源模型显卡显存建议不低于 16GB具体取决于模型大小和量化方式。本文的示例以 API 模式为主本地部署我会在第七节补充思路。2.2 软件依赖清单实际操作时版本需要根据你的项目实际情况调整下面列的是常见开发环境软件建议版本/说明操作系统Windows 10/11、macOS、Linux 均可Python3.9 及以上Node.js部分 Harness 版本基于 Node建议 18Git用于拉取开源仓库代码Docker可选用于部署中间依赖或隔离环境IDEVS Code / PyCharm 均可我这次会用 Python 来写 Agent 主程序和 Skill 脚本。这样不依赖特定前端框架更容易理解核心逻辑。2.3 获取 DeepSeek API Key要调用 DeepSeek 的大模型能力你需要先到 DeepSeek 开放平台注册账号创建一个 API Key。创建成功后把 Key 保存好后面我们要配置到项目的环境变量文件中。这里有一个关键点DeepSeek 开放平台提供了兼容 OpenAI 格式的接口也就是说我们可以用 OpenAI 的请求格式把 base_url 指向 DeepSeek 的接口地址模型名换成 DeepSeek 提供的模型名即可。具体模型名和接口地址以你注册账号后开放平台文档为准。为了安全API Key 不要写死在代码里而是要放在.env文件中并加入.gitignore避免提交到代码仓库。2.4 Harness 框架安装以开源仓库方式安装 Harness 时不同项目步骤略有差异但大体流程一致# 1. 克隆开源仓库换成你实际使用的 Harness 项目地址 git clone https://example.com/your-harness-repo.git cd your-harness-repo # 2. 如果项目是 Python 编写的 pip install -r requirements.txt # 3. 如果项目是 Node 编写的 npm install安装完成后通常还需要进行初始化配置。配置项一般包括API Key 配置默认模型名称插件目录路径日志等级。因为 Harness 的社区版本很多我不能保证某一条命令在所有项目上都适用所以建议你安装后先看一下项目 README。README 里的安装命令通常最准确。3. 核心机制拆解从“一问一答”到“插件编排”3.1 Harness 的完整工作流为了帮助你理解我把 Harness 处理一次任务的过程拆成 7 步接收任务用户输入自然语言任务例如“请评审一下 main.py 的代码风格”。任务理解DeepAgent 把任务放入上下文并和系统提示词拼接形成完整请求发给模型。技能选择模型在可用的 Skill 列表中选择最匹配的一个并输出该 Skill 所需的参数。插件加载Harness 根据模型选择结果从 skills 目录加载对应插件。脚本执行Skill 内部可以执行 Python/Shell 脚本也可以调用外部 API、数据库、命令行工具。结果返回Skill 执行结果返回给模型模型根据结果生成最终回答。输出反馈Agent 把最终结果反馈给用户。这里和普通 API 调用的最大区别是Harness 让模型拥有了“调用外部能力”的通道并且能够根据执行结果动态调整下一步。3.2 Skill 插件到底长什么样在社区常见的 Harness 实现中一个 Skill 插件通常是一个目录目录里至少包含一个描述文件可能还有一个或多个脚本。下面是一个典型 Skill 目录结构skills/ └── code-review/ ├── SKILL.md └── review.pySKILL.md是插件的能力描述文件它告诉 Agent 这个插件是干什么的、什么时候应该使用它、使用时需要传递哪些参数。review.py则是真正执行逻辑的脚本。这种设计非常关键因为 Agent 本身并不能“看懂”Python 代码它只能通过SKILL.md的描述来决定是否调用这个插件。描述文件写得越清晰Agent 的技能选择准确率就越高。3.3 Skill 中关键字段的设计虽然不同 Harness 项目的字段名可能有差异但核心字段是通用的。下面是我在实战中常用的几个关键字段字段作用注意事项nameSkill 的唯一名称建议用英文小写和连字符例如 code-reviewdescription描述插件能力这段文字会被发给大模型必须写清楚“何时使用”when_to_use触发场景说明哪些任务适合本插件能提高选择准确率parameters参数定义定义脚本需要哪些入参例如 file_path、modeworkflow执行流程说明插件内部会执行哪些步骤帮助 Agent 理解结果写 description 时有一个常见误区写得太笼统。例如“用于代码评审”就不太好因为模型无法判断什么时候该选它。更好的写法是“当用户要求对某个 Python/Java/Go 文件进行代码质量检查、找出潜在 Bug 或风格问题时使用”。3.4 Agent 如何决定调用哪个 Skill在 Harness 的实现中Agent 决定调用哪个 Skill本质上是一次“函数选择”过程。System Prompt 里会注入当前可用的 Skill 列表例如你是一个可以调用插件完成任务的 Agent。 当前可用 Skill - code-review: 当用户要求评审代码质量时使用参数 file_path。 - sql-optimizer: 当用户要求优化 SQL 语句时使用参数 sql_text。模型在生成回复时会根据用户输入决定是直接回答还是输出一个“调用插件”的指令。目前社区主流的做法有两种一种是让模型输出结构化 JSON包含action和params另一种是走 OpenAI 的 Function Calling / Tool Calling 机制。无论哪种核心逻辑都是模型负责决策Harness 负责执行。4. 实战从 0 到 1 搭建一个 DeepSeek Harness 项目这一节我们直接动手。我会用 Python 编写一个小型 Harness虽然比不上开源框架完整但麻雀虽小五脏俱全。它包含 DeepAgent 调度逻辑、Skill 扫描机制、代码评审插件和 SQL 优化插件你完全可以基于这套结构改成自己的项目。4.1 项目结构设计先设计目录结构deepseek-harness-demo/ ├── .env ├── .gitignore ├── requirements.txt ├── main.py ├── agent/ │ ├── __init__.py │ └── core.py └── skills/ ├── code-review/ │ ├── SKILL.md │ └── review.py └── sql-optimizer/ ├── SKILL.md └── optimize.py目录说明main.py入口文件接收用户输入调用 Agent。agent/core.pyDeepAgent 核心调度类。skills/Skill 插件目录每个子目录是一个插件。.env存放 API Key 等敏感信息。4.2 安装依赖本项目只需要两个依赖requests和python-dotenv。前者用于调用 DeepSeek API后者用于读取.env配置。# requirements.txt requests2.31.0 python-dotenv1.0.0安装命令pip install -r requirements.txt如果下载较慢可以临时配置国内镜像源pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple4.3 配置环境变量在项目根目录创建.env文件DEEPSEEK_API_KEY你的APIKey DEEPSEEK_BASE_URLhttps://api.deepseek.com/v1 DEEPSEEK_MODELdeepseek-chat这里注意几个点DEEPSEEK_BASE_URL和DEEPSEEK_MODEL需要以 DeepSeek 开放平台文档为准。不同时期平台提供的模型名称可能不同比如有些项目用deepseek-chat有些可能拆成deepseek-reasoner。我这里给出的是常见写法你在实际使用时要确认。.env文件不要提交到 Git。4.4 编写 Agent 主程序先写核心调度代码。这个类负责三件事加载 Skill 列表、生成系统提示词、调用 DeepSeek API。# 文件路径agent/core.py import json import os import requests from dotenv import load_dotenv from pathlib import Path load_dotenv() DEEPSEEK_API_KEY os.getenv(DEEPSEEK_API_KEY) DEEPSEEK_BASE_URL os.getenv(DEEPSEEK_BASE_URL, https://api.deepseek.com/v1) DEEPSEEK_MODEL os.getenv(DEEPSEEK_MODEL, deepseek-chat) SKILLS_DIR Path(__file__).resolve().parent.parent / skills def load_skills() - list: 扫描 skills 目录读取每个 Skill 的 SKILL.md 描述文件。 返回技能描述列表后续会被注入到系统提示词中。 skills [] if not SKILLS_DIR.exists(): return skills for skill_dir in SKILLS_DIR.iterdir(): skill_md skill_dir / SKILL.md if skill_md.exists(): content skill_md.read_text(encodingutf-8) skills.append({name: skill_dir.name, description: content}) return skills def call_deepseek(messages: list, temperature: float 0.3) - str: 调用 DeepSeek 的 Chat Completions 接口。 这里使用 requests 直接请求方便理解完整的 HTTP 流程。 url f{DEEPSEEK_BASE_URL}/chat/completions payload { model: DEEPSEEK_MODEL, messages: messages, temperature: temperature, } headers { Authorization: fBearer {DEEPSEEK_API_KEY}, Content-Type: application/json, } try: response requests.post(url, jsonpayload, headersheaders, timeout60) response.raise_for_status() data response.json() return data[choices][0][message][content] except requests.exceptions.Timeout: return 请求超时请检查网络或稍后重试。 except requests.exceptions.HTTPError as e: return fHTTP 错误{e.response.status_code}请检查 API Key 是否有效。 except Exception as e: return f请求异常{str(e)} class DeepAgent: 一个极简的 Harness Agent 原型。 它负责管理上下文、构造系统提示词并在模型需要调用 Skill 时执行脚本。 def __init__(self): self.skills load_skills() self.messages [] self.skills_dir SKILLS_DIR def build_system_prompt(self) - str: skill_text \n.join( [f- {s[name]}:\n{s[description]} for s in self.skills] ) system_prompt f 你是一个运行在 Harness 框架中的智能体可以调用 Skill 插件完成任务。 当前可用的 Skill 插件如下 {skill_text} 当你认为需要调用某个插件时请严格按照以下 JSON 格式返回不要输出多余文字 {{ action: skill名称, params: {{ 参数1: 值1, 参数2: 值2 }} }} 如果你确认不需要插件就能回答用户问题请直接回答。 .strip() return system_prompt def run_skill(self, action: str, params: dict) - str: 根据模型返回的 action 找到对应 Skill 目录执行其中的 Python 脚本。 脚本接收 JSON 格式参数并输出 JSON 格式结果。 skill_dir self.skills_dir / action script_path None # 查找 Skill 目录下的所有 .py 文件按文件名自然排序 for py_file in sorted(skill_dir.glob(*.py)): script_path py_file break if script_path is None: return fSkill {action} 中未找到可执行脚本。 # 把参数写入临时 JSON 文件交给子进程脚本执行 import subprocess import tempfile with tempfile.NamedTemporaryFile( modew, suffix.json, encodingutf-8, deleteFalse ) as f: json.dump(params, f, ensure_asciiFalse) temp_path f.name try: result subprocess.run( [python, str(script_path), temp_path], capture_outputTrue, textTrue, encodingutf-8, timeout60, ) if result.returncode ! 0: return fSkill 脚本执行失败{result.stderr} return result.stdout.strip() finally: os.unlink(temp_path) def chat(self, user_input: str) - str: 处理用户输入并在必要时自动调用 Skill。 self.messages.append({role: user, content: user_input}) # 系统提示词每次根据最新 Skill 列表生成 system_prompt self.build_system_prompt() messages [{role: system, content: system_prompt}] self.messages[-10:] response call_deepseek(messages) response response.strip() # 尝试解析 JSON判断是否要调用 Skill skipped_lines [] parsed None try: parsed json.loads(response) except json.JSONDecodeError: # 如果模型没有返回 JSON直接作为普通回答返回 self.messages.append({role: assistant, content: response}) return response if parsed and action in parsed: action parsed[action] params parsed.get(params, {}) # 把“调用 Skill 的决策”记录进上下文 decision_text f[Agent 调用插件] action{action}, params{json.dumps(params, ensure_asciiFalse)} self.messages.append({role: assistant, content: decision_text}) # 执行 Skill result self.run_skill(action, params) # 把 Skill 执行结果返回给模型让模型总结 self.messages.append( {role: user, content: fSkill 执行结果如下\n{result}\n请根据结果回复用户。} ) final_response call_deepseek( [{role: system, content: system_prompt}] self.messages[-10:] ) self.messages.append({role: assistant, content: final_response}) return final_response self.messages.append({role: assistant, content: response}) return response这段代码的核心思路是DeepAgent 每次都会把可用 Skill 的描述注入到系统提示词里。当用户提问时模型可以选择直接回答也可以返回一个 JSON 指令告诉我们“要调用哪个 Skill”。一旦检测到 JSON 指令主程序就会找到对应脚本并执行把结果继续交给模型做最终总结。这里使用了subprocess来执行 Skill 脚本好处是插件之间相互隔离某个脚本崩溃不会拖垮主进程坏处是每次调用都会新起进程性能略低。在生产环境可以换线程池或进程池方案。4.5 编写入口文件# 文件路径main.py from agent.core import DeepAgent def main(): agent DeepAgent() print(DeepSeek Harness Demo 已启动输入 exit 退出。) while True: try: user_input input(\n用户: ).strip() except (KeyboardInterrupt, EOFError): print(\n再见) break if user_input.lower() in {exit, quit}: print(再见) break if not user_input: continue print(\nAgent 思考中...) reply agent.chat(user_input) print(f\nAgent: {reply}) if __name__ __main__: main()4.6 创建第一个 Skill代码评审插件接下来创建code-review这个 Skill。先写描述文件# SKILL.md 文件路径skills/code-review/SKILL.md name: code-review description: 当用户要求对某个源代码文件进行代码评审、代码质量检查、找出潜在 Bug 或风格问题时使用。 when_to_use: 用户提到“评审代码”、“检查代码”、“review”、“找出 bug”等场景时使用。 parameters: file_path: type: string description: 待评审的源代码文件路径然后写执行脚本# 文件路径skills/code-review/review.py import sys import json from pathlib import Path def load_params(param_file: str) - dict: with open(param_file, r, encodingutf-8) as f: return json.load(f) def review_code(file_path: str) - str: 一个非常简单的评审脚本。 真实项目中可以接入 pylint、eslint、spotbugs 等工具这里先用基础规则演示。 path Path(file_path) if not path.exists(): return json.dumps({error: f文件不存在: {file_path}}, ensure_asciiFalse) content path.read_text(encodingutf-8) issues [] lines content.splitlines() for index, line in enumerate(lines, start1): stripped line.strip() if len(stripped) 120: issues.append(f第 {index} 行代码长度超过 120 字符) if stripped.endswith( ) or stripped.endswith(\t): issues.append(f第 {index} 行结尾有多余空白) if print( in stripped and import not in stripped: issues.append(f第 {index} 行使用了 print 调试语句) if len(lines) 300: issues.append(文件过长建议拆分为多个模块) if not issues: result {file: file_path, status: passed, message: 未发现明显问题} else: result { file: file_path, status: warning, issues: issues[:20], total_issues: len(issues), } return json.dumps(result, ensure_asciiFalse, indent2) if __name__ __main__: param_file sys.argv[1] params load_params(param_file) file_path params.get(file_path) print(review_code(file_path))这个脚本做了一件事读取待评审文件的内容检查长度、尾随空格和疑似调试语句。真实项目中你可以换成 pylint 或 eslint但演示阶段足够说明问题了。4.7 运行与验证在项目根目录启动python main.py输入以下内容测试用户: 请评审一下当前目录下的 test.py如果代码评审脚本正常执行Agent 会返回类似下面这样的结果Agent: 我已经检查了 test.py发现以下潜在问题 1. 第 15 行代码长度超过 120 字符 2. 第 42 行使用了 print 调试语句。 建议优化这两处后再进行合并。这说明 Harness 已经成功完成了一次“任务理解 - Skill 选择 - 脚本执行 - 结果总结”的完整链路。5. 进阶实战把命令行工具封装成 Skill 插件5.1 业务场景上面的代码评审 Skill 能跑通基础流程。接下来我们做一个更贴近真实业务的 Skill根据 MySQL 表结构生成 CRUD 代码。这个场景在 AI 大模型应用开发中很常见。以前开发者需要手动写 SQL 建表语句再写 Java 或 Python 的数据访问代码。现在我们可以把“表结构分析”和“代码生成”封装成 Skill让 Agent 自动处理。考虑到完整生成代码会很长我这里用一个简化示例Skill 从 JSON 参数中读取表名和字段列表生成 SQL 建表语句和 Python CRUD 函数模板。5.2 设计 SKILL.md# SKILL.md 文件路径skills/crud-generator/SKILL.md name: crud-generator description: 当用户要求根据表结构生成建表 SQL 或 CRUD 操作代码时使用。 when_to_use: 用户提到“生成建表语句”、“生成 CRUD 代码”、“根据表结构写增删改查”等场景。 parameters: table_name: type: string description: 数据库表名 fields: type: array description: 字段列表每项包含 name、type、comment、primary_key 等属性5.3 编写脚本# 文件路径skills/crud-generator/generate.py import sys import json def load_params(param_file: str) - dict: with open(param_file, r, encodingutf-8) as f: return json.load(f) def generate_sql(table_name: str, fields: list) - str: 根据字段列表生成 MySQL 建表 SQL。 lines [fCREATE TABLE {table_name} (] column_defs [] for field in fields: name field.get(name) ftype field.get(type) comment field.get(comment, ) primary field.get(primary_key, False) nullable field.get(nullable, True) default field.get(default) col f {name} {ftype} if not nullable: col NOT NULL if default is not None: col f DEFAULT {default} if comment: col f COMMENT {comment} if primary: col PRIMARY KEY column_defs.append(col) lines.append(,\n.join(column_defs)) lines.append(f) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT{table_name};) return \n.join(lines) def generate_crud_python(table_name: str, fields: list) - str: 生成一个简单的 Python CRUD 类模板。 columns [field[name] for field in fields] placeholders , .join([%s] * len(columns)) columns_str , .join(columns) column_list_str , .join([f{col} for col in columns]) code f class {table_name.capitalize()}Repository: 基于 MySQL 的 {table_name} 表 CRUD 示例。 生产环境请使用参数化查询并放在事务中执行。 TABLE_NAME {table_name} COLUMNS [{column_list_str}] def __init__(self, connection): self.connection connection def create(self, data: dict) - None: sql fINSERT INTO {{self.TABLE_NAME}} ({columns_str}) VALUES ({placeholders}) with self.connection.cursor() as cursor: values [data.get(col) for col in self.COLUMNS] cursor.execute(sql, values) self.connection.commit() def get_by_id(self, record_id: int) - dict: sql fSELECT * FROM {{self.TABLE_NAME}} WHERE id %s with self.connection.cursor() as cursor: cursor.execute(sql, (record_id,)) row cursor.fetchone() return dict(row) if row else {{}} def update(self, record_id: int, data: dict) - None: set_clause , .join([f{{col}} %s for col in data.keys()]) sql fUPDATE {{self.TABLE_NAME}} SET {{set_clause}} WHERE id %s with self.connection.cursor() as cursor: values list(data.values()) [record_id] cursor.execute(sql, values) self.connection.commit() def delete(self, record_id: int) - None: sql fDELETE FROM {{self.TABLE_NAME}} WHERE id %s with self.connection.cursor() as cursor: cursor.execute(sql, (record_id,)) self.connection.commit() return code if __name__ __main__: param_file sys.argv[1] params load_params(param_file) table_name params.get(table_name) fields params.get(fields, []) # 自动把第一个字段设为主键如果没显式指定 if fields and not any(f.get(primary_key) for f in fields): fields[0][primary_key] True sql generate_sql(table_name, fields) py_code generate_crud_python(table_name, fields) result { table_name: table_name, sql: sql, python_code: py_code, } print(json.dumps(result, ensure_asciiFalse, indent2))这个脚本的作用是接收结构化字段信息输出建表 SQL 和 Python CRUD 代码模板。由于我们只需要向 Agent 演示 Skill 流程脚本逻辑相对简单不涉及真实数据库连接。5.4 在 Agent 中测试重启main.py输入类似这样的指令用户: 帮我生成一张用户表的建表语句和 CRUD 代码包含 id、name、email、created_at 四个字段模型解析意图后会尝试调用crud-generatorSkill并将字段信息以 JSON 形式传过去。最终 Agent 会返回类似这样的总结建表 SQL 已生成Python CRUD 类已生成代码中已经将 id 字段自动设为主键。到这里我们就实现了“一切皆插件”的最小闭环。以后想增加能力不需要改 Agent 主程序只要往skills目录下增加新文件夹即可。6. 常见问题与排查思路在开发 Harness 和 Skill 插件时最常遇到下面几类问题。我整理了一个排查表格问题现象常见原因解决思路调用 API 返回 401API Key 无效或未配置检查.env文件确认 Key 正确且余额充足模型不识别 Skill总是直接回答SKILL.md 描述不清晰重新编写 description 和 when_to_use写明触发场景Skill 脚本执行失败参数传递错误或脚本路径不对检查模型返回的 JSON 参数确认文件路径存在中文乱码文件编码不是 UTF-8在 Python 读取文件时显式指定 encodingutf-8响应超时网络问题或模型推理时间过长增大 requests 超时时间或检查网络稳定性上下文越来越长费用升高没有限制历史消息数量只保留最近 N 轮对话例如 10 轮模型输出 JSON 格式错误没有在提示词中强调格式在 System Prompt 中明确“不要输出多余文字”Skill 目录新增后未生效Agent 启动后没有再扫描将 Skill 扫描改为每次请求前动态读取如果你遇到“模型返回了 JSON 但 Harness 没解析出来”的情况建议按以下顺序排查打印模型原始输出确认是否包含代码块标记例如json ...有的话需要在解析前先去除。确认 JSON 中的 action 名称和 skills 目录名完全一致包括大小写。确认 Skill 目录下至少有一个 .py 脚本否则主程序找不到执行入口。查看子进程错误输出很多时候问题出在脚本内部的语法或路径权限上。7. 最佳实践与工程建议7.1 Skill 文件的命名与描述Skill 名称使用小写英文和连字符比如code-review、sql-optimizer。不要用中文命名目录避免跨平台文件系统兼容问题。description 是给大模型看的要做到“触发场景 参数说明 处理动作”三者齐全。示例description: 当用户要求优化 SQL 查询语句、分析慢查询、改写 SQL 执行计划时使用。 参数包括 sql_text 原始 SQL 以及 database_type 数据库类型。写描述的时候可以多写几个典型说法例如“评审”、“检查”、“review”、“code quality”都列进去。这样能显著提高模型选择 Skill 的准确率。7.2 密钥与配置管理API Key 永远不要写死在代码和 Skill 脚本中使用.env文件管理并在.gitignore中加入.env __pycache__/如果团队协作可以提供一个.env.example模板把 Key 字段留空其他人复制后填写自己的 Key。7.3 异常与重试调用大模型 API 时网络抖动是常态。建议在call_deepseek中增加指数退避重试逻辑。第一次失败后等待 1 秒重试第二次等待 2 秒最多重试 3 次。同时记录每次调用的耗时和 Token 消耗方便后续分析成本。7.4 安全边界Skill 执行脚本意味着 Agent 能够在你的机器上运行任意命令这里的安全风险必须重视。不要让普通用户直接指定任意 Skill 脚本路径涉及文件删除、数据库写操作、生产环境变更时必须增加审批或确认步骤Skill 脚本运行建议放入沙箱或容器至少也要限制工作目录和可执行命令范围数据库连接信息不要放在 Skill 参数中直接传给模型尽量从本地配置读取。尤其注意包含数据库删除、表结构变更的 Skill在生产环境必须由人确认后再执行。最小权限原则是 Agent 开发中最重要的一条底线。7.5 上下文与性能控制DeepAgent 的上下文是有限的。如果任务过程中既有工具调用又有历史对话很容易把上下文塞满。建议只保留最近 5 到 10 轮对话Skill 执行结果如果很长先做摘要再传给模型系统提示词中的 Skill 描述不要太长每段控制在几百字以内高频小任务可以单独创建轻量 Agent不要把所有能力都堆到一个 Harness 里。7.6 本地部署 DeepSeek 的衔接思路如果你的业务要求数据不出内网可以选择本地部署 DeepSeek 模型。常见链路是用 Ollama 或 vLLM 加载本地模型本地模型暴露 OpenAI 兼容的 API 接口Harness 的DEEPSEEK_BASE_URL指向本机或内网地址保持 Skill 插件架构不变只需替换模型层。这样做的好处是插件逻辑完全不用改只需要修改.env里的模型服务地址。但本地部署需要关注显存、推理速度、模型效果和运维成本尤其是并发场景需要额外考虑 GPU 调度。8. 总结与学习路线通过这篇文章你已经从零搭建了一套基于 DeepSeek 的 Harness 原型。你掌握的不仅仅是几个概念而是一条完整的 Agent 开发路径理解 Harness 在 Agent 架构中的作用知道 DeepAgent 和 Skill 是如何分工协作的能自己编写 SKILL.md 描述文件和 Skill 执行脚本能调试常见的 Skill 调用失败、API 鉴权、上下文过长等问题了解生产环境中插件化开发需要注意的安全和性能边界。下一步我建议按这样的路线继续深入学习学习 Function Calling / Tool Calling 机制把模型输出的 JSON 指令替换为更规范的结构化调用研究 MCPModel Context Protocol把外部工具接入方式标准化尝试接入 RAG检索增强生成让 Agent 能读取私有知识库体验多 Agent 协作把一个复杂任务拆给多个 Skill Agent 并行处理建立评测集用固定测试用例验证每次修改后的 Agent 效果防止回归。插件化是 AI Agent 工程化的重要方向。你现在写的每一个 Skill都是在为未来的项目积累可复用的能力。如果这篇文章对你有帮助可以收藏备用也欢迎在实际使用中把遇到的问题记录下来。技术只有亲手跑一遍才能真正变成自己的经验。

相关新闻

最新新闻

用Claude Code在Lean中形式化证明:AI与定理证明器的协作实践

用Claude Code在Lean中形式化证明:AI与定理证明器的协作实践

这次我们来看一个很特别的组合:陶哲轩公开演示了用 Claude Code 在 Lean 中形式化证明。很多人第一反应是“数学家也开始用 AI 编程工具了”,但更准确地说,这个演示展示了 AI 编程 Agent 和一个严格的证明助手之间是怎么协作的:Cl…

2026/9/1 11:01:49
网易iOS提前批笔试复盘:底层原理与算法并重的工程实战

网易iOS提前批笔试复盘:底层原理与算法并重的工程实战

网易这场提前批笔试,我是抱着“练手”心态投的,结果整套题做下来,发现它比很多大厂的正式批笔试都更有区分度——不是单纯考刷题量,而是真的在筛选“懂iOS的人”。如果你准备投2023届或者之后的iOS开发岗,这篇复盘建议…

2026/9/1 11:01:49
LangChain+LangGraph企业级Agent开发实战:从V1到可观测部署

LangChain+LangGraph企业级Agent开发实战:从V1到可观测部署

企业级 Agent 开发,现在绕不开两个框架:LangChain 和 LangGraph。LangChain 解决的是 LLM 应用开发的组件化问题,把模型对话、提示词模板、工具调用变成标准化模块;LangGraph 则把 Agent 从“一个循环调函数”升级成“一张可编排、…

2026/9/1 11:01:49
Excel数据分析实战:从数据清洗到可视化报表的完整流程

Excel数据分析实战:从数据清洗到可视化报表的完整流程

这次我们来看一个运营人拿到数据后,如何用 Excel 进行高效分析的实际操作流程。对于运营、市场、产品等岗位的同学来说,数据到手只是第一步,如何快速、准确、有深度地将其转化为洞察和决策依据,才是核心能力。Excel 作为最普及的数…

2026/9/1 11:01:49
MATLAB .m转.mlapp指南:从脚本到App Designer应用

MATLAB .m转.mlapp指南:从脚本到App Designer应用

简介:面向Matlab开发者与工程师的M文件转MLAPP格式转换工具包,用于将传统脚本升级为支持GUI与模块化封装的现代应用格式,解决旧项目交互能力弱、功能扩展难的问题,适合算法原型产品化、工程工具集成、科研代码整理及重构迁移等场景…

2026/9/1 11:01:49
从零构建拼豆在线编辑器:Canvas交互与图形算法实战

从零构建拼豆在线编辑器:Canvas交互与图形算法实战

大家好,我是长期分享前端与创意工具开发实战的博主。今天我们来深入探讨一个有趣且实用的项目:如何从零开始构建一个功能完整的“拼豆在线编辑器”。这类工具在手工爱好者、设计师和教育领域有着广泛的应用,它允许用户在网页上自由设计拼豆图…

2026/9/1 10:56:48