news 2026/9/23 4:46:33

从倒排索引到AI流式输出:搜索引擎技术栈全链路拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从倒排索引到AI流式输出:搜索引擎技术栈全链路拆解

很多做技术朋友问我,想理解头部搜索引擎到底是怎么工作的,最简单的切入点是什么。我通常会反问一句:你上一次在百度搜索框里敲下关键词、按下回车,到结果页完全呈现,中间到底发生了什么?大部分人会愣一下,然后说"就是一个搜索框嘛"。但如果你沿着这个框往下拆,会发现它背后是一整套由数据管道、倒排索引、Ranking模型、实时检索架构组成的庞大工程系统。这篇文章,我想以一个后端工程师的视角,把这条链路从离线到在线、从索引到排序、从传统检索到AI流式输出,一层一层扒开来讲。

内容主要面向三类人:一是想进入搜索推荐领域的后端或算法工程师,二是正在准备大厂搜索相关岗位面试的同学,三是对技术栈选型、系统设计感兴趣、想给自己项目里塞一个"搜索能力"的独立开发者。我会尽量用"工程实现逻辑"而不是"神奇算法"的角度来讲,毕竟搜索这个领域,真正难的不是某一个模型,而是把几十个模块在毫秒级约束下稳定地串起来。

1. 别把搜索引擎当成一个"框":先拆清它的整体分层

搜索引擎最容易被低估的地方,就是它看起来太简单了。一个输入框、一个按钮、十来个结果链接,好像谁都能做。但你要是在本地电脑上对一个几百万行的文本文件做一次grep,再想想百度索引的是千亿级别的网页,就会明白这完全是两个物种。grep是"从头到尾扫一遍",搜索引擎没这个奢侈,它必须提前把数据加工成某种适合快速查找的结构,这就是"索引"。

所以理解搜索引擎技术栈的第一件事,是建立一个分层心智模型。整个系统可以被粗暴地切成离线和在线两条大线,外加一条贯穿两边的效果评估闭环。

模块离线还是在线要解决的核心问题
网页抓取与内容解析离线为主互联网内容怎么变成结构化文档
索引构建离线为主文档怎么变成可快速查询的倒排结构
Query理解在线用户输入的一句话到底想表达什么
召回在线从海量索引里快速捞出"可能相关"的候选
粗排 / 精排 / 重排在线候选集里谁应该排在最前面
前端渲染与交互在线结果怎么展示、用户怎么进一步交互
日志与评估闭环怎么知道今天比昨天做得更好

这张表建议背下来,因为它基本也是搜索岗位面试时的地图。很多人一上来就聊排序模型多牛、BERT多强,但模型只是精排这一小环节,上游召回不给力,下游排序再强也巧妇难为无米之炊。

提示:搜索引擎的难点从来不是"某个算法不够聪明",而是"每个环节都必须足够快且足够稳"。理解了这句话,后面所有工程细节就都串起来了。

1.1 一个查询请求从输入框到结果页,链路是怎样的

我用一个最简单的例子模拟整条链路:用户输入"北京到上海高铁"。

第一步,Query理解模块会把这句话拆成一个一个词项:"北京"、"上海"、"高铁",同时做纠错、归一化、意图识别。这里机器要判断用户是想查时刻表、票价,还是想看沿途站点,这个判断结果会直接影响后续召回策略。

第二步,系统会把拆好的词项丢给索引层做召回。倒排索引返回的是包含"北京"、"上海"、"高铁"这些词的所有文档ID集合,然后对多个词项的文档集合做交集、并集操作,得到候选文档队列。这一步基本不做什么复杂计算,拼的是数据结构和存储带宽,但它是整个系统的底座。

第三步,候选集进入排序流水线。先经过一个很轻量的粗排模型,把几万候选砍到几百;再进入精排模型,从几百里挑出几十个;之后可能还有重排环节处理多样性、时效性、商业化约束,最终生成用户看到的搜索结果。

第四步,前端拿到结果后渲染页面。用户如果点了某条结果,行为会被记入日志,第二天系统再用这些日志训练新的排序模型。理解这条完整链路,比只盯着某一个模型重要得多。

1.2 各模块的耗时预算:为什么搜索不能慢慢算

