项目进度:

当前群面项目已经跑通文字版功能,且前端后端均已完善,并实现了时间线与事件流的报告导出

本周工作:

1.分析学习OpenManus源码,学习自己实现ReAct智能体

首先在学习前,我了解了什么是OpenManus,什么是ReAct,
ReAct 的核心思想就 8 个字:思考 (Think) ->行动 (Act),让大模型先思考我要做什么、需要用什么工具,再执行动作,最后根据结果迭代思考,直到完成任务。

而 OpenManus 做的,就是把这个抽象逻辑,拆成了分层代理、工具解耦、状态管理、提示词工程四大模块,解决了工程落地的问题

OpenManus架构
1.整体文件组织

OpenManus由智能体核心、工作流、自定义的MCP、提示词、沙箱环境、工具组成,其目录划分不是随意的,而是按照智能体的核心能力边界拆分的,如下图所示

这种拆分最大的价值是可扩展性。比如我想换一个大模型,不用改智能体核心;想加一个新工具,不用动 ReAct 的执行逻辑,这就是软件工程里的单一职责原则。

2.agent核心目录

agent目录是OpenManus实现的核心,采用了分层的代理架构,不同层次的代理负责不同的功能,这样更利于系统的扩展。

OpenManus的代理架构主要包含以下层:
1.BaseAgent:最基础的代理抽象类,定义了所有代理的基本状态管理和循环
我认为这个抽象基类的作用是定规范,所有智能体都必须遵循这套状态和循环,这让后续扩展 ReActAgent、ToolCallAgent 变得极其简单 —— 不用重复写状态判断,只需要重写核心逻辑

2.ReActAgent:实现ReAct模式的代理,具有思考(Think)和动(Act)两个主要步骤
ReActAgent 没有绑定任何工具,只实现纯逻辑循环

# 伪代码还原源码核心逻辑
while 任务未完成:
    1. Think(思考):把记忆+任务交给LLM,让模型输出「思考结论」
    2. Act(行动):根据思考结果,决定是直接回答,还是调用工具
    3. 结果回写:把行动结果存入记忆,进入下一轮循环

3.ToolCallAgent:能够调工具的代理,继承自ReActAgent并扩展了工具调能
这里用了继承 + 扩展的设计,完美符合开闭原则(对扩展开放,对修改关闭)。不需要改动 ReAct 的核心循环,只需要新增工具调用逻辑,就能让基础的思考型智能体变成工具型智能体。


4.Manus:具体实现的智能体实例,集成了所有能并添加了更多专业工具
把 LLM、记忆、工具、ReAct 循环全部组装起来,对外提供直接调用的接口,这是框架的门面模式,用户不需要关心底层分层,直接调用 Manus 就能用

3.tool目录

tool目录定义了各种各样的工具,比如网页搜索、文件操作、询求用户帮助等等

4.prompt目录

prompt 目录定义了整个项目中可能会用到的提示词

5.else

为了实现完整的智能体功能,OpenManus 还依赖以下组件:
1.记忆系统:使Memory类存储对话历史和中间状态
2.LLM大模型:通过LLM类提供思考和决策能力
3.工具系统:提供BaseTool 和ToolCollection类扩展智能体的能力边界
4.流程控制:通过AgentState 和执行循环管理状态转换和任务流程

2.实现基于ReAct的ai复盘智能体

在学习完OpenManus后,我自己设计了一个基于ReAct的ai复盘智能体,目录如下:

1. 先搭 ReAct 核心骨架:分层抽象,定好基础规则

ReAct 的核心是 “思考->行动” 的循环,我参考OpenManus先定义了三层代理结构,核心是遵循 单一职责 + 开闭原则:

BaseManusAgent:最底层的抽象基类,负责通用能力(状态管理、执行循环、输入校验、流式 / 非流式运行入口)。

比如把 “maxSteps 最大步数控制”“IDLE/RUNNING/FINISHED 状态管理”“cleanup 清理资源” 这些所有智能体都需要的逻辑抽出来,避免重复造轮子。

这里的关键是 “定规范”—— 所有子类只需要实现 step () 方法,不用关心状态判断、循环终止这些通用逻辑。

核心函数run:

定义智能体循环步数,每次循环指向step方法并打印工作信息

      public String run(String userPrompt) {
            validateBeforeRun(userPrompt);
        this.state = ManusAgentState.RUNNING;
        this.messageList.add(new UserMessage(userPrompt));
        if (StringUtils.hasText(getNextStepPrompt())) {
            this.messageList.add(new UserMessage(getNextStepPrompt()));
        }
        log.info("[{}] run started, maxSteps={}, initialPromptLength={}", name, maxSteps, userPrompt.length());

        List<String> outputs = new ArrayList<>();
        try {
            for (int i = 0; i < maxSteps && state != ManusAgentState.FINISHED; i++) {
                this.currentStep = i + 1;
                log.info("[{}] executing step {}/{}", name, currentStep, maxSteps);
                String stepResult = step();
                outputs.add("Step " + currentStep + ": " + stepResult);
                log.info("[{}] step {} completed, resultPreview={}", name, currentStep, truncate(stepResult, 180));
            }
            if (currentStep >= maxSteps && state == ManusAgentState.RUNNING) {
                this.state = ManusAgentState.FINISHED;
                outputs.add("Terminated: reached max steps");
                log.warn("[{}] terminated by maxSteps", name);
            }
            return String.join("\n", outputs);
        } catch (Exception e) {
            this.state = ManusAgentState.ERROR;
            log.error("[{}] manus agent run error at step {}", name, currentStep, e);
            return "执行错误: " + e.getMessage();
        } finally {
            log.info("[{}] run finished, finalState={}", name, state);
            cleanup();
        }
    }

ReActManusAgent:继承 BaseManusAgent,专门实现 ReAct 的核心循环。

把 step () 拆成 think ()(思考)和 act ()(行动)两个抽象方法,只保留 “思考后决定是否行动” 的纯逻辑框架,不绑定任何工具或业务逻辑。伪代码核心就是:

@Override
public String step() {
    boolean shouldAct = think(); // 让子类实现“思考要不要调用工具”
    if (!shouldAct) {
        return "无工具调用的思考完成";
    }
    return act(); // 让子类实现“执行工具调用”
}

这一步的价值是 “解耦”——ReAct 的核心循环和具体业务、工具完全分开,后续扩展工具调用、报告生成,都不用改这个骨架。

2. 扩展工具调用能力:ToolCallManusAgent

基于 ReActManusAgent 扩展出 ToolCallManusAgent,核心目标是让智能体能调用工具,还能规避重复调用、循环调用的问题,这是从 “纯思考型智能体” 到 “实用型智能体” 的关键一步。

该Agent类实现了父类的think与act函数,具体如下:

思考阶段(think ()):

先做 “纠偏提示”:如果智能体连续一轮没调用 exportMarkdown 工具,就主动注入提示词,强制它调用导出工具(避免只写报告文本不执行导出)
调用大模型生成响应,解析工具调用列表
 

行动阶段(act ()):

执行工具调用,把结果写回对话历史;
终止逻辑校验:调用终止工具doTerminate 前,必须确认导出需求(exportFormat=pdf 才调 exportPdf,否则只调 exportMarkdown),如果导出不完整就拒绝终止,强制补全导出步骤。

工具调用不是 “调了就行”—— 大模型可能会无限制调用读取工具,或者重复调用相同参数,必须在工程层加校验。

3. ReportManusAgent报告生成

基于 ToolCallManusAgent,设计出专门的 ReportManusAgent,这是从 通用工具调用代理”到 具体业务代理的步骤,核心是把业务规则注入提示词 + 工具调用约束。

提示词设计

系统提示词明确三大核心规则:

证据约束:所有结论必须绑定事件流的时间戳、发言人ID(避免编造内容)
分析约束:必须包含“事实摘录→基于事实的推断→建议”三层结构,推断部分要标注分析师判断
导出约束:优先调 exportMarkdown,exportPdf仅在用户指定exportFormat=pdf 时调用

门面模式使用

把 ChatModel、工具列表、提示词、最大步数(setMaxSteps (10))全部组装到 ReportManusAgent 中,对外只暴露调用入口(run/runStream)。

用户不用关心底层的 ReAct 循环、工具校验逻辑,直接实例化 ReportManusAgent 就能生成报告 —— 这是门面模式的典型应用,降低用户使用成本。

4.其他

对于工具层,我定义了三个静态工具以获取房间信息、题目信息、群面对话过程等直接注入智能体中无需智能体调用,定义了MarkDownExportTool和PdfExportTool以支持智能体导出报告,定义了TerminateReportTool支持智能体自主结束调用过程,定义了WebSearchTool和WebScrapingTool支持网页抓取功能

此外,我定义了Advisor拦截器以实现智能体工作日志的打印以方便调试,
定义了ReportManusToolConfig注册所有实现的工具以方便智能体调用

5. 技术进度总结

1. 基础层:抽象 BaseManusAgent,解决所有智能体的通用状态/循环问题;
2.核心层:实现ReActManusAgent,搭好“思考→行动”的骨架;
3.扩展层:开发ToolCalManusAgent,解决工具调用的校验、防坑问题;
4.业务层:定制 ReportManusAgent,绑定面试复盘报告的业务规则,落地具体场景。

3.生成报告示例

经过查看后台日志等信息,确定了当前智能体具有独立执行工具调用生成markdown文档与自主调用终止工具、网页爬取工具等等功能,实现了基于ReAct的ai复盘报告生成的流程

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