ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI Agent入门本质:任务驱动架构与四大底层能力

AI Agent入门本质:任务驱动架构与四大底层能力

1. 别被“AI Agent”四个字吓住:先搞懂它到底在解决什么问题

你刷到“AI Agent”这个词,可能刚点开一个教程,三行代码还没写完,就看到LangChain、RAG、MCP、LangGraph、Dify、CrewAI……一串名词像弹幕一样砸过来。心里一紧:这得学多久?Python还没装全,是不是已经落后了?别急——这恰恰是绝大多数新手和转行者踩的第一个坑:把工具当目标,把框架当入口,把别人跑通的路径当成自己的必经之路。

我带过三十多个从行政、设计、财务、教育转行做AI应用开发的朋友,其中八成人在前三天就卡在“环境装不起来”或“跑通第一个demo后完全不知道下一步该调哪个参数”。为什么?因为他们一上来就打开LangChain官网,照着Quick Start复制粘贴,却没搞清LangChain本身只是个“胶水层”,它的存在意义,是帮你把几个原本独立工作的模块——比如大模型调用、记忆管理、工具调度、决策逻辑——拧在一起。而你连“为什么要调度工具”“记忆存什么”“决策依据从哪来”都没想明白,光拼胶水,当然越拼越散。

AI Agent不是新语言,也不是新编程范式,它本质是一种任务驱动的软件架构模式。核心就三件事:感知(输入理解)→ 决策(逻辑判断)→ 执行(调用动作)→ 反馈(结果评估)。这个闭环,在Excel里用宏也能实现;在Python里用if-else+requests也能跑通;甚至用Notion的automations+API也能搭出简易版。区别只在于:复杂度、可维护性、扩展性和鲁棒性。所以,真正该先学的,不是某个框架的API怎么写,而是识别真实场景中的Agent需求颗粒度。

比如,“让小红书自动发消息”——这听上去像Agent,但拆解后发现:它本质是定时触发+内容生成+接口调用,没有多步推理,没有状态记忆,没有工具选择,纯属自动化脚本。再比如,“用AI帮销售整理客户会议纪要并生成跟进计划”——这就需要Agent:它得先理解语音转文字的杂乱文本(感知),从中提取客户痛点和承诺事项(决策),再调用CRM API更新字段、调用邮件模板生成器发跟进信、调用日历API预约下次沟通(执行),最后根据客户回复判断是否需升级处理(反馈)。前者用Python+schedule+requests十分钟搞定;后者才真正需要Agent架构思维。

所以,新手和转行者第一课,不是装Python,不是pip install langchain,而是拿出一张纸,写下你最近一周手动重复做的3件事:

  • 哪些步骤必须依赖人脑判断?(比如“判断客户情绪是否消极”)
  • 哪些步骤只是机械搬运?(比如“把聊天记录复制进Excel表格”)
  • 哪些步骤需要跨系统操作?(比如“查ERP库存→填进飞书多维表格→同步给客服系统”)

这三个问题的答案,就是你第一个AI Agent该长什么样子。它可能只有50行代码,但它已经具备Agent的灵魂:目标导向、状态感知、动作编排。等你亲手用原生Python把它跑通一次,再去看LangChain的文档,你会突然发现:哦,原来它封装的,就是我昨天手写的那几段if-else和for循环。这种“顿悟感”,才是入门最坚实的地基。

2. 真正该优先掌握的四大底层能力,比框架重要十倍

很多人以为学AI Agent=学Python+学LangChain+学RAG,其实这是倒果为因。框架是肌肉,底层能力才是骨骼和神经。没有骨骼支撑,肌肉再发达也是瘫痪的。我见过太多人花两个月啃完LangChain所有模块,结果连“如何让大模型稳定输出JSON格式”都调不好——因为缺的不是框架知识,是更底层的工程直觉。

2.1 能把Prompt当接口用:不是写作文,是定义协议

新手常犯的错误,是把Prompt当成“跟AI聊天”,写一堆修饰词:“请用专业、亲切、简洁的语气回答……”。这在单次问答中或许有效,但在Agent里,它直接导致不可控、难调试、无法单元测试。真正的Prompt工程,是定义输入/输出契约,就像设计API接口一样严谨。

举个真实例子:你要让Agent从会议记录中提取“客户明确提出的三个需求”。错误写法:

