news 2026/9/12 10:33:51

AI Agent 生产级基础设施搭建实战:从模型接入到数据安全

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent 生产级基础设施搭建实战:从模型接入到数据安全

这几年 AI Agent 从概念到落地,最不缺的就是 PPT 和 demo。真正把 Agent 推到生产环境的时候,最先遇到的往往不是模型能力不够,而是基础设施缺位:密钥散落在代码里、日志查不到一次工具调用链路、数据库查询把线上库拖慢了、模型供应商一换整个流程重写。我在 LCODER 团队做“问数项目”时,第一阶段把业务需求梳理清楚,第二阶段就老老实实打地基。这篇就讲我们是怎么搭建这套 AI Agent 基础设施的,适合正在做或者准备做数据问答智能体的开发者,也适合想系统学习 Agent 工程化落地的人参考。

“问数项目”做什么?简单说,就是让业务人员用自然语言查询数据。用户输入“上个月华东区销售额环比是多少”,Agent 理解问题、生成 SQL、执行查询、返回一段人能看懂的结论。这个链路看着不长,但它横跨模型调用、任务编排、数据库访问、日志监控、权限控制好几个层面。任何一个环节没想清楚,上线后都会变成半夜打电话叫你起来的故障。基础设施搭建阶段,就是把这一条链路上的“地基”一件一件摆正。

1. 开工前先想清楚:问数项目的基础设施到底要解决什么问题

1.1 问数项目的本质是一条数据链路

问数项目本质上是把“自然语言到 SQL,再到结果解释”这条链路自动化。用户的一句话要经历这些环节:意图理解、字段映射、SQL 生成、SQL 执行、结果摘要、回答生成。每个环节都可能出错,而且错误会层层放大:模型生成 SQL 时漏掉一个过滤条件,查询结果就是错的,但看起来还挺像那么回事。

所以基础设施搭建不能只围绕“调用大模型”这一个点,而是要把整条数据链路当成一个系统来设计。模型接入层只负责文字生成,编排层负责控制流程,数据访问层负责安全高效地执行查询,可观测层负责记录每次决策和工具调用。只有每一层边界清晰,后续排查问题时才不会把所有锅都甩给“模型太笨”。

1.2 基础设施的四条原则

我给团队定过四条原则,后面所有搭建工作都围绕它们展开:

  • 可替换:模型供应商不能绑定。今天用 A 厂商,明天换成 B 厂商,不能动业务代码。
  • 可观察:每次 Agent 调用都要能回放。完整记录 prompt、工具参数、SQL、查询结果、最终回答。
  • 可限流:失控查询不能拖垮数据库。无论是 SQL 还是并发请求,都要有兜底机制。
  • 可回滚:模型、提示词、工具配置化。线上出问题时能在一分钟之内切回旧版本。

这四条不是理论。可替换保证你不被单一供应商拿捏;可观察保证每次回答错误都能定位是模型问题、工具问题还是数据问题;可限流是生产环境的生死线;可回滚是最后一道安全网。基础设施阶段把这些原则落实,后面迭代才有底气。

1.3 技术选型边界

我们的技术栈是这样定的,你完全可以按自己的环境调整:

  • 语言:Python 3.11+。Agent 生态基本都在 Python 这边。
  • 编排框架:LangGraph。因为问数流程天然是“生成 SQL、执行、再回复”的状态流转,LangGraph 的状态图模型很适合。
  • 工具协议:MCP。后面要接数仓、告警平台、知识库,统一用 MCP 暴露工具,Agent 端不重复造轮子。
  • LLM:优先兼容 OpenAI 协议,具体模型可切换,我们主力用 qwen-plus 和 deepseek-chat。
  • 数据库:示例用 MySQL 语义,本地开发用 SQLite。生产建议单独账号、只读权限。
  • 可观测:外部用 LangSmith,内部保留结构化日志作为兜底。

选型有一个原则:能不自己写框架就不自己写,但底层细节一定要吃透。框架只是帮我们管理复杂度,不能代替我们思考。

