---
# System prepended metadata

title: RAG CRUD & ER Model Design

---

# RAG CRUD & ER Model Design

## 每個實體（教材、考古題、詳解）可以作為一個集合，在Milvus中創建。例如，對於教材：

```
fields = [
    {"name": "question_vector", "type": DataType.FLOAT_VECTOR, "params": {"dim": 768}},  
    {"name": "question_id", "type": DataType.INT64},
    {"name": "textbook_id", "type": DataType.INT64}  # 關聯到教材的ID
]

client.create_collection("ExamQuestion", fields)

# 假設每個考古題已轉換為向量
exam_question_vectors = [vector1, vector2]  # 這些是問題的向量表示
exam_question_ids = [1, 2]
related_textbook_ids = [1, 2]  # 每個問題相關的教材ID

exam_entities = [
    {"name": "question_vector", "values": exam_question_vectors, "type": DataType.FLOAT_VECTOR},
    {"name": "question_id", "values": exam_question_ids, "type": DataType.INT64},
    {"name": "textbook_id", "values": related_textbook_ids, "type": DataType.INT64}
]

client.insert("ExamQuestion", exam_entities)
client.flush(["ExamQuestion"])
```

## 利用Milvus的搜索功能和metadata，使用考古題的問題ID或文本來查詢相關的教材ID，然後再去教材集合中檢索相應的教材內容：
```
# 假設你已經有一個問題的向量
search_vector = [0.1, 0.2, 0.3]  # 這是一個查詢向量

# 在考古題集合中搜索相應的向量
search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
results = client.search("ExamQuestion", [search_vector], {"bool": {"must": [{"vector": {"question_vector": {"topk": 1, "query": [search_vector], "metric_type": "L2", "params": {"nprobe": 10}}}}]}}, search_params)

# 假設results返回了相關的教材ID
related_textbook_id = results[0].id  # 取得第一個結果的教材ID

# 再次查詢教材集合以獲取詳細信息
textbook_info = client.query("Textbook", ["title", "content"], {"term": {"text_id": related_textbook_id}})
```

## 資料結構與關聯設計

我們需要設計一個資料結構，使得教材內容、考古題和詳解之間的關聯性明確，並在檢索和生成答案的過程中有效利用這些關聯。

### 資料準備

首先，我們需要收集和整理護理醫療教科書的教材內容以及考古題詳解。這些資料可以分為以下幾類：

1. 教科書內容（教材）
2. 考古題問題
3. 考古題詳解

### 資料結構

```
教材 (Textbook)
ID: 教材唯一標識符
標題: 教材標題
內容: 教材內容

考古題 (ExamQuestion)
ID: 考古題唯一標識符
問題: 考古題問題文本
答案: 考古題答案文本
教材ID: 關聯的教材ID（可選）

詳解 (Explanation)
ID: 詳解唯一標識符
考古題ID: 所屬考古題的ID
詳解內容: 詳解的文本內容
```
這樣設計的資料結構，使得每個考古題和其詳解可以關聯到相應的教材。

### 資料欄位描述

教材 (Textbook)
```
[
    {
        "ID": "1",
        "標題": "護理學概論",
        "內容": "這是護理學概論的教材內容。"
    },
    {
        "ID": "2",
        "標題": "內科護理學",
        "內容": "這是內科護理學的教材內容。"
    }
    // 更多教材資料...
]
```

考古題 (ExamQuestion)
```
[
    {
        "ID": "1",
        "問題": "何者不是護理過程的步驟？",
        "選項": ["評估", "診斷", "計劃", "執行", "制定護理計劃"],
        "答案": "制定護理計劃",
        "教材ID": "1"
    },
    {
        "ID": "2",
        "問題": "內科護理的主要內容是什麼？",
        "選項": ["心臟護理", "肺部護理", "腎臟護理", "所有上述"],
        "答案": "所有上述",
        "教材ID": "2"
    }
    // 更多考古題資料...
]
```
詳解 (Explanation)
```
[
    {
        "ID": "1",
        "考古題ID": "1",
        "詳解內容": "護理過程的步驟包括：評估、診斷、計劃、執行和評值。"
    },
    {
        "ID": "2",
        "考古題ID": "2",
        "詳解內容": "內科護理涉及心臟、肺部和腎臟等多方面的護理。"
    }
    // 更多詳解資料...
]
```
### 資料預處理與向量化

我們需要將這些資料進行預處理，並將其向量化，以便在向量資料庫中儲存和檢索。

```
from sentence_transformers import SentenceTransformer
import pinecone

# 初始化向量模型和向量資料庫
model = SentenceTransformer('model_name')
pinecone.init(api_key='your_api_key')
index = pinecone.Index('your_index')

# 假設我們有一些教材資料
textbooks = [
    {"ID": "1", "標題": "護理學概論", "內容": "這是護理學概論的教材內容。"},
    # 更多教材資料...
]

exam_questions = [
    {"ID": "1", "問題": "何者不是護理過程的步驟？", "答案": "制定護理計劃", "教材ID": "1"},
    # 更多考古題資料...
]

explanations = [
    {"ID": "1", "考古題ID": "1", "詳解內容": "護理過程的步驟包括：評估、診斷、計劃、執行和評值。"},
    # 更多詳解資料...
]

# 向量化並儲存教材內容
for textbook in textbooks:
    embedding = model.encode(textbook['內容'])
    index.upsert([(textbook['ID'], embedding, textbook)])

# 向量化並儲存考古題問題
for question in exam_questions:
    embedding = model.encode(question['問題'])
    index.upsert([(question['ID'], embedding, question)])

# 向量化並儲存詳解內容
for explanation in explanations:
    embedding = model.encode(explanation['詳解內容'])
    index.upsert([(explanation['ID'], embedding, explanation)])
```

