Ollama 0.5.1重磅更新:支持结构化输出,让 AI 回复更精准

最新消息!开源 AI 工具 Ollama 新增了结构化输出支持。这意味着我们可以使用预定义的格式来约束 AI 的输出,让回复更加精确和可控。让我们通过一些实际的代码示例来看看这个强大的新功能。

Ollama 0.5.1重磅更新:支持结构化输出,让 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 0.5.1重磅更新:支持结构化输出,让 AI 回复更精准

图片分析能力

Ollama 还支持图片内容分析,可以返回结构化的图片描述

这里使用 Llama 3.2-Vision作为图片识别模型

Llama 3.2-Vision是Meta公司于2024年9月发布的多模态大语言模型,具备处理文本和图像的能力。该模型提供11B和90B两个版本,支持128,000个tokens的上下文长度。在文本处理方面,Llama 3.2-Vision支持多种语言,包括英语、德语、法语、意大利语、葡萄牙语、印地语、西班牙语和泰语。然而,在图像与文本结合的应用中,目前仅支持英语。

先上图

Ollama 0.5.1重磅更新:支持结构化输出,让 AI 回复更精准

再上代码

/**   * 图片内容分析测试   * 演示如何使用 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);

返回结果如下图:
Ollama 0.5.1重磅更新:支持结构化输出,让 AI 回复更精准

简历信息提取

结构化输出在处理文档信息时也很有用:

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())  }))  });

实用技巧

  • 使用 Zod 来定义清晰的数据结构
  • 为每个字段添加描述,帮助模型理解
  • 设置 temperature 为 0,使输出更稳定
  • 合理使用可空字段(nullable)增加灵活性

应用场景

  • 自动化数据提取和整理
  • 智能文档解析
  • 图片内容分析
  • 结构化知识提取
  • API 响应格式化

扩展阅读:Zod 使用详解

1. 基础类型定义

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

2. 复杂对象定义

// 对象定义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  }))  });

3. 类型转换和验证

// 添加自定义验证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")  });

4. 继承和合并

// 基础配置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);

5. 实战应用技巧

  • 添加字段描述
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;  },"用户名已存在"  )  });

6. 最佳实践

  • 类型复用
// 定义可复用的类型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);

前沿技术大模型技术新闻资讯

以大模型和图谱驱动的企业综合分析系统构建思路

2026-2-26 23:10:59

前沿技术大模型技术新闻资讯

AI智能体元年:六大实战启示

2026-2-27 0:00:23

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
购物车
优惠劵
搜索