张墨轩的技术宅

不忘初心,方得始终

LangChain简介

大型语言模型(LLMs)作为一项具有变革性的技术正在兴起,使得开发者能够构建之前无法实现的应用程序。LLMs就像人类的大脑,但是光有大脑也没用,还需要身体,手,脚等各个组成部分一起才能构建一个真正强大的应用程序。Python下的LangChain开发框架就是这样一个强大的工具,它通过模块化的设计将各种类型的LLMs(大脑)与其他各种计算组件和知识来源相结合,共同构建出各种实用的应用程序。举个例子,比如通过LangChain开发框架构建一个简单的商品价格查询程序,那么你只需要向程序输入一段人类自然语言:“当前最便宜的XXX产品是多少钱?”,那么LangChain会首先将这段话交给指定的LLM解析,然后LLM可以通过对输入文本的分析自动生成相关的API调用接口参数等,接下来LangChain通过接口参数调用真正的商品查询接口获取结果返回给用户,整个过程中用户全程都是通过人类自然语言与程序进行交互。

从某种意义来讲LLMs就像是C++的编译器,Python的解释器一样:
语言类型
执行原理
C++语言
C++语言 --> 编译器/链接器 --> 既定任务
Java语言
Java语言 --> 编译器/虚拟机 --> 既定任务
Python语言
Python语言 --> 解释器 --> 既定任务
人类自然语言
人类自然语言 --> LLMs --> 各种后端组件 --> 既定任务

LangChain项目当前一直在快速迭代中,目前主要大模块包括以下六大组成部分:
Models, Prompts, Indexes, Memory, Chains, Agents

1.Models
主要包含了LangChain支持的各种各样的LLMs

2.Prompts
外部需要通过Prompt与各种LLMs进行交互, 本部分主要负责Prompt管理、Prompt优化和Prompt格式化输入等,以及LLMs输出内容的格式化管理等

3.Indexes
如果想构建自己的知识库,并且针对自己的知识库构建智能问答机器人,那么就需要本部分的帮助。本部分主要包括各种类型文档的加载,转换,长文本切割分段,文本向量计算,向量索引存储查询等

4.Memory
Memory涉及在用户与LLMs进行交互的整个过程中保持状态的概念。可以简单理解为对聊天消息的管理

5.Chains
Chains是LangChain中最重要的概念,顾名思义其可以将各个组件组合构成一个链条,成为一个完成某个特定任务的应用程序。例如,我们可以创建一个链,它接收用户输入,使用Prompts相关组件格式化输入,然后将格式化后的结果传递给LLM,然后将LLM的输出传递给后端组件或者其他链。我们也可以通过将多个链组合在一起,或将链与其他组件组合来构建更复杂的链。LangChain已经默认为我们实现了很多有用的链,比如用于对文章进行总结的Summarization链,用于对指定文本进行问答的Question Answering/Question Answering with Sources链,用于对指定知识库问答的Retrieval Question Answering/Retrieval Question Answering with Sources链,用于获取并解析网页的LLMRequestsChain链,用于操作关系型数据库的SQLDatabaseChain链等。另外还有一些由第三方实现的链,比如用于从文本提取结构化信息的create_extraction_chain链,其项目地址为:

6.Agents
虽然Chains已经很强大,但是开发者为了让LangChain更灵活更强大还进一步提出了Agents(代理)的概念,每个Agents都具有一套Tools(工具),
通过LLMs的强力加持,Agents可以根据用户输入内容自动决定调用所持有工具集中的与用户意图最匹配的一个工具。工具可以是一个函数,也可以是一个组件,甚至是一个链。

LangChain开发框架项目地址:
帮助文档地址:

python爬虫

Python爬虫的主要目的是在互联网上自动获取、解析、存储和处理大量的数据,以供后续分析和应用。Python爬虫可以对各种网站进行爬取,如搜索引擎、社交媒体、电子商务平台等。它可以自动化地模拟人类在网页上的浏览、点击和输入等操作,并提取所需的信息。Python爬虫在大数据时代中发挥着越来越重要的作用,是数据分析、机器学习、人工智能等领域的重要基础工具之一。
对于不同级别的需求,我们一般会用到不同的工具,这里记录一些常用工具:

1.对于初级需求,比如一些静态页面的抓取,利用python的urllib/requests加BeautifulSoup库就能很好的实现网络抓取静态页面+HTML解析.
其中开源项目BeautifulSoup是一种用于解析HTML和XML文档的Python库。它可以快速地从HTML和XML文件中提取数据,并支持CSS选择器和XPath表达式来定位元素。Beautiful Soup还提供了许多方便的方法,可以帮助你遍历解析树、搜索元素以及修改文档结构等, 项目地址:

