聊《Agent 核心原理:从概念到可交付结果》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。
摘要
本文概述文章目标、核心观点和实践价值。
分类:AI Agent | 账号:Java技术那些事
摘要:很多团队把 Agent 当成“调参玩具”,一推上生产环境就频繁超时或状态错乱。这篇不堆砌框架名词,直接拆解规划、工具、记忆和容错四个底层模块。结合我上个月在订单履约链路里因为 Agent 越权调用导致数据不一致的真实排查过程,重点讲清楚怎么设计监控指标、怎么做事务回滚,以及普通开发者该怎么把这部分工程经验写进简历。
目录
目录
- Agent 的本质
- 规划能力
- 工具调用
- 记忆系统
- 失败恢复
- 总结
Agent 的本质

别被“自主智能”这种词带偏。剥开提示工程和框架包装,Agent 就是一个带状态的循环决策器:接收输入 → 评估上下文 → 决定下一步动作 → 执行并更新状态 → 重复。传统微服务是确定性的路由,Agent 处理的是概率性的意图。这意味着它天生会犯错、会卡死、会生成不符合预期的中间态。
我在排查一起工单流转异常时看到,Agent 连续重试了 7 次同一个查询接口,因为大模型把一次短暂的网关 502 误判成了“用户需要补充材料”。如果把它当普通函数调,加个重试队列就能解决;但它是 Agent,重试逻辑本身也是 LLM 生成的,结果陷入自增强的死循环。所以做 Agent 架构的第一步,是承认它的非确定性,并在外围包一层确定性的控制面。不要指望 Prompt 能兜底所有边界情况,那只是成本最高的调试手段。
规划能力

规划不是把任务拆成固定步骤写死,而是动态的路径选择。早期项目喜欢用静态 Chain-of-Thought,流程写得像流水线。实际跑起来才发现,业务场景的分支比预期多得多。比如一个客服 Agent,原本规划了“识别意图→查知识库→生成回复”三步,结果遇到投诉类请求时,知识库返回了冲突条款,这时候硬走第三步只会输出矛盾内容。
我的做法是引入轻量级的 RePlan 机制:每完成一步,先让 LLM 用结构化字段输出当前进度和置信度。置信度低于阈值(比如 0.6),或者工具返回了异常码,就触发重新规划。这里有个明显的取舍:重规划会增加延迟和 Token 消耗,但在复杂场景里,这比让用户反复重试或人工介入要划算得多。面试或写项目文档时,别只说“用了 ReAct”,明确写出你的判定阈值、重规划触发条件和对应的性能损耗数据,这才是能过技术面筛子的细节。

