ai学习笔记(十六)
这次分享一下对话与推荐系统、Function Calling、Grep相关知识。
1. 对话系统
核心定义:对话系统是通过自然语言实现人机交互的人工智能系统,旨在模拟人类对话能力。
1.1 常见对话系统
对话系统主要分为任务导向型、开放域闲聊型、混合型三种类别。
a. 任务导向型对话系统
-
目标: 帮用户解决具体问题、达成特定任务(如:订机票、查天气、预约会议、导航)。
-
特点: 追求高效、精准、短路径。用户希望用最少的对话轮数把事情办成。
-
核心机制: 槽位填充(Slot Filling)。比如订机票,系统必须集齐“出发地”、“目的地”、“出发时间”这几个核心信息(槽位),缺了就得主动追问。
b. 开放域闲聊型对话系统
-
目标: 情感陪伴、娱乐、闲聊(如:小冰、早期的 Siri 闲聊模式)。
-
特点: 追求上下文连贯性、趣味性、共情能力。没有明确的终点,对话轮数越多越好。
-
核心机制: 开放域生成(Open-Domain Generation),更依赖于模型对宏大知识库和人类情感的建模。
c. 混合型对话系统
-
目标: 结合任务导向型系统和闲聊型系统的优势,既能高效完成特定任务,又能进行自然流畅的开放式对话,并实现两种模式间的无缝切换。。
-
特点: 高智商(完成任务)与高情商(情感陪伴、丝滑过渡)有机结合,让机器的表现更像一个真正的“人”。
-
核心机制: 采用多模块架构:任务模块处理结构化请求,对话模块管理开放话题,上下文理解模块确保交互连贯性。使系统响应准确率提升40%以上(对比单一模式系统)。
1.2 任务型对话核心模块
在 LLM(大语言模型)爆发之前,工业界最成熟、架构最清晰的是任务型对话系统。它像一条精密的流水线,由四个核心模块串联而成:
-
自然语言理解 (NLU, Natural Language Understanding)
-
输入: 用户的原始文本(文本或语音转文字)。
-
输出: 结构化的语义表示。它主要干两件事:
-
意图识别 (Intent Detection): 搞清楚用户想干嘛。比如输入“帮我买一张明天去北京的机票”,意图就是
book_flight。 -
槽位填充: 抠出关键信息。比如提取出
date="明天",destination="北京"。
-
-
-
对话状态跟踪 (DST, Dialogue State Tracking)
-
作用: 系统的“短期记忆”。在多轮对话中,用户的信息是陆陆续续给出的,甚至会中途修改。DST 的任务就是把当前轮次的新信息和历史记忆整合起来,维护一个最新的“全局状态字典”。
-
-
对话策略选择 (DP, Dialogue Policy)
-
作用: 系统的“决策大脑”。基于 DST 提供的当前状态,决定系统下一步该做出什么动作(Action)。
-
决策示例:
-
如果信息不全
执行“追问”动作(“请问您从哪里出发?”)。
-
如果信息齐全
执行“调用外部API/数据库查询”动作。
-
如果查到了结果
执行“向用户展示结果”动作。
-
-
-
自然语言生成 (NLG, Natural Language Generation)
-
作用: 把大脑做出的抽象动作决策,翻译成人类能听懂的自然语言文本。传统上多使用模板(如:
"已为您找到从{NLU.departure}到{NLU.destination}的机票..."),现在更多使用生成式模型。
-
小结: NLU(听懂)
DST(记住)
Policy(决策)
NLG(表达)。这就是经典的 Pipeline(流水线)架构。

