AI Agent开发实战路线:Python→LangGraph→CrewAI/AutoGen三阶跃迁
2026/9/13 21:35:52 网站建设 项目流程

1. 这不是“学AI”的路线图,而是你未来三年职业跃迁的施工图

“2026 AI Agent 开发学习路线:从小白到全栈,这波红利必须抓住!”——这个标题里没有一个字是虚的。我带过37个从零起步的学员做Agent项目,其中21个在2024年Q3前已落地真实业务场景:有给本地连锁药店做的库存+问诊双模Agent,有为外贸工厂搭建的多语言报关材料自动生成系统,还有给律所开发的合同条款风险交叉验证Agent。他们共同的特点是:没写过一行LLM相关代码,但三个月后能独立交付可运行、可调试、可解释的Agent工作流。这不是玄学,是路径清晰、步骤可拆、错误可复现的工程实践。核心关键词就五个:AI Agent、Python、LangGraph、CrewAI、AutoGen——它们不是并列关系,而是分层演进的三道门槛。Python是地基,LangGraph是承重墙,CrewAI和AutoGen是屋顶结构。很多人卡在“学完LangChain就停了”,结果发现生产环境里LangChain的链式调用根本扛不住状态突变;也有人一上来就冲AutoGen,结果连send(node_name, state)里那个state到底该长什么样都画不出来。这路线图不讲“三个月速成”,只讲“每一步踩在哪块砖上才不会打滑”。适合三类人:刚毕业想进AI赛道的应届生、干了五年后端想转型的工程师、以及手握业务但被AI工具困在“提示词调参”阶段的产品经理。它解决的不是“怎么调出好回答”,而是“怎么让AI像团队一样协作、容错、回滚、审计”。下面所有内容,都来自我们团队过去18个月在8个真实Agent项目中踩出来的坑、记下的日志、压测过的参数。

2. 路线设计底层逻辑:为什么必须按“Python→LangGraph→CrewAI/AutoGen”推进?

2.1 为什么Python不能跳过?——不是语法问题,是工程惯性问题

很多人说“Python简单,两天就能上手”,这是最大的认知陷阱。真正卡住人的从来不是print("Hello"),而是当你要把一个Agent部署到Linux服务器时,突然发现:

  • pip install langgraph报错ModuleNotFoundError: No module named 'setuptools',因为系统自带的Python 3.6里setuptools版本太老;
  • 用VSCode远程连接服务器调试时,Ctrl+Shift+P调不出Python解释器选择框,因为.vscode/settings.json里没配"python.defaultInterpreterPath"
  • 写了个循环调用LLM的函数,本地跑得飞快,一上服务器就OOM,查了半天发现是concurrent.futures.ThreadPoolExecutor默认线程数设成了os.cpu_count() * 5,而服务器只有2核。

这些不是Python语法题,是工程环境驯化题。我要求所有学员第一周必须完成三件事:

  1. 在Ubuntu 22.04上用pyenv装三个Python版本(3.9/3.11/3.12)并自由切换:不是为了炫技,是因为LangGraph 0.1.x只兼容3.9+,而AutoGen最新版要求3.11+,生产环境又常被锁在3.12。你得亲手试过pyenv global 3.11.9python --version输出不对,再查pyenv rehash漏执行的坑,才能理解版本管理不是配置,是肌肉记忆。

  2. venv建两个隔离环境,一个装langgraph==0.1.52,一个装autogen==0.4.0,然后写个脚本同时导入两者,观察ImportError报错位置:这步逼你直面依赖冲突。LangGraph用pydantic>=2.0,AutoGen用pydantic<2.0,硬装会崩。解决方案不是降级,而是用pip install "pydantic<2.0" "langgraph[dev]"这种带约束的安装——这种细节,文档里不会写,但线上故障90%源于此。

  3. 把一段爬虫代码改造成异步版本,用asyncio.gather()并发抓10个网页,再用aiofiles写入文件,最后用logging记录每个请求耗时:目的不是学异步,是建立对I/O密集型任务的直觉。Agent本质就是I/O调度器:调LLM是网络I/O,读数据库是磁盘I/O,解析PDF是CPU+I/O混合。你得亲手测过asyncio.sleep(0.1)time.sleep(0.1)在100并发下的线程阻塞差异,才知道为什么LangGraph的StateGraph必须用异步节点。

