TL;DR
TEN Framework 最初叫 Astra,后改为 TEN,即 Transformative Extensions Network。
我第一次见到 TEN (那时还叫 Astra)是在今年的 6 月份的极客公园 AGI Playground 大会 RTE OpenDay 的活动上。当时展区现场人声嘈杂,但对话效果已经很不错。当时我们在展示用 XSwitch 支持多模态对话,我们已经可以接入各种视频会议系统,以及各种 AI 提供商的 API,但还没有接入 TEN。
XSwitch 是一个多协议的音视频和 AI 连接器(Connector),致力于接入所有音视频和 AI 相关的平台和服务。因此,TEN 也是一个我们需要接入的框架和协议。
TEN 框架写得其实非常好,Docker 容器也很容易跑起来,但在接入过程中,我们还是遇到了一些问题,有些已经解决,有些还在解决中。在踩坑的过程中,也深入理解了这个框架,遇到一些问题,也发现了它的好。
前端的问题及优化
在官方网站上试用的时候,有时候发现前端不响应。点击 Join 按钮没有任何反应。后来发现,服务器可能在国外,首页加载看起来倒很快,但后台可能还在“懒”加载一些 JS 等内容,在加载完成前,Join 按钮是没有反应的,看起来就像是卡住了。
我们做了一些优化并提了一个 PR,在加载过程中显示“Loading ...”,并不允许点击,这样,至少用户可以理解成是页面由于等待网络等原因没有加载完成,而不是个 Bug。
Docker 相关的问题
TEN 是使用 C、Rust 和 Go 混合开发的,因此会用到 Cgo。底层组件有一些没有适配 ARM,因此只有 x86-64 镜像,这对于 Apple Silicon 的用户来说不够友好,不过,按官方文档中的指导,也可以顺利跑起来。
编译却很令人头疼。由于我使用了 OrbStack,TEN 开发人员可能都没有用过,因此在编译时有一个检查没有通过。后来几经探索,找到一个编译脚本,把里面的检查去掉,算是绕过去了。后来反馈到微信群里,TEN 的开发人员也确认了这个问题,现在已经修好了。
编译遇到的问题
TEN 提供了一键编译的脚本,但 TEN 包含了 Python、Go 等多种语言和多种依赖,在编译期间会自动下载一些依赖,有时候下载时间很长,有时候下载失败,再加上那段时间正好碰上国内无法下载 Docker 镜像的问题,总之一键编译并不能一键完成。
这也算是生活在国内程序员的日常了,如果使用这么复杂的系统,就必须具备一定的上网技能。我有一个 socks5 代理,但是有些 Python 环境不支持 socks5,我只好禁用掉代码,在开发镜像中安装了以下内容:
pip install pysocks
pip install httpx[socks]
然后,再开启 HTTPS 代理:
export HTTPS_PROXY=socks5://host.orb.internal:8888
其中,host.orb.internal:8888
是我 socks5 代理的地址。这是在 OrbStack 在 Docker 容器中访问宿主机 IP 的方法。这样,我拿着笔记本满世界乱跑时就不需要每次都修改 IP 地址之类的。
为了让 OpenAI 能用上代理,需要在 .env
中配置以下内容:
OPENAI_PROXY_URL=socks5://host.orb.internal:8888
好在编译脚本基本上是幂等的,多执行几次,总会成功。
Graph Designer 相关问题
TEN 的 Graph Designer 是一个很好的工具,可以用来设计对话流程。但最初的版本功能很弱(现在也不是很强,还是 Beta 版)。Graph Designer 连接到后台一个 property.json
文件,修改了以后刷新页面不生效。需要重启所有 Docker 容器。但我在开发过程中,重启所有 Docker 容器就意味着要重新编译安装很多东西,而这个过程很慢,又不是每次能成功。在微信群里问,开发人员支持很积极,但是没有给出有效的解决方案,直到后来我自己找到了原因。
ten_graph_designer
容器只是个前端,它连接到 astra_agents_dev
里的一个 tman
服务进程上,默认端口是 49483
,由 make run-gd-server
命令启动。因此,只需要重启这个 tman
服务进程就可以了,而不需要重启整个 Docker 容器。
但事情没有那么简单,make run-gd-server
是随着 Docker 容器一起启动的,kill 掉 tman
以后整个容器也会退出!所以,我只好修改了 docker-compose.yml
,增加了一个entrypoint
,让它启动 bash
而不是 tman
。
entrypoint: ["/usr/bin/bash"]
启动 Docker 后,通过docker exec -it astra_agents_dev bash
再进入容器,手工使用 make run-gd-server
启动 tman
服务进程。这样,每次修改 property.json
以后,只需要在容器中重启 tman
服务进程就可以了。
作为一个新手,在 Graph Designer 做了修改并 Save 以后,习惯性地看一看 git diff
。发现 property.json
格式变化很大,无法有效知道到底是改了什么。这个如果能保证一个一致的格式就好了。好像有一个 PR 已经在跟进这个问题了。
其实这个问题也不难发现,只是我前期急于写框架,反正全面重启下又不是不能用。现在看来,“磨刀不误砍柴工”,如果早点搞定这个问题应该能多节约一点时间。
缓存优化
astra_agents_dev
容器在安装各种 Python 或 Go 依赖包时,会有很多缓存到/root/.cache
目录下。在docker-compose.yml
中做一个持久化,映射到宿主机的.cache
目录下,可以加快后续的编译速度。当然,这个要重启容器。
volumes:
- ./:/app
- ./.cache:/root/.cache
编译过程优化
整个编译过程基本都是靠install_deps_and_build.sh
脚本完成的,它会编译所有内容。这个编译非常耗时。目前,我只开发了 Go Extension,没有改 Python,就没有必要每次都检查并下载 Python 的依赖。好在这个脚本写得非常清楚,我只是简单的把 Go 不相关的行全部注释掉了,这样编译速度就快了很多。
echo "install dependencies..."
#tman install
# build extensions and app
echo "build_cxx_extensions..."
#build_cxx_extensions $APP_HOME
echo "build_go_app..."
build_go_app $APP_HOME
echo "install_python_requirements..."
#install_python_requirements $APP_HOME
echo "post installation..."
#post_install $APP_HOME
当然,如果你只是尝试在本地运行 TEN Framework,也没必要像我这样折腾,因为你一般只需要编译一次就好了。而我需要写插件。
写 Hello World 插件
按官方文档用 Go 写了个 Hello World 插件,比较顺利,但也不是一点都不需要改。用 tman
生成代码后,要修改hello_world/default_extension.go
中 init
函数中的内容,有一个字符串要改成hello_world
,否则会提示找不到插件。
// Register addon
ten.RegisterAddonAsExtension(
"hello_world",
ten.NewDefaultExtensionAddon(newDefaultExtension),
)
在使用 tman
生成插件以后,使用 git diff
可以看到有一个 manifest
文件有变化,但是编译完成后,变化又还原了一部分,开发人员说可能是个 Bug,但是我测试了好像也不影响运行。
一点建议
Graph Designer 虽然还是 Beta 版,但功能已经很不错了。不过,也还有一些可改进之处。
首先是它看起来很酷,但我花了很长时间才搞明白它是怎么用的。文档也不是很全,尤其是 flush
根本没有任何解释,只好去啃源代码。
Graph 看起来很酷,表示数据流的虚线也是动的,看起来就像是数据在流动。但是一旦图一复杂,就容易花眼。我感觉这个虚线应使用样条曲线(spline)而不应该使用直线,另外,也可以使用不同的颜色表示不同的数据类型。大家可以对比以下两个图看哪个更容易理解。
后面的图是我使用 Graphviz 生成的,我其实对 Python 并不熟,但有了 ChatGPT,我也会写 Python 代码了,我使用了如下提示词。
write a python script, convert json into graphviz digraph
graph nodes take from nodes
nodes label use html syntax
graph edge take from connections
node has ports like data and text_data, make them in a sub table, in ports at left, out ports and right
an example json follows
... 后面是简化后的 property.json 内容 ...
当然生成的代码直接编译会有错误,我修了一下,并做了很多改进,最后提了一个 PR。
我们还做了什么
我们其实研究了很多。TEN 框架包括前端和后端,在我们还没有搞明白后端的时候,我们就山寨了一个前端,然后把后端接入到了 TEN(当时还叫 Astra)官方的后端上给客户演示,薅了一把 TEN 的流量,直到有一天我们发现被限流。不过我们只是自己测试也没有对外宣传,遇到限流应该就是 TEN 的试用者本身比较多,而不是我们的锅
标签:坑记,插件,Designer,TEN,编译,Graph,Framework,Docker From: https://www.cnblogs.com/dujinfang/p/18444275/the-ten