本帖想分享我最近开发prismcat的一些想法,之前已经发过一篇帖子进行介绍:【开源自荐】 PrismCat — 无感接入你的api调用流程,获得全量日志
不知道为什么带上github链接后就会进入审核,然后每次审核都无法通过,所以干脆把仓库链接从本帖删了,也不想作为推广发布
回到正题,PrismCat是一个llm api观测工具,虽然代码是ai写的但架构决策是我自己做的,有些决策真的让我很纠结,本文主要就是记录它们并分享一下
起因是我在用各种客户端,中转站(cherry studio,newapi等)及给自己的机器人接入llm时老是遇到很多奇怪的错误,所以我想它们到底是如何构造请求的,我想知道每一个请求到底长什么样,以及现在各种吹的天花乱坠的功能——什么mcp,skill等,到底是如何实现的。我想要一个工具,它最好足够轻,可以接入任何链路,能记录我所有的请求并且不影响原本的运行
以上是prismcat的由来,它的初衷其实是做一个通解
第一个纠结:要不要合并流式响应
LLM的流式响应是一堆SSE事件碎片,每个chunk里只有部分内容,按照我原本的设想肯定就直接展示流式了,因为如果要进行合并,就要知道响应体里的内容,我感觉这会导致它变得不纯粹,不够通解
但经过一段时间的体验后我还是妥协了,流式不是人看的,如果都看不懂还怎么调试?我尽量让ai做成可拓展的,其实最近我还在考虑是否应该把流式合并也改成配置项
第二个纠结:Token统计该不该做
token展示这个需求来自于我自己的机器人请求,有很多请求我确实只想看一眼token消耗,虽然我自己搭建了中转站但实际上平时更多的是使用prismcat了,但我不想做这个功能的原因很简单——真想看token可以直接点开具体的请求然后看详细日志,如果专门展示就意味着我需要去解析响应体,而且token字段在每家provider那里都不一样,如果真的加了这个功能,很可能意味着我要一直去更新它适配它,我讨厌这种感觉
跟ai讨论后我决定采用配置化的方案:用 JSON Pointer(一种标准的路径表达式)让用户自己定义token数据在响应的哪个位置,然后我对主流provider提供默认规则,但它们可以被覆盖
上面的这些纠结我自己也感觉很奇怪,几乎每一个功能的拓展都在让我怀疑我的产品是不是变得更脆弱
我到底在追求什么
我发现我真正想要的可能不是通用,而是一劳永逸。如果上游改变了我的代码也自动跟着改变,那有什么不好的?但问题是不会,所以我才执着于实现通解。
但这个追求如果走到极端,就会变成“什么都不做”,只要做了,就意味着实现了绑定,就会变得脆弱
想通这一点之后,我重新审视了整个项目,发现它其实天然分成了三层:
可以看到,其实把变化控制在配置里,就无需担心写死
prismcat没有过0.x的版本,直接从1.0开始发布,因为一开始我就觉得基础能力已经完善,但这段时间以来功能越加越多,因为我更加信任自己写的东西,我讨厌大部分的sdk还有一些客户端的上下文拼接逻辑,我觉得它们写死了很多东西,我给prismcat加了很多新功能:请求改写、token 提取、链路追踪……功能上它好像重得像一个轻量网关(当然我不会因为任何功能而舍弃性能,这是底线),这是我不愿意看到的,因为社区里的网关项目很多,我不想重复造轮子。但仔细想一下,两者还是有本质区别的:网关回答的是请求该怎么走,我的工具回答的是“请求到底走了什么”
说白了我做的是 LLM 流量的 DevTools。Chrome DevTools也能改请求看性能指标,但没人叫它网关。
总结下学到的点,也算是和自己的妥协:
1、纯粹只是实现稳定的手段之一,配置化是另一种,执着于纯粹会让你什么功能都不敢加
2、变化应该被隔离,而不是被消灭,因为上游接口一定会变,问题不是“怎么让工具不需要变”,而是变的时候,用户能不能自己搞定
3、我花在“要不要做”上的时间,远超“怎么做”,这些纠结不是浪费——它们塑造了工具的边界,而边界才是一个工具最重要的东西
如果你也在做自己的小工具,希望这些弯路能帮你少走一点。
1 个帖子 - 1 位参与者