普通视图

发现新文章,点击刷新页面。
今天 — 2026年5月7日首页

Vue创建一个简单的Agent聊天

2026年5月7日 11:11

创建项目

用的为vue3.6测试版本

npm create vue@latest

什么是Agent?

就是大语言模型+记忆+工具调用

  • 大语言模型:大脑,会思考、理解、规划、推理

  • 记忆:短期对话记忆 + 长期知识库,知道上下文、历史人设、过往任务

  • 工具调用:会联网搜索、查文件、写代码、调接口、操作插件

安装依赖

  npm install @langchain/core @langchain/langgraph @langchain/openai

@langchain/core

LangChain 核心底座

  • 提供统一接口:LLM、Prompt、Runnable、回调、工具
  • 所有 LangChain 生态都依赖它
  • 相当于底层操作系统

@langchain/openai

对接 OpenAI 大模型

  • 让你能调用 gpt-4o, gpt-3.5-turbo
  • 支持结构化输出、工具调用(Tool Calling)
  • 就是 Agent 的大脑

@langchain/langgraph

做 Agent / 智能体的框架

  • 管理:记忆、状态、工具调用、多步骤流程
  • 支持:循环思考、决策、多 Agent 协作
  • 你说的「LLM + 记忆 + 工具调用」= 全靠它实现

env全局变量

TITLE=聊天机器人

# 模型配置
VITE_API_KEY=你的ApiKey 
VITE_AI_MODEL=模型
VITE_AI_BASE_URL=https://api.deepseek.com/v1 # api地址,此处为deepseek

# api配置
# 高德地图配置 https://console.amap.com/dev/key/app # 高德地图api地址
VITE_AMAP_KEY=你的高德地图APIKEy(用于工具:ip地址查询,天气查询)

ts类型

type ROLE = 'user' | 'assistant' | 'system';

interface IChat {
  id: string,
  name: string,
  messages: string,
  role: ROLE,
  created_at: Date
}

export type Chat = IChat;

创建agent

import type { Chat } from "@/types/chat";
import { AIMessage, HumanMessage } from "@langchain/core/messages";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { RunnableSequence } from "@langchain/core/runnables";
import { ChatOpenAI } from "@langchain/openai";

function createLLM() {
  // 创建LLM
  const llm = new ChatOpenAI({
    model: import.meta.env.VITE_AI_MODEL,
    apiKey: import.meta.env.VITE_API_KEY,
    configuration: {
      baseURL: import.meta.env.VITE_AI_BASE_URL,
    },
    temperature: 0.7, // ai生成的内容丰富度
  })

  return llm
}

function createPrompt() {
  // 创建一个提示模板
  return ChatPromptTemplate.fromMessages([
    ["system", "你是善解人意的,且热爱着某人的智能女友"],// 创建个对象(提示词,prompt)
    ["placeholder", "{chat_history}"], // 聊天记录(记忆,memory)
    ["human", "{input}"], // 用户输入的问题
  ])
}

function createChain() {
  const llm = createLLM()
  const prompt = createPrompt()
  // 创建一个链,将prompt和llm联系起来
  return RunnableSequence.from([prompt, llm])
}


export default async function chat(
  input: string,
  onChat: (text: string) => void,
  messages: Chat[] = []) {

  // 历史记录
  const allMessages: Array<HumanMessage | AIMessage> = []

  // 遍历历史聊天记录
  for (const msg of messages) {
    if (msg.role === "user") {
      allMessages.push(new HumanMessage(msg.messages))
    } else if (msg.role === "assistant") {
      allMessages.push(new AIMessage(msg.messages))
    }
  }

  // 添加当前用户信息
  allMessages.push(new HumanMessage(input))

  const chain = createChain()
  const res = await chain.invoke({
    chat_history: allMessages,
    input: input,
  })

  onChat(String(res.content) || '')
}

页面组件

<template>
  <div class="p-4 flex justify-center items-center">
    <div class="flex gap-2 p-4 rounded-2xl shadow-md w-full max-w-200">
      <input v-model="value" class=" w-full outline-0" type="text" placeholder="发送消息吧( •̀ ω •́ )✧">
      <ElButton :disabled="isDisabled" type="primary" @click="onChatHandler">{{ btnText }}</ElButton>
    </div>
  </div>
</template>

<script setup lang="ts">
import chat from '@/agent';
import type { Chat } from '@/types/chat';
import { ElButton, ElMessage } from 'element-plus';
import { computed, reactive, ref } from 'vue';
const value = defineModel<string>(''); // vue3.6提供的新语法糖,不用再props和emit一个modelValue了
const loading = ref(false);
const history = reactive<Chat[]>([]);
const isDisabled = computed(() => !value.value && !loading.value); // 禁用按钮
const btnText = computed(() => loading.value ? '正在思考...' : '发送');

// 生成一个随机字符串
function randomId() {
  return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}

const onChatHandler = async () => {
  if (!value.value) return ElMessage.error('请输入内容');
  loading.value = true;

  console.log("用户:" + value.value);
  console.log("====================================");

  history.push({
    id: randomId(),
    name: 'user',
    messages: value.value,
    role: "user",
    created_at: new Date(),
  });

  try {
    await chat(value.value, (text) => {
      console.log("ai:" + text);
      console.log("====================================");

      history.push({
        id: randomId(),
        name: 'assistant',
        messages: text,
        role: "assistant",
        created_at: new Date(),
      });
    }, history);
  } catch (error) {
    if (error instanceof Error)
      ElMessage.error('请求错误' + error.message);
  } finally {
    value.value = '';
    loading.value = false;
  }

};

</script>

<style lang="css" scoped></style>

经测试,控制台内容如下:

image.png

注意:

  • 诺未生效,可能是没有充值,我deepseek充值了10块钱都用了两个月了
  • apiKey一定要真实的,去模型提供商网站申请
  • 本示例中还使用了element plustailwind css
❌
❌