DeepSeek 近期挂出"Agent Harness 产品经理"岗位,正式组建 Harness 团队。招聘信息里一句话把思路钉得很死——Model + Harness = Agent。模型是引擎,Harness 是底盘、方向盘和刹车。引擎再强,没有底盘也跑不起来。
这个公式不是修辞,是工程事实。下面拆开看 Harness 到底要包什么,以及你自己怎么搭一个最小 Harness。
Harness 不是"套壳",是 Agent 的工程骨架
招聘信息把 Harness 定义为让 Agent 可靠工作的"工程外壳"。这个词选得精准——Harness 在英文里本意就是"挽具",套在马身上把拉力变成可控运动的整套装备。
对 Agent 来说,模型只负责"想"和"说"。真正让 Agent 在生产环境里干活,至少要兜住这几层:
| 层级 | 模型做的事 | Harness 要兜的事 |
|---|---|---|
| 感知 | 理解用户意图 | 输入校验、格式适配、多模态预处理 |
| 规划 | 拆解任务、生成步骤 | 步骤编排、依赖管理、失败重试 |
| 执行 | 决定调用哪个工具 | 工具注册/鉴权、参数校验、超时熔断 |
| 记忆 | 上下文推理 | 会话存储、长期记忆检索、摘要压缩 |
| 反馈 | 生成回复 | 输出格式化、幻觉过滤、安全审计 |
每一层都有模型"出主意"的部分和 Harness"兜底线"的部分。模型可以幻觉,Harness 不能幻觉——工具调用参数必须校验,超时必须熔断,敏感输出必须拦截。
为什么 DeepSeek 单独拉一个团队做这件事
把 Harness 和模型分开做,背后有一个工程判断:模型的迭代节奏和 Harness 的迭代节奏完全不同。
模型迭代靠算力、靠数据、靠训练周期,节奏是月级别。Harness 迭代靠场景反馈、靠 bug 修复、靠工具接入,节奏是天级别。如果 Harness 耦合在模型团队里,要么模型拖慢 Harness 的响应速度,要么 Harness 打断模型的训练节奏。拆团队是让两边各自按自己的节奏跑。
另一个隐含判断:Harness 是产品壁垒。模型会趋同——各家大模型在基准测试上差距在缩小,开源模型追得很快。但 Harness 做得好不好,直接决定 Agent 是"能 demo"还是"能干活"。用户感知到的可靠性、响应速度、工具覆盖度,全在 Harness 这一层。
自己搭一个最小 Harness:从模型到能跑的 Agent
DeepSeek 的 Harness 还在招人,但思路已经公开了。下面用 Python 写一个最小 Harness,把一个裸模型包成能调用工具、有记忆、有熔断的 Agent。你可以直接跑,也可以在此基础上扩展。
依赖只需要两个:openai(DeepSeek API 兼容 OpenAI SDK)和标准库。
"""
minimal_harness.py — 把裸模型包成 Agent 的最小 Harness
依赖: pip install openai
运行: python minimal_harness.py
"""
import json
import time
import os
from openai import OpenAI
# ---------- 1. 工具注册层 ----------
# Harness 的第一件事:声明 Agent 能用什么工具,参数长什么样
TOOLS = {
"get_weather": {
"description": "查询指定城市的当前天气",
"parameters": {
"city": {"type": "string", "description": "城市名,如 '北京'"},
},
"timeout": 5, # 超时熔断阈值(秒)
},
"search_docs": {
"description": "在内部文档库中搜索关键词",
"parameters": {
"query": {"type": "string", "description": "搜索关键词"},
"limit": {"type": "integer", "description": "返回条数,默认5"},
},
"timeout": 10,
},
}
# ---------- 2. 工具执行层 ----------
# Harness 的第二件事:真正执行工具调用,加上校验和熔断
def execute_tool(name: str, params: dict) -> dict:
"""执行工具调用,带参数校验 + 超时熔断"""
if name not in TOOLS:
return {"error": f"未知工具: {name}"}
tool_spec = TOOLS[name]
# 参数校验:只允许声明过的参数通过
allowed_keys = set(tool_spec["parameters"].keys())
filtered = {k: v for k, v in params.items() if k in allowed_keys}
# 缺失必要参数则补默认值或报错
for k, spec in tool_spec["parameters"].items():
if k not in filtered:
if spec["type"] == "integer":
filtered[k] = 5 # 简单默认值
else:
return {"error": f"缺少必要参数: {k}"}
# 模拟执行(真实场景替换为实际 API 调用)
start = time.time()
try:
# 这里用 mock 数据演示,真实 Harness 会调外部服务
if name == "get_weather":
result = {"city": filtered["city"], "temp": "22°C", "condition": "晴"}
elif name == "search_docs":
result = {"matches": [f"文档{i}: 包含关键词'{filtered['query']}'" for i in range(filtered.get("limit", 5))]}
else:
result = {"error": "未实现"}
elapsed = time.time() - start
if elapsed > tool_spec["timeout"]:
return {"error": f"工具 {name} 超时 ({elapsed:.1f}s > {tool_spec['timeout']}s)"}
return result
except Exception as e:
return {"error": f"工具 {name} 执行异常: {e}"}
# ---------- 3. 会话记忆层 ----------
# Harness 的第三件事:管理上下文,防止 token 爆炸
MAX_HISTORY = 10 # 保留最近 10 轮对话
def manage_history(history: list, new_msg: dict) -> list:
"""追加消息并裁剪历史,防止上下文过长"""
history.append(new_msg)
if len(history) > MAX_HISTORY:
# 简单策略:保留 system + 最近消息
# 更成熟的 Harness 会做摘要压缩
history = history[-MAX_HISTORY:]
return history
# ---------- 4. Agent 主循环 ----------
# Harness 的核心:把模型推理和工具执行串成闭环
SYSTEM_PROMPT = """你是一个助手,可以调用工具帮助用户。
当需要外部信息时,你必须通过工具获取,不要凭猜测回答。
可用工具: {tool_names}
调用工具时严格按参数规范传值。"""
def build_tool_schema():
"""把 TOOLS 注册表转成 OpenAI function calling 格式"""
functions = []
for name, spec in TOOLS.items():
func = {
"name": name,
"description": spec["description"],
"parameters": {
"type": "object",
"properties": spec["parameters"],
"required": [k for k in spec["parameters"]],
},
}
functions.append(func)
return functions
def run_agent(user_input: str, history: list) -> str:
"""Agent 主循环:推理 → 工具调用 → 再推理,最多 3 轮"""
client = OpenAI(
api_key=os.environ.get("DEEPSEEK_API_KEY", "sk-xxx"),
base_url=os.environ.get("DEEPSEEK_BASE_URL", "https://api.deepseek.com"),
)
tool_schema = build_tool_schema()
system_msg = SYSTEM_PROMPT.format(
tool_names=", ".join(TOOLS.keys())
)
history = manage_history(history, {"role": "user", "content": user_input})
max_rounds = 3 # 防止无限循环
for _ in range(max_rounds):
messages = [{"role": "system", "content": system_msg}] + history
resp = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
functions=tool_schema,
function_call="auto",
)
msg = resp.choices[0].message
# 模型选择直接回复 → 结束
if msg.function_call is None:
history = manage_history(history, {"role": "assistant", "content": msg.content})
return msg.content
# 模型选择调用工具 → 执行 → 把结果喂回模型
func_name = msg.function_call.name
try:
func_args = json.loads(msg.function_call.arguments)
except json.JSONDecodeError:
func_args = {}
tool_result = execute_tool(func_name, func_args)
# 记录工具调用和结果
history = manage_history(history, {
"role": "assistant",
"content": None,
"function_call": {
"name": func_name,
"arguments": msg.function_call.arguments,
},
})
history = manage_history(history, {
"role": "function",
"name": func_name,
"content": json.dumps(tool_result, ensure_ascii=False),
})
return "Agent 达到最大推理轮数,终止。"
# ---------- 5. 运行 ----------
if __name__ == "__main__":
history = []
print("=== 最小 Harness Agent Demo ===")
print("输入问题,Ctrl+C 退出\n")
while True:
try:
user_input = input("你: ")
if not user_input.strip():
continue
answer = run_agent(user_input, history)
print(f"Agent: {answer}\n")
except KeyboardInterrupt:
print("\n退出。")
break
运行前设置环境变量:
export DEEPSEEK_API_KEY="你的 API Key"
# 如果用 DeepSeek 官方 API,base_url 不用改
# 如果用其他兼容端点,按需设置
export DEEPSEEK_BASE_URL="https://api.deepseek.com"
pip install openai
python minimal_harness.py
这个 Harness 虽小,但已经兜住了 DeepSeek 公式里提到的关键层:工具注册与校验、超时熔断、会话记忆裁剪、推理-执行闭环。模型只负责"想",所有兜底线的活都在 Harness 里。
从最小 Harness 到生产 Harness,差距在哪
上面的代码能跑,但离生产还有几道坎:
可靠性。工具调用的参数校验只做了最简单的过滤。生产 Harness 需要 schema 校验(用 pydantic 或 jsonschema)、重试策略(指数退避)、降级方案(工具挂了走备用路径)。
安全性。没有做输出审计。模型可能泄露工具返回里的敏感字段,或者生成有害内容。生产 Harness 要在输出层加过滤——关键词拦截、PII 检测、甚至二次模型审核。
可观测性。没有日志、没有 trace。生产 Harness 必须记录每轮推理的 token 消耗、工具调用耗时、失败原因,方便排查和优化。OpenTelemetry 或 Langfuse 这类方案可以直接接入。
编排能力。当前只支持单线循环。真实场景需要并行工具调用、条件分支、子任务委派。这涉及 DAG 编排或类 LangGraph 的状态机设计。
DeepSeek 招 Harness 团队,大概率就是要补这些。从招聘"产品经理"这个信号看,他们不是在做底层框架,是在做面向开发者和终端用户的产品——意味着上面的每一层都要有配置界面、SDK 接口和可视化调试。
什么时候该自己搭,什么时候该等 DeepSeek
如果你现在就要在生产环境跑 Agent,自己搭 Harness 是唯一选择。上面的最小版本可以当起点,按场景逐步补校验、熔断、审计。核心原则:模型可以犯错,Harness 不能放任错误流出。
如果你在做原型验证或内部工具,可以先用 LangChain/LangGraph 这类现成框架快速搭。它们本质上也是 Harness,只是通用性强、深度不够。等 DeepSeek 的 Harness 产品出来后,再评估是否切换——切换成本主要在工具注册格式和会话存储接口,这两块提前做好抽象就不怕。
一个简单的决策清单:
- ✅ 自己搭:Agent 涉及自研工具、有严格安全要求、需要深度定制编排逻辑
- ✅ 用现成框架:快速验证、工具都是标准 API、安全要求中等
- ⏳ 等 DeepSeek Harness:如果你主要用 DeepSeek 模型、且希望官方方案做深度优化(比如模型和 Harness 的联合调优),可以观望,但不要把当前进度赌在上面
Model + Harness = Agent 这个公式,拆开看就是:模型提供智能,Harness 提供工程确定性。没有 Harness 的 Agent,就像没有刹车的引擎——能发出声音,但不能上路。