资讯动态

MCP协议实战:LangGraph多AI服务协同调用全链路解析

发布时间:2026/10/8 16:35:17 来源:尧图企业网站定制
1. 这不是又一个“AI协议”概念秀而是真实跑通的工程链路MCP——最近三个月在开发者圈子里反复刷屏的缩写它既不是某个新出的AI模型也不是某家大厂刚发布的闭源框架。我第一次在UE5.8的插件列表里看到“MCP Server”时下意识以为是Unreal Engine内部的调试通道代号后来在Altium Designer的AI接口文档里再见到它才意识到这东西已经悄悄渗透进EDA、逆向分析、游戏引擎、低代码平台甚至工业软件的底层通信层。它不声不响但凡你用过x64dbg的插件、调过Codex对接Figma的API、或者在Dify浏览器插件里点开过“启用MCP代理”你就已经站在了这条链路的末端。MCPModel Communication Protocol本质是一套轻量级、可扩展、面向AI服务间协同的语义化通信协议规范不是SDK不是中间件更不是某种“AI网关”。它的核心设计哲学非常朴素让不同厂商、不同语言、不同部署形态的AI服务能像HTTP请求一样互相“打招呼”但比HTTP多一层语义理解能力——比如它能明确告诉对方“我不是要你返回一段文本而是要你启动一个带状态的推理会话支持流式输出、支持中途取消、支持上下文快照回滚。”这种能力在LangGraph这类需要编排多个LLM节点、维护图状态、处理分支条件与循环重试的场景里就不再是锦上添花而是刚需。标题里说的“从协议握手到LangGraph多Server调用”指的就是一条完整落地路径先让两个独立部署的服务比如一个本地Ollama运行的Qwen2-7B一个云上部署的Claude-3-haiku API通过MCP标准完成身份识别、能力协商、会话初始化再把它们注册为LangGraph工作流里的可调用节点让LangGraph的StateGraph能自动识别每个节点的输入/输出Schema、错误码含义、流式支持能力并在执行过程中按需触发MCP call、解析MCP response、处理MCP error。这不是Demo级别的玩具而是我在一个实际交付的智能硬件诊断系统里跑通的链路——前端用户上传一张电路板热成像图LangGraph调度三个MCP Server第一个做图像描述Vision MCP第二个查知识库RAG MCP第三个生成维修建议Reasoning MCP整个流程耗时稳定在3.2秒以内失败率低于0.7%。如果你正在被以下问题困扰这篇分享就是为你写的LangGraph里加个新LLM节点总要重写Adapter改来改去全是JSON Schema映射和错误码转换多个AI服务混用时有的支持流式有的只支持同步有的超时是408有的是504有的干脆不返回status code想把本地微调的小模型、云上商用大模型、甚至私有部署的Code LLM统一纳管但发现它们的API长得五花八门连“取消请求”这个基础操作都没有统一方式看到“MCP”这个词就想到IDA Pro插件或UE5.8的某个开关却不知道它背后那套协议如何真正用起来。接下来我会拆解这条链路的每一个真实环节为什么MCP握手不是发个HTTP POST就完事LangGraph怎么“看懂”一个MCP Server的能力声明多Server调用时状态如何跨服务传递以及——那些没人告诉你、但上线第一天就会踩的坑。2. 协议握手不是“你好”而是“我们能一起做什么”的深度协商2.1 MCP握手的本质一次结构化的服务能力自描述交换很多人误以为MCP握手就是客户端向服务端发个GET /health或POST /v1/connect收到200就算成功。这是对MCP最典型的误解。真正的MCP握手是一次双向、结构化、带语义约束的服务能力自描述交换过程。它不依赖HTTP状态码而依赖一套明确定义的MCP消息类型MCP_HELLO客户端发起、MCP_WELCOME服务端响应、MCP_ERROR协商失败。整个过程必须在单个TCP连接或WebSocket会话内完成且必须在任何业务调用前完成。我拿一个真实案例说明当LangGraph工作流准备调用一个部署在树莓派上的Ollama MCP Server时第一步不是发prompt而是建立WebSocket连接后立即发送一条MCP_HELLO消息{ type: MCP_HELLO, version: 0.5.2, capabilities: [ streaming, cancellation, context_snapshot ], tools: [ { name: describe_image, description: Generate detailed description of uploaded image, input_schema: { type: object, properties: { image_url: { type: string } } } } ] }注意这里的关键字段version不是随便填的必须严格匹配服务端声明的MCP版本。0.5.2和0.5.1之间可能存在工具参数校验逻辑差异版本不匹配直接返回MCP_ERRORcapabilities声明客户端支持哪些高级能力。“streaming”意味着客户端能处理MCP_EVENT_STREAM类型的消息“cancellation”表示客户端能在任意时刻发MCP_CANCEL指令tools这是最常被忽略的部分。它不是服务端暴露的所有功能列表而是客户端当前工作流需要用到的工具子集。LangGraph在初始化节点时会根据StateGraph中该节点的invoke方法签名动态生成这个tools数组。比如如果Graph里定义的是node.invoke(image_url: str) - str那么tools里就只包含describe_image这一项而不是把Ollama里所有可用模型都列出来。服务端收到后不会简单回个{status:ok}而是返回MCP_WELCOME其中包含服务端的反向声明{ type: MCP_WELCOME, server_name: ollama-mcp-server, server_version: 0.3.1, mcp_version: 0.5.2, capabilities: [ streaming, cancellation, context_snapshot, tool_choice ], tools: [ { name: describe_image, description: Generate detailed description of uploaded image, input_schema: { type: object, properties: { image_url: { type: string, format: uri }, max_tokens: { type: integer, default: 512 } } }, output_schema: { type: object, properties: { description: { type: string }, confidence_score: { type: number } } } } ] }对比客户端发的MCP_HELLO你会发现几个关键差异server_version和mcp_version确认双方实现的兼容性基线capabilities多了tool_choice表示服务端支持客户端在调用时指定tool_choiceauto或tool_choice{type:function,function:{name:describe_image}}这是后续LangGraph做工具路由的基础tools里的input_schema和output_schema更完整服务端补充了image_url的format: uri约束增加了max_tokens参数及默认值并明确定义了output_schema——这才是LangGraph能自动生成类型安全的invoke方法签名的依据。提示MCP握手失败最常见的原因不是网络不通而是capabilities不匹配。比如客户端声明支持streaming但服务端MCP_WELCOME里没返回streamingLangGraph就会拒绝将该节点加入工作流报错MCP server does not support required capability: streaming。这不是Bug是协议强制的安全机制——避免客户端尝试接收流式数据而服务端根本没发。2.2 握手背后的工程细节为什么必须用WebSocket而非HTTP你可能会问既然都是JSON为什么不用更简单的HTTP POST答案藏在MCP的设计目标里状态感知、双向实时、长连接复用。HTTP是无状态的请求-响应模型而MCP要求服务端能主动推送事件如流式token、进度百分比、工具调用触发客户端也能在任意时刻中断会话。HTTP/1.1无法满足HTTP/2虽支持Server Push但浏览器兼容性差、服务端实现复杂HTTP/3太新生态不成熟。WebSocket成了事实标准但它不是开箱即用的。我在部署第一个MCP Server时在Nginx反向代理层就栽了跟头。默认配置下Nginx会缓存WebSocket帧导致MCP_EVENT_STREAM消息延迟高达200ms以上。解决方法是在Nginx配置里显式开启WebSocket支持location /mcp/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; # 关键禁用缓冲确保流式消息零延迟 proxy_buffering off; proxy_cache off; proxy_send_timeout 300; proxy_read_timeout 300; }另一个容易被忽视的细节是TLS。MCP规范强烈建议虽未强制使用wss://。但很多开发者用Lets Encrypt证书时忘了给WebSocket endpoint配置SNIServer Name Indication。结果是Chrome浏览器能连上Firefox却报SEC_ERROR_UNKNOWN_ISSUER。排查方法很简单用wscat -c wss://your-server.com/mcp命令测试如果失败再用openssl s_client -connect your-server.com:443 -servername your-server.com检查SNI是否生效。2.3 实操心得三次握手之外你必须做的三件事为每个MCP Server分配唯一ID并持久化MCP规范没有规定Server ID的生成方式但LangGraph在多Server场景下需要靠ID区分同名工具比如两个都叫search_knowledge_base的工具来自不同Server。我的做法是在Server启动时读取/etc/machine-id 启动时间戳 配置文件hash生成一个32位小写hex字符串作为server_id写入/var/run/mcp-server.id。这样即使容器重启只要配置没变ID就不变LangGraph的状态快照就能正确关联。在MCP_WELCOME里嵌入健康检查端点规范没要求但工程上极有必要。我在MCP_WELCOME的metadata字段里加了一个health_check_pathmetadata: { health_check_path: /healthz?mcptrue }LangGraph的Node Manager会定期GET这个路径如果返回非200就自动将该Server标记为unhealthy跳过调度。这比单纯靠WebSocket连接存活判断可靠得多——毕竟网络抖动可能只断几秒但服务进程可能已OOM挂掉。强制校验input_schema的$ref引用完整性很多MCP Server实现尤其是基于OpenAPI Generator生成的会把复杂Schema拆成$ref引用。但MCP客户端如LangGraph的MCP Adapter通常不带完整的JSON Schema Resolver。我的经验是在Server启动时用jsonschema.validators.Draft202012Validator预加载所有tools的input_schema调用.check_schema()方法验证引用是否可解析。如果失败直接panic退出绝不让一个Schema不完整的Server进入生产环境。这省去了后期无数个ValidationError: unknown field user_context的深夜排查。3. LangGraph集成让图编排“看懂”MCP Server的能力边界3.1 LangGraph的MCP Adapter不是胶水而是协议翻译器LangGraph官方并没有内置MCP支持。所谓“LangGraph多Server调用”本质是开发者自己实现的一个MCPNode类它继承自Runnable并实现了invoke、astream、ainvoke等核心方法。这个类不是简单的HTTP Client包装器而是一个MCP协议翻译器它把LangGraph的State对象、Graph执行上下文、中断信号翻译成符合MCP规范的二进制帧再把MCP Server返回的MCP_EVENT_STREAM、MCP_RESULT、MCP_ERROR翻译回LangGraph能理解的dict、AsyncIterator或BaseException。我开源的langgraph-mcp-adapter库的核心逻辑就在这三层翻译LangGraph侧翻译动作MCP协议侧state[input] {image_url: https://...}提取input字段按tools[0].input_schema校验并序列化MCP_CALL消息体中的arguments字段await node.ainvoke(state)建立WebSocket连接发送MCP_HELLO等待MCP_WELCOME再发MCP_CALLTCP/WS帧流async for chunk in node.astream(state)监听MCP_EVENT_STREAM解析event_type为token/progress/tool_callyield对应chunkMCP_EVENT_STREAM消息关键点在于MCPNode必须在初始化时完成一次完整的握手并缓存MCP_WELCOME的全部内容。因为LangGraph的StateGraph在构建时会调用每个Node的get_input_schema()和get_output_schema()方法来生成Graph的全局Schema。这两个方法的返回值直接来自MCP_WELCOME.tools[0].input_schema和output_schema。如果每次invoke都重新握手Graph构建会卡死——想象一下一个包含5个MCP Node的Graph构建时要发起5次WebSocket连接、5次握手、5次Schema解析耗时从毫秒级变成秒级。所以我的MCPNode构造函数里强制要求传入一个MCPClient实例而这个实例在创建时就已完成握手class MCPNode(Runnable): def __init__(self, client: MCPClient, tool_name: str): self.client client # 已完成握手的client self.tool_name tool_name # 缓存schema供LangGraph构建时调用 self._input_schema client.get_tool_schema(tool_name)[input_schema] self._output_schema client.get_tool_schema(tool_name)[output_schema] def get_input_schema(self) - Type[BaseModel]: return create_model_from_json_schema(self._input_schema) def invoke(self, input: dict, config: RunnableConfig) - dict: # 直接复用已建立的连接发MCP_CALL return self.client.call_tool(self.tool_name, input)3.2 多Server调用的图状态管理跨服务的上下文接力LangGraph最强大的地方在于State管理而MCP让这种管理突破了单服务边界。举个典型场景用户问“这个电容烧了怎么换”LangGraph工作流可能是vision_nodeMCP Server A接收图片返回{component: C12, failure_mode: short_circuit}knowledge_nodeMCP Server B用component查手册返回{replacement_part: KEMET C0603C104K8RACTU, soldering_temp: 260°C}reasoning_nodeMCP Server C综合前两步生成步骤化维修指南问题来了knowledge_node需要知道vision_node的结果reasoning_node需要知道前两者的输出。传统做法是把所有结果塞进一个大字典里传下去但MCP提供了更优雅的方案——Context Snapshot。MCP的context_snapshot能力允许服务端在MCP_RESULT中附带一个snapshot_id客户端可以用这个ID在后续调用中恢复上下文。我在vision_node的invoke里做了这件事def invoke(self, input: dict, config: RunnableConfig) - dict: result self.client.call_tool(describe_component, input) # 生成快照ID并存储结果 snapshot_id fvision-{uuid4().hex[:8]} self._snapshot_store[snapshot_id] result return { result: result, snapshot_id: snapshot_id # 透传给下一个Node }然后knowledge_node的invoke方法接收这个snapshot_id并在调用MCP Server B时把snapshot_id作为MCP_CALL的context字段{ type: MCP_CALL, tool: search_manual, arguments: { component: C12 }, context: vision-abc12345 }Server B收到后如果实现了context_snapshot就会从自己的快照存储里取出vision-abc12345对应的数据用于增强检索比如加权匹配“short_circuit”相关的维修章节。这比在LangGraph State里手动拼接字段干净得多也更利于服务端做缓存优化。注意context_snapshot不是MCP强制要求的能力。LangGraph的MCPNode在初始化时会检查MCP_WELCOME.capabilities是否包含context_snapshot。如果不包含invoke方法会自动降级为普通调用不传context字段。这种优雅降级是MCP协议设计的精髓——不强求所有Server都支持全部能力而是让Client根据Server声明的能力动态选择最优路径。3.3 工具路由与动态发现让LangGraph自动适配新Server最头疼的运维场景是什么——半夜收到告警说knowledge_node调用失败登录一看是知识库Server升级了新增了一个search_by_symptom工具但LangGraph的Node代码里还是硬编码调用search_manual。MCP的解决方案是让LangGraph在运行时动态发现并路由工具。我的做法是在LangGraph的StateGraph构建完成后启动一个后台任务定期比如每5分钟向所有已注册的MCP Server发送MCP_HELLO带空tools数组获取最新的MCP_WELCOME解析其tools列表更新内存中的工具注册表。然后MCPNode的invoke方法不再依赖构造时传入的tool_name而是根据State里的tool_choice字段动态选择def invoke(self, input: dict, config: RunnableConfig) - dict: # 从State里读取tool_choice可能是字符串或dict tool_choice input.get(tool_choice) if isinstance(tool_choice, str): tool_name tool_choice elif isinstance(tool_choice, dict) and function in tool_choice: tool_name tool_choice[function][name] else: raise ValueError(Invalid tool_choice format) # 从动态注册表里获取该tool的schema和endpoint tool_info self._tool_registry.get(tool_name) if not tool_info: raise ValueError(fTool {tool_name} not found in registry) return self.client.call_tool(tool_name, input)这样当知识库Server上线search_by_symptom时LangGraph无需重启5分钟内就能自动识别并路由。我在生产环境用这套机制支撑了12个MCP Server的滚动升级零停机。4. 多Server调用实操从零搭建一个三节点诊断工作流4.1 环境准备与工具链选型整个工作流基于Python 3.11核心依赖如下requirements.txt精简版langgraph0.1.32 langchain0.2.11 pydantic2.7.4 websockets12.0 httpx0.27.0 ollama0.3.0 fastapi0.111.0 uvicorn0.29.0为什么选这些版本langgraph0.1.32这是首个正式支持RunnableConfig中断信号的版本对MCP的cancellation能力至关重要pydantic2.7.4修复了create_model_from_json_schema在处理oneOf联合类型时的bug而MCP的output_schema经常用oneOf描述多种返回格式ollama0.3.0原生支持MCP Server模式ollama serve --mcp无需额外封装。基础设施采用Docker Compose编排共4个服务服务名镜像作用端口langgraph-apppython:3.11-slimLangGraph主应用含MCPNode实现8000vision-serverollama/ollama:latest运行qwen2-vl:7b提供describe_component工具11434 (MCP: 11435)knowledge-serverfastapi-mcp-kb:latest自研FastAPI服务接入PostgreSQL知识库8001reasoning-serverllama3-8b-instruct:latestOllama模型提供generate_repair_steps工具11434 (MCP: 11436)注意Ollama的MCP端口默认是11435但官方镜像启动时会占用11434HTTP API和11435MCP WebSocket。为避免端口冲突我在docker-compose.yml里显式映射services: vision-server: image: ollama/ollama:latest ports: - 11434:11434 # HTTP API - 11435:11435 # MCP WebSocket4.2 Vision Server用Qwen2-VL实现电路板缺陷识别Ollama本身不带MCP支持但ollama/ollama:0.1.32版本已内置。启动命令只需一行ollama run qwen2-vl:7b --mcp --port 11435但这只是开始。Qwen2-VL的原始API接受{images: [base64...], prompt: Describe this image}而MCP要求工具必须有明确的input_schema。所以我写了一个轻量级Wrapper放在Ollama容器里# /app/mcp-wrapper.py from fastapi import FastAPI, WebSocket, UploadFile, File from pydantic import BaseModel import base64 import json app FastAPI() class DescribeInput(BaseModel): image_url: str prompt: str Describe the electronic component and its failure mode in detail. app.post(/describe) async def describe(input: DescribeInput): # 下载image_url转base64 import httpx async with httpx.AsyncClient() as client: resp await client.get(input.image_url) img_b64 base64.b64encode(resp.content).decode() # 调用Ollama HTTP API ollama_resp httpx.post( http://localhost:11434/api/chat, json{ model: qwen2-vl:7b, messages: [{role: user, content: input.prompt, images: [img_b64]}] } ) return ollama_resp.json()然后用uvicorn启动这个Wrapper监听0.0.0.0:8002再在MCP_WELCOME里声明describe_component工具input_schema指向DescribeInput的JSON Schema。这样LangGraph的MCPNode就能拿到精确的Schema生成类型安全的调用。4.3 Knowledge ServerPostgreSQL驱动的智能知识库这个Server的挑战在于如何让MCP的search_manual工具既能查结构化字段如part_number又能做全文检索如symptom_description。我的方案是用PostgreSQL的pg_trgm扩展 jsonb字段-- 创建表 CREATE TABLE repair_manuals ( id SERIAL PRIMARY KEY, part_number VARCHAR(50), symptom_description TEXT, repair_steps JSONB, embedding VECTOR(1024) -- 用pgvector存储向量 ); -- 创建GIN索引加速全文检索 CREATE INDEX idx_manuals_gin ON repair_manuals USING GIN (symptom_description gin_trgm_ops); -- 创建向量索引加速语义检索 CREATE INDEX idx_manuals_vector ON repair_manuals USING IVFFLAT (embedding vector_cosine_ops) WITH (lists 100);MCP工具的input_schema定义为{ type: object, properties: { query: { type: string }, part_number: { type: string, nullable: true }, top_k: { type: integer, default: 3 } } }Server收到MCP_CALL后会根据query和part_number是否存在自动选择SQL查询路径如果part_number存在走精确匹配全文排序如果不存在走向量相似度检索。返回的output_schema则统一为{ type: array, items: { type: object, properties: { title: { type: string }, score: { type: number }, steps: { type: array, items: { type: string } } } } }LangGraph的MCPNode拿到这个Schema就能自动生成List[Dict[str, Any]]类型的返回值无需手动json.loads()。4.4 LangGraph主应用三节点串联与错误熔断StateGraph定义如下from langgraph.graph import StateGraph, END from typing import TypedDict, List, Dict, Any class GraphState(TypedDict): input_image_url: str vision_result: Dict[str, Any] knowledge_result: List[Dict[str, Any]] reasoning_result: str error: str workflow StateGraph(GraphState) # 定义三个MCP Node vision_node MCPNode( clientMCPClient(ws://vision-server:11435/mcp), tool_namedescribe_component ) knowledge_node MCPNode( clientMCPClient(ws://knowledge-server:8001/mcp), tool_namesearch_manual ) reasoning_node MCPNode( clientMCPClient(ws://reasoning-server:11436/mcp), tool_namegenerate_repair_steps ) workflow.add_node(vision, vision_node) workflow.add_node(knowledge, knowledge_node) workflow.add_node(reasoning, reasoning_node) # 边缘逻辑带错误熔断 def should_continue(state: GraphState) - str: if state.get(error): return error return knowledge def call_knowledge(state: GraphState) - Dict[str, Any]: # 将vision结果注入knowledge调用 return { query: state[vision_result].get(failure_mode, ), part_number: state[vision_result].get(component, ) } workflow.add_edge(vision, knowledge) workflow.add_edge(knowledge, reasoning) workflow.add_edge(reasoning, END) workflow.set_entry_point(vision) workflow.add_conditional_edges(vision, should_continue)关键的熔断逻辑在should_continue函数里如果vision_node返回error字段由MCP Adapter捕获MCP_ERROR并注入State就跳转到error节点而不是继续调用下游。这避免了“一个服务挂整条链路雪崩”的经典问题。4.5 实测性能与稳定性数据在AWS t3.xlarge实例4 vCPU, 16GB RAM上连续压测1小时结果如下指标数值说明平均端到端延迟3.18s ± 0.42s从HTTP POST到最终JSON响应P95延迟4.21s满足工业现场5s的硬性要求WebSocket连接成功率99.998%基于10万次连接尝试MCP握手失败率0.012%主要发生在Server刚启动的1秒内已加重试多Server调用失败率0.67%其中92%为knowledge-server超时已调大pg_timeout最值得提的稳定性设计是我在MCPClient里实现了三级重试——协议层重试对MCP_HELLO失败最多重试3次间隔100ms连接层重试WebSocket断开后自动重建连接并重握手最多3次业务层重试对MCP_CALL返回MCP_ERROR且code为503Service Unavailable按指数退避重试最多2次。这三级重试覆盖了从网络抖动到服务瞬时过载的所有常见故障让整个工作流在弱网环境下依然坚挺。5. 常见问题与独家排查技巧实录5.1 “MCP_HELLO timeout”不是网络问题是Server没启动MCP模式现象LangGraph日志显示MCPClient handshake timeout after 5000ms但curl http://server:11434/health返回200。根因Ollama等工具默认只开HTTP API11434MCP WebSocket端口11435需要显式启用。很多开发者以为ollama serve就自动启MCP其实必须加--mcp参数。排查技巧用netstat -tuln | grep 11435确认端口是否LISTEN用wscat -c ws://localhost:11435/mcp手动连接如果报Error: connect ECONNREFUSED就是Server根本没开MCP查Ollama日志docker logs ollama-server | grep -i mcp应看到MCP server started on :11435。5.2 “Tool not found in registry”LangGraph的动态发现失效了现象新上线一个search_by_symptom工具但LangGraph始终调用老的search_manual日志报Tool search_by_symptom not found in registry。根因动态发现任务fetch_welcome_task被阻塞。我遇到过两次第一次是knowledge-server的/mcpendpoint返回了502但fetch_welcome_task没设timeout整个协程卡死第二次是MCP_WELCOME.tools里有个工具的input_schema语法错误少了个逗号json.loads()抛异常后续工具不被解析。解决方案给fetch_welcome_task加asyncio.wait_for(..., timeout10.0)在解析tools时用try/except包裹每个工具的Schema解析失败则log warning并跳过该工具不影响其他工具注册。5.3 流式输出卡在第一个tokenWebSocket帧被代理截断现象node.astream()只yield第一个MCP_EVENT_STREAMtoken然后静默结束无错误。根因Nginx或Traefik等反向代理默认启用buffering把多个WebSocket帧合并成一个大帧发送而MCP客户端期望逐帧解析。验证方法关掉代理直连Server如果正常就是代理问题在代理配置里加proxy_buffering off;Nginx或traefik.http.middlewares.nobuffer.bufferingfalseTraefik。终极技巧在MCPClient的WebSocket接收循环里加一行debug logasync for msg in websocket: print(f[DEBUG] Raw frame length: {len(msg)}) # 如果总是10000就是被合并了5.4 “Context snapshot not found”快照ID在跨Server时丢失现象vision_node生成了snapshot_id但knowledge_node调用时Server B返回MCP_ERRORwithcode: CONTEXT_NOT_FOUND。根因snapshot_id是vision-server生成的但knowledge-server的快照存储是独立的。MCP规范没要求快照跨Server共享所以必须由LangGraph层做透传。正确做法vision_node.invoke()返回时把snapshot_id写入State的context字段不是顶层字段knowledge_node.invoke()从state.get(context, {}).get(vision_snapshot_id)读取在MCP_CALL.context里传这个ID。避坑提示不要把snapshot_id存在Redis之类共享存储里——这违背了MCP“服务自治”原则且引入单点故障。快照ID应该只是个opaque string由Client负责生命周期管理。5.5

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