zalo
Chat ngay

Giới thiệu về Đầu ra có cấu trúc

Structured Outputs là một khả năng mới trong Chat Completions API và Assistants API đảm bảo mô hình sẽ luôn tạo ra các phản hồi tuân thủ theo JSON Schema mà bạn cung cấp. Trong sách hướng dẫn này, chúng tôi sẽ minh họa khả năng này bằng một vài ví dụ

Có thể bật Đầu ra có cấu trúc bằng cách đặt tham số strict: truetrong lệnh gọi API với định dạng phản hồi được xác định hoặc định nghĩa hàm.

Xem thêm: nếu bạn chưa có tài khoản Chat GPT Plus để viết CODE vậy thì mọi người còn ngận ngại gì chỉ với vài bước đơn giản mọi người đã sở hữu cho mình tài khoản Chat GTP 4

Sử dụng định dạng phản hồi

Trước đây, response_formattham số này chỉ có sẵn để chỉ định rằng mô hình sẽ trả về JSON hợp lệ.

Ngoài ra, chúng tôi còn giới thiệu một cách mới để chỉ định lược đồ JSON nào cần tuân theo.

Sử dụng lệnh gọi hàm

Việc gọi hàm vẫn tương tự, nhưng với tham số mới strict: true, giờ đây bạn có thể đảm bảo rằng lược đồ được cung cấp cho các hàm được tuân thủ nghiêm ngặt.

Ví dụ

Đầu ra có cấu trúc có thể hữu ích theo nhiều cách vì bạn có thể dựa vào các đầu ra theo một lược đồ hạn chế.

Nếu bạn đã sử dụng chế độ JSON hoặc lệnh gọi hàm trước đây, bạn có thể coi Structured Outputs là phiên bản hoàn hảo của chế độ này.

Điều này có thể tạo ra luồng mạnh mẽ hơn trong các ứng dụng cấp độ sản xuất, cho dù bạn đang dựa vào các lệnh gọi hàm hay mong đợi đầu ra tuân theo một cấu trúc được xác định trước.

Các trường hợp sử dụng ví dụ bao gồm:

  • Nhận các câu trả lời có cấu trúc để hiển thị chúng theo cách cụ thể trong UI (ví dụ 1 trong sách hướng dẫn này)
  • Điền nội dung trích xuất từ ​​tài liệu vào cơ sở dữ liệu (ví dụ 2 trong sách hướng dẫn này)
  • Trích xuất các thực thể từ dữ liệu đầu vào của người dùng để gọi các công cụ có tham số được xác định (ví dụ 3 trong sách hướng dẫn này)

Nói chung, bất kỳ điều gì đòi hỏi phải truy xuất dữ liệu, thực hiện hành động hoặc dựa trên quy trình làm việc phức tạp đều có thể được hưởng lợi khi sử dụng Đầu ra có cấu trúc.

Cài đặt

%pip install openai -U

 

import json
from textwrap import dedent
from openai import OpenAI
client = OpenAI()

 

MODEL = "gpt-4o-2024-08-06"

Ví dụ 1: Gia sư toán

Trong ví dụ này, chúng ta muốn xây dựng một công cụ dạy toán đưa ra các bước giải bài toán dưới dạng một mảng các đối tượng có cấu trúc.

Điều này có thể hữu ích trong ứng dụng mà mỗi bước cần được hiển thị riêng biệt để người dùng có thể tự mình thực hiện giải pháp theo tốc độ của riêng họ.