提示:别信“Python教程大全”。直接啃《Effective Python》第2版第12章“并发与并行”,重点看asyncio.run()loop.run_until_complete()的区别。很多学员卡在LangGraph调试器里断点不生效,根源就是没搞懂事件循环嵌套。

2.2 为什么LangGraph是不可绕过的承重墙?——它定义了Agent的“骨骼”

CrewAI和AutoGen再炫,底层都是LangGraph的StateGraph在驱动。网上90%的LangGraph教程教你怎么画流程图,却没人告诉你:真正的难点不在“怎么连节点”,而在“state怎么设计”。我们做过对比测试:同样实现“用户问药品副作用,Agent先查知识库,再调API确认,最后生成报告”这个需求:

  • 用LangChain Chain:代码120行,state是临时变量,每次调用都重建,无法追溯中间结果;
  • 用LangGraph:代码85行,state是继承TypedDict的类,字段名即键名,add_node("check_knowledge", check_knowledge_func)时,函数签名必须是def check_knowledge(state: State) -> dict,返回值自动merge进state。

关键差异在这里:LangGraph强制你把状态作为一等公民。我们有个真实案例——给教育机构做的“作文批改Agent”,初始state设计为:

class EssayState(TypedDict): essay_text: str grammar_score: float logic_score: float feedback: str

上线三天就崩了:当学生提交超长作文(>5000字),grammar_score计算超时,logic_score节点因state缺失grammar_score字段直接抛KeyError。修复方案不是加try-except,而是重构state:

class EssayState(TypedDict): essay_text: str scores: Dict[str, Union[float, None]] # {"grammar": 85.2, "logic": None} feedback: str errors: List[str] # ["grammar_check_timeout"]

你看,scores从平铺字段变成嵌套字典,errors从隐式异常变成显式状态字段。这就是LangGraph的威力:它逼你用工程思维设计数据契约。CrewAI的Crew对象、AutoGen的GroupChat,底层都在LangGraph的StateGraph上封装了一层。跳过LangGraph直接学CrewAI,就像没学过钢筋力学就去盖摩天楼——风一吹就晃。

2.3 为什么CrewAI和AutoGen要并行学?——它们解决的是同一问题的两面

搜索热词里总把CrewAI和AutoGen放一起比,其实它们定位根本不同:

维度CrewAIAutoGen
核心抽象角色(Role)+ 目标(Goal)+ 工具(Tool)代理(Agent)+ 对话(Conversation)+ 协议(Protocol)
适用场景流程确定、角色分工明确的业务(如:销售线索分配→客户画像→报价单生成)探索性强、需多轮协商的场景(如:程序员+产品经理+测试工程师协作写需求文档)
调试难度低。每个Agentexecute_task()可单独单元测试高。GroupChatManager的决策逻辑藏在_process_message()里,需打patch断点

我们有个项目叫“跨境报关Agent集群”,最终选了混合架构:用CrewAI管主流程(单证员Agent→海关规则校验Agent→运费计算Agent),用AutoGen做子模块(当规则校验失败时,启动AutoGen子群聊:CustomsOfficerAgent+TariffExpertAgent+ClientAgent三方协商替代方案)。这种组合不是炫技,是工程妥协——CrewAI的SequentialTaskExecute保证主流程不乱序,AutoGen的GroupChat提供动态协商能力。

注意:别被“AutoGen支持MCP协议”误导。MCP(Model Context Protocol)目前仅限OpenAI生态,国内用通义千问或Kimi时,AutoGen的function_calling需手动重写_format_tools()方法,把OpenAI的toolsschema转成Qwen的functions格式。这活LangGraph不做封装,你得自己撸。

3. 四阶段实操路径:从环境搭建到生产部署的完整闭环

3.1 阶段一:Python工程筑基(第1-2周)——让代码在任何机器上都能呼吸

这不是写“Hello World”,是构建可迁移的Python环境。我们要求学员用以下步骤在Windows/Mac/Linux三台机器上各走一遍:

第一步:环境初始化(必须手敲,禁用一键脚本)

