基于LlamaIndex实现CodeAct Agent:代码执行工作流的技术架构与原理

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: CodeAct是一种先进的AI辅助系统范式,深度融合自然语言处理与代码执行能力。通过自定义代码执行代理,开发者可精准控制代码生成、执行及管理流程。本文基于LlamaIndex框架构建CodeAct Agent,解析其技术架构,包括代码执行环境、工作流定义系统、提示工程机制和状态管理系统。同时探讨安全性考量及应用场景,如软件开发、数据科学和教育领域。未来发展方向涵盖更精细的代码生成、多语言支持及更强的安全隔离机制,推动AI辅助编程边界拓展。

CodeAct作为AI辅助系统的一种先进范式,实现了自然语言处理与代码执行能力的深度融合。通过构建自定义代码执行代理,开发者能够精确控制应用程序中代码的生成、执行及管理流程。本文将详细阐述如何利用LlamaIndex框架从底层构建CodeAct Agent,深入剖析其内部工作机制,以及如何在预构建解决方案的基础上进行定制化扩展。

CodeAct技术范式的核心特性

从技术架构角度而言,CodeAct赋予AI助手以下关键能力:

  1. 基于自然语言指令的代码生成:将用户语义需求转换为可执行的程序代码
  2. 安全的代码执行环境:在隔离的受控环境中运行生成的代码
  3. 执行结果分析:获取并解析代码执行的输出与返回值
  4. 迭代式优化:基于执行结果智能调整解决方案

技术架构与核心组件

CodeAct Agent的技术架构由以下相互依存的关键组件构成:

  1. 代码执行环境:提供安全隔离的代码运行时环境,确保代码执行不影响宿主系统
  2. 工作流定义系统:规范代码生成、执行与结果处理的逻辑流程
  3. 提示工程机制:引导大语言模型以特定格式生成符合语法与逻辑要求的可执行代码
  4. 状态管理系统:维护对话历史、执行上下文与计算结果的持久化存储

代码实现

1、基础工具函数实现

首先需要定义代理可调用的基础函数集。以下实现了一组基本数学运算工具函数:

 def add(a: int, b: int) -> int:  
    """将两个数字相加"""  
    return a + b  

def subtract(a: int, b: int) -> int:  
    """两个数字相减"""  
    return a - b  

def multiply(a: int, b: int) -> int:  
    """两个数字相乘"""  
    return a * b  

def divide(a: int, b: int) -> float:  
    """两个数字相除"""  
     return a / b

2、代码执行环境构建

接下来,实现代码执行环境,该环境需具备在多次调用间保持状态的能力。

SimpleCodeExecutor

类实现了这一功能:

 from typing import Any, Dict, Tuple  
import io  
import contextlib  
import ast  
import traceback  

class SimpleCodeExecutor:  
    """  
    一个简单的代码执行器,可以在状态持久化的情况下运行Python代码。  
    这个执行器在多次执行之间维护全局和局部状态,  
    允许变量在多次代码运行中持久化。  
    注意:不适合在生产环境中使用!谨慎使用。  
    """  
    def __init__(self, locals: Dict[str, Any], globals: Dict[str, Any]):  
        """  
        初始化代码执行器。  
        参数:  
            locals: 在执行上下文中使用的局部变量  
            globals: 在执行上下文中使用的全局变量  
        """  
        # 在执行之间持久化的状态  
        self.globals = globals  
        self.locals = locals  
    def execute(self, code: str) -> str:  
        """  
        执行Python代码并捕获输出和返回值。  
        参数:  
            code: 要执行的Python代码  
        返回:  
            包含输出和返回值的字符串  
        """  
        # 捕获标准输出和标准错误  
        stdout = io.StringIO()  
        stderr = io.StringIO()  
        output = ""  
        return_value = None  
        try:  
            # 执行并捕获输出  
            with contextlib.redirect_stdout(  
                stdout  
            ), contextlib.redirect_stderr(stderr):  
                # 尝试检测是否有返回值(最后一个表达式)  
                try:  
                    tree = ast.parse(code)  
                    last_node = tree.body[-1] if tree.body else None  
                    # 如果最后一个语句是表达式,捕获它的值  
                    if isinstance(last_node, ast.Expr):  
                        # 分割代码以添加返回值赋值  
                        last_line = code.rstrip().split("\n")[-1]  
                        exec_code = (  
                            code[: -len(last_line)]  
                            + "\n__result__ = "  
                            + last_line  
                        )  
                        # 执行修改后的代码  
                        exec(exec_code, self.globals, self.locals)  
                        return_value = self.locals.get("__result__")  
                    else:  
                        # 正常执行  
                        exec(code, self.globals, self.locals)  
                except:  
                    # 如果解析失败,按原样执行代码  
                    exec(code, self.globals, self.locals)  
            # 获取输出  
            output = stdout.getvalue()  
            if stderr.getvalue():  
                output += "\n" + stderr.getvalue()  
        except Exception as e:  
            # 捕获异常信息  
            output = f"Error: {type(e).__name__}: {str(e)}\n"  
            output += traceback.format_exc()  
        if return_value is not None:  
            output += "\n\n" + str(return_value)  
         return output

