geo-sleuth คือสกิลสำหรับ AI agent ที่ตามหาพิกัดจากรูปถ่ายด้วย OpenStreetMap เส้นขอบฟ้า ดาวเทียม และ street view พร้อมแสดงหลักฐานทุกขั้น ไม่ตอบแค่พิกัดลอยๆ
geo-sleuth ให้ AI agent ตามหาพิกัดภาพด้วยแผนที่ เส้นขอบฟ้า ดาวเทียม และ street view ดูการไล่เบาะแสในภาพไร้ตัวหนังสือจนเหลือจุดเดียว พร้อมไฟล์หลักฐานทุกขั้น

geo-sleuth เป็นชุดทักษะเสริมสำหรับ AI Agent หรือ Agent Skill ที่รวมคู่มือและสคริปต์ Python เอาไว้ให้ AI ใช้งาน โดยรับภาพถ่ายมา 1 ใบ แล้วช่วยสืบหาว่าภาพนั้นถ่ายจากจุดไหนบนโลก จุดเด่นที่ทำให้ต่างจากการส่งรูปไปถาม AI ทั่วไป คือทุกข้อสรุปต้องมีที่มาที่ไป ระบุได้ชัดเจนว่ามาจากคำสั่งใดที่รันจริง และเกิดจากไฟล์หลักฐานชิ้นไหน ส่วนเรื่องความโด่งดังของสถานที่หรือจำนวนประชากรในพื้นที่ โปรเจกต์นี้ระบุชัดเจนว่าจะไม่นำมานับเป็นหลักฐานในการตัดสิน
การสืบหาไม่ได้พึ่งพาป้ายข้อความ ป้ายทะเบียนรถ หรือแลนด์มาร์กชื่อดัง แต่ใช้วิธีวิเคราะห์รูปทรงและตำแหน่งของสิ่งต่างๆ ในภาพ แล้วนำไปเทียบกับข้อมูลโครงสร้างสะพานและทางรถไฟใน OpenStreetMap ซึ่งเป็นฐานข้อมูลแผนที่แบบเปิด ร่วมกับแนวสันเขาที่คำนวณจากระดับความสูงภูมิประเทศจริง ภาพถ่ายดาวเทียม ตลอดจนภาพถ่ายระดับถนนอย่าง Street View
เคสตัวอย่างที่ Oldcircle ผู้พัฒนาโปรเจกต์นี้บน GitHub นำมาแสดงไว้ คือภาพถ่ายจากมือถือที่ลบข้อมูล EXIF ระบุพิกัดและวันเวลาถ่ายออกไปจนหมด ทั้งยังไม่มีตัวหนังสือให้แกะรอยเลยแม้แต่ตัวเดียว แต่ระบบสามารถไล่ตัดตัวเลือกจากสะพานรถไฟทั้งหมด 27,335 ช่วง จนเหลือพิกัดจริงเพียงจุดเดียว โดยคลาดเคลื่อนไม่เกิน 2 เมตร และใช้เวลารวมราว 72 นาที
สคริปต์เป็นคนคัด โมเดลเป็นคนตัดสิน

