环曜Agent核心功能拆解:RAG、工作流与AI数据分析的实现原理

📅 2026/6/30 16:02:43
环曜Agent核心功能拆解:RAG、工作流与AI数据分析的实现原理
环曜Agent核心功能拆解RAG、工作流与AI数据分析的实现原理前两篇分别讲了架构和部署这篇来深入聊聊环曜Agent最吸引人的三个功能RAG知识库、可视化工作流和AI数据分析。我会结合源码尽量把实现原理讲清楚而不是停留在功能介绍层面。一、RAG知识库从文档到智能回答RAGRetrieval-Augmented Generation是环曜Agent知识库的核心。它的价值在于让大模型能基于私有文档回答问题而不是瞎编。环曜Agent的RAG实现有几个值得说道的细节。1.1 文档处理流水线用户上传一个PDF后台经历了什么我梳理了一下流程PDF/DOCX上传 ↓ LibreOffice转PDF如果是Office文档 ↓ PDFBox提取文本 页码信息 ↓ 智能分块按段落/语义切分 ↓ Embedding向量化 ↓ 存入Elasticsearch向量全文索引智能分块这个环节比较关键。环曜Agent没有简单按固定字数切分而是做了语义完整性判断。源码里能看到它尽量在段落边界处切分避免把一句话拦腰截断。这样做的好处是检索时每个chunk都是语义完整的注入Prompt后模型更容易理解上下文。1.2 混合检索策略环曜Agent的检索不是单纯的向量相似度而是向量检索 BM25全文检索的混合方案# application.properties里的配置 rag.enable-hybrid-searchtrue rag.bm25-weight0.3 rag.vector-weight0.7混合检索的意义在于互补向量检索擅长语义匹配比如用户问怎么退款能匹配到退货流程相关的内容BM25检索擅长关键词精确匹配比如用户问某个特定的产品型号能精确命中环曜Agent的做法是分别用两种方式检索然后按权重合并结果。向量占70%、BM25占30%这个配比在通用场景下比较均衡。如果你的场景关键词精确匹配更重要可以调大BM25的权重。1.3 重排序优化第一次检索可能返回几十个结果但不是每个都相关。环曜Agent做了重排序Rerank用户提问 → 混合检索Top 15 → 重排序 → 取Top 5 → 注入Prompt重排序的作用是把最相关的内容排到前面。因为混合检索的打分方式不同直接合并的结果顺序不一定最优。重排序模型会对候选结果重新打分通常能显著提升最终答案的质量。1.4 原文定位功能这个功能挺实用的。当AI基于知识库回答时可以显示答案引用自哪篇文档的哪一页。实现原理是文档处理时PDFBox提取文本的同时记录每段文字的页码和坐标分块时把位置信息一起存入ES检索返回结果时把位置信息一并带回前端展示时生成原文链接点击可以跳转到对应位置这个功能依赖LibreOffice把文档转成PDF所以README里反复强调推荐安装LibreOffice。如果没装功能会降级只能显示文档名不能精确定位。1.5 本地Embedding降级方案环曜Agent有个很贴心的设计LocalEmbeddingModel。当用户没有配置API Key时系统会自动用这个本地模型做Embedding。它的实现基于n-gram哈希特征512维向量。虽然效果不如OpenAI的text-embedding-ada-002但胜在完全本地运行不依赖外网零成本不消耗API额度启动时自动初始化无需额外配置源码在LocalEmbeddingModel.java里有兴趣可以看看。对于内网环境或者预算有限的场景这个降级方案很实用。二、可视化工作流拖拽背后的执行引擎工作流编排是环曜Agent的另一个亮点。前端看着是拖拽连线后端其实是个完整的执行引擎。2.1 节点类型设计环曜Agent支持7种节点类型节点类型作用典型场景LLM节点调用大模型生成内容文本生成、意图识别条件节点根据条件分支执行if/else逻辑判断循环节点批量数据处理遍历列表、批量分析工具节点调用外部工具/API查天气、调数据库变量节点数据传递和转换格式转换、字段提取定时节点定时触发执行定时报表、定时巡检结束节点流程结束输出返回最终结果这些节点基本覆盖了常见的自动化场景。更复杂的需求可以通过组合实现比如定时触发 → 读取数据库 → 循环处理每条记录 → LLM分析 → 条件判断 → 发送通知2.2 执行引擎原理工作流的执行不是简单的顺序执行而是基于拓扑排序的有向无环图DAG执行// 伪代码核心逻辑在 WorkflowEngine.javapublicclassWorkflowEngine{publicExecutionResultexecute(Workflowworkflow,MapString,Objectinputs){// 1. 构建DAGGraphgraphbuildGraph(workflow.getNodes(),workflow.getEdges());// 2. 拓扑排序确定执行顺序ListNodeexecutionOrdertopologicalSort(graph);// 3. 按顺序执行每个节点WorkflowContextcontextnewWorkflowContext(inputs);for(Nodenode:executionOrder){NodeExecutorexecutorgetExecutor(node.getType());NodeResultresultexecutor.execute(node,context);context.setOutput(node.getId(),result);}// 4. 返回最终结果returnbuildResult(context);}}拓扑排序保证了依赖关系如果节点B依赖节点A的输出那A一定在B之前执行。如果用户连成了环A依赖BB又依赖A系统会检测并报错。2.3 变量传递与表达式节点之间怎么传数据环曜Agent设计了一套变量引用机制节点A输出: {summary: 这是一段摘要} 节点B输入: {{nodeA.output.summary}}双大括号语法表示引用其他节点的输出。执行时引擎会解析表达式从上下文里取值替换。这套机制虽然简单但足够支撑大多数数据传递场景。2.4 错误处理与重试工作流执行难免出错环曜Agent做了几层保护节点级重试每个节点可以配置重试次数和间隔错误分支条件节点可以判断上一个节点是否失败超时控制防止某个节点卡住导致整个流程挂起日志记录每个节点的输入输出都记录方便排查这些设计让工作流在 production 环境下更可靠。毕竟自动化流程跑在后台出了问题不能指望用户手动重试。三、AI数据分析自然语言查询数据库这是环曜Agent最有特色的功能也是我花时间研究最多的部分。3.1 整体流程用户输入自然语言 ↓ 意图识别判断是不是查询意图 ↓ 获取数据源表结构/索引信息 ↓ 构建Prompt包含表结构 用户问题 ↓ 调用LLM生成SQL/DSL ↓ 安全验证四层防护 ↓ 执行查询只读连接 ↓ 返回结果 生成的SQL AI分析3.2 Prompt工程Prompt的设计直接决定了生成SQL的质量。环曜Agent的Prompt大致长这样你是一个数据分析助手。根据下面的表结构将用户的问题转换为SQL查询。 表结构 表名: orders 字段: - id (INT, 主键) - user_id (INT, 用户ID) - amount (DECIMAL, 订单金额) - status (VARCHAR, 订单状态) - created_at (DATETIME, 创建时间) 约束 - 只能生成SELECT查询 - 禁止INSERT/UPDATE/DELETE/DROP/TRUNCATE - 使用标准SQL语法 用户问题最近7天的订单总额是多少 请生成SQLPrompt里包含几个关键要素表结构信息字段名、类型、注释帮助模型理解数据含义约束条件明确告诉模型只能生成查询语句示例引导如果有历史查询记录会作为示例加入Prompt3.3 四层安全防护AI生成SQL最大的风险是安全问题。环曜Agent做了四层防护我逐层分析第一层意图识别在调用LLM之前先判断用户的问题是不是查询意图。如果是删除所有数据这种明显危险的意图直接拦截。实现方式可以用简单的关键词匹配也可以用一个小模型做分类。第二层Prompt约束在Prompt里明确写入安全规则“只能生成SELECT查询”“禁止INSERT/UPDATE/DELETE/DROP/TRUNCATE”“禁止修改数据库结构”LLM对Prompt里的约束通常比较听话尤其是GPT-4和通义千问这种强模型。第三层SQL验证LLM生成的SQL不是直接执行而是先过一遍正则检查// 伪代码publicbooleanisSafe(Stringsql){Stringuppersql.toUpperCase();// 禁止的SQL关键字String[]forbidden{INSERT,UPDATE,DELETE,DROP,TRUNCATE,ALTER};for(Stringkeyword:forbidden){if(upper.contains(keyword)){returnfalse;}}// 必须以SELECT开头returnupper.trim().startsWith(SELECT);}这层是硬规则不管LLM生成了什么只要包含危险关键字就直接拒绝。第四层数据库只读连接最后一道防线执行SQL时用的数据库连接是只读权限的。即使前面三层都被绕过了只读连接也做不了破坏。# 配置只读数据源 spring.datasource.read-onlytrue这四层防护从应用层到数据库层层层递进在安全和可用性之间做了不错的平衡。3.4 同义词与口语化理解业务人员不会用精确的字段名提问。比如表里有created_at字段用户可能问下单时间、“什么时候买的”、“购买日期”。环曜Agent的解决方案是领域词典管理员可以配置同义词映射“下单时间” - “created_at”用户提问时先做同义词替换替换后的文本再送入LLM生成SQL这个功能在领域词典管理页面配置对于业务术语多的场景比如医疗、金融特别有用。3.5 Elasticsearch DSL生成除了MySQL环曜Agent还支持自然语言查询Elasticsearch。生成DSL的逻辑和SQL类似但Prompt里要教LLM DSL语法ES索引结构 索引: logs 字段: - timestamp (date) - level (keyword) - message (text) 请生成Elasticsearch DSL查询...ES DSL比SQL复杂生成准确率会稍低一些。但对于日志分析、全文搜索场景这个功能能省不少事。四、Function Calling扩展AI的手脚Function Calling让AI能调用外部工具是智能体从能说到能做的关键。4.1 内置工具集环曜Agent内置了7个工具工具功能使用场景天气查询查指定城市天气出行助手、生活咨询计算器数学运算财务计算、数据分析数据库查询执行SQL数据查询、报表生成Web搜索联网搜索实时信息获取URL阅读读取网页内容资讯摘要、竞品分析当前时间获取时间时效性回答工作流调用触发工作流复杂任务自动化4.2 工具注册与发现工具的注册机制设计得挺灵活ComponentpublicclassToolRegistry{privateMapString,TooltoolsnewHashMap();publicvoidregister(Tooltool){tools.put(tool.getName(),tool);}publicToolgetTool(Stringname){returntools.get(name);}publicListToolgetAllTools(){returnnewArrayList(tools.values());}}每个工具实现统一的Tool接口 Spring启动时自动扫描注册。新增工具只需要写个类加Component注解不需要改其他代码。4.3 工具调用流程用户提问 → LLM判断是否需要工具 → 生成工具调用参数 → 执行工具 → 结果返回LLM → 生成最终回答LangChain4j封装了大部分细节开发者只需要实现工具的执行逻辑。比如天气查询工具Tool(查询指定城市的天气)publicStringgetWeather(P(城市名如北京、上海)Stringcity){// 调用天气APIreturnweatherApi.query(city);}Tool和P注解会自动生成工具描述LLM根据描述判断什么时候调用这个工具。五、小结环曜Agent这三个核心功能的实现有几个共同的设计思路分层架构每个功能都有清晰的层次RAG分文档处理/检索/生成工作流分编辑/执行数据分析分意图识别/SQL生成/执行安全优先尤其是AI数据分析四层防护从应用到数据库层层把关降级策略LocalEmbeddingModel、只读连接等设计保证系统在资源受限时也能运行扩展性工具注册、领域词典、模型配置等都留了扩展接口下篇文章我会从源码层面解读环曜Agent的代码结构并分享二次开发的经验。如果你想在这个基础上定制自己的功能下篇应该对你有帮助。本文基于环曜Agent实际项目经验撰写仅供技术交流参考。关于环曜Agent环曜Agent是一家专注于企业级AI智能体本地化部署的服务商提供从平台搭建、模型适配到二次开发的全栈技术支持。我们致力于帮助企业构建安全可控、私有化部署的AI智能体平台让非技术人员也能轻松创建和管理AI助手。服务范围智能体平台部署 | RAG知识库搭建 | 工作流自动化 | AI数据分析 | 模型本地化适配 | 企业定制开发