摘要:
最近“DeepSeek Harness”这个词在Agent和Coding Agent圈里快速升温。
但真正值得开发者研究的,不是某个项目是不是“国产Claude Code”。
更重要的问题是:为什么同一个DeepSeek V4模型,放进不同Agent工具里,实际完成任务的能力会差这么多?
答案在Harness。
本文从插件协议、任务状态机、上下文管理、工具注册、沙箱、验证闭环、模型适配与多模型路由几个角度,拆解Model + Harness = Agent背后的工程实现。
FACT-001|先把“官方信息”和“第三方项目”分开
DeepSeek官方目前可以确认的是:V4明确强化了Agentic Coding能力,并提供Claude Code、OpenCode、OpenClaw、Copilot CLI、Pi等Agent与Coding Assistant的官方接入文档。
DeepSeek官方GitHub中也存在awesome-deepseek-agent仓库,用于整理V4 Pro / Flash与不同Agent工具的集成方案。
但“DeepSeek官方独立Harness产品、MIT协议、npx @deepseek-ai/dsh web、4小时34K stars”等说法,目前没有在DeepSeek官方组织仓库或API文档里找到对应页面。
当前公开的deepseek-harness项目来自第三方开发者,因此本文不会把第三方项目属性写成DeepSeek官方产品事实。
1. Harness到底是什么?先别把它理解成一个“Agent App”
用汽车做类比其实非常准确。
大模型更像发动机。
它提供推理、理解和生成能力。
但只有发动机,没有方向盘、刹车、仪表盘、传动系统和车身,仍然不能真正上路。
Harness负责的就是“整车系统”。
Agent = Model + Context + Planner + Tools + State + Memory + Guardrails + Verifier + Retry / Recovery所以Harness不是简单包一层UI。
它真正控制的是模型如何拿到上下文、如何调用工具、如何执行、如何验证以及什么时候停止。
2. DeepSeek V4为什么特别适合拿来讨论Harness
DeepSeek V4官方发布时,就把Agentic Coding单独列为重点能力。
V4 Pro面向更复杂的Agent任务。
V4 Flash则强调更低成本和更快速度,并且在简单Agent任务上接近Pro。
两者都支持1M上下文和工具调用。
这给Harness留下了很大的调度空间。
User Task ↓ Harness ├── Simple Search → V4 Flash ├── File Summary → V4 Flash ├── Main Planning → V4 Pro ├── Deep Debug → V4 Pro └── Result Check → Flash / Pro同一个用户任务内部,可以同时使用多个模型层级。
这已经不是传统Chatbot的调用方式。
3. Harness的第一层:Plugin Contract,而不是“所有代码写死”
真正可扩展的Harness,需要把模型、工具、记忆、工作流甚至UI能力抽象成插件。
否则每增加一种Agent场景,都要复制整套代码。
from dataclasses import dataclass from typing import Protocol, Any class Plugin(Protocol): name: str version: str async def setup(self, context: dict) -> None: ... async def invoke(self, payload: dict) -> Any: ... async def teardown(self) -> None: ... @dataclass class PluginMeta: name: str version: str kind: str permissions: set[str] enabled: bool = True有了统一Plugin Contract以后,模型适配、网页工具、知识库、终端、视觉理解都可以挂在同一个运行时上。
PLUGIN-101|NO_CONTRACT
插件只靠约定调用,没有统一输入输出、生命周期和权限声明,插件数量一多就无法治理。
4. 第二层:Model Adapter,让Harness和模型解耦![]()
插件化系统最重要的一个能力,是不能把Agent逻辑写死在某一家模型SDK上。
DeepSeek官方同时提供OpenAI兼容和Anthropic兼容接口。
这意味着Harness完全可以做统一Model Adapter。
class ModelAdapter(Protocol): async def generate( self, messages: list[dict], tools: list[dict], ) -> dict: ... class DeepSeekAdapter: def __init__(self, client, model: str): self.client = client self.model = model async def generate(self, messages, tools): return await self.client.chat( model=self.model, messages=messages, tools=tools, )如果以后换成其他兼容模型,只需要新增Adapter。
Planner、Tool Registry和Task State都不需要重写。
5. 第三层:Task State,专门解决“目标遗忘”和“任务跑偏”
长任务最怕的不是模型不会做,而是做了十几轮以后开始忘记最初目标。
from dataclasses import dataclass, field from enum import Enum class Phase(str, Enum): PLAN = "plan" EXECUTE = "execute" VERIFY = "verify" DONE = "done" FAILED = "failed" @dataclass class TaskState: task_id: str goal: str phase: Phase plan: list[str] = field(default_factory=list) completed: list[str] = field(default_factory=list) observations: list[str] = field(default_factory=list) iteration: int = 0 max_iterations: int = 20Goal、Plan、Completed、Observation应该成为结构化状态。
不能只靠模型“自己记住”。
STATE-202|STATE_IN_PROMPT_ONLY
任务状态全部存在自然语言上下文里,上下文压缩、断线恢复或者多Agent协作时都容易丢状态。
6. 第四层:Tool Registry,工具不能等于“无限Shell”
Agent真正开始“干活”,靠的不是回答,而是工具。
读文件、检索网页、调用数据库、运行测试、分析图片,都应该被抽象成受控能力。
from dataclasses import dataclass from typing import Callable @dataclass class Tool: name: str handler: Callable read_only: bool = True requires_approval: bool = False timeout_seconds: int = 60 class ToolRegistry: def __init__(self): self.tools = {} def register(self, tool: Tool): self.tools[tool.name] = tool def get(self, name: str) -> Tool: if name not in self.tools: raise KeyError(f"unknown tool: {name}") return self.tools[name]工具必须声明权限。
读操作和写操作不能混在一起。
高风险工具还应该进入审批。
TOOL-303|UNRESTRICTED_TOOL
所有插件都能任意读写本地文件、访问公网或执行命令,插件化会直接变成权限失控。
7. 第五层:“一切皆插件”真正难在权限,不在安装
插件越多,系统越灵活。
但同时攻击面也越大。
所以插件系统必须带Capability声明。
plugin: name: vision-reviewer permissions: - image.read - model.invoke network: allow: - api.example-model.com filesystem: read: - /workspace/assets write: [] secrets: - VISION_PROVIDER_KEY这样一个视觉插件只能读取素材并调用模型。
它没有权限修改代码,也不能访问任意网络。
8. 第六层:Context Engineering,1M上下文不等于“全塞进去”![]()
DeepSeek V4已经把1M上下文作为默认能力。
但Harness仍然要做上下文选择。
因为Context越大,不代表有效信息比例越高。
@dataclass class ContextItem: source: str relevance: float freshness: float token_count: int content: str def select_context(items, budget): items = sorted( items, key=lambda x: 0.7 * x.relevance + 0.3 * x.freshness, reverse=True, ) result, used = [], 0 for item in items: if used + item.token_count > budget: continue result.append(item) used += item.token_count return resultContext Engineering不是“拼Prompt”。
它更像一个实时信息调度系统。
CTX-404|DUMP_EVERYTHING
因为模型支持超长上下文就把全部文件、历史和日志塞进去,最终会同时增加噪声、延迟与成本。
9. 第七层:Plan → Execute → Verify,才是长任务真正的闭环![]()
Harness最重要的设计,不是一次调用有多聪明。
而是失败以后还能不能继续。
async def run_task(state: TaskState): while state.iteration < state.max_iterations: if state.phase == Phase.PLAN: state.plan = await planner(state) state.phase = Phase.EXECUTE elif state.phase == Phase.EXECUTE: observation = await executor(state) state.observations.append(observation) state.phase = Phase.VERIFY elif state.phase == Phase.VERIFY: passed = await verifier(state) if passed: state.phase = Phase.DONE return state state.phase = Phase.PLAN state.iteration += 1 state.phase = Phase.FAILED return stateSTEP 1|计划
先明确当前要做什么,避免模型一上来就直接操作。
STEP 2|执行
通过受控工具完成当前步骤,并保存Observation。
STEP 3|验证
检查任务是不是满足验收条件,而不是相信模型自己宣布完成。
STEP 4|继续
如果验证失败,根据新的Observation重新规划,而不是整条任务重来。
10. 第八层:Checkpoint解决“长任务中途断掉怎么办”![]()
真正跑半小时以上的Agent,不可能保证永远不断线。
模型服务可能超时,工具可能失败,用户也可能关闭页面。
@dataclass class Checkpoint: task_id: str goal: str current_plan: list[str] completed_steps: list[str] important_context: list[str] unresolved_errors: list[str] next_action: str恢复任务时,不需要重新把完整历史塞给模型。
只需要恢复继续工作必需的最小状态。
11. 第九层:模型路由,让Pro和Flash承担不同工作
Agent和普通对话最大的不同,是一个任务内部可以调用几十次模型。
如果每次都使用最贵模型,成本会快速放大。
def route_model(task_type: str, complexity: int): if task_type in { "summarize_file", "classify", "simple_tool_decision", }: return "deepseek-v4-flash" if complexity <= 2: return "deepseek-v4-flash" return "deepseek-v4-pro"主规划和复杂Debug可以使用Pro。
文件摘要、分类和简单子任务可以交给Flash。
12. 视觉Agent怎么做?重点仍然不是“换个多模态模型”
如果需要增加图片理解能力,可以增加一个Vision Adapter。
底层模型可以是任何符合接口的视觉模型。
class VisionAdapter: async def analyze( self, image_uri: str, instruction: str, ) -> dict: result = await self.client.generate( image=image_uri, prompt=instruction, ) return { "summary": result.text, "confidence": result.score, }真正重要的是Harness仍然统一负责权限、任务状态、工具调用与结果验证。
换模型只是Adapter层的事情。
13. 为什么这套架构也适用于多模型AI平台
如果平台只有聊天,聚合模型主要解决“选谁回答”。
当平台加入智能体、图片、视频、音频、漫剧和PPT以后,任务已经不再是一次调用。
它会变成多阶段工作流。
User Goal ↓ Task Planner ↓ Text Model ↓ Image / Video / Audio Model ↓ Asset Registry ↓ Quality Gate ↓ Final Deliverable对于创源AIGC这类聚合500+模型,并同时提供智能体、无限画布、AI漫剧、AI PPT等能力的平台来说,下一阶段真正有技术价值的部分并不是继续把模型列表做长。
而是让不同模型通过统一Harness参与同一个任务。
Multi-Model Harness ├── Model Registry ├── Model Router ├── Plugin Runtime ├── Tool Registry ├── Task State ├── Asset Registry ├── Workflow DAG ├── Checkpoint ├── Quality Gate └── Audit Log14. 五个Harness系统最容易踩的坑
PLUGIN-101|PLUGIN_WITHOUT_PERMISSION
插件支持热插拔,但没有权限声明和隔离,扩展能力越多,安全风险越高。
STATE-202|NO_CHECKPOINT
Agent任务状态只保存在当前会话里,一旦中断就只能从头开始。
TOOL-303|SHELL_EVERYWHERE
所有工具最终都被实现成任意Shell命令,平台失去最小权限和审计能力。
CTX-404|CONTEXT_IS_STORAGE
把上下文窗口当数据库使用,不做筛选、压缩和状态持久化。
DONE-505|MODEL_SAYS_DONE
模型说任务完成就直接返回,没有独立Verifier确认验收条件。
15. 如果真要做一个Harness,建议从这4层开始
STEP 1|先做统一状态模型
不要先追求复杂插件市场,先保证Goal、Plan、Observation和Checkpoint能够可靠保存。
STEP 2|再做Tool Registry
把读、写、网络和执行能力显式拆开,建立最小权限模型。
STEP 3|然后做Verifier
没有独立验收的Agent,本质上只是会自动连续聊天。
STEP 4|最后做插件和多模型路由
等运行时稳定以后,再扩展视觉模型、第三方模型、办公插件与复杂Workflow。
16. 最后:Agent下一阶段拼的,可能真的不是模型
过去两年,我们习惯把AI产品差异归结为模型差异。
但Agent时代开始以后,越来越多体验差距会来自模型之外。
上下文怎么选。
工具怎么开放。
状态怎么保存。
任务怎么恢复。
结果怎么验收。
模型怎么分工。
这些才是Harness真正要解决的问题。
模型决定Agent的智力上限。
Harness决定这个上限能不能稳定地变成真实产出。