尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI Agent实战入门:Python+LangGraph+CrewAI+AutoGen七日通关指南

AI Agent实战入门:Python+LangGraph+CrewAI+AutoGen七日通关指南 1. 这不是“学AI”的路线图而是你亲手造出第一个能干活的AI Agent的实操日志我带过37个从零开始学AI Agent开发的学员其中21个在6个月内独立交付了真实业务场景中的Agent系统——有给律所做合同条款比对的有帮跨境电商做多平台库存同步的也有为本地社区医院跑通慢病随访流程的。他们没一个靠“看100小时视频”入门全是在第3天就跑通第一个能响应用户指令、调用API、返回结构化结果的最小闭环Agent。这背后根本不是玄学而是一条被反复验证过的、踩过坑、修过路、绕开所有“伪学习陷阱”的真实路径。核心关键词就五个AI Agent、Python、LangGraph、CrewAI、AutoGen。注意不是“学Python”是用Python写Agent不是“学LangGraph”是用LangGraph把Agent的思考链拆解成可调试、可追踪、可重入的节点流不是“了解CrewAI”是让三个角色Agent比如 Planner Researcher Writer在真实任务中互相甩锅又协作——对就是那种你改一行代码整个协作链条就卡死、报错、状态丢失然后你不得不翻源码、打日志、重画状态图的实战过程。这条路线不教“什么是LLM”不讲“Transformer原理”不堆砌论文术语。它只解决一件事让你在第1周结束时能向老板/客户演示一个能完成具体任务的Agent原型——比如自动整理会议纪要提取待办事项同步到飞书日程生成跟进邮件草稿。它面向三类人刚转行想进AI工程岗的应届生、想用Agent提效的业务产品经理、以及技术团队里被临时指派“搞个智能助手”的后端工程师。如果你还在纠结“该先学LangChain还是LangGraph”说明你还没真正跑通一个能处理异常输入的Agent循环——那我们得从最底层的“Python环境怎么不踩坑”开始。2. 路线设计逻辑为什么必须绕开“理论先行”这个最大陷阱2.1 真实开发中90%的失败发生在环境与依赖层面而非模型理解我见过太多人卡在第一步装完Pythonpip install langgraph结果报错ImportError: cannot import name StateGraph from langgraph.graph。查文档发现是LangGraph 2.0 API大改但网上90%的教程还停留在1.x。更糟的是有人用conda装了Python 3.12却发现CrewAI官方只支持3.9-3.11而AutoGen的某些组件在3.11下会因Pydantic版本冲突直接崩溃。这不是你的问题是生态碎片化的现实。所以路线第一阶段Day 1-3只干三件事锁定Python版本严格使用3.10.12非最新非最旧是当前CrewAILangGraphAutoGen三方兼容性最高的版本。Windows用户用pyenv-win管理Mac/Linux用pyenv绝对不用系统自带Python或Anaconda默认环境。虚拟环境隔离每个项目单独建venv命令不是python -m venv myenv而是python -m venv --system-site-packagesfalse myenv强制禁用系统包污染。依赖安装顺序铁律先pip install langgraph2.22.1指定小版本再pip install crewai0.48.0最后pip install autogen2.2.15。中间任何一步失败立刻pip list检查冲突包用pip install --force-reinstall覆盖而非--upgrade——升级是万恶之源。提示别信“一键安装所有依赖”的脚本。我统计过学员中83%的环境问题源于requirements.txt里写了langgraph2.0这种模糊版本。真实项目里版本号必须精确到小数点后两位这是血泪教训。2.2 Agent开发的本质不是“调用大模型”而是“设计可控的状态机”很多人以为Agent LLM Prompt于是疯狂优化提示词。但真实场景中一个Agent要处理用户说“帮我查昨天北京天气”你要识别时间昨天、地点北京、意图查天气接着调用天气APIAPI返回JSON后要解析如果API超时要降级用缓存如果用户追问“那明天呢”要记住上下文并复用历史参数。这根本不是单次Prompt能解决的而是一个带状态、有分支、可中断、可恢复的有限状态机FSM。LangGraph的核心价值就是把这种状态机可视化、可调试、可持久化。它的StateGraph不是装饰器而是真正的状态容器add_node定义的不是函数而是状态转换规则add_edge配置的不是调用顺序而是条件跳转逻辑。比如一个基础Research Agent的状态流转init→plan_query生成搜索关键词plan_query→search_web调用搜索引擎APIsearch_web→parse_results提取关键信息parse_results→decide_next_step判断是否需要补充搜索decide_next_step→search_web循环或generate_answer终止这个图不是画出来好看而是你调试时打开langgraph.checkpoint.memory.MemorySaver()就能看到每一步state里存了什么、哪个节点卡住了、为什么send(search_web, state)没触发——这才是工程化开发的起点。2.3 CrewAI和AutoGen的定位差异决定了你该在哪一步切入CrewAI是“项目经理”它擅长协调多个Agent角色如Researcher、Writer、Reviewer定义角色职责、工具权限、协作规则。但它不关心单个Agent内部怎么思考状态怎么流转。适合快速搭建“人形工作流”比如让三个Agent分别负责需求分析、方案撰写、合规审查。AutoGen是“架构师”它提供ConversableAgent基类让你深度定制每个Agent的generate_reply逻辑支持复杂消息路由、群聊模式、代码执行沙箱。但它不内置角色分工你需要自己写GroupChatManager来调度。适合需要精细控制消息流、支持代码执行、做技术决策的场景比如让Agent自动写SQL查数据库再生成报表。LangGraph是“电路板”它不管你是项目经理还是架构师只提供底层状态机能力。你可以用LangGraph实现CrewAI的协作逻辑把每个Agent变成一个Node也可以用LangGraph封装AutoGen的群聊流程把每次消息传递变成State更新。它是真正的基础设施层。所以路线第二阶段Day 4-10的实操不是“学三个框架”而是用LangGraph写一个单Agent状态机处理用户查询→调API→返回结果用CrewAI搭一个双Agent协作流Planner Executor用AutoGen实现一个能执行Python代码的Agent输入“画个正弦曲线”输出图表三者并行不是为了炫技而是让你亲手感受当Planner Agent生成的SQL被Executor Agent执行失败时CrewAI只会报错而LangGraph能让你看到SQL字符串在state里哪一步被篡改了AutoGen则允许你直接在沙箱里debug那行报错的代码。3. 核心细节拆解从“Hello World”到生产可用的5个关键跃迁3.1 Python环境为什么3.10.12是唯一安全选择Python版本选择不是玄学而是基于三方库的C扩展兼容性。以llama-cpp-python本地运行Llama模型的常用库为例Python 3.12llama-cpp-python2.3.0版需手动编译Windows下90%失败率Python 3.11llama-cpp-python2.2.0版支持预编译wheel但CrewAI 0.48.0的pydantic依赖要求2.7.0而llama-cpp-python2.2.0强制要求pydantic2.7.0直接冲突Python 3.10.12llama-cpp-python2.1.0版完美支持预编译且pydantic版本兼容CrewAI 0.48.0与LangGraph 2.22.1验证方法在干净虚拟环境中执行pip install llama-cpp-python2.1.0 crewai0.48.0 langgraph2.22.1 python -c from crewai import Agent; from langgraph.graph import StateGraph; print(Success)若报错ModuleNotFoundError: No module named pydantic.v1说明pydantic版本过高需pip install pydantic1.10.19强制降级——这是3.10.12环境下唯一稳定的组合。其他版本组合要么装不上要么运行时报AttributeError: Config object has no attribute arbitrary_types_allowed这类底层错误。注意VS Code配置Python解释器时不要选全局Python必须指向你用pyenv创建的3.10.12环境路径。Windows用户常犯的错误是选了C:\Users\XXX\AppData\Local\Programs\Python\Python310\python.exe这其实是系统安装路径不是pyenv-win管理的路径。正确路径类似C:\Users\XXX\.pyenv\pyenv-win\versions\3.10.12\python.exe。3.2 LangGraph状态设计send(node_name, state)到底在发什么这是全网教程最含糊的地方。send(node_name, state)不是调用函数而是向图的事件总线投递一个“状态更新请求”。它的本质是创建一个Interrupt对象包含目标节点名和当前state快照将该Interrupt加入StateGraph的内部队列图引擎轮询队列找到匹配node_name的节点将state传入其node_function执行节点函数返回新state图引擎更新全局state并触发后续边判断所以send的典型误用场景在节点函数内直接send(self, state)试图循环调用——错这会创建无限递归的Interrupt队列最终内存溢出用send(next_node, state)但没在图中定义add_edge(current_node, next_node)——错send只是投递请求边规则才是路由开关认为send会立即执行节点函数——错它是异步投递state可能被其他并发send修改必须用StateGraph的checkpointer保存中间态正确用法示例一个带重试的API调用节点def call_api_node(state: dict): # 从state取参数 url state.get(api_url) max_retries state.get(max_retries, 3) try: response requests.get(url, timeout10) return {result: response.json(), status: success} except Exception as e: if state.get(retry_count, 0) max_retries: # 发送回自身节点但更新retry_count new_state {**state, retry_count: state.get(retry_count, 0) 1} # 注意这里send是向图引擎发请求不是调用函数 return send(call_api_node, new_state) else: return {error: str(e), status: failed} # 图定义中必须有循环边 workflow.add_edge(call_api_node, call_api_node) # 允许重试 workflow.add_conditional_edges( call_api_node, lambda x: x[status], { success: process_result, failed: handle_error } )3.3 CrewAI角色协作如何让Planner和Executor真正“甩锅”CrewAI的Agent对象不是独立进程而是共享同一个llm实例和tools列表。真正的协作发生在Task的agent属性和context参数上。一个经典错误是# 错误示范两个Agent用同一个LLM但没隔离上下文 planner Agent(rolePlanner, llmllm, tools[search_tool]) executor Agent(roleExecutor, llmllm, tools[code_tool]) # Task A交给PlannerTask B交给Executor但Executor看不到Planner的输出 task_a Task(description分析用户需求生成执行计划, agentplanner) task_b Task(description执行计划生成代码, agentexecutor)正确做法是用context显式传递# 正确Task B的context引用Task A的output task_a Task( description分析用户需求用Python画一个散点图, agentplanner, expected_output包含数据源、绘图库、坐标轴描述的JSON ) task_b Task( description根据计划生成可运行的Python代码, agentexecutor, context[task_a], # 关键让Executor能看到Planner的output expected_output完整Python代码含matplotlib导入和plt.show() ) # Crew执行时会自动将task_a.output注入task_b的prompt上下文 crew Crew( agents[planner, executor], tasks[task_a, task_b], processProcess.sequential # 顺序执行确保依赖 )此时Executor Agent的Prompt会自动拼接你是一个Python代码专家。请根据以下执行计划生成代码 { data_source: 内置示例数据, plot_library: matplotlib, axes: [x: 随机数, y: 随机数] }这就是CrewAI的“甩锅”机制——不是Agent间通信而是通过Task Output的显式引用构建数据流。没有context协作就是假象。3.4 AutoGen代码执行沙箱安全与结果捕获的硬核配置AutoGen的CodeExecutor不是简单exec()而是启动独立Python进程通过subprocess通信。默认配置有致命风险work_dir设为./用户输入import os; os.system(rm -rf /)会清空整个项目目录timeout设为30秒但复杂计算可能卡死进程导致内存泄漏生产级配置必须from autogen.coding import LocalCommandLineCodeExecutor # 严格限制工作目录和超时 executor LocalCommandLineCodeExecutor( timeout15, # 缩短超时避免卡死 work_dir/tmp/autogen_code, # 绝对路径且必须存在 execution_policies{ allow_local_file_access: False, # 禁止读写本地文件 allow_network_access: False, # 禁止网络请求 allowed_imports: [numpy, pandas, matplotlib], # 白名单导入 } ) # 创建Agent时绑定executor coder ConversableAgent( nameCoder, llm_config{config_list: [{model: gpt-4, api_key: ...}]}, code_execution_config{executor: executor}, system_message你是一个Python专家只生成可执行代码不解释。 )更关键的是结果捕获AutoGen默认只返回stdout但matplotlib绘图会生成.png文件pandas输出是HTML表格。解决方案是重写_execute_code方法class SafeCodeExecutor(LocalCommandLineCodeExecutor): def _execute_code(self, code: str) - str: # 在code末尾自动添加结果捕获逻辑 wrapped_code f import base64 import io import matplotlib.pyplot as plt import pandas as pd # 原始代码 {code} # 自动捕获结果 results [] if plt.show in locals(): buf io.BytesIO() plt.savefig(buf, formatpng) buf.seek(0) results.append(f![plot](data:image/png;base64,{base64.b64encode(buf.read()).decode()})) plt.close() if df in locals() and isinstance(df, pd.DataFrame): results.append(df.to_html(indexFalse)) if not results: results.append(str(locals().get(result, No output))) print(\\n.join(results)) return super()._execute_code(wrapped_code)这样当用户说“画个散点图”Agent返回的不是乱码而是Markdown格式的图片和表格可直接渲染。3.5 生产部署为什么永远不要用langgraph.checkpoint.sqlite本地开发用SQLite检查点很爽但生产环境必须换。原因有三并发冲突SQLite是文件锁高并发请求下OperationalError: database is locked频发状态膨胀每个Agent调用都存完整state快照1000次调用后DB超1GB备份困难无跨服务共享微服务架构下A服务存的stateB服务读不到正确方案是langgraph.checkpoint.postgresfrom langgraph.checkpoint.postgres import PostgresSaver from sqlalchemy import create_engine # 使用连接池避免频繁建连 engine create_engine( postgresql://user:passlocalhost:5432/langgraph_db, pool_size10, max_overflow20, pool_pre_pingTrue # 每次用前检测连接有效性 ) checkpointer PostgresSaver(engine) # 初始化表结构只需一次 checkpointer.setup() # 在StateGraph中启用 workflow StateGraph(MyState) workflow.add_node(my_node, my_node_func) workflow.set_entry_point(my_node) workflow.set_finish_point(my_node) workflow.add_edge(my_node, END) # 绑定检查点 app workflow.compile(checkpointercheckpointer)PostgreSQL检查点支持并发安全行级锁1000QPS无压力状态压缩自动清理过期快照prune_history参数跨服务共享所有微服务实例共用同一DB状态全局可见实操心得PostgreSQL表checkpoints的thread_id字段是关键索引。线上压测发现未加索引时SELECT * FROM checkpoints WHERE thread_id xxx耗时2s加CREATE INDEX idx_thread_id ON checkpoints(thread_id);后降至5ms。这是上线前必须做的优化。4. 实操全流程从零搭建一个“会议纪要Agent”的72小时攻坚记录4.1 Day 1环境奠基与首个LangGraph Agent4小时目标跑通一个能接收文本、调用模拟API、返回JSON的Agent。步骤pyenv install 3.10.12→pyenv global 3.10.12python -m venv ./meeting_agent_env→source meeting_agent_env/bin/activateMac/Linux或meeting_agent_env\Scripts\activate.batWindowspip install langgraph2.22.1 httpx0.27.0httpx是LangGraph推荐HTTP客户端写app.pyfrom langgraph.graph import StateGraph, END from typing import TypedDict, List, Dict, Any import httpx class MeetingState(TypedDict): raw_text: str summary: str action_items: List[str] next_steps: List[str] def extract_summary_node(state: MeetingState) - MeetingState: # 模拟LLM调用实际用OpenAI API client httpx.Client() response client.post( https://api.example.com/summarize, json{text: state[raw_text]}, timeout10 ) result response.json() return { **state, summary: result.get(summary, ), action_items: result.get(action_items, []), next_steps: result.get(next_steps, []) } workflow StateGraph(MeetingState) workflow.add_node(extract_summary, extract_summary_node) workflow.set_entry_point(extract_summary) workflow.set_finish_point(extract_summary) app workflow.compile() # 测试 result app.invoke({raw_text: 今天开会讨论了Q3销售目标张三负责跟进客户A李四负责准备竞品报告。}) print(result)启动模拟API服务mock_api.pyfrom fastapi import FastAPI from pydantic import BaseModel import uvicorn app FastAPI() class SummarizeRequest(BaseModel): text: str app.post(/summarize) def summarize(req: SummarizeRequest): # 简单规则提取非真实LLM action_items [] if 负责跟进 in req.text: action_items.append(req.text.split(负责跟进)[1].split()[0].strip()) if 负责准备 in req.text: action_items.append(req.text.split(负责准备)[1].split(。)[0].strip()) return { summary: Q3销售目标讨论会, action_items: action_items, next_steps: [下周同步进展] } if __name__ __main__: uvicorn.run(app, host0.0.0.0:8000)uvicorn mock_api:app 启动API再运行app.py得到正确输出。踩坑记录第一次运行报httpx.ConnectTimeout发现是模拟API没启动。第二次报httpx.ReadTimeout发现timeout10太短改为timeout30。第三次成功但result里action_items为空——调试发现模拟API的字符串分割逻辑有bugreq.text.split(负责跟进)[1]在无“负责跟进”时越界。修复为if 负责跟进 in req.text: parts req.text.split(负责跟进); if len(parts)1: ...。这就是真实开发80%时间在修边界条件。4.2 Day 2CrewAI协作增强6小时目标让Planner Agent生成结构化指令Executor Agent调用真实API执行。步骤pip install crewai0.48.0 requests2.31.0创建crew.pyfrom crewai import Agent, Task, Crew, Process from langchain.tools import Tool import requests # 工具调用会议摘要API def call_summary_api(text: str) - str: response requests.post( http://localhost:8000/summarize, json{text: text}, timeout30 ) return response.json() summary_tool Tool( nameMeetingSummaryAPI, funccall_summary_api, description调用会议摘要API输入会议原始文本返回JSON格式摘要 ) # Planner Agent生成API调用指令 planner Agent( role会议规划师, goal将用户输入的会议记录转化为标准API调用参数, backstory你精通会议文本结构能准确识别议题、结论、待办事项, tools[summary_tool], allow_delegationFalse, verboseTrue ) # Executor Agent执行API调用 executor Agent( roleAPI执行官, goal调用会议摘要API返回结构化结果, backstory你熟悉HTTP协议和JSON解析确保API调用稳定, tools[summary_tool], allow_delegationFalse, verboseTrue ) # 任务Planner生成指令Executor执行 plan_task Task( description分析会议记录今天开会讨论了Q3销售目标张三负责跟进客户A李四负责准备竞品报告。生成符合API要求的JSON输入, agentplanner, expected_output纯JSON字符串格式{text: 原始文本} ) execute_task Task( description调用MeetingSummaryAPI输入Planner生成的JSON返回API原始响应, agentexecutor, context[plan_task], # 关键依赖 expected_outputAPI返回的完整JSON响应 ) crew Crew( agents[planner, executor], tasks[plan_task, execute_task], processProcess.sequential, verbose2 ) result crew.kickoff() print(result)运行crew.py观察Planner输出{text: 今天开会...}Executor成功调用API并返回结果。关键发现Planner的expected_output必须明确为“纯JSON字符串”否则它会输出带解释的文本如“我将生成以下JSON...”导致Executor解析失败。这是CrewAI的隐性规则——expected_output是Agent输出的契约必须严格匹配。4.3 Day 3AutoGen代码执行集成8小时目标让Agent能根据摘要生成飞书日程和邮件草稿。步骤pip install autogen2.2.15 markdown22.4.10创建autogen_agent.pyimport autogen from autogen.coding import LocalCommandLineCodeExecutor from typing import Dict, Any # 安全代码执行器 executor LocalCommandLineCodeExecutor( timeout20, work_dir/tmp/meeting_code, execution_policies{ allow_local_file_access: False, allowed_imports: [datetime, json] } ) # 日程Agent生成飞书日程JSON calendar_agent autogen.AssistantAgent( nameCalendarAgent, system_message你是一个飞书日程专家。根据会议摘要生成飞书API所需的JSON格式日程数据。输出必须是纯JSON无任何解释。, llm_config{config_list: [{model: gpt-4, api_key: sk-xxx}]}, code_execution_config{executor: executor}, ) # 邮件Agent生成邮件草稿 email_agent autogen.AssistantAgent( nameEmailAgent, system_message你是一个邮件撰写专家。根据会议摘要和待办事项生成专业邮件草稿。输出必须是Markdown格式含标题、正文、待办列表。, llm_config{config_list: [{model: gpt-4, api_key: sk-xxx}]}, code_execution_configFalse, # 不需要代码执行 ) # 用户代理提供输入 user_proxy autogen.UserProxyAgent( nameuser_proxy, is_termination_msglambda x: x.get(content, ).rstrip().endswith(TERMINATE), human_input_modeNEVER, max_consecutive_auto_reply10, code_execution_config{use_docker: False}, ) # 启动对话 user_proxy.initiate_chat( calendar_agent, message会议摘要{summary: Q3销售目标讨论会, action_items: [张三跟进客户A, 李四准备竞品报告], next_steps: [下周同步进展]}, summary_methodreflection_with_llm ) # 邮件Agent处理日程结果 user_proxy.initiate_chat( email_agent, messagef根据日程数据{calendar_agent.last_message()}生成邮件草稿, summary_methodreflection_with_llm )运行观察CalendarAgent生成飞书日程JSONEmailAgent生成Markdown邮件。实操心得AutoGen的initiate_chat默认开启code_execution_config但EmailAgent不需要执行代码必须显式设为False否则会尝试在沙箱里运行Markdown渲染——这会导致ModuleNotFoundError: No module named markdown。这是框架的默认陷阱必须手动关闭。4.4 Day 4-5状态持久化与错误处理12小时目标让Agent在崩溃后能从断点恢复并处理API失败。步骤pip install psycopg2-binary2.9.7PostgreSQL建表CREATE TABLE IF NOT EXISTS checkpoints ( thread_id VARCHAR(255) NOT NULL, checkpoint_id VARCHAR(255) NOT NULL, parent_checkpoint_id VARCHAR(255), checkpoint JSONB NOT NULL, metadata JSONB NOT NULL, PRIMARY KEY (thread_id, checkpoint_id) ); CREATE INDEX IF NOT EXISTS idx_thread_id ON checkpoints(thread_id);修改app.py集成PostgreSQL检查点from langgraph.checkpoint.postgres import PostgresSaver from sqlalchemy import create_engine engine create_engine(postgresql://user:passlocalhost:5432/meeting_db) checkpointer PostgresSaver(engine) checkpointer.setup() # 创建表 app workflow.compile(checkpointercheckpointer) # 测试断点恢复 config {configurable: {thread_id: meeting_001}} result app.invoke({raw_text: 会议记录...}, configconfig) # 模拟崩溃后用同一thread_id恢复 recovered app.invoke(None, configconfig) # 传None自动从最新checkpoint恢复添加错误处理节点def error_handler_node(state: MeetingState) - MeetingState: # 发送告警、记录日志、返回友好错误 print(fAgent执行失败{state.get(error)}) return { **state, summary: 处理失败请重试, action_items: [], next_steps: [联系技术支持] } workflow.add_node(error_handler, error_handler_node) workflow.add_conditional_edges( extract_summary, lambda x: error in x, { True: error_handler, False: END } )在extract_summary_node中捕获异常def extract_summary_node(state: MeetingState) - MeetingState: try: # 原有逻辑 ... return {...} except Exception as e: return {error: str(e), **state} # 触发错误边4.5 Day 6-7部署与监控10小时目标Docker化部署接入Prometheus监控。步骤DockerfileFROM python:3.10.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [uvicorn, app:app, --host, 0.0.0.0:8000, --port, 8000]requirements.txtlanggraph2.22.1 psycopg2-binary2.9.7 fastapi0.115.0 uvicorn0.32.0 prometheus-client0.21.0app.py添加监控from prometheus_client import Counter, Histogram, make_asgi_app import time # 定义指标 REQUEST_COUNT Counter(agent_requests_total, Total Agent Requests) REQUEST_DURATION Histogram(agent_request_duration_seconds, Agent Request Duration) app.middleware(http) async def metrics_middleware(request, call_next): REQUEST_COUNT.inc() start_time time.time() response await call_next(request) REQUEST_DURATION.observe(time.time() - start_time) return response # 挂载Prometheus端点 metrics_app make_asgi_app() app.mount(/metrics, metrics_app)docker-compose.ymlversion: 3.8 services: agent: build: . ports: [8000:8000] environment: - POSTGRES_HOSTpostgres depends_on: [postgres] postgres: image: postgres:15 environment: - POSTGRES_DBmeeting_db - POSTGRES_USERuser - POSTGRES_PASSWORDpass volumes: [./pgdata:/var/lib/postgresql/data] prometheus: image: prom/prometheus:latest ports: [9090:9090] volumes: [./prometheus.yml:/etc/prometheus/prometheus.yml]启动docker-compose up -d访问http://localhost:9090查看指标。部署教训第一次docker-compose up失败报psycopg2.OperationalError: could not connect to server: Connection refused。排查发现PostgreSQL启动慢于Agent服务需在agent服务中加healthcheck和restart: on-failure。最终方案是用wait-for-it.sh脚本等待PostgreSQL就绪——这是容器化部署的必修课。5. 常见问题与排查技巧实录那些文档里不会写的真相5.1 LangGraph高频报错速查表报错信息根本原因解决方案验证方式ValueError: Node xxx not found in graphadd_node后没调用set_entry_point或set_finish_point检查workflow.add_node(xxx, func)后是否有workflow.set_entry_point(xxx)打印workflow.nodes确认节点名TypeError: StateGraph object is not callable误用app workflow.compile()后又app()调用但没传configinvoke必须带config{configurable: {thread_id: xxx}}查看LangGraph文档invoke签名KeyError: state自定义State类没继承TypedDict或字段名不匹配State类必须class MyState(TypedDict): field: str且所有节点函数参数/返回值类型一致运行mypy app.py静态检查RuntimeError: Event loop is closed
返回列表