初识Function Calling:让AI学会“调用工具”

从"只会聊天"到"能干实事",一文搞懂AI工具调用机制

什么是Function Calling?为什么它如此重要?

一个让所有开发者都头疼的场景

想象一下,我们正在开发一个AI助手,此时用户提问:

text 复制代码
用户:"帮我查一下北京今天的天气怎么样?"

如果没有 Function Calling,AI只能这样回答:

复制代码
AI:"抱歉,目前我无法直接获取实时天气信息。建议您打开天气应用或访问天气网站。"

或者更糟糕的情况:

bash 复制代码
用户:"帮我把当前目录的文件列表列出来"
AI:"我无法直接访问您本地的文件系统,您可以使用以下命令:ls -la (在Linux/Mac)或 dir (在Windows)"

看到了吧,这种情况下,AI只能告诉我们 该怎么做 ,而不是 帮我们做。这就像我们问助手"帮我拿杯水",他回答"你应该走到饮水机旁,按下出水按钮"一样------理论上没错,但毫无用处。

Function Calling:让AI真正"动起来"

Function Calling的核心思想很简单:让AI输出结构化的函数调用请求,而不是普通文本

sql 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      没有Function Calling                        │
├─────────────────────────────────────────────────────────────────┤
│  用户:北京天气怎么样?                                             │
│  AI:抱歉,我无法查询实时天气...(死胡同)                            │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                      有Function Calling                         │
├─────────────────────────────────────────────────────────────────┤
│  用户:北京天气怎么样?                                             │
│  AI:返回 { "tool": "get_weather", "args": { "city": "北京" } }   │
│  开发者:执行get_weather("北京") → { temp: 22, condition: "晴" }   │
│  AI:北京今天晴,温度22℃,适合户外活动!                              │
└─────────────────────────────────────────────────────────────────┘

一句话总结

Function Calling让AI从"只会说话"进化到"能干实事"。它可以:

  • ✅ 查询实时数据(天气、股票、新闻)
  • ✅ 操作本地系统(读写文件、执行命令)
  • ✅ 调用第三方API(发送邮件、创建日历)
  • ✅ 执行复杂计算(数学运算、数据分析)

Function Calling的核心机制

请求格式:告诉AI,我们有哪些工具

调用 API 时,除了常规的messages,还可以传入 tools 参数,描述可用的工具:

json 复制代码
{
  "model": "deepseek-chat",
  "messages": [
    {
      "role": "user",
      "content": "北京今天天气怎么样?"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "获取指定城市的天气信息,返回温度、天气状况、湿度",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {
              "type": "string",
              "description": "城市名称,如:北京、上海、深圳"
            }
          },
          "required": ["city"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

响应格式:AI决定调用哪个工具

当 AI 认为需要调用工具时,返回的就不在是普通文本,而是 tool_calls

json 复制代码
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"北京\"}"
            }
          }
        ]
      }
    }
  ]
}

关键字段解析

字段 说明
id 工具调用的唯一标识,用于追踪和调试
function.name 要调用的函数名称
function.arguments JSON字符串格式的参数

完整的5步调用流程

步骤1:发送用户消息 + 工具定义

javascript 复制代码
messages: [{ role: "user", content: "北京天气" }]
tools: [{ function: { name: "get_weather", ... } }]     

步骤2:AI返回tool_calls

javascript 复制代码
tool_calls: [
	{ 
		function: { name: "get_weather", 
		arguments: "{\"city\":\"北京\"}" 
	}
] 

步骤3:执行对应函数

javascript 复制代码
const result = await getWeather("北京") 

步骤4:将结果作为tool角色消息返回给AI

javascript 复制代码
messages.push({
   role: "tool",
   tool_call_id: "call_abc123",
   content: JSON.stringify(result)
})   

步骤5:AI基于工具结果生成最终答案

text 复制代码
AI: "北京今天晴,温度22℃,湿度65%,适合户外活动!"   

完整代码示例(5步流程)

typescript 复制代码
// 步骤1:发送消息 + 工具定义
async function chatWithTools(userMessage: string) {
  const messages = [{ role: 'user', content: userMessage }]
  
  // 第一次调用
  const response = await callDeepSeek(messages, tools)
  const assistantMessage = response.choices[0].message
  
  // 检查是否有tool_calls
  if (assistantMessage.tool_calls) {
    // 步骤2:有工具调用,执行工具
    messages.push(assistantMessage) // 先把AI的消息加入历史
    
    for (const toolCall of assistantMessage.tool_calls) {
      // 步骤3:执行工具
      const result = await executeToolCall(toolCall)
      
      // 步骤4:将工具结果加入历史
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify(result)
      })
    }
    
    // 步骤5:再次调用AI,带上工具结果
    const finalResponse = await callDeepSeek(messages, tools)
    return finalResponse.choices[0].message.content
  }
  
  // 没有工具调用,直接返回
  return assistantMessage.content
}

