当前位置: 首页 > news >正文

基于MCP协议构建AI安全访问PostgreSQL数据库的实战指南

1. 项目概述与核心价值

最近在折腾AI应用开发,特别是围绕Claude、GPTs这类智能体构建工具链时,一个绕不开的痛点就是如何让AI安全、可控地访问和操作我们的数据。直接给AI开放数据库连接?风险太高。手动写API接口?效率太低,且难以应对AI动态的数据查询需求。正是在这个背景下,我注意到了VKirill/multi-postgres-mcp-server这个项目。简单来说,它是一个实现了Model Context Protocol(MCP)标准的服务器,专门用于为AI智能体提供对多个PostgreSQL数据库的安全、结构化访问能力。

MCP,你可以把它理解成AI智能体(如Claude Desktop、Cursor等)与外部工具、数据源之间的一种“标准化插座”协议。它定义了智能体如何发现、调用工具,以及如何获取结构化数据。而这个项目,就是专门为PostgreSQL数据库定制的那个“插座”。它的核心价值在于,将复杂的数据库操作(如执行查询、查看表结构、获取数据样本)封装成一系列AI可以安全、直观调用的“工具”(Tools)和“资源”(Resources)。开发者和数据分析师无需为每个查询需求编写冗长的API,只需配置好这个MCP服务器,AI就能在对话中直接提出“帮我查一下上个月的订单趋势”或“用户表里有多少活跃用户”这样的需求,并得到准确、可视化的结果。

这不仅仅是方便。从安全角度看,它通过MCP协议层和自身的权限模型,实现了对数据库操作的范围限定(比如只读某些表、限制查询行数),避免了AI因误解指令而执行DROP TABLE这类危险操作。从效率看,它极大地缩短了“数据提问-获取答案”的路径,让非技术背景的团队成员也能通过自然语言与数据库交互。我花了一周时间深度部署、测试并定制了这个项目,本文将分享从原理拆解、实战部署到高级调优的全过程,以及我踩过的那些坑和总结出的最佳实践。

2. 核心架构与MCP协议深度解析

2.1 MCP协议:AI的“工具调用”标准化接口

要理解这个项目的意义,必须先搞懂MCP。它不是某个公司的私有产品,而是一个由Anthropic主导推动的开放协议。你可以把它类比为Web开发中的REST API标准,或者硬件中的USB接口标准。其目标是解决一个核心问题:不同的AI智能体(客户端)需要与海量不同的外部工具、数据源(服务器)进行交互,如果没有统一标准,就会造成N×M的集成复杂度

MCP定义了三类核心实体:

  1. 工具(Tools):AI可以调用的函数。例如,在这个PostgreSQL MCP服务器中,就定义了像execute_sql(执行SQL)、list_tables(列出所有表)这样的工具。每个工具都有严格的输入参数(Schema)定义。
  2. 资源(Resources):AI可以读取的静态或动态数据。例如,一个名为postgres://server1/schema1/table1的URI可以指向某张表的结构定义(DDL)或前N行数据样本。资源通过URI标识,内容以结构化格式(如JSON)返回。
  3. 提示词(Prompts):可复用的对话模板,用于引导AI完成特定任务。

这个项目的本质,就是实现了一个MCP服务器,它将PostgreSQL的元数据(库、表、列信息)和操作(查询)包装成了标准的MCP工具和资源,暴露给支持MCP的AI客户端(如Claude Desktop)。协议通信基于JSON-RPC over STDIO(标准输入输出)或SSE(服务器发送事件),这意味着服务器是一个独立的进程,通过标准流与客户端交换结构化消息,耦合度低,安全性相对较好。

2.2 multi-postgres-mcp-server 设计思路拆解

项目名中的“multi-postgres”是它的关键特色。很多简单的数据库连接工具只能连一个库,但在企业微服务架构下,数据往往分散在多个业务数据库中。这个项目从设计上就支持同时连接并管理多个PostgreSQL数据库实例