搜索场景下,用户对延迟极其敏感。业界常说一个经验值:搜索结果如果超过一两秒才出来,用户会明显感觉"卡了"。所以整个在线系统会被设计成"预算制",每个模块能花多少毫秒,基本是提前定死的。

假设一次搜索的整体目标控制在300毫秒以内,大概是这样的分配逻辑:

环节耗时预算(参考值)说明
网络与接入层30ms前端到后端、网关转发
Query理解20ms分词、纠错、意图识别
多路召回80ms倒排、向量、缓存并行发出去
粗排30ms轻量模型快速过滤
精排80ms复杂模型跑头部候选
聚合与重排20ms规则干预、结果多样性调整
返回与渲染40ms序列化、网络回包、前端绘制

实际生产肯定比这个复杂,不同业务分配也不同,但核心思路一致:每个模块必须在自己预算内完成,超时的模块要么降级、要么跳过,绝不能让用户体验到"无限等待"。这也是为什么搜索引擎里到处是超时控制、熔断、降级的影子。

2. 倒排索引:为什么说它是搜索引擎的"底裤"

如果说搜索引擎有什么数据结构是灵魂级的,那一定是倒排索引。所有关于排序模型的讨论,都建立在"能快速找到候选文档"这个前提上。没有倒排索引,再强的模型也只能面对一个空空的候选集。

2.1 正排表 vs 倒排表,理解为什么搜索要用倒排

为了讲清楚倒排索引,我先搬出另一张表:正排表。正排表的概念和数据库表很像:每一行是一篇文档,列是文档的属性,包括文档ID、标题、正文、URL、发布时间等。如果你想知道"文档3"里包含哪些词,正排表一次就能查到。但搜索引擎的查询往往是反过来的:用户输入一个词,我们要知道"这个词出现在哪些文档里"。这个问题在正排表上会变成一次全表扫描,海量数据下完全不可行。

倒排表就是把这张表翻过来:以词项为主键,每个词项对应一个"包含该词的文档ID列表"。

词项倒排列表(文档ID列表)
北京[1, 4, 889, 1024, ...]
上海[1, 55, 887, 1024, ...]
高铁[4, 887, 1024, 5678, ...]

当用户搜"北京 高铁"时,系统只需要取出"北京"和"高铁"两个倒排链,求个交集,就能快速得到候选文档。正是这个"以词查文档"的反向结构,让海量文本检索成为可能。

如果用代码实现一个最简版本,可以这样理解:

from collections import defaultdict # 原始文档集 docs = { 1: "北京到上海的高铁票", 2: "上海迪士尼游玩攻略", 3: "高铁动卧体验报告", } # 构建倒排索引(简化版,未做分词细节处理) inverted_index = defaultdict(set) for doc_id, text in docs.items(): terms = text.replace("的", " ").replace("了", " ").split() for term in terms: inverted_index[term].add(doc_id) # 查询:包含"上海"的文档 print(inverted_index["上海"])

真实搜索引擎里的分词、去停用词、词权重计算肯定要复杂得多,但这个骨架就是倒排索引的精髓:提前把"词到文档"的映射关系算好,查询时只做集合操作。

2.2 倒排链的存储压缩与快速求交

倒排索引听起来简单,但在千亿文档的规模下,一个高频词的倒排链可能有上亿个文档ID,如果每条ID都用一个int32甚至int64存,存储成本会爆炸。所以工程上会有大量压缩手段。

最常见的做法是差分编码。文档ID一般不存绝对值,而是存"和前一个ID的差值"。比如ID序列[1000, 1001, 1005, 1030],差分为[1000, 1, 4, 25],这些差值往往很小,可以用更少的比特位存储。再配合变长编码,小数值占一个字节,大数值占多个字节,整体压缩率非常可观。

另一个常用手段是跳表。倒排链是有序数组,求两个词项的文档交集时,可以用双指针或者带跳跃指针的技术快速跳过不匹配的区间,避免完全遍历长链。更高阶的方案还有位图(Bitmap)、Roaring Bitmap 等。说实话,这块在面试里问得很细,因为它是搜索引擎最"抠"性能的地方。

2.3 索引更新的工程难题:全量、增量、近实时