หลักการออกแบบของโปรเจกต์นี้ใช้แนวคิดให้สคริปต์เป็นฝ่ายคัดกรอง แล้วให้โมเดลเป็นผู้ตัดสิน โดยมีสคริปต์ Python ราว 20 ตัว แต่ละตัวทำหน้าที่เฉพาะด้าน คอยค้นหา คำนวณคะแนน และจัดอันดับตัวเลือกทั้งหมด ส่วนโมเดล AI มีหน้าที่เพียงอย่างเดียว คือพิจารณาและตัดสินใจจากตัวเลือกอันดับต้นๆ ที่สคริปต์คัดมาให้
หลายคนอาจเข้าใจผิดว่าระบบนี้คือการให้ AI ดูรูปแล้วเดาชื่อเมืองออกมาตรงๆ ซึ่งจริงๆ แล้ว AI สามารถตั้งสมมติฐานได้ แต่สิ่งที่เดาจะนำไปใช้ลดน้ำหนักความน่าจะเป็นของบางตัวเลือกเท่านั้น ไม่สามารถนำมาใช้เป็นหลักฐานยืนยันได้ โปรเจกต์นี้จึงตั้งกฎเหล็กไว้ 3 ข้อ:
- ทุกข้อสรุปต้องตรวจสอบได้ว่ามาจากคำสั่งที่รันจริง และเกิดจากไฟล์หลักฐานชิ้นไหน
- การจะตัดตัวเลือกใดทิ้ง ต้องมีหลักฐานที่อ่านค่าได้หรือคำนวณออกมาเป็นตัวเลขได้จริง
- สิ่งที่โมเดลสังเกตเห็นหรือคาดเดา ใช้ได้แค่ลดน้ำหนักคะแนนของตัวเลือกเท่านั้น แต่ไม่มีสิทธิ์เพิ่มคะแนนให้ตัวเลือกใดๆ
หลักคิดนี้สอดคล้องกับแนวคิดในบทความ unlazy ที่เป็นสกิลกำหนดให้ Agent รายงานผลว่างานเสร็จเฉพาะส่วนที่คำสั่งรันผ่านจริง นั่นคือการผูกคำตอบของ AI ไว้กับผลลัพธ์ที่เกิดจากการรันโค้ดจริงเสมอ
โครงสร้างการทำงานแบ่งออกเป็น 3 ชั้น:
- ชั้นแรกคือ
board.py: ทำหน้าที่เป็นกระดานกลาง คอยบันทึกว่ายังเหลือตัวเลือกใดบ้าง มีเบาะแสอะไร แต่ละเบาะแสเพิ่มหรือลดน้ำหนักคะแนนเท่าไร พร้อมจัดอันดับและกำหนดว่าขั้นตอนถัดไปควรสแกนพื้นที่ใด - ชั้นที่สองคือกลุ่มสคริปต์ค้นหาและวิเคราะห์: เช่น
intake.py,ocr.py,clues.py,sat_scan.py,match.pyและgeo.pyทำหน้าที่อ่านตัวหนังสือในภาพ ตรวจสอบตารางข้อมูล สแกนหาเป้าหมายในภาพถ่ายดาวเทียม และเปรียบเทียบภาพ Street View ก่อนจะส่งเฉพาะตัวเลือกอันดับต้นๆ มาให้พิจารณา - ชั้นที่สามคือโมเดล AI: ทำงานตามคู่มือใน
SKILL.mdและโฟลเดอร์references/มีหน้าที่ดึงเบาะแสจากภาพ ตั้งสมมติฐาน และตัดสินใจเลือกจากตัวเลือกที่สคริปต์คัดกรองมาให้ สำหรับใครที่ยังไม่แน่ใจว่า Skill ต่างจาก Tool หรือ Subagent อย่างไร สามารถอ่านเพิ่มเติมได้ในบทความ Tool, Skill หรือ Subagent
เหตุผลที่ต้องแบ่งระบบแบบนี้จะเห็นได้ชัดเจนในเคสทดสอบจริง เพราะงานประเภทที่ต้องไล่ตรวจข้อมูลเป็นหมื่นๆ จุด โปรเจกต์จะยกให้สคริปต์คำนวณทั้งหมด แล้วปล่อยให้การตัดสินใจว่าตัวเลือกไหนตรงกับภาพถ่ายจริง เป็นหน้าที่ของโมเดล AI ในชั้นที่สาม
ตามรอยเคสจริง จากสะพาน 27,335 ช่วง เหลือจุดเดียว

ภาพโจทย์ตั้งต้นของเคสนี้ คือภาพเตาอบสีขาวตั้งอยู่ริมทุ่งนาหลังเก็บเกี่ยว ไกลออกไปมองเห็นสะพานรถไฟยกระดับทอดยาวพาดผ่าน และทางฝั่งขวาของภาพมีแนวภูเขาลาดชัน

