仿淘宝 AI 推荐:用 Next.js 构建入门智能水果推荐 Demo

大家好,我是印刻君。平时逛淘宝的时候,不知道大家有没有体验过平台的 AI 搜索功能。它能结合你的需求,做相对精准的商品推荐。

今天我想和大家分享一个入门级别的 Demo,用 Next.js 简单实现类似的推荐助手,内容偏基础。

我们最终实现的 Demo 视频如下,它主要就 3 项基础功能:

  1. 基础的 AI 聊天对话,支持流式消息回复;
  2. 简易的水果价格查询,支持价格升序、降序查询;
  3. 对话过程中嵌入商品卡片,引导用户购买。

视频链接:mp.weixin.qq.com/s/pousaUIg7...

一、先搭建基础的聊天机器人

在实现推荐功能之前,我们先搭建一个基础的 AI 聊天机器人。本次 Demo 以接入 DeepSeek 大模型为例,整体可以分为 4 个关键步骤:

1.1 设计聊天界面

一个聊天界面包括两大核心部分,

  • **消息展示区:**是用户消息和 AI 消息的列表,常规布局是 AI 消息靠左展示,用户消息靠右展示;

  • 下方的输入框:包括文本输入框和发送按钮,一直固定在页面底部。

UI 布局很常规,我们不详细展开介绍,重点分析一个智能滚动交互------当消息增多时,消息展示区应该会自动滚动到底部,确保用户能第一时间查看到最新的回复。

要实现这个效果,我们可以在聊天消息列表的底部放一个元素,借助 useRef 绑定它,并配合 useEffect 监听消息。当消息变化时,通过 scrollIntoView 方法,触发自动滚动。

tsx 复制代码
export function Chatbot() {
  const messagesEndRef = useRef<HTMLDivElement>(null);
  // ...
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({
      behavior: "smooth"
    });
  }, [chat.messages]);
  // ...
  return (
    <div>
      {/* ... */}
      <div ref={messagesEndRef} />
    </div>
  )
}

1.2 简化聊天状态管理

界面搭建好之后,我们需要处理消息的发送、接收、加载等逻辑,手动编写相关代码比较繁琐,推荐使用 @ai-sdk/react 提供的 useChat Hook,它可以帮助我们大幅简化状态管理。

useChat 返回的对象中,我们主要用到 3 个属性:

  1. messages:消息列表,包括用户发送的消息和 AI 的回复,可以直接遍历渲染;
  2. status:当前状态,表示消息是否正在发送或流式传输中,可以用来做加载状态的交互;
  3. sendMessage:将用户的输入发送给后端的方法,可以用来和 AI 对话。
tsx 复制代码
import { useChat } from "@ai-sdk/react";

export function Chatbot() {
  const chat = useChat({
    transport: new DefaultChatTransport({
      api: "/api/chat",
    }),
  });

  const handleSend = async () => {
    // ...
    await chat.sendMessage({ text });
  };

  // ...
  const isLoading = chat.status === "submitted"
                    || chat.status === "streaming";
  // ...

  return (
    <div>
      {/* ... */}
    </div>
  )
}

1.3 搭建后端 API 服务

之前介绍的都是前端逻辑,想要真正调用 AI 模型,需要后端做中转。

后端主要做三件事:

  1. 转换消息格式:使用 convertToModelMessages 将前端格式的消息转换成大模型能识别的标准格式;
  2. 调用模型:使用 streamText 以流式方式调用大模型生成回复。
  3. 返回流式响应:使用 toUIMessageStreamResponse 将模型的流转换成符合 HTTP 规范的 SSE(Server-Sent Events)响应,前端可以实时接收并显示。

注意,需要在 DeepSeek 的控制台申请一个 API Key,并且放到 .env.local 文件中。@ai-sdk/deepseek 会自动读取该文件下的 DEEPSEEK_API_KEY

后端代码示例如下:

ts 复制代码
import { convertToModelMessages, streamText } from "ai";
import { deepseek } from "@ai-sdk/deepseek";

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const { messages: uiMessages } = body;

    const modelMessages = await convertToModelMessages(uiMessages);

    const result = streamText({
      model: deepseek("deepseek-chat"),
      messages: modelMessages,
    });

    return result.toUIMessageStreamResponse();
  } catch (error) {
    // ...
  }
}

1.4 美化消息展示

完成前 3 步后,其实已经搭建好了一个聊天机器人,可以和 deepseek 模型进行对话。

但实际使用中,大模型返回的内容常常是 Markdown 格式的,直接渲染会显得比较杂乱。

我们可以用 streamdown 来美化 AI 返回的信息,它是专门处理 AI 流式消息的组件。

通过 npm 安装 streamdown 之后,我们可以这样使用 Streamdown 组件:

  1. 从 useChat 返回的 messages 中提取出需要展示的文本消息;
  2. 将文本内容作为子元素传递给 Streamdown 组件,就可以自动完成格式解析。

核心渲染代码如下:

jsx 复制代码
export function Chatbot() {
  // ...
  return (
    {/* */}
    {chat.messages.map((message) => {
      // 从 parts 中提取 text
      const textPart = message.parts?.find(
        (p) => "text" in p && typeof p.text === "string",
      ) as { type: "text"; text: string } | undefined;
      
      const content = textPart?.text || "";

      return (
        <div key={message.id}>
          <div>
            {message.role === "user" ? (
              content
            ) : (
              <Streamdown animated isAnimating={isLoading}>
                {content}
              </Streamdown>
            )}
          </div>
        </div>
      );
    })}
  )
}

到这里,我们便搭建了一个像模像样的聊天机器人。接下来我们基于这个机器人,扩展出商品推荐的功能。

二、实现 AI 工具调用,完成水果推荐

