커넥터와 웹 검색으로 퀵스타트 생성기 만들기
커넥터와 웹 검색으로 퀵스타트 생성기 만들기 (Build a Quickstart Generator with Connectors and Web Search)
Polars(Python용 빠른 DataFrame 라이브러리)를 배우고 싶다고 가정해 볼게요. 직접 문서를 읽고 블로그 포스트를 훑어보며 퀵스타트를 조립할 수도 있지만, Mistral에게 적절한 도구 접근권을 주고 대신 처리하게 할 수도 있어요. 이 노트북은 같은 프롬프트를 네 번 보내면서 각각 다른 도구 구성을 사용해서, 모델에 더 나은 소스를 줄수록 출력 품질이 어떻게 향상되는지 보여줘요.
출처: 문서
본문
Polars(Python용 빠른 DataFrame 라이브러리)를 배우고 싶다고 가정해 볼게요. 문서를 읽고, 블로그 포스트를 훑어보고, 퀵스타트를 직접 조립할 수도 있지만 — 올바른 도구에 접근할 수 있는 Mistral에게 맡길 수도 있어요.
이 노트북은 동일한 프롬프트를 네 번 보내되, 각각 다른 도구 구성을 사용해요. 모델에 더 나은 소스를 줄수록 출력 품질이 어떻게 향상되는지 볼 수 있어요.
| Step | Tools | What the model can access |
|---|---|---|
| 1 | None | Training data only |
| 2 | Web search | Blog posts, Stack Overflow, release notes |
| 3 | Context7 connector | Official Polars documentation |
| 4 | Both | Docs + web — the model picks the best source per sub-topic |
| 5 | Filtered connector | A single doc-retrieval tool (skip the resolver) |
API 상태 (API status): 이 노트북은 client.beta.connectors와 client.beta.conversations를 사용해요. 이들은 베타(beta) 엔드포인트로 변경될 수 있어요. 최신 API 참조는 Connectors 문서를 참조하세요.
셀을 위에서 아래로 실행하세요. Conversations API의 TypeScript 버전은 레퍼런스 쿡북에서 다룹니다.
사전 준비사항 (Prerequisites)
이 노트북을 완료하려면 다음이 필요해요.
- Python 3.9 이상
- Mistral 계정과 API 키
환경 설정 (Environment setup)
아래 셀을 실행해서 Mistral Python SDK를 설치해요.
이 쿡북을 완료하려면 Mistral API 키가 필요해요. Studio에서 API keys 섹션으로 이동해서, Connector access scope에 대해 Private and shared connectors를 선택하고 새 API 키를 만들어요.
클라이언트 셀을 실행하기 전에 다음 옵션 중 하나로 설정하세요.
옵션 1 — 환경 변수 (로컬 사용에 권장):
MISTRAL_API_KEY=your-mistral-api-key
옵션 2 — 프롬프트 때 입력: MISTRAL_API_KEY가 환경에 아직 설정되어 있지 않다면, 다음 코드 셀에서 키를 직접 붙여넣을 수 있는 안전한 입력 필드가 표시돼요.
Python
%pip install mistralai --quiet
SDK를 가져오고 클라이언트를 만들어요. MISTRAL_API_KEY가 환경 변수로 설정되어 있지 않다면, 안전한 입력 프롬프트가 나타나요.
import getpass
import os
from mistralai.client import Mistral
if not os.environ.get("MISTRAL_API_KEY"):
os.environ["MISTRAL_API_KEY"] = getpass.getpass("Mistral API key: ")
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
1단계 — 기준선: 도구 없음 (Step 1 — Baseline: no tools)
먼저 도구 없이 모델에게 Polars 퀵스타트를 생성하도록 요청해요. 모델은 학습 데이터만 사용할 수 있으므로, 지식 컷오프 이후 바뀐 것은 빠지거나 틀릴 거예요.
공정한 비교를 위해 PROMPT를 한 번 정의하고 1~4단계에서 재사용해요.
Python
PROMPT = (
"Write a Polars quickstart for a developer who knows pandas. "
"Cover: installation, reading a CSV, filtering rows, groupby aggregation, "
"and lazy evaluation. End with 3 gotchas when migrating from pandas. "
"Include runnable code examples."
)
print("--- Step 1: Baseline (no tools) ---\n")
response = await client.beta.conversations.start_async(
model="mistral-medium-latest",
inputs=[{"role": "user", "content": PROMPT}],
)
for output in response.outputs:
if getattr(output, "type", None) == "message.output":
content = output.content
if isinstance(content, str):
print(content)
else:
print("".join(getattr(c, "text", str(c)) for c in content))
2단계 — 웹 검색 (Step 2 — Web search)
내장 도구로 web_search를 추가하면 모델이 최신 정보(최근 블로그 포스트, Stack Overflow 답변, 릴리스 노트)를 끌어올 수 있어요. 커넥터 설정은 필요 없어요.
출력을 1단계와 비교해 보세요. 더 최신 구문과 커뮤니티 팁을 볼 수 있을 거예요.
print("--- Step 2: Web search ---\n")
response = await client.beta.conversations.start_async(
model="mistral-medium-latest",
inputs=[{"role": "user", "content": PROMPT}],
tools=[{"type": "web_search"}],
)
for output in response.outputs:
if getattr(output, "type", None) == "message.output":
content = output.content
if isinstance(content, str):
print(content)
else:
print("".join(getattr(c, "text", str(c)) for c in content))
3단계 — Context7 커넥터: 공식 문서 (Step 3 — Context7 connector: official docs)
Context7는 인기 오픈소스 라이브러리의 최신 문서를 제공하는 MCP 서버예요. 인증이 필요 없어서 첫 커넥터로 좋아요.
이 단계는 세 부분으로 나뉘어요.
- Create: Context7의 MCP 엔드포인트를 가리키는 커넥터를 만들어요.
- Register credentials: 자격 증명을 등록해요(Context7은 공개 서비스라 비어있지만, 레코드는 존재해야 해요).
- List tools: 커넥터가 노출하는 도구를 확인해요 (5단계에서 이 이름들을 사용할 거예요).
CONTEXT7_URL = "https://mcp.context7.com/mcp"
connector = await client.beta.connectors.create_async(
name="quickstart_context7",
description="Context7 connector — library documentation lookup",
server=CONTEXT7_URL,
visibility="private",
)
print(f"Created: {connector.name} (id={connector.id})")
await client.beta.connectors.create_or_update_user_credentials_async(
connector_id_or_name=connector.name,
name=f"{connector.name}-default",
credentials={"headers": {}},
is_default=True,
)
print(f"Credentials registered for {connector.name}")
tools_list = await client.beta.connectors.list_tools_async(
connector_id_or_name=connector.name,
)
print(f"\nTools exposed by {connector.name}:")
DOC_TOOL_NAME = None
for tool in tools_list:
print(f" - {tool.name}: {tool.description}")
if "documentation" in (tool.description or "").lower() or "doc" in tool.name.lower():
DOC_TOOL_NAME = tool.name
if DOC_TOOL_NAME:
print(f"\nDoc-retrieval tool for Step 5: {DOC_TOOL_NAME}")
else:
print("\nNo doc-retrieval tool auto-detected — check tool names above and set DOC_TOOL_NAME manually.")
Context7 커넥터가 연결된 에이전트를 만들어요. 커넥터 도구 호출(tool.execution.started, tool.execution.delta, tool.execution.done)을 실시간으로 스트리밍하고 지켜볼 수 있도록 conversations API 대신 에이전트를 사용해요. 지시사항은 모델이 학습 데이터만으로 의존하지 않고 커넥터를 사용하도록 안내해요.
connector_agent = await client.beta.agents.create_async(
name="quickstart_context7_agent",
model="mistral-medium-latest",
instructions=(
"You are a helpful programming assistant. "
"When asked about a library, always use the Context7 connector to look up "
"the official documentation before answering. Do not rely on training data alone."
),
tools=[{"type": "connector", "connector_id": connector.id}],
)
print(f"Agent ready: {connector_agent.name} (id={connector_agent.id})")
이제 대화에서 에이전트를 사용해요. 모델이 공식 Polars 문서에 접근하므로 권위 있는 API 참조를 볼 수 있어야 하지만, 블로그에 있는 커뮤니티 팁과 마이그레이션 조언은 놓칠 수 있어요.
Python
print("--- Step 3: Context7 connector (official docs) ---\n")
conversation_id = None
async for event in await client.beta.conversations.start_stream_async(
agent_id=connector_agent.id,
inputs=[{"role": "user", "content": PROMPT}],
timeout_ms=300_000,
):
data = event.data
event_type = getattr(data, "type", None)
if event_type == "conversation.response.started":
conversation_id = data.conversation_id
elif event_type == "message.output.delta":
print(".", end="", flush=True)
else:
name = getattr(data, "name", "")
print(f"\n[{event_type}]{' ' + name if name else ''}")
messages = await client.beta.conversations.get_messages_async(
conversation_id=conversation_id
)
last_output = next(
(m for m in reversed(messages.messages)
if getattr(m, "type", None) == "message.output"),
None,
)
if last_output:
print("\n")
content = last_output.content
if isinstance(content, str):
print(content)
else:
print("".join(getattr(c, "text", str(c)) for c in content))
4단계 — 두 도구 결합 (Step 4 — Both tools combined)
이것이 핵심이에요. 에이전트를 다시 업데이트해서, 이번에는 웹 검색 그리고 Context7 커넥터를 둘 다 주는 거예요. 모델은 정확한 API 예시를 위해 공식 문서를, 커뮤니티 지혜·마이그레이션 함정·최근 릴리스 노트를 위해 웹 결과를 끌어올 수 있어요. 각 하위 주제에 어떤 소스를 쓸지 스스로 결정해요.
이 출력을 1~3단계와 비교해 보세요. 결합 버전이 눈에 띄게 더 풍부해요.
Python
print("--- Step 4: Web search + Context7 connector ---\n")
combined_agent = await client.beta.agents.update_async(
agent_id=connector_agent.id,
tools=[
{"type": "web_search"},
{"type": "connector", "connector_id": connector.id},
],
)
conversation_id = None
async for event in await client.beta.conversations.start_stream_async(
agent_id=combined_agent.id,
inputs=[{"role": "user", "content": PROMPT}],
timeout_ms=300_000,
):
data = event.data
event_type = getattr(data, "type", None)
if event_type == "conversation.response.started":
conversation_id = data.conversation_id
elif event_type == "message.output.delta":
print(".", end="", flush=True)
else:
name = getattr(data, "name", "")
print(f"\n[{event_type}]{' ' + name if name else ''}")
messages = await client.beta.conversations.get_messages_async(
conversation_id=conversation_id
)
last_output = next(
(m for m in reversed(messages.messages)
if getattr(m, "type", None) == "message.output"),
None,
)
if last_output:
print("\n")
content = last_output.content
if isinstance(content, str):
print(content)
else:
print("".join(getattr(c, "text", str(c)) for c in content))
5단계 — 도구 필터링 (Step 5 — Tool filtering)
Context7은 여러 도구를 노출해요: 라이브러리 ID를 이름에서 찾는 리졸버(resolver)와 라이브러리 ID로 페이지를 가져오는 문서 검색 도구가 있어요. 라이브러리 ID를 이미 안다면 tool_configuration.include를 사용해 커넥터를 문서 검색 도구로만 제한해서 리졸버를 건너뛸 수 있어요.
에이전트를 마지막으로 업데이트해서, 도구를 단일 필터링된 커넥터로 교체해요. 이 단계는 또한 Polars 라이브러리를 미리 지정해서 리졸버가 불필요하도록 하는, 더 집중된 다른 프롬프트를 사용해요.
Python
FILTERED_PROMPT = (
"Using the Polars documentation, explain lazy evaluation in Polars. "
"Cover: what LazyFrame is, how to build a lazy query with .lazy(), "
"how .collect() triggers execution, and when to prefer lazy over eager. "
"Include a runnable before/after code example."
)
if DOC_TOOL_NAME:
print(f"--- Step 5: Filtered connector (only {DOC_TOOL_NAME}) ---\n")
filtered_agent = await client.beta.agents.update_async(
agent_id=combined_agent.id,
tools=[
{
"type": "connector",
"connector_id": connector.id,
"tool_configuration": {
"include": [DOC_TOOL_NAME],
},
},
],
)
conversation_id = None
async for event in await client.beta.conversations.start_stream_async(
agent_id=filtered_agent.id,
inputs=[{"role": "user", "content": FILTERED_PROMPT}],
timeout_ms=300_000,
):
data = event.data
event_type = getattr(data, "type", None)
if event_type == "conversation.response.started":
conversation_id = data.conversation_id
elif event_type == "message.output.delta":
print(".", end="", flush=True)
else:
name = getattr(data, "name", "")
print(f"\n[{event_type}]{' ' + name if name else ''}")
messages = await client.beta.conversations.get_messages_async(
conversation_id=conversation_id
)
last_output = next(
(m for m in reversed(messages.messages)
if getattr(m, "type", None) == "message.output"),
None,
)
if last_output:
print("\n")
content = last_output.content
if isinstance(content, str):
print(content)
else:
print("".join(getattr(c, "text", str(c)) for c in content))
else:
print("Skipped — DOC_TOOL_NAME was not set. Set it manually from the tool list in Step 3.")
비교 (Comparison)
각 구성이 어떻게 수행됐는지 살펴볼게요.
| Step | Tools | Strengths | Weaknesses |
|---|---|---|---|
| 1 | None | Fast, no setup | May have outdated syntax, no citations |
| 2 | Web search | Current info, community tips, migration advice | May surface low-quality sources |
| 3 | Context7 connector | Authoritative API docs, correct signatures | Misses community wisdom and gotchas |
| 4 | Both | Best of both — accurate docs + practical tips | Slightly longer response time |
| 5 | Filtered connector | Precise — skips unnecessary tool calls | Requires knowing tool names upfront |
정리 (Cleanup)
작업이 끝나면 에이전트와 커넥터를 삭제해요. 2~5단계에서 단일 에이전트를 재사용(매번 도구를 업데이트)했으므로 정리할 에이전트는 하나뿐이에요.
Python
await client.beta.agents.delete_async(agent_id=connector_agent.id)
print(f"Agent deleted: {connector_agent.name}")
result = await client.beta.connectors.delete_async(connector_id=connector.id)
print(f"Connector deleted: {connector.name} — {result.message}")
요약 (Summary)
이 노트북은 Mistral 대화에 도구를 추가하면 출력 품질이 점진적으로 어떻게 향상되는지 보여줬어요. 학습 데이터만 사용하는 기준선 응답부터, 웹 검색과 문서 커넥터를 거쳐, 둘을 결합해 가장 풍부한 결과를 얻기까지요.
만든 것 (What you built):
- 도구를 추가할 때마다 개선되는 Polars 퀵스타트 생성기
- 공식 라이브러리 문서를 가져오는 Context7 커넥터
- 불필요한 커넥터 도구를 건너뛰는 필터링된 도구 구성
사용한 Mistral 기능 (Mistral features used):
- Connectors (beta)
- Conversations API (beta)
- Agents API (beta) — 도구 실행 이벤트 스트리밍에 사용
- Web search 내장 도구
- Tool filtering (
tool_configuration.include)
기타 서비스 (Other services):
- Context7 — 오픈소스 라이브러리 문서용 MCP 서버
Connector를 Studio에서 확인할 수 있어요.