2.对于一些中级需求,比如需要操作表单,比如需要进行登录,保持状态等,有一个非常好用的库推荐:MechanicalSoup, MechanicalSoup 是一个用于自动化与网站交互的 Python 库,它内部HTML解析也基于BeautifulSoup实现。它可以自动存储和发送 cookie,跟随重定向,并可以跟随链接和提交表单。简单来说它模拟了一个浏览器,可以用类似浏览器的方式与网页交互,但可惜的是它无法执行页面上的JavaScript代码,其项目地址:

3.对于一些高级的需求,最常见的就是需要获取JavaScript执行后的动态内容,因为很多网站都大量使用JavaScript与各种前端技术和库集成,例如 React、Vue 和 jQuery 等,从而使得网站的功能更加丰富和可扩展,这种情况下网页内容很多都是JavaScript动态与网站后端交互获取数据后进行展示,所以前面讲的各种方法基本都很难凑效,这个时候可以使用Selenium项目。Selenium是一个用于自动化Web浏览器的Python项目,它模拟用户在浏览器中的交互,例如点击、输入和浏览网页等,可以用它自动执行各种任务,例如爬取网站数据和自动化网页操作等。简单来说Selenium可以通过WebDriver控制一个真实的浏览器打开网页,因为是真实的浏览器所以JavaScript也能正常执行,然后可以获取网页内容并且利用其他Python库,如BeautifulSoup处理HTML等,其项目地址:

以上这些都是一些轻量级的爬虫方案,如果想处理大规模复杂任务则建议使用Scrapy,Scrapy 是一个强大的网络爬虫框架,提供了丰富的功能和工具,可以自动化地从网页中提取所需的数据。它基于 Twisted 框架,具有异步、多线程的优势,可以处理大规模的数据抓取任务。Scrapy 使用 Python 的选择器库 Selector 来解析 HTML 和 XML 文档,并提供了多种存储方式,如 JSON、CSV、XML、MySQL 等,方便用户存储和处理数据。其项目地址:

TradestationAPI 授权认证机制

Tradestation API 采用了OAuth2.0认证方式(是目前互联网领域最流行的授权机制,用来给第三方应用授权)

功夫编译系统心得总结

1.yarn工具可以理解为node下npm工具的升级版
2.cross-env,cross-var是node下的一个包(工具),用于解决跨平台环境变量设置问题
3.pipenv是一个python程序 用于建立python虚拟环境(带包管理器),Pipfile包含依赖,Pipfile.lock能有效解决依赖版本问题(注意和anconda中conda create创建的python环境在概念上进行区分和对比)
4.conan(柯南)也是一个python程序,用于C++包管理(配置执行文件:conanfile.py)
5.electron-builder electron程序编译工具,关于electron的简单理解就是把JavaScript,HTML 和 CSS和一个本地浏览器内核(包含v8-js解析引擎)打包到一起,成为一个可执行文件,而其中js代码是用ts代码开发,然后将ts代码通过typescript编译(转换)成js代码,关于typescript请自行百度
6.webpack js打包工具

core部分:
因为我装的anconda是3.8版本的,所以首先利用conda create -n创建了一个py37的环境,然后切换到这个py37的环境下,然后开始进行下面的工作
首先运行yarm 更新所有的node依赖包,然后生成yarn.lock文件,yarn.lock能有效解决依赖版本问题
然后利用pipenv安装python虚拟环境,并在这个环境下把所有需要的包装好
然后利用conan安装所有需要的C++包
然后调用python/build.py进行编译(内部通过cmake-js进行编译) 【2.2版本后改成利用conan通过conanfile.py文件操作
然后利用setup.py打包成wheel包【2.2版本后改成利用conan通过conanfile.py文件操作
然后通过python/build.py freeze打包成可执行文件(内部调用pyinstaller)【2.2版本后改成利用conan通过conanfile.py文件操作

app部分:
首先运行electron-builder install-app-deps安装相应依赖
然后调用.electron-kungfu/build.js和electron-builder进行编译和打包

功夫采用c/c++, python, js/ts/electron, js/node 混合开发,其中js/node和C++之间采用node的N-API机制交互,关于N-API请自行百度node-addon-api/node-gyp等。python与C++之间采用pybind11库进行混合编程, pybind11可实现C++11标准和Python之间的无缝操作,具体请自行百度