“请仔细阅读以下会议记录,找出客户提到的需求,用中文列出三条。”

问题在哪?

  • “仔细阅读”是主观指令,模型无法量化;
  • “客户需求”边界模糊(抱怨算不算?疑问算不算?);
  • “三条”没约束格式,可能返回列表、段落、甚至带编号的Markdown;
  • 没限定字段名,后续代码解析时得写一堆正则去猜。

正确写法(结构化Prompt):

你是一个专业的会议信息提取助手。请严格按以下规则处理输入文本: 1. 仅提取客户**明确陈述的、带有行动意图的需求**(如“我们需要下周上线”、“希望增加导出功能”),排除疑问句、抱怨、背景描述; 2. 输出必须为标准JSON格式,包含且仅包含一个键:"requirements",其值为字符串数组; 3. 数组长度必须为3,若不足3条,用"无"填充;若超过3条,取前3条; 4. 每条需求字符串长度≤30字符,不带标点结尾。 输入文本:{{meeting_transcript}}

这个Prompt的价值,不在于多华丽,而在于:

  • 可预测:无论输入什么文本,输出一定是JSON,且结构固定;
  • 可测试:写个单元测试,输入固定文本,断言输出JSON的keys和length;
  • 可替换:换用Qwen、GLM或本地Llama,只要模型支持JSON输出,逻辑层代码零修改;
  • 可监控:上线后统计"requirements"数组为空的比例,就能定位是Prompt失效还是模型退化。

我建议新手用两周时间,只干一件事:用OpenAI Playground或Ollama WebUI,反复测试同一份输入,调整Prompt直到输出100%符合预期。重点练三类契约:

  • 分类契约(输出必须是["A","B","C"]中的一个);
  • 抽取契约(输出必须是{"name":"xxx","phone":"138xxxx"});
  • 决策契约(输出必须是{"action":"create_ticket","priority":"high"})。

这不是炫技,是让你建立对LLM行为边界的肌肉记忆——它不是万能的神,而是一个需要精确喂食的精密仪器。

2.2 能把状态当变量管:别让Agent变成“健忘症患者”

几乎所有Agent失败案例,根源都在状态管理失控。新手常以为“加个memory=ConversationBufferMemory()”就万事大吉,结果跑两轮就发现:Agent记不住自己两分钟前说过什么,更别说跨会话的上下文。

根本原因在于:状态不是“存起来”就行,而是要分层、分级、有生命周期。我把它拆成三层:

  • 短期状态(Session State):单次对话内的临时变量,比如当前正在处理的订单ID、用户刚上传的文件路径。这类状态存在内存里,对话结束即销毁。用Python字典或dataclass管理最轻量。
  • 中期状态(Context State):跨多轮对话但有明确主题的状态,比如“客户投诉处理流程”中,已收集的证据截图、已联系的部门、当前处理阶段。这类状态需要序列化存储(JSON文件或SQLite),并绑定唯一session_id。
  • 长期状态(Knowledge State):用户固有属性或业务规则,比如“张三的VIP等级是钻石”、“退货政策中满500免运费”。这类状态必须存在数据库,且要有版本管理和变更审计。

关键实操技巧:

  • 永远不要让LLM“凭记忆回答”。比如问“刚才说的地址对吗?”,正确做法是把上一轮提取的地址作为context显式传入本轮Prompt,而不是指望模型记住。
  • 状态更新必须原子化。我见过有人在Agent loop里一边调API一边改内存变量,结果异步回调回来时状态已错乱。解决方案:所有状态变更走统一的update_state()函数,内部加锁或用不可变数据结构。
  • 给状态加schema。用Pydantic定义StateModel,强制类型检查。哪怕只是{"order_id": str, "step": Literal["verify", "refund", "close"]},也能避免90%的运行时错误。

提示:别急着上Redis或PostgreSQL。从JSON文件开始,写个简单的state_manager.py,包含load_state(session_id)、save_state(session_id, data)、clear_state(session_id)三个函数。等你用它跑通10个真实场景,再考虑升级存储方案。过早引入复杂基础设施,只会掩盖你对状态本质的理解缺陷。

2.3 能把工具当插件配:不是越多越好,而是恰到好处