它的核心设计思路如下:

  1. 配置驱动:所有数据库连接信息、权限规则都通过一个配置文件(如servers.yaml)来管理,而不是硬编码在代码中。这符合十二要素应用的原则,便于不同环境(开发、测试、生产)的部署。
  2. 连接池与生命周期管理:服务器启动时,根据配置初始化到各个数据库的连接池。好的连接池管理能有效避免频繁建立/断开连接的开销,提升查询响应速度。服务器需要优雅地处理连接中断、重连等异常情况。
  3. 工具与资源的动态生成:服务器并非写死几个工具。它会根据连接到的每个数据库的实际Schema,动态生成对应的资源URI。例如,连接到analytics_db后,会自动生成postgres://analytics_db/public/users这样的资源URI,供AI客户端发现和读取。
  4. 安全沙箱:这是重中之重。项目通过多种机制构建安全层:
    • 查询限制:可以在配置中限制单次查询返回的最大行数(row_limit),防止AI无意中触发SELECT * FROM huge_table导致内存溢出或网络阻塞。
    • 操作白名单:理论上,可以通过工具定义,只暴露SELECT查询工具,隐藏INSERTUPDATEDELETE甚至EXECUTE功能。
    • 凭据隔离:数据库密码等敏感信息只存在于服务器配置中,AI客户端完全接触不到。客户端只与MCP服务器通信。

注意:MCP协议本身不强制加密,通信安全依赖于部署环境。如果MCP服务器和客户端不在同一台机器,你需要确保传输通道的安全(例如,通过SSH隧道或将服务部署在安全的内部网络)。

3. 实战部署:从零到一的配置与运行

3.1 环境准备与依赖安装

这个项目是用TypeScript/Node.js编写的,因此你的环境需要Node.js(建议LTS版本,如18.x或20.x)和npm或yarn、pnpm等包管理器。

首先,获取项目代码:

git clone https://github.com/VKirill/multi-postgres-mcp-server.git cd multi-postgres-mcp-server

接下来安装依赖。项目根目录下应该有package.json

# 使用 npm npm install # 或使用 pnpm (速度更快,推荐) pnpm install # 或使用 yarn yarn install

安装过程会拉取所有必要的依赖,包括@modelcontextprotocol/sdk(MCP官方SDK)、pg(PostgreSQL客户端)、zod(配置验证)等。

3.2 核心配置文件详解

项目通常提供一个配置文件模板,如servers.example.yaml。你需要复制它并创建自己的servers.yaml。这个文件是整个服务器的中枢神经。

下面是一个支持两个数据库的配置示例,我加入了大量注释说明每个字段的用意:

# servers.yaml servers: # 第一个数据库:分析库,只读权限 analytics_db: host: "analytics-db.internal.company.net" # 数据库主机地址 port: 5432 # 端口,默认5432 database: "analytics_prod" # 数据库名 user: "mcp_reader" # **专用账号**:强烈建议创建仅具有必要权限的账号 password: "${ANALYTICS_DB_PASSWORD}" # 密码,推荐从环境变量读取,避免硬编码 ssl: true # 是否使用SSL连接,生产环境建议开启 # 此数据库的特定配置 options: row_limit: 1000 # 单次查询最多返回1000行,防止爆内存 schema_filter: # 模式过滤器,只暴露public和dwh模式 include: ["public", "dwh"] # 可以设置表级过滤,例如排除包含敏感信息的表 # table_filter: # exclude: ["user_passwords", "payment_logs"] # 第二个数据库:用户服务库,只读特定表 user_service_db: host: "localhost" port: 5432 database: "user_service" user: "mcp_user" password: "${USER_SERVICE_DB_PASSWORD}" ssl: false options: row_limit: 500 # 用户表可能很大,限制更严格 schema_filter: include: ["public"] # 只暴露public模式 # 工具权限控制:可以定义只允许哪些MCP工具对此数据库生效 # allowed_tools: ["list_tables", "get_table_schema"] # 全局默认配置,会被各个服务器配置继承或覆盖 defaults: row_limit: 10000 # 全局默认行数限制 ssl: false # 连接池配置,对性能有重要影响 pool: max: 10 # 连接池最大连接数 idleTimeoutMillis: 30000 # 空闲连接超时时间(毫秒)

