1. 这不是速成班,而是用“工程化切片”把AI Agent开发从玄学拉回地面
“3个月0基础上岸AI Agent开发”——看到这个标题,我第一反应是点开看看作者是不是刚从斯坦福AI Lab辞职回来的。结果发现是个和我一样在小公司带团队、天天被产品催着上线RAG功能的普通工程师。他没讲大模型原理,没列100篇论文,就甩出一张Excel:第1周学什么、第2天练什么、第7天必须跑通哪个最小闭环。我照着做了,第三周周五下午四点,我的第一个能调用天气API+查本地知识库+生成Markdown报告的Agent,在测试环境里吐出了第一句像人话的输出:“今天上海多云,建议带伞;您上周存的《客户拜访SOP》第3.2条提到‘雨天需提前确认交通方式’。”
这背后根本不是天赋或运气,而是一套被严重低估的工程化切片法:把“AI Agent开发”这个模糊概念,按真实项目交付链条,切成可计时、可验证、可回滚的原子模块。比如,“调用外部API”不是一句“用requests.post就行”,而是拆成:① 如何识别LLM返回的JSON结构是否合法(不是靠try-except硬扛);② 怎样设计fallback机制——当天气API超时,Agent该说“正在重试”还是直接查缓存?③ API响应字段名和LLM提示词中变量名如何做映射校验?这些细节,90%的教程连提都不提,但它们才是你卡在“第28天”的真正原因。
关键词里反复出现的“RAG”“LLMs”“agent”不是并列关系,而是三层依赖栈:最底层是LLM的推理能力(你得知道它能做什么、不能做什么),中间层是RAG提供的“记忆外挂”(解决LLM记不住你公司文档的问题),顶层才是Agent的“决策大脑”(决定什么时候查知识库、什么时候调API、什么时候直接回答)。很多人一上来就想搭Agent框架,结果连RAG检索出来的文本都拼不进prompt里——就像想造飞机却连螺丝刀怎么握都不知道。
所以这篇内容不叫“教程”,它是一份可执行的工程日志。里面没有“你应该学Python”,只有“第3天下午2点前,你必须让这段代码在你的Mac上跑出‘Hello, LLM’”;没有“RAG很重要”,只有“为什么你用FAISS建的索引,召回率永远卡在62%——因为没做query重写,而重写规则必须基于你知识库的PDF元数据结构”。所有内容,都来自我过去三个月带5个转行新人的真实踩坑记录。如果你现在打开终端还分不清conda和pip的区别,或者看到“ontology”这个词会下意识去搜百度百科——恭喜,你就是这份日志的目标读者。
2. 第1-14天:用“最小可行推理链”建立对LLM的肌肉记忆
很多零基础者失败的第一步,是试图理解“大模型怎么工作”。别干这事。你不需要知道反向传播怎么算,就像开车不用懂内燃机原理。你需要的是建立对LLM行为模式的条件反射式直觉——看到某种输入,立刻预判它大概率会怎么输出。这种直觉,只能通过高频、微量、即时反馈的“推理链训练”来获得。
2.1 拒绝一切抽象概念,从“Prompt即接口”开始
把LLM当成一个黑盒API,它的输入是prompt,输出是text。第一天的任务只有一件:用curl调通OpenAI的API(哪怕用免费额度)。重点不是写多炫的prompt,而是观察三个关键信号:
- token消耗的肉眼可见性:在prompt里加10个字,看response_tokens是否同步增加。你会发现,LLM对“空格”“换行符”也计费——这直接决定了你后续设计RAG时,要不要在chunk里保留原始PDF的排版符号。
- temperature=0时的确定性:同一段prompt跑10次,输出是否完全一致?如果出现“有时说北京有时说上海”,说明你的prompt存在歧义(比如用了“首都”这种指代词),必须立刻重构。
- system message的权重霸权:把“你是一个严谨的律师”写进system,再问“地球是平的吗”,它会先说“根据科学共识……”,而不是直接回答“不是”。这证明system message不是装饰,而是LLM的底层人格设定开关。
提示:别用ChatGPT网页版!它隐藏了所有底层参数。必须用官方SDK或curl,亲眼看到
"usage": {"prompt_tokens": 42, "completion_tokens": 15}这样的数字跳动。这是建立工程直觉的起点。
2.2 “三明治Prompt法”:用结构化模板对抗LLM的自由发挥
LLM讨厌开放式问题。第2-3天,强制自己用固定模板写prompt:
[Role] 你是一名资深运维工程师,负责排查K8s集群故障。 [Context] 当前集群有3个节点,node-1状态为NotReady,kubectl get nodes输出显示"KubeletNotReady"。 [Task] 请分三步诊断:① 列出可能原因;② 给出每种原因对应的kubectl命令;③ 预测执行后最可能出现的输出。 [Format] 严格用Markdown表格,表头为"原因|命令|预期输出"。这个模板的价值在于:它把LLM的“自由创作”压缩到表格单元格里,而表格结构本身是程序可解析的。第5天,你就能用Python脚本自动提取表格中的命令,丢给subprocess.run执行——这才是Agent的雏形。我带过的学员里,坚持用此模板写满100个prompt的人,第14天基本能手写JSON Schema约束LLM输出格式。
2.3 亲手拆解一次“幻觉”:为什么LLM会编造不存在的API文档
第7天,安排一个经典陷阱任务:“用Python写一个调用GitHub API获取用户仓库列表的函数,要求包含错误处理”。90%的LLM会生成类似github.get_user_repos(username)的伪代码。这不是它“撒谎”,而是其训练数据里,大量教程用这种简写描述API。
真正的解法是:用few-shot learning教它“什么是真实API”。在prompt里塞两个例子:
- 错误示例:
requests.get("https://api.github.com/users/{user}/repos")→ 缺少headers和auth - 正确示例:
requests.get(f"https://api.github.com/users/{username}/repos", headers={"Authorization": f"token {token}"})
第10天,你会突然意识到:所谓“减少幻觉”,本质是给LLM提供足够多的、带上下文约束的“正确样本”。这直接导向第15天的RAG设计——你的知识库,就是给LLM喂的“正确样本集”。
3. 第15-30天:RAG不是插件,而是你给LLM定制的“第二大脑”
搜索热词里“RAG知识库”“python + milvus 实现rag”高频出现,但绝大多数人卡在“为什么检索结果总不准”。真相是:RAG失效的根源,80%不在向量数据库,而在知识入库前的预处理链路。我们用一个真实案例说明。
3.1 知识库构建的致命三连错:PDF→文本→向量化
假设你要把《Kubernetes权威指南》PDF变成RAG知识库。大多数人流程是:PDF→pdfplumber提取文本→直接喂给sentence-transformers。结果呢?第20天测试时,问“如何配置Pod的健康检查”,检索出的chunk全是“第3章 容器运行时”,因为PDF里“健康检查”四个字旁边有张图,pdfplumber把图片占位符识别成乱码,导致整个段落向量漂移。
正确的切片逻辑是:
- PDF解析阶段:用PyMuPDF(fitz)而非pdfplumber,因为它能精准提取文字坐标,过滤掉页眉页脚和图片区域;
- 文本清洗阶段:不是简单去空格,而是识别“代码块”“表格”“标题层级”。比如,把“
livenessProbe:”这样的YAML关键字单独成行,确保向量模型能捕捉其技术语义; - Chunk策略阶段:拒绝固定长度(如512字符)。对技术文档,按“标题+其下所有内容”切分;对API文档,按“端点URL+请求体+响应示例”切分。
我实测过:同样一本PDF,用PyMuPDF+标题感知切分,召回率从58%升到89%。这不是玄学,是把文档结构当作代码结构来解析。
3.2 向量数据库选型:Milvus不是银弹,FAISS才是新手护城河
热词里“python + milvus 实现rag”很诱人,但第22天你会被Milvus的Docker部署搞崩溃。作为过来人,我建议:前30天,只用FAISS。理由很实在:
- FAISS的
IndexFlatIP(内积相似度)比Milvus默认的L2距离,更匹配LLM嵌入向量的分布特性; faiss.write_index()生成的.bin文件,你可以直接用xxd命令查看二进制结构——这让你真正理解“向量索引”是什么,而不是当黑盒用;- 当你发现检索不准时,FAISS允许你用
index.search()返回的distances数组,手动计算每个chunk与query的余弦相似度,从而定位是embedding模型问题还是chunk质量问题。
注意:别碰Milvus的GPU版本!第25天你还在为CUDA驱动版本打架时,用FAISS+CPU已经跑通全流程了。工程原则第一条:能用单机解决的,绝不引入分布式。
3.3 RAG的“灵魂校验”:为什么你必须手写一个re-ranker
LLM返回的top-k chunk,常有“相关但无用”的干扰项。比如问“K8s Service的ClusterIP原理”,检索出的chunk可能包含“ClusterIP是Service的虚拟IP”(正确),但也混入“ClusterIP范围默认是10.96.0.0/12”(无关)。这就是为什么第28天必须加入re-ranker。
最简单的re-ranker,就是用LLM自己当裁判:
# 把query和每个chunk拼成新prompt rerank_prompt = f"""请判断以下文本是否直接解释'{query}'的原理: 文本:{chunk_text} 回答:是/否""" # 调用LLM,只取"是"的chunk这个操作看似绕,但它强迫你面对一个事实:RAG不是“检索完就结束”,而是“检索→校验→精炼”的闭环。第30天,当你看到re-ranker把召回率从72%提升到91%时,你就真正理解了RAG的工程内核。
4. 第31-60天:Agent不是智能体,而是“可控的决策流水线”
热词里“agent框架”“pi agent”“hermes agent”让人眼花缭乱,但第31天你要做的,是忘掉所有框架,先用Bash脚本写一个Agent原型。为什么?因为Agent的本质,是把多个独立工具(LLM、RAG、API)串成一条可中断、可监控、可回溯的流水线。
4.1 用Shell脚本定义Agent的“心跳协议”
创建agent.sh,内容只有三行:
# 1. 接收用户输入 read -p "User: " user_input # 2. 调用LLM判断需要什么动作 action=$(curl -s -X POST http://localhost:8000/llm -d "prompt=判断'$user_input'需要:A)查知识库 B)调天气API C)直接回答" | jq -r '.choices[0].message.content') # 3. 根据action执行分支 case $action in "A") echo "$(python rag_query.py "$user_input")" ;; "B") echo "$(curl -s 'http://wttr.in/Shanghai?format=%C+%t')" ;; *) echo "直接回答..." ;; esac这个脚本的价值,远超代码本身。它让你亲手触摸到Agent的三个核心契约:
- 输入契约:用户一句话,必须被转化为结构化指令(A/B/C);
- 调度契约:不同动作必须走不同执行路径,且路径间不能互相污染;
- 输出契约:无论走哪条路,最终输出必须是纯文本,供下一轮输入。
第40天,当你把Bash换成Python,把curl换成LangChain的RouterChain时,你不会觉得是在学新东西,而是在给老朋友升级引擎。
4.2 “Tool Calling”的本质:不是函数调用,而是协议协商
热词里“skill和agent的区别”常被讨论,但真相是:Skill是Agent的对外协议,Agent是Skill的调度中枢。第45天,你必须亲手实现一个WeatherTool:
class WeatherTool: def __init__(self): self.api_url = "http://wttr.in/{city}?format=%C+%t" def invoke(self, city: str) -> str: # 关键:这里不是直接返回天气,而是返回结构化结果 return { "city": city, "weather": "Sunny", "temp": "+22°C", "timestamp": "2024-06-15T14:30:00Z" }为什么返回dict而不是字符串?因为第50天,你要把这个dict喂给LLM,让它生成“今天上海晴,气温22度”这样自然的句子。如果Tool直接返回字符串,LLM就失去了二次加工的空间——这违背了Agent“分层解耦”的设计哲学。
4.3 失败处理的黄金法则:Agent必须有“降级开关”
所有热词里“agent execution terminated due to error”都在提醒一件事:Agent必须预设失败场景。第55天,强制你在每个Tool里加入降级逻辑:
def invoke(self, city: str) -> str: try: response = requests.get(self.api_url.format(city=city), timeout=3) if response.status_code == 200: return self._parse_weather(response.text) else: return self._fallback_to_cache(city) # 从本地JSON缓存读 except requests.Timeout: return self._fallback_to_default() # 返回“当前无法获取实时天气”这个设计教会你:真正的Agent开发,不是追求100%成功,而是定义清楚“什么情况下算失败”“失败后用户能接受什么替代方案”。第60天,当你看到Agent在天气API宕机时,自动切换到缓存数据并告知用户“这是昨日数据”,你就摸到了工程化的门把手。
5. 第61-90天:从Demo到生产:用“可观测性”终结玄学调试
最后30天,不再新增功能,而是把前60天的代码,改造成可维护、可监控、可协作的生产级系统。热词里“大模型部署”“大模型本地部署”指向同一个痛点:当LLM变成你系统的一部分,它就必须像MySQL一样可诊断。
5.1 给LLM调用装上“行车记录仪”
在每次LLM调用前后,强制记录四要素:
- Input Prompt:完整prompt,包括system message和few-shot examples;
- Output Text:原始输出,不做任何trim;
- Metadata:调用时间、模型名称、temperature、max_tokens;
- Trace ID:关联前端请求ID,实现全链路追踪。
用一个简单的SQLite表实现:
CREATE TABLE llm_traces ( id INTEGER PRIMARY KEY, trace_id TEXT, prompt TEXT, response TEXT, model TEXT, temperature REAL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP );第70天,当你发现某个特定prompt总是触发“agent couldn't generate a response”,直接查表,发现90%发生在temperature=0.8且max_tokens=512时——这就指向了LLM的输出截断问题,而不是笼统地说“模型不稳定”。
5.2 RAG效果的量化仪表盘:别信“看起来不错”
热词里“rag框架”常被当作黑盒,但第75天,你必须建立自己的RAG评估体系。最有效的指标不是准确率,而是用户意图满足率:
| 用户问题类型 | 满足标准 | 示例 |
|---|---|---|
| 事实查询(如“K8s Pod状态有哪些”) | 检索chunk包含全部状态值,且无冗余信息 | ✅ 返回“Pending, Running, Succeeded, Failed, Unknown” |
| 操作指导(如“如何扩容Deployment”) | 检索chunk包含kubectl命令+参数说明+注意事项 | ✅ 返回kubectl scale deployment nginx --replicas=5及“注意:需指定namespace” |
每周抽10个真实用户问题,人工标注“是否满足”,第80天你会得到一张趋势图:当满足率连续两周低于85%,说明知识库更新滞后,必须触发重新索引流程——而不是等用户投诉。
5.3 Agent的“灰度发布”:用A/B测试驯服不确定性
第85天,当你想给Agent加新功能(比如支持画图),千万别全量上线。用Nginx做流量分发:
# 将10%流量导到新版本 split_clients $request_id $version { 10% "new"; * "old"; } location /agent { proxy_pass http://backend_$version; }然后对比两组数据:
- 成功率:新版本是否因画图功能增加失败率?
- 停留时长:用户在新版本页面停留是否更久?(说明画图功能真有用)
- 退出率:用户是否在看到画图结果后立刻关闭页面?(说明结果不符合预期)
第90天,当你看着A/B测试报表,决定是否全量上线时,你就完成了从“写代码的人”到“交付价值的人”的蜕变。这90天,不是教你成为AI科学家,而是把你锻造成一个能用工程手段,把不确定的AI能力,变成确定的业务价值的建造者。
我在第87天收到一个需求:给销售团队做一个“竞品分析Agent”。他们不要PPT,只要输入竞品名,自动生成SWOT表格。我打开第1天写的那个Bash脚本,把rag_query.py换成新的竞品知识库,把WeatherTool换成CompetitorTool,3小时上线。销售总监发来截图,表格里“优势”栏写着“价格比友商低15%,但技术支持响应慢”,——这行字,就是90天工程化切片结出的果子。