Sua geladeira é um dispositivo de pagamento válido — Eleonora Drykina e Nina Žižakić, In The Pocket
Autoria: AI Engineer · Assistir no YouTube
Vídeo de autoria do canal indicado, não da IANIA; todos os direitos pertencem ao criador. Transcrição, resumo e tradução gerados automaticamente; o conteúdo no idioma original é preservado na versão em idioma original.
Idioma original: ar
Vídeo original: Your Fridge Is a Valid Payment Device — Eleonora Drykina & Nina Žižakić, In The Pocket · Canal: AI Engineer · 24:28 · Assistir no YouTube
Tópicos: Agentes de IA, Aplicações empresariais de IA, Avaliação e benchmarks de IA, RAG, busca e recuperação de informação
Nina Žižakić e Eleonora Drykina apresentam um sistema RAG criado para responder a perguntas sobre os regulamentos de uma grande empresa belga de pagamentos. Elas explicam como preservaram a estrutura dos documentos, trataram tabelas e combinaram busca vetorial com BM25 para melhorar a recuperação. O sistema usa um agent com ferramentas para buscar trechos, seções e regulamentos completos, além de transmitir respostas para tornar a espera mais clara. A apresentação também aborda avaliações, monitoramento do uso e aprendizados obtidos com usuários reais.
Pontos-chave
Seção intitulada “Pontos-chave”- O sistema usa cerca de 270 PDFs, com aproximadamente 6.000 páginas e 3.000 tabelas.
- Cada resposta deve indicar com precisão o regulamento, a seção e a página usados como fonte.
- Os documentos são divididos em trechos sem separar tabelas nem perder os caminhos das seções.
- As tabelas são convertidas para CSV, preservando as relações entre linhas e colunas para melhorar a recuperação.
- A busca híbrida combina embeddings densos e BM25; em uma avaliação com 63 perguntas, a taxa de recuperação subiu de 92% para 97%.
- O agent dispõe de ferramentas para buscar trechos, recuperar seções completas, consultar regulamentos pequenos e listar os regulamentos disponíveis.
- A transmissão progressiva de texto Markdown e de cartões de fonte ajuda a tornar utilizável uma experiência com tempo médio de resposta de 38 segundos.
- A equipe criou cerca de 86 testes abrangentes com Promptfoo, avaliações por LLM e verificações de citações e recuperação.
- Testes com usuários reais ajudaram a identificar usos práticos e a formular avaliações para orientar o produto.
Capítulos
Seção intitulada “Capítulos”| Início | Capítulo | Resumo |
|---|---|---|
| 00:00 | O projeto e o desafio dos regulamentos | As apresentadoras introduzem o sistema de pagamentos, os regulamentos em PDF e a necessidade de respostas fundamentadas e citadas. |
| 03:06 | Requisitos de precisão e visão geral do sistema | A equipe explica os requisitos de citação e fundamentação, além da arquitetura de indexação e serviço. |
| 05:39 | Indexação, metadados e tratamento de tabelas | A apresentação detalha a divisão dos PDFs em trechos, a inclusão de metadados e a conversão das tabelas para CSV. |
| 11:28 | Busca híbrida e ferramentas do agent | As apresentadoras descrevem a combinação de embeddings densos com BM25 e as ferramentas que ampliam a recuperação conforme necessário. |
| 15:38 | Streaming, interface e registro de uso | A equipe explica como o streaming de texto e os cartões de fonte melhoram a experiência, e como registra interações. |
| 18:10 | Avaliações e aprendizados dos testes | As apresentadoras apresentam as fontes dos testes, as avaliações com Promptfoo e os cuidados necessários ao interpretar resultados. |
| 20:13 | Uso real e análise das conversas | A equipe compartilha dados iniciais de uso e exemplos de como as pessoas recorrem ao assistente em situações reais. |
| 22:51 | Principais lições do projeto | As lições finais destacam a preservação da estrutura documental, a recuperação por agent, o streaming e os testes com usuários. |
Citações
Seção intitulada “Citações”Você pode pagar com coisas inovadoras, como abotoaduras, bolsa, roupas e até uma geladeira. — 00:31
A abordagem híbrida elevou a taxa de recuperação de 92% para 97%. — 12:30
É uma pequena tarefa de pesquisa. — 15:38
É importante testar com usuários reais desde cedo. — 24:28
Conceitos e entidades
Seção intitulada “Conceitos e entidades”- In The Pocket (empresa): Estúdio de produtos digitais sediado na Bélgica que desenvolveu o sistema apresentado.
- Nina Žižakić (pessoa): Engenheira de IA da In The Pocket que apresenta a etapa de indexação e aspectos do projeto.
- Eleonora Drykina (pessoa): Engenheira de produto da In The Pocket que apresenta a etapa de serviço e a experiência do usuário.
- RAG (conceito): Abordagem que recupera informações de documentos para fundamentar as respostas do sistema.
- BM25 (conceito): Método de recuperação lexical usado em conjunto com a busca por embeddings densos.
- Reciprocal Rank Fusion (conceito): Método de fusão de posições usado para combinar os resultados das buscas densas e BM25.
- Pydantic (ferramenta): Biblioteca usada para descrever componentes estruturados que o agent poderia incluir nas respostas.
- Azure Table Storage (ferramenta): Serviço escolhido para registrar perguntas, chamadas de ferramentas, respostas e eventos de uso.
- Promptfoo (ferramenta): Ferramenta usada para executar testes e avaliações do sistema.
Tradução completa (pt-BR)
Seção intitulada “Tradução completa (pt-BR)”00:00 Boas-vindas à nossa conversa intitulada “Sua geladeira é um meio de pagamento válido: um sistema RAG incomum em produção”. Deixem-me começar explicando esse título. Esta é uma página de um dos manuais de regras dos nossos clientes. É um dos muitos documentos em torno dos quais construímos nosso sistema RAG. Você pode esperar documentos financeiros áridos, e a maioria deles realmente é assim. Mas há
00:31 também alguns detalhes divertidos e interessantes. Por exemplo, esta página mostra uma lista de dispositivos com os quais você pode pagar. Há coisas esperadas, como celulares e cartões, mas também coisas inovadoras, como abotoaduras, bolsas, roupas e até geladeiras. Achei realmente incrível encontrar uma curiosidade assim em documentos que eu esperava que fossem
01:02 extremamente entediantes. Vamos nos apresentar. Esta é a única foto que temos juntas. Normalmente não usamos headsets de realidade estendida, mas naquele dia no escritório estávamos experimentando todo tipo de dispositivo divertido. Eu sou Nina. Sou engenheira de IA. >> E eu sou Eleonora. Sou engenheira de produto. Nós
01:32 trabalhamos na In The Pocket, um estúdio de produtos digitais sediado na Bélgica. Ajudamos nossos clientes na transformação com IA e no desenvolvimento de software personalizado. >> Hoje vamos falar sobre um projeto RAG que construímos para um dos nossos clientes, uma grande empresa belga de tecnologia financeira. A empresa permanecerá anônima durante esta conversa. No fundo, este é um problema
02:03 clássico de RAG. Nesta conversa, queremos apresentar as decisões técnicas que tivemos de tomar e aprofundar como construímos esse sistema. Esta é uma conversa que teria sido útil para nós no início do projeto. Então, qual é o problema que estamos enfrentando? Nosso cliente administra o maior sistema de pagamentos
02:34 da Bélgica, e todas as regras desse sistema estão documentadas em manuais de regras. São arquivos PDF, cerca de 270 PDFs. Ou seja, aproximadamente 6.000 páginas. Muitas informações estão em tabelas. Cerca de 3.000 tabelas. É assim que organizam o conhecimento. Muito conhecimento importante está dentro das próprias tabelas. Além disso, os manuais
03:06 de regras fazem muitas referências uns aos outros. Um manual remete a outro, que remete a outro, e assim por diante. Uma aplicação RAG para uma instituição financeira traz alguns desafios. O primeiro desafio são as citações e referências. É claro que as respostas precisam estar sempre corretas. Mas, especificamente no contexto financeiro,
03:37 isso é ainda mais importante. Portanto, cada resposta precisa citar com precisão a seção e a página do manual de regras, para que as pessoas possam saber de onde veio a resposta. O segundo ponto é a fundamentação. O LLM que funciona nos bastidores é um modelo geral, então foi treinado com conhecimento geral. Ele sabe muita coisa, inclusive informações sobre outros sistemas de pagamento, como funcionam ou quais são suas tarifas. Então, tivemos de definir e garantir que tipo de conhecimento poderia ser usado. Por exemplo, saber o que é um banco é aceitável, faz sentido e não é algo que seria definido nos manuais de regras. Mas o que outros sistemas de pagamento cobram ou como funcionam não deve aparecer na resposta, a menos que esteja mencionado nos manuais de regras. Este é o aspecto da solução
04:07 que construímos. É um chatbot. Você faz uma pergunta, e ele responde com base nesses manuais de regras. Se a resposta estiver em uma tabela, ele também mostra essa tabela. Abaixo da resposta, há uma lista das fontes usadas para extrair ou formular a resposta, com a seção e a parte do manual de regras, para que o usuário possa abri-la. Neste exemplo, perguntei: “Posso pagar usando minha geladeira?”
04:37 Recebi uma resposta e também posso fazer perguntas complementares. É assim que o sistema inteiro se parece. Ele é composto por duas partes. À esquerda está o processo de indexação, que fazemos offline. A cada nova versão dos manuais de regras, convertemos esses PDFs em trechos e os armazenamos em um banco de dados vetorial. À direita está a parte de atendimento, que fica online para cada pergunta feita pelo usuário. O agente pesquisa nesse banco de dados vetorial, e então a resposta é transmitida ao usuário.
05:08 Vou falar sobre a indexação, e Eleonora falará sobre a parte de atendimento. Quanto à indexação, a configuração é bem simples. Começamos com arquivos PDF, dividimos em trechos e adicionamos metadados a cada trecho. Fazemos um processamento especial para as tabelas e, depois, criamos os embeddings. Criamos dois tipos de embeddings: um embedding denso e um BM25. Então, vou detalhar agora as três primeiras etapas, e Eleonora falará depois sobre os embeddings. Certo, a primeira etapa
05:39 é dividir os arquivos PDF em trechos. O processo funciona assim: extraímos o texto de cada página, dividimos em parágrafos e agrupamos os parágrafos em um trecho até chegar a cerca de 2.000 caracteres. Também nos certificamos de não dividir nenhuma tabela entre dois trechos. Além disso, detectamos os títulos das seções usando expressões regulares, como:
06:10 Capítulo três ou 4.2.1. Isso dá a cada trecho seu próprio caminho de seção. Por exemplo, este trecho está no capítulo quatro, seção 4.2. Esse caminho é usado para adicionar uma referência, mas também para buscar a seção inteira quando o agente precisa de mais contexto. E tudo isso funciona porque não sobrepomos os trechos. Assim, uma seção é apenas um conjunto de trechos. Se você os reordenar, eles voltam ao estado original. Na segunda etapa, adicionamos metadados a cada trecho. Neste exemplo, vemos o texto do trecho deste manual de regras da geladeira. Na parte inferior, há alguns campos de metadados. Precisamos
06:41 do nome do manual de regras e do número da página para poder exibi-los na referência ou no cartão da fonte para o usuário. No entanto, o usuário pode acessar o link para o arquivo PDF. Também usamos os caminhos das seções, tanto para a referência quanto para permitir que o agente busque a seção inteira de uma só vez.
07:12 Também temos um índice de trechos que permite ao agente reconstruir uma seção ou até mesmo um manual de regras inteiro. O agente usa os IDs dos manuais de regras para poder obter uma lista de todos os manuais ou descobrir o que está disponível. Na etapa de indexação de cada manual de regras, usamos um LLM para gerar um resumo que é anexado a cada trecho e indica a qual manual de regras ele pertence.
07:42 Dessa forma, o agente sabe de qual documento vem o trecho. Quanto ao restante, os outros metadados são campos da lógica de negócios. Então, qual manual de regras é, a quais regras se aplica e se contém uma tabela. São essas informações que o agente usa ou recebe junto com os resultados da pesquisa.
08:14 A terceira etapa é o processamento das tabelas. Essa etapa é importante porque, como eu disse, há muito conhecimento dentro das tabelas. No início, não percebemos muito bem isso. Então, nosso processamento inicial simplesmente extraía o texto simples diretamente do PDF, e as tabelas não ficavam bem formatadas. Mas, neste exemplo hipotético, você vê que o campo local se estende por várias linhas e atravessa duas outras linhas; depois, a recuperação se estende pelas duas. Então, se isso não estiver claro ou bem formulado em texto, sim, o agente pode recuperar informações erradas. Especialmente em coisas importantes como tarifas, é importante recuperar a linha e a coluna corretas. Então, o que fazemos
08:47 é converter as tabelas para o formato CSV. Basicamente, duplicamos esses campos e, assim… desse modo, o agente os recupera e, quando faz isso, recupera a linha correta. Essa é a linha de que ele precisa. Isso realmente fez uma grande diferença na precisão das respostas. Certo, era isso sobre a indexação. Agora temos cerca de 4.000 trechos de texto. E agora Eleonora vai falar sobre a parte de atendimento. Sim. >> Certo, a parte anterior construiu o índice. Agora, esta parte será sobre encontrar os 10 trechos corretos entre os 4.000 preparados. A etapa óbvia aqui é recorrer
09:17 a embeddings densos da pergunta, transformar cada trecho em um vetor e comparar a distância. Isso é ótimo para o significado, mas os códigos de regras de negócios, os nomes das mensagens e os identificadores exatos parecem ruído para o embedding. Para o membro que faz a pergunta, porém, muitas vezes esse é justamente o ponto central. Com o algoritmo BM25, temos o cenário inverso. Os termos exatos funcionam, mas as paráfrases não. Então, combinamos os dois em uma única chamada (Quadrant) e os fundimos usando a fusão de classificação recíproca.
09:49 Embedding denso com os 50 melhores, BM25 com os 50 melhores; eles são combinados para chegar aos 30 melhores e, depois, reordenados para garantir a coesão da seção. Os 10 melhores resultados são fornecidos ao agente. O bom do RRF é que não precisamos calibrar as pontuações entre esses dois caminhos. Em uma avaliação apenas da recuperação, com 63 perguntas e comparando com embeddings densos sozinhos, a abordagem híbrida elevou a taxa de acerto de 92% para 97% e não perdeu nenhuma pergunta que os embeddings densos já conseguiam encontrar.
10:21 Certo, agora temos 10 trechos adequados, mas nem toda pergunta cabe em 10 trechos. Alguns estão ligados em uma cadeia. Um manual aponta para outro, e a resposta só fica completa se você seguir esse link. E alguns exigem um escopo mais amplo. As tarifas desse tipo de transação nunca caberiam entre os 10 melhores resultados de qualquer coisa. Então,
10:57 em vez de um pipeline fixo de recuperação e geração, nosso agente tem quatro ferramentas, da mais restrita à mais ampla. A pesquisa nos manuais de regras vem sempre em primeiro lugar. São os 10 trechos de que falamos no slide anterior. Se isso não for suficiente, a ferramenta de recuperação de seções do manual busca a seção inteira, ordenada pela sequência das seções. É exatamente a abordagem que Nina mencionou antes: armazenar a sequência da seção. E essa ampliação aqui — afastar-se dos detalhes — consiste simplesmente em buscar
11:28 todos os trechos desse caminho, ordenados pelo índice do trecho. Acima disso, há uma ferramenta para recuperar o manual de regras inteiro, que funciona apenas com manuais pequenos. E uma ferramenta para listar os manuais disponíveis, quando o agente precisa saber o que existe. Então, as proteções fizeram isso funcionar na prática. Primeiro, se o manual for grande demais — cerca de mais de 100 mil tokens —, a ferramenta do manual rejeita
11:59 para os embeddings densos da pergunta e transformar cada trecho em um vetor; depois, comparar a distância. Isso é ótimo para o significado, mas tokens de regras de negócio, nomes de mensagens e identificadores exatos vão parecer ruído para o embedding. Para o membro que faz a pergunta, porém, muitas vezes esse é justamente o ponto central. Com o algoritmo BM25, temos o cenário inverso. Os tokens exatos funcionam, mas as paráfrases não. Então, combinamos os dois em uma única chamada (Quadrant) e os combinamos usando fusão recíproca de rankings.
12:30 Um embedding denso dos 50 melhores e BM25 dos 50 melhores são combinados para chegar aos 30 melhores; em seguida, eles são reordenados para garantir a coesão da seção, e os 10 melhores resultados são fornecidos ao agent. O bom do RRF é que não precisamos calibrar os resultados entre esses dois caminhos. Em uma avaliação apenas da recuperação, com 63 perguntas, em comparação com embeddings densos sozinhos, a abordagem híbrida elevou a taxa de acerto
13:02 de 92% para 97% e não deixou de encontrar nenhuma pergunta que os embeddings densos já conseguiam encontrar. Certo, agora temos 10 trechos adequados, mas nem toda pergunta se encaixa em 10 trechos. Alguns estão relacionados entre si em uma sequência. Um guia aponta para outro, e a resposta só fica completa se você seguir esse link. E alguns exigem um escopo mais amplo. As taxas desse tipo de transação nunca caberiam nos 10 melhores resultados de nada. Então,
13:33 em vez de um pipeline fixo de recuperação e geração, nosso agent tem quatro ferramentas, da mais restrita à mais ampla. A busca nos manuais de regras vem sempre em primeiro lugar. São os dez trechos de que falamos no slide anterior. Se isso não for suficiente, uma ferramenta de recuperação de seções do manual traz a seção inteira, ordenada pela sequência das seções. É exatamente a abordagem que Nina mencionou antes: armazenar a sequência da seção. E essa ampliação aqui — afastar-se dos detalhes — consiste simplesmente em buscar cada trecho desse caminho ordenado pelo índice do trecho.
14:04 Acima disso, há uma ferramenta para recuperar o manual de regras inteiro, que funciona apenas com manuais pequenos. E uma ferramenta para listar os manuais disponíveis, quando o agent precisa saber o que existe. Então, as proteções fizeram isso funcionar na prática. Primeiro, se o manual for grande demais (cerca de mais de 100 mil tokens), a ferramenta do manual se recusa a
14:36 esvaziar completamente seu conteúdo no contexto e, em vez disso, retorna uma lista das seções disponíveis, com um aviso de que o manual é longo demais. Em segundo lugar, se o nome da seção não corresponder, ela retorna as seções disponíveis para que o agent possa tentar novamente, em vez de desistir ou tentar inventar um nome. Por fim, há uma ferramenta chamada “Instruções de disciplina” no prompt. Como a maioria das perguntas
15:07 exige de duas a quatro chamadas, antes da sexta chamada, pede-se ao agent que se pergunte se está realmente trazendo algo novo ou apenas reformulando uma pesquisa que já falhou antes. Essa ideia veio da observação de trajetórias reais, quando o agent tentava fazer a mesma pesquisa repetidamente, na esperança de que o resultado aparecesse no fim. Então, o custo de tudo isso é o tempo de resposta, com uma média de 38
15:38 segundos por resposta. Isso não é apenas uma resposta de conversa. É uma pequena tarefa de pesquisa. Dependemos do streaming para fazer com que os 38 segundos pareçam um período em que algo está acontecendo, e não apenas uma conversa travada. Isso me leva ao próximo slide. Na nossa primeira iteração, queríamos muito nos afastar da interface tradicional de chatbot. Preparamos componentes de interface e os descrevemos como modelos Pydantic disponíveis
16:08 para o agent, dizendo: “Estes são os componentes disponíveis para você. Use-os na sua resposta junto com o texto”. Por exemplo, o cartão de fonte era um componente; um evento poderia ser um componente, ou uma lista de verificação expansível, e assim por diante. A ideia era ter uma interface gerada por IA, mais fácil de ler do que apenas texto simples. O problema é que não dá para transmitir um objeto Pydantic parcial. Ele só se torna um arquivo JSON válido quando o último token chega.
16:38 Como vocês podem ver aqui, para um sistema cujas respostas levam 38 segundos, isso significava 38 segundos de tela vazia, e então tudo aparecia de uma vez. Portanto, a solução que salvou a experiência foi dividir a resposta em partes. Agora, o agent transmite texto Markdown token por token, e o frontend o formata imediatamente, assim que chega. Depois, o cartão de fonte é uma parte separada, que representa um componente de interface real. Ele não contém nenhuma informação que
17:09 você gostaria de clicar antes de ler a resposta completa. Portanto, não perdemos nada esperando o streaming da resposta terminar antes de adicionar esse componente. Isso nos dá um cartão clicável, em vez de um link comum dentro do texto, o que é melhor para o usuário. Mas, assim que essa resposta aparece na tela, a próxima pergunta é o que o usuário realmente fará com ela. Vai clicar na fonte
17:39 ou copiar a resposta, continuar a conversa ou sair? Essa é a experiência do usuário que queremos acompanhar, e isso nos leva ao registro. Por enquanto, optamos pela solução de registro mais simples: Azure Table Storage. Registramos cada pergunta, chamada de ferramenta, resposta e feedback positivo ou negativo, além de eventos como clicar na fonte ou copiar a resposta, junto com
18:10 o histórico da conversa, que mantemos pequeno de propósito. Ele inclui apenas as últimas 20 mensagens como contexto. Para o estágio atual deste produto, isso é suficiente. Quando o produto crescer, saberemos do que realmente vamos precisar nessa altura. E como sabemos se tudo isso está funcionando? Nossas perguntas de avaliação vêm de fontes reais e de duas rodadas de testes com usuários, envolvendo membros reais, além de diretrizes comportamentais sobre o que o sistema de IA deve e não deve fazer. Por exemplo: não dê conselhos, mantenha-se neutro em relação aos concorrentes e declare claramente quando algo não estiver mencionado nos manuais. Temos cerca de 86 testes abrangentes executados com Promptfoo, com uma avaliação completa feita por um agent LLM segundo critérios definidos, além da verificação da citação do documento-fonte correto e de uma avaliação apenas da recuperação que
18:41 orientações comportamentais sobre o que o sistema de IA deve e não deve fazer. Por exemplo: não dar conselhos, manter-se neutro em relação aos concorrentes e declarar claramente quando algo não estiver mencionado nos manuais de regras. Temos cerca de 86 testes abrangentes executados com Promptfoo, com uma avaliação completa por um agent LLM segundo critérios definidos, além da verificação de que a citação corresponde ao documento-fonte correto e de uma avaliação apenas da recuperação que
19:11 realizamos anteriormente. Aprendemos duas coisas ao fazer os testes e gostaríamos de compartilhá-las. Primeiro, as avaliações de modelos de linguagem têm um nível de ruído, e é preciso executá-las novamente antes de confiar em qualquer mudança. Por exemplo, quando fizemos nossa própria avaliação, cinco dos 12 casos de mudança não se repetiram. Segundo, às vezes o próprio texto padrão é o problema, e não o modelo.
19:41 Encontramos uma data fictícia pela qual o avaliador continuava penalizando o sistema; depois, descobrimos que essa data constava de fato no manual. >> Sim. E agora, sobre o uso. Lançamos este assistente para o manual em junho. No início, ele foi lançado
20:13 apenas para os usuários internos dos nossos clientes, e o objetivo é disponibilizá-lo até o fim do ano para os membros e clientes externos deles. Até agora, temos alguns números preliminares de uso. Temos cerca de 900 perguntas até o momento, distribuídas por mais de 100 conversas,
20:43 e cerca de 34 pessoas realmente o estão usando. Também coletamos feedback de gostei e não gostei, mas a maioria dos usuários parou de usar esse recurso depois do primeiro mês. Também temos informações sobre quantas vezes as fontes foram acessadas ou as respostas copiadas. Esses são os números que temos disponíveis. Também usamos IA para fins de análise. À
21:17 direita, vemos como o modelo de linguagem interpretou isso. O que observamos foi que, no primeiro mês, enquanto perguntávamos às pessoas, fizemos alguns exercícios de “red team” (testes de invasão). As pessoas tentavam quebrar o assistente e tirá-lo do assunto, ou faziam perguntas fora do escopo. Mas, no terceiro mês, mais de 90% das perguntas eram perguntas reais e legítimas. Em segundo lugar,
21:48 as pessoas usam a ferramenta em situações reais. Vimos pessoas usá-la copiando um e-mail de um cliente e pedindo ajuda para responder. Ou copiando uma mensagem ou uma tabela real de protocolo e, então, redigindo uma resposta que gostariam de revisar. Em terceiro lugar, como não recebemos muito feedback de gostei e não gostei,
22:20 tentamos interpretar o sentimento da conversa observando as perguntas de acompanhamento. Se as pessoas dizem “obrigado” ou passam para um novo assunto, consideramos isso uma interação positiva. Se perguntam a mesma coisa outra vez, é provável que a interação tenha sido negativa. Com base nisso, vimos que a maioria das conversas correu bem.
22:51 Então, em resumo, quais são as principais lições aprendidas com este projeto até agora? Em relação aos documentos, descobrimos que é importante preservar a estrutura. Portanto, as seções são importantes para recuperar respostas e também para permitir que o agent tenha uma visão geral do conhecimento. Também percebemos
23:25 que as tabelas exigem um tratamento especial e uma abordagem diferente. Do lado do agent, como mencionado, foi importante dar a ele vários níveis de zoom e definir de quanto contexto precisa. De modo geral, foi muito útil passar de chamadas individuais ao modelo de linguagem para a recuperação por meio do agent.
23:56 Percebemos que as pontuações de avaliação aumentaram significativamente. Do ponto de vista da experiência do usuário, o streaming foi o que tornou a ferramenta utilizável e boa. E só adicionamos um componente estruturado quando a experiência do usuário exige isso. Por fim,
24:28 descobrimos que é importante testar com usuários reais desde cedo e usar essas entrevistas para criar prompts de avaliação que nos ajudem a moldar o produto e a decidir se aquilo que consideramos uma melhoria realmente é uma melhoria. Obrigada por ouvirem nossa apresentação. >> Obrigado.
Transcrição original
[00:00] مرحبًا بكم في حديثنا بعنوان “ثلاجتك هي وسيلة دفع معتمدة: نظام RAG غير اعتيادي في بيئة الإنتاج”. دعوني أبدأ بشرح هذا العنوان . هذه صفحة من إحدى كراسات القواعد الخاصة بعملائنا. إنها واحدة من الوثائق العديدة التي بنينا نظام RAG الخاص بنا حولها. قد تتوقع وثائق مالية جافة، وهذا هو الحال في معظمها بالفعل. لكن هناك
[00:31] أيضًا بعض التفاصيل الممتعة والمثيرة. على سبيل المثال، هذه الصفحة التي تعرض قائمة بالأجهزة التي يمكنك الدفع من خلالها . هناك أشياء متوقعة مثل الهواتف والبطاقات، ولكن هناك أيضًا أشياء مبتكرة مثل أزرار الأكمام، وحقيبة اليد، والملابس، وحتى الثلاجة. لقد وجدت أنه من الرائع حقًا العثور على حقيقة ممتعة كهذه في وثائق كنت أتوقع أن
[01:02] تكون مملة للغاية. لنقدم أنفسنا. هذه هي الصورة الوحيدة التي لدينا لنا معًا. نحن لا نرتدي سماعات الواقع الممتد عادةً، لكن في ذلك اليوم في المكتب كنا نجرب جميع أنواع الأدوات الممتعة. أنا نينا. أنا مهندسة ذكاء اصطناعي. >> وأنا إليونورا. أنا مهندسة منتجات. نحن
[01:32] نعمل في شركة “In The Pocket” ، وهو استوديو للمنتجات الرقمية يقع مقره الرئيسي في بلجيكا. نحن نساعد عملائنا في التحول نحو الذكاء الاصطناعي وتطوير البرمجيات المخصصة. >> واليوم سنتحدث عن مشروع RAG الذي بنيناه لأحد عملائنا، وهي شركة تكنولوجيا مالية بلجيكية كبيرة. ستبقى الشركة مجهولة الهوية خلال هذا الحديث. في جوهرها، هذه مشكلة
[02:03] كلاسيكية من مشاكل RAG. في هذا الحديث، نريد استعراض القرارات التقنية التي كان علينا اتخاذها والتعمق في كيفية بناء هذا النظام. هذا حديث كان سيكون مفيدًا لنا في بداية هذا المشروع. إذًا، ما هي المشكلة التي نواجهها؟ يدير عميلنا أكبر نظام دفع
[02:34] في بلجيكا، وجميع قواعد هذا النظام مدونة في كراسات قواعد . هذه عبارة عن ملفات PDF ، حوالي 270 ملف PDF. أي حوالي 6,000 صفحة. الكثير من المعلومات موجودة في جداول. حوالي 3,000 جدول. وهذه هي الطريقة التي ينظمون بها معرفتهم. الكثير من المعرفة المهمة موجودة داخل الجداول نفسها. كما أن كراسات
[03:06] القواعد تشير إلى بعضها البعض كثيرًا. فإحدى الكراسات تحيلك إلى أخرى، وتلك تحيلك إلى أخرى، وهكذا. إن تطبيق RAG لمؤسسة مالية يأتي ببعض التحديات. التحدي الأول هو الاستشهادات والمراجع . بالطبع، يجب أن تكون الإجابات صحيحة دائمًا. لكن في السياق المالي تحديدًا،
[03:37] تزداد أهمية ذلك. لذا، يجب أن تستشهد كل إجابة بقسم وصفحة كتاب القواعد بدقة. حتى يتمكن الأشخاص من معرفة مصدر الإجابة. والأمر الثاني هو التأسيس المعرفي. فنموذج اللغة الكبير الذي يعمل في الخلفية هو نموذج عام، لذا تم تدريبه على معرفة عامة . إنه يعرف الكثير، بما في ذلك معلومات عن أنظمة دفع أخرى وكيفية
[04:07] عملها أو رسومها. لذا كان علينا تحديد والتأكد من نوع المعرفة المسموح باستخدامها. على سبيل المثال، من المقبول معرفة ماهية البنك، فهذا منطقي، وهو ليس شيئًا سيتم تعريفه في كتب القواعد. لكن ما تفرضه أنظمة الدفع الأخرى أو كيفية عملها ، لا ينبغي أن يظهر في الإجابة إلا إذا كان مذكورًا في كتب القواعد. هذا هو الشكل الذي يبدو عليه الحل
[04:37] الذي بنيناه. إنه برنامج دردشة آلي. تطرح سؤالاً ويجيب بناءً على كتب القواعد هذه. إذا كانت الإجابة في جدول، فسيقوم بعرض ذلك الجدول أيضًا. أسفل الإجابة توجد قائمة بالمصادر التي استخدمها لاستخراج أو صياغة الإجابة، مع تحديد القسم والجزء من كتاب القواعد ليتمكن المستخدم من فتحه. في هذا المثال، سألت: “هل
[05:08] يمكنني الدفع باستخدام ثلاجتي؟” حصلت على إجابة، ويمكنني بعد ذلك طرح أسئلة متابعة أيضًا. هذا هو الشكل الذي يبدو عليه النظام بأكمله. إنه يتكون من جزأين. على اليسار توجد عملية الفهرسة، وهي ما نقوم به دون اتصال بالإنترنت. مع كل إصدار جديد من كتب القواعد، نقوم بتحويل ملفات PDF هذه إلى أجزاء وتخزينها في قاعدة بيانات متجهية. وعلى اليمين يوجد جزء
[05:39] الخدمة، وهو الجزء المتصل بالإنترنت لكل سؤال يطرحه المستخدم. يبحث الوكيل في قاعدة البيانات المتجهية هذه، ثم يتم بث الإجابة للمستخدم. سأتحدث عن الفهرسة، وستتحدث إليونورا عن جزء الخدمة. حول الفهرسة، الإعداد بسيط للغاية. نبدأ بملفات PDF، ونقسمها
[06:10] إلى أجزاء، ونضيف بيانات وصفية لكل جزء. نقوم ببعض المعالجة الخاصة للجداول، ثم ننشئ التضمينات. نقوم بإنشاء نوعين من التضمينات (embeddings)، تضمين كثيف وتضمين BM25. لذا، سأقوم الآن بالتفصيل في الخطوات الثلاث الأولى، وستتحدث إليونورا لاحقاً عن التضمينات. حسناً، الخطوة الأولى
[06:41] هي تقسيم ملفات PDF إلى أجزاء، الطريقة التي يعمل بها ذلك هي استخراج النص من كل صفحة، ونقوم بتقسيمه إلى فقرات، ونجمع الفقرات في جزء واحد حتى يصل إلى حوالي 2000 حرف، كما نحرص أيضاً على عدم تقسيم أي جدول على جزأين. نقوم أيضاً باكتشاف عناوين الأقسام باستخدام التعبيرات النمطية ( regular expressions)، مثل:
[07:12] الفصل الثالث، أو 4.2.1. وهذا يمنح كل جزء مسار القسم الخاص به. على سبيل المثال، هذا الجزء موجود في الفصل الرابع، القسم 4.2. ويُستخدم هذا المسار لإضافة مرجع، ولكن يُستخدم أيضاً لجلب القسم بالكامل عندما يحتاج الوكيل إلى مزيد من السياق. وكل هذا يعمل لأننا لا نجعل
[07:42] الأجزاء متداخلة. لذا، القسم عبارة عن مجموعة من الأجزاء فقط. وإذا قمت بإعادة ترتيبها، فإنها تعود إلى حالتها الأصلية. بالنسبة للخطوة الثانية، نقوم بإضافة بيانات وصفية لكل جزء. لذا، في هذا المثال، نرى نص الجزء من كتاب قواعد الثلاجة هذا. وفي الأسفل توجد بعض حقول البيانات الوصفية. نحن بحاجة
[08:14] إلى اسم كتاب القواعد ورقم الصفحة حتى نتمكن من عرضها في المرجع أو في بطاقة المصدر للمستخدم. ومع ذلك، يمكن للمستخدم الوصول إلى الرابط المؤدي لملف PDF. نستخدم أيضاً مسارات الأقسام، سواء للمرجع أو لتمكين الوكيل من جلب القسم بالكامل دفعة واحدة.
[08:47] ولدينا أيضاً فهرس الأجزاء الذي يسمح للوكيل بإعادة تجميع قسم أو حتى كتاب قواعد بالكامل. يستخدم الوكيل معرفات كتب القواعد ليكون قادراً على الحصول على قائمة بجميع كتب القواعد أو معرفة ما هو متاح. وفي وقت الفهرسة لكل كتاب قواعد، نقوم باستخدام نموذج لغوي كبير (LLM) لإنشاء ملخص يتم إرفاقه بكل جزء ليعبر
[09:17] عن كتاب القواعد الخاص به. وبهذه الطريقة يعرف الوكيل المستند الذي يأتي منه المقطع. أما البقية، فبقية البيانات الوصفية هي عبارة عن حقول منطق عمل. إذن، أي كتاب قواعد هو، وأي القواعد ينطبق عليها، وما إذا كان يحتوي على جدول، وهذه هي الأمور التي يستخدمها الوكيل أو يحصل عليها مع نتائج
[09:49] البحث. ثم الخطوة الثالثة هي معالجة الجدول. هذه الخطوة مهمة لأنه كما قلت، هناك الكثير من المعرفة داخل الجداول. في البداية لم ندرك ذلك نوعاً ما. لذا، كانت معالجتنا الأولية مجرد جلب مباشر للنص العادي من ملف PDF، ولم ينسق ذلك الجداول بشكل جيد. لكن
[10:21] في هذا المثال الوهمي، ترى أن الحقل المحلي يمتد عبر صفوف متعددة، وعبر الحدود عبر صفين آخرين، ثم يمتد الاسترداد عبر كليهما. لذا، إذا لم يكن ذلك واضحاً أو مصاغاً جيداً في نص، نعم، يمكن للوكيل جلب معلومات خاطئة، وخاصة في أشياء مهمة مثل الرسوم، من المهم جلب الصف الصحيح والعمود الصحيح. لذا، ما نقوم
[10:57] به هو تحويل الجداول إلى تنسيق CSV، فنقوم أساساً بتكرار تلك الحقول، ثم نحن…وبهذه الطريقة يجلبها الوكيل، وعندما يجلبها، فإنه يجلب الصف الصحيح. هذا هو الصف الذي يحتاجه. وقد أحدث ذلك فرقاً كبيراً حقاً في دقة الإجابات. حسناً، كان هذا كل ما
[11:28] يتعلق بالفهرسة. الآن، لدينا حوالي 4000 قطعة نصية. والآن ستتحدث إليونورا عن جزء التقديم. أجل. >> حسناً، الجزء السابق قام ببناء الفهرس. الآن هذا الجزء سيدور حول العثور على هذه القطع العشر الصحيحة من أصل 4000 قطعة تم إعدادها. الخطوة الواضحة هنا هي اللجوء
[11:59] إلى التضمينات الكثيفة للسؤال وتحويل كل قطعة إلى متجه، ثم مقارنة المسافة. وهذا رائع للمعنى، لكن رموز قواعد العمل، وأسماء الرسائل، والمعرفات الدقيقة ستبدو كضوضاء بالنسبة للتضمين، ولكن بالنسبة للعضو الذي يطرح السؤال، غالباً ما يكون هذا هو جوهر السؤال. مع خوارزمية BM25، لدينا صورة معكوسة. الرموز الدقيقة ستعمل، لكن إعادة الصياغة لن تعمل . لذا، قمنا بدمج كليهما في استدعاء
[12:30] واحد (Quadrant) ودمجهما باستخدام دمج الرتب المتبادل. تضمين كثيف لأعلى 50، و BM25 لأعلى 50، يتم دمجهما للوصول إلى أفضل 30، ثم إعادة الترتيب لضمان تماسك القسم، وتُغذي أفضل 10 نتائج للوكيل. الشيء الجيد في RRF هو أننا لسنا بحاجة لمعايرة النتائج بين هذين المسارين. في تقييم الاسترجاع فقط لـ 63 سؤالاً مقارنة بالتضمينات الكثيفة وحدها، رفع النهج الهجين معدل الإصابة
[13:02] من 92%إلى 97%، ولم يفقد أي سؤال كانت التضمينات الكثيفة قادرة على العثور عليه بالفعل. حسناً، لدينا الآن 10 أجزاء مناسبة، لكن ليس كل سؤال يتناسب مع 10 أجزاء. بعضها مرتبط ببعضها الآخر في سلسلة. يشير دليل إلى آخر، ولن تكتمل الإجابة إلا إذا تتبعت ذلك الرابط. وبعضها يتطلب نطاقاً أوسع. رسوم هذا النوع من المعاملات لن تتناسب أبداً مع أفضل 10 نتائج لأي شيء. لذا،
[13:33] بدلاً من خط أنابيب ثابت للاسترجاع ثم التوليد، يمتلك وكيلنا أربع أدوات. من الضيق إلى الواسع. البحث في كتيبات القواعد يأتي دائماً في المقام الأول. هذه هي الأجزاء العشرة التي تحدثنا عنها في الشريحة السابقة. إذا لم يكن ذلك كافياً، فإن أداة استرجاع أقسام الكتيب تسحب القسم بالكامل مرتباً حسب تسلسل الأقسام. وهو بالضبط النهج الذي ذكرته نينا في وقت سابق. تخزين تسلسل القسم. وهذا التوسع هنا-الابتعاد عن التفاصيل-هو مجرد جلب
[14:04] كل جزء بهذا المسار مرتباً حسب فهرس الجزء . فوق ذلك توجد أداة استرجاع كتيب القواعد بالكامل، والتي تعمل فقط مع الكتيبات الصغيرة. وأداة سرد الكتيبات المتاحة عندما يحتاج الوكيل لمعرفة ما هو موجود أصلاً. لذا، فإن حواجز الحماية جعلت هذا يعمل من الناحية العملية. أولاً، إذا كان الكتيب كبيراً جداً (أكثر من 100 ألف رمز تقريباً)، ترفض أداة الكتيب
[14:36] الكامل إفراغ محتوياته في السياق، وتعيد قائمة الأقسام المتاحة بدلاً من ذلك مع تحذير بأن الكتيب طويل جداً. ثانياً، إذا لم يتطابق اسم القسم، فإنها تعيد الأقسام المتاحة ليتمكن الوكيل من المحاولة مجدداً بدلاً من الاستسلام أو محاولة اختراع الاسم. وأخيراً، توجد أداة تسمى “تعليمات الانضباط” في المطالبة . لأن معظم الأسئلة
[15:07] تتطلب من استدعاءين إلى أربعة، وقبل الاستدعاء السادس، يُطلب من الوكيل أن يسأل نفسه عما إذا كان يجلب شيئاً جديداً حقاً أو يعيد صياغة بحث فشل بالفعل من قبل. وهذه الفكرة جاءت من مراقبتنا للمسارات الحقيقية عندما حاول الوكيل إجراء نفس البحث مراراً وتكراراً على أمل أن تظهر النتيجة في النهاية. إذن، تكلفة كل هذا هي زمن الاستجابة، بمتوسط 38
[15:38] ثانية لكل إجابة. هذا ليس مجرد رد محادثة. إنها مهمة بحثية صغيرة . نحن نعتمد على البث المباشر لنجعل الـ 38 ثانية تبدو وكأن شيئاً ما يحدث بالفعل، وليست مجرد محادثة عالقة. وهذا يقودني إلى الشريحة التالية. في تكرارنا الأول، أردنا حقًا الابتعاد عن واجهة مستخدم روبوتات الدردشة التقليدية. وقد جهزنا مكونات الواجهة ووصفتها كنماذج Pydantic متاحة
[16:08] للوكيل، قائلين: “هذه هي المكونات المتاحة لديك”. “استخدمها في إجابتك جنبًا إلى جنب مع النص”. على سبيل المثال، كانت بطاقة المصدر مكونًا، ويمكن أن يكون الحدث مكونًا، أو قائمة مرجعية قابلة للطي، وهكذا. كانت الفكرة هي الحصول على واجهة مستخدم مُنشأة بواسطة الذكاء الاصطناعي، لتكون أكثر قابلية للقراءة من مجرد نص عادي. المشكلة هي أنك لا تستطيع بث كائن Pydantic جزئي. إنه لا يصبح ملف JSON صالحًا إلا عند وصول الرمز الأخير.
[16:38] كما ترون هنا، بالنسبة لنظام تستغرق إجاباته 38 ثانية، كان ذلك يعني 38 ثانية من الفراغ على الشاشة، ثم يظهر كل شيء دفعة واحدة. لذا، الحل الذي أنقذ التجربة كان تقسيم الإجابة إلى أجزاء. الآن يقوم الوكيل ببث نصوص Markdown رمزًا برمز، وتقوم الواجهة الأمامية بتنسيقها مباشرةً فور وصولها. ثم تكون بطاقة المصدر جزءًا واحدًا يمثل مكون واجهة مستخدم حقيقي. إنه لا يحتوي على أي معلومات قد
[17:09] ترغب في النقر عليها قبل قراءة الإجابة كاملة. لذا، نحن لا نفقد شيئًا بالانتظار حتى اكتمال بث الإجابة قبل إضافة هذا المكون. وهذا يمنحنا بطاقة قابلة للنقر بدلاً من رابط عادي داخل النص، وهو أمر أفضل للمستخدم . ولكن بمجرد ظهور هذه الإجابة على الشاشة، السؤال التالي هو ما الذي سيفعله المستخدم بها فعليًا. هل سينقر
[17:39] على المصدر، أم ينسخ الإجابة، أم يواصل المحادثة، أم يغادر؟ هذه هي تجربة المستخدم التي نريد تتبعها، وهذا يقودنا إلى التسجيل. لذا، في الوقت الحالي، اخترنا أبسط حل للتسجيل، وهو Azure table storage. نحن نسجل كل سؤال، واستدعاء للأداة، وإجابة، وتعليقات إيجابية كانت أم سلبية، بالإضافة إلى أحداث مثل النقر على المصدر أو نسخ الإجابة، مع
[18:10] سجل المحادثة الذي نبقيه صغيرًا عمدًا. إنه يكتفي بآخر 20 رسالة فقط كسياق. بالنسبة لمرحلتنا الحالية في هذا المنتج ، هذا يكفي. بمجرد نمو المنتج، سنعرف ما الذي سنحتاجه فعليًا حينها. وكيف نعرف أن أيًا من هذا يعمل بالفعل؟ أسئلة التقييم لدينا تأتي من مصادر حقيقية، وجولتين من اختبار المستخدمين مع أعضاء فعليين، بالإضافة إلى
[18:41] إرشادات سلوكية لما يجب وما لا يجب على نظام الذكاء الاصطناعي فعله. على سبيل المثال، لا تقدم نصائح، ابقَ محايدًا تجاه المنافسين، وصرح بوضوح عندما لا يكون هناك شيء مذكور في كتيبات القواعد. لدينا حوالي 86 اختباراً شاملاً تم تشغيله باستخدام Promptfoo، مع تقييم كامل من وكيل LLM وفقاً لمعايير محددة، بالإضافة إلى التحقق من الاستشهاد بالمستند المصدر الصحيح، وتقييم الاسترجاع فقط الذي
[19:11] أجريناه سابقاً. هناك أمران تعلمناهما من إجراء الاختبارات ونود مشاركتهما: أولاً ، تقييمات نموذج اللغة تحتوي على مستوى ضوضاء ، وعليك إعادة التشغيل قبل الوثوق بأي تغيير. على سبيل المثال، عندما أجرينا تقييمنا الخاص، لم يتكرر حدوث خمس من أصل 12 حالة تغيير. والثاني، أحياناً يكون القالب المعياري نفسه هو
[19:41] الخلل، وليس النموذج. فقد واجهنا تاريخاً وهمياً ظل المقيم يعاقب عليه، ليتضح لاحقاً أن هذا التاريخ كان نصاً فعلياً موجوداً في كتيب القواعد. >> أجل. والآن، فيما يخص الاستخدام. لقد أطلقنا مساعد كتيب القواعد هذا في شهر يونيو. في البداية، تم إطلاقه
[20:13] فقط للمستخدمين الداخليين لعملائنا، والهدف هو إطلاقه بحلول نهاية العام لأعضائهم الخارجيين وعملائهم. حتى الآن، لدينا بعض أرقام الاستخدام الأولية. لدينا حوالي 900 سؤال حتى الآن. مقسمة إلى أكثر من 100 محادثة،
[20:43] وهناك حوالي 34 شخصاً يستخدمونه فعلياً. قمنا أيضاً بجمع ملاحظات الإعجاب وعدم الإعجاب، لكن معظم المستخدمين توقفوا عن استخدام هذه الميزة بعد الشهر الأول. ولدينا أيضاً معلومات حول عدد المرات التي تم فيها النقر على المصادر أو نسخ الإجابات. هذه هي الأرقام المتوفرة لدينا. نستخدم الذكاء الاصطناعي أيضاً لأغراض التحليلات. على
[21:17] الجانب الأيمن، نرى كيف قام نموذج اللغة بتفسير ذلك. ما لاحظناه هو أنه في الشهر الأول، بينما كنا نسأل الناس، أجرينا بعض عمليات “ الفريق الأحمر”(اختبار الاختراق). كان الناس يحاولون كسر المساعد ومحاولة إخراجه عن الموضوع أو طرح أسئلة خارج النطاق. لكن بحلول الشهر الثالث، كانت أكثر من 90%من الأسئلة أسئلة فعلية وحقيقية. ثانياً،
[21:48] يستخدم الناس الأداة لحالات واقعية. لقد رأينا أشخاصاً يستخدمونها عبر نسخ بريد إلكتروني من عملائهم وطلب المساعدة في الرد عليه . أو يقومون بنسخ رسالة بروتوكول حقيقية أو جدول، ثم يصيغون رداً يرغبون في مراجعته. ثالثاً، نظراً لعدم حصولنا على الكثير من التعليقات عبر الإعجاب وعدم الإعجاب
[22:20] ، حاولنا تفسير مشاعر المحادثة من خلال النظر إلى الأسئلة المتابعة. إذا قال الأشخاص “شكرًا” أو انتقلوا إلى موضوع جديد، فإننا نعتبر ذلك تفاعلاً إيجابيًا. أما إذا سألوا عن الشيء نفسه مرة أخرى، فمن المحتمل أن التفاعل كان سلبيًا. وبناءً على ذلك، رأينا أن معظم المحادثات سارت
[22:51] على ما يرام. إذًا، باختصار، ما هي الدروس الرئيسية المستفادة من هذا المشروع حتى الآن؟ فيما يخص المستندات، وجدنا أنه من المهم الحفاظ على بنيتها. لذا، فإن الأقسام مهمة لاسترجاع الإجابات، وكذلك لتمكين الوكيل من إلقاء نظرة شاملة على المعرفة. لاحظنا
[23:25] أيضًا أن الجداول تتطلب معالجة خاصة وطريقة تعامل مختلفة. أما من جانب الوكيل، فكما ذُكر، كان من المهم منحه مستويات تكبير متعددة وتحديد مقدار السياق الذي يحتاجه، وبشكل عام كان من المفيد جدًا التحول من الاستدعاء الفردي للنموذج اللغوي إلى الاسترجاع عبر الوكيل.
[23:56] لاحظنا أن أرقام التقييم ارتفعت بشكل ملحوظ. من منظور تجربة المستخدم، كان البث المباشر هو ما جعله أداة قابلة للاستخدام وجيدة. ونحن لا نضيف مكونًا منظمًا إلا عندما تتطلبه تجربة المستخدم. وأخيرًا،
[24:28] وجدنا أنه من المهم الاختبار مع مستخدمين حقيقيين في وقت مبكر، واستخدام هذه المقابلات لإنشاء مطالبات التقييم التي تساعدنا في تشكيل المنتج واتخاذ القرارات بشأن ما إذا كان ما نعتبره تحسينًا هو بالفعل كذلك. شكرًا لكم على الاستماع إلى حديثنا. >> شكرًا.