聊《同样是Agent,为什么有的能上线、有的只能演示?》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。
摘要
上周的需求评审会上,产品经理甩出一个需求:“我们要做一个能自动排查线上故障的 Agent。”
会议室里气氛很微妙。后端开发皱眉,因为这意味着 Agent 需要读日志、查监控甚至重启服务;前端开发沉默,因为如果 Agent 能修 Bug,他们的代码谁写?作为负责架构落地的我,心里清楚这不是技术能不能实现的问题,而是“权限与边界”的问题。
市面上那些炫酷的 AI 编程工具,从 Codex 到 Claude Code,确实让个人开发者体验到了“描述即交付”的快感。但一旦进入团队协作,尤其是生产环境,你会发现:一个只会“写代码”的 Agent 是灾难,一个懂得“调工具、记状态、懂规划”的 Agent 才是资产。
很多团队在做 Agent 项目时,容易陷入一种误区:以为把 LLM 接上 LangChain 就能解决所有问题。结果往往是 Demo 阶段跑得欢,一上生产就崩盘——要么乱改数据库,要么在死循环里消耗 Token,要么因为上下文太长而遗忘关键指令。
今天我不谈虚的概念,只复盘我们在构建内部运维助手时,关于工具调用(Function Calling)、记忆系统(Memory)和任务规划(Planning)这三个核心组件的真实踩坑经验与取舍逻辑。
目录
- Agent 的本质:不是聊天,是执行
- 规划能力:从线性链到动态图
- 工具调用:权限的边界在哪里?
- 记忆系统:短期是上下文,长期是知识库
- 失败恢复:给 Agent 留条后路
- 总结
Agent 的本质:不是聊天,是执行

首先得纠正一个观念:Agent 不是一个高级版的 Chatbot。Chatbot 的核心是“理解与生成”,而 Agent 的核心是“感知、决策与行动”。
在真实项目中,我们将 Agent 定义为:给定目标,通过调用外部工具,利用记忆辅助,自主完成一系列动作闭环的系统。
这里的关键在于“自主”。如果每一步都需要人工确认,那它只是自动化脚本;如果它能根据上一步的结果动态调整下一步动作,这才是 Agent。
但在落地时,我们面临的最大冲突是:灵活性与可控性的平衡。 给 Agent 太多自由,它会幻觉出根本不存在的 API;给太少,它又变回了僵硬的流程引擎。我们的解决方案是:将能力显式化,将约束结构化。
规划能力:从线性链到动态图

早期的 Agent 实现多采用 Chain(链式调用),比如:读取日志 -> 分析错误 -> 查询文档 -> 输出报告。这种结构简单直观,但在面对复杂场景时极其脆弱。一旦中间某一步失败(比如没查到相关文档),整个链条就会断裂。
在重构我们的故障排查 Agent 时,我们引入了基于 ReAct(Reasoning + Acting)模式的规划器。
关键在于,规划不再是预设的代码路径,而是由 LLM 实时生成的 JSON 指令序列。我们设计了一个简单的状态机,允许 Agent 在遇到未知错误时“回退”或“询问用户”,而不是直接抛出异常。
import json
class AgentPlanner:
def __init__(self, llm_client):
self.llm = llm_client
# 定义当前状态,用于追踪规划进度
self.state = {
"step": 0,
"history": [],
"conclusion": None
}
def plan_step(self, goal, current_context):
"""
生成下一步行动计划
这里不直接返回最终答案,而是返回一个待执行的工具列表
"""
prompt = f"""
Goal: {goal}
Context: {current_context}
Previous Steps: {json.dumps(self.state['history'])}
Analyze the current state. If the goal is met, return {{"action": "FINISH", "result": "..."}}.
Otherwise, return a list of tools to call next. Format:
{{
"action": "TOOL_CALL",
"tools": ["tool_name_1", "tool_name_2"]
}}
"""
response = self.llm.generate(prompt)
try:
return json.loads(response)
except json.JSONDecodeError:
return {"action": "ERROR", "error": "Invalid plan"}
def execute_and_update(self, action_result):
"""
执行结果反馈,更新记忆和历史
"""
self.state['history'].append(action_result)
if action_result.get("is_success"):
self.state['step'] += 1
取舍点: 不要试图让 LLM 一次性规划完所有步骤。让它“走一步看一步”不仅更符合人类逻辑,也能减少因长上下文导致的注意力分散。同时,必须设置最大迭代次数(Max Iterations),防止死循环。

