构建人工智能代理,实现企业级软件开发自动化:实用视角
- Rifx.Online
- Programming , Machine Learning , Autonomous Systems
- 30 Nov, 2024
Randy Zhang 和 Shamin Aggarwal
Agentic AI 是一款基于大型语言模型(LLMs)的软件应用,通过模拟类人推理和决策来自动化任务。它在自动化小型和简单脚本的软件开发方面显示出了显著的能力 [1]。AI 代理能否用于自动化企业级软件开发?在大型复杂的软件开发环境中,我们会遇到什么样的挑战?
企业级软件项目通常是旨在满足复杂业务需求的大规模软件开发计划。这类项目可能包含大量的长脚本、复杂的功能依赖关系、长长的软件特性列表以及强大的操作要求。本文将尝试解决我们在项目中遇到的一些挑战,并记录我们提出的解决方案。这些实用的建议和推荐可能会对您实施类似的 AI 项目有所帮助。
一般观察
LLM 工程在应用开发中可能会呈现特定的考虑或挑战,在代理 AI 环境中可能会更加明显。AI 代理本质上是具有预定义目的和能力的 LLM,例如特定的“系统消息”和一组“工具”。我们还可以为每个代理定义特定的对话“流程”,以控制它们遵循的步骤。对于企业软件开发,这通常归结为为研究/规划、代码库探索、编码、验证/测试、编排/报告等不同任务设置不同的代理。通过将任务分 compartmentalize 和正确定义代理之间的流程来处理不同的场景,我们可以提高整体工作流的可靠性,减少令牌消耗,并增加可见性/可追溯性,以便轻松理解所执行的操作。
以下是关于在企业软件开发中使用 AI 代理时 LLM 工程的一些一般观察的简短列表。
令牌消耗优化
使用 LLM 的成本与提示和响应中的令牌(单词或单词的一部分)数量成正比。在开发自动化工作流时,我们不断问自己:“我们如何能用最少的单词完成这个任务?”在使用 AI 代理编码时,这转化为确定我们需要向 LLM 提供多少信息和现有代码以获得足够的上下文。随着对话的进行,令牌消耗会累积,因此在消息的数量和复杂性之间取得平衡至关重要。
上下文窗口管理
与人类相比,LLM 的短期记忆非常小,这被定义为上下文窗口长度,或简单的上下文长度。这个长度会影响 LLM 处理、理解和生成文本的能力。更重要的是,有一个经验观察到的“有效上下文长度”,即令牌数量,在此之后 LLM 的准确性显著下降。有效上下文长度通常远低于广告宣传的上下文长度。更大的有效上下文长度允许 LLM 更好地执行,因为它能够在给出响应时“有效地”处理更多的信息。因此,这样的 LLM 可以处理更复杂的输入,在长对话中保持更高的连贯性,并最终生成更准确的响应。这就是为什么通常观察到,利用 LLM 的整个上下文窗口长度并不如拥有适当分 compartmentalization 和有限对话长度的多代理工作流更可靠和更具成本效益。
捕捉幻觉
这通常是最具挑战性的任务。重要的是要对您的用例进行实验,以识别您选择的 LLM 可能犯的常见错误。解决方案可能有所不同;有些可以通过提示工程来解决,其他可能需要实施特殊检查和纠正提示,还有一些可能需要更改工作流或使用更好的“工具”。涉及数字或冗长对话的情况更容易出错,因此最好尽量避免这种情况。
无限循环
LLM 有时会陷入循环,不断重复相同的操作或在几个操作之间循环。这在让它们独立编码和调试时尤其如此。AI 代理可能会对代码进行更改,运行它,看到相同的错误,然后再次尝试相同的更改。虽然我们尚未找到万无一失的解决方案,但检测此类情况并指示代理尝试其他方法通常有效,或者至少可以防止无用的令牌消耗。
处理行号
LLM 在处理数字方面 notoriously 不佳,例如 ChatGPT-4o 甚至无法告诉“草莓”这个词中有多少个 r。在编码中,这表现为代码文件中的行号错误。理想情况下,我们希望代理指定它们想要编辑的行,而不是重写整个代码块。然而,我们注意到在长对话中,编码代理往往会在行号上出错。我们通过限制对话长度来解决这个问题,有效地在对话过长时重置代理的记忆,然后让它从中断的地方继续。
代理框架选择
为了加快代理开发过程,我们可以使用代理框架快速原型化一个项目。像 AutoGen 和 LangChain 这样的代理框架使开发人员能够创建工作流程,让 AI 代理能够自主规划、生成、修改和调试代码。当我们启动这个项目时,我们需要选择一个最适合我们需求的代理框架。我们评估了几个选项,包括 AutoGen、LangChain 和其他一些框架。经过一些尝试,我们决定选择 AutoGen。
AutoGen 是由 Microsoft 开发的一个库,用于利用 LLM 自动生成代码和管理工作流程。它特别适合快速原型制作,使我们能够快速尝试不同的代理工作流程,而不必陷入复杂性。以下是我们喜欢它的原因:
· 易于使用:设置和启动都很简单。
· 快速原型制作:允许我们快速测试想法。
· 功能足够:拥有我们所需的所有基础组件,用于我们提议的工作流程。
我们还研究了 LangChain,这是一个流行的库,专注于为基于 LLM 的应用程序创建模块化和可扩展的管道。它适合构建精细的对话代理和数据检索系统。
LangChain 的优点:
· 高度模块化:提供对组件的细粒度控制。
· 可扩展:易于与不同的工具和 API 集成。
· 活跃的社区:有很多资源和社区支持。
LangChain 的缺点:
· 学习曲线较陡:需要更多时间来熟悉。
· 需要更多设置:原型制作不如 AutoGen 快捷。
现在我们已经完成了项目,以下是我们发现 AutoGen 的一些优点:
· 简单性:我们不需要写大量的样板代码。
· 专业功能:与 LangChain 不同,AutoGen 是专门为代码生成而编写的,并具有额外的功能,例如执行生成的代码。
· 专注于工作流程:使我们能够专注于设计代理工作流程,而不是底层机制。
· 快速迭代:使调整和测试不同方法变得容易。
对于未来更复杂的项目,特别是在企业级别,我们建议认真考虑 LangChain。随着我们项目的增长,我们开始怀念 LangChain 提供的细粒度控制和额外功能。虽然 AutoGen 非常适合入门,但 LangChain 可能在长期内帮助我们取得更好的结果。
LLM 选择
LLM 的选择是一个关键决策,将影响开发的许多方面,超越代理工作流的一般性能;包括提示、上下文窗口长度、幻觉类型、工具调用格式、最大对话长度等。
对于我们的项目,我们选择了 OpenAI 的 LLM,在我们的测试中,其性能优于其他可比的基础模型,特别是来自 Meta 和 Google 的模型。像 ChatGPT-3.5 这样的较小 LLM,其上下文窗口范围在 4k 左右,太小以处理代码探索、规划和编码的“主要任务”,因为企业代码库有着长且复杂的模块,至少需要 32k 的上下文窗口,甚至 128k。
Anthropic 的 Claude 3.5 Sonnet 模型在与编码相关的任务上表现优于 GPT-4o,然而 OpenAI 的 API 提供了一套更强大的工具调用、结构化输出等功能,使得使用他们的 LLM 作为 AI 代理变得更加容易。
令牌限制
人工智能代理的力量在于其迭代决策和代理之间的协作,这在一定程度上导致了令牌使用量的增加。这在企业级软件库中尤为明显。令牌有两种类型,它们都会增加成本:
· 提示令牌:用户(通过代理)发送给模型的输入提示中使用的令牌。
· 响应令牌:模型在其响应中生成的令牌。
我们使用的LLM API对令牌使用率施加了限制,规定了每分钟、每小时和每天可以消耗的令牌数量。在代码库探索过程中,代理在读取长代码脚本时会消耗大量令牌。在此过程中达到令牌限制会导致我们的工作流程中断,因此我们需要一个解决方案。我们实施了一个令牌跟踪系统,以实时监控消耗情况。在发送提示之前,我们计算预期的令牌使用量,并确保不会超过限制。如果接近限制,我们会引入一个睡眠计时器,暂停代理,直到安全继续。
在我们的实现中,我们估算令牌使用量并在必要时暂停。通过这种方式,我们保持代理顺利运行,而不会触及API限制。以下是我们令牌管理代码的简化版本,用于控制消息长度,以确保我们低于每分钟的限制:
如果提示令牌和响应令牌都适用速率限制,确保您永远不会超过限制的唯一可靠方法是假设任何响应都可能是最长可能长度,即上下文窗口长度减去提示长度。这是因为事先无法知道给定提示的响应可能有多长。实际上,这将导致大量不必要的睡眠计时器,因为大多数响应实际上会小得多,因此在这种情况下,优先优化对话长度而不是控制消息长度会更好。
即使您没有任何令牌限制,优化令牌消耗以限制对话长度仍然非常重要。然而,挑战在于,随着我们减少对话长度,我们增加了每条消息的“工作”量,从而降低了平均准确性/可靠性。您可能需要进行实验,以根据您选择的LLM在优化对话长度和准确性之间找到平衡。尽管如此,通常来说,当我们优化对话长度时,我们会获得更低的令牌成本。
优化对话长度
代理之间的对话长度可以通过多种方式进行优化,以适应代理工作流程,以下是两个示例:
限制每个对话中的代理数量
在对话中,来自特定代理的每条消息都有可能被其他每个代理以任意对任意的方式读取,从而使得令牌消耗呈指数级增加,而不是线性增加。这意味着,3个代理之间的对话可能消耗的令牌是2个代理之间对话的两倍。
在我们的实现中,我们选择仅使用单代理对话,也称为用户代理对话,其中没有任何代理直接“对话”。我们通过一个“用户代理”与每个代理进行独立对话,并将来自代理的最终响应插入到工作流程中下一个代理的“初始化提示”中。
限制每个代理的消息/步骤数量
如果我们减少对话中的代理数量,我们基本上依赖更少的代理来完成相同的工作。例如,在我们的实现中,我们指定编码代理扮演多个角色。这种安排的一个缺点是,这使得预测编码代理的对话长度变得困难,并可能导致过度重新规划、无限调试循环等场景。我们需要一种方法来允许编码代理摆脱此类场景或进行外部中断。一种实现“突破”的方法是允许编码代理向规划代理请求“澄清”。这可以通过常规的提示工程或编写工具调用来实现,以调用规划代理。
外部中断可以通过检测代理何时陷入循环或其对话长度超过预设的最大值来实现。在这种情况下,我们会提示编码代理提供其迄今为止编写或修改的所有代码的摘要,然后清除对话历史。然后,通过将生成的摘要附加到编码代理的初始化提示中,来“恢复”对话,以模拟持续的编码代理对话。
工具调用
AI 代理利用软件功能或工具执行特定任务,以帮助 LLM 解决问题。工具使代理能够执行超出文本生成的操作。在软件开发的背景下,我们通常需要至少两组工具:
· 文件操作:读取、写入、修改文件。
· 执行代码:运行脚本或代码片段,CLI 命令等。
拥有强大的工具库对于 LLM 代理至关重要,尤其是在软件开发任务中。这些工具有时可能被忽视,因为它们看似简单。提示:尝试思考如果仅使用 CLI 命令,您将如何探索代码库。
我们应该尽量识别人类软件开发者在 IDE 上执行的尽可能多的操作,并确保 LLM 有相应的功能可用。一个例子是 VS Code 的“转到定义”功能,它允许开发者轻松跳转到导入/引用符号(函数、类等)的定义。
每当代理决定使用工具时,它会消耗令牌。频繁或冗长的工具调用会迅速消耗您的令牌配额。
根据工具的不同,工具调用请求、响应或两者都可能消耗大量令牌:
· 请求工具:编写长代码脚本会消耗大量“LLM 响应”令牌。
· 处理响应:解释工具的输出,如果很长,会消耗大量“提示”令牌,例如在读取长代码脚本时。
我们可以优化工具接口,使其更具令牌效率:
· 标准化命令:使用简洁的预定义命令,而不是冗长的自然语言请求。
· 最小响应:设计工具仅返回必要的信息。
· 灵活性:构建具有可选功能的工具调用,以提供更多控制和灵活性(见下面的示例)。
即使是简单的文件读取工具调用,我们也可以包括指定范围的能力,以允许 AI 代理读取文件中的特定行,从而减少不必要的令牌消耗。此外,我们选择在工具响应中包含行号,以进一步促进这一点。
依赖解析
一般来说,依赖是指在当前脚本/代码块之外编写的一些代码,这些代码被导入/引用。然而,依赖通常指的是你的代码所依赖的外部库或模块。理解它们的工作原理对于正确使用它们至关重要。
我们为 AI 代理编写的一个有用工具(在开源社区中并未观察到广泛使用)是用来探索给定代码块/脚本的依赖关系。这包括外部库以及代码库内部的模块间依赖关系。这使得代理能够自主地递归检查某处引用的函数、类等的定义,从而深入理解代码库。
缩进处理
在 Python 中,缩进不仅仅是为了可读性,它在语法上也是重要的。缩进不对齐可能导致缩进错误,从而导致程序崩溃。
AI 模型可能在保持一致的缩进方面遇到困难,因为它们依赖于一定数量的空格,而 LLM 在处理数字时表现不佳。这个问题在企业软件开发中更加严重,因为:
· 上下文限制:它们可能会失去嵌套级别的跟踪。
· 复制粘贴错误:当代码在多个回合中生成时,一致性可能会丢失。
· 格式问题:制表符与空格可能会导致问题。
处理代理缩进问题有几个选项:
1. 严格和精确的提示
a. 优点:鼓励模型保持正确的缩进。
b. 缺点:并非万无一失;增加了令牌使用量。
2. 后处理
a. 优点:可以自动修正小问题。
b. 缺点:可能无法修复逻辑缩进错误。
3. 代码解析器
a. 优点:在执行之前验证代码。
b. 缺点:增加计算开销。
我们使用 ‘ast’ python 库实现了一个确定性的验证步骤,以解析生成的代码并检查语法错误。通过集成这个验证步骤,我们显著减少了由于缩进问题导致的运行时错误,使我们的代理更加可靠。以下是相同内容的简化版本:
摘要
开发代理以执行日常任务正成为人工智能领域的热门趋势。在本文中,我们记录了构建人工智能代理以自动化企业级软件开发项目的经验。我们从构建人工智能代理的一般观察开始,分享了在代理开发中的关键考虑因素的经验教训和学习,包括代理开发框架选择、LLM选择、优化和控制令牌、处理工具调用、代码依赖关系解析以及代码缩进要求处理。随着人工智能代理越来越多地用于自动化人类任务和工作流程,我们可以合理地预期会看到越来越多的进展和应用案例。
关于作者
Randy Zhang,博士,是思科系统公司的首席架构师。他拥有3项美国专利,并且是两本书和30多篇其他出版物的作者。他正在积极从事网络用例的人工智能项目。Randy经常在行业会议上发言,可以通过LinkedIn与他联系,https://www.linkedin.com/in/randyzhang/,以及GitHub,https://github.com/ranzhang/。
**Shamin Aggarwal,**计算机科学硕士(专注于机器学习),是一位对人工智能和自动化充满热情的软件工程师。他专注于为软件开发开发代理工作流,并喜欢探索新技术。LinkedIn: https://www.linkedin.com/in/shamin1998/
参考文献
[1] Randy Zhang, Automated networking script development with AI agents, link