如何给langchainjs添加代理
langchain这个框架是个好东西,本以为又是python的天下,没想到竟然有js版本,不过openai毕竟是国外的嘛,能否配置代理对我们这些渴望高质量服务的国人来说至关重要。
你要是用clash,这个软件有个虚拟网卡模式,开启后,电脑上的所有流量都会走这个虚拟网卡,但是毕竟是国人,老是开虚拟网卡有点不方便。
langchainjs更新很快,老版本可以用以下的方式配置proxy。
1 | const llm = new OpenAI( |
这种方式已经失效了(0.0.198),新版本推荐以下的方式配置代理
1 | const model = new ChatOpenAI({ |
不过就我用的node18.16.0来说,以上方式并不生效,为此,我大概翻了一下langchain的代码,并且找到了原因。
embeddings.ts L258。以我用的embedding api为例子,看一下langchian内部是如何发起网络请求的,await this.client.embeddings.create这一句,这里的this.client是怎么来的,243行,this.client = new OpenAIClient(params),这里的OpenAIClient是openai这个js库导出的,所以langchianjs内部实际上调了openai-node。
openai-node L480 这里的fetch来自this.getRequestClient(),487行,getRequestClient返回的fetch来自this.fetch,184行,this.fetch = overridenFetch ?? fetch,这里的overridenFetch是个实例参数,一般不会传的,所以最终的fetch来自_shims
/index.js 。
1 | /** |
这几行代码其实不复杂,registry里面导出了一堆需要shims的方法或者属性,也包括fetch,这些东西最终会通过那个for循环+Object.defineProperty导出给外部使用,可以通过shims.setShims给这些方法或者属性打补丁。看看auto.getRuntime()的实现。
web-runtime.ts L20 20行这里的fetch赋值找不到定义,说明最终发起网络请求的fetch来自运行这段js的环境。
我们知道fetch这个api是浏览器上用来替代XMLHttpRequest的,node环境想用一直用node-fetch这个库,但是从node18开始也实现了原生的fetch,,所以这就是httpAgent不生效的原因,因为nodejs18内置的fetch根本不支持传递httpAgent参数。它通过以下的方式配置代理。
1 | import { ProxyAgent } from 'undici' |
很明显,这个dispatcher选项langchainjs没有给我们提供,那怎么办呢,我们可以通过刚才的overridenFetch覆盖掉默认的fetch检测,而这个参数langchainjs提供了。
embeddings.ts 这里的configuration类型是ClientOptions,而ClientOptions来自openai-node,fetch option 这里的fetch就是上面说的overridenFetch,可以给这个参数赋值node-fetch,然后httpAgent参数就起作用了。所以最终的代码:
1 | import fetch from 'node-fetch' |
