
Crewai:代理真的可以编写 Rest Api 代码吗?
- Rifx.Online
- Generative AI , Software Development , Best Practices
- 05 Mar, 2025
使用代理来编写工作流程
- 继续我对使用 Crew AI 的代理的探索
- 抽象出代码创建所需的代理
- 为代理编写代码
- 结果:好的,坏的,丑的
- 代码库链接
- 下一步
前提条件
我的目标是更多地与代理合作,并考虑一个满足新项目开始需求的代理管道。这不是一个优化资源使用的练习,因为代理在API调用LLMs、内存使用和处理上更为资源密集;相反,他们擅长提供一个可关联的模式和内存共享。主要目标是生成一个项目,使用任何语言,并附带支持文件;理想情况下,生成的代码在生成后能够正常工作。
主要场景
Instead of coding the entire software product, we consider setting up 代理 to fulfill a specific portion. While there are many complicated systems out there, we’ll consider the following software scenarios which are extremely simple:
- Create A RESTful API
- Create A Stand-alone webpage
- Create A 命令行应用程序
抽象化代码创建所需的代理
让我们考虑一下我们所拥有的 3 种场景以及可能有用的代理。首先,让我们考虑一下为了保持简单,我们将忽略什么。
保持简单
- 我们不考虑迭代周期。
- 我们不考虑代理的工具。
这里是每种情况所需步骤的详细说明。
要创建一个 RESTful API,我需要:
- 解释 需求并概述所需的文件
- 生成 接口规范
- 编码 API 以请求的语言
- 编码 实用库以请求的语言
- 添加 测试
- 创建 文档 以说明如何运行
要创建一个独立的网页,我需要:
- 解释需求并概述所需的文件
- 编写页面代码以满足需求
- 编写页面样式以满足需求
- 添加 测试
- 创建 文档 以说明页面功能
要创建一个命令行应用程序,我需要:
- 解释 需求并概述所需的文件
- 编码 CLI 应用程序以符合规范
- 添加 测试
- 创建 文档 以说明如何使用
让我们再看一下这个,并标记每个任务可以完成该任务的专家,这可能有助于组织一个代理。
要创建一个 RESTful API,我需要:
- 项目架构师 解释需求并概述所需的文件
- 项目架构师/开发人员 生成接口规范
- 开发人员 用请求的语言编写 API
- 开发人员 用请求的语言编写工具库
- 开发人员/质量保证 添加测试
- 开发人员/技术写作 创建关于如何运行的文档
要创建一个独立的网页,我需要:
- 项目架构师 解释需求并概述所需的文件
- 高级软件开发人员 根据需求编写页面代码
- 高级软件开发人员 根据需求编写页面样式
- 高级软件开发人员/质量保证 添加测试
- 高级软件开发人员/技术写作 创建关于页面功能的文档
要创建一个命令行应用程序,我需要:
- 项目架构师:解释需求并概述所需的文件
- 高级软件开发人员:按照规范编写CLI应用程序
- 高级软件开发人员/质量保证:添加测试
- 高级软件开发人员/技术写作:创建使用文档
这里是提到的3种场景中的专业人员名单:
- [项目架构师]
- [项目架构师/开发人员]
- [开发人员]
- [开发人员/质量保证]
- [开发人员/技术写作]
让我们将它们映射到可以进一步讨论的代理:
- [architect] -> manifest_agent “将问题分解为所需的文件集”
- [architect/developer] -> idl_agent “将问题分解为接口规范”
- [developer] -> code_agent “接受文件列表并进行编码”
- [developer/QA] -> test_agent “创建测试”
- [developer/technical-writer] -> docs_agent “创建文档”
这里是我们需要考虑的三个场景的代理:
- manifest_agent: “将问题拆分为一组可以填充 manifest.json 的文件”
- idl_agent: “将问题拆分为接口规范”
- code_agent: “获取文件和代码的列表”
- test_agent: “创建测试”
- docs_agent: “创建文档”
抽象代理及其目标
保持简单:一个管道统治所有
大多数场景遵循以下管道:
- 项目架构师 -> 开发人员 -> 质量保证 -> 技术写作
我们可以将其映射到我们的代理:
- manifest_agent -> idl_agent -> code_agent -> test_agent -> docs_agent
为了保持简单,我们假设以下几点:
- 不必要/额外的步骤将使代码更清晰(例如,网页的 idl_agent 将是多余的)
- 没有冗余步骤来处理复杂性,因此我们将依赖代理一次性完成任务
需求通过 manifest agent 被解释为文件清单,由 IDL agent 解释,并创建接口。编码代理获取接口并生成代码,测试代理获取生成的代码并创建测试,文档代理将文件清单、代码和测试汇总以生成文档。
编写代理
代理与任务是 1:1
- 每个代理都有一个相关的任务。这种一对一的映射提供了它试图实现的目标的清晰性。
顺序工作
- 首先,由 manifest_agent 在一个小组中创建文件清单和大纲。
- 生成的文件清单由 idl_agent → code_agent → test_agent → docs_agent 依次分发并处理。
清单 代理/任务
return Agent(
role='项目架构师',
goal='确定项目结构和文件组织',
backstory="""你是一名软件架构师,专注于分析项目
需求并确定最佳文件结构。你擅长根据项目规范识别
适当的文件名称和组织方式。""",
tools=[],
verbose=True
)
return Task(
description=f"""分析以下项目规范并确定适当的文件结构:{project_spec}
你的任务是处理这个规范并返回一个包含文件结构信息的 JSON 字符串。
仅返回此 Python 代码的 JSON 字符串输出
不要在你的响应中包含任何额外的文本或格式。""",
agent=agent,
expected_output="一个有效的 JSON 字符串,包含文件路径和语言信息,具有以下键:name, language, implementation_file, test_file, docs_file, interface_file",
output_file='src/manifest.json'
)
接口定义语言 代理
return Agent(
role='IDL Specification Expert',
goal='Convert project specifications into detailed Interface Definition Language',
backstory="""You are an expert in creating Interface Definition Language (IDL)
specifications from project requirements. You excel at translating business
requirements into technical interfaces and data structures.""",
verbose=True
)
return Task(
description=f"""Analyze the following project specification and create a detailed IDL:
{specification}
Your task is to create a comprehensive IDL specification following this template:
// 数据结构
struct [StructName] {{
// 带类型的属性
}}
// 接口定义
interface [InterfaceName] {{
// 带参数和返回类型的方法签名
}}
// 类型定义
typedef [NewType] [BaseType];
// 错误规范
exception [ErrorName] {{
// 错误属性
}}
The IDL should cover:
1. 所有必需的数据结构
2. 完整的接口定义
3. 必要的类型定义
4. 错误规范""",
agent=agent,
expected_output="""A complete IDL specification document containing:
- Clearly defined data structures for the project
- Well-documented interface definitions
- Appropriate type definitions
- Comprehensive error specifications""",
output_file=output_file
)
代码代理
return Agent(
role='高级软件开发人员',
goal='根据规格实现高质量、可维护的代码',
backstory="""您是一位经验丰富的软件开发人员,专注于编写干净、高效的代码。您擅长将技术规格转换为实际实现,同时遵循最佳实践。""",
verbose=True
)
return Task(
description=f"""根据以下接口定义语言(IDL)规格,实现一个完整的应用程序:
{idl_spec}
确保实现:
0. 使用指定的语言编写
1. 遵循面向对象原则
2. 包含适当的错误处理
3. 具有类型提示的良好文档
4. 遵循适当的风格指南
5. 实现所有指定的接口和数据结构""",
agent=agent,
expected_output="""完整实现包括:
- IDL中定义的所有类和方法
- 适当的错误处理机制
- 类型提示和文档字符串
- 遵循面向对象原则的干净代码结构
- 实现所有所需功能""",
output_file=output_file
)
测试代理
return Agent(
role='测试专家',
goal='为生成的代码创建全面的测试',
backstory="""您是一名专注于创建全面测试套件的质量保证工程师。通过全面的测试覆盖和边缘情况处理,确保代码的可靠性,适用于任何编程语言。""",
tools=[],
verbose=True
)
return Task(
description=f"""为生成的代码在目标语言中创建全面的单元测试:
{code}
测试套件必须覆盖:
0. 使用与代码相同的语言编写
1. 所有公共接口和方法
2. 错误处理场景
3. 边缘情况和边界条件
4. 适用时的集成测试
5. 输入验证""",
agent=agent,
expected_output="""指定语言中的完整测试套件,包括:
- 所有公共方法的单元测试
- 错误处理验证
- 边缘情况覆盖
- 集成测试
- 测试场景的文档""",
output_file=output_file
)
文档 代理
return Agent(
role='技术写作',
goal='创建清晰的计算器应用程序文档',
backstory="""您是一名技术写作专家,专注于为命令行工具创建用户友好的
文档。您擅长清晰地解释数学概念和软件使用方法。""",
tools=[],
verbose=True
)
return Task(
description=f"""为计算器应用程序创建全面的文档:
{project_info}
文档应包括:
1. 安装和设置
2. 可用操作
3. 使用示例
4. 错误处理指南
5. 历史功能使用""",
agent=agent,
expected_output="""完整的计算器文档包括:
- 清晰的安装说明
- 详细的操作指南
- 示例计算
- 故障排除部分
- 历史功能说明""",
output_file=output_file
)
结果 — 代码质量与细分
要讨论结果,让我们回顾一下我们希望创建的内容。以下列表概述了我们试图构建的三件事,我为清晰起见在规范中添加了语言:
- 创建一个 RESTful API(使用 GO)
- 创建一个独立的网页(使用 HTML + JAVASCRIPT)
- 创建一个 命令行应用程序(使用 PYTHON)
创建一个命令行应用程序(使用 Python)
这有最佳结果
好处
- 创建了一个过度设计的计算器类,配备了所有的功能
- 测试正常工作
坏处
- 我必须修改生成的代码以去除 Markdown 装饰器
- 我必须修改生成的代码以包含生成的库
- 尽管我们有一个代理来创建清单,但我的计算器类还是不知怎么的出现在了 main.py 中,而我的 idl-spec(与 Python 程序无关)却被收集到了 calculator.py 中
丑陋
- 无
创建一个 RESTful API (在 GO 中)
好的
- 它生成了一个不错的计算器类和良好的测试。
坏的
- 我不得不修改生成的代码以去除 markdown 装饰器。
丑陋的
- 它忽视了要求它是一个 RESTful API,而不是一个命令行驱动的程序。
创建一个独立的网页(使用 HTML + JavaScript)
我们先从坏的方面开始,请记住最终的代理,即文档代理,可以访问所有之前代理的结果,这使它能够在最后一步进行一些评估。
坏的方面
- 项目所需的 HTML 和 JavaScript 文件在最终的 Readme.md 文档中作为说明出现,而不是独立的项目文件。它有这样的标题:“创建 HTML 文件 (
index.html
):将以下模板复制到您的index.html
文件中。 …”。我猜文档步骤注意到这些文件缺失,但却拥有创建它所需的一切。 - Readme.md 中生成的 HTML 文件缺少对我建议创建的
script.js
文件的引用。 - 我不得不修改生成的代码以去除 Markdown 装饰符。
丑陋的方面
- 一些代码显示为 Python。
- 创建的一些子目录没有意义。
- 我不得不进行大量的手动文件创建,而这些本应由服务来处理;大型语言模型(LLM)将其重新委派给我,在 Readme.md 文件中。
好的方面
- 在按照 Readme 的说明操作并添加一行以包含
script.js
文件后,我得到了一个可工作的单页面应用程序计算器。
下一步
作为第一步,主要目标已经达成,尽管有一些注意事项,但这是朝着正确方向迈出的一步。这个项目的下一步:
- 完善工作流程 连接 以更好地连接文件描述符
- 完善: 添加一个函数以自动从代码中去除 markdown
- 完善: 移动文件时清理任何子目录
- 审查/修复: 该项目最初仅为 Python 创建,后来进行了扩展。因此,我很可能在将文件清单连接到工作流程其余部分的代码中有一些特定于 Python 的代码。
代码库
DEMO
工厂生产线上的机器人工作者 — 生成