关键配置解析与经验

  • 专用数据库账号:绝对不要使用应用的高权限账号(如postgres)。务必为MCP服务器创建专属账号,并遵循最小权限原则。对于只读场景,命令如下:
    CREATE USER mcp_reader WITH PASSWORD 'strong_password'; GRANT CONNECT ON DATABASE analytics_prod TO mcp_reader; GRANT USAGE ON SCHEMA public, dwh TO mcp_reader; GRANT SELECT ON ALL TABLES IN SCHEMA public, dwh TO mcp_reader; -- 确保未来新建的表也能被读取 ALTER DEFAULT PRIVILEGES IN SCHEMA public, dwh GRANT SELECT ON TABLES TO mcp_reader;
  • 密码管理:使用${ENV_VAR}语法从环境变量读取密码是安全最佳实践。在启动服务器前,通过.env文件或shell导出环境变量。
  • schema_filtertable_filter:这是数据安全的第一道防火墙。务必仔细规划,只暴露AI需要访问的模式和表。我曾在测试时不小心暴露了一个包含日志的庞大模式,AI在尝试“了解数据库”时触发了对超大表的查询,导致响应缓慢。
  • row_limit第二道防火墙。根据表的数据量合理设置。对于维度表可以设大点(如5000),对于事实表务必设小(如500或1000)。这能有效防止资源耗尽。

3.3 启动服务器并与Claude Desktop集成

配置完成后,可以启动MCP服务器进行测试。通常项目会提供启动脚本。

# 方式1:使用npm script,假设package.json中定义了 "start": "node dist/index.js" npm start -- --config ./servers.yaml # 方式2:直接运行编译后的JS文件(如果项目是TypeScript需要先构建) npx tsx src/index.ts --config ./servers.yaml

如果启动成功,你会看到服务器监听在某个端口(对于SSE模式)或等待STDIO输入。接下来,我们需要将它配置到AI客户端中。以Claude Desktop为例:

  1. 打开Claude Desktop,点击右上角设置(Settings)。
  2. 找到DeveloperMCP Servers设置项。
  3. 点击“Add Server”或“Edit Config”。
  4. Claude Desktop的MCP配置通常是一个JSON文件。你需要添加一个新的服务器配置。配置取决于你的服务器运行模式:
    • STDIO模式(推荐,更安全):服务器作为子进程启动。
    { "mcpServers": { "multi-postgres": { "command": "node", "args": [ "/absolute/path/to/multi-postgres-mcp-server/dist/index.js", "--config", "/absolute/path/to/multi-postgres-mcp-server/servers.yaml" ], "env": { "ANALYTICS_DB_PASSWORD": "your_password_here", "USER_SERVICE_DB_PASSWORD": "another_password_here" } } } }
    • SSE模式:服务器作为一个HTTP服务运行,需要配置URL。
    { "mcpServers": { "multi-postgres": { "url": "http://localhost:8080/sse" } } }
  5. 保存配置并重启Claude Desktop。

重启后,在Claude的对话界面,你应该能看到一个新的数据库图标或工具图标。点击它,或者直接尝试对Claude说:“你能看到哪些数据库工具?” 如果配置成功,Claude会回复它已连接到MCP服务器,并可以列出可用的工具和资源。

4. 高级功能与定制化开发

4.1 实现自定义工具与资源

开源项目的优势在于可以按需扩展。假设我们想添加一个“健康检查”工具,用于快速检查所有配置数据库的连接状态,或者添加一个获取“今日订单总数”的预定义查询资源。

你需要找到项目定义工具和资源的地方,通常在src/目录下,可能有tools/resources/的子目录或相关定义文件。

