Showing Posts From

LLM

2026 年 AI Agent 框架选型:LangGraph、Mastra、PydanticAI 对比与 LangGraph 最小实现

框架横向对比(2026)框架 语言 适合场景LangGraph Python 生产环境、多 Agent、长流程Mastra TypeScript Next.js 全栈项目PydanticAI Python FastAPI、结构化输出CrewAI Python 多角色协作 AgentAutoGen Python 研究方向、自动代码执行OpenAI Agents SDK Python 轻量 Tool Calling、OpenAI 为主综合推荐排名:LangGraph > OpenAI Agents SDK > Mastra > PydanticAI > CrewAI > AutoGen LangGraph:生产首选 LangGraph 基于状态机(StateGraph),天然支持:循环图(Think → Act → Observe → Think) Checkpoint 持久化 Multi-Agent(Supervisor / Swarm) Human-in-the-Loop(Interrupt + Resume) 与 Playwright/Browser Use 集成大量生产环境已从 LangChain Agent 迁移至 LangGraph。 LangGraph 最小实现 pip install langgraph langchain-openai langchain-coretools.py: from langchain_core.tools import tool import subprocess@tool def search(query: str) -> str: """搜索信息""" return f"搜索结果: {query}"@tool def shell(command: str) -> str: """执行命令""" try: return subprocess.check_output(command, shell=True, text=True, timeout=5)[:5000] except Exception as e: return str(e)app.py: from typing import TypedDict from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage from tools import search, shellllm = ChatOpenAI(model="gpt-4o") tools = [search, shell] llm_with_tools = llm.bind_tools(tools)class AgentState(TypedDict): messages: listdef agent_node(state): response = llm_with_tools.invoke(state["messages"]) return {"messages": state["messages"] + [response]}def tool_node(state): last = state["messages"][-1] tool_messages = [] for call in last.tool_calls: result = search.invoke(call["args"]) if call["name"] == "search" else shell.invoke(call["args"]) tool_messages.append(ToolMessage(content=str(result), tool_call_id=call["id"])) return {"messages": state["messages"] + tool_messages}def should_continue(state): last = state["messages"][-1] return "tool" if hasattr(last, "tool_calls") and last.tool_calls else ENDgraph = StateGraph(AgentState) graph.add_node("agent", agent_node) graph.add_node("tool", tool_node) graph.set_entry_point("agent") graph.add_conditional_edges("agent", should_continue, {"tool": "tool", END: END}) graph.add_edge("tool", "agent") app = graph.compile()运行: result = app.invoke({"messages": [HumanMessage(content="列出当前目录")]}) print(result["messages"][-1].content)Agent Memory 分级架构 高 Token 消耗的核心问题是全量注入记忆。推荐分三级: L1 工作记忆 → 最近 10~20 条消息,直接进 Prompt L2 任务记忆 → 当前项目/任务相关,按需读取 L3 长期记忆 → 用户偏好、历史经验,向量检索 TopKMemory Router 方案 不让 Memory 全量注入,而是先路由: def memory_router(state): query = state["query"] if "合约" in query: return {"memory_keys": ["web3"]} if "SpringBoot" in query: return {"memory_keys": ["coding", "project"]} return {"memory_keys": []}再根据 memory_keys 去向量库检索 Top-K 相关记忆注入 Prompt。 推荐存储方案 Redis → L1 短期记忆(最近消息、任务状态) pgvector → L2/L3 长期记忆(向量检索) Qdrant → 替代 pgvector(独立向量库)这样单次请求上下文通常能从 50k+ Token 压到 3k~10k Token,且效果往往更好(减少无关记忆干扰)。 OpenClaw 与 LangGraph 的关系 OpenClaw 是一个 Agent Runtime(Agent 操作系统),包含 Gateway(消息入口)、Skills(工具插件)、Memory、Workspace。LangGraph 提供了其中 Agent Loop + Persistence + Multi-Agent 的核心能力,但不负责 Gateway 和 Tool 生态。 用 LangGraph 可以实现 OpenClaw 绝大部分核心功能,真正耗工程量的是:权限系统、Tool 生态、Browser 自动化和可观测性系统。 最小技术栈(个人项目) Next.js / SpringBoot → 前后端 LangGraph → Agent 编排 Redis → 短期记忆 Postgres + pgvector → 长期记忆 Playwright → 浏览器操作 Quartz / @Scheduled → 定时任务