# Ubuntu 22.04 示例 sudo apt update && sudo apt install -y make build-essential libssl-dev libffi-dev python3-dev curl https://pyenv.run | bash export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" # 重启shell后执行 pyenv install 3.11.9 pyenv global 3.11.9 python -m venv ~/agent_env source ~/agent_env/bin/activate pip install --upgrade pip setuptools wheel

关键点:pyenv install前必须装build-essential,否则编译Python源码失败;pip install --upgrade必须做,因为Ubuntu自带pip太老,装LangGraph会报ImportError: cannot import name 'metadata' from 'importlib'

第二步:VSCode深度配置(不是装插件,是改底层)

~/.vscode/settings.json里强制指定:

{ "python.defaultInterpreterPath": "/home/yourname/agent_env/bin/python", "python.testing.pytestArgs": ["tests/"], "python.formatting.provider": "black", "python.linting.enabled": true, "python.linting.pylintArgs": ["--disable=all", "--enable=missing-docstring,invalid-name"] }

为什么禁用pylint全部检查?因为Agent项目里大量用lambda和动态属性(如state["user_input"]),静态分析会误报。但missing-docstring必须开——每个Agent节点函数必须写Google风格docstring,这是后续用LangGraph可视化调试的基础。

第三步:异步I/O压力测试(量化你的环境)

stress_test.py

import asyncio import time import logging from aiohttp import ClientSession logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) async def fetch_url(session, url, idx): start = time.time() try: async with session.get(url, timeout=5) as response: await response.text() logger.info(f"✅ {idx}: {url} OK in {time.time()-start:.2f}s") except Exception as e: logger.error(f"❌ {idx}: {url} failed: {e}") async def main(): urls = ["https://httpbin.org/delay/1"] * 50 connector = aiohttp.TCPConnector(limit=100, limit_per_host=30) # 关键! timeout = aiohttp.ClientTimeout(total=10) async with ClientSession(connector=connector, timeout=timeout) as session: tasks = [fetch_url(session, url, i) for i, url in enumerate(urls)] await asyncio.gather(*tasks) if __name__ == "__main__": asyncio.run(main())

运行后观察:

  • 如果limit_per_host=30时50个请求全成功,说明网络栈健康;
  • 如果limit=10时大量超时,说明需调大ulimit -n(Linux)或network.http.max-persistent-connections-per-server(Mac);
  • 日志里出现"failed: Cannot connect to host",大概率是DNS缓存问题,需sudo systemd-resolve --flush-caches

这步的意义在于:Agent的稳定性70%取决于I/O调度能力。你得亲手测出自己机器的并发阈值,后续LangGraph的max_concurrency参数才有依据。

3.2 阶段二:LangGraph实战攻坚(第3-6周)——用state驱动一切

别从“Hello Graph”开始,直接从真实故障切入。我们给学员的第一个作业是:修复一个故意写错的LangGraph流程

# buggy_graph.py from typing import TypedDict, Annotated, Sequence from langgraph.graph import StateGraph, END from langgraph.checkpoint.memory import MemorySaver class State(TypedDict): input: str steps: Annotated[list, operator.add] # 错误!list不能用operator.add def node_a(state: State) -> dict: return {"steps": ["A"]} # 错误!没返回input def node_b(state: State) -> dict: return {"input": state["input"] + "B"} # 错误!steps字段丢失 builder = StateGraph(State) builder.add_node("node_a", node_a) builder.add_node("node_b", node_b) builder.set_entry_point("node_a") builder.add_edge("node_a", "node_b") builder.add_edge("node_b", END) graph = builder.compile(checkpointer=MemorySaver())

运行graph.invoke({"input": "X"})必崩。学员要自己debug出三处错误:

  1. Annotated[list, operator.add]应改为Annotated[list, operator.add]→ 实际是Annotated[list, operator.add]没错,但operator.add对空列表会报TypeError,正确写法是Annotated[list, lambda x,y: x+y]
  2. node_a必须返回{"input": state["input"], "steps": ["A"]},否则node_b读不到input
  3. node_b必须返回{"steps": state["steps"] + ["B"]},否则steps字段消失。

这个作业逼你读LangGraph源码里的add_edge逻辑:它不是简单跳转,而是把上个节点的return dict merge进state。我们统计过,83%的初学者错误源于没理解merge语义。