2. 开发脚手架与配置管理:一个能持续演进的工程底板

2.1 项目目录:按职责拆模块,而不是按页面拆

基础设施搭建第一步是搭一个可持续演进的目录结构。我的习惯是让“工具”成为独立模块,每增加一个数据源就加一个文件,不破坏主流程。

lcoder_askdb/ ├── app/ │ ├── agent/ # LangGraph 编排层 │ │ ├── graph.py │ │ ├── state.py │ │ └── nodes.py │ ├── tools/ # 工具集,一个文件一个工具 │ │ ├── sql_query.py │ │ └── registry.py │ ├── llm/ # 模型工厂 │ │ ├── factory.py │ │ └── errors.py │ ├── db/ # 数据库访问层 │ │ ├── engine.py │ │ └── safe_query.py │ ├── config.py # 全局配置 │ └── logging_conf.py # 结构化日志 ├── mcp_server/ # MCP 服务端 ├── tests/ ├── pyproject.toml └── .env.example

依赖管理我推荐用 uv。它比 pip 快一个数量级,还能直接管理 Python 版本。项目初始化的时候直接uv init,之后所有依赖加进pyproject.toml,配合锁文件保证开发环境一致。这个阶段别省时间,环境不一致带来的坑比想象中多。

2.2 配置中心:别在代码里硬编码任何东西

配置管理的核心工具是 pydantic-settings。它能在启动时自动读取环境变量和 .env 文件,还能做类型校验。问数项目的配置类大概是这样的:

from pydantic_settings import BaseSettings class Settings(BaseSettings): model_config = {"env_file": ".env", "extra": "ignore"} # 模型配置 llm_provider: str = "openai_compatible" llm_model: str = "qwen-plus" llm_base_url: str = "" # 生产环境从环境变量读取 llm_api_key: str = "" llm_temperature: float = 0.1 llm_timeout_seconds: int = 60 # 数据库配置 db_url: str = "sqlite:///./askdb.db" db_pool_size: int = 5 db_max_overflow: int = 10 db_statement_timeout_ms: int = 5000 # 查询限制 query_max_rows: int = 100 query_max_sql_length: int = 2000 # 可观测 langsmith_api_key: str = "" langchain_tracing_v2: bool = False settings = Settings()

这里有个实操细节:.env绝对不能进 git,但.env.example必须进仓库。.env.example里写好每个配置项的含义和取值示例,让新同学五分钟之内能跑起来。另外所有配置项集中在config.py里 import,别在业务代码里到处读os.getenv,否则一个月后你自己都记不清哪些变量在哪些地方用到了。

2.3 密钥管理:第一道安全红线

密钥管理是基础设施里最容易被忽视的部分。很多项目把 API Key 写在.env里就算完成,但生产环境还应该做到:密钥由部署平台统一注入环境变量,开发者本地使用个人 Key,代码仓库里任何位置不允许出现明文密钥。

我们在 CI 里加了扫描工具,只要检测到疑似的高权限密钥就会让流水线失败。判断标准就一条:仓库泄露后,攻击者能不能拿到模型调用额度或者数据库访问权。如果能,这就算安全事故。密钥这件事没有中间态,宁可严格一万次,也不能松一次。

3. 模型接入层:让 Agent 能对话,也能换模型

3.1 统一模型工厂:一次封装,全局复用

模型接入层在问数项目里承担一个核心职责:屏蔽底层差异。不管是 qwen、deepseek 还是 OpenAI,对上层的 Agent 逻辑来说,都只应该是一个“能接收消息并返回文本和工具调用”的黑盒。

我们用工厂函数创建模型实例,核心代码如下:

from langchain_openai import ChatOpenAI from app.config import settings def get_llm(): return ChatOpenAI( model=settings.llm_model, base_url=settings.llm_base_url, api_key=settings.llm_api_key, temperature=settings.llm_temperature, timeout=settings.llm_timeout_seconds, max_retries=1, )

