【AI】Agent 全栈进阶|Agent 工程化与兜底

简介: Agent开发中,LLM动态决策易致死循环、误调用、权限越界三大故障。通过设置最大步数、工具分级与参数校验、人工确认等四道防线,可有效兜底。实战“加盟助手”演示规避风险,保障Agent稳定运行

200x200

  ◆ 博主名称: QuZhengRong

  AI俘虏,样式苦手

⭐️ LuckReport专栏LuckReport

⭐️ SpringBoot专栏SpringBoot

⭐️ SpringCloud专栏SpringCloud


目录

91ed469e26db98fc1c49f9908a198cf7.jpg

上一篇讲完了 记忆 机制,Agent 该有的要素差不多齐了:对话、调工具、 RAG 、规划任务、管理记忆。但 Agent 项目除了要具备完整的功能外,我们还需要保障它能够稳定可靠地运行。

实际做过 Agent 开发的人应该都见过类似的问题:任务突然卡住了,过了十几分钟任务推进 0 % ;模型一直重复说胡话,陷入死循环。任务没做完,Agent 却回复完成了。

Agent 的价值在于每一步都能自己拿主意,但风险也同样来源于此。由于 LLM 自带的黑盒特性,它出问题的时候我们往往很难排查出原因。

这一篇要讲的就是 Agent 工程化与兜底:如何应对生产环境的三大典型故障。

一、Agent 翻车

传统程序的执行路径是固定的。比如一个请假申请的后台流程:员工发起请假申请 → 系统校验剩余假期额度 → 推送待办至直属上级审批 → 超长假期触发二级领导审批 → HR 备案归档,审批结果回传给申请人。每一步都在代码里,出了问题能直接定位。

Agent 的步骤是动态规划的,它根据中间结果决定下一步,思考的同时也增加了犯错的概率。

实际开发过程中,我碰到的翻车情况有以下几种:

1、死循环

表现:反复调用同一个工具,或者在几个工具之间来回横跳。

原因其实很简单:LLM 不知道什么时候该停,于是一直尝试调工具,或者调用工具失败,然后反复重试。

解决方法:

1. 设置最大步数,超出步数就强制收尾,程序层面不让它再调了
2. 工具返回结果里如果缺关键信息,直接提示模型向用户提问

2、误调用

表现:用户查询设备运行状态,Agent 调错了工具,查的是设备信息而非当前运行状态;或者工具名相近(get_status / query_status / search_status),模型分不清该用哪个。

原因:工具边界模糊,读写没分开;工具命名风格不统一;参数 Schema 太宽泛,区分度不够。

解决方法:

1. 查询类和执行类工具物理分开,各干各的
2. 参数加校验,格式不对直接抛出异常
3. 收紧参数 Schema 描述,添加错误调用案例

3、权限越界

表现:用户只是问某个配置的含义,Agent 直接去修改了生产配置;或者用户提了一句"帮我分析这个",它理解为执行修改操作而不是只读查询。

原因:工具权限太大,模型认为用户说"帮我处理"就是授权执行,系统 Prompt 里写的规则不一定完全遵循。

解决方法:

1. 高风险动作单独拆出来,提交类工具必须要用户确认
2. 根据账号权限限制工具调用,只允许调用自己权限范围内的工具

二、实战:加盟助手

下面对三个工具按风险分了级,增加了四道防线,跑两轮演示看效果。

from dotenv import load_dotenv
import os
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage, ToolMessage

load_dotenv()

llm = ChatOpenAI(
    model="qwen-plus",
    api_key=os.getenv("API_KEY"),
    base_url=os.getenv("BASE_URL")
)

# 三个工具按风险分了级:只读查询 / 生成草稿 / 正式提交
@tool
def check_franchise_info(brand: str) -> str:
    """查询指定加盟品牌的信息,只读操作。brand 为品牌全名。"""
    brands = {
   
        "哪吒仙饮": "加盟费 8 万,要求店面面积 ≥ 80 平、日均客流 ≥ 150 人,总部提供装修和培训支持,回本周期预估 14 个月",
        "旺客炸鸡": "加盟费 5 万,要求店面面积 ≥ 50 平、日均客流 ≥ 200 人,总部提供设备和原料统一配送,回本周期预估 10 个月",
    }
    if brand not in brands:
        return "查询失败:暂未收录这个品牌的加盟信息。hint:请向粉丝确认品牌全名,不要猜。"
    return f"{brand} 加盟信息:{brands[brand]}"