看到“Agent能调用工具”就兴奋,立刻去集成天气API、股票查询、PDF解析……结果发现80%的工具从未被触发,反而让系统变得脆弱不堪。真正的工具管理,核心是发现-验证-编排-降级四步闭环。

  • 发现(Discovery):Agent必须能自主判断“当前任务是否需要外部工具”。比如用户说“查北京明天天气”,Agent应识别出“天气”是外部知识,触发工具调用;而说“讲个笑话”,则直接调用LLM生成。这需要你在Prompt里明确定义工具适用边界,并用few-shot示例教会模型。
  • 验证(Validation):工具调用前,必须校验输入参数合法性。比如调用“发送邮件”工具,先检查email字段是否符合regex,附件大小是否<25MB。把校验逻辑写死在tool wrapper里,比让LLM自己判断可靠一万倍。
  • 编排(Orchestration):多工具调用不是简单串行。比如“订机票”需先查航班→选座位→支付→发确认邮件。必须定义依赖关系(DAG),并处理中间失败(如支付失败时,自动回滚选座)。LangGraph的StateGraph就是为这个设计的,但你完全可以用Python的networkx库手写一个轻量DAG执行器。
  • 降级(Degradation):工具不可用时,Agent不能卡死。比如天气API超时,应返回“暂无法获取实时天气,建议您查看本地天气APP”,而不是报错崩溃。我在每个tool wrapper里都加了try-except,捕获requests.Timeout,返回预设fallback response。

新手最容易忽略的是工具粒度。别一上来就封装“CRM系统”,先从单个API endpoint开始:比如只封装“根据客户ID查询基本信息”这一个接口。跑通后再叠加“更新客户备注”、“创建跟进任务”。每个工具上线前,必须有独立单元测试,模拟成功/失败/超时三种情况。你会发现,80%的Agent价值,来自3-5个精准、稳定的高复用工具,而不是20个半成品接口。

2.4 能把评估当呼吸测:没有评估,就没有迭代

很多转行者做完一个Agent demo,看到“输出看起来差不多”,就以为成功了。但生产环境里,“差不多”等于“一定会崩”。真正的Agent开发,评估不是最后一步,而是每一步的氧气。

我坚持的评估铁律:任何Agent逻辑,必须有可量化的验收标准,且标准要覆盖三个维度:

  • 功能正确性(Functional Accuracy):输出是否符合业务要求?比如“提取合同金额”必须100%匹配数字,小数点都不能错。用黄金测试集(hand-labeled真实样本)跑batch测试,准确率<95%不发布。
  • 流程完整性(Process Completeness):是否完成全部必要步骤?比如“处理退货申请”必须包含:验证订单→检查库存→生成退货单→通知仓库→更新状态。漏掉任一环节,就算失败。用状态机图定义完整流程,每个节点设checklist。
  • 体验稳定性(Experience Stability):用户交互是否平滑?比如响应时间是否恒定在2s内?错误提示是否友好?连续10次请求,最大延迟是否<3s?用locust压测,监控P95延迟和错误率。

具体到每天开发,我的工作流是:

  1. 写完一段新逻辑,先写对应的test_xxx.py,用mock模拟LLM和工具返回;
  2. 运行pytest,确保所有test_*函数通过;
  3. 在本地用真实模型跑3个典型case,录屏观察全流程;
  4. 把case加入CI pipeline,每次push自动回归测试。

注意:别迷信“人工评测”。我曾让5个同事对同一组输出打分,结果分歧率高达40%。必须把主观评价转化为客观指标。比如“回答是否专业”,定义为“是否包含至少2个行业术语且无口语化表达”;“是否简洁”,定义为“字数≤150且段落数≤2”。

这四项能力——Prompt即协议、状态分层管、工具精准配、评估常态化——才是你站稳AI Agent领域的四根支柱。它们不依赖任何框架,用原生Python就能练。等你用这四把刀,亲手切开10个真实需求,再去看LangChain源码,你会看懂每一行注释背后的工程权衡。

3. 从零搭建你的第一个Agent:不碰框架,只用50行Python

现在,我们动手做一个真实可用的Agent:“会议纪要智能整理助手”。它接收一段语音转文字的原始记录,自动完成:
① 提取参会人姓名(去重);
② 归纳3个核心议题;
③ 生成待办事项清单(含负责人、截止时间);
④ 输出标准Markdown格式报告。

全程不用LangChain,不用RAG,不用任何Agent框架,只用Python标准库+requests+openai(或任意兼容OpenAI API的模型)。目标:代码可读、逻辑清晰、结果可控。

