|
PROFESSIONAL NEWSGROUPS WINDEV, WEBDEV and WINDEV Mobile |
| | | | | |
| Home → WINDEV 25 → Como instalar pelo Powershell a sua iA e usar ela com os seus sistemas |
| Como instalar pelo Powershell a sua iA e usar ela com os seus sistemas |
| Started by Boller, Jan., 29 2026 11:35 AM - 2 replies |
| |
| | | |
|
| |
Registered member 4,618 messages |
|
| Posted on January, 29 2026 - 11:35 AM |
<# Phoenix AI - Windows 11 Setup (Ollama + LLaMA + RAG + LangGraph) - Instala dependências Python - Cria venv - Baixa modelos no Ollama - Cria estrutura kb/ - Gera scripts index_kb.py e rag_graph.py - Roda index e inicia o chat RAG
Como usar: 1) Instale manualmente: Python 3.11+ (marque "Add to PATH") e Ollama for Windows. 2) Abra PowerShell como Usuário normal. 3) Rode: .\setup_phoenix_ai.ps1
Obs: Se der erro de ExecutionPolicy: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned #>
$ErrorActionPreference = "Stop"
function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
function Assert-Command($cmd, $hint) { if (-not (Get-Command $cmd -ErrorAction SilentlyContinue)) { Write-Host "`nERRO: '$cmd' não encontrado no PATH." -ForegroundColor Red Write-Host "Dica: $hint" -ForegroundColor Yellow exit 1 } }
Write-Step "Checando pré-requisitos (python, pip, ollama)" Assert-Command "python" "Instale Python 3.11+ (64-bit) e marque 'Add Python to PATH'." Assert-Command "pip" "O pip vem junto do Python. Reinstale o Python marcando PATH." Assert-Command "ollama" "Instale o Ollama for Windows e reabra o PowerShell."
Write-Step "Mostrando versões" python --version pip --version ollama --version
# Pasta do projeto $ProjectDir = Join-Path $PWD "phoenix_ai" Write-Step "Criando pasta do projeto: $ProjectDir" if (-not (Test-Path $ProjectDir)) { New-Item -ItemType Directory -Path $ProjectDir | Out-Null } Set-Location $ProjectDir
# Criar venv $VenvDir = Join-Path $ProjectDir ".venv" Write-Step "Criando venv em: $VenvDir" if (-not (Test-Path $VenvDir)) { python -m venv .venv } else { Write-Host "Venv já existe. Mantendo." -ForegroundColor DarkGray }
# Ativar venv Write-Step "Ativando venv" $ActivatePs1 = Join-Path $VenvDir "Scripts\Activate.ps1" if (-not (Test-Path $ActivatePs1)) { Write-Host "ERRO: Não achei $ActivatePs1" -ForegroundColor Red exit 1 } . $ActivatePs1
# Atualizar pip Write-Step "Atualizando pip" python -m pip install -U pip
# Instalar deps Python Write-Step "Instalando dependências (langgraph, langchain, ollama, chroma)" pip install -U langgraph langchain langchain-ollama langchain-chroma chromadb langchain-text-splitters
# Baixar modelos Ollama Write-Step "Baixando modelos no Ollama (llama3.1 + embeddings)" ollama pull llama3.1 ollama pull mxbai-embed-large
# Estrutura KB Write-Step "Criando estrutura de base de conhecimento (kb/...)" $KbDir = Join-Path $ProjectDir "kb" $KbCommands = Join-Path $KbDir "commands" $KbFunctions = Join-Path $KbDir "functions" $KbCases = Join-Path $KbDir "cases"
foreach ($d in @($KbDir, $KbCommands, $KbFunctions, $KbCases)) { if (-not (Test-Path $d)) { New-Item -ItemType Directory -Path $d | Out-Null } }
# Criar um exemplo mínimo (para você testar na hora) $SampleMd = Join-Path $KbCommands "print.md" if (-not (Test-Path $SampleMd)) { @" # print
## O que faz Imprime texto na saída padrão.
## Sintaxe print(text)
## Parâmetros - text: string
## Retorno - void
## Exemplo print("Olá, Phoenix!") "@ | Set-Content -Path $SampleMd -Encoding utf8 }
# Gerar index_kb.py Write-Step "Gerando index_kb.py" $IndexPy = Join-Path $ProjectDir "index_kb.py" @" import os from pathlib import Path
from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_chroma import Chroma from langchain_ollama import OllamaEmbeddings
KB_DIR = Path("kb") CHROMA_DIR = Path("chroma_db") COLLECTION = "phoenix_kb"
def load_markdown_files(root: Path): docs = [] for p in root.rglob("*.md"): text = p.read_text(encoding="utf-8", errors="ignore") rel = p.relative_to(root).as_posix() docs.append({"text": text, "metadata": {"source": rel}}) return docs
def main(): if not KB_DIR.exists(): raise SystemExit("Pasta kb/ não existe. Crie kb/ e coloque .md lá dentro.")
embeddings = OllamaEmbeddings(model="mxbai-embed-large")
vectorstore = Chroma( collection_name=COLLECTION, persist_directory=str(CHROMA_DIR), embedding_function=embeddings, )
raw_docs = load_markdown_files(KB_DIR)
splitter = RecursiveCharacterTextSplitter( chunk_size=1200, chunk_overlap=150, )
texts = [] metadatas = [] for d in raw_docs: chunks = splitter.split_text(d["text"]) for i, c in enumerate(chunks): texts.append(c) metadatas.append({**d["metadata"], "chunk": i})
vectorstore.add_texts(texts=texts, metadatas=metadatas)
print(f"OK: indexados {len(texts)} chunks em {CHROMA_DIR}/ coleção {COLLECTION}")
if __name__ == "__main__": main() "@ | Set-Content -Path $IndexPy -Encoding utf8
# Gerar rag_graph.py Write-Step "Gerando rag_graph.py" $RagPy = Join-Path $ProjectDir "rag_graph.py" @" from typing_extensions import TypedDict, List
from langgraph.graph import StateGraph, START, END from langchain_chroma import Chroma from langchain_ollama import ChatOllama, OllamaEmbeddings
CHROMA_DIR = "chroma_db" COLLECTION = "phoenix_kb"
class State(TypedDict): question: str contexts: List[str] answer: str
def retrieve(state: State) -> dict: embeddings = OllamaEmbeddings(model="mxbai-embed-large") vs = Chroma( collection_name=COLLECTION, persist_directory=CHROMA_DIR, embedding_function=embeddings, ) retriever = vs.as_retriever(search_kwargs={"k": 6}) docs = retriever.get_relevant_documents(state["question"]) contexts = [d.page_content for d in docs] return {"contexts": contexts}
def generate(state: State) -> dict: llm = ChatOllama(model="llama3.1", temperature=0)
context_text = "\n\n---\n\n".join(state["contexts"]).strip()
prompt = f\""" Você é o assistente oficial da linguagem Phoenix. Responda APENAS usando o contexto abaixo. Se o contexto não tiver a resposta, diga: "Não sei com base na base atual."
CONTEXTO: {context_text}
PERGUNTA: {state["question"]}
RESPOSTA (com exemplo de código e notas de uso): \""".strip()
out = llm.invoke(prompt) return {"answer": out.content}
def build_app(): g = StateGraph(State) g.add_node("retrieve", retrieve) g.add_node("generate", generate)
g.add_edge(START, "retrieve") g.add_edge("retrieve", "generate") g.add_edge("generate", END)
return g.compile()
if __name__ == "__main__": app = build_app()
while True: q = input("\nPergunta> ").strip() if not q: continue if q.lower() in ("exit", "quit"): break
result = app.invoke({"question": q, "contexts": [], "answer": ""}) print("\n" + result["answer"]) "@ | Set-Content -Path $RagPy -Encoding utf8
# Indexar KB Write-Step "Indexando base de conhecimento (index_kb.py)" python .\index_kb.py
# Rodar RAG Write-Step "Iniciando chat RAG (rag_graph.py). Para sair: exit" python .\rag_graph.py
-- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianoboller http://wxinformatica.com.br/ |
| |
| |
| | | |
|
| | |
| |
Registered member 4,618 messages |
|
| Posted on January, 29 2026 - 11:46 AM |
Sim — dá pra usar com WX (WinDev/WebDev/WinDev Mobile). Só não é “rodar Python dentro do WX”. O padrão é:
WX = app/IDE IA = serviço local (Ollama + RAG) exposto via HTTP Aí o WX chama esse serviço e recebe JSON.
a) Arquitetura que funciona • Ollama rodando no Windows (local). • Seu RAG + LangGraph vira uma API HTTP (FastAPI/Flask). • No WX, você faz requisição HTTP (GET/POST) e renderiza resposta.
Vantagem: serve pra WinDev, WebDev e Mobile com o mesmo backend.
⸻
b) O que você reaproveita do que fizemos
Você reaproveita quase tudo: • index_kb.py (cadastra a base no Chroma) • lógica de retrieve+generate (RAG) • só adiciona uma camada HTTP pra “perguntar” via endpoint.
⸻
c) Como o WX conversa com isso (na prática)
Você expõe um endpoint tipo:
POST http://127.0.0.1:8000/ask Body:
{ "question": "Como funciona o comando print?" }
Resposta:
{ "answer": "...", "sources": ["commands/print.md"] }
No WX você chama HTTP e pronto.
⸻
d) Limites e pegadinhas • WinDev Mobile: não dá pra depender de 127.0.0.1 no celular. Você precisa hospedar o serviço: • na LAN (se for uso interno), • num servidor Windows/Linux, • ou embutir outro runtime (chato e geralmente não vale). • Offline no celular: aí você entra em outro mundo (modelos pequenos on-device, bem mais complexo). • Performance: LLaMA local pode ser pesado; pra desktop ok, pra servidor depende de GPU.
⸻
e) Recomendação “na lata” • Pra WinDev/WebDev em PC/servidor: perfeito. • Pra WinDev Mobile: funciona se a IA estiver num servidor acessível pelo app.
⸻
Pacote completo: • API FastAPI (1 arquivo) com /ask e /reindex • retornando answer + sources • e o código WLanguage (WinDev/WebDev/Mobile) chamando esse endpoint (HTTPRequest/HTTPPost) com tratamento de erro e timeout.
Boa noite, Adriano. Sim — dá pra fazer “só com WinDev” (sem Python, sem LangGraph). O que você ainda precisa é de um motor LLM/embeddings rodando local, e o mais simples é o Ollama (é um serviço/exe externo). Aí o WinDev faz RAG + orquestração na unha.
A base técnica fica assim: • WinDev: indexa seus docs, faz busca (RAG), monta prompt, chama o LLM. • Ollama: entrega embeddings via POST /api/embed  e resposta via POST /api/chat .
⸻
a) O caminho recomendado “só WinDev”
a) HFSQL (ou outra base) guarda: • source (nome do arquivo/comando) • content (texto do doc) • embedding_json (vetor em JSON) • norm (norma do vetor, pra acelerar cosine)
b) WinDev indexa: • lista arquivos com fListFile(..., frRecursive)  • lê conteúdo com fLoadText()  • gera embedding chamando Ollama POST /api/embed  • grava no HFSQL.
c) Na pergunta: • gera embedding da pergunta (Ollama embed) • calcula similaridade (cosine) contra os docs • pega Top-K trechos • chama POST /api/chat com stream:false .
⸻
b) O que você cria no WinDev (HFSQL)
Crie um arquivo HFSQL (análise) chamado PHX_DOC com campos: • doc_id (string 36) Unique • source (string 260) • content (Memo Text) • embedding_json (Memo Text) • norm (real) • updated_at (DateTime)
⸻
c) Procedimentos WLanguage prontos (RAG sem Python)
c1) Embedding via Ollama (/api/embed)
(Endpoint atual recomendado é /api/embed; /api/embeddings está “superseded”. )
//############################## // PhoenixAI_Embed // Retorna: Variant com embeddings[1] (array de números) // Ollama: POST http://localhost:11434/api/embed [oai_citation:7‡Ollama Docs](https://docs.ollama.com/api/embed) //############################## PROCEDURE PhoenixAI_Embed(sText is string, sEmbedModel is string = "mxbai-embed-large", sOllamaBaseURL is string = "http://127.0.0.1:11434")
IF sText = "" THEN RESULT Null END//IF
vReq is Variant vReq.model = sEmbedModel vReq.input = sText
sJSON is string = VariantToJSON(vReq) // [oai_citation:8‡doc.windev.com](https://doc.windev.com/en-US/…)
httpReq is httpRequest httpReq.Method = httpPost httpReq.URL = sOllamaBaseURL + "/api/embed" httpReq.ContentType = "application/json" httpReq.Content = sJSON
httpRep is httpResponse = HTTPSend(httpReq) // [oai_citation:9‡doc.windev.com](https://doc.windev.com/en-US/…)
IF ErrorOccurred THEN Error(ErrorInfo(errFullDetails)) RESULT Null END//IF
vRep is Variant = JSONToVariant(httpRep.Content) // [oai_citation:10‡doc.windev.com](https://doc.windev.com/en-US/…)
IF vRep.embeddings = Null THEN RESULT Null END//IF IF vRep.embeddings..Occurrence < 1 THEN RESULT Null END//IF
// embeddings é number[][], vamos usar a 1ª linha RESULT vRep.embeddings[1]
c2) Chat via Ollama (/api/chat) com stream:false
//############################## // PhoenixAI_Chat // Ollama: POST http://localhost:11434/api/chat [oai_citation:11‡Ollama Docs](https://docs.ollama.com/api/chat…) //############################## PROCEDURE PhoenixAI_Chat(sSystem is string, sUser is string, sModel is string = "llama3.1", sOllamaBaseURL is string = "http://127.0.0.1:11434")
vReq is Variant vReq.model = sModel vReq.stream = False
vReq.messages is Variant vMsg1 is Variant vMsg1.role = "system" vMsg1.content = sSystem vReq.messages.Add(vMsg1)
vMsg2 is Variant vMsg2.role = "user" vMsg2.content = sUser vReq.messages.Add(vMsg2)
sJSON is string = VariantToJSON(vReq) // [oai_citation:12‡doc.windev.com](https://doc.windev.com/en-US/…)
httpReq is httpRequest httpReq.Method = httpPost httpReq.URL = sOllamaBaseURL + "/api/chat" httpReq.ContentType = "application/json" httpReq.Content = sJSON
httpRep is httpResponse = HTTPSend(httpReq) // [oai_citation:13‡doc.windev.com](https://doc.windev.com/en-US/…)
IF ErrorOccurred THEN Error(ErrorInfo(errFullDetails)) RESULT "" END//IF
vRep is Variant = JSONToVariant(httpRep.Content) // [oai_citation:14‡doc.windev.com](https://doc.windev.com/en-US/…) IF vRep.message = Null THEN RESULT "" END//IF IF vRep.message.content = Null THEN RESULT "" END//IF
RESULT vRep.message.content
c3) Cosine similarity (pra ranking)
//############################## // PhoenixAI_VectorNorm //############################## PROCEDURE PhoenixAI_VectorNorm(vVec is Variant)
sum is real = 0
FOR i = 1 _TO_ vVec..Occurrence val is real = vVec[i] sum += val * val END//FOR
RESULT Sqrt(sum)
//############################## // PhoenixAI_Cosine //############################## PROCEDURE PhoenixAI_Cosine(vA is Variant, normA is real, vB is Variant, normB is real)
IF normA <= 0 OR normB <= 0 THEN RESULT 0 END//IF
dot is real = 0 maxI is int = vA..Occurrence IF vB..Occurrence < maxI THEN maxI = vB..Occurrence END//IF
FOR i = 1 _TO_ maxI dot += (vA[i] * vB[i]) END//FOR
RESULT dot / (normA * normB)
c4) Indexar KB (lendo .md e gravando no HFSQL)
//############################## // PhoenixAI_IndexKB // Varre kb\*.md (recursivo), lê texto, gera embedding e grava em PHX_DOC // fListFile [oai_citation:15‡doc.windev.com](https://doc.windev.com/en-US/…) | fLoadText [oai_citation:16‡doc.windev.com](https://doc.windev.com/en-US/…) //############################## PROCEDURE PhoenixAI_IndexKB(sKbRoot is string, sOllamaBaseURL is string = "http://127.0.0.1:11434", sEmbedModel is string = "mxbai-embed-large")
IF sKbRoot = "" THEN RESULT False END//IF
sList is string = fListFile(sKbRoot + "\*.md", frRecursive) // [oai_citation:17‡doc.windev.com](https://doc.windev.com/en-US/…) IF sList = "" THEN Info("Nenhum .md encontrado em: " + sKbRoot) RESULT False END//IF
filePath is string
FOR EACH STRING filePath OF sList SEPARATED BY CR sText is string = fLoadText(filePath) // [oai_citation:18‡doc.windev.com](https://doc.windev.com/en-US/…) IF sText = "" THEN CONTINUE END//IF
vEmb is Variant = PhoenixAI_Embed(sText, sEmbedModel, sOllamaBaseURL) IF vEmb = Null THEN CONTINUE END//IF
norm is real = PhoenixAI_VectorNorm(vEmb)
// Upsert simples por source (filePath) PHX_DOC.source = filePath HReadSeekFirst(PHX_DOC, source, filePath) IF HFound() THEN PHX_DOC.content = sText PHX_DOC.embedding_json = VariantToJSON(vEmb) // [oai_citation:19‡doc.windev.com](https://doc.windev.com/en-US/…) PHX_DOC.norm = norm PHX_DOC.updated_at = DateTimeSys() HModify(PHX_DOC) ELSE PHX_DOC.doc_id = GetUUID() PHX_DOC.source = filePath PHX_DOC.content = sText PHX_DOC.embedding_json = VariantToJSON(vEmb) PHX_DOC.norm = norm PHX_DOC.updated_at = DateTimeSys() HAdd(PHX_DOC) END//IF END//FOR
RESULT True
c5) Perguntar (RAG Top-K + Chat)
//############################## // PhoenixAI_Ask // Busca Top-K por cosine e chama Ollama /api/chat [oai_citation:20‡Ollama Docs](https://docs.ollama.com/api/chat…) //############################## PROCEDURE PhoenixAI_Ask(sQuestion is string, k is int = 6, sOllamaBaseURL is string = "http://127.0.0.1:11434", sLLMModel is string = "llama3.1", sEmbedModel is string = "mxbai-embed-large")
IF sQuestion = "" THEN RESULT "" END//IF
vQ is Variant = PhoenixAI_Embed(sQuestion, sEmbedModel, sOllamaBaseURL) IF vQ = Null THEN RESULT "" END//IF qNorm is real = PhoenixAI_VectorNorm(vQ)
bestScore is array of real bestText is array of string bestSource is array of string
// inicializa arrays com tamanho k FOR i = 1 _TO_ k bestScore[i] = -1 bestText[i] = "" bestSource[i] = "" END//FOR
HReadFirst(PHX_DOC) WHILE HFound() IF PHX_DOC.embedding_json <> "" AND PHX_DOC.norm > 0 THEN vD is Variant = JSONToVariant(PHX_DOC.embedding_json) // [oai_citation:21‡doc.windev.com](https://doc.windev.com/en-US/…) score is real = PhoenixAI_Cosine(vQ, qNorm, vD, PHX_DOC.norm)
// inserção simples no top-k FOR pos = 1 _TO_ k IF score > bestScore[pos] THEN // shift pra baixo FOR j = k DOWNTO pos + 1 bestScore[j] = bestScore[j-1] bestText[j] = bestText[j-1] bestSource[j] = bestSource[j-1] END//FOR bestScore[pos] = score bestText[pos] = PHX_DOC.content bestSource[pos] = PHX_DOC.source BREAK END//IF END//FOR END//IF
HReadNext(PHX_DOC) END//WHILE
ctx is string = "" FOR i = 1 _TO_ k IF bestText[i] <> "" THEN IF ctx <> "" THEN ctx += CR + "-----" + CR END//IF ctx += bestText[i] END//IF END//FOR
sSystem is string = "Você é o assistente oficial da linguagem Phoenix. Responda só com base no CONTEXTO. Se não tiver no contexto, diga: 'Não sei com base na base atual.'" sUser is string = "CONTEXTO:" + CR + ctx + CR + CR + "PERGUNTA:" + CR + sQuestion
RESULT PhoenixAI_Chat(sSystem, sUser, sLLMModel, sOllamaBaseURL)
⸻
d) O que isso substitui do “LangGraph”
O LangGraph é só orquestração em grafo. No “só WinDev”, você faz isso com: • procedures (IndexKB, Embed, Retrieve, Ask) • regras (“se não tem contexto bom, responda ‘não sei’”) • logs/Trace/erros.
Funciona igual, só menos “framework”.
⸻
e) Ponto crítico: endereço do Ollama
Por padrão o Ollama sobe em porta 11434 (localhost) e expõe endpoints tipo /api/embed e /api/chat.  Se seu WinDev e Ollama estiverem na mesma máquina: http://127.0.0.1:11434.
⸻
Se você rodar isso com poucos milhares de docs, HFSQL + cosine dá conta. Se crescer muito, a evolução natural é trocar o “retrieve” por um banco vetorial de verdade — mas aí já foge do “só WinDev”.
-- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianoboller http://wxinformatica.com.br/ |
| |
| |
| | | |
|
| | |
| |
Registered member 4,618 messages |
|
| Posted on January, 29 2026 - 12:24 PM |
Sim. WebDev + Ollama é ainda mais fácil que WinDev, porque você já está no mundo HTTP.
Você tem 2 jeitos:
a) Jeito certo (recomendado): WebDev chama um “AI Gateway” (WinDev/Python/Node) • WebDev (site) faz POST pra um endpoint seu /api/ai/ask • Esse endpoint chama o Ollama local/servidor e aplica RAG • Volta JSON pro WebDev renderizar
Por quê: WebDev rodando no browser não pode acessar localhost:11434 do servidor do usuário; e você quer controle, logs, segurança.
b) Jeito rápido (só se Ollama estiver no MESMO servidor do WebDev)
Se seu WebDev está hospedado no mesmo Windows/Linux que roda o Ollama: • Você faz o WebDev server-side chamar http://127.0.0.1:11434/api/chat direto.
⸻
c) Código WebDev (server-side) chamando Ollama direto
c1) Função: chat (sem streaming)
//############################## // WEB_PhoenixAI_Chat (server-side) //############################## PROCEDURE WEB_PhoenixAI_Chat(sSystem is string, sUser is string, sModel is string = "llama3.1", sOllamaBaseURL is string = "http://127.0.0.1:11434")
vReq is Variant vReq.model = sModel vReq.stream = False
vReq.messages is Variant vMsg1 is Variant vMsg1.role = "system" vMsg1.content = sSystem vReq.messages.Add(vMsg1)
vMsg2 is Variant vMsg2.role = "user" vMsg2.content = sUser vReq.messages.Add(vMsg2)
sJSON is string = VariantToJSON(vReq)
httpReq is httpRequest httpReq.Method = httpPost httpReq.URL = sOllamaBaseURL + "/api/chat" httpReq.ContentType = "application/json" httpReq.Content = sJSON
httpRep is httpResponse = HTTPSend(httpReq)
IF ErrorOccurred THEN Trace("Ollama error: " + ErrorInfo(errFullDetails)) RESULT "" END//IF
vRep is Variant = JSONToVariant(httpRep.Content) IF vRep.message = Null OR vRep.message.content = Null THEN RESULT "" END//IF
RESULT vRep.message.content
c2) Endpoint WebDev (Page/PROC Webservice): /api/ai/ask
Você cria um procedimento server-side que: • lê RequestContent() • parseia JSON (JSONToVariant) • chama WEB_PhoenixAI_Chat • devolve JSON (ResponseContentType("application/json") + ResponseWrite())
Exemplo:
//############################## // WEB_API_AI_Ask (server-side) // Body: {"question":"..."} -> {"answer":"..."} //############################## PROCEDURE WEB_API_AI_Ask()
ResponseContentType("application/json")
sBody is string = RequestContent() IF sBody = "" THEN ResponseWrite("{""error"":""body vazio""}") RETURN END//IF
vIn is Variant = JSONToVariant(sBody) IF vIn.question = Null THEN ResponseWrite("{""error"":""campo question ausente""}") RETURN END//IF
sQuestion is string = vIn.question
sSystem is string = "Você é o assistente oficial da Phoenix. Responda só com base no contexto fornecido." // Aqui você encaixa o RAG (buscar docs) e monta CONTEXTO. // Pra versão mínima sem RAG: sUser is string = sQuestion
sAnswer is string = WEB_PhoenixAI_Chat(sSystem, sUser)
vOut is Variant vOut.answer = sAnswer ResponseWrite(VariantToJSON(vOut))
⸻
d) Onde entra o RAG no WebDev
Exatamente igual no WinDev: • você guarda docs + embeddings no banco (HFSQL ou Postgres) • faz retrieve top-k • monta CONTEXTO • chama WEB_PhoenixAI_Chat
WebDev só vira “o servidor” que faz o fluxo.
⸻
e) Regra de ouro (pra não dar dor de cabeça) • Se o Ollama estiver em outro servidor, WebDev chama via IP/hostname. • Não exponha o Ollama direto pra internet (sem proxy/autenticação). Faça gateway.
⸻
Se você quiser, eu te solto o pacote “completo WebDev” com: • tabela HFSQL PHX_DOC • WEB_IndexKB() (reindex) • WEB_RetrieveTopK() (cosine) • endpoint /api/ai/ask retornando answer + sources (pra cortar alucinação).
-- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianoboller http://wxinformatica.com.br/ |
| |
| |
| | | |
|
| | | | |
| | |
| | |
| |
|
|
|