微信扫码
添加专属顾问
我要投稿
最新消息!开源 AI 工具 Ollama 新增了结构化输出支持。这意味着我们可以使用预定义的格式来约束 AI 的输出,让回复更加精确和可控。让我们通过一些实际的代码示例来看看这个强大的新功能。
使用 Ollama 进行数据提取非常简单。下面是一个提取宠物信息的示例:
这里使用国产最强开源模型qwen2.5
Qwen2.5是阿里巴巴通义千问团队于2024年9月发布的最新开源大语言模型系列,涵盖从0.5B到72B参数规模的模型,包括基础版本和指令微调版本。
/**
* 数据提取测试
* 演示如何从自然语言文本中提取结构化数据
*/import { Ollama } from "ollama";import { z } from "zod";import { zodToJsonSchema } from "zod-to-json-schema";const config = {baseUrl: "http://192.168.1.180:8000",model: "qwen2.5:14b",
};// 定义宠物信息的数据结构const Pet = z.object({name: z.string().describe("宠物名字"),animal: z.string().describe("动物类型"),age: z.number().describe("年龄"),color: z.string().nullable().describe("毛色"),favorite_toy: z.string().nullable().describe("最喜欢的玩具"),
});// 定义宠物列表的数据结构const PetList = z.object({pets: z.array(Pet).describe("宠物列表"),
});async function extractPetsInfo() {const ollama = new Ollama({host: config.baseUrl,
});try {console.log("\n=== 宠物信息提取测试 ===");const response = await ollama.chat({model: config.model,messages: [
{role: "user",content: `
我家有三只宠物。
一只叫小白的猫咪,今年3岁,是白色的,最喜欢玩逗猫棒。
还有一只2岁的橘猫叫胖虎,特别喜欢玩毛线球。
最后是一只叫旺财的狗,5岁了,是棕色的,最喜欢玩飞盘。
`,
},
],format: zodToJsonSchema(PetList),
});// 解析返回的数据const petInfo = PetList.parse(JSON.parse(response.message.content));// 打印原始 JSON 数据console.log("\n提取的原始数据:");console.log(JSON.stringify(petInfo, null, 2));// 格式化输出每只宠物的信息console.log("\n=== 宠物信息汇总 ===");
petInfo.pets.forEach((pet, index) => {console.log(`\n${index + 1}. ${pet.name}:`);console.log(` - 类型: ${pet.animal}`);console.log(` - 年龄: ${pet.age}岁`);console.log(` - 毛色: ${pet.color || "未知"}`);console.log(` - 最爱玩具: ${pet.favorite_toy || "未知"}`);
});// 统计信息console.log("\n=== 统计信息 ===");const animalCount = petInfo.pets.reduce((acc, pet) => {
acc[pet.animal] = (acc[pet.animal] || 0) + 1;return acc;
}, {});console.log("宠物类型统计:");Object.entries(animalCount).forEach(([animal, count]) => {console.log(`- ${animal}: ${count}只`);
});const avgAge =
petInfo.pets.reduce((sum, pet) => sum + pet.age, 0) / petInfo.pets.length;console.log(`平均年龄: ${avgAge.toFixed(1)}岁`);
} catch (error) {console.error("数据提取失败:", error.message);if (error.response) {console.error("API 响应:", error.response);
}
}
}提取结果如下图所示:
Ollama 还支持图片内容分析,可以返回结构化的图片描述
这里使用 Llama 3.2-Vision作为图片识别模型
Llama 3.2-Vision是Meta公司于2024年9月发布的多模态大语言模型,具备处理文本和图像的能力。该模型提供11B和90B两个版本,支持128,000个tokens的上下文长度。在文本处理方面,Llama 3.2-Vision支持多种语言,包括英语、德语、法语、意大利语、葡萄牙语、印地语、西班牙语和泰语。然而,在图像与文本结合的应用中,目前仅支持英语。
先上图
再上代码
/**
* 图片内容分析测试
* 演示如何使用 AI 模型分析图片并返回结构化数据
*/import { Ollama } from "ollama";import { z } from "zod";import { zodToJsonSchema } from "zod-to-json-schema";import fs from "fs/promises";const config = {baseUrl: "http://192.168.1.180:8000",model: "llama3.2-vision",
};// 定义物体信息的数据结构const Object = z.object({name: z.string().describe("物体名称"),confidence: z.number().min(0).max(1).describe("置信度"),attributes: z.string().describe("物体属性描述"),
});// 定义图片描述的数据结构const ImageDescription = z.object({summary: z.string().describe("图片整体描述"),objects: z.array(Object).describe("检测到的物体列表"),scene: z.string().describe("场景描述"),colors: z.array(z.string()).describe("主要颜色列表"),time_of_day: z
.enum(["Morning", "Afternoon", "Evening", "Night"])
.describe("拍摄时间"),setting: z.enum(["Indoor", "Outdoor", "Unknown"]).describe("环境设置"),text_content: z.string().nullable().describe("图片中的��字内容"),
});async function analyzeImage(imagePath) {const ollama = new Ollama({host: config.baseUrl,
});try {// 读取图片文件const imageBuffer = await fs.readFile(imagePath);const base64Image = imageBuffer.toString("base64");console.log("\n=== 图片内容分析测试 ===");const response = await ollama.chat({model: config.model,messages: [
{role: "user",content:"请分析这张图片,描述你看到的内容,包括物体、场景、颜色和任何可以检测到的文字。",images: [base64Image],
},
],format: zodToJsonSchema(ImageDescription),options: {temperature: 0, // 设置为0以获得更确定性的输出},
});// 解析返回的数据const imageInfo = ImageDescription.parse(JSON.parse(response.message.content)
);// 打印原始 JSON 数据console.log("\n=== 原始 JSON 数据 ===");console.log(JSON.stringify(imageInfo, null, 2));// 打印格式化的分析结果console.log("\n=== 格式化分析结果 ===");console.log("\n【整体描述】");console.log(imageInfo.summary);console.log("\n【场景信息】");console.log(`场景类型: ${imageInfo.scene}`);console.log(`环境设置: ${getChineseSettingName(imageInfo.setting)}`);console.log(`拍摄时间: ${getChineseTimeName(imageInfo.time_of_day)}`);console.log("\n【检测到的物体】");
imageInfo.objects.forEach((obj, index) => {console.log(`\n${index + 1}. ${obj.name}`);console.log(` 置信度: ${(obj.confidence * 100).toFixed(1)}%`);console.log(` 属性: ${obj.attributes}`);
});console.log("\n【主要颜色】");
imageInfo.colors.forEach((color) => console.log(`- ${color}`));if (imageInfo.text_content) {console.log("\n【检测到的文字】");console.log(imageInfo.text_content);
}
} catch (error) {console.error("图片分析失败:", error.message);if (error.response) {console.error("API 响应:", error.response);
}
}
}// 环境设置的中文映射function getChineseSettingName(setting) {const settingMap = {Indoor: "室内",Outdoor: "室外",Unknown: "未知",
};return settingMap[setting] || setting;
}// 时间段的中文映射function getChineseTimeName(time) {const timeMap = {Morning: "早晨",Afternoon: "下午",Evening: "傍晚",Night: "夜晚",
};return timeMap[time] || time;
}// 使用示例const imagePath = "/Users/SCR-20241019-marq.png";analyzeImage(imagePath).catch(console.error);返回结果如下图:
结构化输出在处理文档信息时也很有用:
const Resume = z.object({basicInfo: z.object({name: z.string().describe("姓名"),age: z.number().describe("年龄"),email: z.string().email().describe("电子邮箱"),phone: z.string().describe("电话号码")
}),education: z.array(z.object({school: z.string(),degree: z.string(),major: z.string(),period: z.object({start: z.string(),end: z.string()
})
})),workExperience: z.array(z.object({company: z.string(),position: z.string(),period: z.object({start: z.string(),end: z.string()
}),responsibilities: z.array(z.string()),achievements: z.array(z.string())
}))
});import { z } from "zod";// 基础类型const stringSchema = z.string();const numberSchema = z.number();const booleanSchema = z.boolean();const nullSchema = z.null();// 可选和可空const optionalString = z.string().optional(); // string | undefinedconst nullableString = z.string().nullable(); // string | null// 对象定义const UserSchema = z.object({id: z.number(),name: z.string().min(2),email: z.string().email(),age: z.number().min(0).max(120),role: z.enum(["admin", "user", "guest"]),tags: z.array(z.string())
});// 嵌套对象const PostSchema = z.object({title: z.string(),content: z.string(),author: UserSchema,comments: z.array(z.object({text: z.string(),user: UserSchema
}))
});// 添加自定义验证const PhoneSchema = z.string().refine((val) => /^1[3-9]\d{9}$/.test(val),"请输入有效的手机号");// 类型转换const NumberFromString = z.string().transform((val) => parseInt(val));// 默认值const ConfigSchema = z.object({port: z.number().default(3000),host: z.string().default("localhost")
});// 基础配置const BaseConfig = z.object({version: z.string(),name: z.string()
});// 扩展配置const FullConfig = BaseConfig.extend({description: z.string(),isEnabled: z.boolean()
});// 合并多个 Schemaconst MergedSchema = z.intersection(SchemaA,SchemaB);const ProductSchema = z.object({name: z.string().describe("产品名称"),price: z.number().describe("产品价格(元)"),stock: z.number().describe("库存数量"),category: z.enum(["电子", "服装", "食品"]).describe("产品类别")
});try {const result = ProductSchema.parse(data);
} catch (error) {if (error instanceof z.ZodError) {
error.errors.forEach(err => {console.log(`${err.path.join('.')}: ${err.message}`);
});
}
}const AsyncSchema = z.object({username: z.string().refine(async (val) => {// 检查用户名是否可用const exists = await checkUserExists(val);return !exists;
},"用户名已存在"
)
});// 定义可复用的类型const DateRangeSchema = z.object({start: z.string(),end: z.string()
});// 在其他 Schema 中复用const EventSchema = z.object({title: z.string(),period: DateRangeSchema,location: z.string()
});// 预编译 Schemaconst compiledSchema = z.object({/*...*/}).compile();// 重复使用已编译的 Schemafunction validateData(data) {return compiledSchema.safeParse(data);53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-10-29
AI本地知识库+智能体系列:手把手教你本地部署 n8n,一键实现自动采集+智能处理!
2025-10-29
n8n如何调用最近爆火的deepseek OCR?
2025-10-29
OpenAI终于快要上市了,也直面了这23个灵魂拷问。
2025-10-29
保姆级教程:我用Coze干掉了最烦的周报
2025-10-29
维基百科,终结了!马斯克开源版上线,用AI重写「真相」
2025-10-28
腾讯开源Nano Banana,我总结了15种邪修玩法(附提示语)
2025-10-28
牛逼,DeepSeek-OCR 最新免费,引爆文档处理效率的黑科技模型
2025-10-28
小红书入局AI智能体开源DeepAgent,在计划什么更新?
2025-08-20
2025-09-07
2025-08-05
2025-08-20
2025-08-26
2025-08-22
2025-07-31
2025-09-06
2025-08-06
2025-10-20
2025-10-29
2025-10-28
2025-10-13
2025-09-29
2025-09-17
2025-09-09
2025-09-08
2025-09-07