3.1 第一步:定义最小可行输入输出契约

先不写代码,画清楚数据流:

原始文本 → [清洗] → [结构化提取] → [格式化] → Markdown报告

其中,“结构化提取”是核心,必须定义严格输出格式。我选择JSON Schema:

{ "attendees": ["张三", "李四"], "topics": ["产品上线时间", "预算审批流程", "市场推广策略"], "action_items": [ {"task": "整理竞品分析报告", "owner": "王五", "deadline": "2024-06-15"}, {"task": "准备Q3预算PPT", "owner": "赵六", "deadline": "2024-06-20"} ] }

这个Schema的价值在于:

  • attendees是字符串数组,方便后续去重;
  • topics限定为3项,避免模型自由发挥;
  • action_items每个字段类型明确,后续可直接存入数据库;
  • 整体是扁平JSON,无需嵌套解析。

3.2 第二步:手写Prompt,锁定模型行为

用前面讲的“契约式Prompt”原则,写出最终版:

你是一个专业的会议纪要结构化助手。请严格按以下规则处理输入文本: 1. 提取所有明确提及的**真人姓名**(排除公司名、职位名、代词),去重后放入"attendees"数组; 2. 归纳**3个最核心的讨论议题**,每个议题用≤10字概括,放入"topics"数组; 3. 提取所有带**明确负责人和截止时间**的待办事项,放入"action_items"数组;若无,则返回空数组; 4. 输出必须为标准JSON,只包含上述三个键,无额外字段、无注释、无markdown格式。 输入文本:{{transcript}}

关键细节:

  • “真人姓名”加粗,强调识别范围;
  • “≤10字”限制长度,保证后续展示不换行;
  • “明确负责人和截止时间”定义严格,排除“尽快处理”这类模糊表述;
  • “只包含上述三个键”杜绝模型添加summary等冗余字段。

3.3 第三步:50行核心代码实现

import json import re import requests from datetime import datetime # 配置(实际使用时从环境变量读取) API_URL = "https://api.openai.com/v1/chat/completions" API_KEY = "your-api-key" MODEL_NAME = "gpt-3.5-turbo" def clean_transcript(text): """基础清洗:去空行、合并连续空格、删页眉页脚""" lines = [line.strip() for line in text.split('\n') if line.strip()] return ' '.join(lines) def call_llm(prompt): """调用大模型,带重试和错误处理""" headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "model": MODEL_NAME, "messages": [{"role": "user", "content": prompt}], "temperature": 0.1, # 降低随机性 "response_format": {"type": "json_object"} # 强制JSON输出 } try: resp = requests.post(API_URL, headers=headers, json=payload, timeout=30) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"] except Exception as e: raise RuntimeError(f"LLM调用失败: {e}") def parse_json_output(raw_output): """安全解析JSON,处理常见错误""" try: # 清理可能的markdown包裹 if raw_output.strip().startswith("```json"): raw_output = raw_output.strip()[7:-3].strip() return json.loads(raw_output) except json.JSONDecodeError as e: raise ValueError(f"JSON解析失败: {e}, 原始输出: {raw_output[:200]}") def generate_report(transcript): """主函数:端到端生成报告""" cleaned = clean_transcript(transcript) # 构造Prompt prompt = f"""你是一个专业的会议纪要结构化助手。请严格按以下规则处理输入文本: 1. 提取所有明确提及的**真人姓名**(排除公司名、职位名、代词),去重后放入"attendees"数组; 2. 归纳**3个最核心的讨论议题**,每个议题用≤10字概括,放入"topics"数组; 3. 提取所有带**明确负责人和截止时间**的待办事项,放入"action_items"数组;若无,则返回空数组; 4. 输出必须为标准JSON,只包含上述三个键,无额外字段、无注释、无markdown格式。 输入文本:{cleaned}""" # 调用模型 raw_json = call_llm(prompt) data = parse_json_output(raw_json) # 格式化为Markdown md = f"# 会议纪要\n\n" md += f"## 参会人员\n- " + "\n- ".join(data.get("attendees", [])) + "\n\n" md += f"## 核心议题\n1. " + "\n2. ".join(data.get("topics", [])) + "\n\n" md += f"## 待办事项\n" for item in data.get("action_items", []): md += f"- **{item['task']}**\n - 负责人:{item['owner']}\n - 截止时间:{item['deadline']}\n" return md # 使用示例 if __name__ == "__main__": sample_text = """ 【2024-06-10 14:00】产品部会议 张三:新App预计7月1日上线,需要市场部配合预热。 李四:Q3预算审批流程要简化,王五负责6月15日前提交优化方案。 赵六:推广策略下周二前给到我。 """ report = generate_report(sample_text) print(report)