3、工作流事件定义

为了规范化代码执行流程,需要定义控制工作流程的事件类型:

 from llama_index.core.llms import ChatMessage  
from llama_index.core.workflow import Event  

class InputEvent(Event):  
    input: list[ChatMessage]  

class StreamEvent(Event):  
    delta: str  

class CodeExecutionEvent(Event):  
     code: str

4、CodeAct Agent工作流实现

下面是完整的CodeAct Agent工作流实现,它将所有组件整合为一个功能完整的系统:

 import inspect  
import re  
from typing import Any, Callable, List  
from llama_index.core.llms import ChatMessage, LLM  
from llama_index.core.memory import ChatMemoryBuffer  
from llama_index.core.tools.types import BaseTool  
from llama_index.core.workflow import (  
    Context,  
    Workflow,  
    StartEvent,  
    StopEvent,  
    step,  
)  
from llama_index.llms.openai import OpenAI  

CODEACT_SYSTEM_PROMPT = """  
你是一个可以执行代码的有用助手。  
根据聊天历史,你可以在<execute>...</execute>标签内编写代码来帮助用户解决问题。  
在代码中,你可以引用之前使用过的任何变量或函数。  
用户还为你提供了一些预定义函数:  
{fn_str}  
要执行代码,请在<execute>...</execute>标签之间编写代码。  
"""  

class CodeActAgent(Workflow):  
    def __init__(  
        self,  
        fns: List[Callable],  
        code_execute_fn: Callable,  
        llm: LLM | None = None,  
        **workflow_kwargs: Any,  
    ) -> None:  
        super().__init__(**workflow_kwargs)  
        self.fns = fns or []  
        self.code_execute_fn = code_execute_fn  
        self.llm = llm or OpenAI(model="gpt-4o-mini")  
        # 将函数解析为截断的函数字符串  
        self.fn_str = "\n\n".join(  
            f'def {fn.__name__}{str(inspect.signature(fn))}:\n    """ {fn.__doc__} """\n    ...'  
            for fn in self.fns  
        )  
        self.system_message = ChatMessage(  
            role="system",  
            content=CODEACT_SYSTEM_PROMPT.format(fn_str=self.fn_str),  
        )  
    def _parse_code(self, response: str) -> str | None:  
        # 查找<execute>...</execute>标签之间的代码  
        matches = re.findall(r"<execute>(.*?)</execute>", response, re.DOTALL)  
        if matches:  
            return "\n\n".join(matches)  
        return None  
    @step  
    async def prepare_chat_history(  
        self, ctx: Context, ev: StartEvent  
    ) -> InputEvent:  
        # 检查是否设置了内存  
        memory = await ctx.get("memory", default=None)  
        if not memory:  
            memory = ChatMemoryBuffer.from_defaults(llm=self.llm)  
        # 获取用户输入  
        user_input = ev.get("user_input")  
        if user_input is None:  
            raise ValueError("user_input kwarg is required")  
        user_msg = ChatMessage(role="user", content=user_input)  
        memory.put(user_msg)  
        # 获取聊天历史  
        chat_history = memory.get()  
        # 更新上下文  
        await ctx.set("memory", memory)  
        # 将系统消息添加到聊天历史并返回  
        return InputEvent(input=[self.system_message, *chat_history])  
    @step  
    async def handle_llm_input(  
        self, ctx: Context, ev: InputEvent  
    ) -> CodeExecutionEvent | StopEvent:  
        chat_history = ev.input  
        # 流式传输响应  
        response_stream = await self.llm.astream_chat(chat_history)  
        async for response in response_stream:  
            ctx.write_event_to_stream(StreamEvent(delta=response.delta or ""))  
        # 保存最终响应,应包含所有内容  
        memory = await ctx.get("memory")  
        memory.put(response.message)  
        await ctx.set("memory", memory)  
        # 获取要执行的代码  
        code = self._parse_code(response.message.content)  
        if not code:  
            return StopEvent(result=response)  
        else:  
            return CodeExecutionEvent(code=code)  
    @step  
    async def handle_code_execution(  
        self, ctx: Context, ev: CodeExecutionEvent  
    ) -> InputEvent:  
        # 执行代码  
        ctx.write_event_to_stream(ev)  
        output = self.code_execute_fn(ev.code)  
        # 更新内存  
        memory = await ctx.get("memory")  
        memory.put(ChatMessage(role="assistant", content=output))  
        await ctx.set("memory", memory)  
        # 获取最新的聊天历史并循环回起点  
        chat_history = memory.get()  
         return InputEvent(input=[self.system_message, *chat_history])

