最近和团队里几位后端同学聊技术演进,发现一个很有意思的对比:一边是大家非常熟悉的“手撸代码”方式,从接口定义、参数校验到日志输出,每一行都要自己敲;另一边是开始尝试让大模型驱动的 Agent 自动完成“理解需求、拆解任务、调用工具、汇总结果”的完整链路。这种从古法编程到 AI Agent 开发的跃迁,不是简单的“换个 IDE”,而是开发范式的变化。本文会先讲清楚两个概念,再给出一套可落地的 AI Agent 开发架构,最后用一个“AI Agent 通过 ES REST API 智能分析日志”的实战案例,带你把整体流程完整跑通。
1. 从“古法编程”说起:我们为什么需要 AI Agent
1.1 什么是古法编程
“古法编程”是社区里近期流行的一个略带调侃的说法,指的是过去几年我们习以为常的传统开发方式:
- 需求文档由产品经理口述,或者写成一份长篇 PRD。
- 开发同学手动梳理业务流程,拆成模块、接口、数据表。
- 用 IDE 手写代码,处理各种边界条件、异常分支。
- 写完代码后手动测试、部署、排查日志。
这种方式本身没有错,它仍然是现代软件工程的基石。尤其是对稳定性要求极高的核心交易系统、金融系统、底层中间件来说,人工可控、逻辑可追溯是最基本的要求。“古法”这个词并不代表落后,反而强调的是人类对代码逻辑的完全掌控。
1.2 传统编程模式的边界
随着业务复杂度提升,传统开发模式开始暴露出一些结构性瓶颈。
第一是需求转化的损耗。从自然语言需求到代码实现,中间隔着大量隐性知识。同一个“查询用户订单”的需求,不同开发写出来的接口性能可能差出十倍,这种差异很难靠“代码规范”彻底解决。
第二是人力的物理瓶颈。一个中大型系统往往涉及几十个接口、几百张表、上千个配置项,开发同学需要记忆和处理的细节越来越多。排查一个问题,经常要在日志系统、监控面板、数据库客户端之间反复切换。
第三是大量“简单但繁琐”的重复劳动。比如编写 CRUD 接口、生成表结构文档、把一段 JSON 转成 Java 对象、分析一段报错日志定位原因。这些事情逻辑不复杂,但非常占用时间。
正是这些边界,让“让程序自己理解需求、自己调用工具、自己总结结果”这件事变得有吸引力。AI Agent 并不是要取代程序员,而是把程序员从重复劳动中解放出来,让人更专注于架构设计、业务理解和代码评审。
1.3 AI Agent 到底解决了什么问题
AI Agent(人工智能智能体)可以理解为一个具备“感知-决策-行动”闭环的程序实体。它不只是“你问我答”的聊天助手,而是能够根据目标自主规划步骤、调用外部工具、观察执行结果、再调整策略直到完成任务。
用一个通俗的对比来说明:
古法编程模式下,想实现“分析最近一小时错误日志的高频异常”,你需要写脚本、调 ES API、写聚合查询、处理返回数据、再人工判断异常类型。
AI Agent 模式下,你只需要告诉 Agent 目标:“请统计最近一小时 ES 日志中的错误级别条目,按异常类型聚合,给出 TOP 5 结果和简要分析”。Agent 会自己决定调用哪个 ES 查询、如何解析返回结果、如何组织分析报告。
这中间的差别不在于“是否写代码”,而在于“控制的粒度”。传统方式是人对每一个步骤负责,Agent 方式是人负责定义边界和审核结果,Agent 负责执行细节。
2. AI Agent 的核心概念与完整架构
2.1 一句话理解 AI Agent
如果给 AI Agent 下一个简明的定义,可以这样说:
AI Agent 是一个以大语言模型为“大脑”,以工具调用为“手脚”,以记忆和规划为“工作记忆”的智能执行系统。
它和普通大模型应用的本质区别是:普通应用是“单轮问答”,Agent 是“多轮任务执行”。在多轮执行过程中,Agent 需要不断根据环境反馈调整自己的下一步动作,直到最终达成目标。
2.2 Agent 的完整架构拆解
一个完整的 AI Agent 通常包含以下核心模块:
| 模块 | 作用 | 类比 |
|---|---|---|
| LLM 核心 | 理解意图、生成决策、推理规划 | 人的大脑 |
| 规划(Planning) | 把大目标拆解为可执行的子任务 | 人的思考过程 |
| 记忆(Memory) | 保存对话上下文、历史结果、领域知识 | 人的工作记忆和长期记忆 |
| 工具(Tools) | 调用外部 API、数据库、命令行、搜索引擎 | 人的手脚 |
| 行动(Action) | 实际执行工具调用并获取结果 | 人的操作过程 |
| 观察与反思(Observation) | 根据执行结果判断是否完成任务 | 人的反馈机制 |
下面用一个 ASCII 简图展示 Agent 的执行闭环:
用户目标 │ ▼ ┌─────────┐ 拆解任务 ┌─────────┐ 调用工具 ┌─────────┐ │ 规划 │ ──────────▶ │ 决策 │ ──────────▶ │ 工具 │ └─────────┘ └─────────┘ └─────────┘ ▲ │ │ │ │ │ └──────── 观察结果并反思 ◀──────── 返回执行结果 ────┘这个闭环就是 ReAct(Reasoning + Acting)模式的核心思想:先推理分析,再行动执行,观察结果后继续推理,循环往复。
2.3 AI Skills 与 Agent 的区别
很多刚开始接触 AI Agent 的同学容易混淆两个概念:AI Skills(技能)和 Agent。
简单来说,AI Skills 是 Agent 可以调用的“能力单元”,它通常是一个封装的函数或工具,完成一件具体的事情。比如“查询订单接口”“发送邮件”“执行 Elasticsearch 聚合查询”都可以是一个 Skill。
而 Agent 是“调度者”。它决定什么时候调用哪个 Skill、调用几次、调用失败后怎么办、多个结果如何组合。
举个例子:一个日志分析 Agent 可能包含三个 Skills——query_es(查询 ES)、aggregate_logs(聚合日志)、generate_report(生成报告)。Agent 根据用户需求决定执行顺序,而 Skills 本身是相对独立、可复用的。
3. AI Agent 开发的环境准备
3.1 技术选型思路
AI Agent 开发目前还没有统一的行业标准,框架更新速度也比较快。因此在开始之前,先明确选型原则:
- 如果是为了学习和验证思路,优先选择轻量、可自控的实现方式,比如直接用 Python 写一个 ReAct 循环。
- 如果是为了快速搭建生产级应用,可以选择成熟的 Agent 框架,例如 LangChain、LlamaIndex,以及 Hugging Face 生态中的 smolagents、Transformers Agents 等。
- 如果团队是 Java 技术栈,可以关注 Spring AI 等 Java 生态方案,或者在现有微服务中单独部署 Python Agent 服务,通过 REST API 与主系统通信。
需要提醒的是,框架版本迭代很快,具体 API 以官方文档为准。本文采用“最小实现”的方式来演示核心原理,不依赖特定重量级框架,这样即使框架升级,你也能理解底层逻辑。
3.2 运行环境与依赖
本文实战案例的演示环境如下:
- 操作系统:Windows / macOS / Linux 均可
- 语言版本:Python 3.9+
- 依赖库:
requests(调用 ES REST API 和 LLM API) - ES 集群:Elasticsearch 7.x 或 8.x,假设本机地址为
http://localhost:9200 - LLM API:使用 OpenAI 兼容格式的大模型接口,具体模型和密钥自行配置
安装依赖:
pip install requests如果你使用的是 Elasticsearch 8.x,并且开启了安全认证,还需要准备用户名密码或 API Key。本文示例以最简单的 HTTP 访问方式演示,生产环境请务必开启认证并使用 HTTPS。
3.3 项目结构规划
为了让代码清晰可维护,我们按功能拆分文件:
agent-demo/ ├── config.py # 模型配置、ES 地址等 ├── tools.py # 工具函数:查询ES、解析日志 ├── agent.py # Agent 核心循环 ├── main.py # 入口程序 └── requirements.txt # 依赖清单这种结构的好处是:工具层和 Agent 逻辑层解耦。后续如果要引入 LangChain 等框架,只需要保留 tools.py,将 agent.py 替换为框架的 Agent 实现即可。
4. 实战案例:AI Agent 通过 ES REST API 智能分析日志
4.1 需求拆解
我们模拟一个真实场景:某后端服务在最近一小时内出现大量错误日志,运维和开发同学希望快速定位“错误集中在哪些异常类型”“主要影响哪些接口”“有哪些典型错误消息”。
如果按照古法编程,我们需要:
- 写一个 Python 脚本,拼装 ES 查询 DSL。
- 调用 ES 的
_searchREST API。 - 解析返回的
aggregations结果。 - 人工分析异常类型,再写一段总结。
现在改用 AI Agent,我们可以把“分析”这个动作交给 LLM 完成,而我们只需要提供两个基础能力:查询 ES 的工具,以及分析结果的大模型。
基于热词中的搜索内容,这类场景就是 “AI Agent 通过 ES REST API 智能分析日志” 的典型应用。它可以用于线上故障排查、日志巡检、告警根因分析等场景。
4.2 编写配置模块
先创建config.py,集中管理所有配置项:
# 文件路径:agent-demo/config.py # 大模型 API 配置(以 OpenAI 兼容接口为例) LLM_API_URL = "https://your-llm-endpoint/v1/chat/completions" LLM_API_KEY = "your-api-key" LLM_MODEL = "your-model-name" # Elasticsearch 配置 ES_URL = "http://localhost:9200" ES_INDEX = "app-logs-*" ES_USERNAME = None # 如开启了安全认证,填入用户名 ES_PASSWORD = None # 如开启了安全认证,填入密码 # Agent 配置 MAX_STEPS = 5 # 最大执行步数,防止死循环在真实项目中,这些配置不应该硬编码在 Python 文件中,建议通过环境变量或配置中心管理。这里为了演示方便,直接写在配置模块里。
4.3 编写工具层
工具层是 Agent 的“手脚”。我们定义两个工具函数:
es_search:向 ES 发起查询请求。extract_aggregation:从 ES 返回结果中提取需要的聚合数据。
# 文件路径:agent-demo/tools.py import requests import json from config import ES_URL, ES_INDEX, ES_USERNAME, ES_PASSWORD def es_search(query_dsl: dict) -> dict: """ 执行 Elasticsearch 查询。 :param query_dsl: ES 查询 DSL 字典 :return: ES 返回的原始 JSON """ url = f"{ES_URL}/{ES_INDEX}/_search" auth = None if ES_USERNAME and ES_PASSWORD: auth = (ES_USERNAME, ES_PASSWORD) resp = requests.post( url, json=query_dsl, auth=auth, timeout=30, headers={"Content-Type": "application/json"} ) resp.raise_for_status() return resp.json() def build_error_aggregation_query(window_minutes: int = 60, top_n: int = 5) -> dict: """ 构造一个日志聚合查询 DSL: 过滤最近 window_minutes 分钟内的 ERROR 级别日志, 按异常类型(log.level 已是 ERROR,再用 message.keyword 分桶)聚合 TOP N。 """ query_dsl = { "size": 5, "query": { "bool": { "filter": [ {"term": {"log.level": "ERROR"}}, {"range": {"@timestamp": {"gte": f"now-{window_minutes}m"}}} ] } }, "aggs": { "error_types": { "terms": { "field": "message.keyword", "size": top_n } } } } return query_dsl这里有几个细节需要注意:
message.keyword是 Elasticsearch 中 text 类型字段的 keyword 子字段,用于精确分桶。如果你的日志字段名不同,需要相应调整。@timestamp是常见的时间字段,也可能是timestamp,需要根据你的索引映射修改。resp.raise_for_status()会在 ES 返回 4xx/5xx 时抛出异常,方便上层捕获。
4.4 编写 Agent 核心循环
接下来是重点部分:Agent 核心循环。这里采用简化版的 ReAct 模式:
- 系统提示词告诉 LLM 它拥有哪些工具、如何调用。
- LLM 根据用户目标输出一个 JSON 格式的“工具调用计划”。
- Agent 解析计划,执行对应工具。
- 把工具返回结果追加到对话上下文,再次请求 LLM 生成最终分析。
# 文件路径:agent-demo/agent.py import json import requests from config import LLM_API_URL, LLM_API_KEY, LLM_MODEL, MAX_STEPS from tools import es_search, build_error_aggregation_query SYSTEM_PROMPT = """ 你是一个日志分析助手。你可以使用以下工具: - es_error_stats: 调用 Elasticsearch 聚合查询最近 N 分钟的错误日志,返回按错误消息分组的 TOP 5 统计。 当用户提出日志分析需求时,你需要按如下格式输出: {"tool": "es_error_stats", "args": {"minutes": 60}} 当已经拿到工具结果后,你需要基于结果生成最终的文本分析报告,报告格式为: {"answer": "你的分析报告内容"} 除了 JSON,不要输出其他内容。 """ def call_llm(messages: list) -> str: """调用 OpenAI 兼容接口的 Chat Completion API。""" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {LLM_API_KEY}" } payload = { "model": LLM_MODEL, "messages": messages, "temperature": 0 } resp = requests.post(LLM_API_URL, json=payload, headers=headers, timeout=60) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"] def run_agent(user_request: str) -> str: """ Agent 主流程: 1. 把系统提示词和用户请求发给 LLM 2. 解析 LLM 返回的 JSON 动作 3. 执行对应工具 4. 把结果作为上下文再次发送给 LLM,生成最终答案 """ messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_request} ] for step in range(MAX_STEPS): # 第一步:让 LLM 决策 raw_response = call_llm(messages) try: action = json.loads(raw_response) except json.JSONDecodeError: # 如果模型直接输出了最终答案,就返回它 return raw_response # 第二步:根据决策执行工具 if "tool" in action: tool_name = action["tool"] args = action.get("args", {}) if tool_name == "es_error_stats": minutes = args.get("minutes", 60) query_dsl = build_error_aggregation_query(window_minutes=minutes) es_result = es_search(query_dsl) buckets = es_result.get("aggregations", {}).get("error_types", {}).get("buckets", []) # 把工具结果整理成简洁文本,方便 LLM 理解 tool_summary = "\n".join( f"异常消息: {b['key']},出现次数: {b['doc_count']}" for b in buckets ) messages.append({ "role": "user", "content": f"工具执行结果如下:\n{tool_summary}\n请基于这些数据生成最终分析报告。" }) continue else: return f"未知工具: {tool_name}" # 第三步:如果模型返回 answer 字段,则任务完成 if "answer" in action: return action["answer"] # 防御性处理:避免死循环 messages.append({ "role": "user", "content": "你的输出格式不正确,请严格按照 JSON 格式输出。" }) return "超过最大执行步数,任务未完成。"这里使用了纯requests实现,是为了让读者看清 Agent 循环的本质。实际生产中,你可以改用 LangChain 的AgentExecutor,或者 Hugging Face 的smolagents,但核心的循环逻辑是共通的。
4.5 编写入口并运行
创建main.py:
# 文件路径:agent-demo/main.py from agent import run_agent if __name__ == "__main__": request = "请分析最近60分钟内错误日志的高频异常,给出TOP5错误消息,并简要说明可能的原因。" report = run_agent(request) print("==== 分析报告 ====") print(report)运行:
python main.py4.6 预期结果说明
如果 ES 中有符合条件的错误日志,且 LLM API 配置正确,你会看到类似下面的输出:
==== 分析报告 ==== 最近60分钟内共发现以下高频异常: 1. Connection timed out (发生 328 次):主要集中在下游服务调用超时, 建议检查依赖服务的负载情况。 2. NullPointerException at OrderServiceImpl (发生 156 次): 可能原因是订单号为空,建议检查入参校验逻辑。 3. ...需要说明的是,最终报告的质量取决于两点:ES 索引中的日志质量,以及大模型的推理能力。如果日志中没有log.level=ERROR字段,或者 message 字段没有 keyword 子字段,查询结果会为空,Agent 也就无从分析。
5. 从 Python Demo 到工程化落地
5.1 引入 Agent 框架的取舍
上面的 Demo 足够演示原理,但离生产可用还有一段距离。生产级的 AI Agent 通常需要以下能力:
- 更稳定的结构化输出。可以用 Pydantic 等库约束 LLM 输出格式,避免 JSON 解析失败。
- 完善的工具注册机制。每个工具都应该有名称、描述、参数 schema,让 LLM 能更准确地选择工具。
- 多轮记忆管理。在长任务中,Agent 需要记住之前步骤的结果,必要时还需要“反思”和“修正”。
- 可观测性。每一步的决策、工具调用参数、返回结果都应该有日志,方便排查。
这也是 LangChain、LlamaIndex、smolagents 等框架存在的意义。它们把“工具注册、Agent 循环、记忆管理”这些通用能力封装好,让你更专注于业务工具本身。
5.2 Java 技术栈下的 Agent 落地
不少 CSDN 读者是 Java 后端,可能会问:Java 生态怎么做 AI Agent?
目前可行的方案有三种:
第一种,在 Java 服务中集成 Spring AI 或 LangChain4j。这类框架提供了类似ToolCalling的能力,可以用注解方式注册工具方法,适合已有 Spring Boot 体系的项目。
第二种,把 Agent 作为独立服务部署。团队用 Python 实现 Agent 服务,对外暴露 REST API,Java 主服务通过 HTTP 调用。这种方案的优点是技术边界清晰,Python 生态在处理 AI 任务时更灵活。
第三种,不引入 Agent 框架,直接在 Java 代码中用RestTemplate或WebClient调 LLM API,自己解析 tool call,实现类似 ReAct 逻辑。适合对依赖包数量敏感、需要深度定制团队。
从实际项目经验来看,第二种方案最容易被团队接受。它不需要把 Agent 塞进现有的 Java 业务链路,而是作为一个独立的“智能分析服务”,和现有的微服务体系并存。
5.3 AI Coding Agent 对开发方式的影响
前面讨论的是“用 Agent 实现业务功能”,还有一种常见形态是 AI Coding Agent,也就是辅助写代码的智能编程工具。2026 年的开发趋势预测中,AI Coding Agent 已经从“自动补全”进化到“多文件级代码生成与重构”。它能理解整个项目的结构,自动修改多个文件、执行测试、修复编译错误。
但这里要提醒一点:AI Coding Agent 生成的代码依然需要人工评审。尤其是在权限、安全、资金交易等领域,必须建立“AI 生成,人工审查”的流程,不能盲目相信模型输出。
6. 常见问题与排查思路
在实际开发 AI Agent 的过程中,最容易遇到以下几类问题。
6.1 Agent 不调用工具,而是直接编答案
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| Agent 把 ES 结果编造出来,没有实际调用工具 | 系统提示词约束不够强,或模型版本不具备 tool calling 能力 | 在提示词中明确强调“必须调用工具后才能回答”;升级模型或改用原生 tool calling 接口 |
这是最常见的问题。解决办法是两步:
- 在系统提示词中写明“没有工具结果,不得生成分析结论”。
- 在代码层面做校验:如果 Agent 没调用工具就直接回答,则拦截并重新引导。
6.2 ES 查询返回空结果
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 聚合 buckets 为空 | 索引名不匹配;字段名错误;时间字段格式不对;没有 ERROR 级别日志 | 先用 Kibana 或 curl 手工验证 DSL,再接入 Agent |
排查步骤:
# 先确认索引是否存在 curl -X GET "http://localhost:9200/_cat/indices/app-logs-*?v" # 再手工执行一次查询,确认字段和结果 curl -X POST "http://localhost:9200/app-logs-*/_search?pretty" \ -H "Content-Type: application/json" \ -d '{"size": 1, "query": {"match_all": {}}}'6.3 LLM API 返回超时或限流
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 请求耗时过长或报 429 | 模型负载高、循环次数多、单次请求上下文过长 | 增加超时时间;控制 Agent 最大步数;压缩工具返回结果的长度 |
在 Agent 循环中,每次都会把工具结果拼进上下文,如果工具返回几万行日志,会迅速撑爆上下文窗口。工程上要在工具层做截断:只返回 TOP N 聚合结果,而不是原始日志。
6.4 Agent 陷入死循环
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| Agent 反复调用同一工具,结果一样但不结束 | 缺少终止条件;LLM 没有从工具结果中获得足够信息 | 设置 MAX_STEPS 上限;在提示词中明确“如果工具结果不足以回答,请基于已有信息回答或明确报告缺失信息” |
7. 最佳实践与工程建议
7.1 设计工具时遵循最小可用原则
Agent 的工具不是越多越好。每个工具都会增加 LLM 的选择成本,也增加了误调用的概率。建议:
- 每个工具只做一件事,函数名和描述要清楚。
- 工具的参数尽量少,且要有默认值。
- 工具返回结果要做摘要和截断,只保留对决策有用的信息。
7.2 建立“人工审核”的安全边界
AI Agent 可以调用 API、操作数据库、执行命令。权限越大,风险越大。这里有几条红线必须遵守:
- 工具层默认只提供只读操作,写操作必须显式开启二次确认。
- 涉及数据库更新、删除操作的工具,必须要求传入审批令牌或走独立审批流程。
- 生产环境中,Agent 服务的 API Key 必须单独管理,遵循最小权限原则,不能使用管理员账户。
- 所有 Agent 调用记录都要留痕,方便事后审计。
7.3 日志与观测是 Agent 项目的生命线
Agent 是“多步骤、非确定性”的程序,排查难度远高于普通代码。因此从第一行代码开始就要考虑观测:
import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") def run_agent_with_logging(user_request: str) -> str: logging.info("收到用户请求: %s", user_request) # ... 在每一步 add logging ...建议在以下位置打日志:
- LLM 返回的原始内容。
- 解析出的工具名和参数。
- 工具执行耗时和结果摘要。
- Agent 最终输出。
7.4 从简单场景做起,先跑通再扩展
很多团队第一次引入 Agent 就希望做成“万能助手”,这往往会导致失败。我的建议是:
- 先选一个边界清晰、工具稳定的场景。比如“日志错误分析”就非常适合,因为 ES 查询是可预期的,结果可控。
- 跑通后再增加场景,比如“慢查询分析”“告警根因推荐”。
- 将公共能力抽象为通用工具层,逐步形成团队内部的 Agent 工具库。
8. 总结与学习路线
从古法编程到 AI Agent 开发的跃迁,并不是从此不再写代码,而是把写代码的重心从“如何实现每一步”转向“如何定义目标、工具和边界”。传统编程方式仍然重要,它是你理解系统、设计架构、评估 Agent 输出质量的基础。AI Agent 则是一种更高层的抽象,它让机器承担更多执行细节。
如果你想系统地学习 AI Agent 开发,可以参考这条路线:
- 掌握大模型基础概念,理解提示词、上下文、温度等参数的作用。
- 用纯 Python 手写一个 ReAct 循环,如本文的日志分析 Demo,理解 Agent 的本质。
- 学习主流 Agent 框架,对比它们的工具注册、记忆管理和编排方式差异。
- 关注 Hugging Face 等社区发布的 Agent 术语和开源项目,了解业界的最新进展。
- 选择一个真实业务场景,从只读分析类工具入手,逐步增加能力。
最后给一个实际的建议:不要盲目追新框架。Agent 领域变化很快,今天热门的框架下个月可能就换了维护团队。把精力放在理解“规划-工具-记忆-反思”这条底层链路上,框架只是实现细节。当你有了稳定的底层认知,任何新框架对你来说都只是换一层皮而已。
如果本文对你有帮助,可以收藏备用。动手把日志分析 Demo 跑通一次,相信你会对 AI Agent 的完整架构有更直观的理解。