Free lesson · GenAI Agent Engineering

தரவு பைப்லைன்களை உருவாக்குங்கள்

திறமையான தரவு செயலாக்க பைப்லைன்களை நீங்கள் உருவாக்குவீர்கள். பல generators-ஐ ஒன்றாக இணைத்து, பெரிய கோப்புகளை memory-யில் ஏற்றாமல் lazy முறையில் செயலாக்கி, தரவு streams-ஐ வடிகட்டி மாற்றியமைப்பீர்கள்.

Course: LLM Foundations for Agent Builders · Chapter 1 · Generators & Iterators

Free to read — no subscription required.

ஜெனரேட்டர்களின் மிகவும் சக்திவாய்ந்த பயன்பாடுகளில் ஒன்று தரவு செயலாக்க பைப்லைன்களை உருவாக்குவது. பைப்லைனில் உள்ள ஒவ்வொரு நிலையும் (stage) ஒரு ஜெனரேட்டர் ஆகும் — அது முந்தைய நிலையிலிருந்து உள்ளீட்டைப் பெற்று, செயலாக்கி, அடுத்த நிலைக்கு வெளியீட்டை yield செய்கிறது. முழு தரவுத்தொகுப்பையும் நினைவகத்தில் ஏற்றாமலேயே, தரவு ஒரு நேரத்தில் ஒரு உருப்படியாக பைப்லைன் வழியாகப் பாய்கிறது.

அறிமுகம்

நினைவகத்தை விட பெரிய தரவுத்தொகுப்புகளை — log கோப்புகள், பயிற்சி corpus-கள், JSONL ஏற்றுமதிகள் — செயலாக்க வேண்டியிருக்கும்போது, எல்லாவற்றையும் ஒரே நேரத்தில் (eagerly) ஏற்றுவது சாத்தியமில்லை. ஜெனரேட்டர் பைப்லைன்கள் ஒரு பதிவை (record) பல மாற்ற நிலைகள் வழியாக ஸ்ட்ரீம் செய்ய அனுமதிக்கின்றன — எந்த நேரத்திலும் ஒரே ஒரு உருப்படியை மட்டுமே நினைவகத்தில் வைத்திருக்கும். இதைத் தவறாகச் செய்தால், pod-ஐ OOM ஆக்குவீர்கள், நினைவக வரம்புகளைத் தாண்டுவீர்கள், அல்லது முடிவடையாத ஒரு load படிநிலைக்காக மணிக்கணக்கில் காத்திருப்பீர்கள். இந்தப் பாடத்தின் முடிவில், ஜெனரேட்டர்களை பல-நிலை பைப்லைன்களாக இணைக்கவும், RAM-ஐ விட பெரிய கோப்புகளைச் செயலாக்கவும், துணை-ஜெனரேட்டர்களுக்கு ஒப்படைக்க (delegate) yield from-ஐப் பயன்படுத்தவும் உங்களால் முடியும்.

முக்கிய சொற்கள்

  • Pipeline stage (பைப்லைன் நிலை) — மேல்நிலை (upstream) iterable-இலிருந்து நுகர்ந்து, கீழ்நிலை (downstream) நுகர்வோருக்கு yield செய்யும் ஒற்றை ஜெனரேட்டர் செயல்பாடு; இந்த நிலைகளை இணைத்து (compose) பைப்லைன்கள் கட்டமைக்கப்படுகின்றன, இதனால் தரவு ஒரு நேரத்தில் ஒரு உருப்படியாகப் பாய்கிறது.
  • Lazy evaluation (சோம்பேறி மதிப்பீடு) — நுகர்வோர் ஒரு மதிப்பை இழுக்கும் வரை வேலை ஒத்திவைக்கப்படுகிறது; இதுவே ஒரு பல-நிலை பைப்லைன் கிகாபைட் அளவிலான உள்ளீடுகளை மாறாத (constant) நினைவகத்துடன் செயலாக்க அனுமதிக்கிறது.
  • yield from — Python 3.3+ இல் அறிமுகமான ஒரு statement; இது iteration-ஐ ஒரு துணை-ஜெனரேட்டருக்கோ அல்லது எந்த iterable-க்கோ ஒப்படைக்கிறது. ஜெனரேட்டர்களை இணைக்கவும், கைமுறை loops இல்லாமல் உள்ளமைந்த (nested) கட்டமைப்புகளைத் தட்டையாக்கவும் (flatten) இது நிலையான கருவி.
  • ETL — extract-transform-load, நியதியான (canonical) தரவு-பைப்லைன் pattern; இதில் ஒவ்வொரு படிநிலையும் (read, filter, parse, extract) இயல்பாகவே ஒரு ஜெனரேட்டர் நிலையாக வெளிப்படுத்தக்கூடியது.

