DeepSeek 的 Agent 公式:Model + Harness = Agent,工程外壳才是关键

2026-05-20 27 预计阅读时间:1 分钟
来源:oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:13 分钟

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,就像没有刹车的引擎——能发出声音,但不能上路。


相关推荐