这里顺便说下cython机制, cython可以简单理解为开发了一种新的语言,这个语言语法类似python,然后编译的基本流程是首先通过Cython.Build.cythonize将cython代码编译(转换)为C++代码,然后通过setup函数调用本地安装的C++编译器将C++代码编译成二进制模块,然后就可以被python给调用了。开源项目AlgoPlus就采用了cython机制.

当我们用pip安装包(轮子文件)的时候,因为有些包内部采用了比如C++开发,并不一定是纯python,那么如果官方没有提供编译好的版本的话,那么就需要下载相应源码到本机进行实时编译,虽然这个过程是自动进行的,但是因为本地编译环境的原因,常常出错,所以我们一般 最好别用太新的版本的python,比如python3.7比较稳定发布时间也很长了,所以与之对应的包基本都有编译好的版本,出问题的概率相对较小,但如果用较新版本的python,比如3.8版本,甚至3.9版本,它们很多包仓库里面还没有编译好的版本,需要安装的时候本地编译,出错概率大大加大,所以开发建议用py37的版本。

多因子指数增强模型

项目概览:

本项目通过构建多因子模型实现了沪深300指数增强策略,流程包括原始数据获取、因子生成、因子预处理、单因子检验、收益预测模型及风险模型等,具体流程如图:

指数增强模型结构.png


强大的异步架构量化平台(alphahunter)

alphahunter是一个基于Python原生异步库(asyncio)实现的异步事件驱动开源量化策略研究/策略回测/量化交易/高频做市平台,本系统实现数据采集,存储,推送,研究,仿真模拟,线上模拟,实盘等全流程量化研究交易支持,各步骤规则,配置,接口高度统一,异步框架提高系统综合性能。

中低频基础框架如下图所示:

asyncio要点

asyncio是一个异步并发库, 注意是并发, 不是并行. 利用 async/await 组合

`可等待对象`有三种主要类型: coroutine,Task,Future, `可等待对象`实现了__await__方法 (Task派生至Future)

coroutine 协程,实现异步模型的基本单元

Future 主要用于coroutine之间`执行权`的切换, 内部本质用的是yield, await future -> __await__ -> yeild,
这个类很大程度上模仿concurrent.futures.Future

Task将(coroutine,Future)整合到一起, 成为一个task, 然后交给loop去执行. add_done_callback可以
为Task添加完成通知回调

loop是一个任务执行队列循环, 底层用类似select机制, linux上可以用epoll, windows上可以
用wsaeventselect或者`完成端口`来实现`单线程多任务`异步非阻塞IO操作

asyncio.run -> loop.run_until_complete -> loop.run_forever()

下面是并发示例代码:

#==========================================================================
#==========================================================================

async def test1():
    """
    asyncio.sleep内部创建了一个future对象和一个定时运行的回调函数,
    然后await等待这个future对象,这样会交出`执行权`,
    然后等到指定时间回调函数被调用,在回调函数里面
    调用future.set_result函数,这样asyncio.sleep将重新获取`执行权`,并返回.
    代码如下:
    async def sleep(delay, result=None, *, loop=None):
        if delay <= 0:
            await __sleep0()
            return result
        
        if loop is None:
            loop = events.get_event_loop()
        future = loop.create_future()  #创建一个future对象
        h = loop.call_later(delay,
                            futures._set_result_unless_cancelled, #这个回调函数里面会调用future.set_result
                            future, result)
        try:
            return await future #进入等待状态,直到回调函数futures._set_result_unless_cancelled被调用
        finally:
            h.cancel()
    """
    obj = asyncio.sleep(3) #生成`协程对象`,并不是真正执行`协程函数`
    await obj              #真正执行协程函数,并且等待完成
    print("test1 done")

async def test2():
    obj = asyncio.sleep(3)
    await obj
    print("test2 done")

