news 2026/7/18 17:20:29

【LLM】用 LangGraph 构建 AI 网络调试助手

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【LLM】用 LangGraph 构建 AI 网络调试助手

1. 前言

顾得助手 是我个人开发的一款 Chrome 插件,这篇文章将分享其中‘网络智能调试助手’功能的实现思路。这个功能主要用于拦截Mock页面上的网络请求。

1.1 为什么会开发这个功能?

在前端开发中,我们经常会遇到这样的问题:

  • 后端接口尚未完成,前端无法联调
  • 某些异常场景(500、延迟、空数据)难以模拟
  • 线上问题难以在测试环境复现,造数据浪费大量时间

除了解决以上痛点,功能还具备以下特点

  • Mock 配置支持界面手动操作自然语言指令生成;
  • 支持 Mock 请求头、请求体、响应体、超时时间等;
  • Mock 配置规则持久化(跟随会话,不会自动删除);
  • 支持多轮对话;
  • 兼容fetchXMLHttpRequest请求;

2. 界面展示

顾得助手 对话界面双击输入框,然后选择‘网络智能调试助手’进入。

3. 整体架构

3.1 架构分层

在整个功能中,我把 AI 的能力限制在了分析用户自然语言并生成 Mock 规则配置,网络请求的拦截还是由确定性代码来实现。

功能的整体架构分层如下,本篇博客只介绍工作流编排层的实现。

┌──────────────────────────────────────────┐ │UI交互层(Vue 组件)│ │ 接收用户输入,展示AI响应 │ └──────────────────────────────────────────┘ ⬇️ ⬆️ ┌───────────────────────────────────────────┐ │工作流编排层(LangGraph)│ │ router → checker → switcher/consultant │ │ ↓ ↓ ↓ ↓ │ │ refiner presenter new_init...│ └───────────────────────────────────────────┘ ⬇️ ┌──────────────────────────────────────────┐ │AI模型层(LLM)│ │ 意图识别、内容生成、结果呈现 │ └──────────────────────────────────────────┘ ⬇️ ┌──────────────────────────────────────────┐ │ 数据持久化层 │ │ 规则存储、会话管理、拦截器步 │ └──────────────────────────────────────────┘

3.2 为什么选择 LangGraph?

我们先看一个典型的用户交互场景。

例如用户可能这样输入:

帮我拦截 /api/user 接口,接口响应数据设置为 {"code":"200","msg":"成功"}

系统需要解析用户意图,并生成一条新的 API 规则。

接着用户可能继续修改刚刚的配置:

不对,将响应数据改成 {"code":"500","msg":"失败"},并设置超时时间为800ms

此时系统不仅需要理解新的修改指令,还需要:

  • 找到当前正在编辑的 API 规则
  • 更新对应的响应数据
  • 增加新的配置项(timeout)

而在真实使用场景中,用户输入往往更加复杂。例如:

  • 与 API 规则相关的配置操作
  • 对已有规则的修改或切换
  • 新规则的创建
  • 与系统的普通闲聊

这意味着系统必须具备两种能力:

  1. 理解多种用户意图
  2. 在多轮对话中保持稳定的状态

如果仅使用单一 Prompt + LLM 推理的方式,很难稳定处理这类问题。因为:

  • Prompt 会随着场景增多而迅速膨胀
  • 逻辑控制完全依赖 LLM,缺乏确定性
  • 多轮对话中的状态管理变得困难

LangGraph正好提供了一种更适合这类场景的解决方案。

LangGraph 的核心特点包括:

  • 显式的状态管理(State):可以在多轮对话中持续维护规则、当前编辑对象等上下文信息
  • 可控的执行流程(Workflow):通过 Graph 的节点和边来明确控制系统行为
  • 确定性的执行路径:不同用户意图可以被路由到不同的处理节点

因此,对于这种场景复杂但结果相对确定的 AI 功能,使用 LangGraph 可以让系统结构更加清晰,也更容易维护和扩展。

3.3 LangGraph 工作流整体架构

基于上述需求,我们使用LangGraph构建了一个可控的 AI 工作流。整个系统被拆分为多个职责清晰的节点,通过 Graph 的方式组织执行流程。

整体架构如下图所示:

这个架构的核心思想是:

让 AI 只负责“理解和生成”,而所有“流程控制”由代码完成。

3.4 GraphState 设计

