结构化输出
大语言模型(如DeepSeek、Claude等)的卓越性能已经在文本生成领域得到广泛应用,能够生成看似自然流畅的文本内容。然而,这些生成的文本往往是自由形式的,缺乏明确的结构,这给后续的处理和利用带来了挑战。例如,当需要从生成的文本中提取关键信息(如姓名、年龄、地址等)时,传统的方法需要复杂的文本解析和正则表达式匹配,开发成本高,鲁棒性差。如果我们能够以结构化的方式获取生成内容,这些问题将迎刃而解。
提升数据处理效率
结构化输出使得生成的内容可以直接以JSON或其他数据格式返回,无需额外的文本解析步骤。例如,当涉及到用户资料处理时,模型可以生成如下结构化数据:
{
"user": {
"name": "李华",
"age": 25,
"address": "北京市朝阳区",
"email": "lihua@example.com"
}
}
在前端应用中,可以立即用这些数据填充表单或用户信息卡片,无需复杂的后端处理。
智能体驱动开发
假设我们有一个创客大赛管理系统开发项目,需要设计数据库、开发 API 接口,并完成 CI/CD 部署。为了高效完成任务,我们构建了一个基于 Agentic Mesh 的智能体编码团队,团队成员包括:
- 系统架构师:负责整体架构规划,包括数据库设计和 API 接口设计。
- Node.js 工程师:负责后端开发,使用 Nest.js 框架和 TypeScript 语言。
- DevOps 工程师:负责 CI/CD 流程和基础设施部署,使用 Docker、Kubernetes 和 Jenkins 等工具。
在传统的开发流程中,任务分配和计划制定通常依赖于手动文档编写和会议讨论,效率低下且容易出错。通过引入结构化输出,我们可以让编排智能体生成开发计划,并将其分配给不同的专家智能体。
import { generateObject, generateText } from "ai";
import { z } from 'zod';
const agents = [
{
id: 'system-architect',
name: '系统架构师',
description: '专业的系统架构师,精通Restful API设计,MySQL数据库设计和优化',
},
{
id: 'nodejs-developer',
name: 'Node.js工程师',
description: '专业的Node.js工程师,精通Nest.js框架,精通TypeScript语言',
},
{
id: 'devops-engineer',
name: 'DevOps工程师',
description: '专业的DevOps工程师,精通Docker和Kubernetes、Jenkins等主流DevOps工具',
}
];
const model = this.agent.createQWenModel();
const result = await generateObject({
model,
schema: z.object({
tasks: z.array(
z.object({
name: z.string(),
description: z.string(),
agentId: z.string(),
steps: z.array(
z.object({
name: z.string(),
description: z.string(),
})
)
})
)
}),
prompt: `
系统中所有的Agent的信息如下:
${agents.map((agent) => `名称:${agent.name} 职责:${agent.description} ID:${agent.id}`).join('\n')}
请生成一份创客大赛管理系统开发计划,包括数据库设计和API接口设计,并将任务分配给合适的Agent,每个任务都必须有多个详细的步骤。
`,
});
res.send(result);
生成结果如下:
{
"object": {
"tasks": [
{
"name": "数据库设计",
"description": "设计创客大赛管理系统的数据库结构",
"agentId": "system-architect",
"steps": [
{
"name": "确定数据表",
"description": "确定需要哪些数据表,例如用户表、项目表、比赛表等"
},
{
"name": "设计字段",
"description": "为每个数据表设计字段,包括字段名、数据类型、长度等"
},
{
"name": "优化索引",
"description": "优化索引设计,提高查询效率"
}
]
},
{
"name": "API接口设计",
"description": "设计创客大赛管理系统的API接口",
"agentId": "system-architect",
"steps": [
{
"name": "确定接口类型",
"description": "确定需要哪些类型的接口,例如CRUD接口、查询接口等"
},
{
"name": "设计接口参数",
"description": "为每个接口设计参数,包括请求参数、返回参数等"
},
{
"name": "编写接口文档",
"description": "编写详细的接口文档,方便其他开发者使用"
}
]
},
{
"name": "Node.js后端开发",
"description": "使用Node.js实现后端逻辑",
"agentId": "nodejs-developer",
"steps": [
{
"name": "搭建项目",
"description": "搭建Node.js项目,安装相关依赖"
},
{
"name": "实现业务逻辑",
"description": "实现后端业务逻辑,包括数据处理、业务逻辑处理等"
},
{
"name": "单元测试",
"description": "编写单元测试,确保代码质量"
}
]
},
{
"name": "DevOps部署",
"description": "使用DevOps工具进行部署",
"agentId": "devops-engineer",
"steps": [
{
"name": "编写Dockerfile",
"description": "编写Dockerfile,定义镜像"
},
{
"name": "构建Docker镜像",
"description": "使用Dockerfile构建Docker镜像"
},
{
"name": "部署到Kubernetes",
"description": "将镜像部署到Kubernetes集群"
}
]
}
]
},
"finishReason": "tool-calls",
"usage": {
"promptTokens": 442,
"completionTokens": 441,
"totalTokens": 883
},
"warnings": [],
"providerMetadata": {
"openai": {}
},
"experimental_providerMetadata": {
"openai": {}
},
"response": {
"id": "chatcmpl-6I5z36TfNUwXduuABR5r5HsTKaMF8BCo",
"timestamp": "2025-02-23T09:17:17.000Z",
"modelId": "qwen2.5",
"headers": {
"content-length": "2354",
"content-type": "application/json; charset=utf-8",
"date": "Sun, 23 Feb 2025 09:16:54 GMT",
"keep-alive": "timeout=15, max=100",
"server": "uvicorn, llama-box/v0.0.117",
"x-request-accepted-at": "1559518723735",
"x-request-id": "1559518723734",
"x-response-tokens-per-second": "22.589093"
}
},
...
}
通过结构化输出,系统架构师智能体设计的数据库结构和 API 接口文档可以共享给 Node.js 工程师智能体,以便其进行后端开发。DevOps 工程师智能体可以获取后端代码和 Dockerfile,进行镜像构建和部署。
工具调用
Tool Calling
(工具调用)是一种允许 AI 模型与外部工具或 API 进行交互的功能。它使模型能够调用特定的工具来执行任务或检索信息,从而扩展了模型的能力。以下是 Tool Calling
的一些关键特点和工作原理:
关键特性
- 增强功能:Tool Calling 允许模型通过调用外部工具来执行其自身无法完成的任务,例如信息检索、数据处理或执行特定操作。
- 灵活性:开发者可以定义各种工具,包括网页搜索、数据库查询、数学计算等,以满足不同的应用需求。
- 智能选择:模型可以根据用户的问题或提示词,智能地选择合适的工具进行调用。
编写一个天气查询工具
import { generateObject, generateText, tool } from "ai";
import { z } from 'zod';
const weather = tool({
description: '获取某地天气',
parameters: z.object({
location: z.string().describe('要获取天气的位置'),
}),
execute: async ({ location }) => ({
location,
temperature: 20 + Math.floor(Math.random() * 21) - 10,
}),
});
const model = this.agent.createQWenModel();
const result = await generateText({
model,
tools: {
weather
},
toolChoice: 'required',
prompt: "杭州的天气如何?"
});
res.send(result);
toolChoice
toolChoice
选项支持以下设置:
auto
(默认):模型可以选择是否以及调用哪些工具。required
: 模型必须调用一个工具,它可以自主选择调用哪个工具。none
: 模型不得调用工具{ type: 'tool', toolName: string }
: 模型必须调用指定的工具
执行上面的代码模型将从用户提问中解析出工具需要的参数,然后选择并调用工具获得结果。
{
"text": "",
"toolCalls": [
{
"type": "tool-call",
"toolCallId": "call-sWJm07WQzzre50Bm4g3GYUKtxYHHJBpk",
"toolName": "weather",
"args": {
"location": "杭州"
}
}
],
"toolResults": [
{
"type": "tool-result",
"toolCallId": "call-sWJm07WQzzre50Bm4g3GYUKtxYHHJBpk",
"toolName": "weather",
"args": {
"location": "杭州"
},
"result": {
"location": "杭州",
"temperature": 29
}
}
],
"finishReason": "tool-calls",
"usage": {
"promptTokens": 215,
"completionTokens": 19,
"totalTokens": 234
},
"warnings": [],
...
}
让智能体调用其他智能体
const payload = {
"name": "welcome-greet",
"data": { "username": "Roy Lin" }
};
const callAgent = tool({
description: '调用智能体',
parameters: z.object({
name: z.string(),
data: z.any(),
}),
execute: async ({ name, data }) => {
return await this.inngestService.send({
name,
data
});
}
});
const model = this.agent.createQWenModel();
const result = await generateText({
model,
tools: {
callAgent
},
toolChoice: 'required',
prompt: `请调用智能体: ${payload.name}, 数据为:${JSON.stringify(payload.data)}`
});
res.send(result);
下面Greeting Agent
代码实现
@Agent({
config: {
id: 'welcome-greet',
name: "Greeting Agent",
description: 'This is an agent used to greet users.'
},
trigger: {
event: 'welcome-greet',
}
})
async greeting({ event, step }: Context) {
const model = this.agentService.createQWenModel();
const { text } = await generateText({
model,
prompt: `请用一句话向${event.data.username}问好。`,
});
return { message: text };
}
查看Inngest UI
可以看到Greeting Agent
的执行结果
总结
通过结构化输出和工具调用,我们可以更好地利用大语言模型的能力,为实际应用带来更高的效率和更好的用户体验。