新一轮拷打
agent项目中如何提高匹配到正确工具的准确性
- 工具描述优化:确保每个工具都有清晰、准确的描述,包括功能、输入参数和输出结果。描述应尽可能详细,并使用自然语言,以便于理解和匹配。
- 工具分类:将工具按照功能或领域进行分类,这样可以根据用户请求的上下文快速缩小候选工具范围。
- 语义匹配:使用语义相似度计算(如余弦相似度)来匹配用户查询和工具描述。可以利用预训练的语言模型(如BERT、Sentence-BERT)来生成嵌入向量,然后计算相似度。
- 多轮对话:在匹配不确定时,可以设计多轮对话来澄清用户意图,例如通过提问让用户提供更多细节。
- 使用强化学习或在线学习来持续优化;多个模型验证
- 查询query重写:因为用户输入大部分是问题,可以先做语义重写,如重写成陈述句+prompt优化,再进行意图匹配
采用的什么将分布式缓存同步到本地缓存?1.Redis Pub/sub 2.MQ
分布式定时任务广播的原理,啥协议通知到多台机子上?
Redis Pub/sub基于啥协议。。
RPC原理
流程
客户端调用 → 代理层 → 序列化 → 网络传输 → 服务端接收 → 反序列化 → 实际方法调用
- 服务端启动,并监听端口。
- 客户端stub通过动态代理调用服务接口的方法。
- 动态代理将调用信息封装成请求消息,序列化后发送给服务端。
- 服务端stub接收请求,反序列化,通过服务名和方法名找到对应的实现方法,使用反射执行方法。
- 服务端将执行结果序列化后返回给客户端。
- 客户端接收响应,反序列化后得到结果,返回给调用者。
动态代理层(客户端)
方法调用 → JDK动态代理拦截 → 构造Request → 序列化 → 网络发送 → 等待响应
服务暴露层(服务端)
设计思路: 1. 扫描标注了@RpcService的类 2. 将服务注册到本地服务映射表 3. 启动网络服务器监听请求 4. 根据请求调用对应服务方法 工作流程: 接收请求 → 反序列化 → 查找服务 → 反射调用 → 返回结果
网络传输层
传输方案选择: 方案1: 基于Netty的NIO长连接 - 优点:高性能,支持连接复用 - 实现:ChannelPool管理连接,心跳保活 方案2: 基于HTTP的短连接 - 优点:简单,穿透性好 - 实现:RestTemplate或HttpClient
服务注册发现
注册中心选择: - ZooKeeper: 强一致性,可靠性高 - Nacos: 易用性好,功能丰富 - Redis: 性能高,部署简单 注册流程: 1. 服务端启动时向注册中心注册服务 2. 客户端订阅服务变化 3. 注册中心通知客户端服务列表变更
3. 详细工作流程
3.1 服务端启动流程
1. 扫描@RpcService注解,构建服务映射表 2. 启动网络服务器,绑定端口 3. 向注册中心注册服务元数据 - 服务名称: userService - 服务地址: 192.168.1.100:8080 - 服务版本: 1.0.0 - 权重: 100 4. 启动心跳线程,定期上报健康状态 5. 进入请求监听循环
3.2 客户端调用流程
1. 通过动态代理创建服务接口的代理对象 2. 从注册中心获取服务提供者列表 3. 根据负载均衡策略选择服务实例 4. 构造RPC请求对象: - 生成唯一Request ID - 设置服务名、方法名 - 序列化方法参数 5. 通过网络发送请求 6. 同步等待服务端响应(支持超时) 7. 反序列化响应结果,返回给调用方
3.3 服务端处理流程
1. 网络层接收请求字节流 2. 协议解码,验证Magic Number和版本 3. 根据序列化类型反序列化请求体 4. 从服务映射表查找对应的服务实例 5. 通过反射调用目标方法 6. 捕获方法执行结果或异常 7. 构造响应对象并序列化 8. 通过原连接返回响应
还有 容错/限流/熔断/负载均衡措施
序列化指request或response序列化为字节流以便传输
RPC 服务端Provider提供的服务是如何注册的 如何被客户端consumer发现的?
服务注册与发现通常涉及三个角色:服务提供者(Provider)、服务消费者(Consumer)和注册中心(Registry)。
- 服务提供者启动时,将自己的信息(如服务名、IP、端口、协议等)注册到注册中心。
- 服务消费者启动时,从注册中心获取服务提供者的地址列表,并建立连接。
- 当服务提供者发生变更(如上下线)时,注册中心会通知服务消费者。
具体步骤:
一、服务注册(Provider端):
- 服务提供者启动后,会向注册中心注册自己提供的服务。
- 注册信息通常包括:服务接口名、版本号、分组、IP地址、端口、协议等。
- 注册中心会保存这些信息,并建立服务名到提供者地址列表的映射。
二、服务发现(Consumer端):
- 服务消费者启动时,会向注册中心订阅自己所需的服务。
- 注册中心将服务提供者的地址列表返回给消费者。
- 消费者根据负载均衡策略从地址列表中选择一个提供者进行调用。
三、动态感知:
- 注册中心会检测服务提供者的健康状态,如果提供者下线或故障,注册中心会将其从地址列表中移除。
- 注册中心会通知订阅了该服务的消费者,更新本地缓存的服务地址列表。
xxljob
监控机子不可用:
xxl-job由调度器和执行器两部分组成,调度器是xxl-job的大脑,何时触发任务,哪个机器执行任务,这都是调度器去决策的。执行器是打工人,是干具体事的,运行在业务服务器上。
执行器在ExecutorRegistryThread类中启动一个线程,告诉调度器一声“我来了”,不管上报成功与否,都会睡眠30s,睡醒了,要继续告诉调度器一声“我还在”,就这样不断的报备。一旦jvm关闭,执行器告诉调度器一声“我走了”。
调度器在JobRegistryMonitorHelper类中启动一个线程,它会将超过90s没有上报的执行器,从xxl_job_registry表中删除,然后更新xxl_job_group表的address_list字段。
链接:https://juejin.cn/post/7051964061474357285 来源:稀土掘金
故障转移:Admin 维护着一个健康的执行器列表,当需要进行故障转移时,可以从这个列表中选择一个合适的“替补”来接管任务。
确保一个任务不会被重复执行:分布式调度系统引入了分布式锁机制,确保在同一时间只有一个 Admin 节点能够对某个任务进行调度。在 XXL-JOB 中,这个锁是利用数据库的行级锁来实现的。源码:XXL-JOB 的调度线程会定期扫描数据库中需要执行的任务。在每次扫描并处理之前,它会尝试获取一个数据库锁。只有成功获取锁的线程才能继续,否则会跳过本次调度,从而避免重复执行。
在阿里实习,那中间件了解哪个?早知道说MQ了
你知道像Clickhouse他们底层的引擎吗?知道MPP吗
讲讲你理解的MCP
RAG检索出来的不对如何处理
mysql 索引(a,b) sql a>1 and b>1会走哪些索引?索引(a,b) 非叶子节点存的是什么
会部分使用 (a, b) 复合索引,并且对前导列 a 进行索引范围扫描。
- 范围扫描开始:在索引的B+树上,找到第一个满足 a < 1 的条目。
- 顺序遍历与过滤:从这个条目开始,沿着叶子节点的链表向后顺序扫描(这就是“范围扫描”),直到遇到第一个 a >= 1 的记录为止。
- 应用 b 的过滤条件:在步骤2的扫描过程中,对于每一条索引记录,会检查它的 b 字段是否满足 b < 1。
关键点: 步骤3中检查 b 字段的方式,在有了索引下推 优化后,是在存储引擎层直接进行的,而不是把所有 a < 1 的记录都拿到Server层再过滤。这大大减少了需要回表(如果查询需要返回其他不在索引中的列)或向上传递的数据量。
如果有个mysql表里面数据非常不均匀,比如人种,那么黑种人就非常少,造成查询很慢。除了建索引、分表、存缓存还没有其他方法?
索引下推
在没有索引下推的情况下,执行一个查询(比如:使用复合索引(a,b)和条件a<1 AND b<1)的步骤是:
- 存储引擎根据索引(如果使用索引)定位到满足a<1的第一行,然后返回所有满足a<1的索引行(注意:这里只利用索引的a列进行范围扫描,然后返回整个索引行,包括b列)。
- 然后,Server层再根据WHERE条件中的b<1来过滤这些行。
但是,如果使用了索引下推,那么过程就变成了:
- 存储引擎根据索引定位到满足a<1的第一行。
- 然后,存储引擎会检查索引中的b列(因为b列也在索引中)是否满足b<1。如果不满足,则跳过该行,继续下一行;如果满足,则返回该行给Server层。
这样,索引下推将本应在Server层进行的过滤条件(b<1)下推到了存储引擎层,从而减少了存储引擎层需要返回给Server层的行数,提高了查询性能。
索引下推的适用条件
- 只能用于复合索引,因为单列索引不存在“下推”另一列的条件。
- 适用于WHERE条件中包含了索引中的列,但是这些列不能全部被用于索引范围扫描(比如,只有前导列用于范围扫描,后续列用于过滤)。索引列的部分条件无法用于快速定位,但可以在扫描过程中过滤
- 查询需要回表(访问主键索引)时,能显著减少回表次数