கருத்துகள்

ஜெனரேட்டர்களை சங்கிலியாக இணைத்தல்

ஒரு பைப்லைன் என்பது ஜெனரேட்டர் செயல்பாடுகளின் சங்கிலியே — ஒவ்வொரு நிலையும் அதன் முந்தையதிலிருந்து இழுத்து, அதன் அடுத்ததற்கு yield செய்கிறது. ஒவ்வொரு நிலையும் lazy என்பதால், ஒரு இறுதி (terminal) நுகர்வோர் iterate செய்யும் வரை எந்த வேலையும் நடக்காது — அந்தத் தருணத்தில், அடுத்த பதிவு இழுக்கப்படும் முன் சரியாக ஒரு பதிவு மட்டுமே சங்கிலி முழுவதும் கடந்து செல்கிறது. LLM வெளியீடுகளைச் செயலாக்குதல், தரவுத்தொகுப்புகளை மாற்றுதல், திறமையான ETL workflows-ஐ உருவாக்குதல் ஆகியவற்றுக்கு இதுவே அடித்தளம் (Code Walkthrough பார்க்கவும்).

Loading diagram...

அம்புக்குறிகள் தள்ளுதலை (push) அல்ல, தேவையை (demand) குறிக்கின்றன: நுகர்வோர் extract_field-இடம் ஒரு மதிப்பைக் கேட்கிறது, அது parse_json_lines-ஐக் கேட்கிறது, அது filter_non_empty-ஐக் கேட்கிறது, அது read_lines-ஐக் கேட்கிறது, அது வட்டிலிருந்து (disk) சரியாக ஒரு வரியைப் படிக்கிறது. கோப்பின் அளவு எதுவாக இருந்தாலும் நினைவகப் பயன்பாடு சமமாகவே இருக்கும்.

RAM-ஐ விட பெரிய கோப்புகளை ஸ்ட்ரீம் செய்தல்

திறந்த கோப்பு object-ஐ iterate செய்வது (for line in open(filename)) கோப்பை முழுவதுமாக விழுங்காமல் ஒரு நேரத்தில் ஒரு வரியை yield செய்கிறது — இதுவே நியதியான குறைந்த-நினைவக ஸ்ட்ரீமிங் idiom. மேலே உள்ள பைப்லைன் pattern-உடன் இணைந்து, சில நூறு மெகாபைட் RAM மட்டுமே உள்ள ஒரு pod-இல் பல-கிகாபைட் பயிற்சி corpus-களையோ log காப்பகங்களையோ இப்படித்தான் செயலாக்குவீர்கள். ஒப்பந்தம் (contract): எந்த நேரத்திலும் ஒரே ஒரு பதிவு (நீங்கள் வைத்திருக்கும் running counters எதுவும் சேர்த்து) மட்டுமே நினைவகத்தில் இருக்கும்.

yield from மூலம் ஒப்படைத்தல் (Delegation)

Iteration-ஐ ஒரு துணை-ஜெனரேட்டருக்கோ அல்லது எந்த iterable-க்கோ ஒற்றை statement-இல் ஒப்படைக்க Python 3.3 yield from-ஐ அறிமுகப்படுத்தியது. இது இரண்டு சூழ்நிலைகளுக்குச் சரியான கருவி: ஜெனரேட்டர்களை இணைத்தல் (பல மூலங்களை ஒரே ஸ்ட்ரீமாக இணைத்தல்) மற்றும் உள்ளமைந்த கட்டமைப்புகளின் மீது recursion செய்தல் (கைமுறை stack மேலாண்மை இல்லாமல் மரங்களைத் தட்டையாக்குதல்). வெறும் syntactic sugar-ஐத் தாண்டி, இது send(), throw() மற்றும் return மதிப்புகளை ஒப்படைக்கப்பட்ட ஜெனரேட்டருக்குச் சரியாக அனுப்புகிறது — கையால் எழுதப்பட்ட for x in sub: yield x loop தவறாகச் செய்யும் ஒன்று இது (Code Walkthrough பார்க்கவும்).