工具调用:权限的边界在哪里?
工具调用(Function Calling)是 Agent 的手脚。但在团队协作中,手脚乱动是最危险的。
我们曾遇到过这样一个案例:一个测试 Agent 被赋予“查询数据库”和“重置测试数据”两个工具。在 Demo 中,它完美地完成了“清理脏数据”的任务。但在实际联调中,由于 Prompt 中的歧义,它误将生产环境的测试表当成了测试环境的数据,执行了 DELETE 操作。
这就是为什么我说,权限控制是 Agent 的生产线生命线。
在实现工具调用时,我们做了三层过滤:
1. 静态类型检查:LLM 输出的参数必须符合预定义的 Schema,否则直接拒绝执行,不让模型“猜”。
2. 动态权限隔离:不同的 Agent 角色拥有不同的 Tool Set。开发者的 Agent 可以“读代码”,但不能“写生产配置”;运维 Agent 可以“重启服务”,但必须经过二次确认(Human-in-the-loop)。
3. 沙箱执行:涉及文件修改或数据库操作的工具,必须在隔离环境中执行,并记录详细的审计日志。
{
"name": "execute_sql",
"description": "Execute a read-only SQL query on the staging database.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The SQL query string. MUST start with SELECT."
}
},
"required": ["query"]
},
"strict": true
}
注意上面的 strict: true 和描述中的限制。这不仅是技术实现,更是管理规范。在简历或项目复盘中,强调你如何设计这些“护栏”,比强调你调用了什么模型更有价值。
记忆系统:短期是上下文,长期是知识库
很多开发者抱怨 Agent “记不住事”。这是因为他们混淆了短期记忆和长期记忆。
- 短期记忆(Working Memory):就是当前的 Conversation History。随着对话变长,Token 成本激增,且容易出现“中间丢失”现象。
- 长期记忆(Long-Term Memory):存储在向量数据库或关系型数据库中,供 Agent 按需检索。
在我们的故障排查场景中,如果每次排查都重新加载所有历史日志,响应延迟会高得无法接受。因此,我们采用了分层记忆策略:
1. 滑动窗口:仅保留最近 N 轮对话作为短期输入。
2. 摘要压缩:当对话超过一定长度,调用 LLM 对之前的内容进行摘要,存入短期记忆的头部。
3. 持久化检索:将关键的技术参数、已知的 Bug 模式存入向量库。当 Agent 遇到类似问题时,先检索相关信息,再注入 Prompt。
这种做法的代价是增加了系统的复杂度,但换来的是准确性和成本的平衡。对于初创团队或小型项目,我建议先从“摘要压缩”做起,这是性价比最高的优化手段。
失败恢复:给 Agent 留条后路
这是最容易被忽视的一点。Demo 里一切顺利,是因为测试用例都是精心挑选的。生产中,网络会超时,API 会返回 404,LLM 会 hallucinate。
一个健壮的 Agent 必须具备自我修复能力。
我们在规划器中加入了一个 retry 机制。如果工具调用失败,Agent 不会立即报错终止,而是会将错误信息(Error Message)作为新的上下文,重新尝试规划。
例如,第一次调用 get_server_status 失败,Agent 可能会尝试换一种方式查询,或者询问用户是否手动检查服务器。
def handle_failure(self, error):
# 记录失败原因
self.state['history'].append({"type": "ERROR", "msg": str(error)})
# 触发重试或降级策略
if error.type == "TIMEOUT":
return {"action": "RETRY", "delay": 5}
elif error.type == "PERMISSION_DENIED":
return {"action": "ASK_USER", "question": "您没有权限访问该资源,是否联系管理员?"}
else:
return {"action": "HALT", "message": "不可恢复错误,已通知运维团队。"}
总结
回到开头的那场需求评审。
最终,我们没有答应产品经理“全自动排查”的需求,而是提出了一个折中方案:“半自动辅助诊断”。
Agent 负责拉取日志、初步分类、推荐可能的解决方案文档,但最终的操作确认权交给人类工程师。这个方案不仅上线顺利,还显著降低了初级工程师的学习成本。
这也印证了我的观点:优秀的 Agent 设计,不是在炫技,而是在管理不确定性。
- 工具调用要严守权限边界,防止“手脚乱动”。
- 任务规划要模块化、可回溯,防止“盲目狂奔”。
- 记忆系统要分层管理,防止“脑容量溢出”。
对于想要深入 Agent 开发的开发者来说,不要再沉迷于 Prompt 调优的技巧了。去研究一下如何设计更好的 Schema,如何构建鲁棒的错误处理流程,如何在团队协作中定义清晰的接口契约。这些才是区分“玩具项目”和“生产级应用”的真正鸿沟。
Agent 的下半场,不是比谁的模型更聪明,而是比谁的架构更稳健,谁的边界更清晰。
资料展示
下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。





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


922

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



