使用LangChain、LangGraph和开源大模型构建实时AI代理:Ollama实战讲解

2024/12/6 21:03:48

本文主要是介绍使用LangChain、LangGraph和开源大模型构建实时AI代理:Ollama实战讲解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

随着人工智能能力的不断提升,工程师们正在探索构建智能应用的新途径。在本文中,我们将介绍如何使用尖端的开源工具和框架来构建一个AI搜索代理的概念验证。我们将利用LangGraph来编排工作流,使用LangChain来集成大型语言模型,使用Ollama运行开源模型,如Llama3.1,并使用Next.js来构建全栈混合web应用。让我们开始吧!

搭建环境

要开始,你需要一个 JavaScript/TypeScript 开发环境。这里提到的是我们将会用到的关键技术。下面是一些我们将用到的关键技术:

  • Node.js 和 npm
  • TypeScript
  • Next.js
  • Zod
  • LangChain
  • LangGraph
  • Ollama(用于运行 Llama 3.1)
  • LangSmith(用于可观察性)

确保你已经安装了 Node.js(LTS 版本 v20 或更高版本),然后创建一个 Next.js 项目。

    npx create-next-app@latest poc-ai  
    cd poc-ai  
    npm i

运行以下命令来创建一个新的Next.js项目并安装依赖项.

安装一下必需的依赖项。

    npm i @langchain/community @langchain/core @langchain/langgraph @langchain/ollama nanoid zod

// 该命令用于安装指定的npm包,包括@langchain社区、核心、langgraph、ollama、nanoid和zod。

项目结构:
poc-ai/  
├── src/  
│   ├── ai/  
│   │   ├── agents/  
│   │   │   └── index.ts  
│   │   ├── llm-model/  
│   │   │   ├── index.ts  
│   │   │   └── ollama.ts  
│   │   └── tools/  
│   │       ├── index.ts  
│   │       └── searchTool.ts  
│   ├── app/  
│   │   └── api/  
│   │       └── ai/  
│   │           └── route.ts  
│   └── ...  
├── .env.local  
├── .eslintrc.json  
├── .gitignore  
├── next-env.d.ts  
├── next.config.mjs  
├── package-lock.json  
├── package.json  
├── postcss.config.js  
├── README.md (读我(README))  
├── tailwind.config.ts  
└── tsconfig.json
实现AI代理程序:

我们来看看关键部分:

LLM模型配置(使用Ollama,与Llama 3.1):

此代码使用Ollama(一个特定的平台或工具)设置我们的语言模型为,并将其与自定义工具集成。

    // src/ai/llm-model/ollama.ts  
    import { ChatOllama } from "@langchain/ollama";  

    const 模型名称 = "llama3.1";  

    export const llm = new ChatOllama({  
      model: 模型名称,  
      温度: 0,  
    });
// src/ai/llm-model/index.ts
import { 工具 } from "../tools";
import { llm } from "./ollama";

export const 模型 = llm.bindTools(工具);

LangGraph Agent(Langchain配置):

这建立了我们的LangGraph工作流,定义了智能体的决策方式和工具使用。

    // src/ai/index.ts

    import { MemorySaver, StateGraph } from "@langchain/langgraph";
    import { callModel, shouldContinue, StateAnnotation } from "./agents";
    import { toolNode } from "./tools";
    import { HumanMessage } from "@langchain/core/messages";

    // 定义一个新的图
    export const workflow = new StateGraph(StateAnnotation)
      .addNode("agent", callModel)
      .addNode("tools", toolNode)
      .addEdge("__start__", "agent")
      .addConditionalEdges("agent", shouldContinue)
      .addEdge("tools", "agent");

    // 初始化内存以在图运行之间持久化状态
    const checkpointer = new MemorySaver();

    export const startRunnable = async (query: string, thread_id: string) => {
      // 最终,我们编译它,
      // 这将它编译成一个 LangChain 可执行对象,同时传递了内存。
      // 注意,我们在编译图时(可选)传递了内存。
      const app = workflow.compile({ checkpointer });
      // 使用这个可执行
      const finalState = await app.invoke(
        {
          messages: [new HumanMessage(query)],
        },
        { configurable: { thread_id: thread_id } }
      );

      // 返回最终状态的最后一条消息的内容。
      return finalState.messages[finalState.messages.length - 1].content;
    };
    // src/ai/agents/index.ts  

    import {  
      AIMessage,  
      BaseMessage,  
      SystemMessage,  
    } from "@langchain/core/messages";  
    import { Annotation } from "@langchain/langgraph";  
    import { model } from "../llm-model";  

    export const StateAnnotation = Annotation.Root({  
      messages: Annotation<BaseMessage[]>({  
        reducer: (x, y) => x.concat(y),  
      }),  
    });  

    // 定义一个函数来判断是否继续执行  
    // 我们可以通过 `StateAnnotation.State` 来提取状态类型  
    export function shouldContinue(state: typeof StateAnnotation.State) {  
      const messages = state.messages;  
      const lastMessage = messages[messages.length - 1] as AIMessage;  

      // 如果LLM调用了一个工具,则转向"tools"节点  
      if (lastMessage.tool_calls?.length) {  
        return "tools";  
      }  
      // 否则,我们停止(回复给用户)  
      return "__end__";  
    }  

    // 定义一个函数来调用模型  
    export async function callModel(state: typeof StateAnnotation.State) {  
      const messages = state.messages;  
      const response = await model.invoke([  
        new SystemMessage(`你是一名记者,正在传达新闻信息。  
        请根据以下请求总结句子。  

    请求:  

1. 用第一句话总结文章,保持在5行或更少。  

2. 用项目符号列出主要要点,并使用印地语。  

3. 不要翻译任何技术术语。  

4. 不要包含任何不必要的信息。  

    你有工具可以在互联网上搜索和获取数据,然后进行总结。  

    摘要:  
    `),  
        ...messages,  
      ]);  

      // 我们返回一个列表,因为这将被添加到现有的消息列表中  
      return { messages: [response] };  
    }

