基于大模型的智能体(Agent)基本组成通常包含规划(Planning)、工具(Tools)、执行(Action)和记忆(Memory)四个方面。其中,规划能力被视为关键的组件之一,用于将复杂任务拆解为更小、可管理的子任务,这对有效可控地处理复杂任务效果显著。
人类做事的类比:PDCA 循环
在日常工作中,我们通常将一项任务拆解成几个步骤:制定计划、执行计划、检查结果,然后将成功的作为标准,未成功的则留待下一次循环解决。这种方法已经被证明是高效完成任务的经验总结,即 PDCA 循环。
PDCA 是美国质量管理专家休哈特博士提出的,由戴明采纳、宣传,获得普及,所以又称戴明环。基于 PDCA 模型可以将一般项目分为四个阶段,即 Plan(计划)——Do(执行)——Check(检查)——Act(处理)。把一件事情做出计划、然后实施计划、检查计划分析哪些出现了问题并提出解决方案、然后成功的纳入标准,不成功的进入下一个循环去解决,循环往复,从而形成一套标准化的流程。
Agent 的工作机制:ReAct 框架
Agent 的执行过程与人做事的方式类似,其中最有名的就是 ReAct 框架的思路。它来自论文《ReAct:在语言模型中协同推理与行动》,作者发现让 Agent 执行下一步行动的时候,加上大模型自己的思考过程,并将思考过程、执行的工具及参数、执行的结果放到提示词中,就能使得模型对当前和先前的任务完成度有更好的反思能力,从而提升模型的问题解决能力。
比如斯坦福 AI 小镇项目、AutoGPT 等去年大火的 Agent 的项目,都可看到 ReAct 的思路。LangChain 框架中直接以 ReAct 为基础定义了几种代表性 Agent(CONVERSATIONAL_REACT_DESCRIPTION、ZERO_SHOT_REACT_DESCRIPTION 等)。
Thought: … Action: … Observation: … …(重复以上过程,即表示 ReAct 的工作过程)
构建 Agent 的代码实践
下面通过代码构建一个最基本的 Agent。这里有必要提前了解几个关键概念,有助于更好地理解 Agent 的工作过程。
AgentAction:它主要包含两部分信息,tool 表示 Agent 将要调用的工具的名称,tool_input 表示传递给这个工具的具体输入。
AgentFinish:它有一个 return_values 参数,是一个字典,该字典的 output 值表示要返回给用户的字符串信息。
intermediate_steps:表示 Agent 先前的操作及其相应的结果。它是一个列表,列表中的每个元素是一个包含 AgentAction 和其执行结果的元组,这些信息对于未来的决策非常重要,因为它让 Agent 了解到目前为止已经完成了哪些工作。
定义工具
定义 Agent 要调用的工具,一个用于获取句子中不同汉字的数量的函数,同时将工具函数绑定到模型上。
def count_unique_chinese_characters(sentence):
"""用于计算句子中不同汉字的数量"""
unique_characters = set()
for char in sentence:
if '\u4e00' <= char <= '\u9fff':
unique_characters.add(char)
return len(unique_characters)
# 将工具函数绑定到模型上
llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(count_unique_chinese_characters)])
定义 Agent
定义一个 Agent,用于处理用户输入、大模型输出及对输出内容解析:
prompt = ChatPromptTemplate.from_messages(
[
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_output"),
]
)
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 构建一个 Agent,它将处理输入、提示、模型和输出解析
agent = (
{
"input": lambda x: x["input"],
"agent_output": lambda x: format_to_openai_function_messages(
x["intermediate_steps"]
),
}
| prompt
| llm_with_tools
| OpenAIFunctionsAgentOutputParser()
)
Agent 执行
下面就是 Agent 的执行过程,主体实际是一个主循环,直到输出预期结果。实际情况中会对循环次数进行控制,以防止无休止执行下去,耗光资源。
# 用于存储中间结果
intermediate_steps = []
while True:
# 调用 Agent 并处理输出
output = agent.invoke(
{
"input": sentence,
"intermediate_steps": intermediate_steps,
}
)
# 检查是否完成处理,如果完成则退出循环
if isinstance(output, AgentFinish):
final_result = output.return_values["output"]
break
else:
print(f"工具名称:{output.tool}")
print(f"工具输入:{output.tool_input}")
tool = {"count_unique_chinese_characters": count_unique_chinese_characters}[output.tool]
observation = tool.run(output.tool_input)
intermediate_steps.append((output, observation))
# 打印最终结果
print(final_result)
一个最基本的 Agent 就构建结束了,这就是当下大家在各种文章上看到的产品层面构建 Agent(代理、智能体、智能代理、AI 代理等)的底层原理,其实很简单。
更复杂的任务与规划策略
仔细观察上面的例子,很显然,只提供了一个工具,而且任务足够简单,当然可以清晰的执行。但是如果面对很复杂的任务场景,任务粒度拆解不细,导致执行步骤无法穷尽,循环就始终无法结束,这样的 Agent 也就无法完成复杂问题了。所以 Agent 要真正可用,任务拆解和规划是极为关键的一步,所以这方面也成为热门研究方向。
以下是常见的十种任务规划思路:
- Zero-Shot(零样本提示):在提示词中简单地加入'一步一步思考',引导模型进行逐步推理。这种方法不需要额外的训练数据,直接利用模型已有的知识进行推理,适用于通用性较强的任务。
- Few-Shot(小样本提示):给模型展示解题过程和答案,作为样例。如果只提供一个样例,又叫 One-Shot。这有助于解答新问题,特别是当任务具有特定格式或逻辑时,示例能显著提高准确率。
- COT(思维链):思维链提示即将一个复杂的多步骤推理问题细化为多个中间步骤,然后将这些中间答案组合起来共同解决问题。其有效性已得到广泛验证,特别适用于数学推理和逻辑判断。
- Auto CoT:大模型在解题前自动从数据集中查询相似问题进行自我学习,但需要专门的数据集支持。这种方法减少了人工编写示例的成本,实现了自动化的思维链生成。
- Meta CoT:在 Auto CoT 的基础上,先对问题进行场景识别,进一步优化自动学习过程。通过识别问题的类型,选择最合适的推理路径,提高了泛化能力。
- Least-to-Most:该策略的核心是把复杂问题划分成若干简易子问题,并依次解决。在处理每个子问题时,前一个子问题的解答有助于下一步。例如提示词中加入'针对每个问题,首先判断是否需分解子问题。若不需,则直接回答;若需,则拆分问题后,整合子问题解答,以得出最优、最全面及最确切的答案。',启用大模型的思维模式,细化问题,从而获得更佳的结果。
- Self-Consistency CoT:在多次输出中选择投票最高的答案。自洽性利用了一个复杂推理问题通常有多种不同的思路,但最终可以得到唯一正确答案的本质。自洽性提升了思维链在一系列常见的算术和常识推理基准测试中的性能,比如在提示词中加入'对于每个问题,你将思考 5 种不同的想法,然后将它们结合起来,输出措辞最佳,最全面和最准确的答案。'
- TOT(Tree of Thoughts,思维树):构建一个树状结构来存储各步推理过程中产生的多个可能结果作为末梢节点。在进行状态评估以排除无效结果之后,基于这些末梢节点继续进行推理,从而发展出一棵树。接着,利用深度优先搜索(DFS)或广度优先搜索(BFS)算法连接这些节点,形成多条推理链。最终,将这些推理链提交至一个大模型以评估哪个结果最为合适。这种方法适合需要多步探索的复杂决策问题。
- GOT(Graph of Thoughts,思维图谱):思维图谱是将大型语言模型的输出抽象成一个灵活的图结构,其中思考单元作为节点,节点间的连线代表依赖关系。这种方式模拟人类解决问题的思维组合,它能合并多条推理链,自然回溯到有效的推理链,并行地探索独立的推理链,更贴近人类思维方式,从而增强了推理能力。
- Multi-Persona Self-Collaboration:模拟多个角色协作解决问题。通过分配不同的角色(如专家、批评家、执行者),让模型在不同视角下进行思考和辩论,最终达成共识。这种方法能有效减少单一视角的偏见,提高方案的全面性。
在这些技巧中,Zero-Shot、Few-Shot、Self-Consistency 和 Least-to-Most 在提示词层面易于应用且效果显著。对于更复杂的场景,建议结合 TOT 或 GOT 等结构化方法。选择合适的规划策略取决于任务的复杂度、数据的可用性以及对实时性的要求。
实施挑战与最佳实践
在实际部署 Agent 系统时,除了规划策略的选择,还需注意以下挑战:
- 上下文窗口限制:随着交互轮数增加,历史记录会占用大量 Token。需设计合理的记忆压缩机制,保留关键信息而非全部历史。
- 工具调用的准确性:模型可能会错误地调用工具或传递错误的参数。需要通过严格的 Schema 校验和异常处理机制来保障稳定性。
- 死循环风险:Agent 可能在某些状态下陷入无限循环。必须设置最大迭代次数和超时机制,确保系统不会挂起。
- 安全性:防止 Prompt Injection 攻击,确保用户输入不会被恶意利用来绕过安全限制或执行非授权操作。
综上所述,Agent 的任务规划是大模型应用开发的核心难点之一。通过理解上述 10 种创新方式并结合实际业务场景进行微调,可以显著提升智能体的自主性和解决问题的能力。未来随着模型能力的增强,规划模块将更加自动化和智能化,推动 Agent 向通用人工智能迈进。