Tool Schema设计指南

工具描述的质量,直接决定了AI调用工具的准确率。一个好的Schema能让AI准确理解工具的用途和参数。

命名规范

使用动词开头的蛇形命名,清晰表达功能:

✅ 好的命名 ❌ 差的命名 说明
get_weather weather 动词开头,明确是获取操作
search_files files 明确是搜索行为
send_email email 明确是发送操作
calculate_expression calc 避免缩写

描述的艺术 - 至关重要

描述越详细,AI选择工具的准确率越高。描述应该包含:做什么、输入什么、输出什么、何时使用

错误示范

json 复制代码
{
  "name": "get_weather",
  "description": "查询天气"  // ❌ 太简单了!
}

正确示范

json 复制代码
{
  "name": "get_weather",
  "description": "获取指定城市的实时天气信息,返回温度、天气状况、湿度、风速。适用于用户询问任何城市的天气情况。如果用户没有指定城市,请先询问城市名称。"
}

参数定义技巧

技巧 说明 示例
详细描述 说明参数含义和格式 "城市名称,如:北京、上海、深圳"
使用enum 限定可选值 enum: ["user", "admin", "editor"]
设置required 明确必填参数 required: ["city"]
提供示例 部分模型支持examples examples: ["北京", "上海"]

复杂参数的Schema设计

json 复制代码
{
  "name": "create_event",
  "description": "在日历中创建新事件",
  "parameters": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "description": "事件标题,简洁明了"
      },
      "start_time": {
        "type": "string",
        "description": "开始时间,ISO 8601格式,如:2026-01-01T14:00:00+08:00"
      },
      "end_time": {
        "type": "string",
        "description": "结束时间,ISO 8601格式"
      },
      "attendees": {
        "type": "array",
        "description": "参与者邮箱列表",
        "items": {
          "type": "string",
          "format": "email"
        }
      },
      "reminder_minutes": {
        "type": "integer",
        "description": "提前多少分钟提醒",
        "minimum": 0,
        "maximum": 1440,
        "default": 15
      }
    },
    "required": ["title", "start_time"]
  }
}

好/坏描述对比表

方面 ❌ 坏描述 ✅ 好描述
工具名 process send_email
工具描述 处理邮件 发送邮件,收件人、主题、正文为必填,支持HTML格式
参数city 城市 城市名称,如北京、上海,支持直辖市和省会城市
参数date 日期 日期,格式YYYY-MM-DD,如2026-01-01
参数status 状态 状态,可选值:pending/done/cancelled

实战:从0到1实现工具调用

项目准备

首先,确保我们有DeepSeek API Key(或者相关大模型 API Key)。如果没有,可以去DeepSeek官网注册获取。

bash 复制代码
# 创建项目目录
mkdir ai-function-calling
cd ai-function-calling

# 初始化项目
npm init -y

# 安装依赖
npm install typescript @types/node axios dotenv
npm install -D ts-node

# 创建TypeScript配置
npx tsc --init

创建 .env 文件:

text 复制代码
DEEPSEEK_API_KEY=sk-your-api-key-here
DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions

完整代码实现

创建 index.ts

typescript 复制代码
import axios from 'axios'
import dotenv from 'dotenv'
import readline from 'readline'

dotenv.config()

// ==================== 类型定义 ====================

interface Message {
  role: 'system' | 'user' | 'assistant' | 'tool'
  content: string | null
  tool_calls?: ToolCall[]
  tool_call_id?: string
}

interface ToolCall {
  id: string
  type: 'function'
  function: {
    name: string
    arguments: string
  }
}