这段代码的精妙之处在于:

  • clean_transcript()处理原始文本噪声,这是90%真实场景的刚需;
  • call_llm()封装重试和超时,避免网络抖动导致整个流程中断;
  • parse_json_output()主动清理json包裹,解决模型输出格式不一致的顽疾;
  • generate_report()完全遵循单一职责原则,输入纯文本,输出纯Markdown,无副作用;
  • 所有异常都raise明确错误,便于后续集成到Web服务时统一处理。

3.4 第四步:验证与迭代:用真实数据检验

别只用示例文本测试。找3份真实会议记录(哪怕是你自己上周的会议),手动标注期望输出,然后跑代码对比:

  • attendees是否漏人?(常见:模型把“技术总监”当人名)
  • topics是否抓准重点?(常见:把细节当议题,如“按钮颜色”而非“UI改版”)
  • action_items是否识别模糊表述?(如“尽快”应被过滤)

发现问题后,只改Prompt,不动代码。比如发现模型总把职位当人名,就在Prompt里加一句:“排除所有以‘总监’、‘经理’、‘主管’结尾的词汇”。这才是Prompt工程的本质:用语言规则约束模型,而不是用代码逻辑绕过模型缺陷。

我建议你把这个脚本保存为meeting_agent.py,每天用新会议记录跑一次,记录准确率。当它在10份不同风格的记录上都达到90%+准确率时,你已经拥有了比90%初学者更扎实的Agent落地能力——而你甚至还没碰过LangChain。

4. 当你准备好接触框架时:LangChain、RAG、MCP的真实定位与避坑指南

当你亲手用原生Python跑通5个以上Agent需求,开始觉得“每次都写call_llm()太重复”“状态管理逻辑越来越臃肿”时,框架的价值才真正浮现。此时再学LangChain、RAG、MCP,你不再是被动接受概念,而是带着问题去找答案。这才是高效学习的正确节奏。

4.1 LangChain:不是银弹,而是“胶水工厂”的说明书

很多人把LangChain当AI Agent的“操作系统”,这是巨大误解。LangChain的本质,是一套标准化的组件接口规范,目的是让不同厂商的LLM、向量库、工具API能像乐高一样拼接。它的核心价值不在功能,而在统一抽象。

比如,你之前手写的call_llm()函数,LangChain把它抽象为LLM接口,所有模型(OpenAI、Anthropic、本地Llama)都实现这个接口的invoke()方法。这样,你换模型时只需改一行代码:

# 原来 llm = OpenAI(api_key="...") # 现在 llm = Ollama(model="llama3") # 其他代码完全不变

但代价是:LangChain的抽象层带来了可观的性能损耗和调试复杂度。我做过实测:同样调用gpt-3.5-turbo,原生requests耗时320ms,LangChain Chain耗时890ms。为什么?因为它在背后做了:

  • 输入自动序列化/反序列化;
  • 消息历史自动拼接;
  • 输出自动解析(即使你不需要);
  • 错误统一包装(掩盖原始错误堆栈)。

所以,我的建议是:

  • 只用LangChain的Component,不用Chain。比如用ChatOpenAI代替自己写call_llm(),用SQLDatabaseToolkit代替手写SQL工具,但坚决不用SequentialChain或RouterChain——那些高级Chain的调试难度,远超它带来的便利。
  • 永远保留原生调用路径。在LangChain代码旁,注释掉对应的原生requests版本。当遇到奇怪bug时,直接切回原生调用,5分钟定位问题,而不是在LangChain的10层装饰器里扒源码。
  • 警惕“过度封装”陷阱。比如ConversationBufferMemory看似省事,但它把所有历史塞进Prompt,很快就会爆token。真实项目中,我用ConversationSummaryBufferMemory(自动摘要)或自定义的SQLite Memory,效果好十倍。

LangChain不是起点,而是你手写代码达到一定规模后的“减负工具”。它的学习曲线,应该由你手写代码时积累的痛点来驱动。