5、CodeAct Agent的实例化与调用

完成组件构建后,可以初始化并调用CodeAct Agent:

 # 使用我们的函数初始化代码执行器  
code_executor = SimpleCodeExecutor(  
    # 提供访问我们的辅助函数  
    locals={  
        "add": add,  
        "subtract": subtract,  
        "multiply": multiply,  
        "divide": divide,  
    },  
    globals={  
        # 提供访问所有内置函数  
        "__builtins__": __builtins__,  
        # 提供访问numpy  
        "np": __import__("numpy"),  
    },  
)  

# 创建代理  
agent = CodeActAgent(  
    fns=[add, subtract, multiply, divide],  
    code_execute_fn=code_executor.execute,  
    llm=OpenAI(model="gpt-4o-mini", api_key="your_api_key_here"),  
)  
# 为代理创建上下文  
ctx = Context(agent)  
# 帮助函数,用于运行代理并输出详细信息  
async def run_agent_verbose(agent: CodeActAgent, ctx: Context, query: str):  
    handler = agent.run(user_input=query, ctx=ctx)  
    print(f"User:  {query}")  
    async for event in handler.stream_events():  
        if isinstance(event, StreamEvent):  
            print(f"{event.delta}", end="", flush=True)  
        elif isinstance(event, CodeExecutionEvent):  
            print(f"\n-----------\nParsed code:\n{event.code}\n")  
    return await handler  
# 运行代理与示例  
queries = [  
    "Calculate the sum of all numbers from 1 to 10",  
    "Add 5 and 3, then multiply the result by 2"  
]  
for query in queries:  
    response = await run_agent_verbose(agent, ctx, query)  
     print("\n" + "="*50 + "\n")

工作原理分析

CodeAct Agent的工作流程可分为以下关键阶段:

  1. 用户输入处理:系统接收用户查询,将其添加到对话记忆中,并结合系统提示准备完整的对话上下文。
  2. LLM代码生成:大语言模型根据对话上下文生成可能包含代码块的响应。系统通过特定标签<execute>...</execute>精确识别可执行代码段。若未检测到代码块,工作流程终止并返回纯文本响应。
  3. 代码执行阶段:系统将识别的代码发送至执行器,在受控环境中运行代码,捕获执行输出和错误信息,并将结果保存至对话记忆。
  4. 响应迭代处理:工作流程循环返回LLM处理阶段,使模型能够访问代码执行结果,并根据需要继续生成响应。此迭代过程持续进行,直至生成不包含代码的最终响应。

安全性考量

本文展示的

SimpleCodeExecutor

仅适用于开发环境。生产环境部署时应考虑以下安全措施:

  1. 实现容器化隔离环境(如Docker),确保代码执行不影响宿主系统
  2. 配置严格的资源限制机制,包括CPU使用率、内存上限及最大执行时间
  3. 实施精细的权限控制,严格限制对敏感模块和系统函数的访问
  4. 构建输入验证和安全过滤系统,防止注入攻击

结语

本文详细阐述了基于LlamaIndex构建CodeAct Agent的完整技术方案,从代码执行环境的构建、工作流事件的定义到完整Agent的实现。通过将代码生成与执行能力无缝集成到对话式AI系统中,CodeAct Agent代表了一种新型交互范式,能够将自然语言指令转化为可执行的计算逻辑。

这一技术架构的核心价值在于其可扩展性和灵活性。开发者可以根据特定应用场景定制执行环境、函数库和安全策略,从而构建出专用的智能工具。随着大语言模型能力的不断提升,CodeAct Agent的应用前景将更加广阔,特别是在以下领域:

  • 专业领域软件开发辅助工具
  • 数据科学探索与可视化系统
  • 教育领域的编程学习平台
  • 企业级自动化工作流构建

未来CodeAct技术的发展方向包括更精细的代码生成控制、多语言执行环境支持、更强大的安全隔离机制以及与专业领域知识库的深度集成。这些进步将进一步拓展AI辅助编程的边界,使自然语言与代码执行之间的转换更加高效、安全和可靠。

通过深入理解CodeAct Agent的核心技术架构,开发者能够构建将大语言模型的自然语言理解能力与代码执行功能有机结合的高度定制化解决方案,为各类应用场景提供强大的智能化支持。

https://avoid.overfit.cn/post/d66bc1e556934aa1b32a3ca58983795c

