
แปลงบันทึกการประชุมแบบไม่มีโครงสร้างให้เป็นกราฟความรู้ที่สามารถสืบค้นได้ และรองรับการอัปเดตแบบเพิ่มเติม — ไม่จำเป็นต้องประมวลผลทั้งหมดใหม่ทุกครั้ง
บันทึกการประชุมคือเหมืองทองแห่งปัญญาขององค์กร ซึ่งบันทึกการตัดสินใจ รายการปฏิบัติงาน ข้อมูลผู้เข้าร่วม และความสัมพันธ์ระหว่างบุคคลกับงาน อย่างไรก็ตาม องค์กรส่วนใหญ่ยังคงมองว่าบันทึกเหล่านี้เป็นเอกสารคงที่ที่สามารถค้นหาข้อความเต็มได้เพียงพื้นฐานเท่านั้น
ลองจินตนาการว่าคุณสามารถสืบค้นบันทึกการประชุมของคุณได้เหมือนกับการสืบค้นฐานข้อมูล:
- “ใครเคยเข้าร่วมการประชุมที่มีหัวข้อ ‘การวางแผนงบประมาณ’?”
- “Sarah ถูกมอบหมายงานอะไรบ้างในการประชุมทั้งหมด?”
- “แสดงการตัดสินใจทั้งหมดในไตรมาสที่สี่ที่เกี่ยวข้องกับทีมวิศวกรรม”
นี่คือจุดที่กราฟความรู้เข้ามามีบทบาท ด้วยการแยกข้อมูลที่มีโครงสร้างออกจากบันทึกการประชุมแบบไม่มีโครงสร้างและสร้างการแสดงผลแบบกราฟ ทำให้สามารถปลดล็อกความสามารถในการสืบค้นตามความสัมพันธ์อันทรงพลัง ซึ่งที่เก็บเอกสารแบบดั้งเดิมไม่สามารถทำได้
บทความนี้จะสร้างไปป์ไลน์การประมวลผล CocoIndex ที่ใช้งานได้จริง เพื่อให้บรรลุฟังก์ชันการทำงานดังต่อไปนี้:
- อ่านบันทึกการประชุมรูปแบบ Markdown จาก Google Drive
- ใช้โมเดลภาษาขนาดใหญ่ (LLM) เพื่อแยกเอนทิตีที่มีโครงสร้าง (การประชุม ผู้เข้าร่วม งาน)
- เขียนข้อมูลลงในฐานข้อมูล Neo4j ในรูปแบบกราฟความรู้
- อัปเดตกราฟอัตโนมัติเฉพาะเมื่อเอกสารต้นฉบับมีการเปลี่ยนแปลง
ซอร์สโค้ดฉบับสมบูรณ์สามารถดูได้ที่ GitHub: https://github.com/cocoindex-io/meeting-notes-knowledge-graph

ภาพรวมสถาปัตยกรรม
ไปป์ไลน์นี้ปฏิบัติตามโฟลว์ข้อมูลที่ชัดเจน และมีตรรกะการประมวลผลแบบเพิ่มเติมในตัวในแต่ละขั้นตอน:
Google Drive (เอกสารพร้อมการติดตามการเปลี่ยนแปลง)
→ ระบุเอกสารที่เปลี่ยนแปลง
→ แยกเนื้อหาตามการประชุม
→ ใช้ LLM แยกข้อมูลที่มีโครงสร้าง (ประมวลผลเฉพาะเอกสารที่เปลี่ยนแปลง)
→ รวบรวมโหนดและความสัมพันธ์
→ ส่งออกไปยัง Neo4j (พร้อมตรรกะ upsert)
ข้อกำหนดเบื้องต้น
- Neo4j: ติดตั้งและเริ่มต้นฐานข้อมูล Neo4j ตัวอย่างในบทความนี้ใช้ที่อยู่ท้องถิ่นเริ่มต้น
http://localhost:7474โดยมีข้อมูลรับรองคือชื่อผู้ใช้neo4jและรหัสผ่านcocoindex - OpenAI API Key: กำหนดค่าคีย์ API ของ OpenAI ของคุณ
- การเตรียม Google Drive:
- สร้างบัญชีบริการ Google Cloud และดาวน์โหลดไฟล์ข้อมูลรับรอง JSON ของบัญชีนั้น
- แชร์โฟลเดอร์ต้นทางที่มีบันทึกการประชุมให้กับอีเมลของบัญชีบริการนั้น
- รับ ID ของโฟลเดอร์รากที่คุณต้องการนำเข้า
- ดูขั้นตอนการตั้งค่าโดยละเอียดได้ที่ “คู่มือการตั้งค่า Google Drive”
ตัวแปรสภาพแวดล้อม
ตั้งค่าตัวแปรสภาพแวดล้อมต่อไปนี้:
export OPENAI_API_KEY=sk-...
export GOOGLE_SERVICE_ACCOUNT_CREDENTIAL=/absolute/path/to/service_account.json
export GOOGLE_DRIVE_ROOT_FOLDER_IDS=folderId1,folderId2
คำอธิบาย:
* GOOGLE_DRIVE_ROOT_FOLDER_IDS รับ ID โฟลเดอร์หลายรายการที่คั่นด้วยเครื่องหมายจุลภาค
* โพรเซสนี้จะโพลลิงหาการเปลี่ยนแปลงล่าสุด และรีเฟรชข้อมูลเป็นระยะ
ต่อไปจะแยกส่วนประกอบต่างๆ ของไปป์ไลน์ทีละส่วน
นิยามโฟลว์
ภาพรวม