基础的聊天机器人只能对话,它不知道我们预设的水果数据,没办法做水果推荐。所以我们需要给 AI 加上工具调用(Tool Call)能力。让 AI 能主动调用我们的数据查询工具,获取水果相关数据后再推荐。

比如用户问最便宜的水果是什么?最贵的水果是什么?AI 就会调用我们的查询工具,拿到排序好的数据推荐给用户。

实现这个功能,你需要经过 3 个步骤:

  1. 定义 AI 调用的工具;
  2. 实现工具执行的函数;
  3. 渲染工具的结果。

2.1 定义 Tool

我们从 ai 的 npm 包中引入 tool 和 jsonSchema,定义一个专门查询水果的工具。主要参数有:

  • description,告诉 AI 这个工具的用途;
  • inputSchema,约束 AI 调用工具时输入的参数格式;
  • execute,绑定的执行函数。
ts 复制代码
import { tool, jsonSchema } from 'ai';

const tools = {
  findFruits: tool({
    description: "查询水果数据,并根据用户的要求返回数据",
    inputSchema: jsonSchema<{
      query?: string;
      limit?: number;
      sortBy?: SortStrategy;
    }>({
        // ...
      },
      required: ["query"],
      additionalProperties: false,
    }),
    execute: findFruitsFunc,
  }),
};

// ...
const result = streamText({
  model: deepseek("deepseek-chat"),
  system:
    "你是一个专业的水果销售助手。当用户询问水果相关问题时,请先调用 findFruits 工具获取数据,然后根据返回的结果用友好的方式向用户推荐并说明理由。",
  messages: modelMessages,
  tools,
  stopWhen: stepCountIs(5),
});

定义好工具后,在调用 streamText 时把工具传入,模型会自动分析用户的输入,判断是否需要调用该工具。

2.2 实现 tool 的执行函数

真正的查询逻辑,是在工具执行函数里进行的,本次 Demo 为了简化理解,我们用一个数组来代替数据库,我们的查询也只是实现了价格升序、价格降序两种查询。

真实场景中,这里会替换为数据库查询,接口调用等逻辑,但核心思路和这个 Demo 是一致的,大家可以自行拓展。

ts 复制代码
const fruits = [
  {
    id: "apple",
    name: "苹果",
    price: 8.8,
    unit: "斤",
    desc: "红富士苹果,口感清爽",
    tags: ["红富士", "水果", "新鲜"],
  },
  // ...
]

const findFruitsFunc = async ({
  sortBy = "price_asc",
}: {
  sortBy?: SortStrategy;
}) => {
  const sortedFruits = fruits.toSorted((a, b) => {
    return sortBy === "price_asc" ? a.price - b.price
                                  : b.price - a.price;
  });

  return {
    sortBy,
    results: sortedFruits,
  };
};

工具执行完毕后,结果会自动传递给大模型,AI 会解析结果内容,再生成相应的自然语言回复。

2.3 前端渲染工具结果

后端把工具查询结果和 AI 文本返回给前端后,前端需要区分普通文本和工具结果。

  • 普通文本:利用 Streamdown 渲染;
  • 工具结果:业务自定义,我们这里是水果推荐,因此会把工具结果渲染为水果推荐卡片。

怎么区分普通文本和工具结果呢,我们可以根据消息的 parts 中每一项的 type 来判断,如果是 text 则是文本,如果是 tool-findFruits 则是 findFruits tool 的结果,可以渲染水果卡片组件。

tsx 复制代码
export function Chatbot() {
  return (
    <div>
      {chat.messages.map((message) => {
        return (
          <div>
            {message.parts?.map((part) => {
              switch (part.type) {
                case 'text': {
                  // ... Streamdown 相关逻辑
                }
                case 'tool-findFruits': {
                  // ... 返回前端水果卡片
                }
                default:
                  return null
              }
            })}
          </div>
        )
      })}
    </div>
  )
}

三、总结

以上就是入门 Demo 的全部实现,通过 AI 聊天功能 + AI 工具调用,就可以简易模拟电商平台的 AI 搜索推荐功能。

当然,这个 Demo 只是入门演示级别,和真实电商推荐系统相比,还有很多可以完善的地方。比如对用户输入的校验、兼容、和真实数据库的对接、用户历史对话记忆等等。但这个 Demo,已涵盖了 "前端交互 + AI 流式调用 + 工具调用 + 结果可视化" 的核心链路。

我是印刻君,一位探索 AI 的前端程序员。关注我,让前端知识有温度,技术落地有深度。

相关推荐
岁岁种桃花儿2 小时前
AI超级智能开发系列从入门到上天第三篇:AI应用需求分析
人工智能·ai
诚诚程程成2 小时前
URL Query Editor 前端开发工具:方便调试页面URL参数 URL参数可视化
前端
文化人你不懂得2 小时前
AI能力的边界
人工智能
CHU7290352 小时前
直播逛购新体验——直播商城APP前端功能详解
前端·小程序
Jackson__2 小时前
Agent Skill 和 MCP 到底有什么区别?很多人搞混了
前端·ai编程·mcp
GJGCY2 小时前
2026企业级AI智能体架构对比:RPA+大模型融合在财务场景的表现
大数据·人工智能·ai·rpa·智能体
无心水2 小时前
【OpenClaw:应用与协同】23、OpenClaw生产环境安全指南——Token管理/沙箱隔离/权限最小化
大数据·人工智能·安全·ai·性能优化·openclaw
向上的车轮2 小时前
AI Agent开发框架——站在巨人肩膀上的入门指南(一):思考-行动的循环
人工智能
_YiFei2 小时前
2026年度论文降重工具全维度评测|高效、合规、低重复率综合榜单
人工智能·深度学习