2026 年 AI Agent 框架选谁:LangGraph / Mastra / PydanticAI 对比

2026 年做 AI Agent / 自动化助手 / 工具编排,可选的框架不少。按技术栈和使用场景推荐。 一句话选型场景 / 栈 首选生产级多 Agent、复杂流程 LangGraphNext.js / TypeScript 栈 MastraPython + 类型安全 PydanticAI多角色协作模拟 CrewAI微软生态 AutoGen轻量 + 只用 OpenAI OpenAI Agents SDKLangGraph(生产级首推) LangGraph 是 LangChain 团队的新一代框架——基于状态机而不是 chain,比传统 LangChain Agent 稳定很多。 核心概念:一个 Agent 是一张有向图,节点是"要做什么",边是"下一步去哪儿"。 from langgraph.graph import StateGraphdef planner(state): return {"plan": llm(state["query"])}def executor(state): return {"result": tool_call(state["plan"])}graph = StateGraph(dict) graph.add_node("plan", planner) graph.add_node("execute", executor) graph.add_edge("plan", "execute") graph.set_entry_point("plan") app = graph.compile()app.invoke({"query": "帮我订机票"})优势:显式状态机、执行流程可视化 支持 Human-in-the-Loop(中断、审核、恢复) 支持 checkpoint 持久化 复杂 workflow 也能表达 生产环境案例最多——很多公司已经从 LangChain Agent 迁到 LangGraph缺点:学习曲线不低,Python + TS 双语言。 Mastra(Next.js 生态首选) Mastra 是全 TypeScript 的 Agent 框架,跟 Vercel AI SDK 生态贴合。 import { Agent } from "@mastra/core"; import { openai } from "@ai-sdk/openai";const agent = new Agent({ name: "Assistant", model: openai("gpt-5"), tools: [webSearch, calculator], });const result = await agent.text("北京今天多少度?");优势:TS 全栈,类型贯穿 Agent / Workflow / Memory / RAG 一站式 部署到 Vercel / Cloudflare Workers 都方便 学习曲线比 LangGraph 低适合:Next.js 项目里直接嵌 Agent、Vercel/Cloudflare 部署、快速迭代。 PydanticAI(Python 类型党) PydanticAI 是 Pydantic 团队做的——Structured Output 特别强,走类型驱动。 from pydantic_ai import Agent from pydantic import BaseModelclass Answer(BaseModel): city: str temp: float condition: stragent = Agent("openai:gpt-5", result_type=Answer)result = agent.run_sync("北京今天多少度?") print(result.data.city, result.data.temp) # 强类型输出优势:输出直接是 Pydantic 模型,编辑器自动补全 支持 OpenAI / Anthropic / Google / Ollama 依赖注入优雅 适合科研 / 数据分析 / 代码 AgentCrewAI(多 Agent 协作) CrewAI 把 Agent 组织成"团队",每个 Agent 有角色: from crewai import Agent, Task, Crewresearcher = Agent(role="研究员", goal="找资料") writer = Agent(role="写作", goal="写报告") reviewer = Agent(role="审校", goal="审核")task1 = Task(description="研究 xxx", agent=researcher) task2 = Task(description="写报告", agent=writer) task3 = Task(description="审核", agent=reviewer)crew = Crew(agents=[researcher, writer, reviewer], tasks=[task1, task2, task3]) crew.kickoff()适合:复杂业务流程模拟——产品-开发-测试-运维流水线;市场调研 → 分析 → 报告。 缺点:抽象层多、开销较大、生产环境案例不如 LangGraph。 AutoGen(微软) AutoGen 强项在多 Agent 对话: from autogen import AssistantAgent, UserProxyAgentassistant = AssistantAgent("assistant", llm_config={...}) user = UserProxyAgent("user", code_execution_config={...})user.initiate_chat(assistant, message="写个爬虫爬 GitHub trending")Agent 之间"对话"完成任务,还能自动执行代码。学习曲线较高,生产环境案例相对少。 OpenAI Agents SDK OpenAI Agents SDK 是 OpenAI 官方的轻量 Agent 框架: from agents import Agent, Runneragent = Agent( name="Helper", instructions="回答问题", tools=[web_search, calculator], )result = Runner.run_sync(agent, "北京今天多少度?")适合:只用 OpenAI 模型 + 简单场景。想接 Claude / Gemini 就得考虑其它。 对比矩阵框架 语言 状态管理 多 Agent 生产案例 学习曲线LangGraph Python/TS 状态机 ✅ 最多 中偏难Mastra TypeScript 简单 ✅ 中 低PydanticAI Python 简单 有限 中 低CrewAI Python 简单 ✅ 中 低AutoGen Python 对话 ✅ 少 高OpenAI SDK Python 简单 有限 少 极低建议一开始就要上生产、多 Agent、需要审核流程 → LangGraph 和 Next.js 网站集成、要部署到 Vercel → Mastra 科研 / 数据分析、追求类型安全 → PydanticAI 只做 demo / 内部工具、就用 OpenAI → OpenAI Agents SDK 要模拟一个团队协作 → CrewAIMCP 生态 不管选哪个,都建议同时接入 MCP(Model Context Protocol)——一层协议,让所有 Agent 框架能共享工具(Context7、Playwright MCP、Slack MCP 等)。所有主流框架都有 MCP client 支持。 一句话总结 LangGraph 是当前生产 Agent 的最佳选择。TS 栈用 Mastra、Python 类型党用 PydanticAI、多角色模拟用 CrewAI。Agent 生态在 MCP 出来后开始有统一入口,选框架同时接 MCP 是长期正确的方向。

