多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

技术碎碎念01

技术碎碎念01 一、多智能体系统1.1 受控多智能体 vs 开放式多智能体开放式的多智能体稳定性太难控制操作不可预期。受控多智能体是一种很好的解决方案虽然会丢失一些灵活性但从企业场景的稳定性来看很值得考虑。先固定再谈论自由自由可以慢慢赋予、一点点摸索一上来全让智能体干就无法控制变量来进行后续的优化。1.2 多智能体通信多智能体的通信可以使用消息队列通过事件发布、接收事件来进行各个智能体的隔离。这样后续添加智能体的时候比较好扩展。1.3 子智能体结果控制受控多智能体的子智能体要进行数据结果的控制。子智能体 A、子智能体 B 的结果都要产出三类结果1. 开始、2. 过程、3. 结束。这样主智能体可以进行横向对比适合需要多维度对比的场景。1.4 多智能体框架CrewAI和DeepAgent都是自主式的多智能体开放性高。二、LangGraph2.1 检查点Checkpoint与 StateSnapshot检查点在用户层面是以StateSnapshot对象存在的底层是 checkpoint。StateSnapshot 有parent_config字段字段内部有thread_id不是线程 id强调的是一种会话的隔离记录不同会话的检查点。跨不跨会话是区分 checkpoint 和 store 很重要的一点。checkpoint_idcheckpoint 的唯一性标识。checkpoint_ns检查点的命名空间可以区分子图或者图。StateSnapshot 中有values字段用来存储当前状态字典的属性及其属性值。2.2 StoreStore 中也有 namespaceStore 的 namespace 是由字符串构成的元组都是用来进行区分的。Store 可以跨会话checkpoint 是针对单个会话而言。两者都可以进行持久化。2.3 节点定义定义节点可以用函数也可以使用对象。使用对象可以在初始化的时候扩展属性。使用对象来定义节点需要重写对象的__call__魔术方法使用对象()来调用。2.4 条件边LangGraph 的条件边组成节点路由函数映射字典可选路由函数返回的值可以是节点的名称没有映射字典的情况下。有映射字典的情况下返回的值会在映射字典中进行映射转换成图中的节点名称。2.5 中断机制中断机制需要提前把数据存放到 checkpoint 中并且要保存thread_id。保存thread_id是为了找到哪个会话进行保存需要先通过thread_id来找到对应的 checkpoint这样才能恢复。恢复的时候使用Command(resume...)传入的值是调用interrupt函数时的返回值。恢复的时候需要重新执行那个节点但是会识别出传入了恢复信息所以不会再次执行interrupt()函数。但是interrupt()的前面部分的代码还是会再次执行尽量保持幂等性这个地方会造成重复操作需要注意。三、记忆管理可以使用 LangGraph 中的Store和checkpoint进行记忆管理。Store 可以跨会话。checkpoint 是针对单个会话而言。较快的获取任务状态可以使用Redis。保留任务执行的状态要让模型在完成任务的过程中知道自己完成了什么还有什么没有完成。四、Agent 工作模式4.1 ReAct 模式ReAct 是思考 → 行动 → 观察的一个循环。问题随着上下文增长会出现上下文漂移的情况。目标、决策会被淹没在很长的文本中注意力会被稀释。会因为当前任务获取的新文本而夺走注意力很容易发生漂移。4.2 Plan and Executor 模式问题怎么保证规划就是对的一开始就错了后面很大概率会导致错误。可以边执行边去查看自己的进度和要完成的目标进行方向的纠正。但纠正的一定是正确的吗还是不确定。五、JSON 约束5.1 JSON Schema使用 JSON Schema 来约束生成 JSON有部分厂商支持。这种 Schema 对于类型、枚举等等进行约束控制模型的幻觉。是目前约束性很好的一种方法。5.2 JSON Mode虽然支持很广但只能保证是个 JSON 格式。对于生成的字段是否正确、是否契合业务等等效果并不好。5.3 提示词约束可以在提示词中举几个 JSON 的 case来强化约束。六、RAG检索增强生成6.1 表格与图片处理对表格和图片进行语义的提取在进行检索的时候进行匹配。表格和图片可以作为一种元数据进行绑定。过程对表格和图片提取语义。语义进行向量化存储到 chunk。表格和图片作为一种元数据在匹配 chunk 的时候查看是否有对应的元数据有的话可以进行展示。图片可以使用MinIO存放然后展示 URL 在前端。表格可以在存放的时候用JSON 格式存放然后放到数据库前后端协商好定义和展示的形式。6.2 知识图谱知识图谱是通过保存实体-关系来打通一些深层关系可以跨越分片。比如一个问题和 A、C 都有关系但语义检索得到 AA 和 C 是一种深层次的关系不好获取使用知识图谱来进行跨分片的查询。知识图谱的维护、成本也是要考量的关键因素。流程获取用户问题提取关键实体。和向量数据库里面的实体数据库进行相似度匹配。获取到相关的实体。根据实体去检索图数据库获取到相关的实体-关系。6.3 文本处理使用正则表达式或者大模型识别电话、姓名、关键信息。对敏感信息进行脱敏。6.4 RAG 评测RAG 评测看四个维度query、检索到的证据、生成的答案、目标答案。指标说明Answer Relevancy答案的相关性看 query 和生成的答案的匹配度生成的答案是否很好地回答了 queryFaithness忠实性看生成的答案是否基于检索到的证据防止大模型幻觉RecallK召回率top-k 返回的相关性文档块的个数 / 总的相关的文档块个数PrecisionK前 K 个位置中相关文档块的个数 / K当前位置Context PrecisionK先计算相关性相关是 1不相关是 0然后和自己的 PrecisionK 相乘最后除以 top-k 中相关的文档总个数Answer Similarity答案的相似度看生成的答案和目标答案的语义相似程度七、Agent 测试对于要上线的 Agent 要进行TTFT首字延迟测试测试性能。测试一组模拟的数据可以让业务人员进行编写输入和目标答案来批量测试效果。八、Skill 体系以前的 skill 是一种经验的提取总结。现在的 skill 有脚本、指导、附件等等慢慢演变成了一种综合的解决方案。可以使用关键词唤醒skill或者对 skill 进行语义提取然后进行语义匹配。九、Python 相关9.1 协程Coroutine协程是一种轻量化的线程但是是被用户所控制的。在 Python 中如果像运行正常函数那样A()运行协程的话是运行不了的因为这只是返回一些协程对象需要创建事件循环放进去。首先要创建事件循环asyncio.run()其实默认是创建的然后create_task()就可以了。但是单纯create_task()是不行的因为没有创建事件循环。出现await就需要把控制权交给事件循环了等到操作系统通知事件循环它的 IO 完成了事件循环会把那个协程设置为就绪等待时机再运行。9.2 asyncio.to_threadasyncio.to_thread是把操作放到一个独立的线程返回一个等待的事件不会阻塞当前事件循环。因为协程很害怕同步阻塞一旦出现同步阻塞整个协程都会停滞因为这个阻塞不会把控制权交给事件循环只能硬等。9.3 闭包闭包是内部函数访问外部函数的变量然后外部函数返回内部函数。这个变量不是全局变量。内部函数的调用会捆绑外部函数的变量使得它不会因为外部函数的结束而销毁可以保持和内部函数一样的生命周期。9.4 字典的 setdefaultsetdefault返回 key 所对应的值。如果没有 key设置 key 为默认值返回默认值。9.5 lru_cachelru_cache会丢弃掉最近最少被使用的对象。可以使用max_size来控制缓存的最大个数。保存的是参数 → 返回值的映射。9.6 ContextVar不同线程之间可以使用 thread 来进行区分。同一线程的协程可以使用ContextVar来区分。不同的协程之间 ContextVar 是相互隔离的可以用来保存请求 id。十、FastAPI10.1 Lifespanlifespan中使用contextmanager。yield之前是应用启动之前做的。yield之后是结束之后做的。finally一般来进行最后资源的释放。yield是进入应用中执行。contextmanager def A(): ... yield 1 ... ​ with A() as num: ...contextmanager配合with使用with中的as是yield的返回值。执行顺序先执行 A() 内部代码到 yield → 进入 with 代码内部 → 执行完 with 内部代码 → 再执行 A() 中 yield 后面的部分。10.2 中间件Middlewaremiddleware 代码执行前的执行动作 call_next() 代码执行后的执行动作中间件是每次的请求都会执行一次。lifespan是在应用启动的时候执行一次初始化结束的时候进行一次清洗。10.3 异步路由FastAPI 对于不加async的路由是创建新的线程。对于加async的路由是在主线程中的事件循环中运行。十一、HTTP11.1 Headersheaders { Content-Type: application/json, Authorization: , }Content-Type强调的是请求体的类型是 JSON 格式。十二、数据结构与算法12.1 最大堆每个节点的值都大于等于其子节点的值。12.2 完全二叉树完全二叉树的最后一层后面可以空着但是从左到右必须是没有空隙的。12.3 B 树 vs B 树B 树非叶子节点存储着数据和键值。B 树非叶子节点只存储键值所以可以存放更多的节点树的高度要更低可以减少磁盘 IO。InnoDB 存储引擎使用 B 树叶子节点使用双向链表方便范围查询。B 树的节点的键值超过了阈值进行分裂左侧数据会在原始的节点。中间的键值会向上传递。右侧的键值会放到新创建的节点中。如果父节点阈值也超了就会递归分裂。12.4 LFULFU 是淘汰最近使用频率最低的数据。12.5 K-meansK-means 是一种无监督的聚类算法。有无监督要看你是否有人工标注的数据。K-means 是没有人工参与的情况下进行的一种数据的分类。十三、数据库13.1 主键与索引数据库的主键是一种逻辑的约束物理层面是以主键索引的形式存在。主键索引唯一且非空。唯一索引唯一但是可以为空。13.2 联合索引联合索引是多个字段组合来进行唯一标识一条记录。13.3 最左前缀原则最左前缀原则说的是联合索引从左往右进行依赖匹配。比如ABC的话就可以匹配 A、AB、ABC 这三种索引类型。如果是 AC 的话就会出现中断的问题A 可以匹配C 因为中间缺少 B出现了中断后面就无法使用索引了。13.4 覆盖索引覆盖索引一般是不包括主键索引因为主键索引根本不需要回表它的叶子节点本身就有行数据。覆盖索引一般指的是非主键索引二级索引查询这个索引不需要回表到主键索引进行查询提升查询效率。比如给 name、age 建立联合索引然后根据 name 查询 age联合索引都覆盖了信息这样就不需要回表查询了。13.5 选择性数据库的选择性 不同值的记录 / 总的记录。比如性别男、女选择性很低就不适合作为索引。13.6 索引使用场景返回的数据量过大也不会使用索引。前缀%ABC是无法使用索引的因为前缀是未知的。ABC%可以使用索引这个前缀是确定性的。十四、消息队列14.1 消息堆积生产者生产的过快或者消费者消费的太慢导致消息会堆积在消息队列中。14.2 消息确认机制消费者消费完消息之后通知消息队列它已经消费成功了。以防发生重复消费、丢失等情况。14.3 顺序消费对于消息队列中很看重顺序的情况可以使用单消费者的情况。但是要注意生产者的产生速度不要太快不然还是会发生消息堆积的问题。十五、网络通信15.1 WebSocket vs SSEWebSocket双向通信全双工。SSE一个长连接的单向通信服务器会持续向客户端发送数据但是长连接会比较耗费资源。15.2 通信模式全双工双向通信可以同时传递消息。半双工不能同时传递消息。单工单向传递消息。15.3 SSE 消息格式data: 内容\n\n十六、大模型相关16.1 基础模型 vs Instruct 模型基础模型对文本的无脑续写指令的听从性差。Instruct 模型进行了很多指令的微调去训练模型去听从指令服从性会更好。16.2 LoRALoRA 更新的时候只会更新低秩矩阵 A、B。到最后再和参数矩阵相加。16.3 残差连接残差连接通过X来使得层数变大的时候梯度很小了。直接乘的话会不断接近于 0所以使用X来保持特性。16.4 SFT监督微调SFT 适合学习好的范式回答和行为。因为在训练的时候关注的是 output 的 loss。16.5 RLHFRLHF 会学习人类更喜欢哪种回答。之前会训练一个 Reward Model。Reward Model 是基于 SFT 监督微调的时候生成了很多答案然后人类进行答案的偏好打分最后训练出来的。16.6 DPODPO 的 β 越大会使得 sigmoid 越容易接近上限容易饱和。饱和之后就会平缓loss 越小越学不到东西就会很接近原始的模型。反之亦然一般选择的参数在 0.1。16.7 强化学习State智能体在环境中做动作所需要的全部信息。价值函数未来所有的路线、发生的概率、对应的奖励全部考虑然后最后得出的结果。十七、ClaudeCode 压缩压缩之前要说清楚自己要压缩的目标保留关键的决策。压缩工具输出只保留工具输出的结论。有些工具的调用是为了某项子任务丢弃中间重复的、无用的思考。没有空间的时候是无法进行压缩的因为压缩的结果是大模型基于上下文窗口产生的输入的文本超过了这个窗口大模型是无法接受的。
返回列表