用 Cursor 改仓库、让 Deep Research 扫论文、让浏览器 Agent 填表、让语音 Agent 打电话改账单——形态差很远,共同点只有一个:系统不再是「你问一句、它答一句」,而是自己决定下一步、并能调用工具

这一篇对应书的第 1 章:先把公式拆开,再看 ReAct 循环,最后落到 Harness——模型之外那一层工程为什么反而成了竞争力。

公式三件套:大脑、眼睛、手脚

Agent = LLM + 上下文 + 工具
直觉实现可选 RL 映射含义
大脑LLMPolicy理解意图、规划、决定是否行动
眼睛上下文Observation当前决策点能看见的全部信息
手脚工具Action能对世界做的全部操作集合

三个词都要广义理解:

  • LLM 不只是权重文件。它是决策内核:预训练给世界知识与语言,后训练(SFT / RL 等,第 7 章)固化「何时调工具、如何拆任务」一类策略。
  • 上下文 不只是用户刚打的那句话。系统提示、工具 schema、记忆、检索片段、轨迹、状态栏……凡是进了本次请求窗口的,都是「眼睛」。
  • 工具 不只是几个 JSON Function。预定义 API、Skills、动态写代码、子 Agent、事件入口、主动联系用户,都属于广义动作空间。

产品对照(只为建立直觉):

类型主要「看见」什么主要「动手」什么
Coding Agent需求、代码库、终端输出搜索、读写文件、跑命令/测试
Research Agent网页、论文、本地资料搜索、阅读、摘要、再搜索
Computer Use屏幕、DOM/无障碍树点击、输入、滚动、截图
办事类 Agent账户、账单、政策知识电话、邮件、表单、与人确认

共同特征通常是:动作空间相对开放(自然语言 + 代码,而不是三四个按钮)、能内部思考、能根据反馈持续改策略

工具调用四步:ReAct 的 API 地基

工具调用(Tool Calling / Function Calling)把「文本生成器」变成「可执行系统」的标准接口。一轮最小流程是:

  1. 在上下文里声明工具(名、描述、参数 schema)
  2. 模型决定是否调用、调哪个、参数是什么
  3. 运行时执行工具,把结果写成 tool 消息追加进上下文
  4. 模型基于结果继续推理或给出最终回答

用伪 API 形状写一遍(OpenAI 风格示意,逻辑通用于多数厂商):

# 可直接当阅读用骨架;接真实 API 时替换 client 与执行器即可
messages = [
    {"role": "system", "content": "你是助手。需要实时天气时调用 get_weather。"},
    {"role": "user", "content": "北京今天天气怎么样?"},
]
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "查询城市当前天气",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

# 第 2 步:模型返回 tool_calls(此处用手写结果模拟)
assistant = {
    "role": "assistant",
    "content": None,
    "tool_calls": [{
        "id": "call_1",
        "type": "function",
        "function": {"name": "get_weather", "arguments": '{"city":"北京"}'},
    }],
}
messages.append(assistant)

# 第 3 步:执行工具,结果回写
messages.append({
    "role": "tool",
    "tool_call_id": "call_1",
    "content": '{"temp": 28, "sky": "晴"}',
})

# 第 4 步:模型再读完整 messages,生成自然语言回答
# final = client.chat.completions.create(model=..., messages=messages)
# 典型输出:"北京今天 28°C,晴。"

设计工具时,优先通用执行器而不是无限堆专用按钮:与其做一个「计算器」工具,不如给沙箱里的 Python;与其做一个「写工作日志」工具,不如给受控的文件系统。通用性把组合空间留给模型,专用性把确定性留给业务规则——第 4 章会细讲粒度权衡。

上下文五块:每次推理到底吃了什么

从 API 视角,一次调用的上下文大致由五部分构成:

  1. 系统提示词:岗位说明书——身份、权限、流程、不可违反的规则;也可挂用户记忆与环境元信息。
  2. 工具定义:有哪些手脚可用;没有定义,模型通常无法发起规范调用。
  3. 用户消息:本轮输入;也可夹 RAG 检索片段。
  4. 模型回复:可能含 reasoning(内部思考)、content(对用户文本)、tool_calls(行动请求)。
  5. 工具结果:执行层回写的观察,驱动下一轮决策。

前两项多是相对稳定的前缀,后三项是增长中的轨迹。第 2 章会从 KV Cache 角度解释:为什么前缀稳定、为什么乱改历史会打爆缓存。

消融思维很有用:拿掉工具定义,模型只剩「嘴炮」;拿掉工具结果,循环断在半空;拿掉系统提示,行为边界全靠模型脾气。构建系统时,缺哪一块,失败模式往往能对上号。

ReAct:把三件套拧成一个环

ReAct(Reasoning + Acting)是把「思考 → 行动 → 观察」迭代起来的核心循环。工程上最简实现就是:

def run_agent(user_text: str, tools: list, max_steps: int = 20) -> str:
    """最小 Agent 循环:模型决定是否调工具,直到给出最终文本或触顶。"""
    messages = [
        {"role": "system", "content": "逐步完成任务。需要时调用工具,完成后直接回答用户。"},
        {"role": "user", "content": user_text},
    ]
    for step in range(max_steps):
        resp = llm_chat(messages, tools=tools)  # 返回 assistant 消息
        messages.append(resp)
        if not resp.get("tool_calls"):
            return resp.get("content") or ""
        for tc in resp["tool_calls"]:
            result = execute_tool(tc)  # 你的运行时
            messages.append({
                "role": "tool",
                "tool_call_id": tc["id"],
                "content": result,
            })
    return "达到步数上限,未完成。"

注意三点反直觉:

  1. 循环主体在客户端(或编排层),直到「模型即 Agent」把部分循环收进服务端(内置 search / code interpreter 等)。
  2. 观察必须回写上下文,否则下一轮模型在「失明」状态下继续幻觉。
  3. 停止条件不能只信模型嘴上的「完成了」——假成功与过早放弃是生产高频病,要用验证层兜住(见下文 Harness)。

旧系列里有更展开的 ReAct 专篇,本篇只建立与公式、Harness 的接口。

三种学习范式:别一提学习就想到训模型

Agent「从经验变好」不只靠改权重:

范式何时发生改什么特点
后训练训练时模型参数通用、贵、慢(第 7 章)
上下文学习推理时注意力里的临时模式快、会话结束即失
外部化学习运行时知识库、Skills、工具代码可审计、可更新、可验证

工程含义:能写进知识库或脚本的流程,不要硬塞进「再训一版模型」;能用评测驱动的后训练解决的通用能力,不要全靠超长提示词硬撑。三者时间尺度互补,第 8 章会回到自我进化时再拧紧。

Harness:模型之外的竞争力

公式描述内部组成;Harness 描述工程外壳——把 Model 绑进可靠任务执行的所有支撑代码。生产展开式:

Agent = Model + Harness
Harness ≈ 上下文 + 工具 + 约束 + 验证 + 纠正

例子帮助分界:

现象更靠近哪一层
系统提示里写退款政策摘要上下文
代码断言「退款额 ≤ 订单额」约束
调用支付 API工具
API 超时自动重试 / 换通道纠正
提交前用第二模型或规则审交付件验证

模型越强,自主决策面越大,出错半径也越大,对约束、验证、纠正的要求往往更高,而不是更低。Sutton 的 Bitter Lesson 提醒我们:长期看可扩展的方法会赢,模型会持续「吃掉」外围技巧。书里的务实立场可以记八个字:方向认同,节奏务实——今天模型还做不稳的,Harness 先补;模型每内化一层,Harness 卸一层,去兜下一道能力前沿。

编排光谱:工作流与自主不是二选一

一端是工作流:边由人定,模型只填节点。可控、可审计,适合合规硬、步骤固定的场景。
另一端是自主 Agent:边由模型在工具空间里长出来。适合开放问题、探索式任务。

中间大量是混合:关键节点人工或规则闸门,中间段落交给 ReAct。选型时问三句:

  1. 失败代价是「重答一遍」还是「真金白银 / 不可逆写操作」?
  2. 路径是否在事先可知、可穷举?
  3. 有没有客观验证器(测试、对账、schema)能当停止条件?

没有验证器的「全自主」,多半是把不确定性外包给运气。

护栏与安全:最小集合

第 1 章收束时常落在护栏上,这里只列工程最小集,细账在工具章与安全专文:

  • 权限最小化:工具默认只读,写操作分工具、分路径、分审批。
  • 参数校验:类型、范围、业务不变量在进真实副作用前检查。
  • 人类在环:高风险动作前确认;超时与异常路径可中止。
  • 轨迹可回放:messages + tool 结果落盘,否则无法评测与追责。

本篇收束

  1. 先用 LLM + 上下文 + 工具 理解系统,再用 Model + Harness 理解生产。
  2. ReAct 是三件套的时间展开;观察回写与停止条件比「多写一句 chain-of-thought」更关键。
  3. 学习有后训练 / 上下文 / 外部化三条路,工程要会分流。
  4. 模型变强不会消灭 Harness,只会改变 Harness 的厚度与位置。

下一篇进入第 2 章主场:上下文工程——消息结构、KV Cache 友好设计、Skills、状态栏与压缩策略。那是全书最「日常」也最容易把系统拖死的一层。

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:01. Agent 入门与 Harness:Model 之外才是竞争力

本文链接:https://www.sshipanoo.com/blog/ai/ai-agent-indepth/01-Agent入门与Harness/

本文最后一次更新为 天前,文章中的某些内容可能已过时!