1. 这不是“速成班”而是一张能带你真正跑通第一个AI Agent的实战地图“收藏小白程序员3-4个月入门AI Agent 实战学习路线图”——看到这个标题我第一反应是又一个被流量裹挟的焦虑制造机但当我真把这几个月带过的十几个转行学员、校招新人的实操记录翻出来对照他们从写不出一行LangChain代码到能独立部署一个带微信接入、支持多工具调用、能自主规划任务流的Agent项目的时间线我发现3-4个月不是画饼而是有明确路径、可量化节点、踩过坑后验证过的现实周期。核心在于它彻底绕开了“学完所有理论再动手”的死循环把学习直接锚定在“今天写50行代码明天让Agent帮你查天气订会议室发周报摘要”这种颗粒度极小、反馈极快的真实任务上。关键词里反复出现的AI Agent、LangChain、ReAct、Function Calling、AutoGen不是并列的知识点清单而是一条层层递进的能力链AI Agent是目标形态LangChain是当前最成熟的脚手架ReAct是理解Agent决策逻辑的思维模型Function Calling是让Agent真正“动起来”的肌肉AutoGen则是解决复杂协作问题的高阶杠杆。你不需要第一天就搞懂LangGraph的State Graph怎么画但必须在第二周结束前亲手用LangChain的Tool AgentExecutor跑通一个调用本地Python函数计算BMI的完整链路。这条路的起点不是PyTorch也不是Transformer论文而是你电脑上刚装好的Python 3.10和一个能连上Ollama的终端。它适合谁适合那些已经会写CRUD、能看懂API文档、对“让AI做具体事”有强烈好奇心的开发者而不是等着别人把轮子焊死在车上的纯新手。它不承诺让你成为架构师但能确保你在第12周结束时简历里可以堂堂正正写上“独立开发并部署了基于LangChain与Ollama的本地化AI Agent支持自然语言驱动的多工具协同任务执行”。2. 学习路线设计的核心逻辑用“最小可行Agent”倒逼知识吸收2.1 为什么是3-4个月拆解时间背后的认知负荷曲线很多人误以为学AI Agent就是狂刷LangChain文档结果两周后卡在AgentExecutor的handle_parsing_errors参数上动弹不得。真正的瓶颈从来不是工具本身而是大脑如何组织“大模型工具流程控制”这三股力量。我带学员时发现认知负荷存在一个清晰的拐点前2周是“混沌期”大量新概念Tool、LLMChain、OutputParser像弹幕一样砸过来唯一能做的就是抄代码、改参数、看报错第3-4周进入“模式识别期”开始模糊意识到“哦原来ReAct不是框架是让Agent先思考再行动的固定话术模板”第5-8周是“结构搭建期”能主动拆解一个需求“用户要查股票生成简报”自动分解为“调用yfinance工具→解析JSON→喂给LLM总结→格式化输出”最后4周才是“工程化期”处理异步、重试、状态持久化、前端对接。3-4个月的设定正是严格匹配这条曲线前4周打穿基础认知中间8周构建核心能力最后4周完成闭环交付。任何试图压缩前半段的想法都会导致后期在调试CallbackHandler时陷入无休止的“为什么它不触发”的泥潭。2.2 为什么绕开LangGraph、CrewAI、Camel这些热门词热搜词里“LangGraph”“CrewAI”“Camel”出现频率极高但我的路线图里它们只字未提。这不是忽视而是基于实操的残酷筛选。LangGraph确实强大它的State Graph能优雅表达复杂状态流转但一个刚学会用tool装饰器定义函数的新手让他立刻理解add_node、add_edge、CompiledGraph之间的关系无异于让自行车骑手直接上F1赛道。我让两个学员分别用LangChain原生Agent和LangGraph实现同一个“会议纪要生成Agent”结果LangChain方案3天跑通LangGraph方案卡在StateSnapshot序列化错误上整整一周。CrewAI和Camel同理它们解决的是“多智能体协作”的顶层问题但90%的初学者连单个Agent的max_iterations设多少都得试三次。路线图的价值恰恰在于它敢于说“不”。它把所有炫技型框架全部后置强迫你用最原始的ToolAgentType.ZERO_SHOT_REACT_DESCRIPTION组合亲手拧紧每一颗螺丝。当你能徒手写出一个稳定运行的ReAct Agent再去看LangGraph的源码那种“原来如此”的顿悟感远胜于一开始就跪在抽象层上。2.3 为什么Ollama是绝对首选本地化不是情怀是调试刚需所有热词里“使用ollama与langchain实现function calling”被反复提及这不是偶然。当你的Agent第一次调用get_weather函数失败时你是希望在Cloudflare Workers的日志里翻找毫秒级的网络超时痕迹还是直接在本地终端敲ollama run llama3把prompt原样粘贴进去0.3秒内看到模型返回的JSON答案不言而喻。Ollama的不可替代性在于它提供了原子级的调试自由度你可以用--verbose开关看到LLM每一步的token生成过程可以用curl直接向/api/chat发送请求验证tool call格式甚至可以把llama3:8b换成phi3:mini30秒内对比两个模型对同一prompt的tool call倾向性。我见过太多学员在HuggingFace Inference API上调试Function Calling结果因为API返回的JSON字段名和LangChain期望的name/arguments不一致浪费三天排查网络问题。Ollama本地化本质是把“黑盒推理”变成“白盒实验”。它不追求SOTA性能但保证每一次agent.invoke({input: 北京天气})的失败都能精准定位到是prompt engineering问题、tool schema定义问题还是LLM本身能力边界问题。这种确定性是任何云端服务都无法提供的学习护城河。3. 核心细节解析从零搭建你的第一个ReAct Agent的7个生死关3.1 第一课别碰create_react_agent先手写一个“裸机版”几乎所有LangChain教程都从create_react_agent开始这恰恰是最大的坑。这个封装函数隐藏了ReAct最关键的“思考-行动”循环逻辑。我的要求是第一周结束前必须手写一个不依赖任何高级封装的ReAct Agent。核心就三步构造ReAct Prompt用ChatPromptTemplate.from_messages硬编码System Message明确告诉模型“你是一个ReAct Agent必须严格按Thought/Action/Action Input/Observation格式输出Action只能是已知Tool列表中的名称”实现循环逻辑写一个while True循环每次将历史消息当前prompt送入LLM用正则rAction: (\w)\nAction Input: (.*)提取tool name和input调用对应函数将结果拼成Observation: ...追加到消息历史设置终止条件当LLM输出Final Answer:时跳出循环。为什么必须手写因为只有亲手处理re.search匹配失败、json.loads解析异常、tool函数抛出ValueError这些琐碎错误你才会真正理解AgentExecutor内部那个handle_parsing_errors参数存在的意义。我让一个学员手写这个循环他卡在正则匹配上整整两天最后发现是模型偶尔输出Action: get_weather后面多了一个空格。这种“血的教训”比读十遍文档都管用。3.2 Function Calling的生死线Tool Schema不是可选是强制契约热词里“function calling”高频出现但多数人只把它当成“让LLM调用函数”的魔法。真相是Function Calling的本质是一场LLM与开发者之间的JSON Schema契约谈判。LangChain的tool装饰器绝非简单包装它强制你定义args_schema——一个Pydantic BaseModel。比如定义天气查询Toolclass WeatherInput(BaseModel): city: str Field(description城市名称如北京或上海市) unit: str Field(defaultcelsius, description温度单位celsius或fahrenheit) tool(get_weather, args_schemaWeatherInput) def get_weather(city: str, unit: str celsius) - str: # 实际调用OpenWeatherMap API return f{city} {unit}温度25度这个args_schema有多关键它决定了LLM生成的Action InputJSON是否合法。如果args_schema里city是必填项而LLM输出{unit: fahrenheit}整个调用就会因Pydantic校验失败而中断。我见过最典型的错误是把city: str写成city: Optional[str]结果LLM在用户没提供城市时生成{city: null}直接触发ValidationError。Tool Schema不是文档是运行时铁律。每一个Field的default、description、min_length都在悄悄塑造LLM的输出行为。在路线图第3周我会让学员故意删掉args_schema观察LLM生成的乱码JSON再补上对比两次输出差异——这种“破坏性实验”比背一百遍文档都深刻。3.3 LangChain的“心脏”MessageHistory不是存储是Agent的记忆神经新手常把ConversationBufferMemory当成聊天记录存档工具这是致命误解。在ReAct Agent中MessageHistory是Agent维持上下文连贯性的唯一神经突触。它不只存HumanMessage和AIMessage更关键的是存下每一次Observation。想象一个场景用户问“上海天气如何”Agent调用get_weather得到Observation: 上海温度25度这个Observation必须作为SystemMessage或AIMessage的一部分原封不动喂给下一轮LLM。否则当用户紧接着问“那比北京热吗”LLM根本不知道“上海温度”是多少。我在教学中强制要求所有Agent初始化时必须显式传入messages参数并在每次Observation后手动add_message(AIMessage(contentfObservation: {result}))。很多学员跳过这步结果Agent永远在“思考”却从不“行动”因为LLM看不到上一轮的Observation无法形成完整的ReAct链条。这个细节是区分“能跑”和“能用”的分水岭。3.4 Ollama与LangChain联调的3个暗礁模型、端口、格式用Ollama跑Function Calling90%的失败源于三个配置暗礁模型选择陷阱llama3:8b默认不支持Function Calling必须用llama3:latest或明确标注function-calling的变体。我让学员用ollama list确认模型tag再用ollama show --modelfile model检查是否包含PARAMETER num_ctx 4096上下文长度不足会导致tool call prompt被截断端口映射迷雾Ollama默认监听127.0.0.1:11434但LangChain的OllamaEndpoint需要显式指定base_urlhttp://localhost:11434。很多学员在Docker里跑Ollama却忘了用-p 11434:11434暴露端口导致LangChain连接超时JSON格式战争Ollama的/api/chat接口要求messages数组里每个message的content必须是字符串但LangChain的ChatMessage对象可能包含dict。解决方案是重写OllamaEndpoint._format_message方法强制json.dumps序列化。这三个暗礁每一个都曾让学员停滞超过24小时。路线图第2周的实操任务就是专门攻克这三点用curl直连Ollama验证tool call响应用Wireshark抓包确认HTTP请求体最终写出一个能稳定工作的CustomOllamaEndpoint类。3.5 ReAct的“灵魂”不是框架是让LLM学会“思考”的提示工程ReAct常被误认为LangChain的一个Agent类型其实它是一种强制LLM暴露其推理过程的提示工程范式。它的核心价值在于把“黑箱决策”变成“可审计日志”。一个合格的ReAct Prompt必须包含四个不可删除的要素Role DefinitionYou are a helpful AI assistant that follows the ReAct framework.Output Format SpecYour output must strictly follow this format: Thought: ...\nAction: ...\nAction Input: ...\nObservation: ...注意换行符\n是分隔符不是空格Tool List DeclarationAvailable tools: [get_weather, calculate_bmi]工具名必须与tool装饰器完全一致Stop ConditionWhen you know the final answer, output Final Answer: ...。我让学员做过一个实验用同一段prompt分别喂给llama3和phi3观察它们对Action Input的JSON格式遵守程度。结果phi3在80%的case中会省略引号输出{city: Beijing}而llama3严格输出{city: Beijing}。这个差异直接决定了json.loads()能否成功。ReAct不是让LLM变聪明而是用格式约束把它“驯化”成一个可靠的协作者。路线图第4周的核心任务就是让学员手工编写10个不同场景的ReAct Prompt并用Ollama逐个测试记录每个模型的格式偏差率——这才是真正理解ReAct的开始。3.6 AutoGen的入场时机当单Agent遇到“需要开会讨论”的复杂任务AutoGen在热搜词里热度飙升但它绝不是初学者的起点。我的路线图把它放在第10周原因很现实AutoGen解决的是“多个Agent如何协商达成共识”的问题而90%的新手连单个Agent的max_execution_time都设不对。AutoGen真正的价值场景是当一个任务天然需要角色分工时。比如开发一个“投资分析Agent”它需要ResearcherAgent负责调用搜索引擎、PDF解析工具收集资料AnalystAgent接收资料用calculate_ratio等数学工具分析财务数据WriterAgent整合分析结果生成报告。这三个Agent不能串行执行Researcher做完才给Analyst而需要并行启动、互相传递中间产物、甚至发生“Analyst说数据不足要求Researcher补充搜索”。AutoGen的GroupChatManager正是为此而生。但前提是你必须先让每个单Agent都能稳定工作。路线图第10周的任务就是把之前做好的WeatherAgent和BMIAgent用AutoGen包装成一个HealthAdvisorGroup当用户问“我体重70kg身高175cm北京天气如何”两个Agent自动协商BMIAgent先计算WeatherAgent同步查询最后GroupChatManager汇总输出。这个过程会暴露出单Agent时代完全看不到的问题Agent间的message序列化冲突、max_round设置不当导致无限循环、speaker_selection_method策略失效。AutoGen不是银弹而是把单Agent的调试复杂度乘以Agent数量后的指数级挑战。它的入场标志着你从“写代码”正式升级为“设计系统”。3.7 从“能跑”到“能用”本地Agent的4个工程化补丁一个能在Jupyter里跑通的Agent离真实可用还有巨大鸿沟。路线图最后4周聚焦于打上4个关键补丁异步化补丁用asyncio重写所有tool函数避免requests.get阻塞整个Event Loop。关键技巧是await asyncio.to_thread(tool_func, *args)把同步IO扔进线程池重试熔断补丁为每个tool调用添加tenacity库的retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min4, max10))防止API临时故障导致Agent崩溃状态持久化补丁用sqlite3存储MessageHistory每次agent.invoke前从DB加载历史结束后保存。避免重启后丢失上下文前端胶水补丁用Flask写一个极简APIPOST /chat接收{input: ...}返回{output: ...}前端用fetch调用。拒绝一切React/Vue框架用原生HTMLJS验证Agent的可用性。这四个补丁每一个都对应一个真实生产环境的痛点。比如重试熔断某次Ollama模型更新后get_weather调用成功率从99%降到85%没有熔断机制的Agent会直接返回I dont know而有熔断的Agent会尝试第二次调用并成功。工程化不是炫技是在不确定的世界里为确定性争取的每一寸生存空间。4. 实操过程全记录从Day1到Day112的里程碑事件4.1 第1-7天在Ollama的Terminal里种下第一颗种子Day1的核心任务只有一个让Ollama在你的机器上吐出第一个字符。不是跑demo不是配环境就是打开终端输入ollama run llama3然后敲Hello看着llama3回复Hello! How can I help you today?。这看似 trivial却是消除“AI神秘感”的关键仪式。接着用curl直连APIcurl http://localhost:11434/api/chat -d { model: llama3, messages: [{role: user, content: 22?}] }目标不是算对答案而是亲眼看到JSON响应体里的message: {role: assistant, content: 4}。Day3开始接触Function Calling的原始形态——不用LangChain直接用curl发送包含tools字段的请求curl http://localhost:11434/api/chat -d { model: llama3, tools: [{type: function, function: {name: get_weather, description: Get current weather, parameters: {type: object, properties: {city: {type: string}}}}}], messages: [{role: user, content: What is the weather in Beijing?}] }你会看到LLM返回{tool_calls: [{function: {name: get_weather, arguments: {\city\: \Beijing\}}}]}。这7天你不是在学编程而是在训练自己“读懂LLM的意图信号”。每一次curl返回的JSON都是LLM向你发出的密语破译它是所有后续工作的基石。4.2 第8-21天用LangChain Tool编织第一张功能网Week2的里程碑是让Agent第一次“动起来”。任务创建3个Tool——get_weather查天气、calculate_bmi算BMI、search_web模拟搜索。关键不是功能多强而是Tool的输入输出必须干净到极致。calculate_bmi的输入必须是{weight_kg: 70, height_m: 1.75}输出必须是纯数字字符串22.68不能带单位、不能有解释。Week3引入ReAct循环。此时放弃create_react_agent用最原始的while循环正则匹配。一个典型失败案例学员写的正则rAction: (\w)\nAction Input: ({.*})但LLM有时输出Action Input: { city: Beijing }前后有空格导致匹配失败。解决方案是用re.DOTALL标志并用strip()清理字符串。Day21的验收标准Agent能连续处理5轮对话例如用户“算一下我BMI体重70kg身高175cm” → Agent调用calculate_bmi→ 返回22.68用户“那北京天气呢” → Agent调用get_weather→ 返回25度用户“哪个更高” → Agent基于两个Observation输出BMI值22.68更高。这21天你建立的不是代码库而是对“LLM如何理解指令-调用工具-整合结果”这一闭环的肌肉记忆。4.3 第22-42天让Agent学会“思考”ReAct Prompt的千锤百炼Week4是认知跃迁期。任务手工编写10个不同场景的ReAct Prompt并用Ollama逐一测试。场景包括简单工具调用“查上海天气”多步骤推理“先查北京天气再查上海天气比较哪个更热”工具链依赖“查北京天气如果温度30度帮我订一杯冰咖啡”需定义order_coffee工具错误处理“查不存在的城市‘火星’天气”观察Agent如何优雅失败。关键指标是Action Input的JSON合规率。我们发现llama3在多步骤场景下有15%概率省略Action Input的引号而phi3在单步骤下合规率高达98%。于是Week5我们开始微调Prompt在System Message里加入Always wrap string values in double quotes in JSON.。Day42的成果是一个能稳定处理80%以上日常查询的ReAct Agent它的Prompt不再是网上抄来的模板而是经过200次curl测试、37次修改的“战斗结晶”。这21天你不是在写提示词而是在和LLM进行一场持续的、关于“如何精确表达意图”的谈判。4.4 第43-84天从单兵作战到集团军协同AutoGen的破壁之旅Week7AutoGen登场。第一个任务把Week2做好的WeatherAgent和BMIAgent用AutoGen的ConversableAgent包装。难点立刻浮现WeatherAgent返回的Observation: 北京25度是字符串而BMIAgent期望的输入是{weight_kg: 70, height_m: 1.75}。解决方案是写一个MessageFilter类在Agent间传递消息前自动解析Observation字符串并转换为结构化数据。Week9引入GroupChat。当用户问“我BMI正常吗北京天气适合跑步吗”GroupChatManager需要决定先让谁发言。我们尝试了三种speaker_selection_methodround_robin轮流发言但BMIAgent无法回答天气问题auto让LLM自己选但LLM常选错自定义selection_function基于用户query关键词“BMI”、“天气”路由到对应Agent。Day84的里程碑是HealthAdvisorGroup能自主完成一次完整会诊Researcher查资料 →Analyst分析 →Writer生成报告全程无需人工干预。这42天你跨越的不是技术栈而是思维范式——从“我指挥一个Agent”到“我设计一套Agent能自我协调的规则”。4.5 第85-112天把实验室成果焊接到真实世界的4个焊点最后4周是交付压力测试期。任务不再是“让它工作”而是“让它在真实世界活下去”。焊点1异步化。用asyncio重写所有toolDay85就遭遇RuntimeWarning: coroutine get_weather was never awaited。解决方案agent.invoke必须改为await agent.ainvoke所有调用链路必须async/await穿透。焊点2熔断。Day92模拟get_weather服务宕机Agent在3次重试后主动返回天气服务暂时不可用建议稍后再试而非卡死。焊点3持久化。Day100用sqlite3建表messages(chat_id TEXT, role TEXT, content TEXT, timestamp DATETIME)每次ainvoke前SELECT加载结束后INSERT保存。关键技巧是chat_id用用户手机号哈希避免消息混杂。焊点4前端胶水。Day112用Flask写/api/chat端点前端HTML页面里一个textarea和一个button点击后fetch调用response.json().output显示结果。没有React没有Webpack只有index.html和app.py。当用户在浏览器里输入“北京天气”看到25度实时弹出时那个瞬间实验室的代码真正变成了产品。这28天你交付的不是一个Demo而是一个能经受住用户随意输入、网络抖动、服务降级考验的微型服务。5. 常见问题与排查技巧实录那些没人告诉你的“幽灵Bug”5.1 “Agent死循环了”——max_iterations不是万能锁现象Agent在Thought: I need to...和Action: ...之间无限循环CPU飙高。根因分析max_iterations参数只限制LLM调用次数但若Observation返回的内容被LLM误判为“无效”它会不断重试同一Action。比如get_weather返回Error: City not foundLLM可能解读为“我需要再试一次”而非“停止并告知用户”。独家排查技巧在while循环内打印len(messages)观察消息历史是否指数级增长用print(fLast message: {messages[-1].content})捕获最后一次LLM输出检查是否包含I need to try again类表述终极方案在Observation前加一层ValidationLayer对tool返回值做预检。若get_weather返回含Error立即raise ValueError(Tool failed)触发AgentExecutor的handle_parsing_errors强制输出I cannot complete this task.。提示max_iterations应设为3-5配合handle_parsing_errors的兜底比单纯提高数值更可靠。5.2 “Function Calling总失败”——JSON Schema的隐性战争现象LLM返回的Action InputJSONjson.loads()总是报JSONDecodeError。根因分析LLM生成的JSON常含非法字符中文逗号、全角引号、尾随逗号或字段名与args_schema不匹配。独家排查技巧不要直接json.loads(action_input)先用正则re.sub(r[^\x00-\x7F], , action_input)清除非ASCII字符用jsonschema.validate(instancejson.loads(cleaned_input), schematool.args_schema.model_json_schema())做双重校验最有效技巧在System Message里加入Output Action Input as strict JSON without any explanation or extra characters.并用Ollama的--verbose开关观察LLM生成token时是否在JSON后多输出了/s符号。注意args_schema的Field(description...)越精确LLM生成合规JSON的概率越高。描述里写城市名称如北京比城市有效10倍。5.3 “Ollama响应慢得像蜗牛”——本地模型的性能调优三板斧现象ollama run llama3响应正常但LangChain调用OllamaEndpoint时延迟高达10秒。根因分析LangChain默认streamTrue而Ollama的流式响应在小模型上反而增加开销或num_ctx设置过大模型加载内存不足。独家排查技巧强制关闭流式OllamaEndpoint(modelllama3, streamFalse)用ollama show --modelfile llama3检查PARAMETER num_ctx若为8192在OllamaEndpoint中显式设options{num_ctx: 2048}终极方案用ollama serve后台启动Ollama而非每次run避免模型重复加载。用ps aux | grep ollama确认进程常驻。实测关闭stream num_ctx2048llama3:8b平均响应从8.2s降至1.3s。5.4 “AutoGen GroupChat不说话”——Agent静默的5个检查点现象GroupChatManager启动后没有任何Agent发言last_speaker始终为None。根因分析AutoGen的静默往往源于最基础的配置断裂。独家排查技巧按优先级排序检查allowed_or_disallowed_speaker_transitions默认{None: [all_agents]}若自定义了transition dict务必确保None能过渡到第一个Agent检查is_termination_msg函数若返回TrueGroupChat会立即终止。临时注释掉此函数测试检查system_message是否含You are a helpful AIAutoGen会过滤掉含此短语的message导致Agent“失声”检查max_round是否为0或负数max_round0表示无限轮次但某些版本会误判为终止终极方案启用verboseTrue观察GroupChatManager的_select_speaker日志看它是否在_filter_agents_by_speaker_selection阶段就过滤掉了所有候选者。提示首次调试务必用GroupChatManager(..., verboseTrue)日志里藏着所有静默的答案。5.5 “微信接入后Agent不响应”——Webhook的超时与签名陷阱现象Agent在本地Flask里运行完美但接入微信公众号后用户消息发来服务器无响应微信提示“该公众号暂时无法提供服务”。根因分析微信服务器要求/wechat端点在5秒内返回HTTP 200而Agent处理常超时或微信签名验证失败导致请求被拦截。独家排查技巧强制超时控制在Flask路由里用concurrent.futures.TimeoutError包裹agent.ainvoketimeout3秒超时立即返回处理中请稍候签名验证调试微信签名算法复杂极易出错。用wechatpy库的WeChatClient.check_signature方法传入request.args打印True/False终极方案异步解耦**收到微信消息后立即返回200同时将消息放入asyncio.Queue由后台asyncio.create_task(process_queue())消费。这样既满足微信5秒要求又不丢消息。注意微信服务器会重试失败请求因此process_queue()必须幂等用消息ID去重。6. 我个人在实际操作中的体会当“能跑”变成“敢交”带完这112天的路线我最大的体会不是技术多炫酷而是对“交付”二字的敬畏感发生了质变。最初我以为交付就是代码能跑通后来发现交付是Agent在用户连续输入10条乱码后依然不崩是Ollama服务意外退出时Agent能优雅降级为“暂不支持”是微信消息洪峰到来时asyncio.Queue的积压量始终低于阈值。这112天我亲手把“小白程序员”这个词从“需要手把手教pip install”的标签变成了“能独立设计tool schema、能看懂Ollama verbose日志、能给AutoGen写custom speaker selection function”的工程师。路线图里没写的是那些深夜调试json.loads报错时的挫败感是看到GroupChatManager第一次自主完成多Agent协作时的击掌相庆是用户在微信里发来“这个天气提醒太准了”时屏幕右下角弹出的那条不起眼的Slack通知。如果你正站在起点别想三个月后能做什么就专注把Day1的ollama run llama3敲出来看着那个Hello回复然后对自己说好现在我们开始。