倒排索引不是建一次就完事的,互联网内容天天在变:新闻页下线、论坛帖子更新、新网页不断产生。如果每次变化都重建一份全量索引,成本不可接受。

业界常规方案是"全量+增量"结合:定期用离线任务重建一份全量索引,比如每天或每几小时一次;同时在线内存里维护一份增量索引,新内容先写入增量索引,查询时把全量索引和增量索引的结果合并。当增量索引变得很大时,再把它合并进全量索引。

这里有个很经典的工程概念叫"段"(Segment)。很多开源搜索引擎比如 Lucene,就是把索引拆成很多小段,新文档写进新段,后台定期把小段合并成大段,删除文档时只打标记不物理清理。头部搜索引擎的工程实现虽然不会完全照搬,但核心思路殊途同归:用空间换时间,用最终一致性换取可用性。

注意:搜索引库里没有绝对"实时"这个概念,更多是"近实时"。你发的帖子能在几秒到几分钟内被搜到,这才是常态。

3. Ranking模型演进:从BM25到LTR再到深度语义排序

索引解决的是"有哪些候选",Ranking模型解决的是"谁排前面"。这一块是搜索技术栈里迭代最快、最热闹的地方,也是最容易被外行误解的地方。

3.1 召回和排序为什么必须分开:先求全,再求准

很多初学者会问,为什么不能直接让一个超强模型把所有文档都算一遍分数?答案是算力不允许。

假设索引里有10亿篇文档,用户搜"北京到上海高铁",理论上包含"北京""上海""高铁"三个词的文档可能有几十万篇。如果精排模型在每篇文档上都跑一次深度神经网络,按每篇几毫秒算,一次搜索要跑几百秒,这是完全不可接受的。

所以系统必须把过程拆成两步:第一步召回,用非常廉价的算法,从海量文档里快速挑出"看起来有点相关"的几千篇或几万篇;第二步排序,只对这几万篇里进一步算更精细的分数。这就是漏斗模型。

阶段候选规模模型复杂度单请求耗时
倒排/向量召回万级低(词匹配/向量近似)几十毫秒
粗排千级低到中(轻量树模型)几十毫秒
精排百级高(深度模型)几十到上百毫秒
重排十级中(业务规则/小模型)十几毫秒

这个漏斗结构是所有现代搜索引擎的骨架。你去看任何一家大厂的搜索架构分享,基本逃不出这个模式。

3.2 从BM25到LTR:排序模型为什么不能只看词频

经典的排序模型是BM25,它本质上是一个"词频-逆文档频"的打分公式。核心思想很直观:一个词在文档里出现得越多,文档和查询越相关;但如果这个词在几乎所有文档里都出现,那它对区分相关性的贡献就很小。比如"的"字到处都是,单独出现说明不了什么。

BM25公式里有几个可调参数,控制词频饱和度和文档长度归一化,这里不展开推导。它的优点是计算极快、无需训练、可解释性强,所以至今仍是很多搜索系统的底线策略,也是粗排阶段的常见选择。

但它解决不了语义问题。用户搜"苹果",可能想买手机,也可能想买水果;搜"怎么退票",和"退款流程"是同一个意思,但字面完全不一样。BM25面对这种情况会力不从心。

于是有了学习排序(Learning to Rank,LTR)。做法是收集大量训练样本,样本包含查询、文档、特征和标注(用户点击、人工标注),然后训练一个模型去预测"这个文档和这个查询有多相关"。模型可以是GBDT、LambdaMART,也可以是深度神经网络。LTR的关键不是模型多复杂,而是特征和训练目标怎么设计,这是真正的壁垒。

3.3 精排模型的服务化:特征、模型、算力之间的倒三角

精排模型就算再强,也必须被塞进几十毫秒的预算里。所以工程上要做很多事:

第一,特征平台。排序特征可能有上千维,包括文本相关性特征、文档质量特征、历史点击特征、时效性特征、个性化特征。这些特征一部分离线算好存起来,一部分在线实时计算,两者要能无缝拼接。

第二,模型推理加速。深度模型在CPU上跑慢,GPU上跑快,但GPU资源贵。所以工程上会做模型裁剪、量化、蒸馏,还会把多个请求的样本拼成一个batch并行推理,尽量提高吞吐。

