[{"data":1,"prerenderedAt":1070},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fpydantic-llm":46,"\u002Fblog\u002Fpydantic-llm-surround":1065},[4],{"title":5,"path":6,"stem":7,"children":8,"page":45},"Blog","\u002Fblog","blog",[9,13,17,21,25,29,33,37,41],{"title":10,"path":11,"stem":12},"Audio Augmentation Techniques for Deep Learning","\u002Fblog\u002Faudio-augmentation","blog\u002Faudio-augmentation",{"title":14,"path":15,"stem":16},"Speed Up Whisper with CTranslate2","\u002Fblog\u002Fc-translate","blog\u002Fc-translate",{"title":18,"path":19,"stem":20},"Calling C++ and Go from Dart using FFI","\u002Fblog\u002Fdart-ffi-native-bridge","blog\u002Fdart-ffi-native-bridge",{"title":22,"path":23,"stem":24},"Russey Keo High School Memories","\u002Fblog\u002Fmemory","blog\u002Fmemory",{"title":26,"path":27,"stem":28},"My Dev Setup: Same Keys Everywhere","\u002Fblog\u002Fmy-dev-setup","blog\u002Fmy-dev-setup",{"title":30,"path":31,"stem":32},"Data Extraction with LangChain and Ollama Locally","\u002Fblog\u002Fpydantic-llm","blog\u002Fpydantic-llm",{"title":34,"path":35,"stem":36},"7-Segment LED Display with Proteus Simulation","\u002Fblog\u002Fseven-segment","blog\u002Fseven-segment",{"title":38,"path":39,"stem":40},"Understanding JWT Refresh Token Rotation & Revocation","\u002Fblog\u002Funderstand-refresh-token","blog\u002Funderstand-refresh-token",{"title":42,"path":43,"stem":44},"Khmer Speech Recognition","\u002Fblog\u002Fwhisper","blog\u002Fwhisper",false,{"id":47,"title":30,"author":48,"body":52,"date":1055,"description":1056,"extension":1057,"image":1058,"meta":1059,"minRead":105,"navigation":415,"path":31,"seo":1063,"stem":32,"__hash__":1064},"blog\u002Fblog\u002Fpydantic-llm.md",{"name":49,"avatar":50},"Phanith LIM",{"src":51,"alt":49},"\u002Fmyprofile.jpg",{"type":53,"value":54,"toc":1046},"minimark",[55,59,62,67,123,149,153,253,257,264,470,474,480,536,539,543,550,601,605,608,754,764,768,826,1014,1022,1042],[56,57,58],"p",{},"An LLM will happily answer \"give me the top 10 phones\" in prose. What I want is rows I can put in a DataFrame.",[56,60,61],{},"Here is how I do that on my own machine: Pydantic describes the shape I expect, LangChain's output parser forces the model to answer in that shape, and pandas takes it from there. Nothing leaves the laptop.",[63,64,66],"h3",{"id":65},"_1-install","1. Install",[68,69,74],"pre",{"className":70,"code":71,"language":72,"meta":73,"style":73},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pip install langchain\npip install ollama\npip install pydantic\npip install pandas\n","bash","",[75,76,77,93,103,113],"code",{"__ignoreMap":73},[78,79,82,86,90],"span",{"class":80,"line":81},"line",1,[78,83,85],{"class":84},"sBMFI","pip",[78,87,89],{"class":88},"sfazB"," install",[78,91,92],{"class":88}," langchain\n",[78,94,96,98,100],{"class":80,"line":95},2,[78,97,85],{"class":84},[78,99,89],{"class":88},[78,101,102],{"class":88}," ollama\n",[78,104,106,108,110],{"class":80,"line":105},3,[78,107,85],{"class":84},[78,109,89],{"class":88},[78,111,112],{"class":88}," pydantic\n",[78,114,116,118,120],{"class":80,"line":115},4,[78,117,85],{"class":84},[78,119,89],{"class":88},[78,121,122],{"class":88}," pandas\n",[124,125,126,132],"blockquote",{},[56,127,128],{},[129,130,131],"strong",{},"You need Ollama running",[56,133,134,135,142,143,148],{},"Install ",[136,137,141],"a",{"href":138,"rel":139},"https:\u002F\u002Follama.com\u002F",[140],"nofollow","Ollama",", open it, and let the server start. If it is new to you, these ",[136,144,147],{"href":145,"rel":146},"https:\u002F\u002Fwww.hostinger.com\u002Ftutorials\u002Follama-cli-tutorial",[140],"command-line basics"," cover enough to get going.",[63,150,152],{"id":151},"_2-imports","2. Imports",[68,154,158],{"className":155,"code":156,"language":157,"meta":73,"style":73},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","from pydantic import BaseModel, Field\nfrom langchain_ollama.llms import OllamaLLM\nfrom langchain.output_parsers import PydanticOutputParser\nfrom langchain.prompts import HumanMessagePromptTemplate, ChatPromptTemplate\nimport pandas as pd\n","python",[75,159,160,183,201,218,239],{"__ignoreMap":73},[78,161,162,166,170,173,176,180],{"class":80,"line":81},[78,163,165],{"class":164},"s7zQu","from",[78,167,169],{"class":168},"sTEyZ"," pydantic ",[78,171,172],{"class":164},"import",[78,174,175],{"class":168}," BaseModel",[78,177,179],{"class":178},"sMK4o",",",[78,181,182],{"class":168}," Field\n",[78,184,185,187,190,193,196,198],{"class":80,"line":95},[78,186,165],{"class":164},[78,188,189],{"class":168}," langchain_ollama",[78,191,192],{"class":178},".",[78,194,195],{"class":168},"llms ",[78,197,172],{"class":164},[78,199,200],{"class":168}," OllamaLLM\n",[78,202,203,205,208,210,213,215],{"class":80,"line":105},[78,204,165],{"class":164},[78,206,207],{"class":168}," langchain",[78,209,192],{"class":178},[78,211,212],{"class":168},"output_parsers ",[78,214,172],{"class":164},[78,216,217],{"class":168}," PydanticOutputParser\n",[78,219,220,222,224,226,229,231,234,236],{"class":80,"line":115},[78,221,165],{"class":164},[78,223,207],{"class":168},[78,225,192],{"class":178},[78,227,228],{"class":168},"prompts ",[78,230,172],{"class":164},[78,232,233],{"class":168}," HumanMessagePromptTemplate",[78,235,179],{"class":178},[78,237,238],{"class":168}," ChatPromptTemplate\n",[78,240,242,244,247,250],{"class":80,"line":241},5,[78,243,172],{"class":164},[78,245,246],{"class":168}," pandas ",[78,248,249],{"class":164},"as",[78,251,252],{"class":168}," pd\n",[63,254,256],{"id":255},"_3-describe-what-you-want-back","3. Describe what you want back",[56,258,259,260,263],{},"The Pydantic model is the contract. Each ",[75,261,262],{},"description"," is a hint the model actually reads, so it is worth writing them properly.",[68,265,267],{"className":155,"code":266,"language":157,"meta":73,"style":73},"class PhoneModel(BaseModel):\n    brand: str = Field(description=\"Brand of the phone\")\n    model: str = Field(description=\"Model of the phone\")\n    year: int = Field(description=\"Year of the phone\")\n    price: float = Field(description=\"Price of the phone\")\n\nclass PhonesModel(BaseModel):\n    phones: list[PhoneModel] = Field(description=\"List of phones\")\n",[75,268,269,287,324,352,381,410,417,431],{"__ignoreMap":73},[78,270,271,275,278,281,284],{"class":80,"line":81},[78,272,274],{"class":273},"spNyl","class",[78,276,277],{"class":84}," PhoneModel",[78,279,280],{"class":178},"(",[78,282,283],{"class":84},"BaseModel",[78,285,286],{"class":178},"):\n",[78,288,289,292,295,298,301,305,307,310,313,316,319,321],{"class":80,"line":95},[78,290,291],{"class":168},"    brand",[78,293,294],{"class":178},":",[78,296,297],{"class":84}," str",[78,299,300],{"class":178}," =",[78,302,304],{"class":303},"s2Zo4"," Field",[78,306,280],{"class":178},[78,308,262],{"class":309},"sHdIc",[78,311,312],{"class":178},"=",[78,314,315],{"class":178},"\"",[78,317,318],{"class":88},"Brand of the phone",[78,320,315],{"class":178},[78,322,323],{"class":178},")\n",[78,325,326,329,331,333,335,337,339,341,343,345,348,350],{"class":80,"line":105},[78,327,328],{"class":168},"    model",[78,330,294],{"class":178},[78,332,297],{"class":84},[78,334,300],{"class":178},[78,336,304],{"class":303},[78,338,280],{"class":178},[78,340,262],{"class":309},[78,342,312],{"class":178},[78,344,315],{"class":178},[78,346,347],{"class":88},"Model of the phone",[78,349,315],{"class":178},[78,351,323],{"class":178},[78,353,354,357,359,362,364,366,368,370,372,374,377,379],{"class":80,"line":115},[78,355,356],{"class":168},"    year",[78,358,294],{"class":178},[78,360,361],{"class":84}," int",[78,363,300],{"class":178},[78,365,304],{"class":303},[78,367,280],{"class":178},[78,369,262],{"class":309},[78,371,312],{"class":178},[78,373,315],{"class":178},[78,375,376],{"class":88},"Year of the phone",[78,378,315],{"class":178},[78,380,323],{"class":178},[78,382,383,386,388,391,393,395,397,399,401,403,406,408],{"class":80,"line":241},[78,384,385],{"class":168},"    price",[78,387,294],{"class":178},[78,389,390],{"class":84}," float",[78,392,300],{"class":178},[78,394,304],{"class":303},[78,396,280],{"class":178},[78,398,262],{"class":309},[78,400,312],{"class":178},[78,402,315],{"class":178},[78,404,405],{"class":88},"Price of the phone",[78,407,315],{"class":178},[78,409,323],{"class":178},[78,411,413],{"class":80,"line":412},6,[78,414,416],{"emptyLinePlaceholder":415},true,"\n",[78,418,420,422,425,427,429],{"class":80,"line":419},7,[78,421,274],{"class":273},[78,423,424],{"class":84}," PhonesModel",[78,426,280],{"class":178},[78,428,283],{"class":84},[78,430,286],{"class":178},[78,432,434,437,439,442,445,448,451,453,455,457,459,461,463,466,468],{"class":80,"line":433},8,[78,435,436],{"class":168},"    phones",[78,438,294],{"class":178},[78,440,441],{"class":168}," list",[78,443,444],{"class":178},"[",[78,446,447],{"class":168},"PhoneModel",[78,449,450],{"class":178},"]",[78,452,300],{"class":178},[78,454,304],{"class":303},[78,456,280],{"class":178},[78,458,262],{"class":309},[78,460,312],{"class":178},[78,462,315],{"class":178},[78,464,465],{"class":88},"List of phones",[78,467,315],{"class":178},[78,469,323],{"class":178},[63,471,473],{"id":472},"_4-turn-the-schema-into-instructions","4. Turn the schema into instructions",[56,475,476,479],{},[75,477,478],{},"PydanticOutputParser"," writes the formatting instructions for you and parses the reply back into your objects.",[68,481,483],{"className":155,"code":482,"language":157,"meta":73,"style":73},"output_parser = PydanticOutputParser(pydantic_object = PhonesModel)\nformat_instructions = output_parser.get_format_instructions()\nprint(format_instructions)\n",[75,484,485,506,524],{"__ignoreMap":73},[78,486,487,490,492,495,497,500,502,504],{"class":80,"line":81},[78,488,489],{"class":168},"output_parser ",[78,491,312],{"class":178},[78,493,494],{"class":303}," PydanticOutputParser",[78,496,280],{"class":178},[78,498,499],{"class":309},"pydantic_object",[78,501,300],{"class":178},[78,503,424],{"class":303},[78,505,323],{"class":178},[78,507,508,511,513,516,518,521],{"class":80,"line":95},[78,509,510],{"class":168},"format_instructions ",[78,512,312],{"class":178},[78,514,515],{"class":168}," output_parser",[78,517,192],{"class":178},[78,519,520],{"class":303},"get_format_instructions",[78,522,523],{"class":178},"()\n",[78,525,526,529,531,534],{"class":80,"line":105},[78,527,528],{"class":303},"print",[78,530,280],{"class":178},[78,532,533],{"class":303},"format_instructions",[78,535,323],{"class":178},[56,537,538],{},"Print them once and read them. That text is what the model is being told.",[63,540,542],{"id":541},"_5-pick-a-local-model","5. Pick a local model",[56,544,545,546,549],{},"Pull whichever model you want from Ollama. I used ",[75,547,548],{},"llama3.2:3b"," here, with temperature at 0 so the output stays repeatable.",[68,551,553],{"className":155,"code":552,"language":157,"meta":73,"style":73},"model = OllamaLLM(\n    model='llama3.2:3b',\n    temperature=0.0,\n)\n",[75,554,555,568,584,597],{"__ignoreMap":73},[78,556,557,560,562,565],{"class":80,"line":81},[78,558,559],{"class":168},"model ",[78,561,312],{"class":178},[78,563,564],{"class":303}," OllamaLLM",[78,566,567],{"class":178},"(\n",[78,569,570,572,574,577,579,581],{"class":80,"line":95},[78,571,328],{"class":309},[78,573,312],{"class":178},[78,575,576],{"class":178},"'",[78,578,548],{"class":88},[78,580,576],{"class":178},[78,582,583],{"class":178},",\n",[78,585,586,589,591,595],{"class":80,"line":105},[78,587,588],{"class":309},"    temperature",[78,590,312],{"class":178},[78,592,594],{"class":593},"sbssI","0.0",[78,596,583],{"class":178},[78,598,599],{"class":80,"line":115},[78,600,323],{"class":178},[63,602,604],{"id":603},"_6-chain-prompt-model-and-parser","6. Chain prompt, model, and parser",[56,606,607],{},"The prompt carries my instruction plus the format instructions. The pipe operator puts the three pieces in a row, which is where the name LangChain comes from.",[68,609,611],{"className":155,"code":610,"language":157,"meta":73,"style":73},"human_text = \"{instruction}\\n{format_instructions}\"\nmessage = HumanMessagePromptTemplate.from_template(human_text)\nprompt = ChatPromptTemplate.from_messages([message])\n\nchain = prompt | model | output_parser\nproducts = chain.invoke({\"instruction\":\"Give top 10 popular phone now\", \"format_instructions\":format_instructions})\n",[75,612,613,635,656,680,684,705],{"__ignoreMap":73},[78,614,615,618,620,623,626,629,632],{"class":80,"line":81},[78,616,617],{"class":168},"human_text ",[78,619,312],{"class":178},[78,621,622],{"class":178}," \"",[78,624,625],{"class":593},"{instruction}",[78,627,628],{"class":168},"\\n",[78,630,631],{"class":593},"{format_instructions}",[78,633,634],{"class":178},"\"\n",[78,636,637,640,642,644,646,649,651,654],{"class":80,"line":95},[78,638,639],{"class":168},"message ",[78,641,312],{"class":178},[78,643,233],{"class":168},[78,645,192],{"class":178},[78,647,648],{"class":303},"from_template",[78,650,280],{"class":178},[78,652,653],{"class":303},"human_text",[78,655,323],{"class":178},[78,657,658,661,663,666,668,671,674,677],{"class":80,"line":105},[78,659,660],{"class":168},"prompt ",[78,662,312],{"class":178},[78,664,665],{"class":168}," ChatPromptTemplate",[78,667,192],{"class":178},[78,669,670],{"class":303},"from_messages",[78,672,673],{"class":178},"([",[78,675,676],{"class":303},"message",[78,678,679],{"class":178},"])\n",[78,681,682],{"class":80,"line":115},[78,683,416],{"emptyLinePlaceholder":415},[78,685,686,689,691,694,697,700,702],{"class":80,"line":241},[78,687,688],{"class":168},"chain ",[78,690,312],{"class":178},[78,692,693],{"class":168}," prompt ",[78,695,696],{"class":178},"|",[78,698,699],{"class":168}," model ",[78,701,696],{"class":178},[78,703,704],{"class":168}," output_parser\n",[78,706,707,710,712,715,717,720,723,725,728,730,732,734,737,739,741,743,745,747,749,751],{"class":80,"line":412},[78,708,709],{"class":168},"products ",[78,711,312],{"class":178},[78,713,714],{"class":168}," chain",[78,716,192],{"class":178},[78,718,719],{"class":303},"invoke",[78,721,722],{"class":178},"({",[78,724,315],{"class":178},[78,726,727],{"class":88},"instruction",[78,729,315],{"class":178},[78,731,294],{"class":178},[78,733,315],{"class":178},[78,735,736],{"class":88},"Give top 10 popular phone now",[78,738,315],{"class":178},[78,740,179],{"class":178},[78,742,622],{"class":178},[78,744,533],{"class":88},[78,746,315],{"class":178},[78,748,294],{"class":178},[78,750,533],{"class":303},[78,752,753],{"class":178},"})\n",[56,755,756,759,760,763],{},[75,757,758],{},"products"," is a ",[75,761,762],{},"PhonesModel",", not a string. If the model answers in the wrong shape, the parser raises instead of quietly handing me junk.",[63,765,767],{"id":766},"_7-into-a-dataframe","7. Into a DataFrame",[68,769,771],{"className":155,"code":770,"language":157,"meta":73,"style":73},"df = pd.DataFrame([product.model_dump() for product in products.phones])\ndf\n",[75,772,773,821],{"__ignoreMap":73},[78,774,775,778,780,783,785,788,790,793,795,798,801,804,807,810,813,815,819],{"class":80,"line":81},[78,776,777],{"class":168},"df ",[78,779,312],{"class":178},[78,781,782],{"class":168}," pd",[78,784,192],{"class":178},[78,786,787],{"class":303},"DataFrame",[78,789,673],{"class":178},[78,791,792],{"class":303},"product",[78,794,192],{"class":178},[78,796,797],{"class":303},"model_dump",[78,799,800],{"class":178},"()",[78,802,803],{"class":164}," for",[78,805,806],{"class":303}," product ",[78,808,809],{"class":164},"in",[78,811,812],{"class":303}," products",[78,814,192],{"class":178},[78,816,818],{"class":817},"swJcz","phones",[78,820,679],{"class":178},[78,822,823],{"class":80,"line":95},[78,824,825],{"class":168},"df\n",[827,828,829,850],"table",{},[830,831,832],"thead",{},[833,834,835,838,841,844,847],"tr",{},[836,837],"th",{},[836,839,840],{},"brand",[836,842,843],{},"model",[836,845,846],{},"year",[836,848,849],{},"price",[851,852,853,871,887,903,919,935,951,967,983,999],"tbody",{},[833,854,855,859,862,865,868],{},[856,857,858],"td",{},"0",[856,860,861],{},"Apple",[856,863,864],{},"iPhone 13",[856,866,867],{},"2021",[856,869,870],{},"699.0",[833,872,873,876,879,882,884],{},[856,874,875],{},"1",[856,877,878],{},"Samsung",[856,880,881],{},"Galaxy S21",[856,883,867],{},[856,885,886],{},"799.0",[833,888,889,892,895,898,900],{},[856,890,891],{},"2",[856,893,894],{},"Google",[856,896,897],{},"Pixel 6",[856,899,867],{},[856,901,902],{},"599.0",[833,904,905,908,911,914,916],{},[856,906,907],{},"3",[856,909,910],{},"OnePlus",[856,912,913],{},"9 Pro",[856,915,867],{},[856,917,918],{},"969.0",[833,920,921,924,927,930,932],{},[856,922,923],{},"4",[856,925,926],{},"Xiaomi",[856,928,929],{},"Mi 11",[856,931,867],{},[856,933,934],{},"749.0",[833,936,937,940,943,946,948],{},[856,938,939],{},"5",[856,941,942],{},"Oppo",[856,944,945],{},"Find X3 Pro",[856,947,867],{},[856,949,950],{},"1149.0",[833,952,953,956,959,962,965],{},[856,954,955],{},"6",[856,957,958],{},"Realme",[856,960,961],{},"GT 2 Pro",[856,963,964],{},"2022",[856,966,902],{},[833,968,969,972,975,978,980],{},[856,970,971],{},"7",[856,973,974],{},"Vivo",[856,976,977],{},"X70 Pro",[856,979,867],{},[856,981,982],{},"899.0",[833,984,985,988,991,994,996],{},[856,986,987],{},"8",[856,989,990],{},"Sony",[856,992,993],{},"Xperia 1 III",[856,995,867],{},[856,997,998],{},"1299.0",[833,1000,1001,1004,1007,1010,1012],{},[856,1002,1003],{},"9",[856,1005,1006],{},"Motorola",[856,1008,1009],{},"Edge 30 Pro",[856,1011,964],{},[856,1013,886],{},[56,1015,1016,1017,1021],{},"One thing worth saying out loud: the model made these numbers up from what it remembers. The schema guarantees the ",[1018,1019,1020],"em",{},"shape"," of the answer, never the truth of it. For anything that matters, check the values against a real source.",[68,1023,1025],{"className":155,"code":1024,"language":157,"meta":73,"style":73},"print(\"Thank you for reading!\")\n",[75,1026,1027],{"__ignoreMap":73},[78,1028,1029,1031,1033,1035,1038,1040],{"class":80,"line":81},[78,1030,528],{"class":303},[78,1032,280],{"class":178},[78,1034,315],{"class":178},[78,1036,1037],{"class":88},"Thank you for reading!",[78,1039,315],{"class":178},[78,1041,323],{"class":178},[1043,1044,1045],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":73,"searchDepth":95,"depth":95,"links":1047},[1048,1049,1050,1051,1052,1053,1054],{"id":65,"depth":105,"text":66},{"id":151,"depth":105,"text":152},{"id":255,"depth":105,"text":256},{"id":472,"depth":105,"text":473},{"id":541,"depth":105,"text":542},{"id":603,"depth":105,"text":604},{"id":766,"depth":105,"text":767},"2025-03-01","Getting typed rows out of a local LLM with Pydantic and LangChain.","md","\u002Fblog\u002Fpydantic-llm\u002Fcover.jpg",{"tags":1060},[1061,1062],"Machine Learning","Python",{"title":30,"description":1056},"5cjs_kXCP4cAoBKbVN2gF4q1hmoVlkH19jgBkD_Nk88",[1066,1068],{"title":26,"path":27,"stem":28,"description":1067,"children":-1},"Omarchy, Neovim, tmux, IntelliJ and a split keyboard, set up so one habit works in every tool.",{"title":34,"path":35,"stem":36,"description":1069,"children":-1},"Turning four input bits into ten digits with K-maps, then simulating the circuit in Proteus.",1791981009297]