`typia`(比原驗證器快20000倍)挑戰`@agentica` AI框架及其編譯器能力
typia
凭借其编译器技能向代理型AI发起挑战。
这个新的挑战伴随着一个新的开源框架,@agentica
。
它专门处理大型语言模型功能调用,并通过这种方式完成所有任务。只需列出你想调用的功能,你就可以创建属于自己的代理AI。如果你是TypeScript开发者,你现在也可以成为AI开发者了,就像变魔术一样。让我们一起进入这个新的AI开发时代吧。
@agentica
: 比如 https://wrtnlabs.io/agentica 和typia
: 比如 https://typia.io
import { Agentica } from "@agentica/core";
import { HttpLlm } from "@samchon/openapi";
import typia from "typia";
const agent = new Agentica({
controllers: [
HttpLlm.application({
model: 'chatgpt',
document: await fetch(
"https://shopping-be.wrtn.ai/editor/swagger.json",
).then(r => r.json()),
}),
typia.llm.application<ShoppingCounselor, 'chatgpt'>(),
typia.llm.application<ShoppingPolicy, 'chatgpt'>(),
typia.llm.application<ShoppingSearchRag, 'chatgpt'>(),
],
});
await agent.conversate("我想买一个 MacBook Pro");
全屏,退出全屏
2. 大纲2.1. 变换器库
//----
// src/checkString.ts
//----
import typia, { tags } from "typia";
// 导入typia库,并引入其内部的tags函数
export const checkString = typia.createIs<string>();
// 导出一个用于检查字符串类型的函数
//----
// bin/checkString.js
//----
import typia from "typia";
// 导入typia库
export const checkString = (() => {
return (input) => typeof input === "string";
})();
// 导出一个检查输入是否为字符串的函数
进入全屏,退出全屏
typia
是一个将 TypeScript 类型转换成运行时函数的工具。
当你调用一个 typia
函数时,它会被编译成如上所述的样子。这就是 typia
的核心理念——将 TypeScript 类型转换为运行时的函数。通过在编译阶段分析目标类型 T
,typia.is<T>()
函数会被编译成一个专门的类型检查器。
此功能允许开发人员通过利用TypeScript的静态类型来确保应用程序中的类型安全,同时提供运行时验证。您无需定义额外的模式,只需使用纯TypeScript类型即可。
另外,由于验证或序列化逻辑是由编译器分析 TypeScript 源代码生成的,因此,它不仅准确,而且比任何竞品都快。
在AMD Ryzen 9 7940HS和Rog Flow x13上测的
2.2 代理型AI的挑战
杰森·黄的图表,以及他的理念:https://youtu.be/R0Erk6J8o70
凭借其 TypeScript 编译能力,「typia」正在改变 Agentic AI 框架领域内的现状。
这个新框架叫做@agentica
,它专攻LLM函数调用,所有操作都通过函数调用完成。函数调用的模式源于typia.llm.application<Class, Model>()
。
这里向你展示一个购物商城的聊天机器人,它是基于企业级购物中心后端的 Swagger/OpenAPI 文档(包含 289 个 API 功能)开发的。如下面的视频所展示,一切运行得非常顺畅。更令人惊叹的是,这个聊天机器人仅使用了一个小型模型 (gpt-4o-mini
, 8b 参数) 就实现了代理智能的功能。
这就是由 typia
通过其编译器技能开启的新代理AI时代。只需列出要调用的函数,你就可以实现代理AI,正如 Jensen Huang 所展示的。如果你是 TypeScript 开发者,你现在也可以做 AI 开发了。
import { Agentica } from "@agentica/core";
import { HttpLlm } from "@samchon/openapi";
import typia from "typia";
const agent = new Agentica({
controllers: [
HttpLlm.application({
model: "chatgpt",
document: await fetch(
"https://shopping-be.wrtn.ai/editor/swagger.json",
).then(r => r.json()),
}),
typia.llm.application<ShoppingCounselor, "chatgpt">(),
typia.llm.application<ShoppingPolicy, "chatgpt">(),
typia.llm.application<ShoppingSearchRag, "chatgpt">(),
],
});
await agent.conversate("我想买个MacBook Pro");
全屏,退出全屏
2.3. 大型语言模型的调用(LLM功能调用)
前往功能调用指南页面: https://platform.openai.com/docs/guides/function-calling
这意味着AI会通过分析与用户的对话上下文来选择合适的函数并填充参数。
typia
和 @agentica
专注于并专门化于这个概念——使用函数调用来实现代理型人工智能。仅从大型语言模型中函数调用的定义来看,这是一个如此优雅的概念,你不禁会想,为什么它没有被更广泛地使用。难道仅仅通过列出在任何给定时间所需的函数,就能实现代理型人工智能吗?
本文将探讨为什么函数调用为什么还没有被广泛采用,并看看typia和@agentica如何使它成为可能。
3. 概念部分3.1. 传统的AI开发
在传统的AI开发领域中,AI开发人员专注于由多个节点构成的工作流程。他们更倾向于开发专用AI代理,而不是开发通用型代理。
然而,这种方法在可扩展性和灵活性方面存在一些关键弱点。当需要扩展代理的功能时,AI开发人员不得不创建越来越复杂的工作流程,包含越来越多的节点。
此外,随着代理图形节点数量的增加,成功率会呈指数下降。这是因为成功率会随着节点数量的增加而呈指数下降。例如,假设每个节点的成功率为80%,并且有五个这样的节点,那么整个流程的成功率就下降到大约32.77%(0.8的五次方)。
为了防止这种笛卡尔积问题,AI开发人员经常创建一个新的监督工作流作为主工作流节点的附加部分。当功能需要扩展时,这将导致工作流呈现出分形结构。为了避免这种笛卡尔积问题,AI开发人员必须应对另一个分形问题。
采用这样的工作流程,能否创建一个购物聊天机器人?是否能搭建一个企业级聊天机器人?这就是为什么我们通常看到的大多是专用聊天机器人,或者说是像玩具一样的聊天机器人项目。
问题源于代理的工作流程本身难以创建和维护,并且扩展性和灵活性都很差这一点。
3.2. 文档驱动的开发
来看看领域驱动设计吧!
每个函数的文档各自独立。
为了避免笛卡尔积问题和分形代理流程的灾难,我建议一种新的方法:“文档驱动开发”。这类似于将复杂项目拆分成更小领域的“领域驱动”方法,使得开发更加简单和可扩展。唯一的不同在于,在这一方法中需要增加文档注释。
为每个函数独立编写文档注释,描述每个函数的目的,这样AI就能理解了。相信@agentica
和LLM函数调用会处理其他所有事情。仅仅通过为每个函数编写独立的文档注释,,这样你的代理就能变得可扩展、灵活且高效。
如果有函数之间存在关系,就不要创建代理工作流了——只需在描述中的注释中详细记录下来。下面是一些详细记录的函数和模式列表:
export class BbsArticleService {
/**
* 获取所有帖子。
*
* 列出归档在BBS数据库中的所有帖子。
*
* @returns 所有帖子的列表
*/
public index(): IBbsArticle[];
/**
* 创建新帖子。
*
* 创建一篇新帖子并将其归档到数据库中。
*
* @param props 创建参数
* @returns 新创建的帖子
*/
public create(props: {
/**
* 要创建的帖子信息
*/
input: IBbsArticle.ICreate;
}): IBbsArticle;
/**
* 更新帖子。
*
* 根据新内容更新帖子。
*
* @param props 更新参数
* @param input 新内容
*/
public update(props: {
/**
* 要更新的帖子的 {@link IBbsArticle.ID}。
*/
id: string & tags.Format<"uuid">;
/**
* 要更新的新内容。
*/
input: IBbsArticle.IUpdate;
}): void;
/**
* 删除帖子。
*
* 从数据库中删除帖子。
*
* @param props 删除参数
*/
public erase(props: {
/**
* 要删除的帖子的 {@link IBbsArticle.ID}。
*/
id: string & tags.Format<"uuid">;
}): void;
}
进入全屏 退出全屏
3.3. 编译器驱动开发
LLM的功能调用规范必须由编译器生成。
@agentica
是一个专长于 LLM 函数调用的代理式 AI 框架,所有功能都通过函数调用实现。因此,最关键的是如何安全且有效地构建 LLM 模型。
在传统的AI开发中,AI开发者定义了手写的LLM功能调用规范。这会导致代码重复,并且这种方式在定义实体上存在危险。
如果手工创建的模式定义出错,人类可以轻松地解决它。然而,AI从不放过这样的错误。无效的手工模式定义会使整个代理系统失效。
所以,如果创建LLM架构很难并且容易出错,@agentica
也会很难并且容易出错。如果构建LLM架构存在危险,使用@agentica
也会很危险。
import { ILlmApplication } from "@samchon/openapi";
import typia from "typia";
import { BbsArticleService } from "./BbsArticleService";
const app: ILlmApplication<"chatgpt"> = typia.llm.application<
BbsArticleService,
"chatgpt"
>();
console.log(app);
切换到全屏 退出全屏
为了确保LLM功能构建的安全和便捷,typia
提供了typia.llm.application<Class, Model>()
。该函数在编译时分析目标TypeScript类,并生成合适的LLM函数调用模式。
因为模式是由编译器通过源代码分析自动生成的,所以模式定义中不会有任何错误。再也不用手工定义模式了,也不再需要重复写代码了。
这种由编译器驱动的模式生成将引导您进入新的代理式人工智能时代。
顺便说一下,@agentica
不仅可以从 TypeScript 类型中获取函数签名,还可以从 Swagger/OpenAPI 文档中获取。那么,后端开发呢?我们又该如何在后端环境中实现这种通过编译器驱动的开发呢?
这个问题的解决方法很清楚,我以后的文章会详细说明。
4. 原则
4.1. OpenAPI 规范 (开放API 规范)
将OpenAPI规范转换为LLM函数调用规范。
LLM功能调用需要基于JSON模式的功能定义。然而,不同公司的大型语言模型服务提供商并未使用相同的JSON模式规范。“OpenAI的GPT和Anthropic的Claude”在LLM功能调用上使用了不同的JSON模式规范,而Google的Gemini则与两者都有所不同。
更具挑战性的是,Swagger/OpenAPI 文档所使用的 JSON 规范与 LLM 函数调用规范不同,并且这些规范在不同版本的 Swagger/OpenAPI 中有很大差异。
为了处理这个问题,@agentica
使用了 @samchon/openapi
。当处理 Swagger/OpenAPI 文档时,它会被转换为一个修订版的 OpenAPI v3.1 规范。然后,它会被转换为特定供应商的 LLM 函数调用方案,从而绕过迁移方案。
作为参考,迁移方案是另一个中间件方案,它将OpenAPI操作模式定义转换为类似于函数的模式定义。如果你想成为一名熟练的AI开发者,能够创建基本库或框架,了解每个模式定义将对你大有裨益:
-
Swagger/OpenAPI 文档:
-
LLM 函数调用模式:
-
LLM DTO 模式:
-
IChatGptSchema
: OpenAI ChatGPT -
IClaudeSchema
: Anthropic Claude -
IGeminiSchema
: Google Gemini -
ILlamaSchema
: Meta Llama -
中间层模式:
-
ILlmSchemaV3
: 基于 OpenAPI v3.0 的中间层 ILlmSchemaV3_1
: 基于 OpenAPI v3.1 的中间层
4.2. 反馈信息
组件 | typia |
TypeBox |
ajv |
io-ts |
zod |
C.V. |
---|---|---|---|---|---|---|
使用简单 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
对象(简单) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
对象(分层) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
对象(递归对象) | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
对象(隐式联合) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
对象(显式联合) | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ |
对象(附加标签) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
对象(模板字面类型) | ✔ | ✔ | ✔ | ❌ | ❌ | ❌ |
对象(动态属性) | ✔ | ✔ | ✔ | ❌ | ❌ | ❌ |
数组(剩余元组) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
数组(分层) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
数组(递归数组) | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ |
数组(递归并集数组) | ✔ | ✔ | ❌ | ✔ | ✔ | ❌ |
数组(R+U,隐式) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
数组(重复数组) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
数组(重复联合数组) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
终极联合类型 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
C.V.
意味着class-validator
LLM的功能调用真的完美吗?不是,一点都不是。
@agentica
是一个专注于LLM函数调用的代理式AI框架。如果有人熟悉AI开发,问“LLM函数调用安全不?在参数生成过程中不会有幻觉?”答案是:“不是这样的,经常失败。哈哈”
由于 @agentica
主要用于函数调用,如果函数调用有危险,也就说明 @agentica
也存在危险,这会动摇 @agentica
的核心思想。
为了克服这些函数调用中的挑战,Agentica
通过以下方式处理类型错误:首先,它允许 LLM 提交错误的参数。然后它详细检查每个类型错误并报告给代理,使代理能够在下次尝试时修正函数调用。这就是所谓的验证反馈策略。
为了得到精确和详细的验证反馈,@agentica
使用了以下面的 typia.validate<T>()
函数。这个过程是由编译器通过分析 TypeScript 源代码生成的,其验证过程比其他任何方案都要详细和准确,其错误追踪比其他任何方案都要详细和准确。
凭借这个强大的编译器驱动的验证反馈策略,@agentica
在函数调用的参数组合层面不会失败。事实上,之前展示的企业级购物聊天机器人,拥有 289 个 API 函数,并运行在一个具有 80 亿参数的小型模型 (gpt-4o-mini
) 上。
这些8B参数意味着代理AI甚至可以在个人电脑上实现。只需要一个具有8GB显存的图形卡就能实现这一点。这种由编译器驱动的验证反馈策略,就是为什么typia
能够成功挑战代理AI领域。
4.3. 内部流程
这是内部的工作流程图吗?
@agentica
中的内部代理工作流。
Agentica 的内部代理操作也很简单。它只使用了三个代理:选择器、调用者和描述器。
选择代理程序设计为通过分析对话上下文来选择或排除候选功能。如果找不到任何合适的功能,它默认作为普通的聊天机器人进行对话。
调用代理尝试通过组合参数来调用候选函数,如果参数不全则会要求用户提供调用所需的更多信息。如果信息不足,它会请用户提供调用所需的更多信息。调用者代理会不断尝试直到所有候选函数都被尝试过。
描述代理只需说明函数调用的结果。
如你所见,Agentica的工作流程并不复杂,甚至可能比许多其他系统还要简单。实现代理式AI的关键不在于设计复杂的工作流程,而在于拥有一个能够安全高效地大规模生产LLM功能调用模式的系统。
让我们一起迎接这一理念的浪潮,函数调用至关重要。
5. 结论部分.typia
是一个起始于运行时验证工具的Transformer库。现在,它利用编译器技能成功实现了代理AI。
代理式AI源于大语言模型的功能调用机制,而typia
是最佳解决方案之一。在编译级别生成类型安全且方便的大语言模型功能调用方案是实现代理式AI的关键,是开发中最重要的一环。
实际上,自从typia
支持了typia.llm.application<Class, Model>()
函数,特别是从那时起,它的下载量激增。过去每月有数十万人使用typia
,而现在每月有数百万人使用。
让我们一起参与新的智能代理时代,借助 typia
和 @agentica
这两个工具。TypeScript 开发者们,你们现在也成为了AI开发的行家了。
import { Agentica } from "@agentica/core";
import { HttpLlm } from "@samchon/openapi";
import typia from "typia";
const agent = new Agentica({
controllers: [
HttpLlm.application({
model: "chatgpt",
document: await fetch(
"https://shopping-be.wrtn.ai/editor/swagger.json",
).then(r => r.json()),
}),
typia.llm.application<ShoppingCounselor, "chatgpt">(),
typia.llm.application<ShoppingPolicy, "chatgpt">(),
typia.llm.application<ShoppingSearchRag, "chatgpt">(),
],
});
await agent.conversate("我要买MacBook Pro");
点击进入全屏模式,点击退出全屏模式
共同學習,寫下你的評論
評論加載中...
作者其他優質文章