这个base_url的设计很关键。很多国产模型厂商提供 OpenAI 兼容接口,只要 base_url 和 model 名字对得上,业务代码一行都不用改。本地开发甚至可以指向 Ollama 跑 7B 小模型。这就是“可替换”原则的落地。

3.2 重试、超时与错误归一化

模型接口不是本地函数,它可能超时、限流、返回 5xx。所以模型层必须统一做三件事:超时控制、重试策略、错误归一化。

一个实用的重试策略是:对网络错误和 5xx 做指数退避重试,初始等待 1 秒,最多重试 3 次;对 429 限流则要根据 Retry-After 头等待;对 4xx 错误不重试,因为重试也没用。所有错误统一包装成LLMError向上抛出,编排层只认这一个异常类型,不跟具体厂商的异常直接打交道。

import time, asyncio from openai import APITimeoutError, RateLimitError async def call_llm_with_retry(func, max_retries=3): delay = 1.0 for attempt in range(max_retries): try: return await func() except (APITimeoutError, RateLimitError) as e: if attempt == max_retries - 1: raise LLMError(f"模型调用失败: {e}") from e await asyncio.sleep(delay) delay *= 2

这个封装不要在业务代码里散落,就放在模型工厂文件里。所有get_llm()返回的客户端,后续调用都走统一封装。

3.3 兼容多模型的两个细节

第一,工具调用能力。问数项目必然要让模型调用查询工具,所以选的模型必须支持 function calling。qwen-plus、deepseek-chat 都支持,但某些本地小模型不支持。如果必须用不支持的模型,就要在提示词里要求输出固定 JSON,再在代码里做解析和校验。这个降级方案我在后面问题排查部分会讲到。

第二,temperature 参数。问数任务追求的是精确而非创意,temperature 建议设 0 或 0.1。设太高,模型同一个问题五次生成五种 SQL,根本没法稳定复现。我们团队实测下来,0.1 是准确率和鲁棒性都比较好的取值。

4. Agent 编排运行时:用 LangGraph 把流程变成可控状态机

4.1 为什么是 LangGraph 而不是一个死循环

很多 Agent demo 就是一个 while 循环:调用模型、拿工具结果、再调用模型,直到结束。这么做 demo 没问题,但它不满足生产环境的三点要求:可控、可回放、可中途干预。LangGraph 把流程定义成状态图,每个节点做一类事情,节点之间按条件路由,整个过程都基于显式的状态流转。

问数项目的状态定义如下:

from typing import TypedDict class AskState(TypedDict): question: str # 用户原始问题 history: list # 多轮对话历史 sql: str | None # 生成的 SQL query_result: list | None # 查询结果 answer: str | None # 最终回答 error: str | None # 错误信息

定义好状态后,图的结构就是:首先 receive_query 节点接收并预处理问题;然后 analyze 节点让模型基于表结构生成 SQL;接着 execute 节点执行查询工具;最后 respond 节点把结果翻译成自然语言。中间如果 SQL 执行失败,就进入 error_handle 节点修正 SQL 重试一次。

4.2 节点与条件路由的实践

LangGraph 的节点就是一个接收 state、返回新 state 的函数。我习惯把每个节点放在nodes.py里独立成函数,避免一个文件几百行。

from langgraph.graph import StateGraph, END def analyze_node(state: AskState) -> AskState: sql = generate_sql(state["question"], state["history"]) state["sql"] = sql return state def execute_node(state: AskState) -> AskState: result, error = safe_query(state["sql"]) state["query_result"] = result state["error"] = error return state def respond_node(state: AskState) -> AskState: state["answer"] = summarize_answer(state["question"], state["query_result"]) return state graph = StateGraph(AskState) graph.add_node("receive_query", receive_query_node) graph.add_node("analyze", analyze_node) graph.add_node("execute", execute_node) graph.add_node("respond", respond_node) graph.add_edge("receive_query", "analyze") graph.add_edge("analyze", "execute") graph.add_conditional_edges( "execute", lambda state: "respond" if state["error"] is None else "analyze" ) graph.add_edge("respond", END)