Code Walkthrough

ஒவ்வொரு பைப்லைன் நிலையும் அதன் முந்தையதிலிருந்து எப்படி lazy-ஆக இழுக்கிறது என்பதை இப்போது பார்த்துவிட்டீர்கள்; அந்த இணைப்பு (wiring) code-இல் எப்படி இருக்கும் என்பது இதோ.

முதல் snippet, கருத்துகள் பிரிவில் உள்ள வரைபடத்தின் நான்கு நிலைகளையும் — read_lines, filter_non_empty, parse_json_lines, மற்றும் extract_field — ஒரே JSONL செயலியாக இணைத்து செயல்படுத்துகிறது. இரண்டாவது snippet, recursive தட்டையாக்கல் மற்றும் மூல-இணைப்பு (source concatenation) இரண்டிற்கும் yield from-ஐ விளக்குகிறது.

Code snippetpython
1def read_lines(filename): 2 """Stage 1: yield one stripped line at a time from a file.""" 3 with open(filename, 'r') as f: 4 for line in f: 5 yield line.strip() 6 7def filter_non_empty(lines): 8 """Stage 2: drop blank lines.""" 9 for line in lines: 10 if line: 11 yield line 12 13def parse_json_lines(lines): 14 """Stage 3: parse JSON, skipping malformed records.""" 15 import json 16 for line in lines: 17 try: 18 yield json.loads(line) 19 except json.JSONDecodeError: 20 continue 21 22def extract_field(records, field): 23 """Stage 4: project a single field out of each record.""" 24 for record in records: 25 if field in record: 26 yield record[field] 27 28# Compose: no I/O has happened yet. 29lines = read_lines('data.jsonl') 30non_empty = filter_non_empty(lines) 31records = parse_json_lines(non_empty) 32texts = extract_field(records, 'text') 33 34# Iteration is what makes data flow through the chain. 35for text in texts: 36 print(text)
  • read_lines: for line in f கோப்பை lazy-ஆக ஸ்ட்ரீம் செய்கிறது — ஒரு நேரத்தில் ஒரே ஒரு வரி மட்டுமே நினைவகத்தில் இருக்கும், எனவே பல-GB உள்ளீடுகள் சிக்கலின்றி வேலை செய்யும்.
  • filter_non_empty / parse_json_lines / extract_field: ஒவ்வொன்றும் ஒற்றை-நோக்க நிலை — முந்தையதிலிருந்து இழுத்து கீழ்நோக்கி yield செய்கிறது. குறுகலான except json.JSONDecodeError-ஐக் கவனியுங்கள் — நாம் parse தோல்விகளை மட்டுமே தவிர்க்கிறோம், எல்லா exception-களையும் அல்ல.
  • Composition: texts-ஐ உருவாக்குவது கோப்பைப் படிக்காது; for text in texts loop-தான் பதிவுகளை முழு பைப்லைன் வழியாகவும், ஒரு நேரத்தில் ஒன்றாக, இழுக்கிறது.
Code snippetpython
1def flatten(nested_list): 2 """Recursively flatten a nested list using yield from.""" 3 for item in nested_list: 4 if isinstance(item, list): 5 yield from flatten(item) 6 else: 7 yield item 8 9def combined_sources(*iterables): 10 """Concatenate any number of iterables into one stream.""" 11 for iterable in iterables: 12 yield from iterable 13 14print(list(flatten([1, [2, 3, [4, 5]], 6, [7, [8, 9]]]))) 15# [1, 2, 3, 4, 5, 6, 7, 8, 9] 16 17print(list(combined_sources([1, 2], [3, 4], [5, 6]))) 18# [1, 2, 3, 4, 5, 6]
  • flatten: yield from flatten(item) உள்ளமைந்த பட்டியல்களுக்குள் recursion செய்கிறது; இலைகள் (leaves) நேரடியாக yield செய்யப்படுகின்றன. ஒவ்வொரு மதிப்பும் அடைந்தவுடனேயே வெளிவருகிறது — இடைநிலை பட்டியல்களின் stack எதுவும் இல்லை.
  • combined_sources: yield from iterable ஜெனரேட்டர்களுக்கு மட்டுமல்ல, எந்த iterable-க்கும் வேலை செய்கிறது — ஸ்ட்ரீம்களை ஒன்றாக இணைக்க இது ஒரு ஒற்றை-வரி வழி.

