Agent = LLM + Harness:用Python代码跑一遍就懂了
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推理执行模式,通常分为以下步骤:
- Thought(思考):LLM理解任务并拆解任务,判断下一步操作
- Action(行动):Harness使用工具完成相应的任务
- Observation(观察):程序将工具执行返回给LLM,LLM基于结果判断下一步
- 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** ✅代码执行过程分析
在这个代码执行过程中,我们来分析一下:
- Thought阶段: LLM接收到用户的指令:"帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案"以及tool定义后,LLM判断需要执行计算,返回了第一个tool call
- Action阶段: 程序调用eval来执行tool call,生成结果
- Observation阶段:程序将结果追加到messages中,用于LLM后续思考
- Thought阶段:LLM读取上一轮Observation,发现任务未完成,返回第二个tool call
- Action阶段:程序调用eval来执行tool call,生成结果
- Observation阶段:程序将结果追加到messages中,用于LLM后续思考
- Final Answer阶段:LLM读取上一轮Observation,判断任务已完成,直接生成最终答案
最后
本文我们了解了Agent是什么以及它的工作原理,纸上得来终觉浅,真正上手后还能体会到Agent与LLM的不同。最后我来推荐几个用的还不错的Agent:
- Codex,推荐指数5星,拥有Computer Use、浏览器操作功能的桌面Agent,既可完成工作也可以编写代码,免费用户有额度,订阅用户经常会重置用量(好评)
- WorkBuddy,推荐指数4星半,腾讯家的桌面Agent,有免费额度可用,可以用于工作和生活中,容易上手,推荐所有人使用,是当前国内最热的Agent之一
- Github Copilot(程序开发),推荐指数4星半,有免费额度,作为IDE插件,代码补全很好用,也可以对代码提问
- Claude Code(程序开发),推荐指数4星,定位是开发者工具,编程领域强大,缺点是需要购买LLM、对普通办公用户不太友好。但是,如果你是开发者并已经订阅了Coding Plan,那它的推荐指数可以给到5星,Claude Code已经成为CLI编程Agent的标杆产品。
附源码
importosimportjsonfromopenaiimportOpenAI client=OpenAI(api_key=os.getenv("DEEPSEEK_API_KEY"),base_url="https://api.deepseek.com")defcalculator(expression:str)->str:try:result=eval(expression,{"__builtins__":{}})returnstr(result)exceptExceptionase:returnf"计算失败:{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}defprint_messages(messages):"""打印当前完整对话上下文"""print("\n========== 当前 messages ==========")fori,minenumerate(messages,1):print(f"\n[{i}] role:{m.get('role')ifisinstance(m,dict)elsem.role}")ifisinstance(m,dict):print(f"content:{m.get('content')}")ifm.get("tool_call_id"):print(f"tool_call_id:{m.get('tool_call_id')}")else:print(f"content:{m.content}")ifm.tool_calls:print("tool_calls:")fortcinm.tool_calls:print(f" id:{tc.id}")print(f" name:{tc.function.name}")print(f" arguments:{tc.function.arguments}")print("===================================\n")defdedupe_repeated_content(content:str)->str:normalized=content.strip()ifnotnormalized:returncontentiflen(normalized)%2==0:first_half=normalized[:len(normalized)//2].strip()second_half=normalized[len(normalized)//2:].strip()iffirst_halfandfirst_half==second_half:returnfirst_half lines=normalized.splitlines()iflen(lines)%2==0:half=len(lines)//2first_half_lines=[line.rstrip()forlineinlines[:half]]second_half_lines=[line.rstrip()forlineinlines[half:]]iffirst_half_lines==second_half_lines:return"\n".join(first_half_lines).strip()paragraphs=[p.strip()forpinnormalized.split("\n\n")ifp.strip()]iflen(paragraphs)%2==0:half=len(paragraphs)//2ifparagraphs[:half]==paragraphs[half:]:return"\n\n".join(paragraphs[:half])returncontentdefbuild_full_prompt(messages,tools=None):"""构建完整 prompt 文本,包含 messages 和 tools 定义"""prompt_chunks=[]fori,minenumerate(messages,1):ifisinstance(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}")ifisinstance(m,dict)andm.get("tool_call_id"):prompt_chunks.append(f"tool_call_id:{m['tool_call_id']}")iftools:prompt_chunks.append("\n=== tools definitions ===")fortoolintools:prompt_chunks.append(json.dumps(tool,ensure_ascii=False,indent=2))return"\n".join(prompt_chunks)defrun_agent(user_input:str):messages=[{"role":"system","content":"你是一个简洁的 Agent。需要计算时使用 calculator 工具。"},{"role":"user","content":user_input}]round_num=1whileTrue: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)ifusageisNoneandisinstance(response,dict):usage=response.get("usage",{})prompt_tokens=usage.get("prompt_tokens")ifisinstance(usage,dict)elsegetattr(usage,"prompt_tokens",None)completion_tokens=usage.get("completion_tokens")ifisinstance(usage,dict)elsegetattr(usage,"completion_tokens",None)total_tokens=usage.get("total_tokens")ifisinstance(usage,dict)elsegetattr(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}")ifmsg.tool_calls:print("LLM 返回 tool call:")fortcinmsg.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,则认为已经获得最终回答ifnotmsg.tool_calls:returnmsg.content# 处理每个 tool call:打印调用内容、执行工具、记录 Observationfortool_callinmsg.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+=1if__name__=="__main__":answer=run_agent("帮我算一下 6 * 5 + 六 等于多少,再计算这个结果乘以 2,最后告诉我答案")print("\n============================================")print("最终结果: "+answer)