工具调用
工具是 Agent 的手脚,也是线上最容易爆雷的地方。很多人以为只要写好 JSON Schema 就安全了,实际上 LLM 经常会在边缘 case 下塞入非法字符、遗漏必填字段,甚至直接拼接未经转义的用户输入。工具层必须独立于 Prompt 之外,做成强类型适配器。
线上排过一次险:Agent 接到“帮我查一下上周的销量”指令,直接拼了个 SQL 丢给数据库。幸好我们的工具层做了严格校验和只读权限隔离,否则直接就是事故。工具调用的监控不能只看成功率,还要追踪参数分布、调用频次和单次耗时。下面是一个我们实际在用的工具封装示例,重点看校验和异常透传部分:
from typing import Literal
import re
from fastapi import HTTPException
class ToolAdapter:
@staticmethod
def query_inventory(product_sku: str, warehouse_code: str):
# 强校验前置拦截
if not re.fullmatch(r"[A-Z]{2,4}-\d{4,8}", product_sku):
raise ValueError(f"SKU 格式错误: {product_sku}")
if warehouse_code not in ALLOWED_WAREHOUSES:
raise PermissionError(f"无权访问仓库: {warehouse_code}")
try:
result = db.query_inventory(sku=product_sku, wh=warehouse_code)
return {"stock": result.stock, "status": "available"}
except Exception as e:
# 统一转为 Agent 可读的错误结构,避免 LLM 猜测
raise HTTPException(status_code=503, detail={
"error_type": "SERVICE_UNAVAILABLE",
"raw_message": str(e)
})
这段代码看着简单,但把校验、鉴权和错误标准化做透了,Agent 后续的错误恢复才会顺畅。记住:工具的稳定性决定了 Agent 的天花板。
记忆系统
记忆本质上就是上下文窗口管理。长短期记忆混在一起是新手最常见的坑。短期记忆该放什么?最近三轮对话、工具返回的关键结果、用户明确声明的约束。长期记忆不该是什么?全部的历史聊天记录往向量库里一扔,检索出来又杂又慢。
我们当时切到了混合策略:Redis 存业务变量(用户 ID、当前阶段、已完成的工具清单),向量库只存经过清洗的业务知识片段和成功执行的案例模板。对话历史采用滑动窗口,超过 8 轮就做一次摘要压缩,保留实体和关键决策点,丢弃寒暄和冗余推理。这样做下来,单次请求的 Token 开销降了将近一半,且任务连续性没受影响。写简历时强调你做过“记忆分层与压缩策略”,比单纯写“接入了 LangChain Memory”有说服力得多,后者现在已经是框架默认行为,体现不出工程价值。
失败恢复
这是区分 Demo 和生产系统的分水岭。大模型会幻觉,网络会抖动,下游接口会限流。Agent 一旦走到脏数据或半提交状态,最忌讳的做法是让 LLM 自己“想办法补救”。LLM 没有事务概念,它不知道上一笔钱已经扣了,下一笔退款还没发起。
那次线上故障后,我们重构了容错链路,主要抓了三件事:
1. **可观测性埋点**:每个 Agent Turn 记录输入输出、Token 消耗、工具调用链和耗时。接入 OpenTelemetry,设置重试次数 > 2 或单步耗时 > 5s 的告警。
2. **熔断与降级**:对高风险工具(支付、库存扣减、权限变更)加断路器。连续失败两次直接切断,转交人工审核或 fallback 规则引擎。
3. **显式回滚日志**:所有产生副作用的操作必须记录 Before/After 快照。如果第 3 步失败,代码层面按逆序调用撤销方法,而不是让 LLM 生成一句“请忽略之前的操作”。
# 伪代码:显式回滚模式
async def execute_plan(plan_steps):
rollback_stack = []
try:
for step in plan_steps:
if step.requires_commit:
snapshot = take_snapshot(step.target_resource)
rollback_stack.append(snapshot)
await step.execute()
except AgentExecutionError as e:
logger.error(f"Plan failed at {step.name}, rolling back...")
for snap in reversed(rollback_stack):
await restore_state(snap)
raise # 向上抛出,由调度器决定重试或转人工
线上跑 Agent,监控面板上要有的不是“用户满意度”,而是:平均重试率、回滚触发频率、工具调用超时占比、人工接管数。这些指标能直接反映你设计的健壮程度。
总结
学 Agent 别一上来就追最新框架。先从确定性工作流写起,把边界条件测透,再慢慢引入 LLM 路由和动态规划。工具层做强校验,记忆层做清分,失败链路做显式回滚。这三样稳了,Agent 才敢往生产环境放。
对于想转方向或找项目的开发者,建议少做纯聊天型演示,多做带状态流转、带外部工具调用、带完整错误处理的端到端小系统。把监控日志、回滚逻辑和性能压测数据拍进 README,面试时直接带着架构图和排查记录去聊。Agent 不是魔法,它是工程能力的延伸。把不确定性关进确定的笼子里,才能拿到可交付的结果。
资料展示
下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。





如果你想看完整资料目录,可以在评论区留言「资料」;也欢迎告诉我你更关注AI大模型里的哪类内容。

1685

被折叠的 条评论
为什么被折叠?