เพิ่ม Source และ Collector
python
@cocoindex.flow_def(name="MeetingNotesGraph")
def meeting_notes_graph_flow(
flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope
) -> None:
"""
กำหนดโฟลว์ตัวอย่างที่แยกข้อมูลสามส่วนจากไฟล์และสร้างกราฟความรู้
"""
credential_path = os.environ["GOOGLE_SERVICE_ACCOUNT_CREDENTIAL"]
root_folder_ids = os.environ["GOOGLE_DRIVE_ROOT_FOLDER_IDS"].split(",")
data_scope["documents"] = flow_builder.add_source(
cocoindex.sources.GoogleDrive(
service_account_credential_path=credential_path,
root_folder_ids=root_folder_ids,
recent_changes_poll_interval=datetime.timedelta(seconds=10),
),
refresh_interval=datetime.timedelta(minutes=1),
)
ไปป์ไลน์เริ่มต้นด้วยการเชื่อมต่อกับ Google Drive ผ่านบัญชีบริการ Source Connector ในตัวของ CocoIndex รับผิดชอบการตรวจสอบสิทธิ์และให้ความสามารถในการตรวจจับการเปลี่ยนแปลงแบบเพิ่มเติม พารามิเตอร์ recent_changes_poll_interval ถูกตั้งค่าให้ตรวจสอบไฟล์ใหม่หรือไฟล์ที่แก้ไขทุก 10 วินาที ในขณะที่พารามิเตอร์ refresh_interval กำหนดความถี่ในการรันโฟลว์ทั้งหมดใหม่ (ทุก 1 นาที)

