看了看第一篇文章,其实有些内容没有写,这里新开一个(二),继续补充一些内容。
一、知识库构建
知识库是Agent获取模型外部知识的重要途径,比如与公司相关的知识,这些知识通常不会出现在模型的训练数据中,所以需要通过知识库来补充这些知识。一个通用的叫法就是RAG(Retrieval Augmented Generation),即通过检索相关知识,结合模型生成答案。
RAG 不等于 向量检索
正是由于RAG过于模板化,导致很多人误以为RAG就是向量检索。其实RAG的核心是检索相关知识,向量检索只是其中一种方式。而且向量检索也并不适合所有场景。很多人在构建知识库的时候,不假思索直接使用向量检索的流程,将文档切片,生成向量,存入向量数据库,然后通过向量检索获取相关知识。
这套流程确实比较成熟,导致大家成为思维定式,认为所有知识库都应该这样构建。其实并非如此。知识库的构建应该根据实际场景来设计,不能一概而论。
优先考虑关键词检索
其实目前常用的检索方法主要有以下几种:
1. 向量检索
2. 关键词检索
3. 混合检索
4. 图谱检索
对于不同的场景,应该选择合适的检索方法。个人经验,在非用户主动上传大篇幅文档的场景下,统一使用关键词检索,往往效果更好。原因在于:
1. 关键词检索的召回率更高,延迟更低
2. 关键词检索实现也很简单
那向量检索为什么不行?
1.
受限于Embedding模型的能力,向量检索的准确率并不高,尤其是对于一些专业领域的知识,向量检索往往无法准确匹配。
2.
文档切片的粒度难以把握,切片过大,容易导致向量不准确,切片过小,容易导致上下文不完整。
在Claude Code出现之前,几乎所有Code Agent都会对代码库进行向量化处理,然后通过向量检索获取相关代码片段。Claude Code的出现,彻底颠覆了这个思维定式。Claude Code直接使用Grep对代码库进行关键词检索,然后结合模型生成答案。反而效果更好。
关键词检索需要注意的问题
关键词检索虽然简单,但在使用的时候也需要注意一些问题:
1.
文档的处理:由于关键词检索会直接返回匹配的全篇文档,所以文档的分类和处理非常重要。比如对于FAQ文档,建议将每个问答对单独成一篇文档,而不是将所有问答对放在一篇文档中。一篇文档最好是包含一个类别的内容,避免出现文档过大,从而检索到不相关的内容。
2.
query生成:和向量检索一样,关键词检索也需要将用户的输入转换为检索的query。需要让模型Agentic的方式生成query,比如一个复杂的query无法检索到相关内容,那么可以让生成简单的query,然后进行检索,这样可以提高检索的成功率。
如果支持分页查询,那么可以只返回检索到的行数的前后几行内容。总体来说就是和人在使用ctrl+f查找内容的思路类似。首先定位到相关内容行,然后结合上下文进行理解,内容不全时,可以继续翻页查找。
二、MCP协议
MCP(Model Context
Provider)是由Anthropic提出的一个概念,主要解决工具调用没有统一标准的问题。为了跟上Agent的发展,可能很多开发者直接使用MCP协议来构建Agent。但现有MCP协议也存在一些问题,主要有以下几点:
1. 单个MCP
server可能会包含非常多的工具,而Agent通常只会使用其中的一部分工具。造成无用的上下文。比如飞书MCP
server,包含了20多个飞书的API,而你的Agent应用真的会用到这么多API吗?很可能不会。
2. 多个MCP
server可能会包含重复的工具或相似的工具,导致Agent无法区分使用哪个工具。比如对于Mysql有一个run_sql
数据库查询工具,而对于Postgres也有一个run_sql
数据库查询工具,这时会导致工具覆盖。或者Postgres的工具名为execute_sql
,但是两个工具的描述和入参很有可能非常相似,此时也会导致Agent无法区分该使用哪个工具。
会造成上面两种问题的根本原因在于MCP server是他人提供的,而不是自己定义的。对于工具名称和描述无法控制,导致工具的粒度和命名不符合自己的需求。
三、Agent调试—全链路监测
Agent的调试是一个非常重要的环节,尤其是在多工具、多步骤的复杂任务中,调试难度更大。很多人在调试Agent时,往往只关注模型的输出,而忽略了工具调用的过程。其实工具调用的过程同样重要,甚至更重要。
要构建一个成功的Agent,必须要有全链路的监测和日志记录。包括模型的输入输出,工具的调用情况,工具的输入输出等。只有这样,才能够全面了解Agent的运行情况,发现问题并进行优化。
要知道模型的输出为什么不符合预期,就必须知道输入给模型API的messages是什么,包含user
、assistant
、tool_call
的内容。否则就无法定位问题。很多开发者忽视了这一环节。
举个例子,之前讲到的部分人认为多Agent调试困难,那是因为不清楚每个Agent的输入输出是什么,不清楚子Agent和主Agent之间的Context传输是怎样的。其实只要监测到每次调用模型API时的请求,就能定位出问题所在。