条件路由的意思就是:如果查询成功,直接生成回答;如果查询失败,回到 analyze 节点重新生成 SQL。但这里要加一个重试次数上限,比如最多重新生成两次,超过就直接返回错误,避免模型死循环消耗 token。

4.3 工具注册与参数校验:把模型关进“笼子”里

问数项目里模型需要调用的是一个查询工具。工具注册阶段最重要的不是“能不能调通”,而是“模型能不能按规矩调”。我们用 LangChain 的@tool装饰器加 Pydantic 参数描述,模型会看到结构化的工具说明。

from langchain_core.tools import tool from pydantic import BaseModel, Field class QueryInput(BaseModel): sql: str = Field(description="要执行的只读 SQL,必须带 LIMIT 100") @tool("safe_query", args_schema=QueryInput) def safe_query_tool(sql: str) -> tuple: """执行只读 SQL 查询,支持 MySQL/SQLite,自动处理超时和行数限制""" return safe_query(sql)

这里有个关键设计:工具描述里要明确写“必须带 LIMIT”,schema 里也要带。模型是概率系统,我们通过描述约束它,再通过后端强校验兜底。底线是:即使模型不听话,数据库层面也不能出问题。

5. 数据访问层:安全高效地“问数”

数据访问层是问数项目最核心的底座。前面模型写得再好,这一层出事就是大事故。所以这块我把安全放在第一位,效率放在第二位。

5.1 只读账号与连接池

生产环境必须为 Agent 单独建一个数据库账号,权限只有 SELECT,不给 INSERT、UPDATE、DELETE、DDL。这一步是为了防止提示词注入的最坏情况。即使模型被诱导生成了恶意 SQL,只读账号也会把损失降到最低。

连接池方面,直接用 SQLAlchemy 统一管理。根据预估并发设置连接池大小,我一般给一个保守值:

from sqlalchemy import create_engine engine = create_engine( settings.db_url, pool_size=settings.db_pool_size, max_overflow=settings.db_max_overflow, pool_pre_ping=True, pool_recycle=3600, )

pool_pre_ping=True很重要,它会在每次从连接池取出连接时先做一次轻量检查,避免拿到坏连接。pool_recycle=3600是防止数据库端超时断开。

5.2 SQL 安全校验:正则只是第一步

很多教程只教“用正则过滤 DELETE、DROP”,但实际生产里正则不够。模型可能生成多语句 SQL,比如SELECT ...; DELETE ...,单条正则很难覆盖所有变体。更可靠的方案是用 sqlglot 这类 SQL 解析器,把 SQL 解析成 AST,再做以下几项检查:

  • 只允许 SELECT 语句,其他语句直接拒绝。
  • 禁止多语句拼接,只取第一个语句,后面的一律丢弃。
  • 强制限制返回行数,如果原 SQL 没有 LIMIT,在外面包一层子查询加上 LIMIT。
  • 设置数据库 statement timeout,防止慢查询拖垮数据库。

同时在查询工具内部加一层后端兜底:

from sqlglot import parse_one, exp def validate_sql(sql: str) -> str: sql = sql.strip().rstrip(";") try: statement = parse_one(sql) except Exception as e: raise ValueError(f"SQL 解析失败: {e}") if not isinstance(statement, exp.Select): raise ValueError("只允许 SELECT 查询") if ";" in sql: raise ValueError("不允许多语句执行") return sql

加一层统一的safe_query函数,把校验、超时、行数限制全部封装进去。Agent 只能通过这个函数访问数据库,不能直连 engine。

5.3 表结构与元数据注入

模型要生成正确的 SQL,前提是它知道数据库里有什么。我们会在 analyze 节点的提示词里注入核心表的建表语句和注释。注入的内容包括:表名、字段名、字段类型、字段注释、索引信息、常用过滤条件示例。

比如 prompt 里会有这么一段:

数据库表结构: - 表名: sales_order - 字段: - id BIGINT 主键 - region VARCHAR 区域:华东、华北、华南等 - amount DECIMAL(10,2) 订单金额 - order_date DATE 下单日期 - created_at DATETIME 创建时间 注意:查询时务必加上时间范围条件,避免全表扫描。