添加一个自定义工具示例

  1. 定义工具Schema:在相应的工具定义文件中,按照MCP SDK的格式添加一个新工具。

    // 假设在 src/tools/index.ts 中 import { z } from "zod"; export const tools = { // ... 已有的工具定义 check_database_health: { name: "check_database_health", description: "检查所有已配置数据库的连接状态和基本信息。", inputSchema: { type: "object", properties: {}, // 此工具不需要输入参数 }, }, get_daily_metrics: { name: "get_daily_metrics", description: "获取关键业务日度指标(如订单量、用户活跃数)。需要指定数据库别名。", inputSchema: { type: "object", properties: { serverAlias: { type: "string", description: "数据库配置的别名,如 'analytics_db'", enum: ["analytics_db", "user_service_db"] // 限定可选范围 }, date: { type: "string", description: "查询日期,格式 YYYY-MM-DD,默认为今天", format: "date" } }, required: ["serverAlias"] }, }, };
  2. 实现工具处理函数:在服务器的主逻辑文件中,找到工具执行器的部分,添加对应的处理函数。

    // 在对应的执行器函数中 async handleToolCall(request) { switch (request.name) { // ... 已有case case "check_database_health": return await this.handleCheckHealth(); case "get_daily_metrics": const { serverAlias, date = dayjs().format('YYYY-MM-DD') } = request.params; return await this.handleGetDailyMetrics(serverAlias, date); default: throw new Error(`Unknown tool: ${request.name}`); } } private async handleCheckHealth() { const healthResults = []; for (const [alias, pool] of Object.entries(this.databasePools)) { try { const start = Date.now(); // 执行一个简单查询测试连接和权限 const result = await pool.query('SELECT 1 as status, current_database() as db, version() as pg_version'); const latency = Date.now() - start; healthResults.push({ alias, status: 'healthy', latency_ms: latency, database: result.rows[0].db, version: result.rows[0].pg_version.split(' ')[1], // 提取版本号 }); } catch (error) { healthResults.push({ alias, status: 'unhealthy', error: error.message, }); } } return { content: [{ type: "text", text: JSON.stringify(healthResults, null, 2) }], }; } private async handleGetDailyMetrics(alias: string, date: string) { const pool = this.databasePools[alias]; if (!pool) throw new Error(`Server alias ${alias} not found`); // 假设analytics_db中有一个orders表 const query = ` SELECT COUNT(*) as total_orders, SUM(order_amount) as total_gmv, COUNT(DISTINCT user_id) as unique_buyers FROM public.orders WHERE DATE(order_time) = $1::date `; const result = await pool.query(query, [date]); return { content: [{ type: "text", text: `**${date} 业务指标**\n` + `- 总订单数: ${result.rows[0].total_orders}\n` + `- 总交易额(GMV): ${result.rows[0].total_gmv}\n` + `- 独立买家数: ${result.rows[0].unique_buyers}` }], }; }
  3. 重新构建并重启服务器:修改代码后,需要重新编译(如果是TypeScript)并重启MCP服务器进程。

4.2 性能优化与连接池调优

在生产环境中,性能至关重要。主要优化点在于PostgreSQL连接池。

  • 连接池参数servers.yaml中的pool配置。

    • max:最大连接数。这不是越大越好。需要根据你的数据库max_connections设置和并发MCP请求量来定。通常设置为(数据库总连接数 / 应用服务数) - 安全余量。对于MCP这种可能突发查询的服务,初始值10-20是个合理的起点。
    • idleTimeoutMillis:空闲连接超时时间。设置太短会导致连接频繁重建,太长则占用资源。30秒到5分钟之间都是常见值。
    • connectionTimeoutMillis:获取连接的超时时间。如果池中无可用连接,等待多久后失败。建议设置5-10秒。
  • 查询优化

    • 索引提示:虽然AI生成的查询是动态的,但你可以在暴露给AI的“资源”描述中,加入关键表的索引信息提示。例如,在表结构资源中,可以追加一行注释:“主要查询字段user_idorder_time已建立索引”。
    • 避免SELECT *:在execute_sql工具的实现逻辑中,可以加入一个简单的解析器,对明显低效的查询进行警告或拦截(例如,对超过10个字段的表使用SELECT *且没有LIMIT)。
  • 缓存策略:对于元数据(如表结构),变化频率很低,可以在服务器内存中缓存一段时间(例如5分钟),避免每次AI询问“有哪些表”都去查询information_schema

4.3 安全加固实践

安全是数据服务的生命线。除了配置中的基础过滤和权限控制,还有更多加固措施:

  1. 网络层隔离:将MCP服务器部署在数据库所在的私有网络(VPC)内。AI客户端(如Claude Desktop)通过安全的内部网关或VPN(此处指企业内网VPN,非敏感词)访问该服务,而不是将服务直接暴露在公网。
  2. 审计日志:修改服务器代码,记录所有通过MCP执行的查询。日志应包括:时间戳、AI客户端标识(如果协议提供)、执行的工具名、查询参数(脱敏后)、执行耗时、是否成功。这有助于事后分析和安全审计。
    // 在工具调用处理函数中 const startTime = Date.now(); let success = false; try { // ... 执行工具 success = true; } finally { const duration = Date.now() - startTime; auditLogger.info({ tool: request.name, params: sanitizeParams(request.params), // 脱敏函数,移除密码等 duration, success, timestamp: new Date().toISOString(), }); }
  3. 查询预检:在真正执行SQL前,可以增加一个预检环节。使用pg库的query方法传入参数化查询,这本身能防止SQL注入。此外,可以引入一个简单的SQL解析库(如@pgquery/parser),对查询进行语法树分析,拦截明显危险的操作(如DROPTRUNCATEALTER),或者检查是否包含未被授权的表名。
  4. 速率限制:为防止滥用,可以在服务器层面或每个数据库连接层面添加速率限制(rate limiting),例如每分钟最多执行30次查询。