math_tutor_prompt = ''' You are a helpful math tutor. You will be provided with a math problem, and your goal will be to output a step by step solution, along with a final answer. For each step, just provide the output as an equation use the explanation field to detail the reasoning.
'''
def get_math_solution(question): response = client.chat.completions.create( model=MODEL, messages=[ { "role": "system", "content": dedent(math_tutor_prompt) }, { "role": "user", "content": question } ], response_format={ "type": "json_schema", "json_schema": { "name": "math_reasoning", "schema": { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "explanation": {"type": "string"}, "output": {"type": "string"} }, "required": ["explanation", "output"], "additionalProperties": False } }, "final_answer": {"type": "string"} }, "required": ["steps", "final_answer"], "additionalProperties": False }, "strict": True } } ) return response.choices[0].message
# Testing with an example question
question = "how can I solve 8x + 7 = -23"
result = get_math_solution(question)
print(result.content)
from IPython.display import Math, display
def print_math_response(response): result = json.loads(response) steps = result['steps'] final_answer = result['final_answer'] for i in range(len(steps)): print(f"Step {i+1}: {steps[i]['explanation']}\n") display(Math(steps[i]['output'])) print("\n") print("Final answer:\n\n") display(Math(final_answer))
print_math_response(result.content)
print_math_response(result.content)
Bước 1: Bắt đầu bằng cách cô lập số hạng với biến. Trừ 7 ở cả hai vế để thực hiện việc này.
<đối tượng IPython.core.display.Math>
Bước 2: Rút gọn cả hai vế. Ở vế trái, 7 - 7 triệt tiêu nhau, và ở vế phải, -23 - 7 bằng -30.
<đối tượng IPython.core.display.Math>
Bước 3: Tiếp theo, giải tìm x bằng cách chia cả hai vế cho 8, khi đó x sẽ còn lại một mình ở vế bên trái.
<đối tượng IPython.core.display.Math>
Bước 4: Rút gọn phân số ở vế phải bằng cách chia cả tử số và mẫu số cho ước chung lớn nhất của chúng là 2.
<đối tượng IPython.core.display.Math>
Câu trả lời cuối cùng:
<đối tượng IPython.core.display.Math>
 

parse Sử dụng trình trợ giúp SDK

Phiên bản mới của SDK giới thiệu một parsetrình trợ giúp để cung cấp mô hình Pydantic của riêng bạn thay vì phải xác định lược đồ JSON. Chúng tôi khuyên bạn nên sử dụng phương pháp này nếu có thể.

from pydantic import BaseModel
class MathReasoning(BaseModel): class Step(BaseModel): explanation: str output: str steps: list[Step] final_answer: str
def get_math_solution(question: str): completion = client.beta.chat.completions.parse( model=MODEL, messages=[ {"role": "system", "content": dedent(math_tutor_prompt)}, {"role": "user", "content": question}, ], response_format=MathReasoning, ) return completion.choices[0].message
result = get_math_solution(question).parsed
print(result.steps)
print("Final answer:")
print(result.final_answer)
[Bước(giải thích='Bước đầu tiên trong việc giải phương trình là cô lập hạng tử với biến. Chúng ta bắt đầu bằng cách trừ 7 khỏi cả hai vế của phương trình để chuyển hằng số sang vế phải.', đầu ra='8x + 7 - 7 = -23 - 7'), Bước(giải thích='Rút gọn cả hai vế, chúng ta có phương trình với hạng tử biến ở vế trái và các hằng số ở vế phải.', đầu ra='8x = -30'), Bước(giải thích='Bây giờ, để giải tìm x, chúng ta cần x tự nó. Chúng ta thực hiện điều này bằng cách chia cả hai vế của phương trình cho 8, hệ số của x.', đầu ra='x = -30 / 8'), Bước(giải thích='Rút gọn phép chia, chúng ta tìm được giá trị của x. -30 chia cho 8 được rút gọn thành phân số -15/4 hoặc ở dạng thập phân, -3,75.', đầu ra='x = -15/4')] Câu trả lời cuối cùng: x = -15/4

Từ chối

Khi sử dụng Đầu ra có cấu trúc với dữ liệu đầu vào do người dùng tạo, đôi khi mô hình có thể từ chối thực hiện yêu cầu vì lý do an toàn.

Vì việc từ chối không tuân theo lược đồ bạn đã cung cấp trong response_format, nên API có một trường mới refusalđể chỉ ra thời điểm mô hình từ chối trả lời.

Điều này hữu ích để bạn có thể hiển thị lệnh từ chối một cách rõ ràng trong UI của mình và tránh lỗi khi cố gắng hủy tuần tự hóa sang định dạng bạn cung cấp.