interface Tool {
  type: 'function'
  function: {
    name: string
    description: string
    parameters: {
      type: 'object'
      properties: Record<string, any>
      required?: string[]
    }
  }
}

// ==================== 工具定义 ====================

const tools: Tool[] = [
  {
    type: 'function',
    function: {
      name: 'get_weather',
      description: '获取指定城市的天气信息,返回温度、天气状况、湿度。适用于用户询问任何城市的天气情况。',
      parameters: {
        type: 'object',
        properties: {
          city: {
            type: 'string',
            description: '城市名称,如:北京、上海、深圳、广州'
          }
        },
        required: ['city']
      }
    }
  },
  {
    type: 'function',
    function: {
      name: 'calculate',
      description: '执行数学计算,支持加减乘除和幂运算。当用户需要计算数学表达式时使用。',
      parameters: {
        type: 'object',
        properties: {
          expression: {
            type: 'string',
            description: '数学表达式,如:2+2、10*5、2^10'
          }
        },
        required: ['expression']
      }
    }
  },
  {
    type: 'function',
    function: {
      name: 'get_current_time',
      description: '获取当前日期和时间。当用户询问现在几点、今天几号、当前时间等信息时使用。',
      parameters: {
        type: 'object',
        properties: {
          timezone: {
            type: 'string',
            description: '时区,如:Asia/Shanghai、America/New_York,默认为本地时区',
            enum: ['Asia/Shanghai', 'America/New_York', 'Europe/London', 'Asia/Tokyo']
          }
        }
      }
    }
  }
]

// ==================== 工具实现 ====================

/**
 * 获取天气(模拟数据,实际可替换为真实API)
 */
async function getWeather(city: string): Promise<any> {
  // 模拟API延迟
  await new Promise(resolve => setTimeout(resolve, 500))
  
  // 模拟天气数据
  const weatherData: Record<string, any> = {
    '北京': { temperature: 22, condition: '晴', humidity: 45, wind_speed: 12 },
    '上海': { temperature: 26, condition: '多云', humidity: 70, wind_speed: 8 },
    '深圳': { temperature: 28, condition: '晴', humidity: 65, wind_speed: 10 },
    '广州': { temperature: 30, condition: '雷阵雨', humidity: 85, wind_speed: 15 }
  }
  
  const data = weatherData[city] || {
    temperature: 20 + Math.floor(Math.random() * 10),
    condition: ['晴', '多云', '阴', '小雨'][Math.floor(Math.random() * 4)],
    humidity: 40 + Math.floor(Math.random() * 40),
    wind_speed: 5 + Math.floor(Math.random() * 15)
  }
  
  return {
    city,
    ...data,
    update_time: new Date().toISOString()
  }
}

/**
 * 执行数学计算
 */
async function calculate(expression: string): Promise<number> {
  // 安全起见,只允许数字和基本运算符
  const sanitized = expression.replace(/[^0-9+\-*/^().]/g, '')
  if (!sanitized) {
    throw new Error('无效的表达式')
  }
  
  // 处理幂运算
  const withPow = sanitized.replace(/\^/g, '**')
  
  // 使用Function构造器执行计算(注意:生产环境需要更严格的安全检查)
  const result = new Function(`return (${withPow})`)()
  
  if (typeof result !== 'number' || isNaN(result)) {
    throw new Error('计算失败')
  }
  
  return result
}

/**
 * 获取当前时间
 */
async function getCurrentTime(timezone?: string): Promise<string> {
  const date = new Date()
  
  if (timezone === 'Asia/Shanghai') {
    return date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
  } else if (timezone === 'America/New_York') {
    return date.toLocaleString('zh-CN', { timeZone: 'America/New_York' })
  } else if (timezone === 'Europe/London') {
    return date.toLocaleString('zh-CN', { timeZone: 'Europe/London' })
  } else if (timezone === 'Asia/Tokyo') {
    return date.toLocaleString('zh-CN', { timeZone: 'Asia/Tokyo' })
  }
  
  return date.toLocaleString('zh-CN')
}

// ==================== 工具调度器 ====================