5. 常见问题排查与实战心得

5.1 连接与配置问题

问题1:启动服务器时报错“Cannot find module ‘@modelcontextprotocol/sdk’”。

  • 原因:依赖未正确安装或Node.js版本不兼容。
  • 解决
    1. 删除node_modulespackage-lock.json(或yarn.lockpnpm-lock.yaml)。
    2. 确认Node.js版本符合项目要求(查看.nvmrcpackage.json中的engines字段)。
    3. 重新运行npm installpnpm install
    4. 如果是TypeScript项目,确保运行了构建步骤(npm run build)后再启动。

问题2:Claude Desktop无法发现MCP服务器工具。

  • 原因:配置路径错误、服务器未成功启动、或MCP通信协议不匹配。
  • 排查步骤
    1. 检查服务器日志:首先确保MCP服务器进程本身已成功启动,没有报错。查看其输出日志,确认它已加载配置并建立了数据库连接。
    2. 验证STDIO通信:对于STDIO模式,可以手动测试。写一个简单的JSON-RPC请求到服务器的标准输入,看是否有响应。这需要一些脚本技巧。
    3. 检查Claude配置:确保Claude Desktop配置文件中commandargs的路径是绝对路径。相对路径在Claude的上下文中可能解析错误。环境变量env是否已正确设置。
    4. 查看Claude日志:Claude Desktop通常有开发者日志输出位置(如macOS可能在~/Library/Logs/Claude/)。查看日志中是否有加载MCP服务器时的错误信息。

问题3:连接数据库超时或认证失败。

  • 原因:网络不通、防火墙规则、数据库用户权限不足或密码错误。
  • 解决
    1. 使用psql命令行工具,用相同的连接参数手动连接,这是最快的排错方法:psql -h host -p port -U user -d database
    2. 检查数据库的pg_hba.conf文件,确保允许来自MCP服务器IP地址的连接,并使用正确的认证方法(如md5scram-sha-256)。
    3. 确认数据库用户密码是否正确,以及是否具有对目标数据库和模式的CONNECTSELECT权限。

5.2 查询执行与性能问题

问题4:AI执行查询返回“行数超过限制”。

  • 原因:查询结果集超过了配置文件中row_limit的限制。
  • 解决:这是预期中的安全行为。你需要引导AI优化查询,例如:
    • 增加更多的WHERE条件来过滤数据。
    • 使用聚合函数(如COUNT,SUM,AVG)代替返回所有明细行。
    • 明确要求AI在查询中加上LIMIT子句。你也可以在工具描述中提示AI默认应使用LIMIT

问题5:复杂查询执行缓慢,导致AI请求超时。

  • 原因:AI客户端或MCP服务器可能有默认的请求超时设置(如30秒或60秒)。查询本身可能缺少索引、涉及多张大表关联或计算量大。
  • 解决
    1. 优化查询:引导AI写出更高效的查询。例如,避免在WHERE子句中对字段进行函数操作(如WHERE DATE(created_at) = '...'),这会导致索引失效。
    2. 利用资源(Resources):对于常用的聚合数据,可以预先定义为“资源”。例如,创建一个名为postgres://analytics_db/dashboard/daily_summary的资源,其内容是一个返回昨日汇总数据的视图或函数的结果。AI直接读取这个资源,速度远快于执行原始查询。
    3. 调整超时设置:如果确实需要执行长查询,可以查阅MCP服务器和客户端的文档,看是否有配置项可以增加超时时间(但需谨慎,避免阻塞)。

