langchain(node.js) 实际应用订单助手

涉及技术点

  1. createAgent(智能体的创建)
  2. tool(工具的调用)
  3. MemorySaver(上下文记忆)
  4. InMemoryStore (将特定信息存到内存)
  5. readline (控制台交互)
  6. zod (输出格式化)
ts 复制代码
import { createAgent, summarizationMiddleware, tool, trimMessages } from "langchain"
import { MemorySaver, InMemoryStore } from "@langchain/langgraph"
import readline from 'readline';

import { getModel } from "../model/index.js";
import z from "zod";
const mainModel = getModel("gpt-4o");
const summaryModel = getModel();


// 下一个订单ID
let nextOrderId = 1;

// 记忆功能
const checkpointer = new MemorySaver();
// 创建内存存储
const store = new InMemoryStore();

const userId = "user123";
const createOrder = tool(
    async ({ customerName, items, totalPrice }, config) => {
        const orderId = `ORD-${String(nextOrderId).padStart(3, "0")}`;
        nextOrderId++;

        const orderData = {
            id: orderId,
            customer: customerName,
            status: "pending",
            total: totalPrice,
            items,
            createdAt: new Date().toISOString(),
        };

        await config.store.put(
            ['orders', userId],
            orderId,
            orderData,
        )
        // 这里必须写return 
        return `订单已创建,客户 ${customerName} 订单商品为 ${items.join(",")},当前商品状态为 ${orderData.status},订单总价为 ${totalPrice} 元。订单编号:${orderId}`
    }, {
    name: 'create_order',
    defaultConfig: '创建订单',
    schema: z.object({
        customerName: z.string().describe("Customer name"),
        items: z.array(z.string()).describe("List of items in the order"),
        totalPrice: z.number().describe("Total order price"),
    })
}
)

const getOrderList = tool(
    async ({ }, config) => {
        try {
            const allOrders = await config.store.search(
                ["orders", userId]
            );

            if (!allOrders || allOrders.length === 0) {
                return "还没有订单";
            }

            const orderSummary = allOrders.map(item => {
                const order = item.value;
                return `客户${order.customer} - ${order.items.join("、")} - ${order.total}元`;
            }).join("\n");

            return `订单列表(共${allOrders.length}个):\n${orderSummary}`;
        } catch (error) {
            return `查询订单列表出错:${error.message}`;
        }
    }, {
    name: 'get_order_list',
    description: "查询所有订单",
    schema: z.object({})
}
)

const getOrderByName = tool(
    async ({ customerName }, config) => {
        try {
            const allOrders = await config.store.search(
                ["orders", userId]
            );
            
            const orderItem = allOrders.find(item =>
                item.value.customer === customerName
            );

            if (orderItem) {
                const order = orderItem.value;
                return `客户 ${customerName} 的订单详情:\n订单ID: ${order.id}\n商品: ${order.items.join("、")}\n总价: ${order.total}元\n状态: ${order.status}`;
            } else {
                return `客户 ${customerName} 没有找到订单`;
            }
        } catch (error) {
            // 错误时也要返回字符串,不要返回 undefined
            return `查询订单出错:${error.message}`;
        }
    }, {
    name: 'get_order_by_name',
    description: "根据客户姓名查询订单详情",
    schema: z.object({
        customerName: z.string().describe("Customer name"),
    })
}
)

const updateOrderStatus = tool(
    async ({ orderId, newStatus }, config) => {
        try {
            const result = await config.store.get(
                ["orders", userId],
                orderId
            );

            if (!result || !result.value) {  // ✅ 检查 result.value
                return `订单 ${orderId} 不存在`;
            }

            const order = result.value;  // ✅ 从 .value 获取数据
            order.status = newStatus;

            // 更新订单
            await config.store.put(
                ["orders", userId],
                orderId,
                order
            );

            return `订单 ${orderId} 状态已更新为 ${newStatus}`;
        } catch (error) {
            return `更新订单状态出错:${error.message}`;
        }
    }, {
    name: 'update_order_status',
    description: "更新订单状态",
    schema: z.object({
        orderId: z.string().describe("Order ID"),
        newStatus: z.string().describe("New order status"),
    })
}
)

const agent = createAgent({
    model: mainModel,
    tools: [createOrder, getOrderList, getOrderByName, updateOrderStatus],
    systemPrompt: `
    你是一个专业的订单助手,负责处理客户订单事务。
        你能够:
        1. 创建新订单
        2. 查询订单详情
        3. 根据订单中的用户名称查询订单
        4. 列出特定客户的所有订单
        5. 更新订单状态(其中pending为待处理,shipped为已发货,delivered为已交付),在返回状态的时候应该返回对应的中文状态
        请根据客户的需求调用相应的工具,并提供清晰准确的回复,在返回的时候不要忘记包含订单ID。
    `,
    // 如果不希望处理其他消息在提示中添加,请不要回答其他问题,只回答与订单相关的问题
    // 那么ai不会处理除订单之外任何问题
    checkpointer,
    store,
    middleware: [
        // 先对消息进行总结
        summarizationMiddleware({
            model: summaryModel,
            trigger: { tokens: 1000 },
            keep: { messages: 25 },
        })
    ],
    preModelHook: async (state) => {
        return {
            // 对消息进行裁剪,保留最后2000个token
            messages: await trimMessages(state.messages, {
                strategy: "last",
                maxTokens: 2000,
                startOn: "human",
                endOn: ["human", "tool"],
                tokenCounter: (msgs) => msgs.length,
            }),
        };
    },
})

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

function askQuestion(query) {
    return new Promise((resolve) => {
        rl.question(query, resolve);
    });
}

async function runChat() {
    console.log("订单助手已启动。输入 'exit' 退出。\n");

    while (true) {
        const userInput = await askQuestion("客户: ");

        if (userInput.toLowerCase() === "exit") {
            console.log("再见!");
            rl.close();
            break;
        }

        const result = await agent.invoke(
            { messages: [{ role: "user", content: userInput }] },
            { configurable: { thread_id: userId } }
        );

        const lastMessage = result.messages[result.messages.length - 1];
        console.log(`助手: ${lastMessage.content}\n`);
    }
}

runChat();
相关推荐
一字白首1 小时前
Node.js+Vue 联动,Vue 快速上手:基础学习
vue.js·学习·node.js
GISer_Jing1 小时前
深入解析Node.js中间件:从Express到Nest
中间件·node.js·express
爱吃无爪鱼1 小时前
02-前端开发核心概念完全指南
css·vue.js·前端框架·npm·node.js·sass
本妖精不是妖精1 小时前
在 CentOS 7 上部署 Node.js 18 + Claude Code
linux·python·centos·node.js·claudecode
遇到困难睡大觉哈哈10 小时前
Harmony os 静态卡片(ArkTS + FormLink)详细介绍
前端·microsoft·harmonyos·鸿蒙
nvd1115 小时前
一个简单的GitHub AI Agent 实现指南
人工智能·langchain
FreeCode15 小时前
一文了解LangGraph智能体设计开发过程:Thinking in LangGraph
python·langchain·agent
曦云沐16 小时前
第二篇:LangChain 1.0 模块化架构与依赖管理
人工智能·langchain·智能体