通用 LLM Agent 构建指南:从基础到进阶
通用 LLM Agent 的构建方法,涵盖从基础概念到进阶实践的全流程。内容包括选择合适的模型、定义控制逻辑(如 ReAct 和计划执行)、设计核心指令、优化工具接口、制定内存处理策略、解析输出及编排执行流程。文章还探讨了多智能体系统的适用场景,并提供了 Python 代码示例和安全、监控方面的最佳实践,旨在帮助开发者构建稳定高效的智能体应用。

通用 LLM Agent 的构建方法,涵盖从基础概念到进阶实践的全流程。内容包括选择合适的模型、定义控制逻辑(如 ReAct 和计划执行)、设计核心指令、优化工具接口、制定内存处理策略、解析输出及编排执行流程。文章还探讨了多智能体系统的适用场景,并提供了 Python 代码示例和安全、监控方面的最佳实践,旨在帮助开发者构建稳定高效的智能体应用。

大语言模型智能体(LLM Agent)是一种程序,其执行逻辑由其底层模型控制。与传统的少样本提示(Few-Shot Prompting)或固定工作流程不同,Agent 能够定义和调整执行用户查询所需的步骤。
通过一组工具(如代码执行、网络搜索、数据库查询),智能体可以决定使用哪个工具、如何使用它,并根据输出对结果进行迭代。这种适应性使系统能够以最小的配置处理各种用例,从简单的问答到复杂的任务规划。
智能体架构存在于一个范围内,从固定工作流程的可靠性到自主智能体的灵活性。例如,像检索增强生成(RAG)这样的固定流程可以通过自我反思循环进行增强,使程序在初始响应不足时能够进行迭代。或者,一个反应式(ReAct)智能体可以配备固定流程作为工具,提供一种灵活而结构化的方法。架构的选择最终取决于用例以及在可靠性和灵活性之间的期望权衡。
选择合适的模型对于实现期望的性能至关重要。需要考虑多个因素,如许可证、成本和语言支持。构建大语言模型智能体时,最重要的考虑因素是模型在关键任务(如编码、工具调用和推理)上的性能。
评估基准包括:
模型的上下文窗口也是一个关键因素。智能体工作流程可能会消耗大量 token,有时甚至超过 10 万个,较大的上下文窗口非常有帮助,因为它能容纳更多的历史对话和工具输出。
可供考虑的模型类别:
一般来说,较大的模型往往性能更好,但能够在本地运行的较小模型仍然是一个不错的选择。使用较小的模型时,你将局限于更简单的用例,并且可能只能将智能体连接到一两个基本工具。
LLM 和智能体之间的主要区别在于系统提示。在 LLM 的背景下,系统提示是在模型处理用户查询之前提供给它的一组指令和上下文信息。大语言模型的智能体行为可以在系统提示中进行编码。
以下是一些常见的智能体模式,可以根据需要进行定制:
最后两种模式(ReAct 和计划 - 执行)通常是构建通用型单智能体的最佳起点。
为了有效地实现这些行为,你需要进行一些提示词工程。你可能还想使用结构化生成技术。这基本上意味着塑造大语言模型的输出以匹配特定的格式或模式,以便智能体的响应与你所期望的通信风格保持一致。
示例:以下是来自 Bee Agent 框架的反应式(ReAct)风格智能体的提示结构:
# Communication structure
You communicate only in instruction lines. The format is: "Instruction: expected output\n".
You must only use these instruction lines and must not enter empty lines between them.
Each instruction must start on a new line.
{{#tools.length}}
You must skip the instruction lines Function Name, Function Input and Function Output if no function calling is required.
{{/tools.length}}
Message: User's message. You never use this instruction line.
{{^tools.length}}
Thought: A single-line plan of how to answer the user's message, including an explanation of the reasoning behind it. It must be immediately followed by Final Answer.
{{/tools.length}}
{{#tools.length}}
Thought: A single-line step-by-step plan of how to answer the user's message, including an explanation of the reasoning behind it. You can use the available functions defined above. This instruction line must be immediately followed by Function Name if one of the available functions defined above needs to be called, or by Final Answer. Do not provide the answer here.
Function Name: Name of the function. This instruction line must be immediately followed by Function Input.
Function Input: Function parameters. Empty object is a valid parameter.
Function Output: Output of the function in JSON format.
Thought: Continue your thinking process.
{{/tools.length}}
Final Answer: Answer the user or ask for more information or clarification. It must always be preceded by Thought.
我们往往认为大语言模型开箱即用就带有许多功能。其中一些功能很棒,但其他功能可能不完全符合你的需求。为了获得你期望的性能,在系统提示中明确列出你想要和不想要的所有功能非常重要。
这可能包括以下指令:
示例:以下是 Bee Agent 框架中指令部分的一个片段:
# Instructions
User can only see the Final Answer, all answers must be provided there.
{{^tools.length}}
You must always use the communication structure and instructions defined above. Do not forget that Thought must be a single-line immediately followed by Final Answer.
{{/tools.length}}
{{#tools.length}}
You must always use the communication structure and instructions defined above. Do not forget that Thought must be a single-line immediately followed by either Function Name or Final Answer.
You must use Functions to retrieve factual or historical information to answer the message.
{{/tools.length}}
If the user suggests using a function that is not available, answer that the function is not available. You can suggest alternatives if appropriate.
When the message is unclear or you need more information from the user, ask in Final Answer.
# Your capabilities
Prefer to use these capabilities over functions.
- You understand these languages: English, Spanish, French.
- You can translate, analyze and summarize, even long documents.
# Notes
- If you don't know the answer, say that you don't know.
- The current time and date in ISO format can be found in the last message.
- When answering the user, use friendly formats for time and date.
- Use markdown syntax for formatting code snippets, links, JSON, tables, images, files.
- Sometimes, things don't go as planned. Functions may not provide useful information on the first few tries. You should always try a few different approaches before declaring the problem unsolvable.
- When the function doesn't give you what you were asking for, you must either use another function or a different function .
- When using search engines, you different formulations of the query, possibly even a different language.
- You cannot do calculations, computations, data manipulations without using functions.
工具赋予智能体超能力。通过一组定义明确的有限工具,你可以实现广泛的功能。关键工具包括代码执行、网络搜索、文件读取和数据分析。对于每个工具,你需要定义以下内容并将其作为系统提示的一部分:
示例:以下是来自 Langchain 社区的 Arxiv 工具实现的摘录。此实现需要一个 ArxivAPIWrapper 实现。
"""Tool for the Arxiv API."""
from typing import Optional, Type
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from langchain_community.utilities.arxiv import ArxivAPIWrapper
class ArxivInput(BaseModel):
"""Input for the Arxiv tool."""
query: str = Field(description="search query to look up")
class ArxivQueryRun(BaseTool): # type: ignore[override, override]
"""Tool that searches the Arxiv API."""
name: str = "arxiv"
description: str = (
"A wrapper around Arxiv.org "
"Useful for when you need to answer questions about Physics, Mathematics, "
"Computer Science, Quantitative Biology, Quantitative Finance, Statistics, "
"Electrical Engineering, and Economics "
"from scientific articles on arxiv.org. "
"Input should be a search query."
)
api_wrapper: ArxivAPIWrapper = Field(default_factory=ArxivAPIWrapper) # type: ignore[arg-type]
args_schema: Type[BaseModel] = ArxivInput
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> :
.api_wrapper.run(query)
在某些情况下,仍需要优化工具以获得期望的性能。这可能涉及通过一些提示工程调整工具名称或描述,设置高级配置来处理常见错误,或者过滤工具的输出以防止污染上下文。
大语言模型受其上下文窗口的限制,即它们一次可以'记住'的令牌数量。在多轮对话中的过去交互、冗长的工具输出或智能体所基于的额外上下文等情况下,内存可能会很快填满。这就是为什么拥有可靠的内存处理策略至关重要。
在智能体中,内存是指系统存储、记忆和利用过去交互信息的能力。这使智能体能够随着时间的推移保持上下文,根据先前的交流改进其响应,并提供更个性化的体验。
常见内存处理策略:
此外,还可以结合混合策略,例如短期使用滑动窗口,长期使用向量检索,以平衡实时性与持久性。
解析器是一种将原始数据转换为应用程序可以理解和处理的格式(如具有属性的对象)的函数。
对于我们正在构建的智能体,解析器需要识别我们在 2.2 中定义的通信结构,并返回结构化输出,如 JSON。这使应用程序更容易处理和执行智能体的下一步骤。
注意:一些模型提供商(如 OpenAI)默认可以返回可解析的输出。对于其他模型,尤其是开源模型,这需要进行配置,可能需要强制模型输出特定格式的 JSON Schema。
最后一步是设置编排逻辑。这决定了大语言模型输出结果后会发生什么。根据输出,你将:
如果触发了工具调用,工具的输出将被发送回大语言模型(作为其工作记忆的一部分)。然后,大语言模型将决定如何处理这个新信息:要么执行另一个工具调用,要么向用户返回答案。
以下是这种编排逻辑在代码中可能呈现的示例:
def orchestrator(llm_agent, llm_output, tools, user_query):
"""
Orchestrates the response based on LLM output and iterates if necessary.
Parameters:
- llm_agent (callable): The LLM agent function for processing tool outputs.
- llm_output (dict): Initial output from the LLM, specifying the next action.
- tools (dict): Dictionary of available tools with their execution methods.
- user_query (str): The original user query.
Returns:
- str: The final response to the user.
"""
max_iterations = 10 # Safety limit to prevent infinite loops
iteration_count = 0
while True:
if iteration_count >= max_iterations:
return "Error: Maximum iterations reached. Please check the task complexity."
action = llm_output.get("action")
iteration_count += 1
if action == "tool_call":
# Extract tool name and parameters
tool_name = llm_output.get("tool_name")
tool_params = llm_output.get("tool_params", {})
if tool_name in tools:
try:
# Execute the tool
tool_result = tools[tool_name](**tool_params)
# Send tool output back to the LLM agent for further processing
llm_output = llm_agent({"tool_output": tool_result})
except Exception as e:
# Handle tool execution errors gracefully
error_msg = f"Error executing tool '{tool_name}': {str(e)}"
llm_output = llm_agent({"error": error_msg})
:
action == :
llm_output.get(, )
:
现在你拥有了一个能够处理各种各样场景的系统,从竞争分析和高级研究到自动化复杂工作流程。
虽然这一代大语言模型非常强大,但它们有一个关键限制:它们难以处理信息过载。过多的上下文或工具可能会使模型不堪重负,导致性能问题。通用型单智能体最终会遇到这个瓶颈,尤其是因为 Agent 通常消耗大量 token。
对于某些应用场景而言,采用多智能体的设置可能更合理。通过将职责分配给多个智能体,你能够避免单个大语言模型智能体的上下文负担过重,并提高整体效率。
例如,一个智能体负责搜索信息,另一个负责分析数据,第三个负责撰写报告。这种分工协作可以提高准确性和速度。
话虽如此,通用的单智能体设置对于制作原型来说是一个很好的开始。它可以帮助你快速测试你的使用案例,并确定在哪些地方开始出现问题。通过这个过程,你可以:
使用框架是快速测试和迭代智能体配置的好方法。不要从零开始编写所有逻辑,利用成熟的生态可以节省大量时间。
如果你计划使用像 Llama 3 这样的开源模型,可以尝试 Bee Agent Framework 的入门模板。它提供了现成的 ReAct 模式和工具集成。
如果你计划使用像 OpenAI 这样的前沿模型,可以尝试 LangGraph 的教程。LangGraph 允许你定义状态图,非常适合构建有状态的复杂 Agent 应用。
在构建生产级 Agent 时,必须考虑安全性:
Agent 不是静态的。随着用户反馈和新工具的引入,你需要不断调整系统提示、更新工具描述并优化内存策略。定期评估模型表现,必要时切换基座模型以提升效果。
通过遵循上述步骤和最佳实践,你可以构建出既强大又可靠的通用 LLM Agent,满足多样化的业务需求。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online