@tool
def draft_franchise_plan(brand: str, budget: str) -> str:
    """生成加盟方案草稿,只生成文本不提交。brand 为品牌全名,budget 为粉丝预算。"""
    return f"【加盟方案草稿】品牌:{brand};预算:{budget};状态:草稿,未提交。"

@tool
def submit_franchise_application(brand: str, budget: str) -> str:
    """正式提交加盟申请。高危操作,必须在粉丝明确确认后才能调用。"""
    return f"加盟申请已提交:{brand},预算:{budget}。"

tools = [check_franchise_info, draft_franchise_plan, submit_franchise_application]
tool_map = {
   t.name: t for t in tools}
llm_with_tools = llm.bind_tools(tools)

SYSTEM_PROMPT = """你是抖音"勇哥餐饮创业说"勇哥的助手,帮粉丝做加盟咨询。

工作规矩:
1. 先查品牌加盟信息再下结论,查不到就问粉丝,禁止猜品牌名
2. 粉丝没明确说"确认提交"之前,绝对不调用 submit_franchise_application,只能先生成方案草稿给粉丝看
3. 同一个工具同样的参数调用失败过,不要原样重试,换思路或者问粉丝"""

# 四道防线
MAX_STEPS = 8                              # 防线一:最大步数,防死循环
BRAND_WHITELIST = ["哪吒仙饮", "旺客炸鸡"]   # 防线二:品牌白名单,防模型瞎编参数
HUMAN_CONFIRMED = False                    # 防线三:粉丝还没确认提交,submit 会被程序拦截
failed_calls = set()                       # 防线四:失败调用记录,同工具同参数不再重试

def guard_check(call: dict):
    """执行前的守门检查,返回 None 表示放行,返回字符串表示拦截原因。

    Args:
        call: 模型产出的工具调用(含 name 和 args 两个键)

    Returns:
        拦截原因文本;None 表示放行
    """
    # 高危动作必须人工确认
    if call["name"] == "submit_franchise_application" and not HUMAN_CONFIRMED:
        return "已被系统拦截:加盟申请属于高危操作,需粉丝明确确认。请先把方案草稿给粉丝看,等确认后再提交。"

    # 品牌名不在白名单,说明模型在瞎编
    brand = call["args"].get("brand", "")
    if brand and brand not in BRAND_WHITELIST:
        return f"已被系统拦截:品牌「{brand}」暂未收录,请向粉丝确认品牌全名。"

    # 同工具同参数已经失败过
    key = (call["name"], tuple(sorted(call["args"].items())))
    if key in failed_calls:
        return "已被系统拦截:这个调用刚才失败过,换个思路或直接问粉丝。"
    return None

def run_guarded_agent(user_input: str) -> str:
    """运行带防线的加盟助手,每次工具调用前都过守门检查。

    Args:
        user_input: 粉丝的咨询内容

    Returns:
        最终回答文本
    """
    messages = [SystemMessage(content=SYSTEM_PROMPT), HumanMessage(content=user_input)]

    for step in range(1, MAX_STEPS + 1):
        response = llm_with_tools.invoke(messages)
        messages.append(response)

        if not response.tool_calls:
            print(f"\n[最终回答]\n{response.content}")
            return response.content

        for call in response.tool_calls:
            blocked = guard_check(call)
            if blocked:
                print(f"[拦截] {call['name']}({call['args']}) -> {blocked}")
                messages.append(ToolMessage(content=blocked, tool_call_id=call["id"]))
                continue

            print(f"[执行] {call['name']}({call['args']})")
            result = tool_map[call["name"]].invoke(call["args"])
            if "失败" in str(result):
                failed_calls.add((call["name"], tuple(sorted(call["args"].items()))))
            print(f"[结果] {result}")
            messages.append(ToolMessage(content=str(result), tool_call_id=call["id"]))

    print("达到最大步数,强制结束。")
    return "达到最大步数,强制结束。"

if __name__ == "__main__":
    print("=== 第一幕:粉丝还没确认 ===")
    run_guarded_agent("勇哥,我想加盟哪吒仙饮,手上大概有 12 万,能帮我分析下吗?合适的话直接帮我提交申请。")

    HUMAN_CONFIRMED = True
    print("\n=== 第二幕:粉丝已确认 ===")
    run_guarded_agent("我确认了。品牌哪吒仙饮,预算 12 万,帮我提交加盟申请吧。")

实际运行轨迹如下(不同模型版本细节会有差异,重点看第一轮里模型想直接调 submit 的时候被拦下的那一行):