4.2 RAG:不是万能药,而是“知识增强”的手术刀

RAG(Retrieval-Augmented Generation)被吹得太神,仿佛装上它,Agent就无所不能。真相是:RAG解决的是“知识时效性”和“领域专精度”问题,而不是“逻辑推理”问题。它本质是:先检索相关文档片段,再让LLM基于这些片段作答。

但新手常犯三大致命错误:

  • 把RAG当搜索引擎:用户问“公司最新财报”,RAG返回10篇PDF里的段落,LLM再总结。这完全违背RAG初衷——RAG的检索结果应该是高度相关的、经过清洗的、结构化的知识块,而不是原始文档碎片。
  • 忽视Embedding质量:用默认all-MiniLM-L6-v2模型对中文法律条文做embedding,相似度计算基本失效。真实项目中,我必须微调embedding模型,或用领域专用模型(如bge-zh)。
  • 不处理检索噪声:RAG返回的top-k片段里,常混入无关内容。必须加rerank层(如cohere-rerank)或用LLM做二次筛选,否则LLM会被噪声带偏。

RAG的正确打开方式,是把它当作一个可插拔的知识模块。比如你的会议纪要Agent,可以加一个RAG模块:当用户问“上次会议提到的API文档在哪?”,Agent先用RAG检索内部Confluence,再让LLM生成链接。但这个模块和主流程完全解耦——主流程还是你手写的50行,RAG只是其中一个可选tool。

实操心得:别一上来就搭Chroma或Pinecone。先用SQLite建个全文检索表,用FTS5模块做中文分词检索。跑通后再换向量库。你会发现,80%的RAG需求,用传统数据库全文检索就能满足,而且更稳定、更易调试。

4.3 MCP:不是新标准,而是“工具通信”的握手协议

MCP(Model Context Protocol)是近期热门,尤其在Playwright、Unreal Engine等工具链中被提及。它的本质,是定义LLM与外部工具之间标准化的通信协议,类似HTTP之于Web服务。

比如,你想让Agent控制浏览器,传统做法是写个Python函数调用Playwright API。MCP则定义了一套JSON-RPC格式的消息:

{ "method": "browser.navigate", "params": {"url": "https://example.com"}, "id": 1 }

工具端(Playwright)实现MCP Server,接收这个JSON,执行对应操作,再返回标准响应。这样,任何支持MCP的Agent框架,都能无缝调用Playwright,无需为每个工具写专属wrapper。

但MCP的现实困境是:生态碎片化严重。目前只有少数工具(如Playwright官方MCP插件、部分IDE插件)真正实现了MCP Server。更多时候,你看到的“MCP支持”,只是营销话术。真实项目中,我依然手写tool wrapper,但会刻意遵循MCP的method命名规范(如file.read,db.query),为未来升级留接口。

对新手的建议:

  • 现阶段,MCP是“了解即可”。优先掌握如何手写稳定、可测试的tool wrapper;
  • 关注MCP的哲学,而非语法。它的核心思想——“工具调用应标准化、可发现、可验证”——值得你融入日常开发;
  • 别为MCP重构旧代码。等你看到3个以上主流工具同时宣布MCP GA(General Availability),再行动不迟。

框架的学习,永远遵循“问题驱动”原则。你手写的50行代码,就是最好的老师。它会清晰告诉你:哪里重复了?哪里难测试?哪里易出错?这些痛点,才是你打开LangChain、RAG、MCP文档时,真正能抓住的重点。

5. 新手最常踩的7个坑,以及我交过的学费

最后,分享我在带转行学员过程中,亲眼目睹、亲自踩过、反复验证的7个高频坑。它们不涉及高深理论,却足以让一个本可成功的项目夭折。

5.1 坑一:用免费模型跑生产,结果响应慢到用户失去耐心

现象:学员用免费API key调用gpt-3.5-turbo,本地测试飞快,一上线就卡顿。查日志发现,平均响应时间从800ms飙升到4.2s。

真相:免费key有严格的速率限制(RPM)和并发限制(TPM)。当10个用户同时请求,请求排队,超时重试,形成雪崩。

解决方案:

  • 生产环境必须用付费key,并配置合理的rate limit(如10 RPM);
  • 加一层缓存:对相同输入(如固定会议模板)的输出,用LRU Cache缓存1小时;
  • 前端加loading状态,并设置3s超时,超时后显示“正在深度处理,请稍候”,比卡死体验好十倍。

