在1.5节中,你跑通了第一个Agent。那段代码里有一个run_agent函数,它做了一件看似简单的事:反复调用LLM,直到得到一个最终回答。
如果你仔细看那段代码,会发现一个隐藏的结构:
for turn in range(max_iterations):
response = call_llm(messages, tools) # 思考
if response.tool_calls:
for tool_call in response.tool_calls:
result = execute_tool(tool_call) # 行动
messages.append(result) # 感知
else:
return response.content
这个结构——调用LLM、执行工具、把结果放回去、再调用LLM——就是Agent的核心循环。它看起来简单,但理解它的每个环节、以及这些环节之间的微妙关系,是构建可靠Harness的基础。
Agent的每一次迭代,都可以拆解为三个步骤:
用户输入:"帮我查一下北京天气,如果下雨就提醒我带伞"
│
▼
┌─────────────────────────────────────────────┐
│ 感知(Perceive) │
│ · 用户说了什么? │
│ · 工具刚返回了什么? │
│ · 之前的推理进行到哪一步了? │
└──────────────────┬──────────────────────────┘
│ 完整的对话历史 = 感知的全部依据
▼
┌─────────────────────────────────────────────┐
│ 思考(Think) │
│ · 我理解用户想要什么吗? │
│ · 我有哪些工具可以用? │
│ · 下一步该调用工具,还是给出回答? │
│ · 如果调用工具,参数是什么? │
└──────────────────┬──────────────────────────┘
│ LLM的决策 = 文本 or 工具调用
▼
┌─────────────────────────────────────────────┐
│ 行动(Act) │
│ · 执行LLM指定的工具 │
│ · 将工具结果格式化为消息 │
│ · 追加到对话历史中,进入下一轮 │
│ · 或者:LLM认为任务完成,输出最终回答 │
└─────────────────────────────────────────────┘
这个循环的本质是:每完成一次“行动”,就把行动的结果反馈给“感知”,触发下一轮“思考”。 这就是为什么Agent能够处理复杂任务——它不是一次性想出所有步骤,而是走一步,看一步,再想下一步。
你可能会问:这有什么特别的?不过是一个while循环而已。因为对于Agent来说,这个循环就是它的“意识流”。
人类解决复杂问题时,也是这个模式:你拿到一个问题,先想想手头有什么工具(知识、人可以问、电脑可以查),然后做一步,看看结果,再想下一步。你不会在动手之前就把所有步骤规划得天衣无缝——你会根据中间结果调整策略。
Agent的循环也是这样。它不知道完成一个任务需要几步,也不知道每一步会遇到什么。它只能:
这就是为什么Agent应对开放性任务的能力远超传统程序——传统程序必须在编码时就穷举所有可能路径,而Agent可以在运行时发现路径。
让我们看一个稍微复杂的例子,感受循环是怎么“一步步推进”的。
用户目标:“帮我查一下我们团队下周有没有人过生日,如果有,帮我选一个合适的礼物。”
循环过程:
【第1轮】
感知:用户想查下周日历,然后根据结果决定是否买礼物。
我有工具:query_calendar(查日历)、search_gifts(搜礼物)、add_to_cart(加购物车)
思考:第一步应该查日历。需要知道"下周"的具体日期范围。
今天是2026-08-27(周四),下周是8月31日-9月6日。
行动:调用 query_calendar(team="我的团队", start="2026-08-31", end="2026-09-06")
【第2轮】
感知:工具返回——"张三:9月3日生日"。确实有人过生日。
思考:需要为张三选礼物。但我不知道张三喜欢什么。
我可以搜通用礼物,或者先查有没有关于张三偏好的信息。
我的工具中没有"查同事偏好",所以先搜通用礼物。
行动:调用 search_gifts(keyword="同事生日礼物", price_range="100-300元")
【第3轮】
感知:工具返回——5款推荐礼物(蓝牙耳机、机械键盘、保温杯、书、桌游)。
思考:这些选择差别很大。张三是什么样的人?
我只有日历工具和购物工具,没有同事信息。
我应该把这些选项呈现给用户,让用户选择,而不是自己决定。
行动:向用户展示选项,请求选择。
【第4轮】
感知:用户说"张三喜欢打游戏,选键盘吧"。
思考:用户提供了关键信息。张三喜欢游戏 → 机械键盘合适。
我应该把机械键盘加入购物车。
行动:调用 add_to_cart(item="机械键盘", recipient="张三", occasion="生日")
【第5轮】
感知:工具返回——已成功加入购物车。
思考:任务完成。我可以总结一下做了什么。
行动:输出最终回答。
这个过程中有几点值得注意:
第一,Agent在每一轮都在做“信息差距分析”。它不断问自己:“我知道什么?我需要知道什么?我有什么工具可以填补这个差距?”
第二,Agent知道自己的知识边界。在第3轮,它没有假装知道张三喜欢什么,而是把决策权交还给用户。这是好的Agent行为——知道自己不知道什么。
第三,循环的长度是不可预知的。这个任务用了5轮。如果中间出了错(比如日历工具返回格式异常),可能更多。Harness必须为这种不可预知性做好设计。
理解了循环的基本结构后,让我们深入几个关键的设计决策。这些决策直接影响Harness的质量。
决策1:LLM如何表达“思考”的结果?
LLM的“思考”输出有两种可能:
// LLM的思考输出 = 工具调用请求
{
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "query_calendar",
"arguments": "{\"team\":\"我的团队\",\"start\":\"2026-08-31\",\"end\":\"2026-09-06\"}"
}
}
]
}
这个设计看似简单,但有一个微妙的点:LLM可能会同时请求多个工具调用。比如它认为“查天气”和“查日历”这两个操作彼此独立,可以在同一个响应中一起请求。Harness需要决定:并行执行还是串行执行?
并行执行更快,但风险是:如果第二个工具的参数依赖于第一个工具的结果,并行就会出错。简单Harness可以串行执行,进阶Harness可以并行执行并在失败时降级为串行。
决策2:如何管理对话历史?
对话历史是Agent“感知”的全部依据。它的管理方式直接影响Agent的表现和成本。最朴素的方式,把所有消息(用户消息、LLM响应、工具结果)全部追加到一个列表里,每次调用LLM时全部发送。但是问题来了:上下文窗口有上限。当对话超过一定长度时,你需要截断。截断哪些?最旧的消息?工具结果?系统提示词?没有标准答案,只有权衡。
此外,对话历史中既有面向LLM的消息(让它理解上下文),也有面向用户的消息(最终回答)。这两者并不总是重合。Harness需要维护好这个区别。
第5章会专门讨论记忆管理。这里你只需要知道:对话历史的管理策略,是循环设计的核心难点之一。
决策3:循环什么时候终止?
循环不能无限进行。终止条件需要明确:
正常终止:LLM给出了最终回答(没有tool_calls)
达到最大迭代次数:循环了N轮还在调用工具,强制停止
超时:总耗时超过限制
用户中断:用户发送了停止信号
工具执行失败且无法恢复:某个关键工具连续失败
每种终止方式都需要被记录和报告。一个Agent在“最大迭代次数”处终止,和“正常终止”是不同的情况——前者可能意味着任务没有完成,后者意味着完成了。
在1.5节的代码中,最大迭代次数是5。如果Agent在5轮内没有完成任务,它会返回一个警告消息。这是一个粗糙但必要的安全阀。
决策4:循环中的错误如何处理?
工具可能失败。API可能超时。LLM可能返回格式异常的响应。
这些问题发生在循环的任何一步,Harness必须决定:
把错误信息返回给LLM是一个有趣的设计。LLM看到“工具执行失败:网络超时”后,可能会选择换一个工具、改变策略、或者告知用户它做不到。这种让LLM参与错误恢复的做法,是Agent优于传统程序的关键特性之一。
最后,让我们谈谈循环的成本。
每一次循环 = 一次LLM调用 + 可能的工具执行 + 对话历史的增长。
假设一个Agent平均需要5轮完成一个任务,每轮调用gpt-4o的费用是$0.01,那么一个任务的成本是$0.05。如果每天有10,000个任务,每天的成本是$500。这还不包括工具执行的资源消耗。
更重要的是延迟。每一轮循环需要等待LLM的响应(1-5秒),5轮就是5-25秒。用户能接受的等待时间是有限的。减少循环次数,是Agent工程中一个持续的优化目标。
第9章会讨论如何通过可观测性来追踪和优化这些成本。这里你只需要意识到:循环的次数 = 成本 + 延迟。每一次不必要的循环,都是在烧钱和考验用户耐心。
理解了循环的基本结构,你就理解了Harness的“心脏”。Harness的所有其他模块,都是为这个循环服务的:
在下一节中,我们将把这个循环放进Harness的整体架构中,看看Runtime、Tool Registry、Memory、Evaluator这些模块是如何围绕循环组织的。
Agent的核心循环是感知→思考→行动的反复迭代。它的力量来自于在运行时发现路径,而非预定义全部步骤。它的成本来自每一次循环的LLM调用和工具执行。它的复杂性来自对话历史管理、终止条件、错误处理等设计决策。
这个循环不是一个“实现细节”——它是Agent的本质。理解了它,你就理解了为什么Agent有时候表现惊艳,有时候又显得笨拙:它不是在“执行一个程序”,而是在“边走边想”。
评论专区
评论加载中...登录后即可发表评论