☰
企业级LLM Agent实战:用LangGraph与MCP协议打通RAG到业务闭环
2026/9/28 7:53:39 网站建设 项目流程

1. 从 RAG 到业务闭环,企业 Agent 卡在哪一步

企业级 LLM Agent 落地时,最常见的起点是一条 RAG 流水线:用户提问、向量检索、拼接 Prompt、模型生成答案。这条链路能跑通 Demo,但一旦进入真实业务,问题立刻暴露。比如运营同学问“帮我查一下上周华东区退货率异常的原因,并给对应供应商发一封说明邮件”,传统 RAG 只能检索到几段文档,既不会拆解任务,也不会调用工单系统,更不会在检索结果不相关时自我修正。

我试过把这类需求硬塞进单轮 Prompt,结果就是模型一本正经地编造数据来源。根因在于:传统 RAG 是一个线性函数,输入到输出一次完成;而真实业务需要的是一个状态机,具备记忆、路由、重试和行动能力。LangGraph 提供了状态机编排能力,MCP 协议标准化了外部工具接入方式,两者结合才能把“检索命中”推进到“业务动作触发”。

这篇文章面向正在做企业级 Agent 的工程师,交付三样东西:可复制的 LangGraph 节点与状态定义骨架、MCP 服务接入配置片段、从检索命中到业务动作触发的端到端验证步骤。读完后你可以搭出一个可运行的闭环 Demo,而不是停留在概念层。

2. TaoToken 前置:模型接入与 Key 准备

在写 LangGraph 节点之前,先把模型调用通道准备好。企业级 Agent 对模型的要求是稳定、可切换、便于统一计费。TaoToken 提供 OpenAI 兼容接口,可以直接替换 LangChain 里的 ChatOpenAI 基址,不需要改业务代码。

你需要先拿到 API Key。访问控制台创建密钥:

https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=console

创建完成后,在 API Keys 页面复制密钥:

https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api-keys

接入文档里有完整的兼容说明和参数列表,建议先扫一遍:

https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

API 基址统一使用:

https://taotoken.net/api

注意这里不要加 UTM 参数,否则部分 SDK 会把查询串拼进请求路径导致 404。把 Key 写进环境变量,不要硬编码:

export TAOTOKEN_API_KEY="sk-你的密钥" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

如果你后续要做长期编码类 Agent,比如自动改代码、跑测试、提交 PR,可以了解 Coding Plan,它更适合高频、长会话的 Agent 场景:

https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding-plan

模型对话调试入口在这里,验证模型是否通的时候直接用:

https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=model-chat

3. 可复制配置:LangGraph 状态机与 MCP 接入

3.1 依赖安装与模型初始化

先装依赖。LangGraph 负责编排,langchain-mcp-adapters 负责把 MCP 工具转成 LangChain 工具:

pip install langgraph langchain-openai langchain-community \ langchain-mcp-adapters httpx redis

模型初始化时把 base_url 指向 TaoToken,其余参数和官方 SDK 一致:

# config/llm.py import os from langchain_openai import ChatOpenAI, OpenAIEmbeddings llm = ChatOpenAI( model="gpt-4o-mini", temperature=0, api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"], ) embeddings = OpenAIEmbeddings( model="text-embedding-3-small", api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"], )

3.2 AgentState 状态定义

状态是整个 Agent 的记忆载体。企业场景里必须显式记录重试次数和评分结果,否则容易出现无限循环:

# agents/state.py from typing import TypedDict, List, Literal from langchain_core.documents import Document class AgentState(TypedDict): question: str # 用户原始问题 route: str # 路由决策: vector | graph | web | direct documents: List[Document] # 检索到的文档 grade_results: List[str] # 文档相关性评分 rewrite_count: int # 查询改写次数,防死循环 generation: str # 最终答案 action_result: str # 业务动作执行结果

3.3 核心节点:路由、评分、改写、生成