目录
相关文章
|
2月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
2月前
|
存储 人工智能 自然语言处理
为什么混合专家模型(MoE)如此高效:从架构原理到技术实现全解析
本文深入探讨了混合专家(MoE)架构在大型语言模型中的应用与技术原理。MoE通过稀疏激活机制,在保持模型高效性的同时实现参数规模的大幅扩展,已成为LLM发展的关键趋势。文章分析了MoE的核心组件,包括专家网络与路由机制,并对比了密集与稀疏MoE的特点。同时,详细介绍了Mixtral、Grok、DBRX和DeepSeek等代表性模型的技术特点及创新。MoE不仅解决了传统模型扩展成本高昂的问题,还展现出专业化与适应性强的优势,未来有望推动AI工具更广泛的应用。
307 4
为什么混合专家模型(MoE)如此高效:从架构原理到技术实现全解析
|
1月前
|
存储 人工智能 前端开发
Google揭秘Agent架构三大核心:工具、模型与编排层实战指南
本文为Google发布的Agent白皮书全文翻译。本文揭示了智能体如何突破传统AI边界,通过模型、工具与编排层的三位一体架构,实现自主推理与现实交互。它不仅详解了ReAct、思维树等认知框架的运作逻辑,更通过航班预订、旅行规划等案例,展示了智能体如何调用Extensions、Functions和Data Stores,将抽象指令转化为真实世界操作。文中提出的“智能体链式组合”概念,预示了未来多智能体协作解决复杂问题的革命性潜力——这不仅是技术升级,更是AI赋能产业的范式颠覆。
611 1
|
2月前
|
机器学习/深度学习 算法 测试技术
图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析
本文探讨了基于图的重排序方法在信息检索领域的应用与前景。传统两阶段检索架构中,初始检索速度快但结果可能含噪声,重排序阶段通过强大语言模型提升精度,但仍面临复杂需求挑战
89 0
图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析
|
2月前
|
Cloud Native 区块链 数据中心
Arista CloudEOS 4.32.2F - 云网络基础架构即代码
Arista CloudEOS 4.32.2F - 云网络基础架构即代码
59 1
|
2月前
|
Java 开发者 Spring
Spring框架 - 深度揭秘Spring框架的基础架构与工作原理
所以,当你进入这个Spring的世界,看似一片混乱,但细看之下,你会发现这里有个牢固的结构支撑,一切皆有可能。不论你要建设的是一座宏大的城堡,还是个小巧的花园,只要你的工具箱里有Spring,你就能轻松搞定。
106 9
|
3月前
|
消息中间件 存储 设计模式
RocketMQ原理—5.高可用+高并发+高性能架构
本文主要从高可用架构、高并发架构、高性能架构三个方面来介绍RocketMQ的原理。
442 21
RocketMQ原理—5.高可用+高并发+高性能架构
|
3月前
|
存储 人工智能 自然语言处理
Cursor这类编程Agent软件的模型架构与工作流程
编程Agent的核心是一个强大的大语言模型,负责理解用户意图并生成相应的代码和解决方案。这些模型通过海量文本和代码数据的训练,掌握了广泛的编程知识和语言理解能力。
198 1
|
4月前
|
机器学习/深度学习 缓存 自然语言处理
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
Tiktokenizer 是一款现代分词工具,旨在高效、智能地将文本转换为机器可处理的离散单元(token)。它不仅超越了传统的空格分割和正则表达式匹配方法,还结合了上下文感知能力,适应复杂语言结构。Tiktokenizer 的核心特性包括自适应 token 分割、高效编码能力和出色的可扩展性,使其适用于从聊天机器人到大规模文本分析等多种应用场景。通过模块化设计,Tiktokenizer 确保了代码的可重用性和维护性,并在分词精度、处理效率和灵活性方面表现出色。此外,它支持多语言处理、表情符号识别和领域特定文本处理,能够应对各种复杂的文本输入需求。
510 6
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
|
5月前
|
存储 SQL 缓存
MySQL原理简介—2.InnoDB架构原理和执行流程
本文介绍了MySQL中更新语句的执行流程及其背后的机制,主要包括: 1. **更新语句的执行流程**:从SQL解析到执行器调用InnoDB存储引擎接口。 2. **Buffer Pool缓冲池**:缓存磁盘数据,减少磁盘I/O。 3. **Undo日志**:记录更新前的数据,支持事务回滚。 4. **Redo日志**:确保事务持久性,防止宕机导致的数据丢失。 5. **Binlog日志**:记录逻辑操作,用于数据恢复和主从复制。 6. **事务提交机制**:包括redo日志和binlog日志的刷盘策略,确保数据一致性。 7. **后台IO线程**:将内存中的脏数据异步刷入磁盘。
224 12