LangChain Agent 实战接入指南

2026-06-20阅读 0热度 0
其他

前言

上篇聊完“AI 产品为什么需要内置本地 Agent”,今天直接进入正题——从架构设计到代码落地,把这套方案怎么搭、怎么接、怎么跑,从头到尾拆一遍。

一、整体架构:五层分离

先看分层设计,这决定了整个系统的扩展性和维护成本。

层级技术选型职责
UI 交互层React + 流式 Hook对话界面、审批卡片、结果展示
基础 Agent 层LangChain createAgent()通用问答与工具调用循环
工作流编排层LangGraph StateGraph复杂任务、检查点、中断恢复
工具接入层自研 Tool Adapter屏蔽数据源、本地命令、第三方差异
宿主层Electron Main + Local Service密钥安全、进程管理、随包发布

几个关键的设计判断:

  • 前端直接调模型?这个想法趁早打消。必须在服务层封装一个本地的 Agent Runtime。
  • API Key 不能暴露给前端,工具执行需要统一收口,后续加能力也不用推翻前端重来。
  • LangChain 用来快速起步,LangGraph 用来做复杂编排,工具层则根据业务需求封装。

二、接入步骤

Step 1:建立本地 Agent 服务

新建 ai-agent-server workspace,基于 Hono 框架起一个 HTTP 服务:

// apps/ai-agent-server/src/server.ts
import { Hono } from 'hono';
import { serve } from '@hono/node-server';

export const createAiAgentServer = async (config) => {
  const app = new Hono();
  
  // 健康检查
  app.get('/health', (c) => c.json({ status: 'ready', model: config.model }));
  
  // 问答接口(Step 2 实现)
  registerChatRoutes(app, config);

  const server = serve({ fetch: app.fetch, hostname: config.host, port: config.port });
  return { origin: `http://{config.host}:{server.address().port}`, close: () => ... };
};

这里有两个要点:

  • 服务只监听 127.0.0.1:39321,确保外部无法访问。
  • API Key 只存在服务端环境变量里,永远不会进前端 bundle。

Step 2:接入 LangChain createAgent

先做一个最简的 Agent,只跑普通问答,工具后续再逐步接入:

// apps/ai-agent-server/src/agent/createHomeAiQaAgent.ts
import { createAgent } from 'langchain';
import { ChatOpenAI } from '@langchain/openai';

export const createHomeAiQaAgent = (config) => {
  const model = new ChatOpenAI({
    apiKey: config.apiKey,
    model: config.model,
    temperature: 0.2,
    configuration: { baseURL: config.baseUrl },
  });

  return createAgent({
    model,
    tools: [], // 先不加工具,二期再扩展
    systemPrompt: '你是本地 AI 助手...',
    name: 'home_qa_agent',
  });
};

SSE 流式接口的实现也很直接:

// apps/ai-agent-server/src/routes/chat.ts
export const registerChatRoutes = (app, config) => {
  const agent = createHomeAiQaAgent(config);

  app.post('/api/agent', async (c) => {
    const body = await c.req.json();
    const stream = await agent.stream(
      { messages: body.messages },
      { encoding: 'text/event-stream', streamMode: ['values', 'updates', 'messages'] }
    );

    return new Response(stream, {
      headers: {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache'
      },
    });
  });
};

Step 3:Electron 托管进程

Agent 服务需要随应用自动启动。开发态用 pnpm dev,打包态用 fork:

// electron/src/main/processManager/aiAgentProcess/index.ts
export const startAiAgentProcess = () => {
  if (app.isPackaged) {
    // 打包态:fork 打包后的 js 文件
    aiAgentProcess = childProcess.fork(path.join(__dirname, 'aiAgentServer.js'), []);
  } else {
    // 开发态:pnpm 启动 dev server
    aiAgentProcess = childProcess.spawn('pnpm', ['--filter', 'ai-agent-server', 'dev'], { env: { ...process.env } });
  }
};

前端通过 LinkService 获取运行状态:

// 前端调用
const runtime = await window.LinkService.request('v1/aiAgent/getRuntime');
// runtime = { ready: true, status: 'ready', baseUrl: 'http://127.0.0.1:39321' }