=== 第一幕:粉丝还没确认 ===
[执行] check_franchise_info(brand='哪吒仙饮')
[结果] 哪吒仙饮 加盟信息:加盟费 8 万,要求店面面积 ≥ 80 平、日均客流 ≥ 150 人,总部提供装修和培训支持,回本周期预估 14 个月
[执行] draft_franchise_plan(brand='哪吒仙饮', budget='12 万')
[结果] 【加盟方案草稿】品牌:哪吒仙饮;预算:12 万;状态:草稿,未提交。
[拦截] submit_franchise_application(brand='哪吒仙饮', budget='12 万') -> 已被系统拦截:加盟申请属于高危操作,需粉丝明确确认。请先把方案草稿给粉丝看,等确认后再提交。

[最终回答]
哪吒仙饮加盟费 8 万,要求店面 80 平以上、日均客流 150 人,你的 12 万预算应该够。我拟了一份加盟方案草稿……你确认要提交吗?确认了我就帮你交。

=== 第二幕:粉丝已确认 ===
[执行] submit_franchise_application(brand='哪吒仙饮', budget='12 万')
[结果] 加盟申请已提交:哪吒仙饮,预算:12 万。

[最终回答]
加盟申请已经帮你提交了:哪吒仙饮,预算 12 万。接下来等品牌方联系你,按流程走就行……

第一轮里模型确实尝试调用了 submit,被 guard_check 拦下来。拦截原因作为 ToolMessage 写入对话,模型自己调整了策略,改成输出草稿加请求确认。第二轮粉丝确认后 HUMAN_CONFIRMED 被置为 True,submit 才被放行。

这里可以看出模型自己能调整策略,但前提是程序必须兜底做好拦截。

三、生产环境如何定位问题

Agent 的一轮对话背后,往往包含多轮 大模型 调用以及多次工具执行,要排查和追踪整条任务链路,就必须引入链路追踪机制,完整记录每一步的输入、输出以及耗时,示例如下:

[trace_id=run-88] step=1 model_call 耗时 1.2s 输出: 调用 check_franchise_info
[trace_id=run-88] step=2 tool:check_franchise_info(哪吒仙饮) 耗时 0.1s 结果: 加盟费 8 万,回本 14 个月
[trace_id=run-88] step=3 model_call 耗时 0.9s 输出: 生成加盟方案草稿
[trace_id=run-88] step=4 guard:submit_franchise_application 拦截: 高危未确认

上面 demo 里那些 print 就是最朴素的 trace,整理成结构化日志后存起来,出问题了能回放完整链路。生产环境可以用 Langfuse、LangSmith 这类工具。

评估指标

改了一版 prompt 或换了个模型,效果到底是变好了还是变差了?没有评估集的话全凭感觉,不够规范。做法是先攒一批测试问题,每个问题写清楚验收标准(比如粉丝说"合适的话直接帮我提交",验收标准是不能直接提交申请,必须先生成草稿),改完就跑一遍,看任务完成率、平均步数、单次成本这些指标。开放性任务可以用大模型打分,再辅以人工抽检。

四、LuckReport 项目推荐

在这里插入图片描述

导航:LuckReport专栏

1、项目简介

Luck-Report 是一款基于开源项目 UReport2 重构的 Java 高性能报表引擎,通过迭代单元格可以实现任意复杂的中国式报表。相较于 UReport2,Luck-Report 在技术架构上进行了全新升级,后端基于 SpringBoot 框架开发、前端采用 Vue 框架构建,技术选型贴合当下主流项目开发标准,可精准适配各类实际开发需求。

Luck-Report 提供了全新的基于网页的报表设计器,可以在 Chrome、Firefox、Edge 等各种主流浏览器运行(IE 浏览器除外)。使用 Luck-Report,打开浏览器即可完成各种复杂报表的设计制作。

Luck-Report 基于 Apache-2.0 开源协议 开源

2、在线体验

