news 2026/10/7 15:00:08

web人工智能开发实战:基于vue+echart+fastapi+langchain+mcp构建AI智能体助手系统,TaoToken统一Key打通多模型调用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
web人工智能开发实战:基于vue+echart+fastapi+langchain+mcp构建AI智能体助手系统,TaoToken统一Key打通多模型调用

1. 从零搭建 AI 智能体助手:Vue + ECharts + FastAPI + LangChain + MCP 全链路拆解

很多人第一次做 AI 智能体助手系统,卡住的地方往往不是模型本身,而是「前端对话、后端编排、数据看板、多模型 Key 管理」这四件事怎么串起来。我这次要分享的这套方案,前端用 Vue3 + ECharts 做对话窗口和数据看板,后端用 Python + FastAPI + LangChain + MCP 编排 Agent 与 Skill,MySQL 存会话与任务,模型调用统一走 TaoToken 的 Key,一个 Key 打通多家模型。适合谁?适合已经会一点 Vue 和 Python、想做一个能跑起来、能演示、能扩展的智能体助手系统的开发者。

整套系统的核心检索词就是「Vue + ECharts + FastAPI + LangChain + MCP 智能体助手系统」。它能做什么?用户在前端输入问题,后端 Agent 判断意图、调用对应 Skill、必要时通过 MCP 访问外部工具,把结果流式返回前端;同时把每次调用的模型、耗时、Token 消耗写进 MySQL,前端用 ECharts 画出调用趋势和模型分布。下面我按目录结构、依赖、配置、验证、排障的顺序,把每一步都写成可复制、可跟做的形式。

2. TaoToken 前置准备:统一 Key 打通多模型调用

在写代码之前,先把模型调用这一层理顺。传统做法是每个模型厂商申请一个 Key,代码里写一堆 if-else 判断走哪家 SDK,维护成本很高。TaoToken 的思路是提供一个统一的 API 入口,你用同一个 Key 就能调用不同模型,后端只需要改 model 字段,不用改调用逻辑。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。

你需要先拿到 API Key。登录后进入控制台,在 API Keys 页面创建一个新 Key,复制保存。这个 Key 后面会写进后端的环境变量,不要硬编码到代码里,也不要提交到 Git。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,API Keys 页面是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。

拿到 Key 之后,先别急着写业务代码,用最简方式验证一下能不能调通。你可以用 curl 直接请求:

curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "用一句话解释什么是智能体"}] }'

如果返回里有 choices 字段和正常的中文回复,说明 Key 和网络都没问题。这一步很重要,因为后面 FastAPI 里报的很多错,根源其实在这一层。模型对话的在线体验入口是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite ,你可以先在网页上试几个模型,确认哪些模型 ID 可用,再写进后端配置。

关于模型 ID,建议后端维护一个白名单,比如 gpt-4o-mini、claude-3-5-sonnet、deepseek-chat 等,前端下拉框只展示白名单里的模型。这样既方便切换,也避免用户传入不存在的模型导致 400 错误。如果你后面要做长期编码类 Agent,可以关注 Coding Plan 相关入口 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合持续性的代码生成场景。

3. 可复制配置:目录结构、依赖清单与环境变量

先给目录结构,这是整套系统的骨架,照着建就行:

ai-agent-assistant/ ├── backend/ │ ├── app/ │ │ ├── main.py │ │ ├── config.py │ │ ├── agent/ │ │ │ ├── orchestrator.py │ │ │ └── skills/ │ │ │ ├── weather_skill.py │ │ │ └── db_skill.py │ │ ├── mcp/ │ │ │ └── client.py │ │ ├── api/ │ │ │ ├── chat.py │ │ │ └── stats.py │ │ └── db/ │ │ ├── models.py │ │ └── session.py │ ├── requirements.txt │ └── .env ├── frontend/ │ ├── src/ │ │ ├── views/ │ │ │ ├── ChatView.vue │ │ │ └── Dashboard.vue │ │ ├── api/ │ │ │ └── request.js │ │ └── main.js │ ├── package.json │ └── vite.config.js └── docker-compose.yml

后端依赖清单 requirements.txt:

fastapi==0.115.0 uvicorn[standard]==0.30.6 langchain==0.3.7 langchain-openai==0.2.5 langchain-community==0.3.5 mcp==1.1.0 sqlalchemy==2.0.35 pymysql==1.1.1 python-dotenv==1.0.1 pydantic==2.9.2 sse-starlette==2.1.3

前端依赖 package.json 关键部分:

{ "dependencies": { "vue": "^3.5.12", "vue-router": "^4.4.5", "axios": "^1.7.7", "echarts": "^5.5.1", "pinia": "^2.2.4" }, "devDependencies": { "vite": "^5.4.10", "@vitejs/plugin-vue": "^5.1.4" } }

环境变量 .env 是重点,TaoToken 的 Key 和 Base URL 都放这里:

TAOTOKEN_API_KEY=sk-你的Key TAOTOKEN_BASE_URL=https://taotoken.net/api DEFAULT_MODEL=gpt-4o-mini MYSQL_URL=mysql+pymysql://root:password@127.0.0.1:3306/ai_agent

config.py 里读取这些变量:

import os from dotenv import load_dotenv load_dotenv() class Settings: api_key: str = os.getenv("TAOTOKEN_API_KEY", "") base_url: str = os.getenv("TAOTOKEN_BASE_URL", "https://taotoken.net/api") default_model: str = os.getenv("DEFAULT_MODEL", "gpt-4o-mini") mysql_url: str = os.getenv("MYSQL_URL", "") settings = Settings()

LangChain 接入时,用 ChatOpenAI 指向 TaoToken 的 Base URL 即可,因为接口是兼容 OpenAI 格式的:

from langchain_openai import ChatOpenAI from app.config import settings def build_llm(model: str | None = None): return ChatOpenAI( model=model or settings.default_model, api_key=settings.api_key, base_url=settings.base_url, temperature=0.3, streaming=True, )

这里有个坑要提醒:base_url 结尾不要多加/v1,因为 SDK 内部会自己拼/chat/completions。如果你写成https://taotoken.net/api/v1,实际请求会变成/api/v1/v1/chat/completions,直接 404。我试过这个错,排查了半小时才发现是路径重复。

MCP 客户端部分,用一个简单的封装管理工具注册:

from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client class MCPManager: def __init__(self): self.sessions = {} async def connect(self, name: str, command: str, args: list[str]): params = StdioServerParameters(command=command, args=args) read, write = await stdio_client(params).__aenter__() session = await ClientSession(read, write).__aenter__() await session.initialize() self.sessions[name] = session return session async def list_tools(self, name: str): session = self.sessions.get(name) if not session: return [] result = await session.list_tools() return result.tools

Agent 编排层 orchestrator.py 负责把用户输入、Skill、MCP 工具串起来:

from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_core.prompts import ChatPromptTemplate from app.agent.skills.weather_skill import weather_tool from app.agent.skills.db_skill import query_task_tool from app.config import settings from app.agent.llm import build_llm PROMPT = ChatPromptTemplate.from_messages([ ("system", "你是一个智能体助手,优先调用工具获取事实,再回答用户。"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) def build_agent(model: str | None = None): llm = build_llm(model) tools = [weather_tool, query_task_tool] agent = create_openai_tools_agent(llm, tools, PROMPT) return AgentExecutor(agent=agent, tools=tools, verbose=True)

FastAPI 的 chat 接口用 SSE 流式返回:

from fastapi import APIRouter from sse_starlette.sse import EventSourceResponse from app.agent.orchestrator import build_agent router = APIRouter() @router.post("/api/chat/stream") async def chat_stream(payload: dict): agent = build_agent(payload.get("model")) async def event_gen(): async for event in agent.astream_events( {"input": payload["message"]}, version="v2" ): if event["event"] == "on_chat_model_stream": chunk = event["data"]["chunk"].content if chunk: yield {"event": "message", "data": chunk} yield {"event": "done", "data": "[DONE]"} return EventSourceResponse(event_gen())

前端 ChatView.vue 用 EventSource 接收流式内容,Dashboard.vue 用 ECharts 画调用统计。ECharts 初始化时注意在 onMounted 里执行,否则容器宽度为 0 会导致图表不显示:

import * as echarts from 'echarts' import { onMounted, ref } from 'vue' const chartRef = ref(null) onMounted(() => { const chart = echarts.init(chartRef.value) chart.setOption({ tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: [] }, yAxis: { type: 'value' }, series: [{ type: 'line', data: [], smooth: true }] }) })

4. 验证请求:多模型调用与 ECharts 图表联动

配置写完后,先启动后端:

cd backend uvicorn app.main:app --reload --port 8000

再启动前端:

cd frontend npm install npm run dev

打开浏览器访问前端页面,在对话框输入「帮我查一下北京天气,并统计今天的任务数量」。正常情况下,后端日志会显示 Agent 先调用 weather_tool,再调用 query_task_tool,最后把结果流式返回。前端对话区会逐字显示回复,同时 Dashboard 页面的 ECharts 折线图会新增一个数据点,表示这次调用的耗时。

验证多模型切换:在前端下拉框把模型从 gpt-4o-mini 换成 claude-3-5-sonnet,再发一条消息。后端不需要重启,因为 build_agent 每次请求都会根据传入的 model 重新构建 LLM 实例。你可以在 MySQL 的 call_log 表里看到两条记录,model 字段不同,但 api_key 是同一个。这就是统一 Key 的价值——切换模型只改一个字段。

验证 MCP 工具:如果你接了一个本地文件查询的 MCP Server,可以在对话里说「列出当前目录下的文件」,Agent 会通过 MCP 调用对应工具。MCP 的返回结果会作为 observation 进入 Agent 的推理链,最终体现在回复里。

验证 ECharts 联动:Dashboard 页面每 5 秒轮询一次 /api/stats 接口,返回最近 20 次调用的耗时和模型分布。折线图展示耗时趋势,饼图展示各模型调用占比。如果图表不更新,先检查接口是否返回了数据,再检查 ECharts 的 setOption 是否被调用。

5. 常见错误排查:401、local proxy failed、reading choices、OAuth

第一个高频错误是 401 Unauthorized。报错信息通常是{"error": {"message": "Invalid API key"}}。原因有三种:Key 复制时带了空格、.env 文件没被 load_dotenv 读到、或者 Key 已经被删除。排查方法是在 Python 里打印settings.api_key[:8],确认前几位是否正确。如果 .env 放在 backend 根目录但启动目录不对,load_dotenv 会找不到文件,建议用绝对路径load_dotenv(dotenv_path=Path(__file__).parent.parent / ".env")。

第二个错误是local proxy failed或连接超时。这通常是 base_url 写错,或者本机网络环境有额外限制。先确认TAOTOKEN_BASE_URL=https://taotoken.net/api,不要带多余路径。然后用 curl 单独测试,如果 curl 能通但 Python 不通,检查是不是 requests 走了系统代理。可以在代码里显式设置os.environ["NO_PROXY"] = "taotoken.net"。

第三个错误是reading choices相关报错,比如KeyError: 'choices'或list index out of range。这通常发生在流式响应解析时,某些模型返回的 chunk 结构不同。解决方法是加防御性判断:

data = response.json() if "choices" not in data or not data["choices"]: raise ValueError(f"Unexpected response: {data}")

第四个错误是 OAuth 相关报错,比如OAuth token expired或invalid_grant。如果你用的是需要 OAuth 的模型或工具,检查 token 刷新逻辑。对于 TaoToken 的 API Key 方式,一般不会遇到 OAuth 问题,但如果你的 MCP Server 需要 OAuth 授权,要确保授权回调地址配置正确。

第五个错误是 MySQL 连接失败,报Access denied for user或Can't connect to MySQL server。检查 MYSQL_URL 里的用户名、密码、端口是否正确,MySQL 是否允许远程连接。本地开发建议用 docker-compose 起一个 MySQL,避免环境差异。

第六个错误是 ECharts 图表不显示。打开浏览器控制台,如果报Cannot read properties of null (reading 'getWidth'),说明图表容器还没渲染就初始化了。把 echarts.init 放到 nextTick 里,或者用 ResizeObserver 监听容器尺寸变化。

6. 继续扩展:从演示系统到可落地 Agent

这套系统跑通之后,你可以按自己的需求继续加东西。比如给 Agent 加更多 Skill,每个 Skill 就是一个 LangChain Tool,注册到 tools 列表里即可。再比如把 MCP 的 stdio 模式换成 SSE 模式,让远程工具也能接入。数据看板那边,可以加一个「模型成本估算」的柱状图,按 Token 消耗乘以单价算出每次调用的成本。

如果你要做长期运行的编码类 Agent,建议单独走 Coding Plan 的接入方式,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各语言的示例代码。Claude Code 相关的接入可以参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 。

最后说一个实用技巧:把 Agent 的每次调用都记一条日志到 MySQL,字段包括 request_id、model、prompt_tokens、completion_tokens、latency_ms、created_at。这样前端 ECharts 可以画出任意维度的统计,也方便你排查线上问题。日志表建好之后,整个系统就从「能跑」变成「能观测」了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 15:00:08

MCP error -32001 超时排查:把 Claude 的 Node.js MCP server 配置改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 14:59:35

mcpo 的简单使用:用 uvx/conda/pip 三种方式跑通 MCP 服务

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 14:59:32

STM32嵌入式开发全解析:从内核架构到实战避坑指南

STM32 这个名字,在嵌入式圈子里几乎是绕不开的。不管你是刚入行的电子专业学生,还是做了几年硬件转软件的工程师,只要碰过 MCU,大概率第一块板子就是 STM32。但很多人对它的理解停留在“库函数能跑就行”的层面,一旦遇…

作者头像 李华
网站建设 2026/10/7 14:59:32

嵌入式AI编程实战:代码审查、板级调试与工作流固化

嵌入式软件这行有个特别拧巴的地方:代码跑在资源受限的板子上,调试靠串口打印和示波器,但写代码的方式却还停留在“手搓寄存器、翻数据手册、对着参考手册一行行抠”的阶段。我做了十多年嵌入式,从8位机裸跑到带RTOS的Cortex-M&am…

作者头像 李华
网站建设 2026/10/7 14:58:43

Agent Skills 实战指南:从原理到自动化测试应用

1. 从“skills”这个热词说起:它到底是什么,为什么突然火了最近几个月,不管是在技术社区、AI 工具群,还是在做前端、写论文、搞自动化测试的朋友圈子里,“skills”这个词出现的频率高得离谱。有人叫它 Agent Skills&am…

作者头像 李华
网站建设 2026/10/7 14:58:03

解决codex回复一直重连问题:把auth.json改到TaoToken的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华