Logo

一文读懂 AI 应用常见术语

AI

前言

RAG / Context / Prompt / Function Calling / MCP / Skill / Rules 这些术语是啥呢?

文章旨在抛砖引玉,通过 NodeJS 代码来实践,了解核心 AI 应用的各个术语概念。

1️⃣ RAG(Retrieval-Augmented Generation)

👉 让AI先查资料再回答

  • 📖 解释: 模型不清楚的东西,先去“翻资料库”,再生成答案。

  • RAG = AI + 外挂知识库

    而这个知识库可以是:

    • 📁 本地文件(PDF / Word / Excel)
    • 🌐 网络搜索(理论上 API 直接获取的不算 RAG)
    • 🧾 数据库
    • 🎥 视频 / 音频(转文字或视觉帧提取)
  • 比如 ChatGPT 上传文件之后,再去问答该文件的信息,AI 就会知道根据你上传文件的内容来回答

代码示例

架构流程

用户提问
问题向量化(nomic-embed-text)
余弦相似度检索 vectorStore
拼接 Prompt(问题 + 相关资料)
LLM 生成回答(qwen:7b)
输出答案

项目结构

这里的 data.txt 就是 “资料”

rag-demo/
├── index.js
├── data.txt
├── package.json

向量原理

向量简单说就是:把一段文字转换成一串数字(向量),这样就能用数学方法计算两段文字的"相似度"。

核心代码

问答模型采用本地的 ollama qwen:7b

还需要下载一个向量模型(就是用它换成 AI 可看懂的向量数据)

BASH
  1. 1
ollama pull nomic-embed-text
JS,C
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
  103. 103
  104. 104
  105. 105
  106. 106
  107. 107
  108. 108
  109. 109
  110. 110
  111. 111
  112. 112
  113. 113
  114. 114
  115. 115
  116. 116
  117. 117
  118. 118
  119. 119
  120. 120
  121. 121
  122. 122
  123. 123
  124. 124
  125. 125
  126. 126
  127. 127
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133
  134. 134
  135. 135
  136. 136
  137. 137
  138. 138
  139. 139
  140. 140
  141. 141
  142. 142
  143. 143
  144. 144
  145. 145
  146. 146
  147. 147
  148. 148
import fs from 'fs';

// ⚠️ Node 18+ 自带 fetch
const OLLAMA_URL = 'http://localhost:11434';

// 1️⃣ 读取知识库
const rawText = fs.readFileSync('./data.txt', 'utf-8');
const docs = rawText.split('\n');

// 2️⃣ 获取 embedding(Ollama)
async function getEmbedding(text) {
  const res = await fetch(`${OLLAMA_URL}/api/embeddings`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'nomic-embed-text',
      prompt: text,
    }),
  });

  const data = await res.json();
  if (!data.embedding) {
    throw new Error(`getEmbedding failed: ${JSON.stringify(data)}`);
  }
  return data.embedding;
}

// 3️⃣ 向量库(内存)
const vectorStore = [];

async function init() {
  for (const doc of docs) {
    const embedding = await getEmbedding(doc);
    vectorStore.push({ text: doc, embedding });
  }
}

// 4️⃣ 余弦相似度
function cosineSimilarity(a, b) {
  const dot = a.reduce((sum, val, i) => sum + val * b[i], 0);
  const normA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
  const normB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
  return dot / (normA * normB);
}

// 5️⃣ 检索
async function retrieve(query, topK = 2) {
  const queryEmbedding = await getEmbedding(query);

  const scored = vectorStore.map((item) => ({
    ...item,
    score: cosineSimilarity(queryEmbedding, item.embedding),
  }));

  scored.sort((a, b) => b.score - a.score);

  return scored.slice(0, topK).map((item) => item.text);
}

