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

Function Calling 最佳实践:10个让代码质量提升10倍的工程技巧


一、前言

Function Calling 最佳实践:10个让代码质量提升10倍的工程技巧。本文从实际项目出发,给出完整可运行的代码,帮你快速掌握实战技能。


二、需求分析与架构设计

2.1 业务需求

功能需求: - 用户注册/登录,支持邮箱和手机号 - JWT 无状态认证,支持 RefreshToken 续期 - RBAC 权限控制(超级管理员/普通用户/访客) - 操作日志审计 非功能需求: - 支持 1000 并发 QPS - 接口响应时间 P99 < 200ms - 99.9% 可用性

2.2 技术选型

语言框架:Node.js + Fastify(或 技术) 数据库:PostgreSQL + Redis 认证:JWT (access_token 15min, refresh_token 7d) ORM:Prisma(类型安全、自动迁移) API:RESTful + OpenAPI 文档 部署:Docker + K8s

三、核心功能实现

3.1 数据库设计与建模

-- 用户表 CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), username VARCHAR(64) NOT NULL UNIQUE, email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, role VARCHAR(32) NOT NULL DEFAULT 'user', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}$') ); -- 角色表 CREATE TABLE roles ( id SERIAL PRIMARY KEY, name VARCHAR(32) NOT NULL UNIQUE, permissions JSONB NOT NULL DEFAULT '[]' ); -- 操作日志表 CREATE TABLE audit_logs ( id BIGSERIAL PRIMARY KEY, user_id UUID REFERENCES users(id), action VARCHAR(128) NOT NULL, resource VARCHAR(256), details JSONB, ip_address INET, created_at TIMESTAMP DEFAULT NOW() ); -- 索引 CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_role ON users(role); CREATE INDEX idx_audit_user ON audit_logs(user_id, created_at DESC);

3.2 用户认证服务

// 技术 用户认证服务 const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); class AuthService { constructor(db, redis) { this.db = db; this.redis = redis; } async register({ username, email, password, role = 'user' }) { // 1. 校验唯一性 const existing = await this.db.query( 'SELECT id FROM users WHERE username=$1 OR email=$2', [username, email] ); if (existing.rows.length > 0) { throw new Error('用户名或邮箱已存在'); } // 2. 密码哈希(bcrypt,cost=12) const password_hash = await bcrypt.hash(password, 12); // 3. 创建用户 const result = await this.db.query( `INSERT INTO users (username, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id, username, email, role`, [username, email, password_hash, role] ); // 4. 生成 Token const user = result.rows[0]; return this.issueTokens(user); } async login({ email, password }) { const result = await this.db.query( 'SELECT * FROM users WHERE email=$1', [email] ); const user = result.rows[0]; if (!user || !(await bcrypt.compare(password, user.password_hash))) { throw new Error('邮箱或密码错误'); } // 记录登录日志 await this.logAction(user.id, 'LOGIN', { email }); return this.issueTokens(user); } issueTokens(user) { const accessToken = jwt.sign( { user_id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '15m' } ); const refreshToken = jwt.sign( { user_id: user.id, type: 'refresh' }, process.env.JWT_REFRESH_SECRET, { expiresIn: '7d' } ); // RefreshToken 黑名单(注销时使用) return { accessToken, refreshToken }; } async logAction(userId, action, details) { await this.db.query( `INSERT INTO audit_logs (user_id, action, details) VALUES ($1, $2, $3)`, [userId, action, JSON.stringify(details)] ); } }

3.3 权限控制中间件

// RBAC 权限检查 const ROLE_PERMISSIONS = { admin: ['users:read', 'users:write', 'users:delete', 'audit:read'], user: ['users:read', 'profile:write'], guest: [] }; function authorize(...requiredPermissions) { return async (req, res, next) => { const user = req.user; if (!user) { return res.status(401).json({ error: '未认证' }); } const userPermissions = ROLE_PERMISSIONS[user.role] || []; const hasPermission = requiredPermissions.every(p => userPermissions.includes(p) ); if (!hasPermission) { await authService.logAction(user.id, 'UNAUTHORIZED_ACCESS', { required: requiredPermissions, user_role: user.role }); return res.status(403).json({ error: '权限不足' }); } next(); }; } // 使用 app.get('/api/users', authenticate, // 认证 authorize('users:read'), // 权限 async (req, res) => { const users = await userService.list(req.query); res.json(users); } );

四、测试与质量保证

4.1 单元测试

// 技术 单元测试(Jest) describe('AuthService', () => { let authService; let mockDb; let mockRedis; beforeEach(() => { mockDb = { query: jest.fn() }; mockRedis = { set: jest.fn(), get: jest.fn() }; authService = new AuthService(mockDb, mockRedis); }); test('register: 正常注册返回 Token', async () => { mockDb.query .mockResolvedValueOnce({ rows: [] }) // 唯一性检查 .mockResolvedValueOnce({ // 创建用户 rows: [{ id: 'uuid-1', username: 'alice', email: 'a@b.com', role: 'user' }] }); const result = await authService.register({ username: 'alice', email: 'a@b.com', password: 'StrongPass123' }); expect(result).toHaveProperty('accessToken'); expect(result).toHaveProperty('refreshToken'); expect(mockDb.query).toHaveBeenCalledTimes(2); }); test('register: 重复邮箱抛异常', async () => { mockDb.query.mockResolvedValueOnce({ rows: [{ id: 'existing-uuid' }] }); await expect( authService.register({ username: 'alice', email: 'a@b.com', password: 'pass' }) ).rejects.toThrow('用户名或邮箱已存在'); }); test('login: 错误密码抛异常', async () => { mockDb.query.mockResolvedValueOnce({ rows: [{ id: 'uuid-1', password_hash: await bcrypt.hash('correct-password', 12) }] }); await expect( authService.login({ email: 'a@b.com', password: 'wrong-password' }) ).rejects.toThrow('邮箱或密码错误'); }); });