Step 4:前端面板接入

右侧副面板使用 LangGraph SDK 的 useStream Hook:

// apps/src/features/home/components/AiQaPanel/index.tsx
import { FetchStreamTransport, useStream } from '@langchain/langgraph-sdk/react';

const AiQaPanel = ({ runtime }) => {
  const transport = useMemo(() =>
    new FetchStreamTransport({
      apiUrl: `${runtime.baseUrl}/api/agent`,
    }),
    [runtime.baseUrl]
  );

  const stream = useStream({ transport });
  
  return (
    <section>
      <header><h2>AI 问答h2>header>
      {/* 消息列表 */}
      <div>{stream.messages.map(renderMessage)}div>
      {/* 输入框 */}
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={() => stream.submit({ messages: [{ type: 'human', content: input }] })}>发送button>
    section>
  );
};

Step 5:权限审批机制

Agent 一旦能执行本地命令,权限审批就是一道必须跨过的门槛。推荐三层模型:

风险等级典型操作默认策略
low读笔记、读线程上下文自动执行
medium新建文档、导出 PDF首次确认,可记住
highShell 命令、发消息必须逐次审批
critical删除文件、批量外发默认拒绝

用 LangGraph 的 interrupt() 实现审批中断:当 Agent 调用高风险工具时,中断执行并等待用户确认;用户点击"允许"后,resume 继续执行。

前端渲染审批卡片:

<ApprovalCard
  title="读取文件"
  reason="需要读取首页实现文件"
  riskLevel="low"
  onApprove={() => AiAgentApis.approveRequest(requestId)}
  onDeny={() => AiAgentApis.denyRequest(requestId)}
/>

三、记忆管理:短期和长期必须分开

这可不是普通聊天,这是 Agent 和普通 Chat 之间最本质的区别。

短期记忆(Thread Memory)

基于 thread_id 的状态持久化,保存当前会话的:消息历史、任务计划、已调用工具结果、中断点。用 LangGraph 的 checkpointer 实现,开发阶段用 MemorySa ver,生产环境用 PostgresSa ver

长期记忆(User Memory)

跨会话持久保存用户偏好(输出风格、常用配置)、授权偏好、常用操作模板。但不是说所有内容都要记住——只保存三类:用户显式要求记住的、高频重复出现且对后续有帮助的、权限与偏好类配置。

四、任务编排:简单 vs 复杂

简单任务(普通问答、单工具调用)直接用 Agent ReAct 循环即可。

复杂任务(多步骤、有审批、多阶段产物)则需要用 LangGraph StateGraph 显式编排。推荐这样分层:

层次作用
Intent Classifier识别意图:问答 / 查询 / 生成 / 执行 / 工作流
Planner拆解目标为可执行步骤
Supervisor调度子袋里、审批、重试
Executor执行工具或子图
Verifier检查结果是否完整

五、错误处理与并发

错误分类

错误类型示例处理
model_error超时、429自动重试 / 模型降级
tool_error参数错误让 Agent 自修复
permission_error审批被拒中断提示用户
sandbox_error路径非法终止并诊断

重试原则

前提很硬:不是所有错误都能重试。

  • 幂等是重试的第一道门槛:涉及副作用的动作必须带幂等键。
  • 非幂等动作绝不重试:已发送的消息、已执行的外发动作。
  • LLM 429 用指数退避 + 模型降级。

六、总结

LangChain Agent 接入的核心,远不止"接个模型"那么简单。从业务落地来看,需要做好三件事:

  1. 分离架构:UI、Agent、编排、工具、宿主各司其职。
  2. 分步接入:启动服务 → 创建Agent → 进程托管 → UI 面板 → 权限审批。
  3. 安全兜底:权限、记忆、沙箱,一个都不能少。

但更关键的认知是:Agent 本身只是一套执行和编排任务的框架,真正让大模型发挥价值的,还是我们背后的工程化能力——Prompt 调优、RAG 向量工程、模型微调、业务数据集评测、人工复核指标,这些才是更深远的课题。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策