表结构可以直接写进系统提示词,也可以作为工具参数描述的一部分。如果数据库表非常多,不可能全部塞进 context,就需要通过检索的方式筛选相关表,这正好用到后面的 RAG 辅助。

5.4 轻量级 RAG 辅助字段映射

用户问题里的词往往和数据库字段名对不上。用户说“毛利”,表里叫gross_profit;说“客户”,表里叫customer_name。这个映射问题单靠提示词很难完全解决。我们的做法是把字段名、字段注释、业务常用别名做成向量索引,在生成 SQL 前先做一次相似度召回,把候选字段信息注入到 analyze 节点。

这一步算“锦上添花”的基础设施,可以在第一版跑通后再加。最开始我建议先把固定表结构注入提示词,跑通全链路,再迭代 RAG 辅助。基础设施搭建讲究“先简后繁”,别一天就想上满所有能力。

6. MCP 协议接入:让外部工具变成标准件

6.1 为什么选 MCP 协议

MCP 全称 Model Context Protocol,它解决的是 Agent 和外部工具之间的标准化问题。没有 MCP 之前,接一个数据库写一套自定义封装,接一个告警平台再写一套,每个 Agent 都在重复造轮子。MCP 把工具暴露成标准服务,Agent 端只需要统一连接 MCP Server,就能发现并调用所有暴露出来的工具。

问数项目用 MCP 的好处是:后续要接数据仓库、BI 报表、知识库、企业 API 时,每个模块做成独立的 MCP Server,Agent 编排层不需要跟着改。这是基础设施层面的“面向未来设计”。

6.2 用 FastMCP 暴露一个查询工具

我们用 FastMCP 框架来写 MCP Server,代码非常简洁。下面是一个最小可用的查询工具服务端:

from fastmcp import FastMCP from app.db.safe_query import safe_query mcp = FastMCP("askdb-tools") @mcp.tool() def query_sales(region: str | None = None, start_date: str | None = None) -> list[dict]: """按区域和时间范围查询销售数据,返回最多 100 条""" sql = "SELECT * FROM sales_order WHERE 1=1" if region: sql += f" AND region = '{region}'" if start_date: sql += f" AND order_date >= '{start_date}'" sql += " LIMIT 100" return safe_query(sql) if __name__ == "__main__": mcp.run()

这里故意用了参数化的方式生成 SQL,而不是让模型直接传入完整 SQL。虽然灵活性降低,但安全性和可控性大幅提高。在这个阶段,我们允许两种模式并行:一种是模型直接生成 SQL 并由校验层兜底,另一种是通过工具参数约束查询维度。生产环境我更推荐后者。

6.3 Agent 端连接 MCP Server

Agent 端可以通过 langchain-mcp-adapters 把 MCP 工具转换成 LangChain 能识别的工具。基础设施阶段,我们只需要验证一条链路:MCP Server 启动后,Agent 能从工具列表里发现query_sales,能正确传递参数,能拿到返回结果。链路跑通后,再考虑同时挂多个 MCP Server 的问题。

有一个坑提前提醒:不同的 MCP Server 如果工具名重复,Agent 端会有命名冲突。我在工具命名时统一加了业务前缀,比如sales_queryschema_list,而不是笼统的query。这个习惯在后端接入更多数据源时会省很多事。

7. 可观测性与评估:没有日志的 Agent 没法修

7.1 结构化日志:每条记录都能回放

Agent 应用和普通 Web 应用不一样,它的一次请求会触发多次模型调用和多次工具调用,链路长且非线性。普通文本日志根本没法看。必须从一开始就上结构化日志,推荐 JSON 行格式,每个事件一行 JSON。

关键事件我会打五类:llm_requesttool_calltool_resultnode_startnode_end。每个事件都挂上同一个trace_id。这样排查问题时,可以用 trace_id 把一次完整交互串起来。日志字段至少包含:时间、trace_id、节点名、事件类型、关键数据和耗时。