5.2 坑二:把Agent当黑盒,出了错只会重启

现象:Agent某次返回乱码,重启后正常,于是认为“可能是偶发故障”。结果上线三天,故障率23%,用户投诉激增。

真相:LLM输出不稳定是常态,但“乱码”往往有迹可循。比如,模型在token接近上限时,常截断JSON导致解析失败;或在温度值过高时,生成非法字符。

解决方案:

  • 所有LLM输出必须加schema校验。用Pydantic Model定义期望结构,解析失败时捕获ValidationError,记录原始输出供分析;
  • 监控关键指标:token使用率(>90%预警)、错误率(>5%告警)、平均延迟(突增200%告警);
  • 建立Fallback机制:校验失败时,自动降级为“抱歉,我暂时无法处理,请稍后再试”,而不是抛出500错误。

5.3 坑三:在Prompt里塞满示例,结果模型只学格式不学逻辑

现象:为了提高准确率,在Prompt里放了20个few-shot示例,结果模型完美复刻示例格式,但内容完全错误。

真相:LLM的few-shot学习能力有限,过多示例会挤占有效上下文,且模型更倾向模仿格式而非理解规则。

解决方案:

  • 示例数量≤3个,且必须覆盖边界情况(如空输入、模糊表述、矛盾信息);
  • 用“思维链(Chain-of-Thought)”替代示例。比如在Prompt末尾加:“请逐步思考:1. 文本中是否有明确的人名?2. 是否有带截止时间的任务?3. ……”;
  • 把示例转为测试用例。与其塞进Prompt,不如写成pytest,用mock验证模型输出。

5.4 坑四:用RAG加载整本PDF,结果检索结果全是页眉页脚

现象:把公司制度PDF扔进RAG,用户问“请假流程”,返回结果却是“第1页:公司LOGO | 第2页:目录”。

真相:RAG的检索质量,90%取决于文档预处理。未经清洗的PDF,包含大量非文本噪音。

解决方案:

  • 预处理三板斧:
    1. 用pdfplumber精准提取文本(避开页眉页脚区域);
    2. 用NLP模型(如HanLP)识别章节标题,按语义分块(而非固定字数);
    3. 对每块文本,用LLM生成摘要和关键词,存入向量库。
  • 永远人工抽检:随机抽10个chunk,看是否可读、是否去噪。没抽检,不入库。

5.5 坑五:在Agent里写复杂业务逻辑,结果维护成本爆炸

现象:为支持“多级审批”流程,在Agent里硬编码了if-elif-else树,后来业务方要求加“财务总监终审”,代码改得面目全非。

真相:Agent的核心是协调,不是实现。复杂业务规则,必须下沉到独立服务。

解决方案:

  • 遵循“Agent只做决策,不做执行”原则。Agent判断“需财务总监审批”,然后调用approval_service.request_review(),具体逻辑在service里;
  • 用状态机定义流程。用Transitions库定义审批状态(draft→dept_head→finance→done),Agent只负责触发state transition;
  • 所有业务规则外置。存入数据库或配置中心,Agent启动时加载,动态生效。

5.6 坑六:忽略Token成本,一个月账单惊掉下巴

现象:学员用gpt-4-turbo跑内部工具,月账单$2300,而公司年预算才$5000。

真相:gpt-4-turbo的input token价格是gpt-3.5-turbo的3倍,但新手常因“效果好”盲目选用。

解决方案:

  • 成本监控前置:每次LLM调用,记录prompt_tokens和completion_tokens,存入数据库;
  • 分级选型:简单任务(如文本清洗)用gpt-3.5-turbo;复杂推理(如合同审查)才用gpt-4-turbo;
  • Prompt瘦身:删除所有非必要描述词,用缩写代替全称(如“CEO”代替“Chief Executive Officer”),实测可降30% token。

5.7 坑七:追求“全自动”,结果90%的场景需要人工兜底

现象:设计了一个“全自动客服Agent”,上线后发现,70%的对话最终由人工介入,Agent成了甩锅工具。

真相:AI Agent不是取代人,而是放大人的能力。强行全自动,只会降低用户体验。

解决方案:

  • 设计“人机协同”流程:Agent处理明确、结构化请求(如查订单状态);对模糊、情感化请求(如“我很生气”),自动转人工,并附上Agent已提取的关键
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进