- SignalDesk3小时前
本帖使用社区开源推广,符合推广要求。我申明并遵循社区要求的以下内容: 我的帖子已经打上 开源推广 标签: 是 我的开源项目完整开源,无未开源部分: 是 我的开源项目已链接认可 LINUX DO 社区: 是 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是 以上选择我承诺是永久有效的,接受社区和佬友监督: 是 以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出 本文是 【AgentSeed】从零开始的Agent开发教程的第三章(下),用最简单的代码带你了解Agent相关概念,并实现自己的Agent原型机! 教程目录 : 【AgentSeed】从零开始的Agent开发教程——前言 & 目录 项目主页 : 【AgentSeed】从零开始的Agent开发教程 —— GitHub 上一节内容 ,我们了解了浏览器、网页和服务器之间的关系,也用 HTML、CSS 和 JavaScript 做出了一个可以交互的页面。 接下来我们就从一个最小的 WebChat 开始,将之前的命令行对话程序逐步搬到网页中。这篇内容完成后你将得到下面的Web Agent! Link Start!第一个 Web Agent 原型机 启动! 前言:导读 这一节,我们将之前运行在终端中的 Agent原型机放进浏览器,完成一个最小的 WebChat。 如果想直接复现最终效果,可以跳转到后文的“ 第四章:快速开始 ”部分; 如果想学习理解浏览器、前端和后端是怎样协作的,可以按照文章顺序继续阅读。 现在我们从整体设计开始,看看一个 WebChat 到底由哪些部分组成! 第一章:从顶层开始设计Web Agent 一、 从终端对话到 WebChat 在前面的章节中,我们已经可以通过 Python 程序调用模型了。 但是,如果我们希望其他人也能使用这个 Agent。更自然的方式是提供一个Web服务,这样用户就可以通过浏览器直接进行交互。这就是这篇教程要解决的问题。 Web Agent并不会改变模型调用的基本过程,只是给这个过程使用Web服务的方式进行包装,提供了一个更方便的入口: 终端输入 → 改成 → 浏览器输入 终端打印 → 改成 → 网页展示 为了实现用户可以通过自己的设备访问服务,我们需要原来的程序拆成两个部分: 前端 :运行在用户侧中,负责展示聊天内容、接收用户输入和响应点击操作; 后端 :运行在服务器中,负责接收前端请求、维护对话历史和调用模型。 这种设计的目的在于实现了两套逻辑的解耦( 交互逻辑 & 计算逻辑) 前端只需要把用户输入交给后端,而忽略实际复杂代码调用权限校验的细节。而后端只需要接收数据、处理数据,然后返回结果,而不用考虑前端交互形式。这样每一部分的职责都会清晰很多。 二、 WebChat 中的角色与分工 为了理解后面的代码,我们先把一次 WebChat 对话中的几个角色列出来: 角色 负责什么 用户 输入消息,并阅读模型回复 浏览器(前端) 展示网页,执行 JavaScript FastAPI(后端) 接收请求,组织后端逻辑 模型服务(第三方外部服务) 根据消息历史生成回复 可以把它们理解成一条流水线。 用户在浏览器中输入消息 浏览器中的 JavaScript 将消息整理成 HTTP 请求 ,发送给 FastAPI FastAPI 收到请求后,把消息加入当前对话,调用模型服务 模型返回结果后,FastAPI 将结果整理成浏览器能够理解的 JSON 数据 最后由 JavaScript 把回复放到页面上。 这里有一个容易产生误解的地方: 浏览器并不是直接调用模型。 浏览器只和我们自己的 FastAPI 后端通信。真正需要 API Key、需要保存上下文、需要调用模型服务的工作,都放在后端完成。 这样做有两个好处: 1. 敏感信息不会直接暴露在网页代码中 :网页代码会被发送到用户的浏览器,任何人都可以查看;API Key 则应该只保存在后端环境中。 2. 模型调用逻辑集中在后端 :后续可以增加消息校验、权限控制、日志记录和持久化存储,而不需要把这些逻辑都放进浏览器。 第二章:Link Start!设计前后端的协议 一、聊天接口:前后端之间的约定 在编写代码之前,我们先约定一个最小的聊天接口。 这个接口只需要完成一件事:接收用户的一条消息,并返回模型的一条回复。 接口地址可以设计为: POST /api/messages 为什么使用 POST?因为这次请求不只是读取数据,而是要把用户输入提交给服务器,并触发一次新的模型调用。按照 HTTP 中常见的使用方式,这类操作适合使用 POST 请求。 客户端发送的请求体如下: { "content": "你好" } 这里的 content 就是用户在输入框中填写的内容。 服务器处理完成后,返回一条助手消息: { "role": "assistant", "content": "你好,很高兴认识你。" } 可以先把这个接口理解成一个服务窗口:浏览器把用户消息递进去,FastAPI 在窗口后面完成模型调用,再把模型回复传出来。 接下来,我们先实现这个接口的后端部分,再让网页通过 JavaScript 调用它。 二、 FastAPI:消息抵达后端后如何处理 现在接口格式已经确定了,接下来后端需要将它根据 FastAPI 撰写具体逻辑。 我们先看一个完整的后端接口: from fastapi import FastAPI from pydantic import BaseModel, Field app = FastAPI() messages: list[dict[str, str]] = [] class MessageRequest(BaseModel): """描述前端提交的一条消息。""" content: str = Field(min_length=1, max_length=2000) @app.post("/api/messages") def create_message(request: MessageRequest) -> dict[str, str]: """接收用户消息,调用模型,并返回模型回复。""" messages.append({"role": "user", "content": request.content}) assistant_content = call_model(messages) messages.append({"role": "assistant", "content": assistant_content}) return { "role": "assistant", "content": assistant_content, } 这里的 call_model 代表我们前面已经实现的模型调用逻辑。实际项目中,它会使用模型服务的 API 地址、认证信息和消息历史,向模型发送请求。 在这段代码中,FastAPI 主要承担三个职责: 请求校验、路由分发和响应返回 ,而具体的模型调用与对话状态管理,则由我们自己编写的业务逻辑完成。 首先,我们定义前后端之间的数据约定: class MessageRequest(BaseModel): content: str = Field(min_length=1, max_length=2000) 要求前端提交的 JSON 包含符合要求的 content 字段,然后通过FastAPI的路由机制将 HTTP 请求映射到 create_message 函数。后面我们只需要通过根据接口路径(/api/messages)修改处理逻辑,接收请求、解析数据,并将最终结果返回就可以了。 三、浏览器与后端的第一次通信 前面的操作我们已经将后端接口准备处理完毕,接下来只需要在浏览器中主动调用它就可以完成第一次通讯。 在前面的示例中,JavaScript 只是在页面内部修改标题。这一次,我们把按钮点击后的逻辑改成发送 HTTP 请求: const input = document.querySelector("#message-input"); const sendButton = document.querySelector("#send-button"); const messageList = document.querySelector("#message-list"); async function sendMessage() { const content = input.value.trim(); if (!content) { return; } addMessage("user", content); input.value = ""; const response = await fetch("/api/messages", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ content }), }); const assistantMessage = await response.json(); addMessage("assistant", assistantMessage.content); } sendButton.addEventListener("click", sendMessage); 首先,我们从输入框中获取用户输入,并通过 addMessage() 将消息立即显示在页面上,而不需要等待模型返回结果。 随后,通过 JavaScript 提供的 fetch() 方法向后端发送 HTTP 请求 : fetch("/api/messages", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ content }), }); 这里的 fetch() 负责将用户消息发送到我们之前定义的 FastAPI 接口。前端只需要按照约定提交数据,具体的模型调用和对话处理都由后端完成。 当后端返回结果后,我们再通过 response.json() 获取模型回复,并使用 addMessage() 将其显示在聊天窗口中。 至此,一次完整的前后端交互就完成了: JavaScript 负责接收输入、发送请求和更新页面,FastAPI 负责处理消息、调用模型并返回结果。 第三章: 页面设计,让交互更便利 到这里,我们已经实现了一个最基本的 WebChat,能够通过前端发送消息,并在后端调用模型后返回回复。 但目前的页面仍然比较简陋,仅仅满足了基本的功能需求。对于一个完整的聊天应用,除了能够正常工作之外,还需要进一步考虑用户的使用体验,主要包括三个方面: UI 设计 :用户能不能快速分辨消息、输入框和操作按钮; 交互设计 :点击发送后,页面是否立即给出反馈,是否能避免重复提交; 响应设计 :请求成功、请求失败和请求等待时,页面分别应该显示什么。 例如,当模型需要较长时间才能生成回复时,我们可以通过加载动画或“思考中…”的提示,让用户知道程序仍在运行;当网络请求失败时,也应该提供明确的错误信息,而不是让页面一直没有反应。 这些优化并不涉及模型本身,而是为了让整个 WebChat 从一个 能够运行的程序,变成一个具有良好交互体验的应用。 借助 Vibe Coding 完成页面优化 如果我们不熟悉 HTML、CSS 或 JavaScript,也不需要从零开始编写所有页面样式和交互逻辑。可以借助 Vibe Coding ,通过自然语言描述预期效果,让大模型基于现有代码完成页面优化。 例如,我们可以将当前的 static/index.html 提供给模型,并输入下面的提示词: 请基于当前的 WebChat 页面进行 UI 和交互优化: 1. 优化聊天界面布局,区分用户与助手的消息气泡。 2. 添加消息发送时的加载状态,以及请求失败时的错误提示。 3. 优化输入框和发送按钮的交互体验,避免重复提交。 4. 支持不同屏幕尺寸,整体采用简洁、现代的聊天界面风格。 要求: - 保留现有的消息发送和模型调用逻辑。 - 不修改 FastAPI 接口及前后端通信格式。 - 尽量保持代码简洁,避免引入不必要的依赖。 需要注意的是, Vibe Coding 并不意味着完全放弃对代码的控制。 在这里,我们明确限制了模型的修改范围,将页面的视觉设计与交互优化交给模型,同时保留已经实现的前后端通信逻辑,避免因为界面调整而影响原有功能。 模型完成修改后,我们只需要重新运行页面,检查消息能否正常发送、加载状态是否正确,以及异常情况下能否恢复交互。如果发现问题,再通过自然语言描述具体的现象,让模型继续调整。 这种 自然语言描述需求 → 模型修改代码 → 运行验证 → 反馈调整 的开发方式,就是 Vibe Coding 在实际项目中的一种典型应用。 至此,我们已经完成了 WebChat 的基本开发:从后端接口的实现,到前端消息交互,再到借助 AI 优化页面体验。 接下来,我们就可以启动服务,在浏览器中体验这个完整的 WebChat 应用了。 第四章:快速开始 如果还没有获取项目代码,可以先克隆仓库,并切换到本节对应的版本: git clone git@github.com:Nick-Hogo/AgentSeed.git cd AgentSeed git checkout v0.3.2-web-chat 安装项目依赖,并启动FastAPI服务: pip install -e . uvicorn main:app --reload 启动完成后,打开浏览器访问: http://127.0.0.1:8000 即可 终章:总结 这一章,我们把之前只能运行在终端中的模型调用,连接到了浏览器页面。 首先,我们从顶层设计开始,明确了 WebChat 中各个角色的职责:浏览器负责页面和交互,FastAPI 负责接口和业务逻辑,模型服务负责生成回复。 接着,我们设计了 POST /api/messages 接口,约定了前端发送的请求体和后端返回的响应体。浏览器通过 JavaScript 的 fetch 发起请求,FastAPI 接收请求并调用模
- 情报分类:服务器与云资源
- 分类依据:内容涉及服务器、云资源或网络线路
- 信息来源:服务器 / LINUX DO - 最新话题
- 发布时间:2026/10/11 00:28:16
- 暂无回复