2026年很多Agent产品爆火了,从OpenClaw到Hermes,再到Codex、Workbuddy等,这些Agent突然闯入了我们的工作和生活中。人们都在谈Agent,那Agent到底是什么?NVIDIA GTC 台北2026中,黄仁勋给出了以下解释:Agent=LLM+Harness。谈一下我的理解,LLM相当于人类的大脑,Harness相当于人的四肢与感官,LLM提供思考能力,感官与四肢可以与现实进行互动。

从定义来看,Agent能够感知环境、进行决策并执行行动以达成特定目标。有这么一个公式:Agent = LLM (大脑) + Planning (规划) + Tool use (执行) + Memory (记忆)。

相较于传统的软件,Agent更像是一个有自主性的员工,他可以理解用户的任务目标,制定计划、使用工具、根据情况调整、持续执行直到完成任务。

这里提一个实际的Agent任务例子,比如我让Agent帮我打车到公司,Agent会先分析这是一个使用APP的任务,拆解任务为:1. 找到打车软件 2. 输入目的地 3. 下单,然后模拟用户操作去完成下单,每次操作截图使用视觉模型分析当前页面及下一步要点击的位置,直到页面显示正在呼叫司机。

在这个例子中,LLM负责思考,Planning负责拆解任务,Tool Use负责完成具体操作,Memory负责记住用户的信息比如公司位置、打车平台偏好等。

ReAct模式:Reasoning + Act

提到Agent,不得不说ReAct模式,即Reasoning+Act,可以理解为边思考边行动。ReAct模式是常见的Agent推理执行模式,通常分为以下步骤:

  1. Thought(思考):LLM理解任务并拆解任务,判断下一步操作
  2. Action(行动):Harness使用工具完成相应的任务
  3. Observation(观察):程序将工具执行返回给LLM,LLM基于结果判断下一步
  4. Repeat(循环):重复1-3,直到LLM认为任务已完成并给出最终答案

对应前边我们提到的Agent=LLM+Harness,Agent能力上限不仅仅取决于LLM,还取决于Harness的设计,以及LLM+Harness这个套餐适配程度。之前看到一个观点,LLM厂商通常会对自家Harness做针对性优化,在这个背景下,原厂LLM+原厂Harness理论上会更稳定。

我写了一个Agent ReAct模式的代码,工具是计算器,用户提问内容是:“帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案”,源代码放到文末了,先看打印输出:

打印输出

=== 第 1 次调用 ===
[1] system
你是一个简洁的 Agent。需要计算时使用 calculator 工具。
[2] user
帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案
=== tools definitions ===
{
  "type": "function",
  "function": {
    "name": "calculator",
    "description": "用于执行简单数学计算",
    "parameters": {
      "type": "object",
      "properties": {
        "expression": {
          "type": "string",
          "description": "要计算的数学表达式,例如:2 + 3 * 4"
        }
      },
      "required": [
        "expression"
      ]
    }
  }
}
LLM 返回内容:先算第一个表达式:6 * 5 + 6
LLM 返回 tool call:
  tool_call_id: call_00_guHDSVstflmqe6hru9rZ9277
  name: calculator
  arguments: {"expression": "6 * 5 + 6"}
LLM tool call 执行内容:
  tool_call_id: call_00_guHDSVstflmqe6hru9rZ9277
  name: calculator
  arguments: {'expression': '6 * 5 + 6'}
tool 执行结果:36
=== 第 2 次调用 ===
[1] system
你是一个简洁的 Agent。需要计算时使用 calculator 工具。
[2] user
帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案
[3] assistant
先算第一个表达式:6 * 5 + 6
[4] tool
36
tool_call_id: call_00_guHDSVstflmqe6hru9rZ9277
=== tools definitions ===
<省略>
=== tools definitions ===
LLM 返回内容:再计算 36 × 2:
LLM 返回 tool call:
  tool_call_id: call_00_dvhsq8Jk5Lm6504Afrg19236
  name: calculator
  arguments: {"expression": "36 * 2"}
LLM tool call 执行内容:
  tool_call_id: call_00_dvhsq8Jk5Lm6504Afrg19236
  name: calculator
  arguments: {'expression': '36 * 2'}
