Jina 是一个云原生技术构建的多模态 AI 应用框架。通过 gRPC、HTTP 和 WebSockets 实现服务交互,易于扩展并可快速部署。开发者只需专注于逻辑和算法,无需为底层架构烦心。Jina 支持从本地到 Kubernetes 等高级编排框架的无缝部署,致力于为每位开发者提供先进的云原生技术解决方案,并支持各种深度学习框架和数据类型。
GitHub 链接:http://oss.jina.ai/
文档链接:http://docs.jina.ai/
🆕 新功能
优化动态批处理处理策略 (#6066)
为了改善系统的性能,我们优化了动态批处理的行为,确保不会把超过
preferred_batch_size
的文档发送给 Executor。这样一来,客户端也将能够更快地收到他们的请求的响应,不需要等待其他请求的处理完成。这样有助于降低系统的平均延迟,提高用户体验。向 GatewayStreamer 方法添加
return_type
参数 (#6027)我们在 GatewayStreamer 方法中添加了一个
return_type
参数,用来指定返回结果的类型。在默认情况下,GatewayStreamer 会自动获取 Executor 的输入和输出模式,并动态重建 DocArray 模型,并将输出结果用于在 Gateway 级别上进行类型转换。虽然转换后的结果与 Executor 级别上定义的原始模式几乎相同,但可能会在某些类型检查上遇到错误。为了避免这种情况,现在可以在 GatewayStreamer 中指定
return_type
参数,确切地指定输出结果的类型。Executor 可以处理单个文档 (#5991)
现在我们提供了用于处理单个文档的 Endpoint,也就是说 Executors 现在也可以处理单个 BaseDoc 了,不再仅限于 DocList。
这样一来,我们就更容易地理解和管理 Executor 的逻辑和功能了,不需要考虑批量处理多个文档的复杂性。特别是有些模型在处理单个文档时表现更好,这样就提供了更大的灵活性,开发者能够根据具体需求定制 Executor 的行为。
要实现这一点,
requests
装饰的方法需要接受一个doc
参数,并且使用输入和输出的类型注解:from jina import Executor, requests from docarray import BaseDoc class MyInputDocument(BaseDoc): num: int class MyOutputDocument(BaseDoc): label: str class MyExecutor(Executor): @requests(on='/hello') async def task(self, doc: MyInputDocument, **kwargs) -> MyOutputDocument: return MyOutputDocument(label='even' if doc.num % 2 == 0 else 'odd')
参数可以描述为 Pydantic 模型 (#6001)
Executor 参数可以使用 Pydantic 模型进行描述,而不是简单的 Python 字典,在定义时需要将模型作为类型注释。
这样有几个主要好处:
参数验证和自定义默认值:使用 Pydantic 模型作为参数的定义,可以提供参数的验证和默认值功能。这样就可以轻松地定义参数的默认值,减少了处理缺失或无效参数的繁琐工作。
更清晰的文档和类型提示:Pydantic 提供了强大的类型推断和自动文档生成功能,使得开发者可以快速了解参数的结构、类型以及可能的取值范围,提高代码的可读性和可维护性。
与 HTTP 协议的集成更加友好:在使用 HTTP 协议时,使用 Pydantic 模型作为参数的定义可以生成更具描述性的 OpenAPI 文档。开发者可以更轻松地了解 Executor 提供的接口规范。
更丰富的 OpenAPI (#5992)
当使用 HTTP 协议为 Executor 提供服务时,Executor 的 OpenAPI 描述变得更加丰富和详细了。我们给 Executor 的接口文档提供了更多详细的信息,包括描述、示例和其他相关字段。这些信息可以帮助开发者更准确地了解如何与 Executor 进行交互,并根据需要构建相应的请求。
在单一 Executor Flows 中支持流式传输 (#5988)
现在,流式传输端点还支持 Flow 编排层,并且不再强制使用 Deployment。Flow 编排层可以接受 gRPC 和 HTTP 协议下的流式传输端点。
with Flow(protocol=protocol, port=port, cors=True).add( uses=StreamingExecutor, ): client = Client(port=port, protocol=protocol, asyncio=True) i = 10 async for doc in client.stream_doc( on='/hello', inputs=MyDocument(text='hello world', number=i), return_type=MyDocument, ): print(doc)
使用 gRPC 协议的流式端点 (#5921)
之前,我们为 HTTP 协议添加了 SSE 支持,支持了流式传输文档,现在 gRPC 协议也支持了相同的功能。Jina 服务端可以使用 gRPC 协议依次向客户端流式传输单个文档。这个功能在内部依赖于流式传输的 gRPC 端点。
一个该功能的典型应用场景是在大型语言模型,流式地传输 token。可以查看我们关于如何流式传输 LLM Token 的文档。
from jina import Executor, requests, Deployment from docarray import BaseDoc # 首先定义模式 class MyDocument(BaseDoc): text: str # 然后定义 Executor class MyExecutor(Executor): @requests(on='/hello') async def task(self, doc: MyDocument, **kwargs) -> MyDocument: for i in range(100): yield MyDocument(text=f'hello world {i}') with Deployment( uses=MyExecutor, port=12345, protocol='grpc', # 或 'http' ) as dep: dep.block()
在客户端中,可以使用新的
stream_doc()
方法逐个接收文档:from jina import Client, Document client = Client(port=12345, protocol='grpc', asyncio=True) async for doc in client.stream_doc( on='/hello', inputs=MyDocument(text='hello world'), return_type=MyDocument ): print(doc.text)
🐞 Bug 修复
修复动态批处理的超时问题 (#6071)
修复了使用动态批处理时,因计时器等待前一个批处理而导致的超时问题。
修复不同容器化执行器中相同文档类型的问题 (#6062)
确保了每个模型名称仅提供一个实例,以解决 Flow 内多个 Executor 具有相同模型名称时的问题。
修复拓扑结构模式验证 (#6057)
以前,如果 Flow 中不同 Executor 的端点模型模式不完全匹配,Flow 将无法启动。即使差异很小,小到只是不同的默认值,也会引发此错误。我们优化了 Flow 中的模型模式检查,使其只验证属性类型是否匹配。
修复共识模块内存泄漏 (#6054)
修复了 Golang 中,部分分配的字符串没有被正确释放的问题。
在 Flow 网关中进行文档转换 (#6032)
在 GatewayStreamer 中调整了文档的转换方式,解决了验证和序列化错误。
移除 Sandbox (#6047)
不再支持在 Jina AI Cloud Sandbox 中部署 Executor。
文档属性注释与字段冲突 (#6035)
当在 Flow 中部署 BaseDoc 模型的 Executor 且该模型带有
ClassVar
值属性,由于 Gateway 无法正确创建模式,服务将无法初始化。我们通过在动态创建这些 Pydantic 模型时保护对__fields__
的访问来修复了这个问题。Gateway 流式结果负载均衡 (#6024)
修复了 Gateway 的流失处理方式,确保更及时的数据返回。
深度嵌套模式支持 (#6021)
在使用深度嵌套的模型时,比如上面代码所示的 RootDoc 内含有 Nested1Doc,而 Nested1Doc 又包含 Nested2Doc,在旧版本中,Jina 的 Gateway 在处理这种结构时会出现问题。代码示例如下:
from typing import List, Optional from docarray import BaseDoc, DocList from jina import Executor, Flow, requests class Nested2Doc(BaseDoc): value: str class Nested1Doc(BaseDoc): nested: Nested2Doc class RootDoc(BaseDoc): nested: Optional[Nested1Doc] class NestedSchemaExecutor(Executor): @requests(on='/endpoint') async def endpoint(self, docs: DocList[RootDoc], **kwargs) -> DocList[RootDoc]: rets = DocList[RootDoc]() rets.append( RootDoc( text='hello world', nested=Nested1Doc(nested=Nested2Doc(value='test')) ) ) return rets flow = Flow().add(uses=NestedSchemaExecutor) with flow: res = flow.post( on='/endpoint', inputs=RootDoc(text='hello'), return_type=DocList[RootDoc] )
2023-08-07 02:49:32,529 topology_graph.py[608] WARNING Getting endpoints failed: 'definitions'. Waiting for another trial
错误原因:这是因为内部函数无法正确地将深度嵌套的 JSON 模式转换为 DocArray 模型。
解决方案:在新版本 3.21 及之后,我们改进了深度嵌套模式的模型生成方式,从而修复了此问题。
Endpoints 输入输出缓存模型 (#6005)
解决了在 Flow 中相同文档类型在不同 Endpoints 被用作输入和输出时的问题。
将 127.0.0.1 用作本地 ctrl 地址 (#6004)
为了更好的本地工作体验,编排层现在使用 127.0.0.1 进行健康检查,而不是之前的默认地址 0.0.0.0。
忽略来自 Google 的警告 (#5968)
减少了 pkg_resources 弃用的 API 相关的警告。