5.3 实战心得与最佳实践

  1. 从“只读”开始,逐步放开:在项目初期,将所有数据库连接配置为只读账号,并且只暴露几个核心的、非敏感的业务表。观察AI如何使用这些数据,并收集日志。在充分信任和验证后,再考虑是否暴露更多表或开放有限度的写操作(需极其谨慎,并配合审批流程)。
  2. 为AI提供“数据字典”:在表结构资源中,除了字段名和类型,最好能加入业务含义注释。你可以在数据库建表时使用COMMENT语句,或者通过MCP服务器在返回资源时动态附加。这能极大提升AI理解数据、生成准确查询的能力。例如,order_status字段,注释上“1-待支付,2-已支付,3-已发货,4-已完成,5-已取消”。
  3. 设计“安全查询”模板:与其让AI完全自由发挥,不如预先定义一些常用的、安全的查询作为“工具”或“提示词”。例如,创建一个get_user_behavior工具,它接收user_iddate_range参数,内部调用一个存储过程或参数化视图。这样既满足了需求,又将查询逻辑牢牢控制在安全范围内。
  4. 监控与告警:将MCP服务器的审计日志接入你的监控系统(如ELK、Prometheus+Grafana)。设置关键告警,例如:同一来源短时间内高频查询、查询返回行数持续触顶、出现语法错误频次过高等。这能帮助你及时发现异常使用模式或潜在攻击。
  5. 团队协作与知识沉淀:当团队多人使用此工具时,维护一份统一的“数据访问指南”文档。记录哪些数据库和表已暴露、各自的业务含义、常用的查询模式示例、以及遇到问题的排查流程。这能降低沟通成本,并让新成员快速上手。

部署和使用multi-postgres-mcp-server的过程,是一个在“释放数据价值”和“保障数据安全”之间寻找精妙平衡点的过程。它不是一个“设置完就忘”的工具,而是一个需要持续观察、调整和优化的数据服务层。通过细致的配置、深度的定制和严格的安全规范,它能真正成为连接AI智能体与企业数据宝藏的安全、高效的桥梁,让数据驱动决策变得更加自然和直接。

http://www.jsqmd.com/news/817707/

相关文章:

  • STM32实战:从零搭建智能温湿度监控与本地报警系统
  • 【工作流】工作流
  • 告别枯燥界面:用Qt自定义控件打造游戏化HMI(汽车仪表+雷达扫描实战)
  • 山东优质双眼皮机构排行 5家正规专科实力盘点 - 资讯焦点
  • DC-4靶机实战:从Web渗透到权限提升的完整路径解析
  • 在企业内部工具中集成 Taotoken 实现安全的 AI 能力调用
  • 在stm32开发板上搭建本地代理并连接taotoken api的实践
  • Python-docx实战:手把手教你制作一份专业简历(附完整源码与样式详解)
  • 包头招聘平台哪个岗位多:秒聘网全岗齐全 - 17322238651
  • 当中国能力遇见全球生态:严定贵的共创实验 - 资讯焦点
  • 使用Taotoken后我的API调用延迟与稳定性体验观察
  • 从零构建个人AI语义代理:架构设计与工程实践指南
  • 从QA技能树到测试架构师:系统化学习路径与工程实践指南
  • 2026年5月涠洲岛海边民宿/海景民宿/靠海民宿/泳池民宿哪家好,认准涠洲岛希暮海岸民宿 - 2026年企业推荐榜
  • SOLID不是教条!DeepSeek检查报告揭示:83%的“违规”实为合理权衡——附5个高可信度豁免决策框架
  • 石家庄地接社 石家庄地接旅行社推荐-石家庄燕赵旅行社 - 好物推荐官
  • 滨州招聘软件哪个岗位多:秒聘网多岗可选 - 17329971652
  • 保姆级教程:在CentOS 7上从源码编译EMQX 4.3并集成Kafka插件(附避坑指南)
  • RADIal数据集实战:手把手教你用Python处理高清雷达原始数据(附FFT-RadNet复现指南)
  • Fluent表达式保姆级教程:像用Excel函数一样玩转CFD仿真(附2024R1版量纲避坑指南)
  • 数据中心节能技术:从冷却优化到供电架构革新
  • 凰标非虚名:立亿万创作草根之精神图腾@凤凰标志
  • 告别繁琐!ESXi 8.0直接部署vCenter 8.0 Appliance(VCSA)超详细图文指南
  • 包头招聘平台推荐:秒聘网实力优选 - 13425704091
  • 滨州招聘软件推荐:秒聘网臻选好物 - 13724980961
  • PLL抖动特性分析的混合信号仿真方法
  • 提示工程:从CRAC框架到思维链,掌握与大模型高效协作的核心技能
  • 用STM32的TIM1和EXTI中断搞定带霍尔BLDC的方波调速(附完整代码)
  • Google借Goog I/O大会推新品抢智能穿戴市场,无屏手环WHOOP凭何逆袭成中产社交符号?
  • 别再只盯着Transformer了!用300小时中文数据实测CLDNN模型,聊聊这个被低估的语音识别‘老将’