五、部署与运维

5.1 Docker Compose 本地开发

version: '3.8' services: app: build: . ports: - "8080:8080" environment: DATABASE_URL: postgresql://appuser:secret@db:5432/appdb REDIS_URL: redis://redis:6379/0 JWT_SECRET: ${JWT_SECRET} depends_on: db: condition: service_healthy redis: condition: service_started db: image: postgres:16-alpine environment: POSTGRES_DB: appdb POSTGRES_USER: appuser POSTGRES_PASSWORD: secret volumes: - pgdata:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - redisdata:/data volumes: pgdata: redisdata:

5.2 GitHub Actions CI/CD

name: CI/CD on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_DB: testdb POSTGRES_USER: test POSTGRES_PASSWORD: test options: >- --health-cmd pg_isready --health-interval 10s steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm ci - run: npm test -- --coverage - uses: codecov/codecov-action@v3 deploy: needs: test if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: docker build -t app . - run: docker push ghcr.io/${{ github.repository }}:latest

六、总结

  1. 先设计再写代码:数据库建模 + API 接口设计在前
  2. 测试驱动开发:每个功能有测试,提交前跑全量 suite
  3. 日志要完整:操作日志是排查问题的救命稻草
  4. 环境隔离:dev/staging/prod 配置要分开

💬收藏本文!关注我,后续更新更多实战项目系列。


💬觉得有用的话,点个赞+收藏,关注我,持续更新优质技术内容!

标签:Function Calling | 最佳实践 | 代码质量 | 工程 | 实战

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

相关文章:

  • 2026-04-18 模拟赛总结
  • 从SPI引脚别名到实战选型:当芯片手册上的SDI/SDO把你搞晕时,这份避坑指南请收好
  • 当芯片研发流程引入AI,我们需要这个checklist
  • 告别依赖地狱:用linuxdeployqt和dpkg为你的Qt应用打造一键安装的deb包(Ubuntu 20.04实测)
  • 基于FPGA与Matlab算法的超声多普勒频移解调系统:DDS生成信号、混合与滤波处理、FFT...
  • 微信在Linux上的默认数据目录
  • ILSpy终极指南:如何快速掌握.NET反编译神器
  • Manjaro新手避坑指南:从依赖缺失到签名错误,一次搞定所有安装报错
  • Tool之Jira:从零到一,构建高效敏捷团队的Jira实战配置与核心流程详解
  • 2026年宁波VBEAUTY科技美肤公司推荐榜/vbeauty美容店,vbeauty面部清洁,vbeauty面部补水,vbeauty面部肌底护理 - 品牌策略师
  • AGI物流决策引擎实测对比:传统TMS vs. 类脑调度系统,响应延迟下降83%,成本优化率达19.4%——数据来自顺丰、菜鸟闭门测试
  • CSS Grid布局如何实现项目水平垂直居中_掌握place-items属性的用法
  • 2019服务器IIS配置
  • Zotero-SciHub插件实战:学术文献自动获取的技术原理与实现深度解析
  • 英飞凌TC387 PMSM FOC电机控制Demo程序深度解析
  • FPGA数码管驱动避坑指南:从共阴共阳到分时复用,新手最容易搞错的5个点
  • 安全代码审查
  • OpCore Simplify:三步快速配置黑苹果的终极自动化工具指南
  • OpenClaw 已过时?在 VS Code 中运行 Hermes Agent!
  • 如果大模型懂电路,那也是工程师塞进去的
  • 2025终极指南:如何快速上手Il2CppDumper进行Unity逆向工程
  • 5分钟完美移植:在Windows和Linux上使用macOS风格鼠标指针的完整指南
  • Joplin跨设备同步冲突:数据一致性保障机制解析
  • 从CloudCompare的ccViewer源码入手,拆解一个工业级Qt+OpenGL点云查看器的架构设计
  • 深聊硅胶胶带厂家,哪家口碑好且价格合理 - 工业品网
  • 华硕游戏本终极优化指南:如何用G-Helper释放硬件全部潜能?
  • FPGA新手必看:MIG配置DDR3 SODIMM内存条接口的5个常见坑点及解决方案
  • G-Helper技术架构深度解析:如何通过轻量化设计重构华硕硬件控制生态
  • Phi-3 Forest Lab从零开始:基于Ollama封装Phi-3 Forest Lab轻量服务API
  • 蓝桥杯单片机NE555测频实战:手把手教你用定时器捕获模式搞定(附完整代码)