1.3 基于LLM的对话系统
大语言模型(如GPT-3/4)通过1750亿参数实现上下文理解,替代了传统基于规则和模块化的NLP处理方式。
核心优势:零样本学习能力使LLM无需领域数据微调即可完成对话任务,相比传统方法节省90%开发周期。
| 特性 | 传统 Pipeline 架构 | LLM Agent 架构(端到端/大模型) |
| 构建复杂度 | 高。需要分别训练 NLU、DST 模块,模块间存在误差传递(NLU 错了,后面全盘皆输)。 | 低。通常一个大模型(End-to-End)直接搞定输入到输出。 |
| 语义理解能力 | 弱。极度依赖人工定义的规则或有限的训练标签,遇到非规范表达容易崩。 | 极强。具备强大的泛化和推理能力,能轻松理解复杂的长句、隐喻和上下文。 |
| 工具调用 (Tool Using) | 刚性。需要工程师硬编码 API 的触发条件和参数绑定。 | 弹性。通过 Function Calling(函数调用) 或 ReAct 框架,大模型能自己判断何时该查数据库、如何拼接参数。 |
| 可控性与确定性 | 极高。行为完全在预设的业务逻辑和模板内,不会胡言乱语。 | 较低。存在**幻觉(Hallucination)**风险,可能会生成看似合理但完全错误的内容。 |
现代 LLM 对话系统的核心:Agent 架构
现在的对话系统不再单纯依靠问答树,而是演变成了 AI Agent(智能体)。它的公式通常是:
Agent=Large Language Model (LLM)+Memory (记忆)+Tools (工具/RAG)+Planning (规划能力)
-
Memory(记忆): 利用向量数据库或特定 Window 机制管理长短期记忆,取代了传统的 DST。
-
Tools(工具): 结合 RAG(检索增强生成) 动态调取外部 PDF 文档、本地知识库或第三方 API,解决大模型的幻觉和时效性问题。
2. 推荐系统
系统定义:推荐系统是信息过滤系统的子集,通过算法预测用户对物品的“偏好“或“评分“,广泛应用于电商、流媒体等领域。
核心任务:是解决信息过载:从海量的商品、视频或文章中,精准挑选出用户当前最感兴趣的极少部分内容,呈现在用户的屏幕上。
2.1 推荐系统的三大经典演进范式
推荐系统的技术发展,本质上是不断挖掘“用户(User)”与“物品(Item)”之间关联的过程。
范式一:基于协同过滤(Collaborative Filtering, CF)——“人以群分,物以类聚”
这是推荐系统最经典的基石算法,分为两种思路:
-
基于用户的协同过滤 (User-CF): 发现和你口味相似的“互联网搭子”。系统发现你和用户 A 都喜欢看科幻片和动作片,最近用户 A 追了一部新出的悬疑片,系统就会把这部悬疑片也推荐给你。
-
基于物品的协同过滤 (Item-CF): 发现物品之间的绑定关系。系统发现喜欢看《星际穿越》的人,通常也极大概率会看《盗梦空间》,如果你刚刚看了前者,系统就会无脑推送后者(电商的“经常一起购买”也是这个原理)。
范式二:基于内容/特征的推荐(Content-Based / Deep Learning)——“打标签”
协同过滤有个致命缺点:如果是一个全新上架的商品,没有任何人买过它,它就永远无法被推荐(冷启动问题)。 于是系统开始拆解物品和用户的特征:
-
物品特征: 这是一部“动作、硬汉、科幻、2026年上映”的电影。
-
用户特征: 这是一个“男性、25岁、程序员、喜欢吴京”的用户。
-
深度学习时代(如经典的 Wide & Deep、DeepFM 模型),算法把成百上千个这样的特征组合起来,丢进神经网络,预测用户点击这个物品的概率(CTR 预估)。
范式三:大模型时代的语义与图推荐(LLM / Graph-based)——“深层理解”
现在的推荐系统开始引入知识图谱(Knowledge Graph)和大语言模型(LLM)。系统不再死板地匹配标签,而是能理解:因为你喜欢“赛博朋克”,所以不仅会喜欢《赛博朋克2077》游戏,还可能对科幻小说《仿生人会梦见电子羊吗?》感兴趣。
3. Function Calling
核心:它是大模型厂商(如 OpenAI、Anthropic、Google 等)在底层对模型进行专门的微调(Fine-tuning),让模型建立了一种强烈的意识——“当用户提问超出我的能力时,我不应该瞎编,而是应该输出一套极其标准、严谨的 JSON 格式参数,交给后台代码去执行。”
有了 Function Calling,大模型不仅能陪你聊天,还能在需要的时候,自己决定去调用外部的代码、API 或数据库,获取真实数据或执行具体任务。
3.1 流程闭环
Function Calling 并不是大模型“自己去运行代码”,它是一个大模型与你的后台服务器(代码环境)来回交接的四步闭合回路。
我们用一个“查询特定城市天气”的例子来拆解这个过程:
第一步:定义工具,扔给大模型
作为开发者,你需要先写好一个查询天气的本地函数 get_current_weather(location, unit)。然后,你用 JSON Schema 的格式把这个函数的“说明书”和用户的提问一起打包发给 LLM。
告诉 LLM: “我有这个工具,名字叫
get_current_weather,它需要一个参数叫location。现在用户说:‘帮我看看北京今天热不热?’”
第二步:大模型决策,返回“参数解构”
LLM 读了用户的输入,又看了工具说明书,发现自己算不出北京现在的温度,但工具可以。于是它中止文本生成,不返回聊天普通文本,而是返回一个标准的 JSON 结构:
{
"name": "get_current_weather",
"arguments": "{\"location\": \"Beijing\"}"
}
第三步:本地代码执行工具
你的后台服务器接收到了 LLM 返回的这个 JSON。你的代码解析它,并真正跑了一行代码:get_current_weather("Beijing")。 函数向气象局 API 请求,拿到了真实结果:{"temperature": "32°C", "weather": "Sunny"}。
第四步:把结果喂回大模型,生成人话
你把这个真实的天气数据(Context)再次打包发给 LLM。LLM 这下心里有底了,它结合这个真实数据,用自然语言回复用户:
LLM 回复: “北京今天是个大晴天,温度有 32°C 呢,体感还是挺热的,出门记得防晒哦!”
3.2 常见问题与解决方案
难点一:工具太多导致模型“眼花”(工具过载与上下文爆炸)
-
痛点: 比如在一个企业 ERP 系统中,可能有几百个 API(查库存、批假、报销等)。如果你把几百个工具的 JSON Schema 一股脑全塞进 Prompt 里,会导致:1. Token 费用飙升;2. 大模型注意力分散,极容易选错工具或传错参数。
-
工业级解法:工具检索(Retrieval-Augmented Tool Selection) 不直接传所有工具。在最前端架设一个轻量级的向量数据库(向量模型如 bge、text-embedding)。把几百个工具的描述做成向量。用户说话后,先去向量库里检索出最相关的 3~5 个工具,然后动态拼进 Prompt 发给大模型。
难点二:大模型“胡言乱语”(幻觉调用与参数格式错误)
-
痛点: 大模型有时会凭空捏造一个不存在的参数,或者把本来需要传入数字
26的地方传成了字符串"二十六度",导致后台 Python 代码直接抛出KeyError或TypeError崩溃。 -
工业级解法:Pydantic 强校验与结构化输出(Structured Outputs)
在代码中绝对不能直接用
json.loads()裸奔。工业界通常配合Pydantic库。现在主流的大模型接口(如 OpenAI)支持response_format={"type": "json_schema", ...}。在本地接收到数据后,必须通过 Pydantic 模型的ValidationError捕获异常。如果出错,自动写一个 Error Prompt 弹回给大模型让它自纠(“你刚刚传的参数类型不对,请重新生成”),通常 1 次 Self-Correction 就能修复。
难点三:用户话没说全(反向追问机制)
-
痛点: 工具
get_weather(location)要求必须有location字段。但用户只说:“帮我查查天气。”这时候大模型无法调用工具。 -
工业级解法:槽位检查与意图锁死(Slot Filling Loop) 利用大模型强大的理解力,在 System Prompt 中硬性规定:“如果用户没有提供必填参数,你绝对不能调用工具,而必须向用户反向提问,引导其说出缺失的参数。”或者在后台使用有限状态机(FSM)拦截,当大模型未能触发 Tool Call 且缺少必要参数时,由业务代码强制下发追问文本。
4. Grep与RAG
grep 是 Linux 操作系统中一个经典的命令行工具,它的全称是 G_lobal Regular E_xpression P_rint。
-
工作原理: 它像一个拿着放大镜的质检员,从头到尾、逐行扫描你指定的文件。只要某一行文本完全包含你输入的字符串(或符合你写的正则表达式),它就把这一行抓取出来打印到屏幕上。
-
核心特点: * 死板但绝对精准: 它不理解文字的意思。你搜 "apple",它能找到苹果公司的 iPhone,也能找到冰箱里的苹果,但它绝对找不到 "iPhone" 或 "fruit"(除非你明确写了这些词)。
-
速度极快,无需训练: 直接在底层对二进制或文本流进行匹配,不需要高昂的算力,也不需要建索引。
-
| 特性维度 | Grep (传统字面检索) | RAG (AI 语义检索增强) |
| 匹配机制 | 字面匹配 / 正则表达式。必须一模一样(或符合规则模式)。 | 语义匹配(Embedding 向量空间距离)。理解概念、同义词和上下文。 |
| 对模糊问题的处理 | 完全无能为力。输入“心情不好看点啥”,若文档里没有这几个字,就查不到任何东西。 | 游刃有余。能理解“心情不好”代表需要安慰,从而检索出治愈系电影或心理疏导文档。 |
| 输出结果 | 原始文本行。搜到什么就原封不动地吐出哪几行。 | 定制化自然语言。把分散在各个角落的知识融会贯通,直接给出一篇条理清晰的总结回答。 |
| 系统复杂度 | 极低。一个单机命令,几毫秒就能搞定。 | 高。包含文档切片、向量化(Embedding)、向量数据库、大模型推理(LLM)等多个环节。 |
| 数据更新成本 | 零成本。文件改了,重新跑一次 grep 就能拿到最新结果。 |
有成本。文档更新后,需要重新切片并计算向量(Upsert 到向量数据库)。 |
在RAG的混合检索中对于专有名词的检索常常用Grep/BM25技术,精准锁定文档位置。
为什么现在的代码agent都是用Grep去检索?
1. 速度差异:Grep 是毫秒级,向量 RAG 是秒级
在编写代码时,开发者对延迟(Latency)的容忍度极低。AI 助手必须在几百毫秒内给出提示,否则就会打断开发者的思路。
-
如果用向量 RAG: 当你在编辑器里写了一句代码,AI 想要寻找相关上下文。它需要先将你当前的代码片段发送给 Embedding 模型(消耗网络请求时间,约 50-200ms),然后再去向量数据库里进行数学计算(距离检索)。整个过程下来,通常需要几百毫秒甚至几秒。
-
如果用 Grep(如 ripgrep):
ripgrep是用 Rust 编写的,它利用了多线程、内存映射(Mmap)和高级正则表达式引擎。它可以在几毫秒内,直接在本地榨干 CPU,横扫你整个包含几万个文件的本地项目工程。 这种瞬时响应的速度,向量检索在单机环境下根本无法比拟。
2. 核心痛点:代码是“绝对精确”的,语义模糊会引发灾难
这正是 Grep 的“死板”在代码领域变成“神技”的核心原因。代码是一门高度崇拜符号和精确性的语言。
-
专有名词与调用链: 假设你在重构代码,想要找到定义了
userService.getUserById_v2的地方。-
向量 RAG: 它通过语义理解,可能会觉得
userService.fetchUser(id)或者adminService.getUser和你的目标“语义很近”,从而把它们作为上下文捞出来喂给大模型。 -
大模型拿到错误上下文: 就会开始瞎编,生成错误的方法调用。
-
Grep: 字符严格匹配。有就是有,没有就是没有。它能百分之百精准地帮你把所有出现过
getUserById_v2的行和文件找出来。对于重构、跳转定义、查找引用,字面匹配是绝对的刚需。
-
3. 动态代码库的“实时性”要求
你的本地代码库是动态的、随时在变的。你可能刚删了一行函数,又新写了一个类。
-
如果用 RAG,这意味着每一次你敲击键盘修改代码,系统都需要在后台对修改的文件重新切片、重新跑 Embedding、重新更新向量数据库。这种高频的增量更新会消耗大量的本地 CPU 和内存。
-
而 Grep 不需要任何“预训练”或“索引建立”,它是直接读取当前磁盘上的最新文件。你刚改完代码,Grep 下一毫秒就能搜到最新结果。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)