路由节点负责判断问题该走向量检索、图检索还是直接回答。用结构化输出约束模型,避免解析自然语言:

# agents/nodes.py from pydantic import BaseModel from typing import Literal from config.llm import llm from agents.state import AgentState class RouteDecision(BaseModel): route: Literal["vector", "graph", "web", "direct"] reasoning: str router_llm = llm.with_structured_output(RouteDecision) def router_node(state: AgentState) -> AgentState: decision = router_llm.invoke( f"将用户问题分类为 vector/graph/web/direct:\n{state['question']}" ) return {**state, "route": decision.route}

评分节点逐个判断文档是否相关,这是自我修正闭环的触发点:

class GradeDoc(BaseModel): score: Literal["relevant", "irrelevant"] grader_llm = llm.with_structured_output(GradeDoc) def grader_node(state: AgentState) -> AgentState: grades = [] for doc in state["documents"]: result = grader_llm.invoke( f"问题:{state['question']}\n文档:{doc.page_content}\n是否相关?" ) grades.append(result.score) return {**state, "grade_results": grades}

改写节点在检索失败时把问题改得更具体,同时累加计数:

def rewriter_node(state: AgentState) -> AgentState: new_query = llm.invoke( f"将以下问题改写为更适合检索的形式,关键词更明确:\n{state['question']}" ).content return { **state, "question": new_query, "rewrite_count": state.get("rewrite_count", 0) + 1, }

3.4 条件边:自我修正闭环的关键

条件边决定评分之后往哪走。有相关文档就生成,全部不相关且未超上限就改写,超限则走兜底:

# agents/edges.py from agents.state import AgentState def grade_edge(state: AgentState) -> str: if "relevant" in state["grade_results"]: return "generate" if state.get("rewrite_count", 0) < 3: return "rewrite" return "web_fallback"

3.5 MCP 服务接入配置

MCP 的价值在于把数据库、通知、工单系统统一成协议化工具,新增数据源不用重写调用代码。下面是一个 MCP 网关的配置片段,用 stdio 方式启动本地 MCP Server:

{ "mcpServers": { "business-gateway": { "command": "python", "args": ["-m", "mcp_server.gateway"], "env": { "DB_DSN": "postgresql://agent:pass@db:5432/ops", "NOTIFY_ENDPOINT": "http://notify-svc:8080/send" } } } }

在 LangGraph 里加载 MCP 工具并注册给 Agent:

# tools/mcp_loader.py from langchain_mcp_adapters.client import MultiServerMCPClient async def load_mcp_tools(): client = MultiServerMCPClient({ "business-gateway": { "command": "python", "args": ["-m", "mcp_server.gateway"], "transport": "stdio", } }) return await client.get_tools()

3.6 图结构接线

把节点和边组装成图,注意 grader 之后走条件边:

# agents/graph.py from langgraph.graph import StateGraph, END from agents.state import AgentState from agents.nodes import router_node, grader_node, rewriter_node from agents.edges import grade_edge def build_graph(retriever_node, generator_node, fallback_node): g = StateGraph(AgentState) g.add_node("router", router_node) g.add_node("retriever", retriever_node) g.add_node("grader", grader_node) g.add_node("rewriter", rewriter_node) g.add_node("generate", generator_node) g.add_node("web_fallback", fallback_node) g.set_entry_point("router") g.add_edge("router", "retriever") g.add_edge("retriever", "grader") g.add_conditional_edges("grader", grade_edge, { "generate": "generate", "rewrite": "rewriter", "web_fallback": "web_fallback", }) g.add_edge("rewriter", "router") g.add_edge("generate", END) g.add_edge("web_fallback", END) return g.compile()

4. 验证请求:从检索命中到业务动作触发

4.1 先验证模型通道

在跑完整图之前,先用一段最小请求确认 TaoToken 通道正常:

from config.llm import llm resp = llm.invoke("用一句话说明什么是 Agentic RAG") print(resp.content)