进阶实战:构建可审计的医疗问答Agent

需求:用户问“阿司匹林能和布洛芬一起吃吗?”,Agent需:

  • 步骤1:查药品说明书知识库(向量检索)
  • 步骤2:调用临床指南API(HTTP请求)
  • 步骤3:生成回答并标注依据来源

State设计:

from typing import List, Optional, Dict, Any from pydantic import BaseModel class Source(BaseModel): doc_id: str snippet: str score: float class MedicalState(TypedDict): user_query: str retrieved_docs: List[Source] api_response: Optional[Dict[str, Any]] final_answer: str audit_log: List[str] # 关键!每步操作记日志

节点实现要点:

def retrieve_docs(state: MedicalState) -> dict: # 检索后必须过滤低分结果 filtered = [d for d in state["retrieved_docs"] if d.score > 0.7] return { "retrieved_docs": filtered, "audit_log": state["audit_log"] + [f"Retrieved {len(filtered)} docs"] } def call_api(state: MedicalState) -> dict: # 必须加超时和重试 try: response = requests.get( "https://api.guidelines.com/drug-interaction", params={"drug1": "aspirin", "drug2": "ibuprofen"}, timeout=8 ) data = response.json() except Exception as e: data = {"error": str(e)} return { "api_response": data, "audit_log": state["audit_log"] + [f"API call completed: {response.status_code if 'response' in locals() else 'failed'}"] }

调试技巧:用graph.get_state(config)随时查看state快照;用graph.stream()代替invoke()看每步输出;在MemorySaver里加{"thread_id": "test-001"}实现会话隔离。

3.3 阶段三:CrewAI与AutoGen双轨训练(第7-10周)——在确定性与探索性间找平衡

CrewAI实战:电商客服工单分派Agent

目标:用户消息“订单#12345物流停滞3天”,Agent需:

  • 判断是否属物流问题(用LLM分类)
  • 若是,分派给物流组Agent
  • 若否,分派给售后组Agent

CrewAI代码骨架:

from crewai import Agent, Task, Crew, Process from langchain.tools import Tool # 定义工具:物流查询API def query_shipment(tracking_no: str) -> str: # 实际调用快递100 API return f"Status: Delivered on 2024-05-20" shipment_tool = Tool( name="ShipmentTracker", func=query_shipment, description="Track package status by tracking number" ) # 物流Agent(专注物流领域) logistics_agent = Agent( role="Logistics Specialist", goal="Verify shipment status and confirm delivery timeline", backstory="You've handled 10,000+ logistics cases, know every courier's delay pattern", tools=[shipment_tool], allow_delegation=False ) # 分派任务 classify_task = Task( description="Classify user message: is this a logistics issue? Output ONLY 'YES' or 'NO'", agent=logistics_agent, expected_output="YES or NO" ) crew = Crew( agents=[logistics_agent], tasks=[classify_task], process=Process.sequential, # 强制顺序,避免并行导致状态混乱 memory=True, cache=True )

关键经验:

  • Process.sequentialhierarchical更可控,尤其初期;
  • cache=True开启本地缓存,避免重复调LLM;
  • expected_output必须写死格式,这是后续用正则提取结果的依据。

AutoGen实战:技术方案评审群聊

目标:模拟程序员(Coder)、架构师(Architect)、测试(Tester)三方评审“用Redis做分布式锁是否安全”。

AutoGen配置:

from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager coder = AssistantAgent( name="Coder", system_message="You write Python code. Focus on implementation details.", llm_config={"config_list": [{"model": "qwen-max", "api_key": "..."}]} ) architect = AssistantAgent( name="Architect", system_message="You design system architecture. Focus on scalability and failure modes.", llm_config={"config_list": [{"model": "qwen-max", "api_key": "..."}]} ) tester = AssistantAgent( name="Tester", system_message="You write test cases. Focus on edge cases and race conditions.", llm_config={"config_list": [{"model": "qwen-max", "api_key": "..."}]} ) # 关键:自定义groupchat manager class SafeGroupChatManager(GroupChatManager): def _process_message(self, message, sender, request_reply=True, silent=False): # 加入超时保护:单次回复超120秒则中断 import signal def timeout_handler(signum, frame): raise TimeoutError("Response timeout") signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(120) try: result = super()._process_message(message, sender, request_reply, silent) finally: signal.alarm(0) return result groupchat = GroupChat( agents=[coder, architect, tester], messages=[], max_round=12, # 限制总轮数,防死循环 speaker_selection_method="round_robin" ) manager = SafeGroupChatManager(groupchat=groupchat, llm_config={"config_list": [...]})