相关文章
|
20天前
|
人工智能 缓存 前端开发
DeepSeek Harness 首发实测 + 入门教程,夯爆了!梁神我错了
DeepSeek Harness + DeepSeek V4 Pro 项目实战保姆级教程!手把手带你从零安装开源 AI 编程工具,开发架构图、知识讲解网站、3D 网页游戏、全栈 AI 应用 4 个项目,覆盖运行模式选择、插件安装与开发,看看能不能对标 Claude。
13231 90
DeepSeek Harness 首发实测 + 入门教程,夯爆了!梁神我错了
|
8天前
|
人工智能 自然语言处理 安全
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
本文聚焦阿里云2026年推出的三款自研AI办公产品,清晰拆解千问办公、Qoder Teams、Qoder CN的差异化定位与能力边界:千问办公主打职场全场景提效,支持自然语言指令一键完成PPT生成、数据分析等高频办公任务;Qoder Teams面向程序员团队,深度整合AI代码生成、团队协同与企业知识库能力;Qoder CN则专为金融、政务等强合规场景打造,实现数据不出境与VPC私有化部署。文章同步给出分场景选型指南与最新活动定价,帮助不同类型的企业按需组合产品,实现业务岗、研发岗与强合规场景的AI能力全覆盖。
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
|
3天前
|
缓存 人工智能 API
阿里云Qwen3.8‑Flash完整能力解析:模型特性、API调用实操与计费规则深度拆解
在AI应用快速落地的当下,开发者与企业选型大模型API,不再只单纯关注评测榜单分数,推理速度、上下文长度、多模态能力、工具调用稳定性以及实际调用成本,共同决定项目能否平稳上线。Qwen3.8‑Flash作为新一代多模态混合专家模型,主打高性能推理与低成本开销,面向编程开发、智能Agent工作流、超长文档解析、图文混合理解等高频场景,提供托管API服务,权重同时开放可供本地部署,兼容主流接口协议,能够无缝接入各类开发工具链。很多开发者在接入过程中,容易混淆普通按量Token计费、缓存计费、各类订阅计划之间的差异,造成实际账单超出预估。本文从模型底层架构、核心功能能力、适用场景、API调用实操、完
801 0
|
13天前
|
Web App开发 人工智能 API
16 个超火的 DeepSeek Harness 插件,大肥鱼已经落后 N 个版本了。。。
DeepSeek Harness 精选插件推荐合集,从图片识别、浏览器操控、多 Agent 协作到手机远程控制,一口气带你看完 DSH 社区热门的十几个插件,覆盖技能扩展、UI 界面增强、整活玩法三大类,让你的鲸鱼变得更强。
1792 4
|
14天前
|
人工智能 Java BI
【AI】DeepSeek Harness 安装、运行、管理插件
本文介绍了如何运行DeepSeek开源的Agent框架DeepSeek Harness(dsh)。主要内容包括:使用nvm安装适配的Node版本;通过代理加速克隆GitHub源码;使用pnpm安装依赖并启动项目;配置DeepSeek API Token;安装扩展功能的插件。该框架自带Web界面,支持模型适配、文件编辑等插件化功能
1969 1
|
人工智能 JavaScript 开发工具
DeepSeek Harness 本地安装与使用指南
DeepSeek Harness(DSH)是DeepSeek AI开源的Agent运行框架,支持本地文件操作、命令执行与工具调用。基于Cordis插件架构,具备高扩展性与强可控性,适合开发者搭建可控Agent环境或开展模型基准测试。当前为开发者预览版,需Node.js环境,推荐先用`npx @deepseek-ai/dsh web`快速体验。
5230 0
|
9天前
|
人工智能 Linux iOS开发
Ollama使用教程:Ollama官网下载、Ollama本地部署大模型(2026最新)
Ollama 是一款免费开源的本地大模型运行工具,支持在 Windows/macOS/Linux 上离线运行 Qwen、DeepSeek、Llama 等主流开源模型,数据不出本机、隐私安全。提供 OpenAI 兼容 API,命令行一键拉取/运行/管理模型,无需联网,无调用限制,是开发者与 AI 爱好者部署本地 AI 助手的理想选择。(239 字)
|
16天前
|
人工智能 JavaScript 测试技术
保姆级教程:DeepSeek Harness从安装到跑通测试,30分钟上手
DeepSeek Harness是DeepSeek开源的AI Agent运行时,主打“一行命令安装、5分钟跑通”。它让模型真正动手干活——读代码、跑测试、分析失败、生成修复方案。本文手把手教你30分钟从零上手,覆盖安装、配置、实测及避坑指南,助你快速掌握下一代AI编程范式。
|
6天前
|
人工智能 监控 测试技术
Qwen3.8-Flash 来了,100万上下文、Agent、Coding 都加强了
8月26日,通义千问发布Qwen3.8-Flash-Next:125B参数、每Token仅激活6B,原生支持26万Token、可扩展至100万上下文;Coding、Agent与工具调用能力显著增强,面向真实软件工程任务,推动大模型从“回答问题”迈向“完成工作”。

热门文章

最新文章