tool 执行结果:72
=== 第 3 次调用 ===
[1] system
你是一个简洁的 Agent。需要计算时使用 calculator 工具。
[2] user
帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案
[3] assistant
先算第一个表达式:6 * 5 + 6
[4] tool
36
tool_call_id: call_00_guHDSVstflmqe6hru9rZ9277
[5] assistant
再计算 36 × 2:
[6] tool
72
tool_call_id: call_00_dvhsq8Jk5Lm6504Afrg19236
=== tools definitions ===
<省略>
=== tools definitions ===
LLM 返回内容:计算结果如下:
1. **6 × 5 + 6** = 30 + 6 = **36**
2. **36 × 2** = **72**
最终答案是 **72** ✅
============================================
最终结果: 计算结果如下:
3. **6 × 5 + 6** = 30 + 6 = **36**
4. **36 × 2** = **72**
最终答案是 **72** ✅

代码执行过程分析

在这个代码执行过程中,我们来分析一下:

  1. Thought阶段: LLM接收到用户的指令:"帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案"以及tool定义后,LLM判断需要执行计算,返回了第一个tool call
  2. Action阶段: 程序调用eval来执行tool call,生成结果
  3. Observation阶段:程序将结果追加到messages中,用于LLM后续思考
  4. Thought阶段:LLM读取上一轮Observation,发现任务未完成,返回第二个tool call
  5. Action阶段:程序调用eval来执行tool call,生成结果
  6. Observation阶段:程序将结果追加到messages中,用于LLM后续思考
  7. Final Answer阶段:LLM读取上一轮Observation,判断任务已完成,直接生成最终答案

最后

本文我们了解了Agent是什么以及它的工作原理,纸上得来终觉浅,真正上手后还能体会到Agent与LLM的不同。最后我来推荐几个用的还不错的Agent:

  1. Codex,推荐指数5星,拥有Computer Use、浏览器操作功能的桌面Agent,既可完成工作也可以编写代码,免费用户有额度,订阅用户经常会重置用量(好评)
  2. WorkBuddy,推荐指数4星半,腾讯家的桌面Agent,有免费额度可用,可以用于工作和生活中,容易上手,推荐所有人使用,是当前国内最热的Agent之一
  3. Github Copilot(程序开发),推荐指数4星半,有免费额度,作为IDE插件,代码补全很好用,也可以对代码提问
  4. Claude Code(程序开发),推荐指数4星,定位是开发者工具,编程领域强大,缺点是需要购买LLM、对普通办公用户不太友好。但是,如果你是开发者并已经订阅了Coding Plan,那它的推荐指数可以给到5星,Claude Code已经成为CLI编程Agent的标杆产品。

附源码

import os
import json
from openai import OpenAI
client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
def calculator(expression: str) -> str:
    try:
        result = eval(expression, {"__builtins__": {}})
        return str(result)
    except Exception as e:
        return f"计算失败:{e}"
tools = [
    {
        "type": "function",
        "function": {
            "name": "calculator",
            "description": "用于执行简单数学计算",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "要计算的数学表达式,例如:2 + 3 * 4"
                    }
                },
                "required": ["expression"]
            }
        }
    }
]
tool_map = {
    "calculator": calculator
}
def print_messages(messages):
    """打印当前完整对话上下文"""
    print("\n========== 当前 messages ==========")
    for i, m in enumerate(messages, 1):
        print(f"\n[{i}] role: {m.get('role') if isinstance(m, dict) else m.role}")
        if isinstance(m, dict):
            print(f"content: {m.get('content')}")
            if m.get("tool_call_id"):
                print(f"tool_call_id: {m.get('tool_call_id')}")
        else:
            print(f"content: {m.content}")
            if m.tool_calls:
                print("tool_calls:")
                for tc in m.tool_calls:
                    print(f"  id: {tc.id}")
                    print(f"  name: {tc.function.name}")
                    print(f"  arguments: {tc.function.arguments}")
    print("===================================\n")