ขั้นที่ 1: วิเคราะห์ข้อมูลจากรูป สิ่งที่ระบบสกัดได้ไม่ใช่ชื่อเมือง แต่เป็นข้อมูลทางกายภาพที่วัดค่าได้จริง เช่น เสาบนสะพานมีสายส่งไฟฟ้าเหนือราง แปลว่าเป็นทางรถไฟระบบไฟฟ้า ระยะห่างระหว่างตอม่อสะพานใช้เป็นไม้บรรทัดวัดระยะทางได้ ถ้าสมมติว่าตอม่อแต่ละช่วงยาว 32 เมตร ฝั่งซ้ายที่ตอม่อดูห่างกันจะอยู่ห่างจากกล้องราว 0.5 กิโลเมตร ส่วนฝั่งขวาที่ตอม่อดูถี่จะอยู่ไกลออกไปเกิน 1 กิโลเมตร ขณะที่ภูเขาชันด้านหลังน่าจะอยู่ห่างออกไปราว 3 กิโลเมตร นอกจากนี้ ข้าวในนาเกี่ยวไปแล้วแต่หญ้ายังเขียวอยู่ แสดงว่ายังไม่เข้าสู่ช่วงที่มีน้ำค้างแข็ง เมื่อรวมข้อมูลเข้าด้วยกันจึงได้สมมติฐานว่าภาพนี้น่าจะถ่ายในพื้นที่ทางตอนใต้ของจีน แต่นี่เป็นเพียงสมมติฐานตั้งต้น ไม่ใช่ข้อพิสูจน์

ขั้นที่ 2: สแกนข้อมูลสะพานทั้งภูมิภาค สคริปต์ดึงข้อมูลสะพานรถไฟทุกช่วงในภูมิภาคเป้าหมายจาก OpenStreetMap ออกมาได้ทั้งหมด 27,335 ช่วง จากนั้นสร้างจุดตรวจสอบทุกๆ ระยะ 400 เมตรตลอดแนวสะพาน แล้วนำข้อมูลความสูงภูมิประเทศมาคำนวณว่า ถ้ายืนอยู่ที่จุดนั้นแล้วมองรอบตัวแบบ 360 องศา จะเห็นเส้นขอบฟ้าและแนวเขาเป็นรูปทรงใด จากนั้นคัดกรองเก็บเฉพาะจุดที่มีพื้นที่ราบอยู่ใกล้ๆ มีแนวภูเขาชัดเจนในระยะไม่กี่กิโลเมตร และมีเส้นขอบฟ้าราบอยู่ด้านข้าง ผลคือตัดตัวเลือกจนเหลือเพียง 171 จุด
ขั้นที่ 3: จับคู่แนวเส้นสันเขา รอบๆ พื้นที่ 171 จุดที่เหลือ สคริปต์จำลองตำแหน่งการตั้งกล้อง แล้วเรนเดอร์ภาพเส้นสันเขาที่จะมองเห็นจากแต่ละตำแหน่ง รวมทั้งหมด 14,372 ตำแหน่ง แต่ปรากฏว่าผลลัพธ์ 20 อันดับแรกต่างกันไม่ถึง 0.1 องศาจนแทบแยกไม่ออก สคริปต์จึงเพิ่มเงื่อนไขจากขั้นที่ 1 เข้าไปช่วยคัดกรอง นั่นคือแนวสะพานต้องอยู่ใกล้ทางฝั่งซ้ายและอยู่ไกลทางฝั่งขวา จนบีบตัวเลือกเหลือเพียง 22 ตำแหน่ง
ขั้นที่ 4: นำเส้นสันเขามาทาบลงบนรูปจริง สำหรับ 3 อันดับแรกที่ได้คะแนนสูงสุด ระบบจะนำเส้นสันเขาที่เรนเดอร์ได้ไปวาดทาบลงบนภาพถ่ายจริงโดยตรง ขั้นตอนนี้ข้ามไม่ได้เด็ดขาด เพราะอันดับ 1 ที่เมืองฝูโจว ได้คะแนนสูงเนื่องจากมีเนินเขาเล็กๆ โผล่มาตรงจุดที่เตาอบบังอยู่พอดี ส่วนอันดับ 3 ที่เมืองฮุ่ยโจว แนวสันเขากลับลาดลงในจุดที่ภาพจริงเป็นพื้นราบ ขณะที่อันดับ 2 ที่เมืองชิงหย่วน แนวสันเขาทาบสนิทกับภูเขาจริงตั้งแต่ตีนเขาไปจนสุดขอบภาพ ถ้าระบบหยุดทำงานตั้งแต่ขั้นตอนคำนวณคะแนนโดยไม่นำภาพมาทาบจริง คำตอบที่ได้ก็จะเป็นเมืองฝูโจว ซึ่งผิดทันที