async function executeToolCall(toolCall: ToolCall): Promise<any> {
  const { name, arguments: argsStr } = toolCall.function
  const args = JSON.parse(argsStr)
  
  console.log(`🔧 执行工具: ${name}`, args)
  
  switch (name) {
    case 'get_weather':
      return await getWeather(args.city)
    
    case 'calculate':
      const result = await calculate(args.expression)
      return { expression: args.expression, result }
    
    case 'get_current_time':
      const time = await getCurrentTime(args.timezone)
      return { time, timezone: args.timezone || 'local' }
    
    default:
      throw new Error(`未知工具: ${name}`)
  }
}

// ==================== DeepSeek API调用 ====================

const API_URL = process.env.DEEPSEEK_API_URL || 'https://api.deepseek.com/v1/chat/completions'
const API_KEY = process.env.DEEPSEEK_API_KEY

async function callDeepSeek(messages: Message[]): Promise<any> {
  const response = await axios.post(
    API_URL,
    {
      model: 'deepseek-chat',
      messages,
      tools,
      tool_choice: 'auto',
      temperature: 0.7
    },
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`
      }
    }
  )
  
  return response.data
}

// ==================== 主对话循环 ====================

async function chat(userInput: string): Promise<string> {
  const messages: Message[] = [
    { role: 'user', content: userInput }
  ]
  
  // 第一次调用
  console.log(`\n📝 用户: ${userInput}`)
  const response = await callDeepSeek(messages)
  const assistantMessage = response.choices[0].message
  
  // 如果没有tool_calls,直接返回
  if (!assistantMessage.tool_calls || assistantMessage.tool_calls.length === 0) {
    console.log(`🤖 AI: ${assistantMessage.content}`)
    return assistantMessage.content
  }
  
  // 有工具调用,处理
  messages.push({
    role: 'assistant',
    content: null,
    tool_calls: assistantMessage.tool_calls
  })
  
  // 执行所有工具调用
  for (const toolCall of assistantMessage.tool_calls) {
    try {
      const result = await executeToolCall(toolCall)
      
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify(result)
      })
    } catch (error) {
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify({ error: (error as Error).message })
      })
    }
  }
  
  // 第二次调用,带上工具结果
  console.log(`🔄 携带工具结果,再次调用...`)
  const finalResponse = await callDeepSeek(messages)
  const finalContent = finalResponse.choices[0].message.content
  
  console.log(`🤖 AI: ${finalContent}`)
  return finalContent
}

// ==================== 交互式运行 ====================

async function runInteractive() {
  // 创建 readline 接口
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  })
  
  // 封装 ask 函数
  const ask = (question: string): Promise<string> => {
    return new Promise((resolve) => {
      rl.question(question, resolve)
    })
  }
  
  console.log('='.repeat(50))
  console.log('🤖 AI助手已启动(支持工具调用)')
  console.log('可用工具: 天气查询、数学计算、获取时间')
  console.log('输入 "exit" 退出')
  console.log('='.repeat(50))
  
  while (true) {
    const input = await ask('\n> ')
    if (input === 'exit') break
    if (!input.trim()) continue
    
    try {
      await chat(input)
    } catch (error) {
      console.error('❌ 错误:', error)
    }
    
    console.log('-'.repeat(50))
  }
  
  rl.close()
  console.log('👋 再见!')
}

// ==================== 启动应用 ====================

// 检查环境变量
if (!API_KEY) {
  console.error('❌ 错误: 请在 .env 文件中设置 DEEPSEEK_API_KEY')
  process.exit(1)
}

runInteractive().catch(console.error)

运行效果演示

diff 复制代码
==================================================
🤖 AI助手已启动(支持工具调用)
可用工具: 天气查询、数学计算、获取时间
输入 "exit" 退出
==================================================

> 北京今天天气怎么样?

📝 用户: 北京今天天气怎么样?
🔧 执行工具: get_weather { city: '北京' }
🔄 携带工具结果,再次调用...
🤖 AI: 根据最新的天气信息,北京今天的天气情况如下:

- **温度**:22°C
- **天气状况**:晴
- **湿度**:45%
- **风速**:12 km/h

今天北京天气晴朗,温度适中,是个不错的天气!

--------------------------------------------------

> 帮我算一下 123 * 456

📝 用户: 帮我算一下 123 * 456
🔧 执行工具: calculate { expression: '123*456' }
🔄 携带工具结果,再次调用...
🤖 AI: 123 × 456 = 56,088

--------------------------------------------------

> 现在几点?

📝 用户: 现在几点?
🔧 执行工具: get_current_time {}
🔄 携带工具结果,再次调用...
🤖 AI: 现在是2026年3月23日 12:26:24。

--------------------------------------------------

多工具协同实战

场景:AI需要连续调用多个工具

用户问:"北京天气怎么样?如果温度低于20度,提醒我多穿衣服"

这个场景需要AI:

  1. 先调用 get_weather 获取北京天气
  2. 分析温度,判断是否需要调用 compare_temperature
  3. 生成最终建议

实现:串行调用链

typescript 复制代码
// 添加温度比较工具
const additionalTools: Tool[] = [
  {
    type: 'function',
    function: {
      name: 'compare_temperature',
      description: '比较温度与阈值,返回是否需要提醒。用于根据天气温度生成生活建议。',
      parameters: {
        type: 'object',
        properties: {
          temperature: {
            type: 'number',
            description: '当前温度(摄氏度)'
          },
          threshold: {
            type: 'number',
            description: '比较阈值,默认20度',
            default: 20
          }
        },
        required: ['temperature']
      }
    }
  }
]

// 实现比较函数
async function compareTemperature(temperature: number, threshold: number = 20): Promise<any> {
  return {
    temperature,
    threshold,
    need_reminder: temperature < threshold,
    suggestion: temperature < threshold 
      ? `温度${temperature}℃低于${threshold}℃,建议多穿衣服`
      : `温度${temperature}℃适宜,无需特殊提醒`
  }
}

// 在调度器中添加case
async function executeToolCall(toolCall: ToolCall): Promise<any> {
  const { name, arguments: argsStr } = toolCall.function
  const args = JSON.parse(argsStr)
  
  switch (name) {
    case 'get_weather':
      return await getWeather(args.city)
    case 'calculate':
      return await calculate(args.expression)
    case 'get_current_time':
      return await getCurrentTime(args.timezone)
    case 'compare_temperature':
      return await compareTemperature(args.temperature, args.threshold)
    default:
      throw new Error(`未知工具: ${name}`)
  }
}

多工具并行调用

当用户问"北京、上海、深圳的天气",AI可能会一次性返回多个 tool_calls

json 复制代码
{
  "tool_calls": [
    { "function": { "name": "get_weather", "arguments": "{\"city\":\"北京\"}" } },
    { "function": { "name": "get_weather", "arguments": "{\"city\":\"上海\"}" } },
    { "function": { "name": "get_weather", "arguments": "{\"city\":\"深圳\"}" } }
  ]
}

并行执行:

typescript 复制代码
// 并行执行所有工具调用
const results = await Promise.all(
  assistantMessage.tool_calls.map(async (toolCall) => {
    const result = await executeToolCall(toolCall)
    return { toolCall, result }
  })
)

// 将结果添加到messages
for (const { toolCall, result } of results) {
  messages.push({
    role: 'tool',
    tool_call_id: toolCall.id,
    content: JSON.stringify(result)
  })
}

调试与优化

常见问题及解决方案

问题 原因 解决方案
AI不调用工具 工具描述不够清晰 优化description,增加使用场景说明
参数传递错误 参数描述不准确 使用enum限制,提供examples
工具结果未被使用 返回格式不符合预期 确保返回的是JSON可序列化对象
无限循环调用 工具结果没有正确传递给AI 检查tool_call_id是否正确匹配
Token超限 工具描述占用过多Token 精简描述,按需传递工具

调试技巧

1. 打印完整的messages数组

typescript 复制代码
function debugMessages(messages: Message[]) {
  console.log('='.repeat(50))
  messages.forEach((msg, i) => {
    console.log(`[${i}] role: ${msg.role}`)
    if (msg.content) console.log(`    content: ${msg.content.slice(0, 100)}`)
    if (msg.tool_calls) console.log(`    tool_calls: ${msg.tool_calls.map(t => t.function.name)}`)
    if (msg.tool_call_id) console.log(`    tool_call_id: ${msg.tool_call_id}`)
  })
  console.log('='.repeat(50))
}

2. 强制调用工具(测试用)

typescript 复制代码
// 设置 tool_choice 为 required 强制调用工具
const response = await axios.post(API_URL, {
  model: 'deepseek-chat',
  messages,
  tools,
  tool_choice: 'required'  // 强制返回tool_calls
})

3. 记录每次调用的Token消耗

typescript 复制代码
console.log(`📊 Token使用: prompt=${usage.prompt_tokens}, completion=${usage.completion_tokens}, total=${usage.total_tokens}`)

Token消耗优化

工具描述会消耗Token,以下是优化策略:

策略 说明 示例
按需传递工具 根据对话场景动态选择工具 天气场景只传天气工具
精简描述 去掉冗余描述 "获取天气" → "获取城市天气"
复用工具 设计通用工具减少数量 一个execute_command替代多个小工具
缓存工具定义 避免重复传递相同的工具 在对话循环中复用tools

进阶:从Function Calling到Agent

Function Calling是Agent的基础

从工具调用到完整Agent的层次等级:

Level 1: 单次工具调用

用户问天气 → AI返回tool_calls → 执行 → 返回结果

Level 2: 多轮工具调用

用户问复杂问题 → AI调用工具A → 分析结果 → 调用工具B → 最终答案

Level 3: Agent(ReAct模式)

循环: 思考(Thought) → 行动(Action) → 观察(Observation) → ... → 直到任务完成

Level 4: 高级Agent

  • 记忆(短期/长期)
  • 规划(任务分解)
  • 自我反思

Agent的核心循环

typescript 复制代码
async function agentLoop(userGoal: string, maxSteps: number = 5) {
  let messages: Message[] = [{ role: 'user', content: userGoal }]
  let step = 0
  
  while (step < maxSteps) {
    step++
    console.log(`\n🔄 Step ${step}`)
    
    const response = await callDeepSeek(messages)
    const assistantMessage = response.choices[0].message
    
    // 没有工具调用,任务完成
    if (!assistantMessage.tool_calls) {
      return assistantMessage.content
    }
    
    // 执行工具
    messages.push(assistantMessage)
    
    for (const toolCall of assistantMessage.tool_calls) {
      const result = await executeToolCall(toolCall)
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify(result)
      })
    }
  }
  
  return "达到最大步数限制"
}

总结与实践建议

核心要点回顾

要点 说明
机制 AI输出tool_calls,开发者执行,结果返回,AI生成答案
Schema设计 命名规范、描述详细、参数精确是准确率的关键
流程管理 需要正确维护messages数组,处理多轮调用
调试技巧 打印messages、强制调用、记录Token消耗

实践建议

  1. 从小工具开始:先实现1-2个简单工具,理解完整流程
  2. 写好描述:工具描述直接决定AI的调用准确率,值得花时间打磨
  3. 记录日志:保存每次调用的messages,便于调试和优化
  4. 处理异常:工具可能失败,需要优雅的错误处理
  5. 考虑安全:涉及文件操作、命令执行等敏感工具时,需要用户确认

结语

对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!

相关推荐
程序员陆业聪2 小时前
上下文工程与提示词工程:拆解 OpenClaw 是如何「喂养」大模型的
前端
wuhen_n2 小时前
异步组件与 Suspense:如何优雅地处理加载状态并优化首屏加载?
前端·javascript·vue.js
万物得其道者成2 小时前
uni-app App 端不支持 SSE?用 renderjs + XHR 流式解析实现稳定输出
前端·javascript·uni-app
恋猫de小郭2 小时前
Flutter 的 build_runner 已经今非昔比,看看 build_runner 2.13 有什么特别?
android·前端·flutter
yuhaiqiang2 小时前
AI 正在偷走大家的独立思考能力……
前端·后端·面试
不会写DN2 小时前
[特殊字符] JS Date 对象8大使用场景
开发语言·前端·javascript
bearpping10 小时前
Nginx 配置:alias 和 root 的区别
前端·javascript·nginx
@大迁世界10 小时前
07.React 中的 createRoot 方法是什么?它具体如何运作?
前端·javascript·react.js·前端框架·ecmascript
January120711 小时前
VBen Admin Select 选择框选中后仍然显示校验错误提示的解决方案
前端·vben