import logging, json def log_event(trace_id: str, event_type: str, node: str, data: dict): logging.getLogger("agent").info(json.dumps({ "trace_id": trace_id, "event": event_type, "node": node, **data, }, ensure_ascii=False))

一个基本原则:任何可能影响最终回答的因素都要记录。模型用的提示词要记录,工具传入的参数要记录,SQL 执行耗时要记录。宁可日志多得翻不过来,也不能在出问题时什么都查不到。

7.2 接入 LangSmith 做完整链路追踪

如果条件允许,强烈建议接入 LangSmith。它对 LangChain/LangGraph 的应用几乎是零侵入式接入,自动捕获每一步的模型调用、工具调用、token 消耗和耗时。我在 config.py 里留了开关,开发环境关掉,测试和生产环境打开。

接入步骤很简单:设置环境变量LANGCHAIN_TRACING_V2=trueLANGCHAIN_API_KEY=...,再设置 project name。之后每次运行 Agent,就能在 LangSmith 里看到完整的链路回放。它最大的价值是快速定位“模型为什么生成这个 SQL”:你能看到系统提示词、用户问题、模型中间推理、工具返回结果,全部一清二楚。

如果你不想依赖外部服务,也可以用 Langfuse 或者自建一个 trace 表。但对小团队来说,先上 LangSmith 以最快速度获得可观测性,是性价比最高的选择。

7.3 准备评估集:让每次优化都可回归

基础设施阶段就要开始建评估集,不要等到上线之后。我们准备了 20 个 golden 问题,覆盖常见业务场景:简单汇总、多条件过滤、时间对比、字段映射、无法回答的问题。每个问题都标注了期望的 SQL 要点和期望答案。

question,expected_sql_note,expected_answer 上个月华东区销售额是多少,必须包含 region='华东' 和订单日期在当月,返回销售总额 哪个客户贡献了最多的订单,必须按 customer_name 分组后 sum(amount) 排序,返回客户名和金额 查询所有订单总量,不允许全表扫描,返回总数

每次修改模型、提示词或工具定义后,跑一遍评估集。这个动作能让“感觉好多了”变成“指标从 82% 涨到 87%”。没有评估集的情况下做 Prompt 调优,约等于蒙着眼睛开车。

8. 常见问题与排查技巧实录

8.1 模型输出 JSON 不稳定,工具解析频繁失败

现象:模型不返回标准工具调用格式,而是把工具参数写成 Markdown 代码块或附带解释文字,解析时直接报错。

后台日志会暴露一个规律:这类问题几乎都出现在更换模型之后。不同厂商对工具调用的实现不完全一样,个别模型在复杂场景下会退化到“用文本回答而不是调用工具”。我的排查步骤是:

  • 先看 LangSmith trace,确认这个问题出现在模型调用环节还是工具解析环节。
  • 确认模型版本是否支持 function calling,确认 base_url 指向正确。
  • 如果模型本身支持但偶尔不稳定,可以在提示词里加强约束,并做文本解析兜底:把返回内容里的 JSON 片段用正则提取出来,再交给 Pydantic 解析。
  • 如果多次重试仍失败,走异常处理节点,返回“暂时无法回答,请联系管理员”。

8.2 SQL 多次重试,单次请求累计耗时过长

现象:一条查询请求总耗时超过 60 秒,原因不是单次 SQL 慢,而是模型生成 SQL 后执行失败,跳到 analyze 节点重新生成,循环了好几次。每次都消耗十几秒,叠加起来就超时了。

我的解决办法是三层超时控制:

  • LangGraph 整体设置递归次数上限,比如最多重试 2 次,超过就终止。
  • analyze 节点的模型调用设置 20 秒超时,执行节点设置 5 秒数据库超时。
  • 外部请求入口设置 90 秒总超时。