自定义搜索工具(使用Tavily的搜索工具):

我们使用自定义工具Tavily搜索API来获取现实世界数据。

// src/ai/tools/searchTool.ts
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";

// 搜索工具,用于从TavilySearchResults获取最多10条结果
export const searchTool = new TavilySearchResults({
  maxResults: 10,
});
// src/ai/工具/index.ts 文件
import { ToolNode } from "@langchain/langgraph/prebuilt";  
import { searchTool } from "./searchTool";  

export const 工具列表 = [searchTool];  
export const toolNode = new ToolNode(工具列表);

API 路由创建 —Next.js (应用路由):

这设置了我们的Next.js API路由,来处理收到的请求,并与我们的AI代理进行互动。

    // src/app/api/ai/route.ts  
    import { startRunnable } from "@/ai";  
    import { nanoid } from "nanoid";  
    import { z } from "zod";  

    const InputBodySchema = z.object({  
      message: z.string().min(1),  
      chatId: z.string().optional(),  
    });  

    type InputBodyType = z.infer<typeof InputBodySchema>;  

    export async function POST(req: Request) {  
      const { message, chatId }: InputBodyType = await req.json();  
      const result = InputBodySchema.safeParse({ message, chatId });  

      if (!result.success) {  
        return Response.json({ data: null, error: result?.error }, { status: 500 });  
      }  
      const res = await startRunnable(message, chatId ?? nanoid());  

      return Response.json({ data: JSON.stringify(res) });  
    }

配置环境变量设置:在根目录下创建一个 .env.local 文件并在该文件中添加您的 API 密钥:

    LANGCHAIN_TRACING_V2=true  # 这是语言链跟踪的环境变量 (This is the environment variable for LangChain tracing)
    LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
    LANGCHAIN_API_KEY="your_langchain_api_key"  # your_langchain_api_key (你的LangChain API密钥)
    LANGCHAIN_PROJECT="your_project_name"
    TAVILY_API_KEY="our_tavily_api_key"
    LANGCHAIN_CALLBACKS_BACKGROUND=true  # 背景回调开关 (background callback toggle)
利用LangSmith提升可观测性

LangSmith 提供了强大的追踪和调试能力,以帮助我们追踪和调试 LangChain 应用程序。从这些截图中,我们可以看到 LangSmith 如何可视化我们代理的决策流程、工具使用情况及其整体性能。

这里是一个查看 Langsmith POC 的链接。

使用 LangSmith 的关键优势:
  1. 详细追踪代理的工作流程中的每一步
  2. 性能数据和延迟分析
  3. 轻松调试复杂的人工智能流水线

启动应用

使用英文“Ollama”和“Llama”,启动你的 Ollama 服务器,并使用 Llama 3.1 模型

运行一下 llama3.1
  1. 运行你的 Next.js 开发服务器:npm run dev:

  2. http://localhost:3000/api/ai 发送一个 POST 请求到,其中请求体包含一个包含 message 字段的 JSON 数据。

    这里我用的是VS Code中的REST客户端。

比如这样的查询和回复:

有人问:关于西孟加拉的抗议活动,发生了什么事?

回复:
    {  
      "data": "\"本文是一句话总结:\n\n在印度西孟加拉邦,一名在公立医院实习的医生遭到强奸并遇害后,数千名抗议者堵塞了铁路轨道,使巴士停止运行,并呼喊口号。\n\n主要要点摘要(印地语):\n\n1. 印度西孟加拉邦公立医院的一名住院医生遭到强奸和杀害。\n2. 数千名抗议者走上街头。\n3. 抗议者堵塞了铁路轨道并使巴士停止运行。\n4. 人们呼喊口号,要求正义。\n5. 这一事件引发了对当地法律和秩序状况的质疑。\""
    }
结语

我们尝试使用LangGraph、LangChain和开源LLM来构建AI驱动的搜索代理。我们看到了这些工具可以如何结合来创建强大且灵活的AI应用。通过利用LangSmith的可观测性,我们可以轻松地调试和优化AI工作流程。

概念验证展示了这些技术在创建智能应用和情境理解方面的潜力。在继续探索并使用这些工具时,请记得要考虑到人工智能系统的伦理问题和潜在的偏见。

喜欢这些内容吗?
如果你想支持我,可以请我喝杯咖啡吧!你的支持让我能继续创作更多有用的内容。
在这里请我喝杯咖啡。☕&#128187;

如果你对这个项目感兴趣,或者想讨论人工智能工程的话题,可以在LinkedIn: Manoj Mukherjee上与我联系。

我一直都在寻找机会扩展我的AI职业生涯。如果您有兴趣合作或讨论潜在的机会,请随时联系我。我愿意分享更多关于这个项目的信息,并探讨我们如何一起突破AI技术的界限。

祝大家编码愉快,期待能与各位AI爱好者和专业人士互动!

照片由Hanny Naibaho在Unsplash发布。



这篇关于使用LangChain、LangGraph和开源大模型构建实时AI代理:Ollama实战讲解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程