ขั้นที่ 5: ตรวจนับและวัดระยะตอม่อสะพาน ในภาพมองเห็นตอม่อสะพาน 17 ต้น และคำนวณตำแหน่งของแต่ละต้นเป็นมุมมองจากกล้องได้รวม 17 มุม เมื่อลากเส้นจากกล้องออกไปตามมุมเหล่านั้นจนตัดกับแนวรางรถไฟบนแผนที่ จุดตัดทั้ง 17 จุดจะต้องมีระยะห่างเท่ากันทั้งหมดตามระยะของตอม่อจริง ในเชิงเรขาคณิต มีตำแหน่งตั้งกล้องเพียงจุดเดียวเท่านั้นที่ทำให้มุมมองและระยะห่างลงตัวแบบนี้ได้ เมื่อนำมารวมกับเงื่อนไขแนวสันเขา ระบบจึงตีกรอบพื้นที่จนเหลือแนวแคบๆ ราว 300 เมตร ก่อนจะบีบพิกัดเข้าสู่จุดตั้งกล้องจริงได้อย่างแม่นยำ โดยคลาดเคลื่อนไม่เกิน 2 เมตร

กระบวนการทั้งหมดนี้ใช้เวลาทำงานประมาณ 72 นาที โดยเวลาราวครึ่งหนึ่งหมดไปกับการรอคอมพิวเตอร์คำนวณข้อมูล
สิ่งที่ได้กลับมา และตัวเลขที่ยังไม่ใช่ค่าความแม่นยำโดยรวม
เมื่อประมวลผลเสร็จสิ้น AI Agent จะส่งคำตอบกลับมาให้ 4 ส่วน ได้แก่ พิกัดตำแหน่งพร้อมรัศมีความคลาดเคลื่อน ทิศทางที่กล้องหันไป ระดับความมั่นใจที่แบ่งตามเกรด และภาพหลักฐานสรุป 1 ภาพ ที่สคริปต์ evidence.py สร้างขึ้นโดยนำภาพถ่ายดาวเทียม พื้นที่มุมมองรูปพัดของกล้อง และตารางเปรียบเทียบข้อมูล มาจัดรวมเป็นภาพเดียว