此外重试逻辑里增加“失败原因透传”,把上一次的数据库错误信息拼进第二次生成的提示词里。比如告诉模型“刚才执行的 SQL 报错:Unknown column 'gross_profit',请检查字段名”。这样模型重试时才有方向,而不是从头开始瞎猜。

8.3 Token 限制导致工具 schema 过大

现象:表多字段多的时候,把所有表结构写进提示词,prompt 越来越长,最终触达上下文窗口。更麻烦的是,模型被大量无关表结构干扰,生成 SQL 的准确率反而下降。

解决思路是“按需注入”:

  • 先用 5 万条左右的核心表结构缓存到本地,作为固定的系统提示词。
  • 剩下的表通过向量检索召回,只注入与用户问题相关的表和字段。
  • 字段描述做压缩,每条只保留字段名、类型、中文注释,去掉冗余说明。

实测下来,按需注入比一股脑全部塞进 context 的准确率高不少,也节省 token 成本。

8.4 并发测试时数据库连接被打满

现象:压测脚本同时发 50 个请求,数据库连接池打满,排队请求直接超时,甚至拖垮了同库的其他业务。

这个问题的排查方向不应该是单纯调大连接池。要分三层处理:

  • 数据库只读账号数量有限,先压住 Agent 入口的并发,比如用队列限流,同一时刻最多处理 10 个请求。
  • 针对 LLM 调用做限流和排队,避免瞬时打爆模型接口的 QPS。
  • 数据库层给 Agent 账号限制最大连接数,防止它占用过多资源,影响其他业务。

同时把慢查询和全表扫描 SQL 在数据库端用审计日志记录下来,回头分析哪些表和查询模式需要优化。基础设施阶段不做这步,上线后被业务方投诉“系统变慢”时再处理就非常被动了。

写到这里,问数项目的基础设施部分基本搭完了。我个人在实际操作中的体会是,基础设施是最不显眼但决定性最强的阶段,后面 90% 的稳定性问题都能在这里找到根因。这块省下的时间,后面会用十倍的时间还回去。下一步我们会在这套底座上正式实现问数智能体的各个业务节点,包括意图路由、SQL 生成优化、多轮对话记忆、结果可视化,到那一步再继续分享实战过程。

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

PyTorch车型识别训练工程拆解:从数据管线到模型部署的完整实践

简介:面向计算机、人工智能等专业学生的PyTorch车型识别课程设计项目,完整覆盖深度学习模型训练主流程;代码经测试可稳定运行,曾获答辩平均分94.5分,既可用于课设/毕设参考,也适合入门者从数据加载到模型训…

作者头像 李华
网站建设 2026/9/12 10:32:26

即梦AI替代工具实测:4款主流AIGC方案深度对比

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

作者头像 李华
网站建设 2026/9/12 10:32:03

如何筛选专业设计公司?品牌设计全流程实操指南

我常年跟品牌设计公司打交道,自己也带过几次完整的产品发布,深知“设计品牌犯难”这几个字背后到底压着多少事。很多创业者拿着预算,翻了几十家设计公司的官网,越看越迷糊:有的作品确实惊艳,但看着就像别人…

作者头像 李华
网站建设 2026/9/12 10:29:18

LabelMe标注格式详解:从JSON到VOC/COCO/YOLO的训练数据转换实战

简介:LabelMe是由MIT开发的开源图像标注工具,这个压缩包包含其完整源码与配套文件,面向计算机视觉研究者、深度学习开发者及数据标注人员,用于高效制作语义分割、目标检测与关键点检测等任务所需的标注数据集。包内共251个文件&am…

作者头像 李华
网站建设 2026/9/12 10:28:41

Flask与Vue前后端分离开发实战指南

1. 项目概述:FlaskVue前后端分离架构解析前后端分离架构已成为现代Web开发的主流模式,它通过解耦前端展示与后端业务逻辑,大幅提升了开发效率和系统可维护性。本教程将详细演示如何使用Python Flask框架与Vue.js构建一个完整的前后端分离项目…

作者头像 李华
网站建设 2026/9/12 10:27:30

程序调试中的信号提示与处理技术详解

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

作者头像 李华