// 6️⃣ 调用 Ollama 生成回答
async function generate(prompt) {
  const res = await fetch(`${OLLAMA_URL}/api/generate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'qwen2.5:7b',
      prompt,
      stream: false,
    }),
  });

  const data = await res.json();
  return data.response;
}

// 7️⃣ RAG问答
async function ask(question) {
  const context = await retrieve(question);

  const prompt = `
你是一个公司HR,请严格根据以下资料回答问题:

资料:
${context.join('\n')}

问题:
${question}
`;

  const answer = await generate(prompt);

  console.log('📚 命中资料:', context);
  console.log('🤖 AI回答:', answer);
}

// 🚀 运行
(async () => {
  await init();

  console.log('===== 不使用RAG =====');

  const noRag = await generate('公司年假多少天?');
  console.log(noRag);

  console.log('\n===== 使用RAG =====');

  await ask('公司年假多少天?');
})();
ata.response;
}

// 7️⃣ RAG问答
async function ask(question) {
  const context = await retrieve(question);

  const prompt = `
你是一个公司HR,请严格根据以下资料回答问题:

资料:
${context.join("\n")}

问题:
${question}
`;

  const answer = await generate(prompt);

  console.log("📚 命中资料:", context);
  console.log("🤖 AI回答:", answer);
}

// 🚀 运行
(async () => {
  await init();

  console.log("===== 不使用RAG =====");

  const noRag = await generate("公司年假多少天?");
  console.log(noRag);

  console.log("\n===== 使用RAG =====");

  await ask("公司年假多少天?");
})();

通过余弦相似度算法来计算,分数越接近 1,代表两个向量(即两段内容)越相似。

通过调试可以看到 score 分数,和答案匹配度 0.8。

低分的代表无用吗?

这个就涉及到 阈值 这个概念,可以设置“严格模式”来让模型只相信高分的,这个要根据场景不同来调试效果。

加载中...


2️⃣ Context(上下文)

👉 AI当前“记住”的内容

  • 📖 解释: AI 之所以有“记忆”是因为根据的是上下文来回答的,即 “当前发送的信息+之前的问答信息”

    就像人一次只能记住几句话,越多越吃力

  • ⚠️ 关键点:

    • 超出长度(token) = 忘记
    • 顺序很重要

我更改了对内存要求更低的模型 “gemma3:1b”

JS,C
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
// context-demo.js
const OLLAMA_URL = 'http://localhost:11434';

// /api/chat 为多轮对话
async function chat(messages) {
  const res = await fetch(`${OLLAMA_URL}/api/chat`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'gemma3:1b',
      messages: messages, // /api/chat 用 messages 字段
      stream: false,
    }),
  });

  const data = await res.json();
  return data.message?.content; // /api/chat 返回 data.message.content
}

async function noContextDemo() {
  console.log('=== ❌ 无 context ===');

  let res1 = await chat([{ role: 'user', content: '我叫小明' }]);
  console.log('AI:', res1);

  let res2 = await chat([{ role: 'user', content: '我叫什么名字?' }]);
  console.log('AI:', res2);
}

async function withContextDemo() {
  console.log('\n=== ✅ 有 context ===');

  const messages = [];

  // 用户说话
  messages.push({ role: 'user', content: '我叫小明' });

  let res1 = await chat(messages);
  console.log('AI:', res1);

  // 把AI回复也加入上下文
  messages.push({ role: 'assistant', content: res1 });

  // 再问问题
  messages.push({ role: 'user', content: '我叫什么名字?' });

  let res2 = await chat(messages);
  console.log('AI:', res2);
}

//noContextDemo();

withContextDemo();

执行 noContextDemo() 方法,大模型就会表现的“失忆”,因为模型需要你提供给它“上下文”,也就是之前说过的话。

执行 withContextDemo() 方法,其实就是把信息放在数组内,一起提供给大模型。

现在很多 AI 聊天的 APP 都加入了记忆功能,其实就是提取了你和它聊天的关键信息。


3️⃣ Prompt(提示词)

👉 你对AI说的话

  • 📖 解释: 你怎么问,AI就怎么答

    提问方式决定答案质量

  • 开发中常用的提示词工程:

    • 角色设定 (Role):你是谁?
    • 任务描述 (Task):你要做什么?
    • 上下文 (Context):背景信息是什么?
    • 约束条件 (Constraints):有什么限制?
    • 输出格式 (Output Format):你想要什么格式?

这种是早期在文本聊天提供给 AI 的代码的详细背景,这样让其能够更好地理解你要做的事。

像现在的 Cursor、Claude 等 AI 编程工具都会通过 tools 来读取本地的代码,以及提前设置好的 rules(规则),实际上给大模型发送的 prompt 是类似这样:

[SYSTEM INSTRUCTION]
You are an expert coding assistant.
Task: Refactor the selected code block.

[FILE CONTEXT]
Path: src/components/UserList.tsx
Language: TypeScript

[ANALYSIS RESULT] (这是关键!)
- The selected block is inside a React functional component.
- Variable 'users' is of type User[] defined in parent scope.


[CODE TO MODIFY]
(你选中的原始代码)

[USER REQUEST]
把这个循环改成使用 map

4️⃣ Function Calling (函数调用)

👉 AI调用工具返回结果

  • 📖 解释: AI 调用工具的过程,“提供参数 -> 执行逻辑 -> 返回结果”。
  • 比如 ChatGPT 的联网搜索,就是一个工具的调用,爬虫搜索得到最新的信息

在 AI 世界里,模型不能直接执行代码。它只能“说话”。

  • 流程

    1. 描述 (Definition):你先告诉模型:“我有一个叫 calculateTotal 的工具,它需要 pricetax 两个数字参数。”(文本描述)。
    2. 思考 (Reasoning):模型分析用户的这句话:“帮我算一下总价,价格 100,税 0.1”。模型推理出:“用户想要计算,我应该调用 calculateTotal”。
    3. 提议 (Proposal):模型不执行计算,而是返回一段文本(通常是 JSON):{ "name": "calculateTotal", "arguments": { "price": 100, "tax": 0.1 } }。”
    4. 执行 (Execution)你的代码(前端或后端)截获这个返回,识别出这是调用请求,然后真正地去执行 calculateTotal函数。
    5. 反馈 (Feedback):把执行结果(比如 110)再发给模型,模型才继续回答用户:“总价是 110。”
  • 特点

    • 有思考:模型根据上下文决定是否调用、调用哪个。
    • 只动口不动手:模型本身只是个“指挥官”,它发出的调用指令只是一段文本,必须靠外部代码去落实。
    • 黑盒:模型不知道函数内部是怎么实现的,它只知道函数的“说明书”(Schema)。

这让模型拥有了和外界沟通的能力,它可以执行函数、获取API、搜索网页等。

传统 Function Calling 的痛点

在没有 MCP 之前,每个 AI 接入工具都需要写定制代码:

  • OpenAI + GitHub = 定制适配器 A
  • Claude + GitHub = 定制适配器 B
  • Gemini + GitHub = 定制适配器 C

开发者通常会在代码里写死一个巨大的 tools 数组:

JAVA
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
// 传统模式:每次请求都必须把所有工具塞进去
const allTools = [
  { name: "tool_1", description: "...", parameters: {...} },
  { name: "tool_2", description: "...", parameters: {...} },
  // ... 直到 tool_50
  { name: "tool_50", description: "...", parameters: {...} },
];

await chatCompletion({ messages: [...], tools: allTools }); 

结果:哪怕用户只是说“你好”,你也浪费了发送 50 个工具定义的 Token。如果工具定义很多,且用户还多轮对话,这可能瞬间消耗几千甚至上万个 Token。

这就要说到下个概念 MCP


5️⃣ MCP(Model Context Protocol)

👉 让 AI 能“标准化地调用外部工具和数据”

  • 📖 人话解释: MCP 是 “工业标准”,统一相同的标准来调用不同的工具。

MCP = 协议标准 + 官方多语言 SDK (实现基础) + 社区构建的具体 Server/Client (最终实现)。

Function Calling 并非被取代了,而是在其基础上标准化了,简单来说是 MCP 的子集。

架构

TEXT
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
MCP Client(如 Cursor、Claude等)
MCP Protocol(JSON-RPC over stdio/SSE)
MCP Server(提供 Tools、Resources、Prompts)

协议

工具怎么描述(Tool Schema)

告诉 AI 这个工具做啥的

JSON
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
{
  name: 'getBeijingTime',
  description: '获取当前北京时间',
  parameters: {
    type: 'object',
    properties: {},
  },
}

AI 和工具怎么对话(通信格式)

JSON
  1. 1
  2. 2
  3. 3
  4. 4
{
  "tool": "getBeijingTime",
  "arguments": {}
}

实现基础 SDK

MCP 不仅仅有协议标准,比如还提供了 TypeScript SDK 可以直接调用方法来开发,不用重头来写底层代码,就跟 axios 本质上是使用 http 协议发起请求一个道理。

最终实现

分为 Server/Client 端

简单理解就是:Client 端(Claude Desktop、Cusor、Kiro等)和 第三方工具厂商(GitHub、Figma、AWS 等)

Server 端

工具提供方,常见的 MCP Server有:

  • Context7 MCP

    • 功能:获取最新技术文档(解决模型训练数据过时问题)

    • 场景:"React 19的新特性是什么?"——自动获取最新文档

  • GitHub MCP Server(官方维护 ⭐)

    • 功能:仓库管理、文件读写、PR操作、Issue管理、代码搜索

    • 安装方式:

    JSON
    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    {
      "mcpServers": {
        "github": {
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-github"],
          "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"}
        }
      }
    }
    

工具提供方会提供 API 给 AI 来调用

Client 端

  • 读取工具描述
  • 决定是否调用
  • 发请求

MCP 大致流程

通过Client AI 调用 Server 流程

TEXT
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
用户问:"帮我看看 GitHub 用户 octocat 最近在做什么"


AI 模型决定调用 get_user_repos


MCP Client 发送请求到 MCP Server:
{
  "method": "tools/call",
  "params": {
    "name": "get_user_repos",
    "arguments": {
      "username": "octocat",
      "sort": "updated"
    }
  }
}


MCP Server 调用真实 GitHub API


返回简化后的数据给 AI:
[
  {
    "name": "Hello-World",
    "url": "https://github.com/octocat/Hello-World",
    "stars": 2500,
    "language": "JavaScript"
  }
]


AI 生成回答:"octocat 最近更新了 Hello-World 项目,这是一个有 2500 星的项目..."

MCP 的优化机制:分层加载 (Lazy Loading / Dynamic Discovery)

MCP 协议设计了一个三阶段交互流程,允许客户端(如 Cursor)智能地决定何时发送什么信息给模型。

第一阶段:只列出名字 (List Tools)

当客户端连接 MCP Server 时,它首先只请求工具的元数据列表(名称、简要描述),而不获取完整的参数 Schema。

  • MCP 请求: tools/list
  • MCP 返回:
    JSON
    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    [
      { "name": "search_db", "description": "Search the database" },
      { "name": "send_email", "description": "Send an email" },
      ... // 只有名字和一句话描述,非常短!
    ]
    
  • 此时模型看到了什么?
    • 智能客户端策略:客户端(如Cursor)不会立刻把这 50 个名字全部塞进模型的 System Prompt 里。

第二阶段:按需获取详情 (Get Tool Definition)

只有当模型确定可能需要某个特定工具时,客户端才会向 MCP Server 请求该工具的完整定义(包含详细的参数 JSON Schema)。

  • 场景:用户问“帮我查一下数据库里的用户表”。
  • 动作:客户端识别到意图,单独向 MCP Server 请求 tools/get (name: "search_db")。
  • MCP 返回: 当前工具完整的参数 schema。
  • 发送给模型: 此时,客户端才将 search_db 的完整定义放入 Prompt 发送给模型。
  • 节省效果:其他 49 个无关工具的定义根本没有被发送给模型

第三阶段:动态上下文 (Resources)

除了工具,MCP 还有 Resources(资源)。

  • 传统模式:你可能要把整个文档内容读出来塞进 Prompt。
  • MCP 模式:模型只看到资源的 URI(如 file://logs/error.log)。只有当模型说“我想读取这个文件”时,客户端才去读取文件内容并传给模型。这避免了把大量无关数据预加载到上下文中。

6️⃣ Skill(文档)

👉 Skill 通过工作流、工具调用、知识库,告诉 AI 该怎么做

  • 📖 人话解释: 给大模型的“说明书”

比如这个 vercel 官方提供的 skill,可以让 AI 变成真正的“资深Next.js工程师”

https://github.com/vercel-labs/next-skills

技能名称功能描述
next-best-practices应用规则与最佳实践:基于代码检查(lint)结果,自动应用 Next.js 官方推荐的项目结构、命名规范、性能优化等规则。
next-cache-components缓存组件处理:专门处理 Next.js 中缓存相关组件的迁移或使用,例如将旧的 unstable_cache API 迁移到新的 cache API。
next-upgrade版本升级助手:帮助开发者将 Next.js 项目从一个版本升级到另一个版本,处理依赖更新、API 变更和配置迁移等复杂任务。

7️⃣ Rules(文档)

👉 Rules 是指约束、规范 AI 行为

  • 📖 人话解释: 给大模型的“规章手册”

比如开发 Next.js 的时候,代码风格、命名规范、技术栈约束、语言、项目结构等

各个厂家的方式不一样,不过大同小异,个人觉得 kiro 这个做的就不错,可以自动帮你分类生成,只不过它这里叫 Steering。

可以去网上找这种模版,或者直接让 AI 生成合适不同项目使用的 rules

https://cursorhub.org/rules/nextjs

文章作者:eyu
原文链接:https://1piece.cc/posts/common-ai-application-terms
版权声明:本文遵循 CC BY-NC-ND 4.0 协议,版权归 eyu 所有,转载请注明出处