第三,降级策略。精排模型服务如果超时或者抽风,系统必须能"退回"到粗排结果甚至BM25结果,不能让用户看到白屏。这种"上游强依赖、下游可降级"的设计,是搜索架构里最常见的容灾哲学。

4. 实时检索架构:从Query分析到结果聚合的超时预算

前面讲的是离线加工和模型逻辑,这一章回到实时链路上。一次真实搜索请求打过来,后端不是"单线程跑一个函数"那么浪漫,更像是一个分布式调度系统在毫秒级内完成一次多路并发查询。

4.1 一次检索请求内部为什么是"并行多路召回"

倒排召回是核心,但不是唯一召回通道。现代搜索引擎还会同时发起其他召回策略:

  • 倒排召回:严格按词项匹配拿候选。
  • 向量召回:把query和文档都embedding成向量,用近似最近邻检索找语义相似的文档。
  • 热点召回:从缓存里直接捞高热内容。
  • 时效召回:专门召回最新发布的新闻、帖子。

这些召回通道是并行执行的,这就是经典的fan-out/fan-in架构。协调节点把请求同时发给多个检索分片和召回通道,每个分片各查各的,然后在协调节点汇总去重。

为什么要并行而不是串行?因为串行会把整个链路的时延加在一起,而并行链路的耗时基本等于最慢的那个通道。只要预算控制得好,多路召回增加的延迟很小,但召回率和效果提升明显。

4.2 超时预算:全链路都在卡时间

在线检索架构里,有一个贯穿全局的设计约束:每个环节都必须有超时时间,没有超时时间的模块是危险的。为什么?因为只要有一个下游服务变慢,调用它的人会一直等,线程池会被占满,最终引起雪崩。

我见过不少团队,一开始只是图省事,给下游调用设置一个"足够大"的超时时间,结果线上一个小抖动就把整条链路拖死。搜索引擎在这种事情上的处理方式非常凶悍:宁可结果不完美,也不能让用户无限期等下去。

场景处理方式
向量召回超时等它到超时点,用倒排结果顶替
精排服务超时直接返回上一级粗排结果
Query理解超时用最简单的默认分词结果
某个索引分片超时把它对应的部分结果丢弃,用其他分片结果

搜索系统甚至会做"短超时优先"策略:先给下游一个很小的超时值,比如20ms,如果下游没返回,再给一个宽限时间,比如50ms。这种两阶段超时能在"尽量等结果"和"防止拖死"之间取平衡。说实话,这套超时预算体系,是搜索架构里最值得后端工程师偷师的智慧。

4.3 大模型搜索结果的SSE流式输出与中断(abort)机制

最近两年,搜索引擎里又多了一个新的角色:大模型生成式回答。用户搜一个问题,系统不再只给一堆蓝色链接,而是直接基于搜索结果生成一段答案。这带来了一个全新的工程问题——生成答案不可能几百毫秒内完成,大模型生成一段话可能需要几秒甚至十几秒。

传统HTTP请求是"一次请求,一次完整响应",用户如果等到答案全部生成完才看到第一个字,体验会非常差。所以现在主流方案是SSE(Server-Sent Events)流式输出:服务端把生成的token一块一块推给前端,前端每收到一块就渲染一块,看起来就像AI在一边打字一边回答。

一个典型的实现思路是:前端用fetch发起请求,拿到ReadableStream,在while循环里读取并解析SSE格式的数据。同时创建一个AbortController,把这个signal传给fetch。一旦用户点了某条搜索结果,或者重新输入了一个新问题,前端就立刻调用abort(),断开连接。

const controller = new AbortController(); async function fetchAnswer(query) { const response = await fetch('/api/search/answer', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query }), signal: controller.signal, }); const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { value, done } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); // 解析 SSE 的 data 字段并渲染 renderChunk(parseSSE(chunk)); } } // 用户点击链接或发起新搜索时 function stopStreaming() { controller.abort(); }

服务端收到abort信号后,要主动把这次生成任务取消掉,释放GPU和线程资源,而不是继续傻傻生成完一整段没人看的文字。这套"流式输出+中断取消"的交互逻辑,是搜索与大模型结合后非常重要的技术栈能力。

