- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
导读
本文围绕 TEN Framework 开源仓库中的官方示例包http_server_extension_nodejs(示例包目录),系统讲解如何在对话式 AI Agent 应用中通过 Node.js 编写一个 HTTP 服务器扩展,将外部 HTTP 请求转换为 TEN 框架内的 Cmd 消息并驱动扩展图中的其他节点。读完本文,你将掌握该扩展的安装方式、manifest.json与图配置的写法、server_port参数配置、以及"HTTP 请求 → Cmd → CmdResult → HTTP 响应"的完整调用链,并了解仓库集成测试如何验证这一链路。
一、扩展概览:这个示例包解决什么问题
该扩展是 TEN Framework 的一个软件包组件(extension package),用 Node.js(TypeScript)编写,核心能力是在 TEN 应用内部启动一个 HTTP 服务器,并把收到的 JSON 请求转译成 TEN 的 Cmd 消息下发到图中其他扩展,再把执行结果回写为 HTTP 响应。
在真实应用场景中,这一模式常用于:外部 Web 前端、移动端或第三方服务通过 HTTP 与 TEN 对话应用交互,例如触发"关闭应用""调用某个扩展能力"等操作,而不必直接接触 TEN 的消息协议。
从仓库元信息看(manifest.json):
- 包类型为
extension,名称为http_server_extension_nodejs,当前版本0.11.73; - 标签为
nodejs,运行时依赖ten_runtime_nodejs(版本与主框架保持一致); - 提供多语言展示名与描述(en-US / zh-CN / zh-TW / ja-JP / ko-KR),并声明了多语言 README 的
import_uri。
二、前提条件与安装
2.1 前提条件
- 一个可用的 TEN Framework 运行环境(含
ten_runtime系统包); - Node.js 运行时组件
ten_runtime_nodejs(版本与扩展一致,即0.11.73),用于加载与执行 TypeScript/JavaScript 扩展; - TypeScript 构建工具链(仓库中
package.json使用 TypeScript^5.7.2与@types/node ^22.13.5)。
2.2 安装
该扩展作为标准 TEN 软件包,按TEN Framework 软件包安装指南安装即可(如使用tman或构建系统自动拉取依赖)。其依赖关系已在 manifest.json 中声明:
"dependencies": [ { "type": "system", "name": "ten_runtime_nodejs", "version": "0.11.73" } ]包发布时包含的文件由 BUILD.gn 与manifest.json的package.include共同约束,包括manifest.json、property.json、BUILD.gn、src/**、tsconfig.json、package.json、LICENSE以及docs/**下的多语言文档。
三、扩展的声明与图集成配置
3.1 包声明(manifest.json)
manifest.json是 TEN 包的"身份证",核心字段包括:
| 字段 | 取值/说明 |
|---|---|
type | extension,标识这是一个扩展包 |
name | http_server_extension_nodejs |
version | 0.11.73,与框架版本对齐 |
dependencies | 依赖ten_runtime_nodejs系统包 |
api | 空对象,本示例未额外导出 API |
3.2 在应用图中挂载扩展
扩展只有被挂载进应用(app)的predefined graph才会随应用启动。以仓库集成测试应用 manifest.json 为例,应用声明依赖:
{ "type": "app", "name": "default_app_nodejs", "version": "0.11.73", "dependencies": [ { "type": "system", "name": "ten_runtime", "version": "0.11.73" }, { "type": "system", "name": "ten_runtime_nodejs", "version": "0.11.73" }, { "type": "extension", "name": "http_server_extension_nodejs", "version": "0.11.73" }, { "type": "extension", "name": "simple_echo_cpp", "version": "0.11.73" } ] }对应 property.json 中的图配置:
{ "ten": { "predefined_graphs": [ { "name": "default", "auto_start": true, "graph": { "nodes": [ { "type": "extension", "name": "http_server_extension_nodejs", "addon": "http_server_extension_nodejs", "extension_group": "default_extension_group", "property": { "server_port": 8002 } }, { "type": "extension", "name": "simple_echo_cpp", "addon": "simple_echo_cpp", "extension_group": "default_extension_group" } ], "connections": [ { "extension": "http_server_extension_nodejs", "cmd": [ { "name": "test", "dest": [ { "extension": "simple_echo_cpp" } ] } ] } ] } } ] } }这里的核心点:
addon名称http_server_extension_nodejs必须与扩展内@RegisterAddonAsExtension("http_server_extension_nodejs")的注册名一致;- 通过节点
property中的server_port指定监听端口(此处为 8002),未配置时扩展会回退到默认端口 8001(见下文源码分析); connections定义了http_server_extension_nodejs发出的名为test的 Cmd 路由到simple_echo_cpp,这是"HTTP 请求驱动其他扩展"的关键一步。
四、源码剖析:HTTP 服务器扩展的实现原理
扩展的全部业务逻辑位于 src/index.ts,其结构清晰体现了 TEN Node.js 扩展的标准生命周期。
4.1 类结构与注册机制
import { Addon, RegisterAddonAsExtension, Extension, TenEnv, Cmd, StatusCode, CmdResult, TenError } from "ten-runtime-nodejs"; class HttpServerExtension extends Extension { tenEnv: TenEnv | undefined = undefined; httpServer: http.Server | undefined = undefined; ... } @RegisterAddonAsExtension("http_server_extension_nodejs") class HttpServerExtensionAddon extends Addon { async onCreateInstance(_tenEnv: TenEnv, instanceName: string): Promise<Extension> { return new HttpServerExtension(instanceName); } }- 扩展本体继承
Extension,通过装饰器@RegisterAddonAsExtension("http_server_extension_nodejs")将 addon 与扩展名绑定; onCreateInstance负责按实例名创建扩展实例,这是 TEN 在图中实例化扩展的入口。
4.2 生命周期回调:配置 → 初始化 → 启动 → 停止 → 销毁
| 回调 | 职责 | 实现要点 |
|---|---|---|
onConfigure | 读取/下发配置 | 仅记录日志 |
onInit | 初始化资源 | 保存tenEnv引用 |
onStart | 启动服务 | 读取server_port并创建 HTTP 服务器 |
onStop | 优雅停止 | 关闭 HTTP 服务器并等待回调 |
onDeinit | 释放资源 | 清空tenEnv引用 |
onStart是核心实现(src/index.ts):
async onStart(tenEnv: TenEnv): Promise<void> { tenEnv.logInfo("HttpServerExtension onStart"); const hostname = "127.0.0.1"; let [port, err] = await tenEnv.getPropertyNumber("server_port"); if (err != undefined) { port = 8001; // 默认端口 } const server = http.createServer(this.handler.bind(this)); server.listen(port, () => { tenEnv.logInfo("Server running at http://" + hostname + ":" + port + "/"); }); this.httpServer = server; }注意两点:
- 端口来源:通过
tenEnv.getPropertyNumber("server_port")从图中节点的property读取端口;读取失败时默认8001; - 监听地址:固定绑定
127.0.0.1,即仅本机可访问,符合示例的安全设定。
4.3 请求处理:HTTP → Cmd → CmdResult → HTTP
handler方法定义了完整的请求处理流程(src/index.ts):
第一步:方法与会话类型校验。仅接受POST且Content-Type: application/json的请求,否则静默返回。
第二步:解析 JSON body,并进行三类分支处理:
- JSON 解析失败→ 返回
400与Failed to parse JSON; - 请求不含
ten字段→ 返回400与No \ten` in JSON data`; ten.type == "close_app"→ 创建ten:close_app命令并发送给应用(closeAppCmd.setDests([{ appUri: "" }])),随后返回200 {"message": "OK"},实现通过 HTTP 优雅关闭应用;ten.name存在→ 以该名称创建 Cmd,将原始 body 通过cmd.setPropertyFromJson("", body)注入,并附加method、url两个属性,然后通过this.tenEnv.sendCmd(cmd)下发:
const cmd = Cmd.Create(name); cmd.setPropertyFromJson("", body); cmd.setPropertyString("method", req.method!); cmd.setPropertyString("url", req.url!); this.tenEnv!.sendCmd(cmd).then(([cmdResult, error]) => { if (error) { res.writeHead(500, { "Content-Type": "text/plain" }); res.end("Error: " + error.errorMessage); } else if (cmdResult?.getStatusCode() == StatusCode.OK) { const [detail, err] = cmdResult!.getPropertyToJson("detail"); res.writeHead(200, { "Content-Type": "application/json" }); res.end(detail); } else { res.writeHead(500, { "Content-Type": "text/plain" }); res.end("Internal Server Error"); } });响应契约约定:下游扩展执行成功后,其 CmdResult 的detail属性会被原样作为 HTTP 响应体返回。因此,若要让 HTTP 调用方拿到业务数据,下游扩展应在结果中写入detail。
第三步:ten结构无效→ 返回400与Invalid ten。
由此可归纳出对外 JSON 请求的两种协议格式:
// 1) 调用图中任意扩展能力 { "ten": { "name": "<cmd名称>", ...任意业务字段 } } // 2) 关闭应用 { "ten": { "type": "close_app" } }4.4 编译与运行配置
- package.json:
"main": "./build/index.js","type": "module",通过npm run build(即tsc --listEmittedFiles)把 TypeScript 编译到build/; - tsconfig.json:
target: ES2023、module: NodeNext、开启experimentalDecorators与emitDecoratorMetadata(装饰器语法必需)、strict严格模式,输出到build目录并生成sourceMap。
五、集成测试:如何验证这条调用链
仓库在 tests/ten_runtime/integration/nodejs/http_server_nodejs 提供了完整的集成测试,从测试角度印证了上述行为:
- 测试应用
http_server_nodejs_app将 HTTP 扩展与simple_echo_cpp连成图,并把server_port设为8002; - test_case.py 的核心逻辑:
- 组装并构建应用包(
prepare_and_build_app); - 编译 TypeScript 扩展(
build_nodejs_extensions); - 启动应用(
bin/start),并轮询等待应用在 8002 端口就绪; - 向
http://127.0.0.1:8002/发送请求:
- 组装并构建应用包(
def http_request(): return http.post( "http://127.0.0.1:8002/", { "ten": { "name": "test", }, }, )- 断言响应码不等于 500,验证"HTTP POST → Cmd
test→simple_echo_cpp→ CmdResult → HTTP 响应"整条链路可用; - 结束后通过
stop_app优雅关闭应用并断言退出码为 0。
该测试同时验证了跨语言协作:HTTP 扩展是 Node.js,而目标扩展simple_echo_cpp是 C++,说明 HTTP 网关式扩展可以无缝驱动任意语言实现的扩展节点。
六、快速上手:从零集成到你的 TEN 应用
- 准备应用:在应用
manifest.json的dependencies中加入http_server_extension_nodejs与ten_runtime_nodejs(版本对齐); - 配置图:在应用
property.json的predefined_graphs中挂载该扩展节点,设置server_port(例如 8002),并通过connections把你要暴露的 Cmd 名称路由到目标扩展; - 构建扩展:进入扩展目录执行
npm install与npm run build(tsc编译到build/); - 启动应用:启动 TEN 应用后,扩展会在
http://127.0.0.1:<server_port>/提供 HTTP 服务; - 发起请求:
curl -X POST http://127.0.0.1:8002/ \ -H "Content-Type: application/json" \ -d '{"ten":{"name":"test"}}'七、常见问题与注意事项
- 端口冲突/未生效:确认图中节点的
property.server_port已正确配置;扩展读取失败时默认回退 8001,可能与其他服务冲突; - 请求被静默忽略:仅
POST+application/json会被处理,其他方法与 Content-Type 不会进入处理分支; - 400 响应排查:检查请求体是否含
ten字段、JSON 是否合法、ten内是否有name或type; - 500 响应排查:
sendCmd返回error,或目标扩展返回的CmdResult状态码不是StatusCode.OK,此时可检查图中 Cmd 名称的路由(connections)是否配置正确,以及下游扩展是否在结果中写入detail; - 安全边界:示例固定监听
127.0.0.1,仅本机可访问;生产环境如需对外暴露,应在网络层做好鉴权与安全策略。
八、许可证
本扩展包隶属于 TEN Framework 项目,遵循 Apache License 2.0(见 LICENSE),与框架本身的开源许可保持一致。
- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
相关推荐
LFM2.5-VL-450M社区资源整合指南:Discord、Playground、Colab Notebooks终极使用教程
LFM2.5 VL 450M社区资源整合指南:Discord、Playground、Colab Notebooks终极使用教程 LFM2.5 VL 450M是L
人工智能AI Agent多模态语音AI 应用TEN Framework Go 扩展实战:以 simple_http_server_go 为例完整解析一个 HTTP 服务扩展包
TEN Framework Go 扩展实战:以 simple_http_server_go 为例完整解析一个 HTTP 服务扩展包 本文以 TEN Framew
人工智能AI Agent多模态语音AI 应用TEN Framework 异步 HTTP 服务器 Python 扩展深度解析:基于 aiohttp 的 HTTP/WebSocket 桥接到 TEN 命令的实现指南
TEN Framework 异步 HTTP 服务器 Python 扩展深度解析:基于 aiohttp 的 HTTP/WebSocket 桥接到 TEN 命令的实
人工智能AI Agent多模态语音AI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考