如果返回正常文本,说明 Key 和 base_url 配置无误。若报 401,检查环境变量是否被 shell 覆盖;若报 404,检查 base_url 是否误加了路径后缀。

4.2 验证检索与评分闭环

构造一个知识库,故意让第一次检索命中不相关文档,观察改写是否触发:

import asyncio from agents.graph import build_graph from tools.mcp_loader import load_mcp_tools async def main(): tools = await load_mcp_tools() app = build_graph(retriever_node, generator_node, fallback_node) result = await app.ainvoke({ "question": "上周华东区退货率异常原因是什么", "rewrite_count": 0, "grade_results": [], }) print("路由:", result["route"]) print("改写次数:", result["rewrite_count"]) print("答案:", result["generation"]) asyncio.run(main())

预期现象:第一次评分全部 irrelevant,rewrite_count 变为 1,问题被改写为更具体的检索式,第二轮命中相关文档后进入 generate。

4.3 验证业务动作触发

在生成节点之后接一个动作节点,通过 MCP 工具发通知。这里用结构化输出抽取动作参数,再由代码层执行,保证确定性:

from pydantic import BaseModel from config.llm import llm class NotifyAction(BaseModel): channel: str message: str def action_node(state: AgentState) -> AgentState: action = llm.with_structured_output(NotifyAction).invoke( f"根据以下结论生成一条通知:\n{state['generation']}" ) # 调用 MCP 工具,实际项目中替换为 await tool.ainvoke(...) result = f"已通过 {action.channel} 发送:{action.message[:30]}..." return {**state, "action_result": result}

把 action_node 接到 generate 之后,再跑一次完整流程,你会看到输出里同时包含答案和动作执行结果。到这一步,从检索命中到业务动作触发的闭环就打通了。

5. 本篇常见错排查

报错一:openai.AuthenticationError: 401多数是环境变量没生效。在 Python 里打印os.environ.get("TAOTOKEN_API_KEY")确认,注意不要在代码里写死 Key 后又忘了导出。

报错二:NotFoundError: 404base_url 写成了https://taotoken.net/api/v1或带了查询串。统一用https://taotoken.net/api,SDK 会自己拼/chat/completions。

报错三:Agent 无限循环grade_edge 里忘了判断 rewrite_count 上限,或者 rewriter 节点没有累加计数。检查state.get("rewrite_count", 0) < 3这行是否生效。

报错四:MCP 工具加载为空stdio 方式启动时,command 和 args 必须能在当前工作目录下执行。先在终端手动跑一遍python -m mcp_server.gateway,确认没有 ImportError 再接入。

报错五:结构化输出解析失败模型返回了多余文本。确认使用的是支持 function calling 的模型,并在 with_structured_output 里显式传入 Pydantic 模型,不要用 dict。

报错六:检索一直不相关Embedding 模型和知识库切分粒度不匹配。chunk_size 建议 400 到 600,overlap 50 左右,太大导致语义稀释,太小导致上下文断裂。

6. 下一步:把闭环接到你的业务系统

到这里你已经有了一个可运行的骨架:LangGraph 负责状态流转和自我修正,MCP 负责工具标准化接入,TaoToken 负责模型通道。接下来要做的,是把 retriever_node 换成你真实的向量库,把 MCP 网关里的工具换成你的工单、审批、通知接口。

接入过程中如果遇到模型调用或工具注册的问题,优先查接入文档:

https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc

需要新建或轮换密钥时走 API Keys 页面:

https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api-keys

如果你的 Agent 要长期跑编码类任务,比如自动修 bug、跑测试、提 PR,Coding Plan 比按次调用更合适:

https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding-plan

最后提醒一句:企业级 Agent 的难点从来不是模型多强,而是状态可观测、动作可回滚、失败可重试。把这三件事在 LangGraph 里显式建模,比换更大的模型有用得多。

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

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

立即咨询