Context7:给 AI 编程助手注入实时文档的 MCP 工具

Context7 是一个给 AI 编程助手补充实时官方文档上下文的工具,核心解决的问题是:大模型的训练数据有截止日期,新框架 API 或频繁变动的库往往使用旧版写法,导致生成的代码无法运行。 工作流程 用户提问 ↓ AI 判断需要文档 ↓ Context7 拉取对应库的最新文档 ↓ 把文档片段注入 Prompt ↓ 模型基于真实文档生成代码例如询问"Next.js 15 middleware 怎么写",普通模型可能给出 Next.js 12 的旧 API,Context7 会先拉取最新 Next.js 文档再生成答案。 与 RAG 的区别维度 RAG Context7数据来源 用户自定义文档库 官方文档仓库更新频率 手动维护 跟随上游自动同步适合场景 内部知识库 公开库文档集成方式 自建 pipeline MCP 协议MCP 接入配置 Context7 提供 MCP server,支持 Cursor、Claude Code、OpenCode 等工具: { "mcpServers": { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] } } }配置后在对话中使用 use context7 指令触发文档检索: Next.js 15 的 middleware 怎么配置重定向?use context7支持的文档范围 常见库均有覆盖:React / Next.js / Remix Node.js / Bun LangChain / LangGraph OpenAI SDK / Anthropic SDK Prisma / Drizzle / TypeORM Docker / Kubernetes 各大主流 npm 包在 AI Agent 架构中的位置 OpenCode / Claude Code ├── LLM ├── Browser ├── Terminal ├── Skills ├── Context7 / RAG ← 文档检索层 └── MCP ToolsContext7 填补了"文档检索层"——让 Agent 在生成代码时能查到当前正确的 API,而不是凭训练数据猜测。 替代方案工具 定位Context7 公开库官方文档Mintlify Scraper 自定义文档爬取Crawl4AI 通用网页抓取自建 pgvector RAG 私有文档库对于内部项目文档,更适合自建 RAG(pgvector + embedding);对于开源库,直接用 Context7 省去维护成本。

LLM Tool Calling 的四种 role 和 "不用调工具" 的空数组约定