提示:很多做AI应用的人只关注prompt写得好不好,却忽略了交互层的实时渲染和资源释放。SSE和abort看起来是前端知识,实际上决定了整个AI搜索产品的服务端资源利用率和成本。

5. 从一次失败的搜索体验反推工程指标:可观测性、容灾与效果评估

搜索引擎不是"上线即完事",它更像一个需要持续调优的生命体。而"调优"不能靠感觉,必须靠一整套指标体系和工程设施。

5.1 线上检索质量如何被量化

你可能觉得搜索结果好不好是主观问题,但工程上必须有量化口径。搜索引擎的核心指标大致分两类:延迟类和效果类。

延迟类很好理解:平均耗时、P90/P99耗时、超时率、错误率。效果类稍微复杂一点,比如无结果率(query返回0条结果的比例)、首条点击率、点击位置分布、搜索后跳出率等。还有一个很重要的口径叫"搜索满意度",通常通过用户在结果页上的二次行为来判断:点了就满意、点了又马上返回可能不满意、完全不点也可能不满意。

离线层面会有另一套指标:NDCG、MRR、Recall@K。这些指标在训练和评测模型时用,但它们和线上真实用户满意度并不完全等价。所以大厂普遍的做法是"离线评测+在线实验"双轨并行,离线过不了关的模型不许上线,离线过了关的模型还得去线上小流量试跑。

5.2 服务降级与容灾:搜索不是所有模块都必须活着

搜索系统依赖很多外部组件:索引服务、模型服务、配置中心、缓存。一旦某个组件出问题,怎么办?好的架构会提前设计好降级路线。

故障点降级方案
Query理解服务挂了放弃高级意图识别,直接字面分词
向量召回服务挂了只走倒排召回
精排模型服务超时降级到粗排结果
粗排服务超时直接按BM25分数排序
广告服务异常只出自然结果,不出广告
配置中心不可用使用本地缓存配置

这些降级逻辑不是等到故障发生才临场写的,而是在开发时就要反复演练。Google和百度这种体量的搜索引擎,都有一个专门的方向叫"稳定性",做的事情就是保P99、防雪崩、做容灾切换。多机房部署、流量调度、数据副本,这些基础设施看起来不性gan,但没有它们,一切算法都是空中楼阁。

5.3 A/B实验平台是搜索迭代的"基础设施"

搜索迭代特别频繁,今天优化一个排序特征,明天调整一个召回通道,怎么知道改动到底有没有效?答案是做A/B实验。把线上流量随机分成两组,一组走旧策略,一组走新策略,然后对比指标。

这个机制说起来简单,做起来很难。搜索实验有几个特有的坑:

  • 用户行为不是完全独立的,一个人可能被分到实验组又分到对照组,体验不一致。
  • 实验之间会互相干扰,比如同时改了召回和排序,结果很难归因。
  • 单日指标波动大,需要积累足够样本量和置信度才有意义。

所以大厂一般会建实验平台,支持分层分桶、参数配置快速生效、实验报告自动计算。搜索工程师的日常,很大一部分就是在实验平台上"做实验、看数据、决定是否全量"。

6. 如果你想动手复刻一套"迷你搜索引擎",怎么开始?

讲了这么多架构和模型,如果你不上手写点东西,很容易变成"听懂了但不会做"。我个人建议,任何人想理解搜索技术栈,都应该自己动手捏一个迷你搜索引擎。

6.1 先实现一个最简单的倒排索引与BM25打分

不用做网页爬取,先拿几篇自己手写的文档做实验。构建倒排索引,实现查询,再用BM25打分排序。这个过程能让你把"索引"和"排序"从抽象概念变成手里的代码。

一个很小的Python示例就能跑通流程:

import math from collections import Counter docs = { 1: "北京到上海的高铁票可以提前预订", 2: "上海虹桥站高铁换乘指南", 3: "北京公园门票价格一览", } # 简化分词:按空格和常用停用词切分 def tokenize(text): for w in ["的", "可以", "了"]: text = text.replace(w, " ") return text.split() # 构建倒排索引 inverted = {} doc_terms = {} for doc_id, text in docs.items(): terms = tokenize(text) doc_terms[doc_id] = terms for term in set(terms): inverted.setdefault(term, []).append(doc_id) N = len(docs) def bm25(query, doc_id, k1=1.5, b=0.75): score = 0.0 doc_len = len(doc_terms[doc_id]) avg_len = sum(len(t) for t in doc_terms.values()) / N for term in tokenize(query): df = len(inverted.get(term, [])) idf = math.log((N - df + 0.5) / (df + 0.5) + 1) tf = doc_terms[doc_id].count(term) score += idf * (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * doc_len / avg_len)) return score query = "上海高铁" results = sorted(docs.keys(), key=lambda d: bm25(query, d), reverse=True) print(results) # 输出按BM25分数排序的文档ID列表

真要实现这个,代码框架也就几十行,但要真正理解每个变量的含义、调参会带来什么变化,需要花不少功夫。建议你把停用词表扩展一下、换几篇不同风格的文档、观察排序结果的变化。

6.2 用现成的开源引擎理解工程化:看看Lucene和Elasticsearch

自己手写一遍是打地基,接下来建议去读开源搜索引擎的工程实现。Lucene是Java生态里最经典的倒排索引库,Elasticsearch又是基于Lucene封装出来的分布式搜索系统。它们帮你把"单机索引"和"分布式检索"之间那条鸿沟补上了。

你用Elasticsearch建一个索引、导入几万条数据,再看它的分片(shard)和段(segment)机制,就能理解我前面说的"全量+增量""合并段"是怎么落地的。特别是Elasticsearch的profile API,可以让你看到一次查询在Lucene层面是怎么走的:哪些倒排链被加载、哪些打分被计算、哪些缓存被命中。这些细节比任何PPT都直观。

6.3 再往后走:向量召回、重排策略和评估闭环

当你能熟练用Elasticsearch做关键词检索之后,我建议你去接触一下向量检索。方法也简单:用一个预训练模型把文档转成向量,存到向量数据库里,查询时也把query转成向量,做相似度检索。最后把"倒排结果"和"向量结果"合并,这就是目前主流搜索引擎的双路召回。

你可以试着做这样一个端到端项目:

步骤内容
1准备几百篇本地文档,比如技术博客
2用Python实现倒排索引和BM25,做一个基础检索接口
3用现成embedding模型生成向量,加一路向量召回
4把两路结果合并去重,用一个简单的线性加权做排序
5记录每次查询的返回结果和用户点击,做一个简易指标看板

做完这套,你已经算是一只脚踏进搜索技术栈的门槛了。之后再去看大厂搜索架构文章,会发现每个名词你都能对应到一个明确的组件和问题,不再是一头雾水。

我自己做迷你搜索引擎时最大的感触是:倒排索引、Ranking模型、实时检索架构这些词,单独拎出来都能写一篇论文,但把它们真正串起来的是"时间预算"和"降级意识"。你在搜索引擎里看到的每一次流畅秒开,背后都是无数个"如果这个模块慢了,我就放弃它"的工程妥协。理解了这种妥协,你才算真正理解了搜索的工程实现逻辑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 4:44:42

图像分割实战指南:语义、实例与全景分割从训练到部署

简介:一份覆盖语义分割、实例分割与全景分割的图像分割Python项目,适合计算机视觉与深度学习方向的开发者、学生及科研人员,可直接用于毕设或课程设计参考。压缩包共5个文件,含3个Markdown说明文档、1个Python脚本与1个工程文件&a…

作者头像 李华
网站建设 2026/9/23 4:43:10

CMMI 3.0规范文档编写指南:四层结构、裁剪逻辑与追溯校验

简介:CMMI 3.0 软件工程规范文档面向软件研发管理者、过程改进(EPG)成员及质量与项目管理从业者,用于系统理解能力成熟度模型集成框架,解决组织在过程定义、量化管理与持续优化中缺乏统一参照的问题。资源包共1个文件&…

作者头像 李华
网站建设 2026/9/23 4:43:06

从描述到治理:Agent技能设计的完整实操指南

1. 先搞清楚:Agent的技能到底是什么1.1 技能不是普通函数,差的不是语法做Agent开发有一段时间的人应该都有同感:把一个大模型接上工具,让它能查天气、发邮件、查数据库,这事儿本身不难。真正难的是让模型在合适的场景下…

作者头像 李华