我们通过Annotation.Root定义全局状态结构 。

constGraphState=Annotation.Root({// 会话IDthreadId:Annotation<string>(),// 用户输入信息userInput:Annotation<string>(),// 意图类型: 'refine' | 'switch' | 'new_api' | 'unknown'intent:Annotation<string>(),// 已配规则列表rules:Annotation<ApiRule[]>(),// 当前操作的规则IDactiveId:Annotation<string>(),// 正在生成的规则片段pendingRule:Annotation<any>(),// 历史对话信息,方便判断用户真实意图history:Annotation<any[]>()});type GraphState=typeofGraphChannels.State;

拓展:LangGraph 中Annotation是定义状态图(State Graph)数据结构的核心工具。用于指定每个状态字段的更新策略(Reducer)和默认值。

Reducer 常见写法示例:

// 完全替换 (Replace)reducer:(_x,y)=>y// 追加合并 (Concat)reducer:(x,y)=>x.concat(y)// 对象合并 (Merge)reducer:(x,y)=>({...x,...y})

3.5 节点解析

下面我们逐个介绍每个节点的设计。

3.5.1 Router 节点:意图识别

Router 是整个系统的入口节点,负责判断用户当前想做什么。

例如用户输入:

帮我拦截 /api/user 接口

或者

不对,把返回值改成 {"code":500}

Router 需要识别出用户意图,例如:

refine 修改/微调规则 switch 切换规则 new_api 新增规则 unknown 未知意图

真实代码如下:

privateasyncrouterNode(state:GraphState):Promise<Partial<GraphState>>{constactiveRule=state.rules.find(r=>r.id===state.activeId);constactivePath=activeRule?activeRule.path:'无';// 组装提示词,提示词中强制 AI 输出结构化 JSONconstprompt=devNetSmartAssistantPrompts.router.replaceAll('{{rulesJson}}',JSON.stringify(state.rules,null,2)).replaceAll('{{currentActiveId}}',state.activeId||'无').replaceAll('{{currentActivePath}}',activePath).replaceAll('{{history}}',this.formatHistory(state.history)).replaceAll('{{userInput}}',state.userInput);// 大模型调用constres=awaitthis.callModel([{role:'user',content:prompt}]);// 解析大模型返回的JSONconstresult=this.extractJson(res);return{intent:result.intent,activeId:result.targetId||state.activeId};}

可以看到,这里并没有直接让 AI 输出自然语言,而是强制 AI 输出结构化 JSON

Prompt 示例:

你是一个网络调试助手,需要识别用户意图。 当前已有规则: {{rulesJson}} 当前激活规则: id={{currentActiveId}} path={{currentActivePath}} 历史对话: {{history}} 用户输入: {{userInput}} 意图判定规则: 1. new_api(新增规则) - 触发场景:用户表达“监听/增加/拦截/模拟”等动作,且未明确指向列表中某个已存在的规则;` - 补充场景:用户正在完善未创建成功的新规则信息(无论是否修改路径); - 返回要求:path提取自用户输入(无则null),targetId=null。 ...... 请分析用户意图,并返回 JSON: { "intent": "refine | switch | new_api | unknown", "targetId": "规则ID(可选)", "path": "接口路径(可选)", "reason": "无法识别时的原因" } 不要输出任何解释,只输出 JSON。

3.5.2 Refiner 节点:修改已有规则

如果 Router 判断用户是refine意图,则进入 Refiner 节点。

典型输入:

把返回值改成 {"code":500}

Refiner 的任务是:在现有规则基础上生成更新字段。

代码实现:

privateasyncrefinerNode(state:GraphState):Promise<Partial<GraphState>>{consttargetRule=state.rules.find(r=>r.id===state.activeId);// 组装提示词constprompt=devNetSmartAssistantPrompts.refiner.replaceAll('{{targetRuleJson}}',JSON.stringify(targetRule,null,2)).replaceAll('{{userInput}}',state.userInput);// 模型调用constres=awaitthis.callModel([{role:'user',content:prompt}]);// 模型返回结果解析constupdateFields=this.extractJson(res);constnewRules=state.rules.map(r=>// 替换模型输出的更新字段r.id===state.activeId?{...r,...updateFields}:r);return{rules:newRules};}

这里 AI 的角色是:限制只生成更新的字段,而不是生成完整对象。

Prompt 示例:

你是一个 API 规则微调专家。用户想要修改现有的 API 拦截规则。 当前规则: {{targetRuleJson}} 用户输入: {{userInput}} 请根据用户要求修改规则,并返回需要更新的字段: 字段说明: - responseBody: 响应体内容,拦截后返回给前端的数据。 - delay: 模拟延迟时间(数字,单位 ms),拦截后延迟多久返回响应 ...... 示例: { "responseBody": "{\"code\":500,\"msg\":\"失败\"}", "delay": 800, ...... } 只返回 JSON,不要解释。

3.5.3 Checker 节点:规则匹配

Checker 节点负责解决一个现实问题:用户说的 API 是否已经存在?

例如:

拦截 /api/user

系统需要判断:

  • 已有规则
  • 还是新规则

代码节选:

privateasynccheckerNode(state:GraphState):Promise<Partial<GraphState>>{letactiveId=state.activeId;// 校验 activeId 真实性,防止过时的ID或AI幻觉if(activeId&&!state.rules.some(r=>r.id===activeId)){activeId='';}constpath=state.pendingRule?.path||'';if(path){constexactMatch=state.rules.find(r=>r.path===path);if(exactMatch){return{activeId:exactMatch.id};}// 如果意图是切换或查看,允许模糊匹配if(state.intent==='switch'||state.intent==='refine'){constfuzzyMatch=state.rules.find(r=>r.path.includes(path)||path.includes(r.path));if(fuzzyMatch){return{activeId:fuzzyMatch.id};}}}return{activeId:''};}

注意:这里使用纯代码,路径匹配属于确定性逻辑,不用交给 LLM。

3.5.4 Consultant 节点:补全规则

如果用户信息不完整,例如:

拦截 /api/user

但没有说明返回内容。

这时 Consultant 节点会:

  • 解析已有信息
  • 判断是否完整
  • 引导用户补充

代码节选:

privateasyncconsultantNode(state:GraphState):Promise<Partial<GraphState>>{constprompt=devNetSmartAssistantPrompts.consultant.replaceAll('{{path}}',state.pendingRule?.path||'').replaceAll('{{userInput}}',state.userInput);constres=awaitthis.callModel([{role:'user',content:prompt}]);constresult=this.extractJson(res);return{pendingRule:result.pendingRule,isComplete:result.isComplete,markdownOutput:result.reply};}

Prompt 示例:

用户希望创建一个新的 API Mock 规则。 当前信息: path: {{path}} 用户输入: {{userInput}} 请提取规则信息,并判断是否完整。 返回 JSON: { "pendingRule": { "path": "", "responseBody": "", "delay": 0 }, "isComplete": true, "reply": "如果信息不完整,需要向用户提问" }

3.5.5 NewInit 节点:创建规则

当 Consultant 判断信息完整后,就进入NewInit节点。

这里不再使用 AI,而是由程序创建规则对象:

privateasyncnewInitNode(state:GraphState):Promise<Partial<GraphState>>{// 组装最终生成的规则对象constnewRule:ApiRule={id:uuidv4(),sessionId:state.threadId,path:state.pendingRule.path||'',active:true,mode:'mock',responseBody:state.pendingRule.responseBody||'',delay:state.pendingRule.delay||0};return{rules:[...state.rules,newRule],activeId:newRule.id};}

核心原则:AI 只负责理解需求,最终数据结构由代码生成。

3.5.6 Presenter 节点:结果生成

最后由 Presenter 统一输出结果。

privateasyncpresenterNode(state:GraphState):Promise<Partial<GraphState>>{constprompt=devNetSmartAssistantPrompts.presenter.replaceAll('{{intent}}',state.intent).replaceAll('{{resultInfo}}',state.status).replaceAll('{{userInput}}',state.userInput);constres=awaitthis.callModel([{role:'user',content:prompt}]);return{markdownOutput:res};}

Prompt 示例:

你是一个友好的 AI 助手。请根据当前的处理结果,为用户生成一段总结性的回复。 用户意图: {{intent}} 用户输入: {{userInput}} 当前操作结果: {{resultInfo}} 回复要求: 1. 回复整体使用 Markdown 格式呈现。 2. 内容简洁明了,禁止直接返回 JSON 格式的代码块。 3. 规则优先级(按顺序匹配,符合一条后停止) - 优先级1:xxx ...... 请直接生成符合上述要求的回复内容

3.6 构建 Graph

完整代码:

privatebuildGraph(){constg=newStateGraph(GraphChannels).addNode('router',(s:GraphState)=>this.routerNode(s)).addNode('refiner',(s:GraphState)=>this.refinerNode(s)).addNode('checker',(s:GraphState)=>this.checkerNode(s)).addNode('switcher',(s:GraphState)=>this.switcherNode(s)).addNode('consultant',(s:GraphState)=>this.consultantNode(s)).addNode('new_init',(s:GraphState)=>this.newInitNode(s)).addNode('presenter',(s:GraphState)=>this.presenterNode(s)).addEdge(START,'router')// 意图跳转逻辑.addConditionalEdges('router',(s:GraphState)=>{if(s.intent==='refine'){// 微调已有规则return'refiner';}if(s.intent==='switch'||s.intent==='new_api'){// 新增规则或切换规则return'checker';}return'presenter';})// Checker 跳转逻辑.addConditionalEdges('checker',(s:GraphState)=>{if(s.activeId){// 规则存在,切换规则return'switcher';}// 规则不存在,引导用户确认规则return'consultant';}).addEdge('refiner','presenter').addEdge('switcher','presenter')// Consultant 跳转逻辑:只有信息完整才初始化.addConditionalEdges('consultant',(s:GraphState)=>{if(s.isComplete){return'new_init';}return'presenter';}).addEdge('new_init','presenter').addEdge('presenter',END);returng.compile();}

4. 关键设计总结

这个 LangGraph 工作流有三个非常重要的工程原则:

4.1 AI 只做理解

AI 只负责:

  • 意图识别
  • 规则解析
  • 信息补全

不负责:

  • 状态管理
  • 数据结构
  • 流程控制

4.2 流程控制由代码完成

所有逻辑判断都在 Graph 中:

router -> checker -> consultant -> new_init

而不是 Prompt 中。

4.3 强制结构化输出

流程程中 AI 输出必须是 JSON,否则直接丢弃。这样可以大幅降低:

  • 幻觉
  • 格式错误
  • Prompt 不稳定

5.遇到的问题

5.1 虽然提示词中限制输出JSON,但LLM有时不按约定返回

虽然在提示词中强制了大模型必须输出 JSON 格式内容,但总有特例,LLM不按照规定格式输出,比如返回:

好的,{JSON内容} 或者 输出的内容使用 ```json ```包裹

下面是几种兜底方式:

  1. 调用模型时传入 response_format 参数(需API支持),强制模型返回合法的JSON格式字符串。
{"model":"gpt-4o","messages":[{"role":"system","content":"你是一个助手,请输出用户信息的JSON。"},{"role":"user","content":"用户叫张三,25岁。"}],"response_format":{"type":"json_object"}}
  1. 从回答中提取出JSON格式字符串。
  2. 如果以上两步获取后的JSON还是解析失败,增加重试机制,让LLM自动纠错并输出正确内容,Prompt示例:
'下面这段文本本应是一个完整、可 JSON.parse 的对象,但可能夹杂了说明文字、markdown 或语法错误。请只输出修复后的那一个 JSON 对象本身,不要代码块、不要任何解释。\n\n' {{模型输出的内容}}

6. 参考文章

● LangGraph 官方文档
● ‘顾得助手’插件功能更新介绍

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 14:10:48

Pixel Dimension Fissioner开源模型:MIT协议,支持二次开发与领域微调

Pixel Dimension Fissioner开源模型&#xff1a;MIT协议&#xff0c;支持二次开发与领域微调 1. 模型概述 Pixel Dimension Fissioner&#xff08;像素语言维度裂变器&#xff09;是一款基于MT5-Zero-Shot-Augment核心引擎构建的开源文本改写与增强工具。该模型采用MIT开源协…

作者头像 李华
网站建设 2026/7/14 14:11:08

科技信息最前沿202603——面向汽车系统的安全合规 Transformer 架构

摘要&#xff1a;慕尼黑工业大学提出面向汽车系统的安全合规Transformer架构&#xff0c;旨在解决深度学习模型在自动驾驶领域的应用挑战。研究通过ISO26262标准中的ASIL分解原则&#xff0c;构建"独立编码器-共享潜空间-通用解码器"框架&#xff0c;实现多模态冗余与…

作者头像 李华