首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >AI Agent实战:基于ReAct与FunctionCalling构建本地编程助手

AI Agent实战:基于ReAct与FunctionCalling构建本地编程助手

原创
作者头像
编码未来
修改2026-03-03 08:13:37
修改2026-03-03 08:13:37
1960
举报
文章被收录于专栏:AIAI

摘要:本文通过一个从零构建的本地编程助手Agent项目,详解FunctionCalling如何与ReAct(推理-行动)模式协同工作,实现大模型对文件系统的增删改查操作。包含完整的Python代码解读、工作流程图及核心概念剖析,助你彻底掌握Agent的底层执行逻辑。

2025年开始智能体这个概念异常火热,从上半年的FunctionCalling、MCP到下半年的Skills。这些标准、协议、规范都旨在通过给大模型扩展“手脚”,来实现大模型从对话辅助到实际干活的跨越,经过这一年的发展,CC、OpenCode、Cursor、OpenClaw等等Agent的涌现,及其具备的能力,可谓是发展火热。程序开发效率得以大幅提升,也引发了程序员的生存危机考虑。本文不探究技术层面以外的影响,这系列博客目标是个人AI转型期间的所有经验积累,因此言归正传,回到主题:FunctionCalling理解。

在讲概念之前,先讲一个代码样例(github地址:https://github.com/coder-sswdg/myAIAgent/tree/main),该样例是作者从0开始创建的一个本地编程Agent(因为是编程助手,所以核心就是文件夹、文件的增删改查),大模型从想到干完成的方式是基于ReAct模式通过FunctionCalling调用具体实现函数来实现。

1、代码解释

代码语言:txt
复制
src/demo
--
  |--do_exec_react.py
  |--main.py
  |--system_prompt.py

代码结构目录如上,其中:

a) main.py是Agent入口,运行后启动对话,接收用户输入,然后通过ReAct循环完成任务。

代码语言:txt
复制
# main.py

"""
主程序入口
启动编程助手 Agent,接收用户输入,运行 ReAct 循环完成文件操作任务
"""

from do_exec_react import run_react_loop


def main():
    """
    主函数:启动交互式命令行界面
    """
    print("📁 欢迎使用本地编程助手 Agent")
    #print("输入您的需求,例如:")
    #print("  - 创建一个叫 my_project 的目录")
    #print("  - 在 my_project 中创建 hello.py 文件")
    #print("  - 读取 hello.py 的内容")
    #print("  - 修改 hello.py 添加函数")
    #print("  - 删除某个文件")
    #print("  - 搜索所有 .py 文件")
    print("输入 'quit'、'exit' 或 'bye' 退出程序。\n")

    while True:
        # 获取用户输入
        user_input = input("👉 你:").strip()
        
        # 跳过空输入
        if not user_input:
            continue
        
        # 退出指令
        if user_input.lower() in ['quit', 'exit', 'bye']:
            print("👋 再见!祝你编码愉快!")
            break

        # 运行 ReAct 循环处理请求
        result = run_react_loop(user_input)
        
        # 输出最终答案
        print(f"\n✅ 助手回复:{result}")


# 程序入口点
if __name__ == "__main__":
    main()

b) do_exec_react.py是Agent执行核心,它的关键点是路由到大模型处理用户请求,根据大模型处理返回匹配到具体的Function,执行Function将结果送给大模型,大模型进一步思考然后下发下一步指令,直到任务完成。

代码语言:txt
复制
def run_react_loop(user_input: str, max_steps: int = 10) -> str:
    """
    运行 ReAct 循环:思考 → 行动 → 观察 → 再思考……直到得出最终答案

    参数:
        user_input (str): 用户原始请求
        max_steps (int): 最大循环步数,防止无限执行

    返回:
        str: 最终的答案回复
    """
    # 初始化对话上下文
    messages=[
        {
            "role": "system",
            "content": SYSTEM_PROMPT
        },
        {
            "role": "user",
            "content": user_input
        }
    ]
    print("当前消息格式:")
    print(json.dumps(messages, ensure_ascii=False, indent=2))

    for step in range(max_steps):
        print(f"\n🔄 第 {step + 1} 步:生成思考与动作...")
        print(f"\n 上下文内容是{messages}")        
        # 模拟调用 LLM 获取响应(实际项目中替换为此处的真实 API)
        agent_response = simulate_llm(messages)
        print(f"🤖 Agent:{agent_response}")
        # 检查是否已有最终答案
        if "<final_answer>" in agent_response:
            return extract_final_answer(agent_response)

        # 解析动作
        action_name, args = parse_action_improved(agent_response)
        print(f"parse action is action_name={action_name},args={args}")
        if not action_name:
            messages = add_message(messages, "assistant", "<observation>⚠️ 未能解析出有效动作。</observation>")
            messages = add_message(messages,"user","请根据是否需要创建文件、更新文件、写入文件来重新思考任务")
            continue

        # 执行对应工具函数
        if action_name in TOOLS:
            observation = TOOLS[action_name](args)
        else:
            observation = f"❌ 未知的操作:{action_name}"

        print(f"🔍 观察结果:{observation}")

        # 将本轮交互追加到上下文中,供后续步骤参考
        messages = add_message(messages, "assistant", f"<observation>{observation}</observation>\n")
        messages = add_message(messages,"user",f"根据observation结果,进行下一步思考和任务")

        # 再次检查是否有 final_answer
        if "<final_answer>" in agent_response:
            return extract_final_answer(agent_response)

    return "<final_answer>⚠️ 达到最大步骤限制,未能完成任务。</final_answer>"