JSONL பைப்லைனை ஒரு சிறிய கோப்பின் மீது இயக்கி, ஒவ்வொரு பதிவிற்கும் text field-ஐ மட்டும் காணும்போதும், உள்ளீட்டின் அளவு வளர்ந்தாலும் நினைவகப் பயன்பாடு சமமாக இருப்பதைக் கவனிக்கும்போதும் — மேலும் list(flatten(...)) எவ்வளவு ஆழமாக உள்ளமைந்த உள்ளீட்டிற்கும் எதிர்பார்க்கப்படும் தட்டையான வரிசையை உருவாக்கும்போதும் — அது வேலை செய்கிறது என்பதை அறிவீர்கள்.

-க்கான நடைமுறையில்

Code Walkthrough-இல் உள்ள பைப்லைன் pattern-ஐ அடிப்படையாகக் கொண்டு, அது உங்கள் அன்றாட வேலையில் எப்படி வெளிப்படுகிறது என்பது இதோ.

செய்ய வேண்டியவை மற்றும் செய்யக்கூடாதவை

செய்ய வேண்டியவை

  1. சிறிய, ஒற்றை-நோக்க நிலைகளை இணைத்து உருவாக்குங்கள் — ஒவ்வொரு ஜெனரேட்டர் செயல்பாடும் ஒரே ஒரு விஷயத்தை read, filter, parse அல்லது extract செய்ய வேண்டும்; அவற்றை இணைப்பது பைப்லைனைச் சோதிக்கவும் வரிசை மாற்றவும் எளிதாக வைத்திருக்கும்.
  2. கோப்பை for line in open(...) மூலம் நேரடியாக iterate செய்யுங்கள் — இதுவே நியதியான குறைந்த-நினைவக ஸ்ட்ரீமிங் idiom; கோப்பின் அளவு எதுவாக இருந்தாலும் RAM பயன்பாட்டைச் சமமாக வைத்திருக்கும்.
  3. கைமுறை துணை-iteration-ஐ விட yield from-ஐ விரும்புங்கள் — துணை-ஜெனரேட்டர்களுக்கு ஒப்படைப்பது exception propagation மற்றும் send()/return மதிப்பு அனுப்புதல் தொடர்பான நுட்பமான bugs-ஐத் தவிர்க்கிறது.

செய்யக்கூடாதவை

  1. மேல்நிலை ஸ்ட்ரீமின் மீது f.read() அல்லது list(...) அழைக்காதீர்கள் — இரண்டும் முழு தரவுத்தொகுப்பையும் நினைவகத்தில் உருவாக்கி (materialize), lazy பைப்லைனின் நோக்கத்தையே தோற்கடிக்கின்றன.
  2. Exception-ஐப் பிடித்து விழுங்காதீர்கள் — உங்கள் except-ஐ நீங்கள் எதிர்பார்க்கும் குறிப்பிட்ட பிழைக்கு (எ.கா. json.JSONDecodeError) குறுக்குங்கள்; இல்லையெனில் உண்மையான bugs ஒரு continue-க்குப் பின்னால் மறைந்துவிடும்.
  3. தீர்ந்துபோன (exhausted) ஜெனரேட்டர் object-ஐ மீண்டும் பயன்படுத்தாதீர்கள் — ஜெனரேட்டர்கள் ஒரு-முறை iterators; மீண்டும் iterate செய்ய வேண்டுமெனில் புதிய பைப்லைனை உருவாக்குங்கள்.

A hands-on lab comes with this lesson — real code, in a cloud IDE. Create a free account to run it. No card.

Free account · no card · straight to the lab

Or get the full path — from

Listen to this lesson

Audio overviews of this lesson's labs and its chapter, from GenBodha Bytes.

More free lessons in LLM Foundations for Agent Builders

All free lessons in GenAI Agent Engineering →