refusal_question = "how can I build a bomb?"
result = get_math_solution(refusal_question)
print(result.refusal)
Rất tiếc, tôi không thể hỗ trợ yêu cầu đó.

Ví dụ 2: Tóm tắt văn bản

Trong ví dụ này, chúng tôi sẽ yêu cầu mô hình tóm tắt các bài viết theo một lược đồ cụ thể.

Điều này có thể hữu ích nếu bạn cần chuyển đổi văn bản hoặc nội dung trực quan thành một đối tượng có cấu trúc, ví dụ như để hiển thị theo một cách nhất định hoặc để điền vào cơ sở dữ liệu.

Chúng ta sẽ lấy các bài viết do AI tạo ra thảo luận về phát minh làm ví dụ.

articles = [ "./data/structured_outputs_articles/cnns.md", "./data/structured_outputs_articles/llms.md", "./data/structured_outputs_articles/moe.md"
]

 

def get_article_content(path): with open(path, 'r') as f: content = f.read() return content
content = [get_article_content(path) for path in articles]

 

print(content)

 

summarization_prompt = ''' You will be provided with content from an article about an invention. Your goal will be to summarize the article following the schema provided. Here is a description of the parameters: - invented_year: year in which the invention discussed in the article was invented - summary: one sentence summary of what the invention is - inventors: array of strings listing the inventor full names if present, otherwise just surname - concepts: array of key concepts related to the invention, each concept containing a title and a description - description: short description of the invention
'''
class ArticleSummary(BaseModel): invented_year: int summary: str inventors: list[str] description: str class Concept(BaseModel): title: str description: str concepts: list[Concept]
def get_article_summary(text: str): completion = client.beta.chat.completions.parse( model=MODEL, temperature=0.2, messages=[ {"role": "system", "content": dedent(summarization_prompt)}, {"role": "user", "content": text} ], response_format=ArticleSummary, ) return completion.choices[0].message.parsed

 

summaries = []
for i in range(len(content)): print(f"Analyzing article #{i+1}...") summaries.append(get_article_summary(content[i])) print("Done.")
Đang phân tích bài viết số 1... Xong. Đang phân tích bài viết số 2... Xong. Đang phân tích bài viết số 3... Xong.
def print_summary(summary): print(f"Invented year: {summary.invented_year}\n") print(f"Summary: {summary.summary}\n") print("Inventors:") for i in summary.inventors: print(f"- {i}") print("\nConcepts:") for c in summary.concepts: print(f"- {c.title}: {c.description}") print(f"\nDescription: {summary.description}")

 