写 LLM Agent 或者接 Function Calling / Tool Use 的时候,role 字段是消息路由的核心。四种 role 分工明确,工具调用要按固定生命周期走。 四种 role 1. system — 全局规则 设定模型的行为准则、可用工具、输出格式约束: { "role": "system", "content": "你是一个只回答天气问题的助手。工具调用格式必须严格 JSON。" }优先级最高。一段对话通常只有一条 system 消息(放最前面)。 2. user — 用户输入 真实用户的问题、指令、上下文: { "role": "user", "content": "上海明天下雨吗?" }3. assistant — 模型响应 模型的回复。可以是普通文本、也可以是 tool_call 请求: 普通回复: { "role": "assistant", "content": "上海明天多云,温度 15-22°C。" }发起工具调用: { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"上海\",\"date\":\"tomorrow\"}" } } ] }content 为 null 表示模型选择用工具而不是直接回答。 4. tool — 工具执行结果 外部函数运行完,把结果塞回上下文让模型继续: { "role": "tool", "tool_call_id": "call_abc123", "content": "{\"weather\":\"多云\",\"temp\":\"15-22\"}" }tool_call_id 必须和上一条 assistant.tool_calls[].id 对上——多工具并行时靠这个匹配。 完整生命周期 user → "上海明天天气" ↓ assistant → tool_calls: [ get_weather({city:"上海"}) ] ↓ [外部执行 get_weather,返回 "多云 15-22°C"] ↓ tool → "多云 15-22°C" (tool_call_id = call_abc123) ↓ assistant → "上海明天多云,15-22°C,建议带件外套"四轮消息、四种 role。每条 tool 消息必须对应上一轮某个 tool_call,不能凭空出现。 "不需要工具"的返回约定 有些 Agent 框架要求 assistant 明确表达"这一轮我不需要工具"。约定俗成的写法是空数组: { "role": "assistant", "content": "你好,我是助手。", "tool_calls": [] }严格规范里:不需要工具 → tool_calls: [](或者干脆不带该字段) 需要工具 → tool_calls: [{...}][] 明确表示"模型已经判断过、决定不用工具",比 null 或缺字段更清晰。写自己的 tool routing 时,这样解析更省心: if (Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) { executeToolCalls(msg.tool_calls); } else { displayText(msg.content); }并行工具调用 现代模型(GPT-4、Claude 3.5+)支持一次返回多个 tool_calls: { "role": "assistant", "tool_calls": [ { "id": "call_1", "function": {"name": "get_weather", "arguments": "{\"city\":\"上海\"}"} }, { "id": "call_2", "function": {"name": "get_weather", "arguments": "{\"city\":\"北京\"}"} } ] }Agent 应该并发执行两个 get_weather,然后按顺序 append 两条 tool 消息回上下文: [ { "role": "tool", "tool_call_id": "call_1", "content": "上海:多云" }, { "role": "tool", "tool_call_id": "call_2", "content": "北京:晴" } ]再让模型继续。 常见坑 1. tool_call_id 忘了对齐 { "role": "assistant", "tool_calls": [{"id": "call_1", ...}] }, { "role": "tool", "tool_call_id": "call_2", ... } // 对不上模型下一轮会困惑——大概率报错或者胡说。每个 tool_call 必须对应恰好一个 tool 消息。 2. 直接输出工具调用当文本 有些开发者 prompt 里让模型 "输出 <tool>...</tool> 格式",然后自己解析。能用原生 tool_calls 就用,稳定性和生态好得多(错误处理、并行、streaming 都有官方支持)。 3. 工具报错没处理 工具执行失败,应该把错误信息作为 tool 消息返回,让模型知道并决定重试或换策略: { "role": "tool", "tool_call_id": "call_1", "content": "{\"error\":\"API rate limit exceeded, retry after 60s\"}" }而不是抛异常终止对话。 4. 工具太多导致 token 爆炸 每次请求都要把所有 tool schema 塞进去。只给模型看当前场景需要的工具子集——按用户意图动态选。20 个以上工具建议做工具路由。 OpenAI / Anthropic 差异字段 OpenAI Anthropic Clauderole: assistant 里的工具调用 tool_calls: [] content 里是 array,含 type: "tool_use" 项工具结果 role tool user(但 content 里是 type: "tool_result")工具定义位置 tools: [] 参数 tools: [] 参数(结构略不同)Anthropic 把工具结果放 user role 是历史原因——本质数据一样,只是包装略不同。 一句话总结 四种 role:system 全局规则、user 用户输入、assistant 模型输出(可含 tool_calls)、tool 外部执行结果。"不用工具"的规范返回是 tool_calls: []。每个 tool 消息必须靠 tool_call_id 对齐前一轮的调用。