这是核心函数,可以发现Agent进入到这一步骤之后,做的动作如下:

第一步是先拿到初始的System Prompt和当前用户的输入请求,这就构成了给大模型的最初始的请求。

这里的System Prompt怎么理解就涉及到提示词工程这个话题,该话题后面再详细展开,大家只需要知道在Agent中System Prompt就是来告诉大模型,你该按照怎样的流程思考,你有哪些工具可以使用,遇到什么关键词就意味着你任务完成了。

第二步循环调用大模型,将最初始请求发送给大模型之后,将大模型的返回agent_response,打印后分析是任务已解决,还是需要继续执行action。

第三步调用对应工具函数```observation = TOOLS[action_name](args) ```让具体的Function干活,比如创建文件,在本样例中支持的Function如下。

代码语言:txt
复制
- CREATE_FILE(path="...", content="...")        → 创建文件(可指定路径和内容)
- READ_FILE(path="...")                         → 读取文件内容
- UPDATE_FILE(path="...", content="...")       → 更新文件内容
- DELETE_FILE(path="...")                       → 删除文件
- CREATE_DIR(path="...")                        → 创建目录(支持嵌套)
- DELETE_DIR(path="...")                        → 删除目录及其内容(递归删除)
- LIST_DIR(path="..." 或 ".")                  → 列出目录中的子目录和文件
- SEARCH_FILE(pattern="...", path="...")        → 在指定路径下按文件名模式搜索(支持正则)

第四步这是很关键的一步,这一步是为什么Agent能够迭代完成任务的关键```add message```,将当前大模型的输出叠加到对话上下文中,这样再次将message发给大模型时,大模型不仅能看到初始的系统约束和用户请求,还能看到自己的思考和行动历史,基于已完成动作来进行下一步动作。

代码语言:txt
复制
"""添加消息到对话列表"""
def add_message(message_list, role, content):
    message_list.append({
        "role": role,
        "content": content
    })
    return message_list

这里说一句题外话,我们看到的模型支持多少上下文窗口,指的就是这个,越大的上下文窗口,意味着模型可以记忆更长的内容,即有完成更复杂任务的可能性。

循环这1~4步直到任务完成。

c) system_prompt.py,从名称就可以看出这里承载的就是Agent的系统提示词,使用FunctionCalling来完成任务,为了避免模型幻觉和内容陈旧,一般都是结合ReAct模式一起来使用,确保任务完成。

2、代码工作流程图说明

基于FunctionCalling的Agent工作流程图
基于FunctionCalling的Agent工作流程图

从文字介绍和流程图说明,对于Agent的工作流程和工作原理现在已经了解到位了,下来我们进入原理讲解。

3、ReAct模式

ReAct模式是一种让大语言模型通过交替进行“推理(Reasoning)”和“行动(Acting)”来解决复杂任务的高级提示框架。它由谷歌和普林斯顿大学的研究人员在2022年首次提出,旨在将模型的内部思考能力与外部工具调用能力协同起来。核心工作机制:思考-行动-观察 循环。

如果把大语言模型比作一个“大脑”,那么ReAct模式就是为这个大脑装上了能够执行具体操作的“手和脚”,以及能够感知外部反馈的“五官”。

在具体的应用中 ReAct 模式的思考与行动,按照标准标准流程进行:

a. <thought> ... </thought>:先分析当前情况,思考下一步该做什么

b. <action> ... </action>:调用一个可用工具执行具体操作

c. 等待环境返回 <observation> ... </observation>:观察执行结果

d. 根据观察继续下一轮思考或给出最终回答

4、FunctionCalling

从上面例子已经可以明确FunctionCalling就是Agent解析大模型的返回后,调用Agent自身支持的一些列函数,来实现与外部世界(一般就是电脑)的交互,完成具体的任务,是具体的动作执行。

理解了这一点,也就可以理解为什么同样的功能,针对不同的Agent都需要挨个实现一遍,因为Function就在Agent内部。

5、其他

Agent本质是通过大模型的API实现多轮对话,那么在对话中有几个角色概念,需要了解一下。

角色:system,这个代表接下来内容是系统提示词。

角色:user,这个代表相关内容是用户输入。

角色:assistant,这个代表相关内容是大模型的输出。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档