Conversational search with RAG
출처: 문서
본문
RAG를 사용한 대화형 검색
대화형 검색을 사용하면 자연어로 질문하고 후속 질문을 통해 답변을 구체화할 수 있습니다. 따라서 대화는 사용자와 대규모 언어 모델(LLM) 간의 대화가 됩니다. 이렇게 하려면 모델이 각 질문에 개별적으로 답변하는 대신 전체 대화의 맥락을 기억해야 합니다.
대화형 검색은 다음 구성 요소로 구현됩니다:
- 대화 기록: LLM이 현재 대화의 맥락을 기억하고 후속 질문을 이해할 수 있도록 합니다.
- 검색 증강 생성(RAG): LLM이 정적 지식 베이스를 독점 정보나 최신 정보로 보완할 수 있도록 합니다.
대화 기록
대화 기록은 _메모리_와 _메시지_라는 두 가지 리소스로 구성된 간단한 CRUD 유사 API로 구성됩니다. 현재 대화의 모든 메시지는 하나의 대화 _메모리_에 저장됩니다. _메시지_는 질문/답변 쌍, 즉 사람이 입력한 질문과 AI 답변을 나타냅니다. 메시지는 단독으로 존재하지 않으며 메모리에 추가되어야 합니다.
RAG
RAG는 인덱스와 기록에서 데이터를 검색하고 모든 정보를 컨텍스트로 LLM에 보냅니다. 그러면 LLM은 동적으로 검색된 데이터로 정적 지식 베이스를 보완합니다. OpenSearch에서 RAG는 검색 증강 생성 프로세서를 포함하는 검색 파이프라인을 통해 구현됩니다. 프로세서는 OpenSearch 쿼리 결과를 가로채고, 대화 메모리에서 대화의 이전 메시지를 검색한 후 프롬프트를 LLM에 보냅니다. 프로세서가 LLM으로부터 응답을 받으면 응답을 대화 메모리에 저장하고 원래 OpenSearch 쿼리 결과와 LLM 응답을 모두 반환합니다.
RAG 기술은 OpenAI, Amazon Bedrock 및 Cohere 모델을 지원합니다. 다른 모델을 사용하려면 llm_response_field 매개변수를 설정하세요. 자세한 내용은 6단계: RAG에 파이프라인 사용을 참조하세요.
{: .note}
Security 플러그인이 활성화되면 모든 메모리는 private 보안 모드로 존재합니다. 메모리를 생성한 사용자만 해당 메모리와 상호 작용할 수 있습니다. 어떤 사용자도 다른 사용자의 메모리를 볼 수 없습니다.
{: .note}
전제 조건
대화형 검색을 사용하려면 대화 메모리 및 RAG 파이프라인 기능을 활성화하세요:
PUT /_cluster/settings
{
"persistent": {
"plugins.ml_commons.memory_feature_enabled": true,
"plugins.ml_commons.rag_pipeline_feature_enabled": true
}
}
{% include copy-curl.html %}
대화형 검색 구성
대화형 검색을 구성하는 방법은 두 가지입니다:
- 자동 워크플로 (빠른 설정에 권장): 최소한의 구성으로 수집 파이프라인과 인덱스를 자동으로 생성합니다.
- 수동 설정 (사용자 지정 구성에 권장): 각 구성 요소를 수동으로 구성하여 유연성과 제어력을 높입니다.
자동 워크플로
OpenSearch는 LLM용 커넥터를 자동으로 생성하고, LLM을 등록 및 배포하며, 검색 파이프라인을 구성하는 워크플로 템플릿을 제공합니다. 워크플로를 생성할 때 구성된 LLM의 API 키를 제공해야 합니다. 대화형 검색 워크플로 템플릿 기본값을 검토하여 매개변수를 업데이트해야 하는지 확인하세요. 예를 들어 모델 엔드포인트가 기본값(https://api.cohere.ai/v1/chat)과 다른 경우 create_connector.actions.url 매개변수에 모델의 엔드포인트를 지정하세요. 기본 대화형 검색 워크플로를 생성하려면 다음 요청을 보내세요:
POST /_plugins/_flow_framework/workflow?use_case=conversational_search_with_llm_deploy&provision=true
{
"create_connector.credential.key": "<YOUR_API_KEY>"
}
{% include copy-curl.html %}
OpenSearch는 생성된 워크플로의 워크플로 ID로 응답합니다:
{
"workflow_id" : "U_nMXJUBq_4FYQzMOS4B"
}
워크플로 상태를 확인하려면 다음 요청을 보내세요:
GET /_plugins/_flow_framework/workflow/U_nMXJUBq_4FYQzMOS4B/_status
{% include copy-curl.html %}
워크플로가 완료되면 state가 COMPLETED로 변경됩니다. 워크플로는 다음 구성 요소를 생성합니다:
- 모델 커넥터: 지정된 모델에 연결합니다.
- 등록 및 배포된 모델: 모델이 추론할 준비가 되었습니다.
- 검색 파이프라인: 대화형 쿼리를 처리하도록 구성됩니다.
이제 4, 5, 6단계를 계속 진행하여 RAG 데이터를 인덱스에 수집하고, 대화 메모리를 생성하고, RAG에 파이프라인을 사용할 수 있습니다.
수동 설정
대화형 검색을 수동으로 구성하려면 다음 단계를 따르세요:
1단계: 모델용 커넥터 생성
RAG가 작동하려면 LLM이 필요합니다. LLM에 연결하려면 커넥터를 생성하세요. 다음 요청은 OpenAI gpt-4o-mini 모델용 커넥터를 생성합니다:
POST /_plugins/_ml/connectors/_create
{
"name": "OpenAI Chat Connector",
"description": "The connector to public OpenAI model service for gpt-4o-mini",
"version": 2,
"protocol": "http",
"parameters": {
"endpoint": "api.openai.com",
"model": "gpt-4o-mini",
"temperature": 0
},
"credential": {
"openAI_key": "<YOUR_OPENAI_KEY>"
},
"actions": [
{
"action_type": "predict",
"method": "POST",
"url": "https://${parameters.endpoint}/v1/chat/completions",
"headers": {
"Authorization": "Bearer ${credential.openAI_key}"
},
"request_body": """{ "model": "${parameters.model}", "messages": ${parameters.messages}, "temperature": ${parameters.temperature} }"""
}
]
}
{% include copy-curl.html %}
OpenSearch는 커넥터의 커넥터 ID로 응답합니다:
{
"connector_id": "u3DEbI0BfUsSoeNTti-1"
}
다른 서비스 및 모델에 연결하는 예제 요청은 커넥터 청사진을 참조하세요. {: .tip}
2단계: 모델 등록 및 배포
이전 단계에서 커넥터를 생성한 LLM을 등록하세요. OpenSearch에 모델을 등록하려면 이전 단계에서 반환된 connector_id를 제공하세요:
POST /_plugins/_ml/models/_register
{
"name": "openAI-gpt-4o-mini",
"function_name": "remote",
"description": "test model",
"connector_id": "u3DEbI0BfUsSoeNTti-1"
}
{% include copy-curl.html %}
OpenSearch는 등록 작업의 작업 ID와 등록된 모델의 모델 ID를 반환합니다:
{
"task_id": "gXDIbI0BfUsSoeNT_jAb",
"status": "CREATED",
"model_id": "gnDIbI0BfUsSoeNT_jAw"
}
등록이 완료되었는지 확인하려면 Get ML Task API를 호출하세요:
GET /_plugins/_ml/tasks/gXDIbI0BfUsSoeNT_jAb
{% include copy-curl.html %}
응답에서 state가 COMPLETED로 변경됩니다:
{
"model_id": "gnDIbI0BfUsSoeNT_jAw",
"task_type": "REGISTER_MODEL",
"function_name": "REMOTE",
"state": "COMPLETED",
"worker_node": [
"kYv-Z5-mQ4uCUy_cRC6LXA"
],
"create_time": 1706927128091,
"last_update_time": 1706927128125,
"is_async": false
}
모델을 배포하려면 model_id를 Deploy API에 제공하세요:
POST /_plugins/_ml/models/gnDIbI0BfUsSoeNT_jAw/_deploy
{% include copy-curl.html %}
OpenSearch는 모델이 배포되었음을 확인합니다:
{
"task_id": "cnDObI0BfUsSoeNTDzGd",
"task_type": "DEPLOY_MODEL",
"status": "COMPLETED"
}
3단계: 검색 파이프라인 생성
다음으로 retrieval_augmented_generation 프로세서를 사용하여 검색 파이프라인을 생성합니다:
PUT /_search/pipeline/rag_pipeline
{
"response_processors": [
{
"retrieval_augmented_generation": {
"tag": "openai_pipeline_demo",
"description": "Demo pipeline Using OpenAI Connector",
"model_id": "gnDIbI0BfUsSoeNT_jAw",
"context_field_list": ["text"],
"system_prompt": "You are a helpful assistant",
"user_instructions": "Generate a concise and informative answer in less than 100 words for the given question"
}
}
]
}
{% include copy-curl.html %}
프로세서 필드에 대한 자세한 내용은 검색 증강 생성 프로세서를 참조하세요.
4단계: RAG 데이터를 인덱스에 수집
RAG는 LLM 지식을 일부 보충 데이터로 보강합니다.
먼저 이 데이터를 저장할 인덱스를 생성하고 기본 검색 파이프라인을 이전 단계에서 생성한 파이프라인으로 설정합니다:
PUT /my_rag_test_data
{
"settings": {
"index.search.default_pipeline" : "rag_pipeline"
},
"mappings": {
"properties": {
"text": {
"type": "text"
}
}
}
}
{% include copy-curl.html %}
다음으로 보충 데이터를 인덱스에 수집합니다:
POST _bulk
{"index": {"_index": "my_rag_test_data", "_id": "1"}}
{"text": "Abraham Lincoln was born on February 12, 1809, the second child of Thomas Lincoln and Nancy Hanks Lincoln, in a log cabin on Sinking Spring Farm near Hodgenville, Kentucky.[2] He was a descendant of Samuel Lincoln, an Englishman who migrated from Hingham, Norfolk, to its namesake, Hingham, Massachusetts, in 1638. The family then migrated west, passing through New Jersey, Pennsylvania, and Virginia.[3] Lincoln was also a descendant of the Harrison family of Virginia; his paternal grandfather and namesake, Captain Abraham Lincoln and wife Bathsheba (née Herring) moved the family from Virginia to Jefferson County, Kentucky.[b] The captain was killed in an Indian raid in 1786.[5] His children, including eight-year-old Thomas, Abraham's father, witnessed the attack.[6][c] Thomas then worked at odd jobs in Kentucky and Tennessee before the family settled in Hardin County, Kentucky, in the early 1800s."}
{"index": {"_index": "my_rag_test_data", "_id": "2"}}
{"text": "Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019."}
{% include copy-curl.html %}
RAG 파이프라인
RAG는 인덱스에서 문서를 검색하고, 이를 LLM과 같은 seq2seq 모델에 전달한 다음, 정적 LLM 정보를 컨텍스트에서 동적으로 검색된 데이터로 보충하는 기술이에요.
RAG 기술은 OpenAI, Amazon Bedrock 및 Cohere 모델을 지원해요. 다른 모델을 사용하려면 llm_response_field 매개변수를 설정하세요. 자세한 내용은 6단계: RAG 파이프라인 사용하기를 참조하세요.
{: .note}
RAG를 활성화하기 위해 Cohere Command 모델을 구성하려면 후처리 함수를 사용하여 모델 출력을 변환해야 해요. 자세한 내용은 Cohere RAG 튜토리얼을 참조하세요.
5단계: 대화 메모리 생성하기
대화의 모든 메시지를 저장할 대화 메모리를 생성해야 해요. 메모리를 쉽게 식별할 수 있도록 다음 예제와 같이 선택적 name 필드에 메모리 이름을 제공하세요. name 매개변수는 업데이트할 수 없으므로, 이것이 대화에 이름을 지정할 수 있는 유일한 기회예요.
POST /_plugins/_ml/memory/
{
"name": "Conversation about NYC population"
}
{% include copy-curl.html %}
OpenSearch는 새로 생성된 메모리에 대한 메모리 ID로 응답해요:
{
"memory_id": "znCqcI0BfUsSoeNTntd7"
}
memory_id를 사용하여 메모리에 메시지를 추가할 거예요.
6단계: RAG 파이프라인 사용하기
RAG 파이프라인을 사용하려면 OpenSearch에 쿼리를 보내고 ext.generative_qa_parameters 객체에 추가 매개변수를 제공하세요.
generative_qa_parameters 객체는 다음 매개변수를 지원해요.
| 매개변수 | 필수 | 설명 |
|---|---|---|
llm_question |
조건부 | LLM이 답변해야 하는 질문이에요. llm_messages가 제공되지 않은 경우 필수예요. |
llm_model |
아니요 | 다른 모델(예: gpt-4o-mini 대신 gpt-4o)을 사용하려는 경우 연결에 설정된 원래 모델을 재정의해요. 파이프라인 생성 중에 기본 모델이 설정되지 않은 경우 이 옵션이 필요해요. 값 접두사는 프로세서가 사용하는 요청 및 응답 형식을 결정해요: Amazon Bedrock 모델의 경우 bedrock/, Amazon Bedrock Converse API의 경우 bedrock-converse/, Cohere 모델의 경우 cohere/, OpenAI 모델의 경우 접두사 없음. |
llm_response_field |
아니요 | LLM 답변이 포함된 모델 응답의 최상위 필드 이름이에요. llm_model 접두사로 처리되지 않는 요청 및 응답 형식을 가진 모델에 이 매개변수를 사용하세요. 이 매개변수가 설정되면 프로세서는 llm_model 접두사를 무시하고 프롬프트를 inputs 커넥터 매개변수의 단일 문자열로 전송하므로, 커넥터 요청 본문은 ${parameters.inputs}를 참조해야 해요. |
llm_messages |
조건부 | 검색 결과 및 대화 기록 후 LLM에 전송할 메시지 배열이에요. 각 메시지는 role과 content 배열을 포함하는 객체예요. 각 content 요소는 다음 객체 중 하나를 포함해요: text(문자열), image(format과 data 또는 url을 포함하는 객체), 또는 document(format, name, data를 포함하는 객체). OpenAI 모델 및 Amazon Bedrock Converse API(bedrock-converse/ 접두사)를 사용하는 모델에서만 지원돼요. llm_question이 제공되지 않은 경우 필수예요. |
system_prompt |
아니요 | 이 요청에 대해 LLM에 전송되는 시스템 프롬프트예요. 프로세서에 설정된 system_prompt를 재정의해요. |
user_instructions |
아니요 | 이 요청에 대해 LLM에 전송되는 사용자 지침이에요. 프로세서에 설정된 user_instructions를 재정의해요. |
memory_id |
아니요 | memory_id를 제공하면 파이프라인이 지정된 메모리에서 가장 최근 메시지 10개를 검색하여 LLM 프롬프트에 추가해요. memory_id를 지정하지 않으면 이전 컨텍스트가 LLM 프롬프트에 추가되지 않아요. |
context_size |
아니요 | LLM에 전송되는 검색 결과 수예요. 이는 모델에 따라 달라질 수 있는 토큰 크기 제한을 충족하기 위해 일반적으로 필요해요. 또는 Search API의 size 매개변수를 사용하여 LLM에 전송되는 검색 결과 수를 제어할 수 있어요. |
message_size |
아니요 | LLM에 전송되는 메시지 수예요. 검색 결과 수와 마찬가지로 LLM이 수신하는 총 토큰 수에 영향을 미쳐요. 설정하지 않으면 파이프라인은 기본 메시지 크기인 10을 사용해요. |
timeout |
아니요 | 파이프라인이 커넥터를 사용하는 원격 모델의 응답을 기다리는 시간(초)이에요. 기본값은 30이에요. |
LLM에 설정된 토큰 제한이 있는 경우 OpenSearch 쿼리의 size 필드를 설정하여 검색 응답에 사용되는 문서 수를 제한하세요. 그렇지 않으면 RAG 파이프라인이 검색 결과의 모든 문서를 LLM에 전송해요.
{: .note}
LLM에게 현재에 관한 질문을 하면, 몇 년 전 데이터로 학습되었기 때문에 답변을 제공할 수 없어요. 하지만 현재 정보를 컨텍스트로 추가하면 LLM이 응답을 생성할 수 있어요. 예를 들어, 2023년 뉴욕시 대도시 지역의 인구에 대해 LLM에게 물어볼 수 있어요. OpenSearch match query와 LLM 쿼리를 포함하는 쿼리를 구성할 거예요. 메시지가 적절한 메모리 객체에 저장되도록 memory_id를 제공하세요:
GET /my_rag_test_data/_search
{
"query": {
"match": {
"text": "What's the population of NYC metro area in 2023"
}
},
"ext": {
"generative_qa_parameters": {
"llm_model": "gpt-4o-mini",
"llm_question": "What's the population of NYC metro area in 2023",
"memory_id": "znCqcI0BfUsSoeNTntd7",
"context_size": 5,
"message_size": 5,
"timeout": 15
}
}
}
{% include copy-curl.html %}
컨텍스트에 뉴욕시 인구에 대한 정보가 포함된 문서가 있었기 때문에 LLM이 질문에 올바르게 답변할 수 있었어요(이전 연도 데이터로 학습되었기 때문에 "projected"라는 단어를 포함했지만). 응답에는 보충 RAG 데이터의 일치하는 문서와 LLM 응답이 포함되어 있어요:
응답
{: .text-delta}{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 5.781642,
"hits": [
{
"_index": "my_rag_test_data",
"_id": "2",
"_score": 5.781642,
"_source": {
"text": """Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019."""
}
},
{
"_index": "my_rag_test_data",
"_id": "1",
"_score": 0.9782871,
"_source": {
"text": "Abraham Lincoln was born on February 12, 1809, the second child of Thomas Lincoln and Nancy Hanks Lincoln, in a log cabin on Sinking Spring Farm near Hodgenville, Kentucky.[2] He was a descendant of Samuel Lincoln, an Englishman who migrated from Hingham, Norfolk, to its namesake, Hingham, Massachusetts, in 1638. The family then migrated west, passing through New Jersey, Pennsylvania, and Virginia.[3] Lincoln was also a descendant of the Harrison family of Virginia; his paternal grandfather and namesake, Captain Abraham Lincoln and wife Bathsheba (née Herring) moved the family from Virginia to Jefferson County, Kentucky.[b] The captain was killed in an Indian raid in 1786.[5] His children, including eight-year-old Thomas, Abraham's father, witnessed the attack.[6][c] Thomas then worked at odd jobs in Kentucky and Tennessee before the family settled in Hardin County, Kentucky, in the early 1800s."
}
}
]
},
"ext": {
"retrieval_augmented_generation": {
"answer": "The population of the New York City metro area in 2023 is projected to be 18,937,000.",
"message_id": "x3CecI0BfUsSoeNT9tV9"
}
}
}
이제 같은 대화의 일부로 LLM에게 후속 질문을 할 거예요. 다시 요청에 memory_id를 제공하세요:
GET /my_rag_test_data/_search
{
"query": {
"match": {
"text": "What was it in 2022"
}
},
"ext": {
"generative_qa_parameters": {
"llm_model": "gpt-4o-mini",
"llm_question": "What was it in 2022",
"memory_id": "znCqcI0BfUsSoeNTntd7",
"context_size": 5,
"message_size": 5,
"timeout": 15
}
}
}
{% include copy-curl.html %}
LLM이 대화 주제를 올바르게 식별하고 관련 응답을 반환해요:
{
...
"ext": {
"retrieval_augmented_generation": {
"answer": "The population of the New York City metro area in 2022 was 18,867,000.",
"message_id": "p3CvcI0BfUsSoeNTj9iH"
}
}
}
두 메시지가 모두 메모리에 추가되었는지 확인하려면 Get Messages API에 memory_ID를 제공하세요:
GET /_plugins/_ml/memory/znCqcI0BfUsSoeNTntd7/messages
응답에는 두 메시지가 모두 포함되어 있어요:
응답
{: .text-delta}{
"messages": [
{
"memory_id": "znCqcI0BfUsSoeNTntd7",
"message_id": "x3CecI0BfUsSoeNT9tV9",
"create_time": "2024-02-03T20:33:50.754708446Z",
"input": "What's the population of NYC metro area in 2023",
"prompt_template": """[{"role":"system","content":"You are a helpful assistant"},{"role":"user","content":"Generate a concise and informative answer in less than 100 words for the given question"}]""",
"response": "The population of the New York City metro area in 2023 is projected to be 18,937,000.",
"origin": "retrieval_augmented_generation",
"additional_info": {
"metadata": """["Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019.","Abraham Lincoln was born on February 12, 1809, the second child of Thomas Lincoln and Nancy Hanks Lincoln, in a log cabin on Sinking Spring Farm near Hodgenville, Kentucky.[2] He was a descendant of Samuel Lincoln, an Englishman who migrated from Hingham, Norfolk, to its namesake, Hingham, Massachusetts, in 1638. The family then migrated west, passing through New Jersey, Pennsylvania, and Virginia.[3] Lincoln was also a descendant of the Harrison family of Virginia; his paternal grandfather and namesake, Captain Abraham Lincoln and wife Bathsheba (née Herring) moved the family from Virginia to Jefferson County, Kentucky.[b] The captain was killed in an Indian raid in 1786.[5] His children, including eight-year-old Thomas, Abraham's father, witnessed the attack.[6][c] Thomas then worked at odd jobs in Kentucky and Tennessee before the family settled in Hardin County, Kentucky, in the early 1800s."]"""
}
},
{
"memory_id": "znCqcI0BfUsSoeNTntd7",
"message_id": "p3CvcI0BfUsSoeNTj9iH",
"create_time": "2024-02-03T20:36:10.24453505Z",
"input": "What was it in 2022",
"prompt_template": """[{"role":"system","content":"You are a helpful assistant"},{"role":"user","content":"Generate a concise and informative answer in less than 100 words for the given question"}]""",
"response": "The population of the New York City metro area in 2022 was 18,867,000.",
"origin": "retrieval_augmented_generation",
"additional_info": {
"metadata": """["Chart and table of population level and growth rate for the New York City metro area from 1950 to 2023. United Nations population projections are also included through the year 2035.\\nThe current metro area population of New York City in 2023 is 18,937,000, a 0.37% increase from 2022.\\nThe metro area population of New York City in 2022 was 18,867,000, a 0.23% increase from 2021.\\nThe metro area population of New York City in 2021 was 18,823,000, a 0.1% increase from 2020.\\nThe metro area population of New York City in 2020 was 18,804,000, a 0.01% decline from 2019.","Abraham Lincoln was born on February 12, 1809, the second child of Thomas Lincoln and Nancy Hanks Lincoln, in a log cabin on Sinking Spring Farm near Hodgenville, Kentucky.[2] He was a descendant of Samuel Lincoln, an Englishman who migrated from Hingham, Norfolk, to its namesake, Hingham, Massachusetts, in 1638. The family then migrated west, passing through New Jersey, Pennsylvania, and Virginia.[3] Lincoln was also a descendant of the Harrison family of Virginia; his paternal grandfather and namesake, Captain Abraham Lincoln and wife Bathsheba (née Herring) moved the family from Virginia to Jefferson County, Kentucky.[b] The captain was killed in an Indian raid in 1786.[5] His children, including eight-year-old Thomas, Abraham's father, witnessed the attack.[6][c] Thomas then worked at odd jobs in Kentucky and Tennessee before the family settled in Hardin County, Kentucky, in the early 1800s."]"""
}
}
]
}
다음 단계
- AI 검색 애플리케이션을 구축하는 방법을 알아보려면 튜토리얼을 살펴보세요.