> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cómo crear un AI Agent con Streamlit y ClickHouse

> Aprende a crear un AI Agent web con Streamlit y el ClickHouse MCP server

En esta guía aprenderás a crear un AI Agent web con [Streamlit](https://streamlit.io/) que puede interactuar con el [Playground de SQL de ClickHouse](https://sql.clickhouse.com/) mediante el [ClickHouse MCP server](https://github.com/ClickHouse/mcp-clickhouse) y [Agno](https://github.com/agno-agi/agno).

<Info>
  **Aplicación de ejemplo**

  Este ejemplo crea una aplicación web completa que ofrece una interfaz de chat para consultar datos de ClickHouse.
  Puedes encontrar el código fuente de este ejemplo en el [repositorio de ejemplos](https://github.com/ClickHouse/examples/tree/main/ai/mcp/streamlit).
</Info>

<div id="prerequisites">
  ## Requisitos previos
</div>

* Deberás tener Python instalado en tu sistema.
  También deberás tener instalado [`uv`](https://docs.astral.sh/uv/getting-started/installation/)
* Necesitarás una API key de Anthropic o una API key de otro proveedor de LLM

Puedes seguir estos pasos para crear tu aplicación de Streamlit.

<Steps>
  <Step title="Instalar bibliotecas" id="install-libraries">
    Instale las bibliotecas necesarias ejecutando los siguientes comandos:

    ```bash theme={null}
    pip install streamlit agno ipywidgets
    ```
  </Step>

  <Step title="Crear archivo de utilidades" id="create-utilities">
    Crea un archivo `utils.py` con dos funciones de utilidad. La primera es una
    función generadora asíncrona para gestionar respuestas en streaming del
    agente Agno. La segunda es una función para aplicar estilos a la
    aplicación de Streamlit:

    ```python title="utils.py" theme={null}
    import streamlit as st
    from agno.run.response import RunEvent, RunResponse

    async def as_stream(response):
        async for chunk in response:
            if isinstance(chunk, RunResponse) and isinstance(chunk.content, str):
                if chunk.event == RunEvent.run_response:
                    yield chunk.content

    def apply_styles():
        st.markdown("""
      <style>
      hr.divider {
      background-color: white;
      margin: 0;
      }
      </style>
      <hr class='divider' />""", unsafe_allow_html=True)
    ```
  </Step>

  <Step title="Configurar credenciales" id="setup-credentials">
    Configura tu clave de API de Anthropic como una variable de entorno:

    ```bash theme={null}
    export ANTHROPIC_API_KEY="your_api_key_here"
    ```

    <Info>
      **Uso de otro proveedor de LLM**

      Si no tienes una API key de Anthropic y quieres usar otro proveedor de LLM,
      puedes consultar las instrucciones para configurar tus credenciales en la documentación de [Agno "Integrations"](https://docs.agentops.ai/v2/integrations/ag2)
    </Info>
  </Step>

  <Step title="Importa las bibliotecas necesarias" id="import-libraries">
    Empieza creando el archivo principal de tu aplicación de Streamlit (por ejemplo, `app.py`) y añade las importaciones:

    ```python theme={null}
    from utils import apply_styles

    import streamlit as st
    from textwrap import dedent

    from agno.models.anthropic import Claude
    from agno.agent import Agent
    from agno.tools.mcp import MCPTools
    from agno.storage.json import JsonStorage
    from agno.run.response import RunEvent, RunResponse
    from mcp.client.stdio import stdio_client, StdioServerParameters

    from mcp import ClientSession

    import asyncio
    import threading
    from queue import Queue
    ```
  </Step>

  <Step title="Defina la función de transmisión del agente" id="define-agent-function">
    Agregue la función principal del agente que se conecta al [Playground de SQL de ClickHouse](https://sql.clickhouse.com/) y transmite las respuestas:

    ```python theme={null}
    async def stream_clickhouse_agent(message):
        env = {
                "CLICKHOUSE_HOST": "sql-clickhouse.clickhouse.com",
                "CLICKHOUSE_PORT": "8443",
                "CLICKHOUSE_USER": "demo",
                "CLICKHOUSE_PASSWORD": "",
                "CLICKHOUSE_SECURE": "true"
            }
        
        server_params = StdioServerParameters(
            command="uv",
            args=[
            'run',
            '--with', 'mcp-clickhouse',
            '--python', '3.13',
            'mcp-clickhouse'
            ],
            env=env
        )
        
        async with stdio_client(server_params) as (read, write):
            async with ClientSession(read, write) as session:
                mcp_tools = MCPTools(timeout_seconds=60, session=session)
                await mcp_tools.initialize()
                agent = Agent(
                    model=Claude(id="claude-3-5-sonnet-20240620"),
                    tools=[mcp_tools],
                    instructions=dedent("""\
                        You are a ClickHouse assistant. Help users query and understand data using ClickHouse.
                        - Run SQL queries using the ClickHouse MCP tool
                        - Present results in markdown tables when relevant
                        - Keep output concise, useful, and well-formatted
                    """),
                    markdown=True,
                    show_tool_calls=True,
                    storage=JsonStorage(dir_path="tmp/team_sessions_json"),
                    add_datetime_to_instructions=True, 
                    add_history_to_messages=True,
                )
                chunks = await agent.arun(message, stream=True)
                async for chunk in chunks:
                    if isinstance(chunk, RunResponse) and chunk.event == RunEvent.run_response:
                        yield chunk.content
    ```
  </Step>

  <Step title="Añade funciones envoltorio síncronas" id="add-wrapper-functions">
    Añade funciones auxiliares para gestionar el streaming asíncrono en Streamlit:

    ```python theme={null}
    def run_agent_query_sync(message):
        queue = Queue()
        def run():
            asyncio.run(_agent_stream_to_queue(message, queue))
            queue.put(None)  # Sentinel to end stream
        threading.Thread(target=run, daemon=True).start()
        while True:
            chunk = queue.get()
            if chunk is None:
                break
            yield chunk

    async def _agent_stream_to_queue(message, queue):
        async for chunk in stream_clickhouse_agent(message):
            queue.put(chunk)
    ```
  </Step>

  <Step title="Crear la interfaz de Streamlit" id="create-interface">
    Añade los componentes de la UI de Streamlit y la funcionalidad de chat:

    ```python theme={null}
    st.title("A ClickHouse-backed AI agent")

    if st.button("💬 New Chat"):
      st.session_state.messages = []
      st.rerun()

    apply_styles()

    if "messages" not in st.session_state:
      st.session_state.messages = []

    for message in st.session_state.messages:
      with st.chat_message(message["role"]):
        st.markdown(message["content"])

    if prompt := st.chat_input("What is up?"):
      st.session_state.messages.append({"role": "user", "content": prompt})
      with st.chat_message("user"):
        st.markdown(prompt)
      with st.chat_message("assistant"):
        response = st.write_stream(run_agent_query_sync(prompt))
      st.session_state.messages.append({"role": "assistant", "content": response})
    ```
  </Step>

  <Step title="Ejecuta la aplicación" id="run-application">
    Para iniciar la aplicación web del agente de IA de ClickHouse, puedes ejecutar el
    siguiente comando en tu terminal:

    ```bash theme={null}
    uv run \
      --with streamlit \
      --with agno \
      --with anthropic \
      --with mcp \
      streamlit run app.py --server.headless true
    ```

    Esto abrirá tu navegador web y te llevará a `http://localhost:8501`, donde
    podrás interactuar con tu agente de IA y hacerle preguntas sobre los conjuntos de datos de ejemplo
    disponibles en el Playground de SQL de ClickHouse.
  </Step>
</Steps>