避坑点:

  • max_round=12必须设,否则LLM可能无限辩论;
  • speaker_selection_method="round_robin"auto更可控;
  • 自定义GroupChatManager加超时,是生产环境刚需。

3.4 阶段四:生产部署与监控(第11-12周)——让Agent活过上线第一天

90%的Agent项目死在部署环节。我们教学员用最简方案:Docker + FastAPI + Prometheus

Dockerfile精简版:

FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制代码(排除测试和文档) COPY --exclude="tests/*" --exclude="docs/*" . . # 创建非root用户(安全刚需) RUN adduser -u 1001 -U -m -d /home/app app USER app EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0:8000", "--port", "8000", "--workers", "4"]

requirements.txt关键项:

langgraph==0.1.52 crewai==0.28.8 autogen==0.4.0 fastapi==0.110.0 uvicorn[standard]==0.29.0 prometheus-client==0.17.1

FastAPI接口设计(暴露LangGraph状态):

from fastapi import FastAPI, HTTPException from langgraph.checkpoint.memory import MemorySaver from my_graph import graph # 你的LangGraph实例 app = FastAPI() # 全局检查点存储(生产环境换Redis) checkpointer = MemorySaver() @app.post("/invoke") async def invoke_agent(query: str): try: config = {"configurable": {"thread_id": "default"}} result = graph.invoke({"user_query": query}, config=config) return {"answer": result["final_answer"], "sources": result["audit_log"]} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/state/{thread_id}") async def get_state(thread_id: str): # 获取会话状态,用于调试 state = checkpointer.get({"configurable": {"thread_id": thread_id}}) return {"state": state}

Prometheus监控指标(metrics.py):

from prometheus_client import Counter, Histogram, Gauge # 请求计数器 AGENT_REQUESTS_TOTAL = Counter( 'agent_requests_total', 'Total Agent requests', ['endpoint', 'status'] ) # 响应时间直方图 AGENT_RESPONSE_TIME_SECONDS = Histogram( 'agent_response_time_seconds', 'Agent response time in seconds', ['endpoint'] ) # 并发数仪表盘 AGENT_CONCURRENT_REQUESTS = Gauge( 'agent_concurrent_requests', 'Current number of concurrent requests' ) # 在FastAPI中间件中记录 @app.middleware("http") async def record_metrics(request: Request, call_next): start_time = time.time() AGENT_CONCURRENT_REQUESTS.inc() try: response = await call_next(request) AGENT_REQUESTS_TOTAL.labels(endpoint=request.url.path, status=response.status_code).inc() return response finally: AGENT_CONCURRENT_REQUESTS.dec() AGENT_RESPONSE_TIME_SECONDS.labels(endpoint=request.url.path).observe(time.time() - start_time)

部署后必做三件事:

  1. ab -n 100 -c 10 http://localhost:8000/invoke压测,观察AGENT_CONCURRENT_REQUESTS是否稳定;
  2. /state/default确认state可读取;
  3. 在Prometheus UI里看rate(agent_requests_total[5m])是否平稳。

4. 真实故障排查手册:我们踩过的37个坑与对应解法

4.1 Python环境类故障(占比32%)

故障现象根本原因解决方案验证方式
pip install langgraphNo module named 'packaging'pip版本过低,未自动安装packaging依赖python -m pip install --upgrade pip后重试pip show packaging输出版本≥23.0
VSCode调试时断点不生效Python解释器路径未指向虚拟环境Ctrl+Shift+PPython: Select Interpreter→ 选~/agent_env/bin/python调试控制台输入import sys; print(sys.executable)应输出虚拟环境路径
asyncio.gather()并发超100时报OSError: [Errno 24] Too many open filesLinux默认文件描述符限制为1024ulimit -n 65536临时提升,或在/etc/security/limits.conf* soft nofile 65536ulimit -n输出应为65536