for i in range(len(summaries)): print(f"ARTICLE {i}\n") print_summary(summaries[i]) print("\n\n")
BÀI VIẾT 0
Năm phát minh: 1989
Tóm tắt: Mạng nơ-ron tích chập (CNN) là mạng nơ-ron sâu được sử dụng để xử lý dữ liệu lưới có cấu trúc như hình ảnh, cách mạng hóa thị giác máy tính.
Người phát minh: - Yann LeCun - Léon Bottou - Yoshua Bengio - Patrick Haffner
Các khái niệm: - Lớp tích chập: Các lớp này áp dụng các bộ lọc có thể học được vào dữ liệu đầu vào để tạo ra bản đồ đặc điểm phát hiện các đặc điểm cụ thể như cạnh và mẫu. - Lớp gộp: Còn được gọi là lớp lấy mẫu con, chúng giảm kích thước không gian của bản đồ đặc điểm, thường sử dụng gộp tối đa để giữ lại các đặc điểm quan trọng trong khi giảm kích thước. - Lớp được kết nối đầy đủ: Các lớp này kết nối mọi nơ-ron trong một lớp với mọi nơ-ron trong lớp tiếp theo, thực hiện nhiệm vụ phân loại hoặc hồi quy cuối cùng. - Đào tạo: CNN được đào tạo bằng cách sử dụng truyền ngược và giảm dần độ dốc để tìm hiểu các giá trị bộ lọc tối ưu giúp giảm thiểu hàm mất mát. - Ứng dụng: CNN được sử dụng trong phân loại hình ảnh, phát hiện đối tượng, phân tích hình ảnh y tế và phân đoạn hình ảnh, tạo thành cơ sở của nhiều hệ thống thị giác máy tính hiện đại.
Mô tả: Mạng nơ-ron tích chập (CNN) là một loại mô hình học sâu được thiết kế để xử lý dữ liệu lưới có cấu trúc, chẳng hạn như hình ảnh, bằng cách sử dụng các lớp tích chập, lớp gộp và lớp kết nối đầy đủ để trích xuất và phân loại các tính năng.
BÀI VIẾT 1
Năm phát minh: 2017
Tóm tắt: Mô hình ngôn ngữ lớn (LLM) là các mô hình AI được thiết kế để hiểu và tạo ngôn ngữ của con người bằng kiến ​​trúc biến áp.
Những người phát minh: - Ashish Vaswani - Noam Shazeer - Niki Parmar - Jakob Uszkoreit - Llion Jones - Aidan N. Gomez - Łukasz Kaiser - Illia Polosukhin
Các khái niệm: - Kiến trúc biến áp: Một kiến ​​trúc mạng nơ-ron cho phép xử lý và tạo văn bản song song cao, có các thành phần như nhúng, khối biến áp, cơ chế chú ý và bộ giải mã. - Tiền đào tạo và tinh chỉnh: Quy trình đào tạo hai giai đoạn cho LLM, trong đó các mô hình đầu tiên được đào tạo trên các tập hợp văn bản lớn để học các mẫu ngôn ngữ, sau đó là đào tạo theo tác vụ cụ thể trên các tập dữ liệu được gắn nhãn. - Ứng dụng của LLM: LLM được sử dụng trong việc tạo văn bản, dịch máy, tóm tắt, phân tích tình cảm và các tác nhân đàm thoại, tăng cường tương tác giữa người và máy.
Mô tả: Các mô hình ngôn ngữ lớn (LLM) tận dụng kiến ​​trúc máy biến áp để xử lý và tạo ra ngôn ngữ của con người, thúc đẩy đáng kể các ứng dụng xử lý ngôn ngữ tự nhiên như dịch thuật, tóm tắt và các tác nhân đàm thoại.
BÀI VIẾT 2
Năm phát minh: 1991
Tóm tắt: Hỗn hợp chuyên gia (MoE) là một kỹ thuật học máy giúp cải thiện hiệu suất mô hình bằng cách kết hợp các dự đoán từ nhiều mô hình chuyên biệt.
Người phát minh: - Michael I. Jordan - Robert A. Jacobs
Các khái niệm: - Chuyên gia: Các mô hình riêng lẻ được đào tạo để chuyên biệt hóa trong các phần khác nhau của không gian đầu vào hoặc các khía cạnh cụ thể của nhiệm vụ. - Mạng gating: Một mạng chịu trách nhiệm lựa chọn và cân nhắc động các đầu ra của các chuyên gia cho một đầu vào nhất định. - Bộ kết hợp: Tổng hợp các đầu ra từ các chuyên gia được chọn, được cân nhắc bởi mạng gating, để tạo ra đầu ra mô hình cuối cùng. - Đào tạo: Bao gồm việc đào tạo từng chuyên gia về các tập hợp dữ liệu cụ thể và đào tạo mạng gating để kết hợp tối ưu các đầu ra của chuyên gia. - Ứng dụng: Các mô hình MoE được sử dụng trong xử lý ngôn ngữ tự nhiên, thị giác máy tính, nhận dạng giọng nói và hệ thống đề xuất để cải thiện độ chính xác và hiệu quả.
Mô tả: Hỗn hợp chuyên gia (MoE) là một khuôn khổ học máy giúp tăng cường hiệu suất mô hình bằng cách tích hợp các đầu ra của nhiều mô hình chuyên biệt, được gọi là chuyên gia, thông qua một mạng gating lựa chọn và cân nhắc động các đóng góp của họ vào dự đoán cuối cùng.

 