def dedupe_repeated_content(content: str) -> str:
    normalized = content.strip()
    if not normalized:
        return content
    if len(normalized) % 2 == 0:
        first_half = normalized[: len(normalized) // 2].strip()
        second_half = normalized[len(normalized) // 2 :].strip()
        if first_half and first_half == second_half:
            return first_half
    lines = normalized.splitlines()
    if len(lines) % 2 == 0:
        half = len(lines) // 2
        first_half_lines = [line.rstrip() for line in lines[:half]]
        second_half_lines = [line.rstrip() for line in lines[half:]]
        if first_half_lines == second_half_lines:
            return "\n".join(first_half_lines).strip()
    paragraphs = [p.strip() for p in normalized.split("\n\n") if p.strip()]
    if len(paragraphs) % 2 == 0:
        half = len(paragraphs) // 2
        if paragraphs[:half] == paragraphs[half:]:
            return "\n\n".join(paragraphs[:half])
    return content
def build_full_prompt(messages, tools=None):
    """构建完整 prompt 文本,包含 messages 和 tools 定义"""
    prompt_chunks = []
    for i, m in enumerate(messages, 1):
        if isinstance(m, dict):
            role = m.get("role")
            content = m.get("content", "")
        else:
            role = m.role
            content = m.content
        prompt_chunks.append(f"[{i}] {role}\n{content}")
        if isinstance(m, dict) and m.get("tool_call_id"):
            prompt_chunks.append(f"tool_call_id: {m['tool_call_id']}")
    if tools:
        prompt_chunks.append("\n=== tools definitions ===")
        for tool in tools:
            prompt_chunks.append(json.dumps(tool, ensure_ascii=False, indent=2))
    return "\n".join(prompt_chunks)
def run_agent(user_input: str):
    messages = [
        {
            "role": "system",
            "content": "你是一个简洁的 Agent。需要计算时使用 calculator 工具。"
        },
        {
            "role": "user",
            "content": user_input
        }
    ]
    round_num = 1
    while True:
        print(f"\n=== 第 {round_num} 次调用 ===")
        print(build_full_prompt(messages, tools=tools))
        response = client.chat.completions.create(
            model="deepseek-v4-flash",
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        # 提取调用返回的 token 统计信息,方便后续调试和成本分析
        usage = getattr(response, "usage", None)
        if usage is None and isinstance(response, dict):
            usage = response.get("usage", {})
        prompt_tokens = usage.get("prompt_tokens") if isinstance(usage, dict) else getattr(usage, "prompt_tokens", None)
        completion_tokens = usage.get("completion_tokens") if isinstance(usage, dict) else getattr(usage, "completion_tokens", None)
        total_tokens = usage.get("total_tokens") if isinstance(usage, dict) else getattr(usage, "total_tokens", None)
        # print(f"本次调用 token 统计:输入={prompt_tokens},输出={completion_tokens},总计={total_tokens}")
        # 解析 LLM 响应消息,并把重复输出内容去重后打印
        msg = response.choices[0].message
        deduped = dedupe_repeated_content(msg.content)
        print(f"LLM 返回内容:{deduped}")
        if msg.tool_calls:
            print("LLM 返回 tool call:")
            for tc in msg.tool_calls:
                print(f"  tool_call_id: {tc.id}")
                print(f"  name: {tc.function.name}")
                print(f"  arguments: {tc.function.arguments}")
        messages.append(msg)
        # 如果没有 tool call,则认为已经获得最终回答
        if not msg.tool_calls:
            return msg.content
        # 处理每个 tool call:打印调用内容、执行工具、记录 Observation
        for tool_call in msg.tool_calls:
            tool_name = tool_call.function.name
            args = json.loads(tool_call.function.arguments)
            print("LLM tool call 执行内容:")
            print(f"  tool_call_id: {tool_call.id}")
            print(f"  name: {tool_name}")
            print(f"  arguments: {args}")
            result = tool_map[tool_name](**args)
            print(f"tool 执行结果:{result}")
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": result
            })
        round_num += 1
if __name__ == "__main__":
    answer = run_agent("帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案")
    print("\n============================================")
    print("最终结果: "+ answer)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