async def main():
    """
    方式一:
    这里是串行执行, 3+3 一共要等待6秒才完成
    """
    obj1 = test1()   #生成`协程对象`,并不是真正执行`协程函数`
    obj2 = test2()   #生成`协程对象`,并不是真正执行`协程函数`
    #obj1.send(None) #协程对象可以这样运行
    await obj1 #真正执行协程函数,并且等待完成
    await obj2 #真正执行协程函数,并且等待完成
    
    """
    方式二:
    这里是并发执行, 一共只需要大约3秒就完成
    """
    obj1 = test1()  #生成`协程对象`,并不是真正执行`协程函数`
    obj2 = test2()  #生成`协程对象`,并不是真正执行`协程函数`
    task1 = asyncio.create_task(obj1)#创建任务对象,并且加入到执行列表里面,Task派生至Future,所以这里可以看成是future对象
    task2 = asyncio.create_task(obj2)#创建任务对象,并且加入到执行列表里面,Task派生至Future,所以这里可以看成是future对象
    """
    因为上面asyncio.create_task把两个协程都排入了执行队列,
    具有并发执行的性质,所以下面虽然从代码看上去是一个接一个在等待,
    但两个任务实际是并发完成的,所以一共只需要大约3秒就完成了
    """
    await task1#其实就是等待一个future对象,task内部执行完协程后,会在这个future对象上调用future.set_result,这样await就会返回,后面的代码继续运行
    await task2#其实就是等待一个future对象,task内部执行完协程后,会在这个future对象上调用future.set_result,这样await就会返回,后面的代码继续运行
    
    """
    方式三:
    这里也是并发执行,一共只需要大约3秒就完成,而且从代码上看更容易理解是并发执行,不会产生歧义.
    
    asyncio.wait内部主要流程是会利用add_done_callback为传入的每个任务添加同一个`任务完成回调通知`函数,
    然后await等待一个future对象,等任务完成后,`任务完成回调通知`函数被调用,这个函数里面有个计数器,
    当计数为0,代表所有任务都完成,然后就会调用future.set_result,这样前面说的await调用就会返回,然后asyncio.wait就会返回
   
    代码如下:
    async def _wait(fs, timeout, return_when, loop):
    
        assert fs, 'Set of Futures is empty.'
        waiter = loop.create_future() #创建一个future对象,后面会用到
        timeout_handle = None
        if timeout is not None:
            timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
        counter = len(fs)
        #下面就是`任务完成回调通知`函数
        def _on_completion(f):
            nonlocal counter #计数器
            counter -= 1 #每完成一个任务计数器减一
            if (counter <= 0 or #计数器为0意味着任务都执行完毕了
                return_when == FIRST_COMPLETED or
                return_when == FIRST_EXCEPTION and (not f.cancelled() and
                                                    f.exception() is not None)):
                if timeout_handle is not None:
                    timeout_handle.cancel()
                if not waiter.done():
                    waiter.set_result(None) #任务都执行完毕,调用set_result,这样后面await waiter代码就会返回,流程得以继续
    
        for f in fs:
            f.add_done_callback(_on_completion) #为每个任务添加`任务完成回调通知`函数
    
        try:
            await waiter #等待之前创建的future对象
        finally:
            if timeout_handle is not None:
                timeout_handle.cancel()
    
        done, pending = set(), set()
        for f in fs:
            f.remove_done_callback(_on_completion)
            if f.done():
                done.add(f)
            else:
                pending.add(f)
        return done, pending
    """
    obj1 = test1()  #生成`协程对象`,并不是真正执行`协程函数`
    obj2 = test2()  #生成`协程对象`,并不是真正执行`协程函数`
    task1 = asyncio.create_task(obj1)#创建任务对象,并且加入到执行列表里面,Task派生至Future,所以这里可以看成是future对象
    task2 = asyncio.create_task(obj2)#创建任务对象,并且加入到执行列表里面,Task派生至Future,所以这里可以看成是future对象
    l = [task1, task2]
    obj = asyncio.wait(l)       #生成`协程对象`,并不是真正执行`协程函数`
    done, pending = await obj   #真正执行协程函数,并且等待完成

asyncio.run(main())

#还可以如下方式调用
#loop = asyncio.get_event_loop()
#loop.run_until_complete(main())

#还可以如下方式调用
#loop = asyncio.get_event_loop()
#t = loop.create_task(main())
#loop.run_until_complete(t)

#还可以如下方式调用,这种方式程序永远不会退出
#loop = asyncio.get_event_loop()
#loop.create_task(main())
#loop.run_forever()

exit()

#==========================================================================
#==========================================================================

若干参考资料:

asyncio源码: Anaconda3/Lib/asyncio/*.py 例如futures.py,tasks.py,coroutines.py,events.py,runners.py等

https://docs.python.org/zh-cn/3/library/asyncio-task.html  《协程与任务》
https://zhuanlan.zhihu.com/p/27258289     《Python Async/Await入门指南》
https://www.cnblogs.com/pigerhan/p/3474217.html 《两种IO模式:Proactor与Reactor模式》
https://www.cnblogs.com/harelion/p/8496360.html 《Python 3.5中async/await的工作机制》

一个不错的数字货币量化交易框架

量化交易系统整体架构:

 

«1»

Powered By Z-Blog 2.2 Prism Build 140101

Copyright phonegap.me Rights Reserved.