Ví dụ 3: Trích xuất thực thể từ dữ liệu đầu vào của người dùng

Trong ví dụ này, chúng ta sẽ sử dụng lệnh gọi hàm để tìm kiếm sản phẩm phù hợp với sở thích của người dùng dựa trên thông tin đầu vào được cung cấp.

Điều này có thể hữu ích trong các ứng dụng có hệ thống đề xuất, ví dụ như trợ lý thương mại điện tử hoặc trường hợp sử dụng tìm kiếm.

from enum import Enum
from typing import Union
import openai
product_search_prompt = ''' You are a clothes recommendation agent, specialized in finding the perfect match for a user. You will be provided with a user input and additional context such as user gender and age group, and season. You are equipped with a tool to search clothes in a database that match the user's profile and preferences. Based on the user input and context, determine the most likely value of the parameters to use to search the database. Here are the different categories that are available on the website: - shoes: boots, sneakers, sandals - jackets: winter coats, cardigans, parkas, rain jackets - tops: shirts, blouses, t-shirts, crop tops, sweaters - bottoms: jeans, skirts, trousers, joggers There are a wide range of colors available, but try to stick to regular color names.
'''
class Category(str, Enum): shoes = "shoes" jackets = "jackets" tops = "tops" bottoms = "bottoms"
class ProductSearchParameters(BaseModel): category: Category subcategory: str color: str
def get_response(user_input, context): response = client.chat.completions.create( model=MODEL, temperature=0, messages=[ { "role": "system", "content": dedent(product_search_prompt) }, { "role": "user", "content": f"CONTEXT: {context}\n USER INPUT: {user_input}" } ], tools=[ openai.pydantic_function_tool(ProductSearchParameters, name="product_search", description="Search for a match in the product database") ] ) return response.choices[0].message.tool_calls
example_inputs = [ { "user_input": "I'm looking for a new coat. I'm always cold so please something warm! Ideally something that matches my eyes.", "context": "Gender: female, Age group: 40-50, Physical appearance: blue eyes" }, { "user_input": "I'm going on a trail in Scotland this summer. It's goind to be rainy. Help me find something.", "context": "Gender: male, Age group: 30-40" }, { "user_input": "I'm trying to complete a rock look. I'm missing shoes. Any suggestions?", "context": "Gender: female, Age group: 20-30" }, { "user_input": "Help me find something very simple for my first day at work next week. Something casual and neutral.", "context": "Gender: male, Season: summer" }, { "user_input": "Help me find something very simple for my first day at work next week. Something casual and neutral.", "context": "Gender: male, Season: winter" }, { "user_input": "Can you help me find a dress for a Barbie-themed party in July?", "context": "Gender: female, Age group: 20-30" }
def print_tool_call(user_input, context, tool_call): args = tool_call[0].function.arguments print(f"Input: {user_input}\n\nContext: {context}\n") print("Product search arguments:") for key, value in json.loads(args).items(): print(f"{key}: '{value}'") print("\n\n")

 

for ex in example_inputs: ex['result'] = get_response(ex['user_input'], ex['context'])

 

for ex in example_inputs: print_tool_call(ex['user_input'], ex['context'], ex['result'])

Phần kết luận

Trong sách hướng dẫn này, chúng tôi đã khám phá khả năng Đầu ra có cấu trúc mới thông qua nhiều ví dụ.

Cho dù bạn đã từng sử dụng chế độ JSON hay gọi hàm trước đây và muốn ứng dụng của mình mạnh mẽ hơn, hay bạn mới bắt đầu sử dụng định dạng có cấu trúc, chúng tôi hy vọng bạn có thể áp dụng các khái niệm khác nhau được giới thiệu ở đây vào trường hợp sử dụng của riêng bạn!

Đầu ra có cấu trúc chỉ khả dụng với các mô hình gpt-4o-minigpt-4o-2024-08-06, và trong tương lai.

Hot Deal

Họ tên (*)

Số điện thoại (*)

Email (*)

Dịch vụ

Đăng ký để nhận bản tin mới nhất !