อย่างไรก็ดี ตัวเลขความคลาดเคลื่อนไม่เกิน 2 เมตรนั้น มาจากการทดสอบในเคสนี้เพียงเคสเดียว ไม่ใช่ค่าเฉลี่ยความแม่นยำทั้งหมดของระบบ ซึ่งผู้พัฒนาระบุไว้อย่างตรงไปตรงมาว่า การทดสอบกับชุดรูปภาพใหม่ๆ เพื่อสรุปตัวเลขความแม่นยำในภาพรวมยังอยู่ในแผนงานและยังไม่ได้ทำ สิ่งที่มีให้ดูในตอนนี้จึงเป็นผลการทดสอบแยกรายสคริปต์:
match.pyสคริปต์จัดอันดับภาพมุมมองถนนเทียบกับภาพโจทย์: ทดสอบ 8 เคสในเมืองเซินเจิ้น โดยนำภาพพาโนรามาเก่าจากเสิร์ชเอนจินของจีนอย่าง Baidu มาเรนเดอร์เป็นภาพโจทย์ แล้วให้ระบบค้นหาจากภาพพาโนรามาอื่นๆ ในรัศมี 150 เมตร ผลปรากฏว่าคำตอบจริงติดอันดับ 1, 2, 4, 1, 1, 5, 1 และ 6 นั่นคือติด 6 อันดับแรกครบทุกเคส และขึ้นอันดับ 1 ถึงครึ่งหนึ่งsat_scan.pyสคริปต์ให้คะแนนตารางภาพถ่ายดาวเทียม: ทดสอบในพื้นที่ขนาด 4×8 กิโลเมตร แบ่งเป็น 364 ช่อง และใช้ตำแหน่งลู่วิ่ง 40 แห่งที่มีแท็กใน OpenStreetMap เป็นเฉลย ถ้าตรวจเพียง 20 ช่องแรกจะเจอลู่วิ่งจริง 17 แห่ง ตรวจ 30 ช่องเจอ 22 แห่ง และถ้าตรวจถึง 100 ช่องจะเจอ 32 แห่ง โดยมีค่ามัธยฐานของอันดับอยู่ที่ 23 หมายความว่าเฉลยครึ่งหนึ่งจะอยู่ใน 23 อันดับแรก ซึ่งตัวเลขนี้ชี้ว่าระบบยังต้องไล่ตรวจดูหลายสิบช่องกว่าจะพบเป้าหมายclues.pyชุดตารางรวบรวมเบาะแส 6 ตาราง: สุ่มตรวจสอบ 9 ค่า พบว่าถูกต้องครบทั้ง 9 ค่า- การทดสอบเคสเตาอบซ้ำแบบจำกัดขอบเขต: เมื่อทดสอบด้วย
terrain.py scan/fitร่วมกับgeo.py spacingผลลัพธ์จริงขึ้นเป็นอันดับ 1 ได้อย่างแม่นยำ และตำแหน่งสุดท้ายห่างจากจุดถ่ายจริงราวๆ 2 เมตร
แนวทางทั้งหมดนี้ไม่ได้คิดค้นขึ้นมาลอยๆ แต่ผู้พัฒนาแกะรอยเทคนิคมาจากคลิปของครีเอเตอร์สายสืบพิกัดภาพแนว GeoGuessing และ OSINT จำนวน 14 คลิป พร้อมโจทย์ทดสอบ 22 ข้อ ควบคู่ไปกับการรันคำสั่งจริง แล้วจึงนำวิธีที่ได้ผลมาแปลงเป็นกฎและสคริปต์อัตโนมัติ โดยในเวอร์ชัน 2 กฎข้อไหนที่เขียนเป็นโค้ดได้ จะย้ายเข้าไปอยู่ใน board.py ทั้งหมด เพื่อให้ระบบรันตรวจสอบด้วยโค้ดจริงๆ ไม่ใช่แค่ส่งให้โมเดลอ่านผ่านตา
ข้อควรรู้เพิ่มเติมก่อนนำไปใช้งาน คือ 3 ขั้นตอนหลักของเคสเตาอบนี้ ทั้งการสแกนระดับภูมิภาค การให้คะแนนแนวสันเขาทีละหลายพันจุด และการหาตำแหน่งกล้องจากระยะตอม่อสะพาน มีรวมไว้เป็นคำสั่งย่อยในตัวสกิลแล้ว ได้แก่ terrain.py scan / ridge / fit, imgprep.py piers และ geo.py spacing ส่วนชุดสคริปต์ที่ปรับแต่งมาเพื่อภาพนี้โดยเฉพาะ ก็แยกเก็บไว้ในโฟลเดอร์ examples/rail-skyline-session/ ให้เข้าไปศึกษาเป็นตัวอย่าง
ติดตั้ง geo-sleuth ด้วยคำสั่งเดียว แล้วสั่งงานด้วยประโยคเดียว
เนื่องจาก geo-sleuth พัฒนาขึ้นตามมาตรฐาน Agent Skills โฟลเดอร์เดียวกันนี้จึงนำไปใช้งานร่วมกับ AI Agent ได้หลากหลาย ทั้ง Claude Code, Codex, Cursor, Gemini CLI, OpenCode, GitHub Copilot และ Agent ตัวอื่นๆ ที่อ่านไฟล์ SKILL.md และมีสิทธิ์รันคำสั่งบนเครื่องได้ โดยติดตั้งผ่านเครื่องมือ skills ได้ทันทีด้วยคำสั่งเดียว:
npx skills add Oldcircle/geo-sleuthเมื่อรันคำสั่งแล้ว ให้เลือก Agent ที่ต้องการติดตั้งตามที่ระบบถาม จากนั้นแค่ส่งรูปภาพให้ Agent พร้อมพิมพ์สั่งสั้นๆ ว่า find where this photo was taken เท่านี้ Agent จะเริ่มอ่านขั้นตอนใน SKILL.md รันสคริปต์ที่เกี่ยวข้อง และส่งรายงานผลลัพธ์ทั้ง 4 ส่วนกลับมาให้เรา
สิ่งที่ต้องเตรียมไว้ในเครื่อง มีเพียง Python เวอร์ชัน 3.10 ขึ้นไป, เครื่องมือ uv ซึ่งเป็นตัวจัดการแพ็กเกจของ Python และ AI Agent ที่รันคำสั่งบนเครื่องได้ โดยสคริปต์แต่ละตัวระบุไลบรารีที่ต้องใช้ไว้ในตัวไฟล์เรียบร้อยแล้ว เมื่อเรียกใช้งาน คำสั่ง uv run จะดาวน์โหลดและติดตั้งสิ่งที่จำเป็นให้โดยอัตโนมัติในการรันครั้งแรก
ส่วนประกอบเสริมที่เลือกตั้งค่าได้มี 2 อย่าง:
อย่างแรกคือ Google Chrome สำหรับใช้ค้นหาด้วยรูปภาพ ถ้าในเครื่องไม่มี Chrome ก็ใช้คำสั่ง uvx playwright install chromium แทนได้ โดยจะติดตั้งหรือไม่ก็ได้ตามความสะดวก ถ้าไม่ติดตั้ง สคริปต์ revimg.py ที่ใช้ค้นหาภาพย้อนกลับบน Baidu และเสิร์ชเอนจินของรัสเซียอย่าง Yandex จะใช้งานไม่ได้
อย่างที่สองคือ Proxy สำหรับกำหนดเส้นทางการเชื่อมต่อ ตั้งค่าผ่านตัวแปร GEO_PROXY=socks5h://127.0.0.1:<port> ได้ เพื่อให้ทุกสคริปต์ที่เชื่อมต่ออินเทอร์เน็ตส่งข้อมูลผ่าน Proxy นั้น
สำหรับเงื่อนไขการใช้งาน โปรเจกต์ระบุข้อกำหนดไว้ชัดเจนว่า ให้นำไปใช้กับรูปภาพของตัวเอง หรือรูปที่ได้รับอนุญาตให้วิเคราะห์แล้วเท่านั้น ห้ามนำไปใช้ตามหาตำแหน่งของบุคคลโดยไม่ได้รับความยินยอม โค้ดทั้งหมดเปิดให้ใช้งานภายใต้สัญญาอนุญาต MIT และเนื่องจากข้อมูล OpenStreetMap ไม่ได้แนบมาในคลังโค้ด แต่สคริปต์จะดึงข้อมูลสดใหม่ทุกครั้ง ถ้านำผลลัพธ์ไปเผยแพร่ต่อ ต้องระบุเครดิต © OpenStreetMap contributors ตามข้อกำหนดด้วย
การลบข้อมูล EXIF อาจทำให้ภาพถ่ายไม่บอกพิกัด แต่แนวภูเขาในภาพยังคงบอกตำแหน่งได้เสมอ
ที่มา: บทความ Oldcircle/geo-sleuth: An agent skill that finds where a photo was taken — OpenStreetMap geometry, elevation skylines, satellite imagery and street view — and shows its work จาก Oldcircle
ชอบเรื่องแนวนี้ มีอีบุ๊คฟรีให้อ่านต่อ
สร้าง Claude Skill แบบไม่ต้องรู้โค้ด คู่มือสร้าง Claude Skill ของคุณเองด้วยการคุยกับ Claude Code เป็นภาษาไทย
กดสมัครแล้วเราจะส่งเทคนิค AI และของแจกใหม่ๆ ให้ทางอีเมล เลิกรับได้ตลอด
สร้าง AI Automation Pipeline ทุกแบบ ด้วย Agents และ Skills

ปูจากพื้นฐาน prompt, context และ cost ไปจนปั้น Skill สั่ง Agent กับ Sub-agent แล้วต่อทุกอย่างเป็น pipeline อัตโนมัติที่ออกแบบเองได้ ดูฟรี 7 บทก่อนตัดสินใจ