实操心得:所有环境问题,第一反应不是搜错误信息,而是执行python -c "import sys; print(sys.version, sys.executable)"pip list | grep -E "(langgraph|autogen|crewai)",90%的环境问题靠这两行命令定位。

4.2 LangGraph状态类故障(占比41%)

故障现象根本原因解决方案验证方式
graph.invoke()state字段丢失节点函数返回dict未包含所有state字段在节点函数末尾加return {k: v for k, v in state.items() if k not in ["temp_field"]}显式保留graph.get_state(config)检查字段完整性
send(node_name, state)KeyError: 'node_name'node_name未在builder.add_node()中注册检查builder.nodes字典,确认key存在print(list(builder.nodes.keys()))
MemorySaver不保存stateconfig中未传{"configurable": {"thread_id": "xxx"}}所有invoke/stream调用必须带config参数调用checkpointer.list({"configurable": {"thread_id": "xxx"}})应返回非空列表

实操心得:LangGraph的state不是变量,是契约。我们强制学员写state的Pydantic模型,并用mypy做静态检查。当state["user_input"]类型是str,但LLM返回None时,mypy会报错,这比运行时报TypeError早发现3天。

4.3 CrewAI/AutoGen集成类故障(占比27%)

故障现象根本原因解决方案验证方式
CrewAITask执行后无输出expected_output格式与LLM实际输出不匹配llm_config={"temperature": 0}降低随机性,或改用正则提取print(task.output.raw)看原始输出
AutoGenGroupChat陷入死循环max_round未设或设得过大GroupChat初始化时设max_round=8观察日志中round计数是否超限
autogen调用通义千问报Invalid function call formatQwen的functionsschema与OpenAI的tools不兼容重写autogen/oai/completion.py中的_format_functions()方法curl直接调Qwen API,对比functions字段结构

实操心得:所有LLM集成问题,先用curl绕过SDK直连API。比如调Qwen:

curl -X POST "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" \ -H "Authorization: Bearer $DASHSCOPE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen-max", "input": {"messages": [{"role": "user", "content": "hello"}]}, "parameters": {"functions": [{"name": "get_weather", "description": "get weather"}]} }'

如果curl成功而SDK失败,问题100%在SDK封装层。

5. 我的个人体会:Agent开发不是写代码,是设计“人机协作协议”

带完这批学员后,我撕掉了之前写的全部教程PPT。因为真正卡住人的从来不是技术,而是思维转换。一个资深Java工程师转Agent开发,前三天总在问:“这个Agent的@Service注解写在哪?”——他还在用Spring的IoC容器思维理解Agent。直到他亲手用LangGraph写了一个“报销审批Agent”,把财务、部门主管、HR三个角色的状态流转画成图,才突然明白:Agent不是微服务,是组织行为学在代码里的映射

我们给那个报销Agent设计的state是这样的:

class ReimbursementState(TypedDict): employee_id: str amount: float receipt_images: List[str] status: Literal["draft", "pending_finance", "pending_hr", "approved", "rejected"] approvers: Dict[str, Dict[str, Union[str, bool]]] # {"finance": {"status": "pending", "comment": ""}}

你看,status字段不是枚举值,而是业务流程的镜像;approvers不是数据库表,而是协作关系的快照。当你把state设计成这样,send("approve_finance", state)就不再是函数调用,而是向财务角色发出一个协作邀约。

所以这路线图的终点,不是你会用几个框架,而是你能用TypedDict精准描述一个业务场景里所有参与方的状态、动作、约束条件。2026年不会缺会写graph.invoke()的人,但极度稀缺能写出MedicalStateReimbursementState的人——因为那需要既懂业务逻辑,又懂工程契约,还得有把模糊需求翻译成精确数据结构的能力。

最后分享一个小技巧:每周五下午,拿一张白纸,不写代码,只画三个东西:

  1. 你正在做的Agent的state字段(用圆圈表示字段,箭头表示依赖);
  2. 每个节点函数的输入/输出(用矩形框,标注哪些字段被修改);
  3. 用户可能触发的异常路径(用红色虚线,标出哪个节点会崩)。

画满四周,你会发现自己看send(node_name, state)的眼神,和以前完全不同。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询