นี่คือความสามารถหลักอย่างหนึ่งของ CocoIndex: การประมวลผลแบบเพิ่มเติมพร้อมการติดตามการเปลี่ยนแปลงอัตโนมัติ แทนที่จะประมวลผลเอกสารทั้งหมดใหม่ทุกครั้ง เฟรมเวิร์กนี้จะ:
- แสดงรายการไฟล์ทั้งหมดพร้อมเวลาที่แก้ไขล่าสุดจาก Google Drive
- ระบุเฉพาะไฟล์ที่เพิ่มหรือแก้ไขตั้งแต่การรันที่สำเร็จล่าสุด
- ข้ามไฟล์ที่ไม่ได้เปลี่ยนแปลงไปโดยสิ้นเชิง
- ส่งเฉพาะเอกสารที่เปลี่ยนแปลงไปยังขั้นตอนต่อไปเพื่อประมวลผล
ผลลัพธ์เป็นอย่างไร? ในสภาพแวดล้อมองค์กรที่มีอัตราการเปลี่ยนแปลงรายวัน 1% มีเพียง 1% ของเอกสารเท่านั้นที่จะทริกเกอร์การประมวลผลในขั้นตอนต่อไป ไฟล์ที่ไม่ได้เปลี่ยนแปลงจะไม่เรียกใช้ API ของ LLM ไม่สร้างคำสั่งค้นหา Neo4j และไม่ใช้ทรัพยากรการคำนวณเพิ่มเติม
เพิ่ม Collector
python
meeting_nodes = data_scope.add_collector()
attended_rels = data_scope.add_collector()
decided_tasks_rels = data_scope.add_collector()
assigned_rels = data_scope.add_collector()
จากนั้น ไปป์ไลน์ใช้ Collector ต่างๆ เพื่อรวบรวมข้อมูลสำหรับเอนทิตีและความสัมพันธ์ประเภทต่างๆ:
- โหนดการประชุม: เก็บข้อมูลของการประชุมเอง รวมถึงวันที่และเนื้อหาบันทึก
- ความสัมพันธ์การเข้าร่วม: จับข้อมูลว่าใครเข้าร่วมการประชุม และเป็นผู้จัดหรือไม่
- ความสัมพันธ์การตัดสินใจงาน: เชื่อมโยงการประชุมกับงานต่างๆ ที่ตัดสินใจในการประชุม
- ความสัมพันธ์การมอบหมายงาน: มอบหมายงานเฉพาะให้กับบุคคลที่เกี่ยวข้อง
ประมวลผลแต่ละเอกสาร
แยกการประชุม
เอกสารการประชุมมักรวมหลายการประชุมไว้ในไฟล์เดียวกัน ขั้นตอนนี้จะแยกตามหัวเรื่อง Markdown (## หรือ # และมีบรรทัดว่างข้างหน้า) โดยถือว่าแต่ละย่อหน้าหัวเรื่องเป็นการประชุมแยกกัน keep_separator="RIGHT" ในโค้ดหมายถึงตัวคั่น (หัวเรื่อง) จะถูกเก็บไว้ในย่อหน้าด้านขวา เพื่อให้แน่ใจว่าบริบทสำหรับการประมวลผลต่อไปจะสมบูรณ์
python
with data_scope["documents"].row() as document:
document["meetings"] = document["content"].transform(
cocoindex.functions.SplitBySeparators(
separators_regex=[r"nn##? "], keep_separator="RIGHT"
)
)

แยกการประชุมเดี่ยว
กำหนด Schema การประชุม
เพื่อให้แน่ใจว่า LLM สามารถแยกข้อมูลที่มีโครงสร้างและเชื่อถือได้ได้ เรากำหนดรูปแบบข้อมูล (Schema) ที่ชัดเจนก่อน วิธีนี้มีประสิทธิภาพมากกว่าการให้ LLM แสดงผลข้อความรูปแบบอิสระ และสามารถสร้างข้อมูลที่มีโครงสร้างโดยตรงที่เหมาะสำหรับการสร้างกราฟความรู้
python
@dataclass
class Person:
name: str
@dataclass
class Task:
description: str
assigned_to: list[Person]
@dataclass
class Meeting:
time: datetime.date
note: str
organizer: Person
participants: list[Person]
tasks: list[Task]
แยกและรวบรวมความสัมพันธ์
ต่อไป เราใช้ LLM เพื่อแยกข้อมูลที่มีโครงสร้างจากข้อความการประชุมเดี่ยวตาม Schema ข้างต้น ขั้นตอนนี้เปิดใช้งานกลไกแคช: ตราบใดที่อินพุต (ข้อความ โมเดล นิยามประเภทเอาต์พุต) ไม่เปลี่ยนแปลง ก็จะนำผลลัพธ์ที่แคชไว้กลับมาใช้ใหม่ เพื่อหลีกเลี่ยงการเรียกใช้ LLM ซ้ำซ้อนที่ไม่จำเป็น ซึ่งมีความสำคัญอย่างยิ่งเมื่อต้องประมวลผลข้อมูลจำนวนมาก
python
with document["meetings"].row() as meeting:
parsed = meeting["parsed"] = meeting["text"].transform(
cocoindex.functions.ExtractByLlm(
llm_spec=cocoindex.LlmSpec(
api_type=cocoindex.LlmApiType.OPENAI, model="gpt-5"
),
output_type=Meeting,
)
)

รวบรวมความสัมพันธ์
ใน CocoIndex Collectors ทำหน้าที่เป็นบัฟเฟอร์หน่วยความจำ เราประกาศตัวรวบรวมสำหรับเอนทิตีและความสัมพันธ์ต่างๆ และเติมข้อมูลในขณะที่ประมวลผลแต่ละการประชุม โค้ดต่อไปนี้รวบรวมโหนดและความสัมพันธ์จากผลลัพธ์ที่แยกวิเคราะห์ เพื่อเตรียมพร้อมสำหรับการสร้างกราฟความรู้ในภายหลัง:
- โหนดการประชุม: รวบรวมข้อมูลหลักของการประชุม
- ความสัมพันธ์การเข้าร่วม: เชื่อมโยงผู้เข้าร่วม (รวมถึงผู้จัด) กับการประชุมที่พวกเขาเข้าร่วม (
ATTENDED) - ความสัมพันธ์การตัดสินใจ: เชื่อมโยงการประชุมกับงานที่ตัดสินใจในการประชุม (
DECIDED) - ความสัมพันธ์การมอบหมาย: เชื่อมโยงงานกับบุคคลที่รับผิดชอบงานนั้น (
ASSIGNED_TO)
python
meeting_key = {“note_file”: document[“filename”], “time”: parsed[“time”]}
meeting_nodes.collect(**meeting_key, note=parsed[“note”])
attended_rels.collect(
id=cocoindex.GeneratedField.UUID,
**meeting_key,
person=parsed[“organizer”][“name”],
is_organizer=True,
)
with parsed[“participants”].row() as participant:
attended_rels.collect(
id=cocoindex.GeneratedField.UUID,
**meeting_key,
person=participant[“name”],
)
with parsed[“tasks”].row() as task:
decided_tasks_rels.collect(
id=cocoindex.GeneratedField.UUID,
meeting_key,
description=task[“description”],
)
with task[“assigned_to”].row() as assigned_to:
assigned_rels.collect(
id=cocoindex.GeneratedField.UUID,
meeting_key,
task=task[“description”],
person=assigned_to[“name”],
)
แมปไปยังฐานข้อมูลกราฟ
ภาพรวม
เราจะสร้างกราฟคุณสมบัติ (Property Graph) ที่ประกอบด้วยโหนดและความสัมพันธ์ที่รวบรวมไว้ข้างต้น สำหรับข้อมูลเพิ่มเติมเกี่ยวกับกราฟคุณสมบัติ โปรดดูส่วน “Property Graph Targets” ในเอกสารประกอบ CocoIndex
แมปโหนดการประชุม
โค้ดต่อไปนี้แมปและส่งออกข้อมูลโหนดการประชุมที่รวบรวมไว้ไปยังฐานข้อมูล Neo4j กำหนดป้ายกำกับ Meeting และระบุคีย์หลักแบบผสม

python
meeting_nodes.export(
"meeting_nodes",
cocoindex.targets.Neo4j(
connection=conn_spec, mapping=cocoindex.targets.Nodes(label="Meeting")
),
primary_key_fields=["note_file", "time"],
)
ประกาศโหนด Person และ Task
ใช้เมธอด flow_builder.declare เราประกาศโครงสร้างโหนดของเอนทิตีหลักสองประเภทในกราฟความรู้ล่วงหน้า
python
flow_builder.declare(
cocoindex.targets.Neo4jDeclaration(
connection=conn_spec,
nodes_label="Person",
primary_key_fields=["name"],
)
)
flow_builder.declare(
cocoindex.targets.Neo4jDeclaration(
connection=conn_spec,
nodes_label="Task",
primary_key_fields=["description"],
)
)
* โหนด Person: แทนผู้เข้าร่วมหรือผู้จัดประชุม โดยใช้ฟิลด์ name เป็นตัวระบุเฉพาะ
* โหนด Task: แทนรายการงานที่เกิดขึ้นในการประชุม โดยใช้ฟิลด์ description เป็นตัวระบุเฉพาะ
แมปความสัมพันธ์ ATTENDED
ขั้นตอนนี้นิยามความสัมพันธ์การเข้าร่วมระหว่างบุคคลกับการประชุม
python
attended_rels.export(
"attended_rels",
cocoindex.targets.Neo4j(
connection=conn_spec,
mapping=cocoindex.targets.Relationships(
rel_type="ATTENDED",
source=cocoindex.targets.NodeFromFields(
label="Person",
fields=[
cocoindex.targets.TargetFieldMapping(
source="person", target="name"
)
],
),
target=cocoindex.targets.NodeFromFields(
label="Meeting",
fields=[
cocoindex.targets.TargetFieldMapping("note_file"),
cocoindex.targets.TargetFieldMapping("time"),
],
),
),
),
primary_key_fields=["id"],
)
* ความหมายของความสัมพันธ์: สร้างเส้นเชื่อ
⚠️ หมายเหตุ: เนื้อหาได้รับการแปลโดย AI และตรวจสอบโดยมนุษย์ หากมีข้อผิดพลาดโปรดแจ้ง
☕ สนับสนุนค่ากาแฟทีมงาน
หากคุณชอบบทความนี้ สามารถสนับสนุนเราได้ผ่าน PromptPay
本文来自网络搜集,不代表คลื่นสร้างอนาคต立场,如有侵权,联系删除。转载请注明出处:https://www.itsolotime.com/th/archives/23053