### 檢索與生成答案

在檢索和生成答案的過程中，我們需要利用資料之間的關聯性，來提供更準確的回答。

```
# 定義檢索和生成答案的函數
def retrieve_and_generate_answer(query):
    # 向量化查詢
    query_embedding = model.encode([query])
    
    # 檢索最相關的考古題和詳解
    result = index.query(query_embedding, top_k=5)
    
    # 提取檢索結果的內容
    context = ""
    related_textbooks = set()
    for match in result['matches']:
        if '考古題ID' in match['metadata']:
            question = match['metadata']['問題']
            explanation = match['metadata']['詳解內容']
            context += f"考古題: {question}\n詳解: {explanation}\n"
            related_textbooks.add(match['metadata']['教材ID'])
        elif '內容' in match['metadata']:
            context += match['metadata']['內容'] + "\n"
    
    # 提取相關教材內容
    for textbook_id in related_textbooks:
        textbook_result = index.query(model.encode([textbook_id]), top_k=1)
        context += "相關教材: " + textbook_result['matches'][0]['metadata']['內容'] + "\n"
    
    # 生成答案
    generated_answer = generate_answer(query, context)
    
    return generated_answer

# 示例查詢
query = "護理過程的步驟有哪些？"
answer = retrieve_and_generate_answer(query)
print(answer)
```

### 模擬考試與行為推論
為了讓 Agent 能夠進行模擬考試並進行行為推論，我們需要進一步細化和模擬考試環境。這包括：

1. 構建考試題庫：將考古題和新增題目進行整理，構建完整的題庫。

```
exam_questions = [
    {
        "ID": "1",
        "問題": "何者不是護理過程的步驟？",
        "選項": ["評估", "診斷", "計劃", "執行", "制定護理計劃"],
        "正確答案": "制定護理計劃",
        "詳解": "護理過程的步驟包括：評估、診斷、計劃、執行和評值。"
    },
    # 更多考古題資料...
]

```


2. 模擬考試過程：設計模擬考試系統，讓 Agent 能夠回答問題並評估其答案。
```
import random

def simulate_exam(agent, exam_questions):
    score = 0
    total_questions = len(exam_questions)
    
    for question in exam_questions:
        print("問題:", question['問題'])
        if '選項' in question:
            for i, option in enumerate(question['選項']):
                print(f"{i+1}. {option}")
        
        # 假設 Agent 可以生成答案
        answer = agent.answer_question(question['問題'])
        print("Agent 的回答:", answer)
        
        if answer == question['正確答案']:
            print("回答正確！")
            score += 1
        else:
            print("回答錯誤。正確答案是:", question['正確答案'])
        
        print("詳解:", question['詳解'])
        print("-" * 50)
    
    print(f"模擬考試結束，總分: {score}/{total_questions}")

# 假設我們有一個簡單的 Agent 類
class SimpleAgent:
    def answer_question(self, question):
        # 這裡用隨機回答來模擬 Agent 的行為
        return random.choice(["評估", "診斷", "計劃", "執行", "制定護理計劃"])

agent = SimpleAgent()
simulate_exam(agent, exam_questions)
```

3. 反饋機制：提供反饋機制，讓 Agent 能夠根據答案評價進行學習和改進。

```
class LearningAgent(SimpleAgent):
    def __init__(self):
        self.knowledge_base = {}
    
    def learn(self, question_id, correct_answer, explanation):
        self.knowledge_base[question_id] = {
            'correct_answer': correct_answer,
            'explanation': explanation
        }
    
    def answer_question(self, question):
        # 這裡用簡單的知識庫查詢來模擬 Agent 的學習行為
        for q_id, knowledge in self.knowledge_base.items():
            if knowledge['correct_answer'] in question:
                return knowledge['correct_answer']
        return random.choice(["評估", "診斷", "計劃", "執行", "制定護理計劃"])

def simulate_exam_with_learning(agent, exam_questions):
    score = 0
    total_questions = len(exam_questions)
    
    for question in exam_questions:
        print("問題:", question['問題'])
        if '選項' in question:
            for i, option in enumerate(question['選項']):
                print(f"{i+1}. {option}")
        
        answer = agent.answer_question(question['問題'])
        print("Agent 的回答:", answer)
        
        if answer == question['正確答案']:
            print("回答正確！")
            score += 1
        else:
            print("回答錯誤。正確答案是:", question['正確答案'])
        
        print("詳解:", question['詳解'])
        print("-" * 50)
        
        # Agent 學習反饋
        agent.learn(question['ID'], question['正確答案'], question['詳解'])
    
    print(f"模擬考試結束，總分: {score}/{total_questions}")

learning_agent = LearningAgent()
simulate_exam_with_learning(learning_agent, exam_questions)
```